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 5dd2f1c2ccc8df3380001c9a64e8a5be42bf2338..8d5e694366651961f35ef2651eb5a80d92de3398 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 8bc82390226d01bddd74ad39548f37b3c84d6dcb..385eb39a25dcd351100ce918f94312708c8325b7 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 3403cfa17b59d6f0da548c9b1fe0cae0199aaee8..bc1a21d16faede7dde18d9bb5c80e8cb5d6e5a90 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());
   }
 
@@ -434,19 +391,6 @@ public: // Called by main thread.
     return GetOrCreateCachedItem<false, Dali::PixelData, Dali::Texture, CreateTextureFromPixelData>(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<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.
    *
@@ -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 df0d9e77d5b2ed53582709007581b3d47bad6670..3957009344081eb45c40073e46cfa1c3f1fb971d 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 1adf514988c4d4c952a724728dbd370ecd48ce74..fb5a9042a01afa43129b1b7069c1f54eb908bc0b 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 877f0ea9f0e935e74779f81ec6a8354244d5e62b..9c74f23f02df949c60f348c9eea3f2d3f5d3989a 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 f7472c4d111683f67663e266e07c5ca0bf9a7e0b..3b7f878c910cfc9cae6ba8bce87c271297836d54 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 6b4dde69492001e7ea361d49bbbdb530423c84fe..2af4da4fbfb611ddf74bef58824a9eb5c14cff6a 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>