[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / common / model-cache-manager.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/internal/common/model-cache-manager.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/devel-api/common/singleton-service.h>
24 #include <dali/devel-api/threading/mutex.h>
25 #include <dali/public-api/object/base-object.h>
26
27 #include <mutex>
28
29 // INTERNAL INCLUDES
30 #include <dali-scene3d/internal/common/image-resource-loader.h>
31 #include <dali-scene3d/public-api/loader/load-result.h>
32 #include <dali-scene3d/public-api/loader/scene-definition.h>
33
34 namespace Dali::Scene3D::Internal
35 {
36 class ModelCacheManager::Impl : public Dali::BaseObject
37 {
38 public:
39   /**
40    * @brief Constructor
41    */
42   Impl()
43   {
44     // Try to create ResourceLoader here, to ensure that we create it on main thread.
45     Dali::Scene3D::Internal::ImageResourceLoader::EnsureResourceLoaderCreated();
46   }
47
48   Dali::Scene3D::Loader::LoadResult GetModelLoadResult(std::string modelUri)
49   {
50     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
51     ModelCache&             cache = mModelCache[modelUri];
52     return Dali::Scene3D::Loader::LoadResult{cache.resources, cache.scene, cache.metaData, cache.animationDefinitions, cache.amimationGroupDefinitions, cache.cameraParameters, cache.lights};
53   }
54
55   void LockModelLoadScene(std::string modelUri)
56   {
57     // To avoid dead-lock, do not use mModelCacheMutex here
58     auto& modelMutex = GetLoadSceneMutexInstance(modelUri);
59     modelMutex.lock();
60   }
61
62   void UnlockModelLoadScene(std::string modelUri)
63   {
64     // To avoid dead-lock, do not use mModelCacheMutex here
65     auto& modelMutex = GetLoadSceneMutexInstance(modelUri);
66     modelMutex.unlock();
67   }
68
69   uint32_t GetModelCacheRefCount(std::string modelUri)
70   {
71     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
72     ModelCache&             cache = mModelCache[modelUri];
73     return cache.refCount;
74   }
75
76   void ReferenceModelCache(std::string modelUri)
77   {
78     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
79     ModelCache&             cache = mModelCache[modelUri];
80     cache.refCount++;
81   }
82
83   void UnreferenceModelCache(std::string modelUri)
84   {
85     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
86     ModelCache&             cache = mModelCache[modelUri];
87     if(cache.refCount > 0)
88     {
89       cache.refCount--;
90     }
91
92     if(cache.refCount == 0)
93     {
94       mModelCache.erase(modelUri);
95
96       // Request image resource GC
97       Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
98     }
99   }
100
101   bool IsSceneLoaded(std::string modelUri)
102   {
103     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
104     ModelCache&             cache = mModelCache[modelUri];
105     return cache.isSceneLoaded;
106   }
107
108   void SetSceneLoaded(std::string modelUri, bool isSceneLoaded)
109   {
110     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
111     ModelCache&             cache = mModelCache[modelUri];
112     cache.isSceneLoaded           = isSceneLoaded;
113   }
114
115   bool IsSceneLoading(std::string modelUri)
116   {
117     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
118     ModelCache&             cache = mModelCache[modelUri];
119     return cache.isSceneLoading;
120   }
121
122   void SetSceneLoading(std::string modelUri, bool isSceneLoading)
123   {
124     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
125     ModelCache&             cache = mModelCache[modelUri];
126     cache.isSceneLoading          = isSceneLoading;
127   }
128
129 protected:
130   /**
131    * A reference counted object may only be deleted by calling Unreference()
132    */
133   virtual ~Impl()
134   {
135   }
136
137 private:
138   /**
139    * @brief Retrieves the mutex object to synchronize the scene loading of the model
140    * with the given URI between multiple threads.
141    * @param[in] modelUri The unique model URI with its absolute path.
142    * @return The mutex object.
143    */
144   std::mutex& GetLoadSceneMutexInstance(std::string modelUri)
145   {
146     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
147     ModelCache&             cache = mModelCache[modelUri];
148     return cache.loadSceneMutex;
149   }
150
151 private:
152   struct ModelCache
153   {
154     Dali::Scene3D::Loader::ResourceBundle  resources{}; ///< The bundle to store resources in.
155     Dali::Scene3D::Loader::SceneDefinition scene{};     ///< The scene definition to populate.
156     Dali::Scene3D::Loader::SceneMetadata   metaData{};  ///< The metadata of the scene.
157
158     std::vector<Dali::Scene3D::Loader::AnimationDefinition>      animationDefinitions{};      ///< The list of animation definitions, in lexicographical order of their names.
159     std::vector<Dali::Scene3D::Loader::AnimationGroupDefinition> amimationGroupDefinitions{}; ///< The list of animation group definitions, in lexicographical order of their names.
160     std::vector<Dali::Scene3D::Loader::CameraParameters>         cameraParameters{};          ///< The camera parameters that were loaded from the scene.
161     std::vector<Dali::Scene3D::Loader::LightParameters>          lights{};                    ///< The light parameters that were loaded from the scene.
162
163     uint32_t   refCount{0};      ///< The reference count of this model cache.
164     std::mutex loadSceneMutex{}; ///< The mutex instance used to synchronise the loading of the scene for the same model in different threads.
165
166     bool isSceneLoaded{false};  ///< Whether the scene of the model has been loaded.
167     bool isSceneLoading{false}; ///< Whether the scene loading of the model is in progress.
168   };
169
170   // Note : We should use some container that the element memory pointer is not changed due to LoadResult and loadSceneMutex validation.
171   using ModelResourceCache = std::map<std::string, ModelCache>;
172   ModelResourceCache mModelCache;
173
174   Dali::Mutex mModelCacheMutex;
175 };
176
177 ModelCacheManager::ModelCacheManager() = default;
178
179 ModelCacheManager::~ModelCacheManager() = default;
180
181 ModelCacheManager ModelCacheManager::Get()
182 {
183   ModelCacheManager manager;
184
185   // Check whether the ModelCacheManager is already created
186   SingletonService singletonService(SingletonService::Get());
187   if(singletonService)
188   {
189     Dali::BaseHandle handle = singletonService.GetSingleton(typeid(ModelCacheManager));
190     if(handle)
191     {
192       // If so, downcast the handle of singleton to ModelCacheManager
193       manager = ModelCacheManager(dynamic_cast<ModelCacheManager::Impl*>(handle.GetObjectPtr()));
194     }
195
196     if(!manager)
197     {
198       // If not, create the ModelCacheManager and register it as a singleton
199       manager = ModelCacheManager(new ModelCacheManager::Impl());
200       singletonService.Register(typeid(manager), manager);
201     }
202   }
203
204   return manager;
205 }
206
207 ModelCacheManager::ModelCacheManager(ModelCacheManager::Impl* impl)
208 : BaseHandle(impl)
209 {
210 }
211
212 Dali::Scene3D::Loader::LoadResult ModelCacheManager::GetModelLoadResult(std::string modelUri)
213 {
214   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
215   return impl.GetModelLoadResult(modelUri);
216 }
217
218 void ModelCacheManager::LockModelLoadScene(std::string modelUri)
219 {
220   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
221   return impl.LockModelLoadScene(modelUri);
222 }
223
224 void ModelCacheManager::UnlockModelLoadScene(std::string modelUri)
225 {
226   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
227   return impl.UnlockModelLoadScene(modelUri);
228 }
229
230 uint32_t ModelCacheManager::GetModelCacheRefCount(std::string modelUri)
231 {
232   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
233   return impl.GetModelCacheRefCount(modelUri);
234 }
235
236 void ModelCacheManager::ReferenceModelCache(std::string modelUri)
237 {
238   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
239   impl.ReferenceModelCache(modelUri);
240 }
241
242 void ModelCacheManager::UnreferenceModelCache(std::string modelUri)
243 {
244   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
245   impl.UnreferenceModelCache(modelUri);
246 }
247
248 bool ModelCacheManager::IsSceneLoaded(std::string modelUri)
249 {
250   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
251   return impl.IsSceneLoaded(modelUri);
252 }
253
254 void ModelCacheManager::SetSceneLoaded(std::string modelUri, bool isSceneLoaded)
255 {
256   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
257   impl.SetSceneLoaded(modelUri, isSceneLoaded);
258 }
259
260 bool ModelCacheManager::IsSceneLoading(std::string modelUri)
261 {
262   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
263   return impl.IsSceneLoading(modelUri);
264 }
265
266 void ModelCacheManager::SetSceneLoading(std::string modelUri, bool isSceneLoading)
267 {
268   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
269   impl.SetSceneLoading(modelUri, isSceneLoading);
270 }
271
272 } // namespace Dali::Scene3D::Internal