diff --git a/Hydrogent/include/HnTextureRegistry.hpp b/Hydrogent/include/HnTextureRegistry.hpp index b4ebd74b..6acd28b6 100644 --- a/Hydrogent/include/HnTextureRegistry.hpp +++ b/Hydrogent/include/HnTextureRegistry.hpp @@ -42,6 +42,8 @@ #include "../../../DiligentCore/Common/interface/ObjectsRegistry.hpp" #include "../../../DiligentTools/TextureLoader/interface/TextureLoader.h" +#include "HnTextureUtils.hpp" + namespace Diligent { @@ -56,7 +58,6 @@ namespace USD { struct HnTextureIdentifier; -struct HnLoadTextureResult; class HnTextureRegistry final : public std::enable_shared_from_this { @@ -140,13 +141,15 @@ class HnTextureRegistry final : public std::enable_shared_from_this; + // Allocates texture handle for the specified texture file path. // If the texture is not loaded, calls CreateLoader() to create the texture loader. - TextureHandleSharedPtr Allocate(const pxr::TfToken& FilePath, - const TextureComponentMapping& Swizzle, - const pxr::HdSamplerParameters& SamplerParams, - bool IsAsync, - std::function CreateLoader); + TextureHandleSharedPtr Allocate(const pxr::TfToken& FilePath, + const TextureComponentMapping& Swizzle, + const pxr::HdSamplerParameters& SamplerParams, + bool IsAsync, + CreateTextureLoaderCallbackType CreateLoader); TextureHandleSharedPtr Get(const pxr::TfToken& Path) { @@ -188,11 +191,12 @@ class HnTextureRegistry final : public std::enable_shared_from_this CreateLoader, - std::shared_ptr TexHandle); + HN_LOAD_TEXTURE_STATUS LoadTexture(const pxr::TfToken Key, + const pxr::TfToken& FilePath, + const pxr::HdSamplerParameters& SamplerParams, + Int64 MemoryBudget, + CreateTextureLoaderCallbackType CreateLoader, + std::shared_ptr TexHandle); void OnDestroyHandle(const TextureHandle& Handle); diff --git a/Hydrogent/include/HnTextureUtils.hpp b/Hydrogent/include/HnTextureUtils.hpp index fc57719a..7ed14aca 100644 --- a/Hydrogent/include/HnTextureUtils.hpp +++ b/Hydrogent/include/HnTextureUtils.hpp @@ -70,7 +70,7 @@ struct HnLoadTextureResult HnLoadTextureResult LoadTextureFromSdfPath(const char* SdfPath, const TextureLoadInfo& LoadInfo, - Uint64 MemoryBudget = 0); + Int64 MemoryBudget = 0); Int64 GetTextureLoaderMemoryUsage(); diff --git a/Hydrogent/src/HnMaterial.cpp b/Hydrogent/src/HnMaterial.cpp index d4e9ebc1..8a9d44f9 100644 --- a/Hydrogent/src/HnMaterial.cpp +++ b/Hydrogent/src/HnMaterial.cpp @@ -480,7 +480,7 @@ HnTextureRegistry::TextureHandleSharedPtr HnMaterial::GetDefaultTexture(HnTextur /*IsAsync = */ false, // Allocate default textures synchronously to make // them immediately available after the first Sync // for the fallback material. - [&]() { + [&](Int64 /*MemoryBudget*/) { RefCntAutoPtr pImage = CreateDefaultImage(DefaultTexName); TextureLoadInfo LoadInfo{Name.GetText()}; diff --git a/Hydrogent/src/HnTextureRegistry.cpp b/Hydrogent/src/HnTextureRegistry.cpp index af816d43..edfa229a 100644 --- a/Hydrogent/src/HnTextureRegistry.cpp +++ b/Hydrogent/src/HnTextureRegistry.cpp @@ -253,24 +253,28 @@ void HnTextureRegistry::Commit(IDeviceContext* pContext) } } -void HnTextureRegistry::LoadTexture(const pxr::TfToken Key, - const pxr::TfToken& FilePath, - const pxr::HdSamplerParameters& SamplerParams, - std::function CreateLoader, - std::shared_ptr TexHandle) +HN_LOAD_TEXTURE_STATUS HnTextureRegistry::LoadTexture(const pxr::TfToken Key, + const pxr::TfToken& FilePath, + const pxr::HdSamplerParameters& SamplerParams, + Int64 MemoryBudget, + CreateTextureLoaderCallbackType CreateLoader, + std::shared_ptr TexHandle) { - HnLoadTextureResult LoadResult = CreateLoader(); + HnLoadTextureResult LoadResult = CreateLoader(MemoryBudget); if (!LoadResult) { - LOG_ERROR_MESSAGE("Failed to create texture loader for texture ", FilePath); + if (LoadResult.LoadStatus != HN_LOAD_TEXTURE_STATUS_BUDGET_EXCEEDED) + { + LOG_ERROR_MESSAGE("Failed to create texture loader for texture ", FilePath); - // Since we don't add the handle to the pending list, we need to decrement the counter here - m_NumTexturesLoading.fetch_add(-1); + // Since we don't add the handle to the pending list, we need to decrement the counter here + m_NumTexturesLoading.fetch_add(-1); - // Set the m_IsInitialized flag or the handle will be stuck in the loading state - TexHandle->m_IsInitialized.store(true); + // Set the m_IsInitialized flag or the handle will be stuck in the loading state + TexHandle->m_IsInitialized.store(true); + } - return; + return LoadResult.LoadStatus; } RefCntAutoPtr pLoader = std::move(LoadResult.pLoader); @@ -319,13 +323,15 @@ void HnTextureRegistry::LoadTexture(const pxr::TfToken Key, std::lock_guard Lock{m_PendingTexturesMtx}; m_PendingTextures.emplace(Key, PendingTextureInfo{std::move(pLoader), SamplerParams, std::move(TexHandle)}); } + + return LoadResult.LoadStatus; } -HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const pxr::TfToken& FilePath, - const TextureComponentMapping& Swizzle, - const pxr::HdSamplerParameters& SamplerParams, - bool IsAsync, - std::function CreateLoader) +HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const pxr::TfToken& FilePath, + const TextureComponentMapping& Swizzle, + const pxr::HdSamplerParameters& SamplerParams, + bool IsAsync, + CreateTextureLoaderCallbackType CreateLoader) { const pxr::TfToken Key{FilePath.GetString() + '.' + GetTextureComponentMappingString(Swizzle)}; return m_Cache.Get( @@ -357,14 +363,10 @@ HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const pxr: RefCntAutoPtr pTask = EnqueueAsyncWork( m_pThreadPool, [=](Uint32 ThreadId) { - if (m_LoadBudget != 0 && GetTextureLoaderMemoryUsage() > m_LoadBudget) - { - // Reschedule the task - return ASYNC_TASK_STATUS_NOT_STARTED; - } - - LoadTexture(Key, FilePath, SamplerParams, CreateLoader, TexHandle); - return ASYNC_TASK_STATUS_COMPLETE; + HN_LOAD_TEXTURE_STATUS LoadStatus = LoadTexture(Key, FilePath, SamplerParams, m_LoadBudget, CreateLoader, TexHandle); + return LoadStatus != HN_LOAD_TEXTURE_STATUS_BUDGET_EXCEEDED ? + ASYNC_TASK_STATUS_COMPLETE : + ASYNC_TASK_STATUS_NOT_STARTED; // Reschedule the task }, Priority); @@ -375,7 +377,7 @@ HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const pxr: } else { - LoadTexture(Key, FilePath, SamplerParams, CreateLoader, TexHandle); + LoadTexture(Key, FilePath, SamplerParams, 0, CreateLoader, TexHandle); } return TexHandle; @@ -394,7 +396,7 @@ HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const HnTe } return Allocate(TexId.FilePath, TexId.SubtextureId.Swizzle, SamplerParams, IsAsync, - [TexId, Format, CompressMode = m_CompressMode]() { + [TexId, Format, CompressMode = m_CompressMode](Int64 MemoryBudget) { TextureLoadInfo LoadInfo; LoadInfo.Name = TexId.FilePath.GetText(); LoadInfo.Format = Format; @@ -405,7 +407,7 @@ HnTextureRegistry::TextureHandleSharedPtr HnTextureRegistry::Allocate(const HnTe LoadInfo.CompressMode = CompressMode; LoadInfo.UniformImageClipDim = 32; - return LoadTextureFromSdfPath(TexId.FilePath.GetText(), LoadInfo); + return LoadTextureFromSdfPath(TexId.FilePath.GetText(), LoadInfo, MemoryBudget); }); } diff --git a/Hydrogent/src/HnTextureUtils.cpp b/Hydrogent/src/HnTextureUtils.cpp index 41147770..feedadac 100644 --- a/Hydrogent/src/HnTextureUtils.cpp +++ b/Hydrogent/src/HnTextureUtils.cpp @@ -199,16 +199,22 @@ std::atomic AssetDataContainer::s_AssetDataSize{0}; HnLoadTextureResult LoadTextureFromSdfPath(const char* SdfPath, const TextureLoadInfo& _LoadInfo, - Uint64 MemoryBudget) + Int64 MemoryBudget) { + // Check memory budget before opening the asset + if (MemoryBudget != 0 && GetTextureLoaderMemoryUsage() > MemoryBudget) + { + // Reschedule the task + return {HN_LOAD_TEXTURE_STATUS_BUDGET_EXCEEDED}; + } + pxr::ArResolvedPath ResolvedPath{SdfPath}; if (ResolvedPath.empty()) { return {HN_LOAD_TEXTURE_STATUS_INVALID_PATH}; } - std::shared_ptr Buffer; - size_t Size = 0; + RefCntAutoPtr pAssetData; { const pxr::ArResolver& Resolver = pxr::ArGetResolver(); std::shared_ptr Asset = Resolver.OpenAsset(ResolvedPath); @@ -217,17 +223,24 @@ HnLoadTextureResult LoadTextureFromSdfPath(const char* SdfPath, return {HN_LOAD_TEXTURE_STATUS_ASSET_NOT_FOUND}; } - Buffer = Asset->GetBuffer(); + std::shared_ptr Buffer = Asset->GetBuffer(); if (!Buffer) { return {HN_LOAD_TEXTURE_STATUS_EMPTY_ASSET}; } - Size = Asset->GetSize(); + // Create asset data container to account for the asset memory usage + pAssetData = AssetDataContainer::Create(std::move(Buffer), Asset->GetSize()); + if (MemoryBudget != 0) + { + size_t LoaderMemoryReq = GetTextureLoaderMemoryRequirement(pAssetData->GetConstDataPtr(), pAssetData->GetSize(), _LoadInfo); + if (GetTextureLoaderMemoryUsage() + static_cast(LoaderMemoryReq) > MemoryBudget) + { + return {HN_LOAD_TEXTURE_STATUS_BUDGET_EXCEEDED}; + } + } } - RefCntAutoPtr pAssetData = AssetDataContainer::Create(std::move(Buffer), Size); - TextureLoadInfo LoadInfo = _LoadInfo; LoadInfo.pAllocator = &TextureMemoryAllocator::Get();