diff --git a/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AssetStreamingManager.cpp b/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AssetStreamingManager.cpp index 45753a573e..0d8c9494d8 100644 --- a/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AssetStreamingManager.cpp +++ b/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AssetStreamingManager.cpp @@ -137,7 +137,15 @@ void ERS_CLASS_AssetStreamingManager::SortSceneModels(std::mapTextureFitsInVRAMBudget(TextureSizeVRAM); if (!AlreadyHasVRAMLevel && !VRAMUpdateQuotaExceeded && TextureFitsInVRAM) { if (Model->TargetTextureLevelVRAM < TargetTextureLevelVRAM) { + + // Allocate + for (unsigned int i = 0; i < Model->Textures_Loaded.size(); i++) { + ResourceMonitor_->AllocateTextureVRAMFromBudget(Model->Textures_Loaded[i].TextureLevels[TargetTextureLevelVRAM].LevelMemorySizeBytes); + Model->Textures_Loaded[i].TextureLevels[TargetTextureLevelVRAM].AllocatedVRAMBudget = true; + } + Model->TargetTextureLevelVRAM = TargetTextureLevelVRAM; + if (Model->TargetTextureLevelVRAM > 0) { CameraVRAMUpdates++; } @@ -154,7 +162,15 @@ void ERS_CLASS_AssetStreamingManager::SortSceneModels(std::mapTextureFitsInRAMBudget(TextureSizeRAM); if (!AlreadyHasRAMLevel && !RAMUpdateQuotaExceeded && TextureFitsInRAM) { if (Model->TargetTextureLevelRAM < TargetTextureLevelRAM) { + + // Allocate + for (unsigned int i = 0; i < Model->Textures_Loaded.size(); i++) { + ResourceMonitor_->AllocateTextureRAMFromBudget(Model->Textures_Loaded[i].TextureLevels[TargetTextureLevelRAM].LevelMemorySizeBytes); + Model->Textures_Loaded[i].TextureLevels[TargetTextureLevelRAM].AllocatedRAMBudget = true; + } + Model->TargetTextureLevelRAM = TargetTextureLevelRAM; + if (Model->TargetTextureLevelRAM > 0) { CameraRAMUpdates++; } diff --git a/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AsyncTextureUpdater.cpp b/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AsyncTextureUpdater.cpp index 39d89603c0..b39397e8d0 100644 --- a/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AsyncTextureUpdater.cpp +++ b/Source/Core/Loader/ERS_ModelLoader/ERS_CLASS_AsyncTextureUpdater.cpp @@ -60,6 +60,9 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture } else if (Level > (int)Texture->TextureLevels.size()) { SystemUtils_->Logger_->Log("Texture Updater Tried To Load Nonexistant Texture Level", 8, LogEnable); return false; + } else if (!ResourceMonitor_->TextureFitsInRAMBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes)) { + SystemUtils_->Logger_->Log("Cannot Load Texture Into Memory, Will Not Fit In RAM Budget", 6); + return false; } // Check If Level Already Loaded @@ -68,6 +71,12 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture } + // If Needed, Allocate Memory From Budget + if (!Texture->TextureLevels[Level].AllocatedRAMBudget) { + ResourceMonitor_->AllocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = true; + } + // Load Image Data ERS_STRUCT_IOData ImageData; long LevelAssetID = Texture->TextureLevels[Level].LevelTextureAssetID; @@ -88,6 +97,8 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture + "' Width Is <1", 8, LogEnable); FreeImage_Unload(RawImage); FreeImage_CloseMemory(FIImageData); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } if (Height <= 0) { @@ -96,6 +107,8 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture + "' Height Is <1", 8, LogEnable); FreeImage_Unload(RawImage); FreeImage_CloseMemory(FIImageData); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } @@ -115,13 +128,14 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture FreeImage_Unload(RawImage); FreeImage_CloseMemory(FIImageData); - std::pair TargetWidthHeight = Texture->TextureLevels[Level].LevelResolution; if ((TargetWidthHeight.first != Width) && (TargetWidthHeight.first != -1)) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(LevelAssetID) + "' Width Does Not Match Metadata Target", 8, LogEnable); FreeImage_Unload(Image); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } if ((TargetWidthHeight.second != Height) && (TargetWidthHeight.second != -1)) { @@ -129,9 +143,10 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(LevelAssetID) + "' Height Does Not Match Metadata Target", 8, LogEnable); FreeImage_Unload(Image); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } - // Detect NumChannels if ((Channels < 1) || (Channels > 4)) { @@ -139,6 +154,8 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(LevelAssetID) + "' Invalid Number Of Channels '" + std::to_string(Channels) + "'", 8, LogEnable); FreeImage_Unload(Image); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } if ((Texture->TextureLevels[Level].LevelChannel != Channels) && (Texture->TextureLevels[Level].LevelChannel != -1)) { @@ -147,15 +164,12 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataRAM(ERS_STRUCT_Texture* Texture + "' Number Channels '" + std::to_string(Channels) + "' Does Not Match Metadata Target '" + std::to_string(Texture->TextureLevels[Level].LevelChannel) + "'", 8, LogEnable); FreeImage_Unload(Image); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; return false; } - // fix images loading incorrectly (perhaps due to broken numbers of channels? - // add error textures so that we can display the error on the model to make it easier to understand what the issue is - for example, display "Loading Error: Invalid Num Image Channels" for the above issue and add the same for the other issues. - // Finally After Passing Sanity Checks, Populate Info. - long MemorySize = FreeImage_GetMemorySize(Image); - ResourceMonitor_->AllocateTextureRAMFromBudget(MemorySize); Texture->TextureLevels[Level].LevelBitmap = Image; Texture->TextureLevels[Level].LevelLoadedInRAM = true; @@ -179,9 +193,8 @@ bool ERS_CLASS_AsyncTextureUpdater::UnloadImageDataRAM(ERS_STRUCT_Texture* Textu return false; } - - long MemorySize = FreeImage_GetMemorySize(Texture->TextureLevels[Level].LevelBitmap); - ResourceMonitor_->DeallocateTextureRAMFromBudget(MemorySize); + ResourceMonitor_->DeallocateTextureRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedRAMBudget = false; // Update Data FreeImage_Unload(Texture->TextureLevels[Level].LevelBitmap); @@ -199,6 +212,9 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataVRAM(ERS_STRUCT_Texture* Textur } else if (Level > (int)Texture->TextureLevels.size()) { SystemUtils_->Logger_->Log("Texture Updater Tried To Load Nonexistant Texture Level Into VRAM", 8, LogEnable); return false; + } else if (!ResourceMonitor_->TextureFitsInVRAMBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes)) { + SystemUtils_->Logger_->Log("Cannot Load Texture Into Memory, Will Not Fit In VRAM Budget", 6); + return false; } // Check If Level Already Loaded @@ -207,6 +223,11 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataVRAM(ERS_STRUCT_Texture* Textur return false; } + // Allocate Budget + if (!Texture->TextureLevels[Level].AllocatedVRAMBudget) { + ResourceMonitor_->AllocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + } + // Get Image Metadata, Perform Checks int MaxLevel = Texture->TextureLevels.size() - 1; int CorrectedIndex = Level; @@ -219,51 +240,58 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataVRAM(ERS_STRUCT_Texture* Textur SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Channel Count >4", 8, LogEnable); + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); return false; } if (Channels < 1) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Channel Count <1", 8, LogEnable); + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; return false; } if (!Texture->TextureLevels[Level].LevelLoadedInRAM) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Not All Prior Levels Are Loaded Into RAM", 8, LogEnable); + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; return false; } if (MaxLevel < 0) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' No Levels To Load", 8, LogEnable); - return false; + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; + return false; } if (MaxWidth < 1) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Width is 0", 8, LogEnable); - return false; + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; + return false; } if (MaxHeight < 1) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Height is 0", 8, LogEnable); - return false; + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; + return false; } if (ImageSize < 1) { SystemUtils_->Logger_->Log(std::string("Error Loading Texture '") + Texture->Path + "', Level '" + std::to_string(Level) + "' With ID '" + std::to_string(Texture->TextureLevels[CorrectedIndex].LevelTextureAssetID) + "' Image Byte Array Has Size Of 0", 8, LogEnable); - return false; + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; + return false; } - - // TODO: Fix mip map loading - // FIx segfaults caused when lots of loading is in the queue - unknown why this happens - //bool EnableMipMaps = false; - - // Setup PBO unsigned int PBOID; glGenBuffers(1, &PBOID); @@ -292,6 +320,8 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataVRAM(ERS_STRUCT_Texture* Textur TextureInternFormat = GL_RED; TextureExternFormat = GL_RED; } else { + ResourceMonitor_->DeallocateTextureVRAMFromBudget(Texture->TextureLevels[Level].LevelMemorySizeBytes); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; return false; } @@ -329,12 +359,8 @@ bool ERS_CLASS_AsyncTextureUpdater::LoadImageDataVRAM(ERS_STRUCT_Texture* Textur glDeleteBuffers(1, &PBOID); // Update Struct - long MemorySize = Texture->TextureLevels[Level].LevelMemorySizeBytes; - ResourceMonitor_->AllocateTextureVRAMFromBudget(MemorySize); Texture->TextureLevels[CorrectedIndex].LevelTextureOpenGLID = OpenGLTextureID; Texture->TextureLevels[CorrectedIndex].LevelLoadedInVRAM = true; - - return true; } bool ERS_CLASS_AsyncTextureUpdater::UnloadImageDataVRAM(ERS_STRUCT_Texture* Texture, int Level, bool LogEnable) { @@ -360,6 +386,7 @@ bool ERS_CLASS_AsyncTextureUpdater::UnloadImageDataVRAM(ERS_STRUCT_Texture* Text // Update Struct long MemorySize = Texture->TextureLevels[Level].LevelMemorySizeBytes; ResourceMonitor_->DeallocateTextureVRAMFromBudget(MemorySize); + Texture->TextureLevels[Level].AllocatedVRAMBudget = false; Texture->TextureLevels[Level].LevelTextureOpenGLID = 0; Texture->TextureLevels[Level].LevelLoadedInVRAM = false; @@ -827,5 +854,4 @@ bool ERS_CLASS_AsyncTextureUpdater::GetQueuePrioritizationEnabled() { } void ERS_CLASS_AsyncTextureUpdater::SetQueuePrioritizationEnabled(bool State) { PrioritizeQueueByVisualImpact_ = State; -} - +} \ No newline at end of file diff --git a/Source/Core/Structures/ERS_STRUCT_TextureLevel/ERS_STRUCT_TextureLevel.h b/Source/Core/Structures/ERS_STRUCT_TextureLevel/ERS_STRUCT_TextureLevel.h index 7292b722a0..9314bda908 100644 --- a/Source/Core/Structures/ERS_STRUCT_TextureLevel/ERS_STRUCT_TextureLevel.h +++ b/Source/Core/Structures/ERS_STRUCT_TextureLevel/ERS_STRUCT_TextureLevel.h @@ -21,11 +21,19 @@ struct ERS_STRUCT_TextureLevel { unsigned int LevelTextureOpenGLID; /** LevelResolution; /**