From 21321b5b93dd667ef52aa503200fbffa13189741 Mon Sep 17 00:00:00 2001 From: Eunki Hong Date: Sat, 13 Jan 2024 09:28:27 +0900 Subject: [PATCH] Remove cubemap cache temperary + Fix bug when Uploaded PixelData resue after Texture GC If we create NewPixelDataWithReleaseAfterUpload and Upload to texture, and if that texture reference count become 1 and GC, the key of PixelData is not valid anymore. To avoid this cases, Let we collect all PixelData container if some texture removed. And also, since PixelData could be key of Texture cache, we should check the reference count is less than 2. + Since current cubemap cache not works well reasonable, just remove it. We will reopen it after we implement PixelDataList cache system again. + Print more log information if we need. Change-Id: I6693ceab9b03cc20e1c6a42282ef39af38344e27 Signed-off-by: Eunki Hong --- .../utc-Dali-EnvironmentDefinition.cpp | 59 ++--- .../common/environment-map-load-task.cpp | 3 +- .../internal/common/image-resource-loader.cpp | 203 +++++++----------- .../internal/common/image-resource-loader.h | 14 +- .../model-components/model-primitive-impl.cpp | 9 +- .../loader/environment-definition.cpp | 2 +- .../loader/environment-map-data.cpp | 26 ++- .../public-api/loader/resource-bundle.cpp | 3 +- 8 files changed, 142 insertions(+), 177 deletions(-) diff --git a/automated-tests/src/dali-scene3d/utc-Dali-EnvironmentDefinition.cpp b/automated-tests/src/dali-scene3d/utc-Dali-EnvironmentDefinition.cpp index 5dd2f1c2cc..8d5e694366 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-EnvironmentDefinition.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-EnvironmentDefinition.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,9 @@ // Enable debug log for test coverage #define DEBUG_ENABLED 1 -#include "dali-scene3d/public-api/loader/environment-definition.h" #include #include +#include "dali-scene3d/public-api/loader/environment-definition.h" using namespace Dali; using namespace Dali::Scene3D::Loader; @@ -28,16 +28,16 @@ using namespace Dali::Scene3D::Loader; int UtcDaliEnvironmentDefinitionLoadRawDefault(void) { EnvironmentDefinition envDef; - auto rawData = envDef.LoadRaw(""); + auto rawData = envDef.LoadRaw(""); DALI_TEST_EQUAL(rawData.mDiffuse.mPixelData.size(), 6u); - for (auto& face: rawData.mDiffuse.mPixelData) + for(auto& face : rawData.mDiffuse.mPixelData) { DALI_TEST_EQUAL(face.size(), 1u); } DALI_TEST_EQUAL(rawData.mSpecular.mPixelData.size(), 6u); - for (auto& face: rawData.mSpecular.mPixelData) + for(auto& face : rawData.mSpecular.mPixelData) { DALI_TEST_EQUAL(face.size(), 1u); } @@ -47,9 +47,9 @@ int UtcDaliEnvironmentDefinitionLoadRawDefault(void) int UtcDaliEnvironmentDefinitionLoadRawFail(void) { - for (auto name: { "nonexistent.ktx", TEST_RESOURCE_DIR "Cobe.obj" , TEST_RESOURCE_DIR "truncated.ktx" }) + for(auto name : {"nonexistent.ktx", TEST_RESOURCE_DIR "Cobe.obj", TEST_RESOURCE_DIR "truncated.ktx"}) { - EnvironmentDefinition envDef { name, name }; + EnvironmentDefinition envDef{name, name}; DALI_TEST_ASSERTION(envDef.LoadRaw(""), "Failed to load cubemap texture"); envDef.mDiffuseMapPath = ""; @@ -61,15 +61,15 @@ int UtcDaliEnvironmentDefinitionLoadRawFail(void) int UtcDaliEnvironmentDefinitionLoadRawSuccess(void) { - EnvironmentDefinition envDef { "forest_irradiance.ktx", "forest_radiance.ktx" }; - auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); + EnvironmentDefinition envDef{"forest_irradiance.ktx", "forest_radiance.ktx"}; + auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); DALI_TEST_EQUAL(rawData.mDiffuse.mPixelData.size(), 6u); - for (auto& face: rawData.mDiffuse.mPixelData) + for(auto& face : rawData.mDiffuse.mPixelData) { DALI_TEST_EQUAL(face.size(), 1u); uint32_t size = 64u; - for (auto& mipLevel : face) + for(auto& mipLevel : face) { DALI_TEST_EQUAL(mipLevel.GetPixelFormat(), Pixel::Format::RGB888); DALI_TEST_EQUAL(mipLevel.GetWidth(), size); @@ -79,11 +79,11 @@ int UtcDaliEnvironmentDefinitionLoadRawSuccess(void) } DALI_TEST_EQUAL(rawData.mSpecular.mPixelData.size(), 6u); - for (auto& face: rawData.mSpecular.mPixelData) + for(auto& face : rawData.mSpecular.mPixelData) { DALI_TEST_EQUAL(face.size(), 5u); uint32_t size = 64u; - for (auto& mipLevel : face) + for(auto& mipLevel : face) { DALI_TEST_EQUAL(mipLevel.GetPixelFormat(), Pixel::Format::RGB888); DALI_TEST_EQUAL(mipLevel.GetWidth(), size); @@ -98,8 +98,8 @@ int UtcDaliEnvironmentDefinitionLoadRawSuccess(void) int UtcDaliEnvironmentDefinitionLoadEmptyRaw(void) { EnvironmentDefinition::RawData rawData; - EnvironmentDefinition envDef; - auto textures = envDef.Load(std::move(rawData)); + EnvironmentDefinition envDef; + auto textures = envDef.Load(std::move(rawData)); DALI_TEST_CHECK(!textures.mDiffuse); DALI_TEST_CHECK(!textures.mSpecular); @@ -108,7 +108,6 @@ int UtcDaliEnvironmentDefinitionLoadEmptyRaw(void) namespace { - void CheckTextureDefault(Texture texture) { DALI_TEST_CHECK(texture); @@ -123,15 +122,16 @@ void CheckTextureNotDefault(Texture texture) DALI_TEST_CHECK(texture.GetHeight() > 1u); } -} +} // namespace int UtcDaliEnvironmentDefinitionLoadDefault(void) { EnvironmentDefinition envDef{}; - auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");; + auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); + ; TestApplication app; - auto textures = envDef.Load(std::move(rawData)); + auto textures = envDef.Load(std::move(rawData)); CheckTextureDefault(textures.mSpecular); CheckTextureDefault(textures.mDiffuse); @@ -141,11 +141,12 @@ int UtcDaliEnvironmentDefinitionLoadDefault(void) int UtcDaliEnvironmentDefinitionLoadDiffuse(void) { - EnvironmentDefinition envDef{ "forest_irradiance.ktx" }; - auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");; + EnvironmentDefinition envDef{"forest_irradiance.ktx"}; + auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); + ; TestApplication app; - auto textures = envDef.Load(std::move(rawData)); + auto textures = envDef.Load(std::move(rawData)); CheckTextureNotDefault(textures.mDiffuse); CheckTextureDefault(textures.mSpecular); @@ -155,11 +156,12 @@ int UtcDaliEnvironmentDefinitionLoadDiffuse(void) int UtcDaliEnvironmentDefinitionLoadSpecular(void) { - EnvironmentDefinition envDef{ "", "forest_radiance.ktx" }; - auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");; + EnvironmentDefinition envDef{"", "forest_radiance.ktx"}; + auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); + ; TestApplication app; - auto textures = envDef.Load(std::move(rawData)); + auto textures = envDef.Load(std::move(rawData)); CheckTextureDefault(textures.mDiffuse); CheckTextureNotDefault(textures.mSpecular); @@ -169,11 +171,12 @@ int UtcDaliEnvironmentDefinitionLoadSpecular(void) int UtcDaliEnvironmentDefinitionLoadBoth(void) { - EnvironmentDefinition envDef{ "forest_irradiance.ktx", "forest_radiance.ktx" }; - auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/");; + EnvironmentDefinition envDef{"forest_irradiance.ktx", "forest_radiance.ktx"}; + auto rawData = envDef.LoadRaw(TEST_RESOURCE_DIR "/"); + ; TestApplication app; - auto textures = envDef.Load(std::move(rawData)); + auto textures = envDef.Load(std::move(rawData)); CheckTextureNotDefault(textures.mDiffuse); CheckTextureNotDefault(textures.mSpecular); diff --git a/dali-scene3d/internal/common/environment-map-load-task.cpp b/dali-scene3d/internal/common/environment-map-load-task.cpp index 8bc8239022..385eb39a25 100644 --- a/dali-scene3d/internal/common/environment-map-load-task.cpp +++ b/dali-scene3d/internal/common/environment-map-load-task.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include // INTERNAL INCLUDES +#include #include namespace Dali diff --git a/dali-scene3d/internal/common/image-resource-loader.cpp b/dali-scene3d/internal/common/image-resource-loader.cpp index 3403cfa17b..bc1a21d16f 100644 --- a/dali-scene3d/internal/common/image-resource-loader.cpp +++ b/dali-scene3d/internal/common/image-resource-loader.cpp @@ -36,6 +36,7 @@ #include ///< for std::function #include ///< for std::shared_ptr #include +#include #include #include ///< for std::pair @@ -50,16 +51,8 @@ constexpr uint32_t GC_PERIOD_MILLISECONDS = 1000u; Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMAGE_RESOURCE_LOADER"); #endif -bool SupportPixelDataCache(Dali::PixelData pixelData) +bool IsDefaultPixelData(const Dali::PixelData& pixelData) { - // Check given pixelData support to release data after upload. - // This is cause we need to reduce CPU memory usage. - if(Dali::Integration::IsPixelDataReleaseAfterUpload(pixelData)) - { - return true; - } - - // Check given pixelData is default pixelData. if(pixelData == Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyPixelDataWhiteRGB() || pixelData == Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyPixelDataWhiteRGBA() || pixelData == Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyPixelDataZAxisRGB() || @@ -70,19 +63,21 @@ bool SupportPixelDataCache(Dali::PixelData pixelData) return false; } -bool SupportPixelDataListCache(const std::vector>& pixelDataList) +bool SupportPixelDataCache(const Dali::PixelData& pixelData) { - for(const auto& pixelDataListLevel0 : pixelDataList) + // Check given pixelData support to release data after upload. + // This is cause we need to reduce CPU memory usage. + if(Dali::Integration::IsPixelDataReleaseAfterUpload(pixelData)) { - for(const auto& pixelData : pixelDataListLevel0) - { - if(!SupportPixelDataCache(pixelData)) - { - return false; - } - } + return true; } - return true; + + // Check given pixelData is default pixelData. + if(IsDefaultPixelData(pixelData)) + { + return true; + } + return false; } struct ImageInformation @@ -152,21 +147,6 @@ std::size_t GenerateHash(const Dali::PixelData& pixelData, bool mipmapRequired) return reinterpret_cast(static_cast(pixelData.GetObjectPtr())) ^ (static_cast(mipmapRequired) << (sizeof(std::size_t) * 4)); } -std::size_t GenerateHash(const std::vector>& pixelDataList, bool mipmapRequired) -{ - std::size_t result = 0x12345678u + pixelDataList.size(); - for(const auto& mipmapPixelDataList : pixelDataList) - { - result += (result << 5) + mipmapPixelDataList.size(); - for(const auto& pixelData : mipmapPixelDataList) - { - result += (result << 5) + GenerateHash(pixelData, false); - } - } - - return result ^ (static_cast(mipmapRequired) << (sizeof(std::size_t) * 4)); -} - // Item Creation functor list Dali::PixelData CreatePixelDataFromImageInfo(const ImageInformation& info, bool releasePixelData) @@ -197,27 +177,17 @@ Dali::Texture CreateTextureFromPixelData(const Dali::PixelData& pixelData, bool return texture; } -Dali::Texture CreateCubeTextureFromPixelDataList(const std::vector>& pixelDataList, bool mipmapRequired) +// Check function whether we can collect given data as garbage, or not. +bool PixelDataCacheCollectable(const ImageInformation& info, const Dali::PixelData& pixelData) { - Dali::Texture texture; - if(!pixelDataList.empty() && !pixelDataList[0].empty()) - { - texture = Dali::Texture::New(Dali::TextureType::TEXTURE_CUBE, pixelDataList[0][0].GetPixelFormat(), pixelDataList[0][0].GetWidth(), pixelDataList[0][0].GetHeight()); - for(size_t iSide = 0u, iEndSize = pixelDataList.size(); iSide < iEndSize; ++iSide) - { - auto& side = pixelDataList[iSide]; - for(size_t iMipLevel = 0u, iEndMipLevel = pixelDataList[0].size(); iMipLevel < iEndMipLevel; ++iMipLevel) - { - texture.Upload(side[iMipLevel], Dali::CubeMapLayer::POSITIVE_X + iSide, iMipLevel, 0u, 0u, side[iMipLevel].GetWidth(), side[iMipLevel].GetHeight()); - } - } - if(mipmapRequired) - { - texture.GenerateMipmaps(); - } - } + return pixelData.GetBaseObject().ReferenceCount() <= 1; +} - return texture; +bool TextureCacheCollectable(const Dali::PixelData& pixelData, const Dali::Texture& texture) +{ + return !IsDefaultPixelData(pixelData) && ///< If key is not default pixelData + pixelData.GetBaseObject().ReferenceCount() <= 2 && ///< And it have reference count as 2 (1 is for the key of this container, and other is PixelData cache.) + texture.GetBaseObject().ReferenceCount() <= 1; ///< And nobody use this texture, except this contianer. } // Forward declare, for signal connection. @@ -232,15 +202,12 @@ public: CacheImpl() : mPixelDataCache{}, mTextureCache{}, - mCubeTextureCache{}, mTimer{}, mLatestCollectedPixelDataIter{mPixelDataCache.begin()}, mLatestCollectedTextureIter{mTextureCache.begin()}, - mLatestCollectedCubeTextureIter{mCubeTextureCache.begin()}, + mDataMutex{}, mPixelDataContainerUpdated{false}, mTextureContainerUpdated{false}, - mCubeTextureContainerUpdated{false}, - mDataMutex{}, mDestroyed{false}, mFullCollectRequested{false} { @@ -259,17 +226,14 @@ public: { mDataMutex.lock(); - mDestroyed = true; - mPixelDataContainerUpdated = false; - mTextureContainerUpdated = false; - mCubeTextureContainerUpdated = false; - mLatestCollectedPixelDataIter = decltype(mLatestCollectedPixelDataIter)(); // Invalidate iterator - mLatestCollectedTextureIter = decltype(mLatestCollectedTextureIter)(); // Invalidate iterator - mLatestCollectedCubeTextureIter = decltype(mLatestCollectedCubeTextureIter){}; // Invalidate iterator + mDestroyed = true; + mPixelDataContainerUpdated = false; + mTextureContainerUpdated = false; + mLatestCollectedPixelDataIter = decltype(mLatestCollectedPixelDataIter)(); // Invalidate iterator + mLatestCollectedTextureIter = decltype(mLatestCollectedTextureIter)(); // Invalidate iterator mPixelDataCache.clear(); mTextureCache.clear(); - mCubeTextureCache.clear(); mDataMutex.unlock(); } @@ -285,9 +249,8 @@ public: private: // Unified API for this class // Let compare with hash first. And then, check detail keys after. - using PixelDataCacheContainer = std::map>>; - using TextureCacheContainer = std::map>>; - using CubeTextureCacheContainer = std::map>, Dali::Texture>>>; + using PixelDataCacheContainer = std::map>>; + using TextureCacheContainer = std::map>>; /** * @brief Try to get cached item, or create new handle if there is no item. @@ -314,6 +277,7 @@ private: // Unified API for this class bool found = false; auto iter = cacheContainer.lower_bound(hashValue); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "HashValue : %zu\n", hashValue); if((iter == cacheContainer.end()) || (hashValue != iter->first)) { containerUpdated = true; @@ -356,6 +320,7 @@ private: // Unified API for this class return returnItem; } + /** * @brief Try to collect garbages, which reference counts are 1. * @@ -367,15 +332,10 @@ private: // Unified API for this class * @oaram[in, out] checkedCount The number of iteration checked total. * @return True if we iterate whole container, so we don't need to check anymore. False otherwise */ - template - bool CollectGarbages(ContainerType& cacheContainer, bool fullCollect, bool& containerUpdated, Iterator& lastIterator, uint32_t& checkedCount) + template + bool CollectGarbages(ContainerType& cacheContainer, bool fullCollect, bool& containerUpdated, Iterator& lastIterator, uint32_t& checkedCount, uint32_t& collectedCount) { - if constexpr(needMutex) - { - mDataMutex.lock(); - } - - DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Collect Garbages : %zu\n", cacheContainer.size()); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Collect Garbages : %zu (checkedCount : %d, fullCollect? %d)\n", cacheContainer.size(), checkedCount, fullCollect); // Container changed. We should re-collect garbage from begin again. if(fullCollect || containerUpdated) { @@ -391,9 +351,11 @@ private: // Unified API for this class { auto& item = jter->second; DALI_LOG_INFO(gLogFilter, Debug::Verbose, "item : %p, ref count : %u\n", item.GetObjectPtr(), (item ? item.GetBaseObject().ReferenceCount() : 0u)); - if(!item || (item.GetBaseObject().ReferenceCount() == 1u)) + if(!item || Collectable(jter->first, item)) { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GC!!!\n"); // This item is garbage! just remove it. + ++collectedCount; jter = cachePairList.erase(jter); } else @@ -412,11 +374,6 @@ private: // Unified API for this class } } - if constexpr(needMutex) - { - mDataMutex.unlock(); - } - return (lastIterator != cacheContainer.end()); } @@ -434,19 +391,6 @@ public: // Called by main thread. return GetOrCreateCachedItem(mTextureCache, hashValue, pixelData, mipmapRequired, mTextureContainerUpdated); } - /** - * @brief Try to get cached cube texture, or newly create if there is no cube texture that already cached. - * - * @param[in] pixelDataList The pixelData list of image. - * @param[in] mipmapRequired True if result texture need to generate mipmap. - * @return Texture that has been cached. Or empty handle if we fail to found cached item. - */ - Dali::Texture GetOrCreateCachedCubeTexture(const std::vector>& pixelDataList, bool mipmapRequired) - { - auto hashValue = GenerateHash(pixelDataList, mipmapRequired); - return GetOrCreateCachedItem>, Dali::Texture, CreateCubeTextureFromPixelDataList>(mCubeTextureCache, hashValue, pixelDataList, mipmapRequired, mCubeTextureContainerUpdated); - } - /** * @brief Request incremental gargabe collect. * @@ -467,12 +411,9 @@ public: // Called by main thread. if(!mTimer.IsRunning()) { // Restart container interating. - if(!mPixelDataContainerUpdated) - { - mDataMutex.lock(); - mPixelDataContainerUpdated = true; - mDataMutex.unlock(); - } + mDataMutex.lock(); + mPixelDataContainerUpdated = true; + mDataMutex.unlock(); mTextureContainerUpdated = true; mTimer.Start(); } @@ -512,40 +453,44 @@ private: // Called by main thread bool IncrementalGarbageCollect(bool fullCollect) { bool continueTimer = false; + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GC start\n"); // Try to collect Texture GC first, due to the reference count of pixelData who become key of textures. // After all texture GC finished, then check PixelData cache. - uint32_t checkedCount = 0u; + uint32_t checkedCount = 0u; + uint32_t collectedCount = 0u; - // GC Cube Texture - continueTimer |= CollectGarbages(mCubeTextureCache, fullCollect, mCubeTextureContainerUpdated, mLatestCollectedCubeTextureIter, checkedCount); + // We should lock mutex during GC pixelData. + mDataMutex.lock(); // GC Texture - continueTimer |= CollectGarbages(mTextureCache, fullCollect, mTextureContainerUpdated, mLatestCollectedTextureIter, checkedCount); + continueTimer |= CollectGarbages(mTextureCache, fullCollect, mTextureContainerUpdated, mLatestCollectedTextureIter, checkedCount, collectedCount); + + // GC PixelData last. If there are some collected Texture before, we should full-collect. + // (Since most of PixelData use 'ReleaseAfterUpload' flags). + continueTimer |= CollectGarbages(mPixelDataCache, fullCollect || (collectedCount > 0u), mPixelDataContainerUpdated, mLatestCollectedPixelDataIter, checkedCount, collectedCount); + + mDataMutex.unlock(); - // GC PixelData. We should lock mutex during GC pixelData. - continueTimer |= CollectGarbages(mPixelDataCache, fullCollect, mPixelDataContainerUpdated, mLatestCollectedPixelDataIter, checkedCount); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GC finished. checkedCount : %u, continueTimer : %d\n", checkedCount, continueTimer); return continueTimer; } private: - PixelDataCacheContainer mPixelDataCache; - TextureCacheContainer mTextureCache; - CubeTextureCacheContainer mCubeTextureCache; + PixelDataCacheContainer mPixelDataCache; + TextureCacheContainer mTextureCache; Dali::Timer mTimer; // Be used when we garbage collection. - PixelDataCacheContainer::iterator mLatestCollectedPixelDataIter; - TextureCacheContainer::iterator mLatestCollectedTextureIter; - CubeTextureCacheContainer::iterator mLatestCollectedCubeTextureIter; + PixelDataCacheContainer::iterator mLatestCollectedPixelDataIter; + TextureCacheContainer::iterator mLatestCollectedTextureIter; + + std::mutex mDataMutex; bool mPixelDataContainerUpdated; bool mTextureContainerUpdated; - bool mCubeTextureContainerUpdated; - - std::mutex mDataMutex; bool mDestroyed : 1; bool mFullCollectRequested : 1; @@ -553,6 +498,7 @@ private: static std::shared_ptr gCacheImpl{nullptr}; static Dali::Texture gEmptyTextureWhiteRGB{}; +static Dali::Texture gEmptyCubeTextureWhiteRGB{}; std::shared_ptr GetCacheImpl() { @@ -569,6 +515,7 @@ void DestroyCacheImpl() // Remove texture object when application stopped. gEmptyTextureWhiteRGB.Reset(); + gEmptyCubeTextureWhiteRGB.Reset(); } } // namespace @@ -589,27 +536,29 @@ Dali::Texture GetEmptyTextureWhiteRGB() return gEmptyTextureWhiteRGB; } -Dali::Texture GetCachedTexture(Dali::PixelData pixelData, bool mipmapRequired) +Dali::Texture GetEmptyCubeTextureWhiteRGB() { - if(SupportPixelDataCache(pixelData)) + if(!gEmptyCubeTextureWhiteRGB) { - return GetCacheImpl()->GetOrCreateCachedTexture(pixelData, mipmapRequired); - } - else - { - return CreateTextureFromPixelData(pixelData, mipmapRequired); + Dali::PixelData emptyPixelData = GetEmptyPixelDataWhiteRGB(); + gEmptyCubeTextureWhiteRGB = Texture::New(TextureType::TEXTURE_CUBE, emptyPixelData.GetPixelFormat(), emptyPixelData.GetWidth(), emptyPixelData.GetHeight()); + for(size_t iSide = 0u; iSide < 6; ++iSide) + { + gEmptyCubeTextureWhiteRGB.Upload(emptyPixelData, CubeMapLayer::POSITIVE_X + iSide, 0u, 0u, 0u, emptyPixelData.GetWidth(), emptyPixelData.GetHeight()); + } } + return gEmptyCubeTextureWhiteRGB; } -Dali::Texture GetCachedCubeTexture(const std::vector>& pixelDataList, bool mipmapRequired) +Dali::Texture GetCachedTexture(Dali::PixelData pixelData, bool mipmapRequired) { - if(SupportPixelDataListCache(pixelDataList)) + if(SupportPixelDataCache(pixelData)) { - return GetCacheImpl()->GetOrCreateCachedCubeTexture(pixelDataList, mipmapRequired); + return GetCacheImpl()->GetOrCreateCachedTexture(pixelData, mipmapRequired); } else { - return CreateCubeTextureFromPixelDataList(pixelDataList, mipmapRequired); + return CreateTextureFromPixelData(pixelData, mipmapRequired); } } diff --git a/dali-scene3d/internal/common/image-resource-loader.h b/dali-scene3d/internal/common/image-resource-loader.h index df0d9e77d5..3957009344 100644 --- a/dali-scene3d/internal/common/image-resource-loader.h +++ b/dali-scene3d/internal/common/image-resource-loader.h @@ -48,20 +48,18 @@ namespace ImageResourceLoader Dali::Texture GetEmptyTextureWhiteRGB(); /** - * @brief Get cached texture handle, or create new texture and upload. - * @param[in] pixelData The PixelData of image to upload - * @param[in] mipmapRequired True if this texture need to generate mipmap - * @return A Texture object containing the pixelData, or an invalid object on failure + * @brief Get cached cube texture handle filled as white with RGB888 format at 6 faces. + * @return A Texture object containing the white RGB888 color at 6 faces. */ -Dali::Texture GetCachedTexture(Dali::PixelData pixelData, bool mipmapRequired); +Dali::Texture GetEmptyCubeTextureWhiteRGB(); /** - * @brief Get cached cube texture handle, or create new texture and upload. - * @param[in] pixelDataList The list of PixelData to upload. pixelDataList[FACE_OF_CUBE][MIPMAP_LEVEL]. + * @brief Get cached texture handle, or create new texture and upload. + * @param[in] pixelData The PixelData of image to upload * @param[in] mipmapRequired True if this texture need to generate mipmap * @return A Texture object containing the pixelData, or an invalid object on failure */ -Dali::Texture GetCachedCubeTexture(const std::vector>& pixelDataList, bool mipmapRequired); +Dali::Texture GetCachedTexture(Dali::PixelData pixelData, bool mipmapRequired); /** * @brief Request to remove unused Texture and PixelData. We can choose the collect garbages incrementally or fully. diff --git a/dali-scene3d/internal/model-components/model-primitive-impl.cpp b/dali-scene3d/internal/model-components/model-primitive-impl.cpp index 1adf514988..fb5a9042a0 100644 --- a/dali-scene3d/internal/model-components/model-primitive-impl.cpp +++ b/dali-scene3d/internal/model-components/model-primitive-impl.cpp @@ -402,14 +402,7 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture(); if(!mSpecularTexture || !mDiffuseTexture) { - Scene3D::Loader::EnvironmentMapData environmentMapData; - environmentMapData.mPixelData.resize(6); - for(auto& face : environmentMapData.mPixelData) - { - face.push_back(Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyPixelDataWhiteRGB()); - } - environmentMapData.SetEnvironmentMapType(Dali::Scene3D::EnvironmentMapType::CUBEMAP); - Texture iblTexture = environmentMapData.GetTexture(); + Texture iblTexture = Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyCubeTextureWhiteRGB(); mDiffuseTexture = iblTexture; mSpecularTexture = iblTexture; } diff --git a/dali-scene3d/public-api/loader/environment-definition.cpp b/dali-scene3d/public-api/loader/environment-definition.cpp index 877f0ea9f0..9c74f23f02 100644 --- a/dali-scene3d/public-api/loader/environment-definition.cpp +++ b/dali-scene3d/public-api/loader/environment-definition.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/dali-scene3d/public-api/loader/environment-map-data.cpp b/dali-scene3d/public-api/loader/environment-map-data.cpp index f7472c4d11..3b7f878c91 100644 --- a/dali-scene3d/public-api/loader/environment-map-data.cpp +++ b/dali-scene3d/public-api/loader/environment-map-data.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,11 +38,31 @@ Texture EnvironmentMapData::GetTexture() { if(mEnvironmentMapType == Scene3D::EnvironmentMapType::CUBEMAP) { - mEnvironmentMapTexture = Dali::Scene3D::Internal::ImageResourceLoader::GetCachedCubeTexture(mPixelData, mPixelData[0].size() == 1u); + // Check for the default case, that we might share the graphic resources + if(mPixelData[0].size() > 0u) + { + if(mPixelData[0][0] == Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyPixelDataWhiteRGB()) + { + mEnvironmentMapTexture = Dali::Scene3D::Internal::ImageResourceLoader::GetEmptyCubeTextureWhiteRGB(); + } + else + { + mEnvironmentMapTexture = Texture::New(TextureType::TEXTURE_CUBE, mPixelData[0][0].GetPixelFormat(), mPixelData[0][0].GetWidth(), mPixelData[0][0].GetHeight()); + for(size_t iSide = 0u, iEndSize = mPixelData.size(); iSide < iEndSize; ++iSide) + { + auto& side = mPixelData[iSide]; + for(size_t iMipLevel = 0u, iEndMipLevel = mPixelData[0].size(); iMipLevel < iEndMipLevel; ++iMipLevel) + { + mEnvironmentMapTexture.Upload(side[iMipLevel], CubeMapLayer::POSITIVE_X + iSide, iMipLevel, 0u, 0u, side[iMipLevel].GetWidth(), side[iMipLevel].GetHeight()); + } + } + } + } } else { - mEnvironmentMapTexture = Dali::Scene3D::Internal::ImageResourceLoader::GetCachedTexture(mPixelData[0][0], mPixelData[0].size() == 1u); + mEnvironmentMapTexture = Texture::New(TextureType::TEXTURE_2D, mPixelData[0][0].GetPixelFormat(), mPixelData[0][0].GetWidth(), mPixelData[0][0].GetHeight()); + mEnvironmentMapTexture.Upload(mPixelData[0][0], 0, 0, 0, 0, mPixelData[0][0].GetWidth(), mPixelData[0][0].GetHeight()); } // If mipmap is not defined explicitly, use GenerateMipmaps. diff --git a/dali-scene3d/public-api/loader/resource-bundle.cpp b/dali-scene3d/public-api/loader/resource-bundle.cpp index 6b4dde6949..2af4da4fbf 100644 --- a/dali-scene3d/public-api/loader/resource-bundle.cpp +++ b/dali-scene3d/public-api/loader/resource-bundle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ #include // EXTERNAL INCLUDES +#include #include #include #include -- 2.34.1