Remove cubemap cache temperary + Fix bug when Uploaded PixelData resue after Texture GC 51/304251/4
authorEunki Hong <eunkiki.hong@samsung.com>
Sat, 13 Jan 2024 00:28:27 +0000 (09:28 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 15 Jan 2024 01:55:33 +0000 (10:55 +0900)
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 <eunkiki.hong@samsung.com>
automated-tests/src/dali-scene3d/utc-Dali-EnvironmentDefinition.cpp
dali-scene3d/internal/common/environment-map-load-task.cpp
dali-scene3d/internal/common/image-resource-loader.cpp
dali-scene3d/internal/common/image-resource-loader.h
dali-scene3d/internal/model-components/model-primitive-impl.cpp
dali-scene3d/public-api/loader/environment-definition.cpp
dali-scene3d/public-api/loader/environment-map-data.cpp
dali-scene3d/public-api/loader/resource-bundle.cpp

index 5dd2f1c..8d5e694 100644 (file)
@@ -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 <dali-test-suite-utils.h>
 #include <string_view>
+#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);
index 8bc8239..385eb39 100644 (file)
@@ -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 <dali-scene3d/internal/common/environment-map-load-task.h>
 
 // INTERNAL INCLUDES
+#include <dali-scene3d/internal/common/image-resource-loader.h>
 #include <dali-scene3d/public-api/loader/environment-map-loader.h>
 
 namespace Dali
index 3403cfa..bc1a21d 100644 (file)
@@ -36,6 +36,7 @@
 #include <functional> ///< for std::function
 #include <memory>     ///< for std::shared_ptr
 #include <mutex>
+#include <sstream>
 #include <string>
 #include <utility> ///< 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<std::vector<Dali::PixelData>>& 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<std::size_t>(static_cast<void*>(pixelData.GetObjectPtr())) ^ (static_cast<std::size_t>(mipmapRequired) << (sizeof(std::size_t) * 4));
 }
 
-std::size_t GenerateHash(const std::vector<std::vector<Dali::PixelData>>& 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<std::size_t>(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<std::vector<Dali::PixelData>>& 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<std::size_t, std::vector<std::pair<ImageInformation, Dali::PixelData>>>;
-  using TextureCacheContainer     = std::map<std::size_t, std::vector<std::pair<Dali::PixelData, Dali::Texture>>>;
-  using CubeTextureCacheContainer = std::map<std::size_t, std::vector<std::pair<std::vector<std::vector<Dali::PixelData>>, Dali::Texture>>>;
+  using PixelDataCacheContainer = std::map<std::size_t, std::vector<std::pair<ImageInformation, Dali::PixelData>>>;
+  using TextureCacheContainer   = std::map<std::size_t, std::vector<std::pair<Dali::PixelData, Dali::Texture>>>;
 
   /**
    * @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 needMutex, typename ContainerType, typename Iterator = typename ContainerType::iterator>
-  bool CollectGarbages(ContainerType& cacheContainer, bool fullCollect, bool& containerUpdated, Iterator& lastIterator, uint32_t& checkedCount)
+  template<typename KeyType, typename ValueType, bool (*Collectable)(const KeyType&, const ValueType&), typename ContainerType, typename Iterator = typename ContainerType::iterator>
+  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());
   }
 
@@ -435,19 +392,6 @@ public: // Called by main thread.
   }
 
   /**
-   * @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<std::vector<Dali::PixelData>>& pixelDataList, bool mipmapRequired)
-  {
-    auto hashValue = GenerateHash(pixelDataList, mipmapRequired);
-    return GetOrCreateCachedItem<false, std::vector<std::vector<Dali::PixelData>>, Dali::Texture, CreateCubeTextureFromPixelDataList>(mCubeTextureCache, hashValue, pixelDataList, mipmapRequired, mCubeTextureContainerUpdated);
-  }
-
-  /**
    * @brief Request incremental gargabe collect.
    *
    * @param[in] fullCollect True if we will collect whole items, or incrementally.
@@ -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<false>(mCubeTextureCache, fullCollect, mCubeTextureContainerUpdated, mLatestCollectedCubeTextureIter, checkedCount);
+    // We should lock mutex during GC pixelData.
+    mDataMutex.lock();
 
     // GC Texture
-    continueTimer |= CollectGarbages<false>(mTextureCache, fullCollect, mTextureContainerUpdated, mLatestCollectedTextureIter, checkedCount);
+    continueTimer |= CollectGarbages<Dali::PixelData, Dali::Texture, TextureCacheCollectable>(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<ImageInformation, Dali::PixelData, PixelDataCacheCollectable>(mPixelDataCache, fullCollect || (collectedCount > 0u), mPixelDataContainerUpdated, mLatestCollectedPixelDataIter, checkedCount, collectedCount);
+
+    mDataMutex.unlock();
 
-    // GC PixelData. We should lock mutex during GC pixelData.
-    continueTimer |= CollectGarbages<true>(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<CacheImpl> gCacheImpl{nullptr};
 static Dali::Texture              gEmptyTextureWhiteRGB{};
+static Dali::Texture              gEmptyCubeTextureWhiteRGB{};
 
 std::shared_ptr<CacheImpl> 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<std::vector<Dali::PixelData>>& 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);
   }
 }
 
index df0d9e7..3957009 100644 (file)
@@ -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<std::vector<Dali::PixelData>>& 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.
index 1adf514..fb5a904 100644 (file)
@@ -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;
     }
index 877f0ea..9c74f23 100644 (file)
@@ -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.
index f7472c4..3b7f878 100644 (file)
@@ -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.
index 6b4dde6..2af4da4 100644 (file)
@@ -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 <dali-scene3d/public-api/loader/resource-bundle.h>
 
 // EXTERNAL INCLUDES
+#include <dali-scene3d/internal/common/image-resource-loader.h>
 #include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
 #include <dali/public-api/rendering/sampler.h>
 #include <cstring>