1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "render_data_store_manager.h"
17 
18 #include <cstddef>
19 
20 #include <base/util/uid_util.h>
21 #include <render/datastore/intf_render_data_store.h>
22 #include <render/device/intf_device.h>
23 #include <render/intf_render_context.h>
24 #include <render/namespace.h>
25 
26 #include "util/log.h"
27 
28 using namespace BASE_NS;
29 
RENDER_BEGIN_NAMESPACE()30 RENDER_BEGIN_NAMESPACE()
31 RenderDataStoreManager::RenderDataStoreManager(IRenderContext& renderContext) : renderContext_(renderContext) {}
32 
CommitFrameData()33 void RenderDataStoreManager::CommitFrameData()
34 {
35     // only modify the write index when double buffered in use
36     if (renderDataStoreFlags_ & DOUBLE_BUFFERED_RENDER_DATA_STORES) {
37         frameWriteIndex_ = 1u - frameWriteIndex_;
38     }
39 #if (RENDER_VALIDATION_ENABLED == 1)
40     commitDeviceFrameIndex_ = renderContext_.GetDevice().GetFrameCount();
41 #endif
42 
43     decltype(pendingRenderAccess_) pendingRenderAccess;
44     {
45         std::lock_guard<std::mutex> lock(mutex_);
46         pendingRenderAccess = std::move(pendingRenderAccess_);
47     }
48 
49     // prepare access for render time access
50     for (auto& pendingRef : pendingRenderAccess) {
51         if (pendingRef.destroy) { // remove deferred destruction stores
52             renderAccessStores_.erase(pendingRef.hash);
53         } else {
54             PLUGIN_ASSERT(pendingRef.renderDataStore);
55             renderAccessStores_.insert_or_assign(pendingRef.hash, pendingRef.renderDataStore);
56         }
57     }
58 
59     // all valid stores can be accessed from render access stores without locks
60     for (const auto& ref : renderAccessStores_) {
61         ref.second->CommitFrameData();
62     }
63 }
64 
PreRender()65 void RenderDataStoreManager::PreRender()
66 {
67     // all valid stores can be accessed from render access stores without locks
68     for (const auto& ref : renderAccessStores_) {
69         ref.second->PreRender();
70     }
71 }
72 
PostRender()73 void RenderDataStoreManager::PostRender()
74 {
75     // all valid stores can be accessed from render access stores without locks
76     for (const auto& ref : renderAccessStores_) {
77         ref.second->PostRender();
78     }
79 }
80 
PreRenderBackend()81 void RenderDataStoreManager::PreRenderBackend()
82 {
83     // all valid stores can be accessed from render access stores without locks
84     for (const auto& ref : renderAccessStores_) {
85         ref.second->PreRenderBackend();
86     }
87 }
88 
PostRenderBackend()89 void RenderDataStoreManager::PostRenderBackend()
90 {
91     // all valid stores can be accessed from render access stores without locks
92     for (const auto& ref : renderAccessStores_) {
93         ref.second->PostRenderBackend();
94     }
95 
96     DeferredDestruction();
97 }
98 
GetRenderDataStore(const string_view name) const99 IRenderDataStore* RenderDataStoreManager::GetRenderDataStore(const string_view name) const
100 {
101     if (name.empty()) {
102         return nullptr;
103     }
104 
105     auto const nameHash = hash(name);
106 
107     std::lock_guard<std::mutex> lock(mutex_);
108 
109     if (const auto iter = stores_.find(nameHash); iter != stores_.cend()) {
110         return iter->second.get();
111     } else {
112 #if (RENDER_VALIDATION_ENABLED == 1)
113         PLUGIN_LOG_ONCE_W(
114             name + "_RDS_NOT_FOUND__", "RENDER_VALIDATION: render data store: (%s), not found", name.data());
115 #endif
116         return nullptr;
117     }
118 }
119 
GetRenderTimeRenderDataStore(const string_view name) const120 IRenderDataStore* RenderDataStoreManager::GetRenderTimeRenderDataStore(const string_view name) const
121 {
122     if (name.empty()) {
123         return nullptr;
124     }
125 
126     // not locked
127 
128     auto const nameHash = hash(name);
129     if (const auto iter = renderAccessStores_.find(nameHash); iter != renderAccessStores_.cend()) {
130         return iter->second;
131     } else {
132 #if (RENDER_VALIDATION_ENABLED == 1)
133         PLUGIN_LOG_ONCE_W(
134             name + "_RDS_NOT_FOUND", "RENDER_VALIDATION: render data store: (%s), not found", name.data());
135 #endif
136         return nullptr;
137     }
138 }
139 
Create(const Uid & dataStoreTypeUid,char const * dataStoreName)140 IRenderDataStore* RenderDataStoreManager::Create(const Uid& dataStoreTypeUid, char const* dataStoreName)
141 {
142     auto const dataStoreTypeHash = hash(dataStoreTypeUid);
143     if (auto const factoryIt = factories_.find(dataStoreTypeHash); factoryIt != factories_.end()) {
144         auto const dataStoreNameHash = hash(string_view(dataStoreName));
145         IRenderDataStore* dataStore = nullptr;
146 
147         std::lock_guard<std::mutex> lock(mutex_);
148 
149         if (auto const namedStoreIt = stores_.find(dataStoreNameHash); namedStoreIt != stores_.cend()) {
150             PLUGIN_LOG_D("Named data store already exists (type: %s) (name: %s)", to_string(dataStoreTypeUid).data(),
151                 dataStoreName);
152             dataStore = namedStoreIt->second.get();
153             if (dataStore->GetUid() != dataStoreTypeUid) {
154                 PLUGIN_LOG_E("Named data store (type: %s, name: %s) exists with different type (%s)",
155                     to_string(dataStoreTypeUid).data(), dataStoreName, dataStore->GetTypeName().data());
156                 dataStore = nullptr;
157             }
158         } else {
159             auto const dataStoreIt = stores_.insert_or_assign(dataStoreNameHash,
160                 RenderDataStorePtr { factoryIt->second.createDataStore(renderContext_, dataStoreName),
161                     factoryIt->second.destroyDataStore });
162             pointerToStoreHash_.insert_or_assign(dataStoreIt.first->second.get(), uint64_t { dataStoreNameHash });
163             dataStore = dataStoreIt.first->second.get();
164         }
165 
166         pendingRenderAccess_.push_back({ dataStoreNameHash, dataStore, false });
167         return dataStore;
168     } else {
169         PLUGIN_LOG_E("render data store type not found (type: %s) (named: %s)", to_string(dataStoreTypeUid).data(),
170             dataStoreName);
171         PLUGIN_ASSERT(false);
172     }
173     return nullptr;
174 }
175 
Destroy(const Uid & dataStoreTypeUid,IRenderDataStore * instance)176 void RenderDataStoreManager::Destroy(const Uid& dataStoreTypeUid, IRenderDataStore* instance)
177 {
178     if (instance) {
179         const uint64_t typeHash = hash(dataStoreTypeUid);
180 
181         std::lock_guard<std::mutex> lock(mutex_);
182 
183         deferredDestructionDataStores_.push_back({ typeHash, instance });
184 
185         PLUGIN_ASSERT(pointerToStoreHash_.contains(instance));
186         if (auto const storeIt = pointerToStoreHash_.find(instance); storeIt != pointerToStoreHash_.cend()) {
187             pendingRenderAccess_.push_back({ storeIt->second, instance, true });
188         }
189     }
190 }
191 
GetRenderDataStoreFlags() const192 IRenderDataStoreManager::RenderDataStoreFlags RenderDataStoreManager::GetRenderDataStoreFlags() const
193 {
194     return renderDataStoreFlags_;
195 }
196 
197 #if (RENDER_VALIDATION_ENABLED == 1)
ValidateCommitFrameData() const198 void RenderDataStoreManager::ValidateCommitFrameData() const
199 {
200     if (renderDataStoreFlags_ & DOUBLE_BUFFERED_RENDER_DATA_STORES) {
201         if (commitDeviceFrameIndex_ != renderContext_.GetDevice().GetFrameCount()) {
202             PLUGIN_LOG_E("Render data store manager CommitFrameData() needs to be called before rendering when using "
203                          "double buffered render data stores.");
204         }
205     }
206 }
207 #endif
208 
GetFrameIndices() const209 IRenderDataStoreManager::FrameIndices RenderDataStoreManager::GetFrameIndices() const
210 {
211     if (renderDataStoreFlags_ & DOUBLE_BUFFERED_RENDER_DATA_STORES) {
212         return { frameWriteIndex_, 1u - frameWriteIndex_ };
213     } else {
214         return { frameWriteIndex_, frameWriteIndex_ };
215     }
216 }
217 
DeferredDestruction()218 void RenderDataStoreManager::DeferredDestruction()
219 {
220     std::lock_guard<std::mutex> lock(mutex_);
221 
222     for (const auto& destroyRef : deferredDestructionDataStores_) {
223         if (auto const pos = factories_.find(destroyRef.dataStoreHash); pos != factories_.end()) {
224             if (auto const storeIt = pointerToStoreHash_.find(destroyRef.instance);
225                 storeIt != pointerToStoreHash_.cend()) {
226                 stores_.erase(storeIt->second);
227                 pointerToStoreHash_.erase(storeIt);
228             }
229         }
230     }
231     deferredDestructionDataStores_.clear();
232 }
233 
AddRenderDataStoreFactory(const RenderDataStoreTypeInfo & typeInfo)234 void RenderDataStoreManager::AddRenderDataStoreFactory(const RenderDataStoreTypeInfo& typeInfo)
235 {
236     // plugin load and factory addition is sequential
237     // not locked access
238 
239     if (typeInfo.createDataStore && typeInfo.destroyDataStore) {
240         auto const dataStoreTypeHash = hash(typeInfo.uid);
241         factories_.insert({ dataStoreTypeHash, typeInfo });
242     } else {
243         PLUGIN_LOG_E("RenderDataStoreTypeInfo must provide non-null function pointers");
244         PLUGIN_ASSERT(typeInfo.createDataStore && "createDataStore cannot be null");
245         PLUGIN_ASSERT(typeInfo.destroyDataStore && "destroyDataStore cannot be null");
246     }
247 }
248 
RemoveRenderDataStoreFactory(const RenderDataStoreTypeInfo & typeInfo)249 void RenderDataStoreManager::RemoveRenderDataStoreFactory(const RenderDataStoreTypeInfo& typeInfo)
250 {
251     for (auto b = pointerToStoreHash_.begin(), e = pointerToStoreHash_.end(); b != e;) {
252         if (b->first->GetUid() == typeInfo.uid) {
253             stores_.erase(b->second);
254             b = pointerToStoreHash_.erase(b);
255         } else {
256             ++b;
257         }
258     }
259     auto const dataStoreTypeHash = hash(typeInfo.uid);
260     factories_.erase(dataStoreTypeHash);
261 }
262 
RenderNodeRenderDataStoreManager(const RenderDataStoreManager & renderDataStoreMgr)263 RenderNodeRenderDataStoreManager::RenderNodeRenderDataStoreManager(const RenderDataStoreManager& renderDataStoreMgr)
264     : renderDataStoreMgr_(renderDataStoreMgr)
265 {}
266 
GetRenderDataStore(const string_view name) const267 IRenderDataStore* RenderNodeRenderDataStoreManager::GetRenderDataStore(const string_view name) const
268 {
269     return renderDataStoreMgr_.GetRenderTimeRenderDataStore(name);
270 }
271 RENDER_END_NAMESPACE()
272