bb826fb382bd52d0b2001243b1dbd6d0b5f79dcf
[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   }
45
46   Dali::Scene3D::Loader::LoadResult GetModelLoadResult(std::string modelUri)
47   {
48     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
49     ModelCache&             cache = mModelCache[modelUri];
50     return Dali::Scene3D::Loader::LoadResult{cache.resources, cache.scene, cache.metaData, cache.animationDefinitions, cache.amimationGroupDefinitions, cache.cameraParameters, cache.lights};
51   }
52
53   void LockModelLoadScene(std::string modelUri)
54   {
55     // To avoid dead-lock, do not use mModelCacheMutex here
56     auto& modelMutex = GetLoadSceneMutexInstance(modelUri);
57     modelMutex.lock();
58   }
59
60   void UnlockModelLoadScene(std::string modelUri)
61   {
62     // To avoid dead-lock, do not use mModelCacheMutex here
63     auto& modelMutex = GetLoadSceneMutexInstance(modelUri);
64     modelMutex.unlock();
65   }
66
67   uint32_t GetModelCacheRefCount(std::string modelUri)
68   {
69     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
70     ModelCache&             cache = mModelCache[modelUri];
71     return cache.refCount;
72   }
73
74   void ReferenceModelCache(std::string modelUri)
75   {
76     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
77     ModelCache&             cache = mModelCache[modelUri];
78     cache.refCount++;
79   }
80
81   void UnreferenceModelCache(std::string modelUri)
82   {
83     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
84     ModelCache&             cache = mModelCache[modelUri];
85     if(cache.refCount > 0)
86     {
87       cache.refCount--;
88     }
89
90     if(cache.refCount == 0)
91     {
92       mModelCache.erase(modelUri);
93
94       // Request image resource GC
95       Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
96     }
97   }
98
99   bool IsSceneLoaded(std::string modelUri)
100   {
101     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
102     ModelCache&             cache = mModelCache[modelUri];
103     return cache.isSceneLoaded;
104   }
105
106   void SetSceneLoaded(std::string modelUri, bool isSceneLoaded)
107   {
108     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
109     ModelCache&             cache = mModelCache[modelUri];
110     cache.isSceneLoaded           = isSceneLoaded;
111   }
112
113   bool IsSceneLoading(std::string modelUri)
114   {
115     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
116     ModelCache&             cache = mModelCache[modelUri];
117     return cache.isSceneLoading;
118   }
119
120   void SetSceneLoading(std::string modelUri, bool isSceneLoading)
121   {
122     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
123     ModelCache&             cache = mModelCache[modelUri];
124     cache.isSceneLoading          = isSceneLoading;
125   }
126
127 protected:
128   /**
129    * A reference counted object may only be deleted by calling Unreference()
130    */
131   virtual ~Impl()
132   {
133   }
134
135 private:
136   /**
137    * @brief Retrieves the mutex object to synchronize the scene loading of the model
138    * with the given URI between multiple threads.
139    * @param[in] modelUri The unique model URI with its absolute path.
140    * @return The mutex object.
141    */
142   std::mutex& GetLoadSceneMutexInstance(std::string modelUri)
143   {
144     Dali::Mutex::ScopedLock lock(mModelCacheMutex);
145     ModelCache&             cache = mModelCache[modelUri];
146     return cache.loadSceneMutex;
147   }
148
149 private:
150   struct ModelCache
151   {
152     Dali::Scene3D::Loader::ResourceBundle  resources{}; ///< The bundle to store resources in.
153     Dali::Scene3D::Loader::SceneDefinition scene{};     ///< The scene definition to populate.
154     Dali::Scene3D::Loader::SceneMetadata   metaData{};  ///< The metadata of the scene.
155
156     std::vector<Dali::Scene3D::Loader::AnimationDefinition>      animationDefinitions{};      ///< The list of animation definitions, in lexicographical order of their names.
157     std::vector<Dali::Scene3D::Loader::AnimationGroupDefinition> amimationGroupDefinitions{}; ///< The list of animation group definitions, in lexicographical order of their names.
158     std::vector<Dali::Scene3D::Loader::CameraParameters>         cameraParameters{};          ///< The camera parameters that were loaded from the scene.
159     std::vector<Dali::Scene3D::Loader::LightParameters>          lights{};                    ///< The light parameters that were loaded from the scene.
160
161     uint32_t   refCount{0};      ///< The reference count of this model cache.
162     std::mutex loadSceneMutex{}; ///< The mutex instance used to synchronise the loading of the scene for the same model in different threads.
163
164     bool isSceneLoaded{false};  ///< Whether the scene of the model has been loaded.
165     bool isSceneLoading{false}; ///< Whether the scene loading of the model is in progress.
166   };
167
168   // Note : We should use some container that the element memory pointer is not changed due to LoadResult and loadSceneMutex validation.
169   using ModelResourceCache = std::map<std::string, ModelCache>;
170   ModelResourceCache mModelCache;
171
172   Dali::Mutex mModelCacheMutex;
173 };
174
175 ModelCacheManager::ModelCacheManager() = default;
176
177 ModelCacheManager::~ModelCacheManager() = default;
178
179 ModelCacheManager ModelCacheManager::Get()
180 {
181   ModelCacheManager manager;
182
183   // Check whether the ModelCacheManager is already created
184   SingletonService singletonService(SingletonService::Get());
185   if(singletonService)
186   {
187     Dali::BaseHandle handle = singletonService.GetSingleton(typeid(ModelCacheManager));
188     if(handle)
189     {
190       // If so, downcast the handle of singleton to ModelCacheManager
191       manager = ModelCacheManager(dynamic_cast<ModelCacheManager::Impl*>(handle.GetObjectPtr()));
192     }
193
194     if(!manager)
195     {
196       // If not, create the ModelCacheManager and register it as a singleton
197       manager = ModelCacheManager(new ModelCacheManager::Impl());
198       singletonService.Register(typeid(manager), manager);
199     }
200   }
201
202   return manager;
203 }
204
205 ModelCacheManager::ModelCacheManager(ModelCacheManager::Impl* impl)
206 : BaseHandle(impl)
207 {
208 }
209
210 Dali::Scene3D::Loader::LoadResult ModelCacheManager::GetModelLoadResult(std::string modelUri)
211 {
212   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
213   return impl.GetModelLoadResult(modelUri);
214 }
215
216 void ModelCacheManager::LockModelLoadScene(std::string modelUri)
217 {
218   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
219   return impl.LockModelLoadScene(modelUri);
220 }
221
222 void ModelCacheManager::UnlockModelLoadScene(std::string modelUri)
223 {
224   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
225   return impl.UnlockModelLoadScene(modelUri);
226 }
227
228 uint32_t ModelCacheManager::GetModelCacheRefCount(std::string modelUri)
229 {
230   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
231   return impl.GetModelCacheRefCount(modelUri);
232 }
233
234 void ModelCacheManager::ReferenceModelCache(std::string modelUri)
235 {
236   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
237   impl.ReferenceModelCache(modelUri);
238 }
239
240 void ModelCacheManager::UnreferenceModelCache(std::string modelUri)
241 {
242   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
243   impl.UnreferenceModelCache(modelUri);
244 }
245
246 bool ModelCacheManager::IsSceneLoaded(std::string modelUri)
247 {
248   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
249   return impl.IsSceneLoaded(modelUri);
250 }
251
252 void ModelCacheManager::SetSceneLoaded(std::string modelUri, bool isSceneLoaded)
253 {
254   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
255   impl.SetSceneLoaded(modelUri, isSceneLoaded);
256 }
257
258 bool ModelCacheManager::IsSceneLoading(std::string modelUri)
259 {
260   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
261   return impl.IsSceneLoading(modelUri);
262 }
263
264 void ModelCacheManager::SetSceneLoading(std::string modelUri, bool isSceneLoading)
265 {
266   ModelCacheManager::Impl& impl = static_cast<ModelCacheManager::Impl&>(GetBaseObject());
267   impl.SetSceneLoading(modelUri, isSceneLoading);
268 }
269
270 } // namespace Dali::Scene3D::Internal