• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_node_graph_manager.h"
17 
18 #include <algorithm>
19 #include <cinttypes>
20 #include <cstdint>
21 
22 #include <base/math/mathf.h>
23 #include <core/io/intf_file_manager.h>
24 #if (RENDER_PERF_ENABLED == 1)
25 #include <core/implementation_uids.h>
26 #include <core/perf/intf_performance_data_manager.h>
27 #endif
28 
29 #include <render/namespace.h>
30 #include <render/resource_handle.h>
31 
32 #include "device/device.h"
33 #include "device/gpu_resource_handle_util.h"
34 #include "device/gpu_resource_manager.h"
35 #include "loader/render_node_graph_loader.h"
36 #include "nodecontext/render_node_graph_node_store.h"
37 #include "util/log.h"
38 
39 using namespace BASE_NS;
40 
41 RENDER_BEGIN_NAMESPACE()
42 namespace {
ValidateBackendFlags(const string_view name,const DeviceBackendType backendType,const IRenderNode::BackendFlags backendFlags)43 void ValidateBackendFlags(
44     const string_view name, const DeviceBackendType backendType, const IRenderNode::BackendFlags backendFlags)
45 {
46 #if (RENDER_VALIDATION_ENABLED == 1)
47     if (backendFlags != IRenderNode::BackendFlagBits::BACKEND_FLAG_BITS_DEFAULT) {
48         if ((backendType == DeviceBackendType::VULKAN) &&
49             ((backendFlags & IRenderNode::BackendFlagBits::BACKEND_FLAG_BITS_EXPLICIT_VULKAN) == 0)) {
50             PLUGIN_LOG_E("unsupported (missing vulkan) render node backend flags for render node %s", name.data());
51         } else if ((backendType == DeviceBackendType::OPENGLES) &&
52                    ((backendFlags & IRenderNode::BackendFlagBits::BACKEND_FLAG_BITS_EXPLICIT_GLES) == 0)) {
53             PLUGIN_LOG_E("unsupported (missing gles) render node backend flags for render node %s", name.data());
54         } else if ((backendType == DeviceBackendType::OPENGL) &&
55                    ((backendFlags & IRenderNode::BackendFlagBits::BACKEND_FLAG_BITS_EXPLICIT_GL) == 0)) {
56             PLUGIN_LOG_E("unsupported (missing gl) render node backend flags for render node %s", name.data());
57         }
58     }
59 #endif
60 }
61 } // namespace
62 
RenderNodeGraphManager(Device & device,CORE_NS::IFileManager & fileMgr)63 RenderNodeGraphManager::RenderNodeGraphManager(Device& device, CORE_NS::IFileManager& fileMgr)
64     : device_(device), renderNodeMgr_(make_unique<RenderNodeManager>()),
65       renderNodeGraphLoader_(make_unique<RenderNodeGraphLoader>(fileMgr))
66 {}
67 
~RenderNodeGraphManager()68 RenderNodeGraphManager::~RenderNodeGraphManager()
69 {
70 #if (RENDER_VALIDATION_ENABLED == 1)
71     uint32_t aliveRngCounter = 0;
72     for (const auto& ref : nodeGraphHandles_) {
73         if (ref && (ref.GetRefCount() > 1)) {
74             aliveRngCounter++;
75         }
76     }
77     if (aliveRngCounter > 0) {
78         PLUGIN_LOG_W(
79             "RENDER_VALIDATION: Not all render node graph handle references released (count: %u)", aliveRngCounter);
80     }
81 #endif
82 }
83 
Get(const RenderHandle & handle) const84 RenderHandleReference RenderNodeGraphManager::Get(const RenderHandle& handle) const
85 {
86     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
87         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
88         const auto lock = std::lock_guard(mutex_);
89 
90         if (arrayIndex < static_cast<uint32_t>(nodeGraphHandles_.size())) {
91             return nodeGraphHandles_[arrayIndex];
92         } else {
93             PLUGIN_LOG_E("invalid render node graph handle (id: %" PRIu64 ")", handle.id);
94         }
95     }
96     return RenderHandleReference {};
97 }
98 
LoadAndCreate(const RenderNodeGraphUsageType usage,const string_view uri)99 RenderHandleReference RenderNodeGraphManager::LoadAndCreate(const RenderNodeGraphUsageType usage, const string_view uri)
100 {
101     if (const auto result = renderNodeGraphLoader_->Load(uri); !result.error.empty()) {
102         PLUGIN_LOG_W("Load and create for render node graph failed: %s %s ", uri.data(), result.error.c_str());
103         return {};
104     } else {
105         return Create(usage, result.desc);
106     }
107 }
108 
GetRenderNodeGraphLoader()109 IRenderNodeGraphLoader& RenderNodeGraphManager::GetRenderNodeGraphLoader()
110 {
111     return *renderNodeGraphLoader_;
112 }
113 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc,const string_view renderNodeGraphName,const string_view renderNodeGraphDataStoreName)114 RenderHandleReference RenderNodeGraphManager::Create(const RenderNodeGraphUsageType usage,
115     const RenderNodeGraphDesc& desc, const string_view renderNodeGraphName,
116     const string_view renderNodeGraphDataStoreName)
117 {
118     const auto lock = std::lock_guard(mutex_);
119 
120     uint64_t handleId = INVALID_RESOURCE_HANDLE;
121     bool newHandle = true;
122     if (availableHandleIds_.empty()) { // no available indices
123         handleId = static_cast<uint64_t>(nodeGraphData_.size()) << RenderHandleUtil::RES_HANDLE_ID_SHIFT;
124         newHandle = true;
125     } else {
126         handleId = availableHandleIds_.back();
127         availableHandleIds_.pop_back();
128         newHandle = false;
129     }
130 
131     const uint32_t indexPart = RenderHandleUtil::GetIndexPart(handleId);
132     const uint32_t generationIndexPart = RenderHandleUtil::GetGenerationIndexPart(handleId) + 1; // next gen
133 
134     const RenderHandle handle =
135         RenderHandleUtil::CreateHandle(RenderHandleType::RENDER_NODE_GRAPH, indexPart, generationIndexPart);
136     RenderHandleReference rhr {
137         handle,
138         IRenderReferenceCounter::Ptr(new RenderReferenceCounter()),
139     };
140     if (newHandle) {
141         nodeGraphData_.emplace_back(); // deferred
142         nodeGraphHandles_.push_back(move(rhr));
143         nodeGraphShareData_.emplace_back();
144     } else {
145         nodeGraphData_[indexPart] = {}; // deferred
146         nodeGraphHandles_[indexPart] = move(rhr);
147         nodeGraphShareData_[indexPart] = {};
148     }
149     pendingRenderNodeGraphs_.push_back({
150         PendingRenderNodeGraph::Type::ALLOC,
151         handle,
152         renderNodeGraphName.empty() ? string_view(desc.renderNodeGraphName) : renderNodeGraphName,
153         renderNodeGraphDataStoreName.empty() ? string_view(desc.renderNodeGraphDataStoreName)
154                                              : renderNodeGraphDataStoreName,
155         desc.renderNodeGraphUri,
156         desc,
157         usage,
158     });
159 
160     PLUGIN_ASSERT(indexPart < static_cast<uint32_t>(nodeGraphHandles_.size()));
161     return nodeGraphHandles_[indexPart];
162 }
163 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc,const string_view renderNodeGraphName)164 RenderHandleReference RenderNodeGraphManager::Create(
165     const RenderNodeGraphUsageType usage, const RenderNodeGraphDesc& desc, const string_view renderNodeGraphName)
166 {
167     return Create(usage, desc, renderNodeGraphName, {});
168 }
169 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc)170 RenderHandleReference RenderNodeGraphManager::Create(
171     const RenderNodeGraphUsageType usage, const RenderNodeGraphDesc& desc)
172 {
173     return Create(usage, desc, {}, {});
174 }
175 
Destroy(const RenderHandle handle)176 void RenderNodeGraphManager::Destroy(const RenderHandle handle)
177 {
178     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
179         const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
180         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
181         if (index < static_cast<uint32_t>(nodeGraphHandles_.size())) {
182             const uint32_t storedGenerationIdx =
183                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
184             // ignore if not correct generation index
185             if (generationIdx == storedGenerationIdx) {
186                 pendingRenderNodeGraphs_.push_back({ PendingRenderNodeGraph::Type::DEALLOC, handle, "", "", {}, {} });
187             }
188         }
189     }
190 }
191 
HandlePendingAllocations()192 void RenderNodeGraphManager::HandlePendingAllocations()
193 {
194     // deferred multi-frame destruction for RenderNodeContextData needed
195     const uint64_t minAge = static_cast<uint64_t>(device_.GetCommandBufferingCount()) + 1;
196     const uint64_t ageLimit = (device_.GetFrameCount() < minAge) ? 0 : (device_.GetFrameCount() - minAge);
197 
198     {
199         // needs to be locked the whole time
200         // methods access private members like nodeGraphData_
201         const auto lock = std::lock_guard(mutex_);
202 
203         // check render node graphs for destruction
204         for (auto& rngRef : nodeGraphHandles_) {
205             if (rngRef && (rngRef.GetRefCount() <= 1)) {
206                 Destroy(rngRef.GetHandle());
207             }
208         }
209 
210         // alloc/dealloc individual render node graphs
211         for (const auto& ref : pendingRenderNodeGraphs_) {
212             if (ref.type == PendingRenderNodeGraph::Type::ALLOC) {
213                 PendingCreate(ref);
214             } else if (ref.type == PendingRenderNodeGraph::Type::DEALLOC) {
215                 PendingDestroy(ref.renderNodeGraphHandle);
216             }
217         }
218         pendingRenderNodeGraphs_.clear();
219 
220         // alloc/dealloc individual render nodes
221         for (auto& ref : pendingRenderNodes_) {
222             if (ref.type == PendingRenderNode::Type::ALLOC) {
223                 PendingAllocRenderNode(ref.renderNodeGraphHandle, ref);
224             } else if (ref.type == PendingRenderNode::Type::DEALLOC) {
225                 PendingDeallocRenderNode(ref.renderNodeGraphHandle, ref.renderNodeDesc.nodeName);
226             }
227         }
228         pendingRenderNodes_.clear();
229 
230         // check for updated render node graph inputs / outputs
231         UpdateRenderNodeGraphResources();
232 
233         // multi-frame deferred destructions
234 
235         // render node graph destruction
236         if (!pendingRenderNodeGraphDestructions_.empty()) {
237             const auto oldResources =
238                 std::partition(pendingRenderNodeGraphDestructions_.begin(), pendingRenderNodeGraphDestructions_.end(),
239                     [ageLimit](const auto& destructionQueue) { return destructionQueue.frameIndex >= ageLimit; });
240             pendingRenderNodeGraphDestructions_.erase(oldResources, pendingRenderNodeGraphDestructions_.end());
241         }
242         // individual render node destruction
243         if (!pendingRenderNodeDestructions_.empty()) {
244             const auto oldResources =
245                 std::partition(pendingRenderNodeDestructions_.begin(), pendingRenderNodeDestructions_.end(),
246                     [ageLimit](const auto& destructionQueue) { return destructionQueue.frameIndex >= ageLimit; });
247             pendingRenderNodeDestructions_.erase(oldResources, pendingRenderNodeDestructions_.end());
248         }
249     }
250 }
251 
PendingCreate(const PendingRenderNodeGraph & renderNodeGraph)252 void RenderNodeGraphManager::PendingCreate(const PendingRenderNodeGraph& renderNodeGraph)
253 {
254     unique_ptr<RenderNodeGraphNodeStore> nodeStore = make_unique<RenderNodeGraphNodeStore>();
255     nodeStore->dynamic = (renderNodeGraph.usageType == RenderNodeGraphUsageType::RENDER_NODE_GRAPH_DYNAMIC);
256     nodeStore->initialized = false;
257     nodeStore->renderNodeGraphName = renderNodeGraph.renderNodeGraphName;
258     nodeStore->renderNodeGraphDataStoreName = renderNodeGraph.renderNodeGraphDataStoreName;
259     nodeStore->renderNodeGraphUri = renderNodeGraph.renderNodeGraphUri;
260     // many of the resources are not yet available as handles
261     nodeStore->renderNodeGraphShareDataMgr =
262         make_unique<RenderNodeGraphShareDataManager>(renderNodeGraph.renderNodeGraphDesc.outputResources);
263 
264     const size_t reserveSize = renderNodeGraph.renderNodeGraphDesc.nodes.size();
265     nodeStore->renderNodeData.reserve(reserveSize);
266     nodeStore->renderNodeContextData.reserve(reserveSize);
267     for (const auto& nodeDesc : renderNodeGraph.renderNodeGraphDesc.nodes) {
268         // combined name is used
269         const RenderDataConstants::RenderDataFixedString combinedNodeName =
270             string_view(nodeStore->renderNodeGraphName + nodeDesc.nodeName);
271         auto node = renderNodeMgr_->CreateRenderNode(nodeDesc.typeName.c_str());
272         if (node) {
273             nodeStore->renderNodeData.push_back({
274                 move(node),
275                 nodeDesc.typeName,
276                 combinedNodeName,
277                 nodeDesc.nodeName,
278                 make_unique<RenderNodeGraphInputs>(nodeDesc.description),
279                 nodeDesc.nodeJson,
280             });
281             auto& contextRef = nodeStore->renderNodeContextData.emplace_back();
282             const RenderNodeManager::RenderNodeTypeInfoFlags typeInfoFlags =
283                 renderNodeMgr_->GetRenderNodeTypeInfoFlags(nodeDesc.typeName.c_str());
284             const IRenderNode::ClassType backendNode = static_cast<IRenderNode::ClassType>(typeInfoFlags.classType);
285             contextRef.renderBackendNode =
286                 (backendNode == IRenderNode::ClassType::CLASS_TYPE_BACKEND_NODE)
287                     ? reinterpret_cast<IRenderBackendNode*>(nodeStore->renderNodeData.back().node.get())
288                     : nullptr;
289             ValidateBackendFlags(combinedNodeName, device_.GetBackendType(), typeInfoFlags.backendFlags);
290         } else {
291             PLUGIN_LOG_W("render node type: %s, named: %s, not found and not used", nodeDesc.typeName.c_str(),
292                 nodeDesc.nodeName.c_str());
293         }
294     }
295 
296     // NOTE: currently locked from outside
297     const uint32_t indexPart = RenderHandleUtil::GetIndexPart(renderNodeGraph.renderNodeGraphHandle);
298     PLUGIN_ASSERT(indexPart < nodeGraphData_.size());
299     nodeGraphData_[indexPart] = move(nodeStore);
300 }
301 
302 // needs to be locked when called
PendingDestroy(const RenderHandle handle)303 void RenderNodeGraphManager::PendingDestroy(const RenderHandle handle)
304 {
305     const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
306     if (index >= nodeGraphData_.size()) {
307         PLUGIN_LOG_E("invalid handle (%" PRIu64 ") given to render node Destroy", handle.id);
308         return; // early out
309     }
310     const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
311     const uint32_t storedGenerationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
312     // silently ignore if not correct generation (might be destroyed already)
313     if ((generationIdx != storedGenerationIdx) || (!nodeGraphData_[index])) {
314         return; // early out
315     }
316 #if (RENDER_PERF_ENABLED == 1)
317     if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
318         inst) {
319         if (CORE_NS::IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
320             for (const auto& rnRef : nodeGraphData_[index]->renderNodeData)
321                 perfData->RemoveData(rnRef.fullName);
322         }
323     }
324 #endif
325     // destroy all expect RenderNodeContextData which has command buffers and such
326     // add to destruction queue
327     pendingRenderNodeGraphDestructions_.push_back(PendingRenderNodeGraphDestruction {
328         device_.GetFrameCount(), move(nodeGraphData_[index]->renderNodeContextData) });
329     nodeGraphData_[index] = nullptr;
330     nodeGraphHandles_[index] = {};
331     nodeGraphShareData_[index] = {};
332 
333     // NOTE: this does not erase the RenderNodeGraphNodeStore element from the nodeGraphData_
334     // i.e. the data is invalidated in nodeGraphData_
335 
336     availableHandleIds_.push_back(handle.id);
337 }
338 
339 // needs to be locked when called
PendingDeallocRenderNode(const RenderHandle nodeGraphHandle,const string_view renderNodeName)340 void RenderNodeGraphManager::PendingDeallocRenderNode(
341     const RenderHandle nodeGraphHandle, const string_view renderNodeName)
342 {
343     const uint32_t index = RenderHandleUtil::GetIndexPart(nodeGraphHandle);
344     if (index >= nodeGraphData_.size()) {
345         return; // early out
346     }
347     const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandle);
348     const uint32_t storedGenerationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
349     // silently ignore if not correct generation (render node graph might be destroyed already)
350     if (generationIdx != storedGenerationIdx) {
351         return; // early out
352     }
353     PLUGIN_ASSERT(nodeGraphData_[index]);
354     auto& nodeStoreRef = *nodeGraphData_[index];
355     if (!nodeStoreRef.dynamic) {
356         PLUGIN_LOG_E("RN (name:%s) cannot be erased from non-dynamic render node graph", renderNodeName.data());
357         return; // early out
358     }
359 
360     uint32_t eraseIndex = ~0u;
361     for (size_t eraseIdx = 0; eraseIdx < nodeStoreRef.renderNodeData.size(); ++eraseIdx) {
362         if (nodeStoreRef.renderNodeData[eraseIdx].node &&
363             (nodeStoreRef.renderNodeData[eraseIdx].nodeName == renderNodeName)) {
364             eraseIndex = static_cast<uint32_t>(eraseIdx);
365             break;
366         }
367     }
368     if (eraseIndex <= nodeStoreRef.renderNodeData.size()) {
369 #if (RENDER_PERF_ENABLED == 1)
370         if (auto* inst =
371                 CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
372             inst) {
373             if (CORE_NS::IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
374                 perfData->RemoveData(nodeStoreRef.renderNodeData[eraseIndex].fullName);
375             }
376         }
377 #endif
378         // only RenderNodeContextData needs deferred destruction
379         pendingRenderNodeDestructions_.push_back({
380             device_.GetFrameCount(),
381             move(nodeStoreRef.renderNodeContextData[eraseIndex]),
382         });
383         // NOTE: this erases the elements from the vectors
384         const int32_t iEraseIndex = static_cast<int32_t>(eraseIndex);
385         nodeStoreRef.renderNodeData.erase(nodeStoreRef.renderNodeData.begin() + iEraseIndex);
386         nodeStoreRef.renderNodeContextData.erase(nodeStoreRef.renderNodeContextData.begin() + iEraseIndex);
387     } else {
388         PLUGIN_LOG_E("invalid render node name for erase (%s)", renderNodeName.data());
389     }
390 }
391 
392 // needs to be locked when called
PendingAllocRenderNode(const RenderHandle nodeGraphHandle,const PendingRenderNode & pendingNode)393 void RenderNodeGraphManager::PendingAllocRenderNode(
394     const RenderHandle nodeGraphHandle, const PendingRenderNode& pendingNode)
395 {
396     const uint32_t index = RenderHandleUtil::GetIndexPart(nodeGraphHandle);
397     if (index >= nodeGraphData_.size()) {
398         return; // early out
399     }
400     const uint32_t genIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandle);
401     const uint32_t sGenIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
402     // silently ignore if not correct generation (render node graph might be destroyed already)
403     const auto& desc = pendingNode.renderNodeDesc;
404     if (genIdx != sGenIdx) {
405         return; // early out
406     }
407     PLUGIN_ASSERT(nodeGraphData_[index]);
408     auto& nsRef = *nodeGraphData_[index];
409     if (!nsRef.dynamic) {
410         PLUGIN_LOG_E("RN (name:%s) cannot be add to non-dynamic render node graph", desc.nodeName.c_str());
411         return; // early out
412     }
413     const RenderDataConstants::RenderDataFixedString combinedNodeName =
414         string_view(nsRef.renderNodeGraphName + desc.nodeName);
415     if (auto node = renderNodeMgr_->CreateRenderNode(desc.typeName.c_str()); node) {
416         uint32_t pos = ~0u;
417         if (pendingNode.posType == PendingRenderNode::PosType::BACK) {
418             pos = static_cast<uint32_t>(nsRef.renderNodeData.size());
419         } else {
420             for (uint32_t rnIdx = 0; rnIdx < nsRef.renderNodeData.size(); ++rnIdx) {
421                 const auto& currDataRef = nsRef.renderNodeData[rnIdx];
422                 if (currDataRef.node && (pendingNode.renderNodeName == currDataRef.nodeName)) {
423                     pos = (pendingNode.posType == PendingRenderNode::PosType::AFTER) ? rnIdx + 1 : rnIdx;
424                     break;
425                 }
426             }
427         }
428         if ((pos <= static_cast<uint32_t>(nsRef.renderNodeData.size())) && (pos != ~0u)) {
429             const RenderNodeManager::RenderNodeTypeInfoFlags tiFlags =
430                 renderNodeMgr_->GetRenderNodeTypeInfoFlags(desc.typeName.c_str());
431             const IRenderNode::ClassType backendNode = static_cast<IRenderNode::ClassType>(tiFlags.classType);
432             RenderNodeContextData rncd;
433             rncd.renderBackendNode = (backendNode == IRenderNode::ClassType::CLASS_TYPE_BACKEND_NODE)
434                                          ? reinterpret_cast<IRenderBackendNode*>(node.get())
435                                          : nullptr;
436             rncd.initialized = false;
437             ValidateBackendFlags(desc.typeName, device_.GetBackendType(), tiFlags.backendFlags);
438             nsRef.renderNodeContextData.insert(
439                 nsRef.renderNodeContextData.cbegin() + static_cast<ptrdiff_t>(pos), move(rncd));
440             nsRef.renderNodeData.insert(nsRef.renderNodeData.cbegin() + static_cast<ptrdiff_t>(pos),
441                 { move(node), desc.typeName, combinedNodeName, desc.nodeName,
442                     make_unique<RenderNodeGraphInputs>(desc.description), desc.nodeJson });
443             // new node needs initialization and info on top-level (render node graph)
444             nsRef.initialized = false;
445         } else {
446             PLUGIN_LOG_W("RNT: %s, named: %s, insert pos NF", desc.typeName.c_str(), desc.nodeName.c_str());
447         }
448     } else {
449         PLUGIN_LOG_W("RN type: %s, named: %s, not found", desc.typeName.c_str(), desc.nodeName.c_str());
450     }
451 }
452 
UpdateRenderNodeGraphResources()453 void RenderNodeGraphManager::UpdateRenderNodeGraphResources()
454 {
455     for (size_t index = 0; index < nodeGraphShareData_.size(); ++index) {
456         PLUGIN_ASSERT(nodeGraphData_.size() == nodeGraphShareData_.size());
457         auto& srcData = nodeGraphShareData_[index];
458         if (nodeGraphData_[index] && ((srcData.inputCount > 0) || (srcData.outputCount > 0))) {
459             auto& ngd = *nodeGraphData_[index];
460             auto& dstData = ngd.renderNodeGraphShareData;
461             dstData = {};
462             dstData.inputCount = srcData.inputCount;
463             dstData.outputCount = srcData.outputCount;
464             for (uint32_t idx = 0; idx < dstData.inputCount; ++idx) {
465                 dstData.inputs[idx] = { "", srcData.inputs[idx].GetHandle() };
466             }
467             for (uint32_t idx = 0; idx < dstData.outputCount; ++idx) {
468                 dstData.outputs[idx] = { "", srcData.outputs[idx].GetHandle() };
469             }
470         }
471     }
472 }
473 
DynamicRenderNodeOpImpl(const RenderHandle handle,const RenderNodeDesc & renderNodeDesc,const PendingRenderNode::Type type,const PendingRenderNode::PosType posType,const string_view renderNodeName)474 void RenderNodeGraphManager::DynamicRenderNodeOpImpl(const RenderHandle handle, const RenderNodeDesc& renderNodeDesc,
475     const PendingRenderNode::Type type, const PendingRenderNode::PosType posType, const string_view renderNodeName)
476 {
477     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
478         const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
479         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
480         const auto lock = std::lock_guard(mutex_);
481 
482         if (index < static_cast<uint32_t>(nodeGraphHandles_.size())) {
483             const uint32_t storedGenerationIdx =
484                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
485             // silently ignored if not current generation
486             if (generationIdx == storedGenerationIdx) {
487                 pendingRenderNodes_.push_back({ type, handle, renderNodeDesc, posType, renderNodeName });
488             }
489         }
490     } else {
491         PLUGIN_LOG_E("invalid render node graph handle for dynamic render node operation");
492     }
493 }
494 
PushBackRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc)495 void RenderNodeGraphManager::PushBackRenderNode(
496     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc)
497 {
498     const RenderHandle rawHandle = handle.GetHandle();
499     DynamicRenderNodeOpImpl(
500         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::BACK, {});
501 }
502 
InsertBeforeRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc,const string_view renderNodeName)503 void RenderNodeGraphManager::InsertBeforeRenderNode(
504     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc, const string_view renderNodeName)
505 {
506     const RenderHandle rawHandle = handle.GetHandle();
507     DynamicRenderNodeOpImpl(
508         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::BEFORE, renderNodeName);
509 }
510 
InsertAfterRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc,const string_view renderNodeName)511 void RenderNodeGraphManager::InsertAfterRenderNode(
512     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc, const string_view renderNodeName)
513 {
514     const RenderHandle rawHandle = handle.GetHandle();
515     DynamicRenderNodeOpImpl(
516         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::AFTER, renderNodeName);
517 }
518 
EraseRenderNode(const RenderHandleReference & handle,const string_view renderNodeName)519 void RenderNodeGraphManager::EraseRenderNode(const RenderHandleReference& handle, const string_view renderNodeName)
520 {
521     const RenderHandle rawHandle = handle.GetHandle();
522     RenderNodeDesc desc;
523     desc.nodeName = renderNodeName;
524     DynamicRenderNodeOpImpl(
525         rawHandle, desc, PendingRenderNode::Type::DEALLOC, PendingRenderNode::PosType::BACK, renderNodeName);
526 }
527 
UpdateRenderNodeGraph(const RenderHandleReference &,const RenderNodeGraphDescInfo &)528 void RenderNodeGraphManager::UpdateRenderNodeGraph(const RenderHandleReference&, const RenderNodeGraphDescInfo&)
529 {
530     // NOTE: not yet implemented
531     // will provide flags for e.g. disabling render nodes
532 }
533 
GetInfo(const RenderHandleReference & handle) const534 RenderNodeGraphDescInfo RenderNodeGraphManager::GetInfo(const RenderHandleReference& handle) const
535 {
536     const RenderHandle rawHandle = handle.GetHandle();
537     RenderHandleType const type = RenderHandleUtil::GetHandleType(rawHandle);
538     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
539         return {};
540     }
541 
542     {
543         uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
544         const auto lock = std::lock_guard(mutex_);
545 
546         if (index >= nodeGraphData_.size()) {
547             return {};
548         }
549         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
550         const uint32_t storedGenerationIdx =
551             RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
552         if ((generationIdx != storedGenerationIdx) || (!nodeGraphData_[index])) {
553             PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
554                 generationIdx, storedGenerationIdx, rawHandle.id);
555             return {};
556         }
557         const auto& ngd = *nodeGraphData_[index];
558         RenderNodeGraphDescInfo rngdi;
559         rngdi.renderNodeGraphName = ngd.renderNodeGraphName;
560         rngdi.renderNodeGraphDataStoreName = ngd.renderNodeGraphDataStoreName;
561         rngdi.renderNodeGraphUri = ngd.renderNodeGraphUri;
562         rngdi.nodes.resize(ngd.renderNodeData.size());
563         for (size_t nodeIdx = 0; nodeIdx < ngd.renderNodeData.size(); ++nodeIdx) {
564             if (ngd.renderNodeData[nodeIdx].node) {
565                 rngdi.nodes[nodeIdx].typeName = ngd.renderNodeData[nodeIdx].typeName;
566                 rngdi.nodes[nodeIdx].nodeName = ngd.renderNodeData[nodeIdx].nodeName;
567                 rngdi.nodes[nodeIdx].flags = 0u; // NOTE: not yet used
568             }
569         }
570         return rngdi;
571     }
572 }
573 
SetRenderNodeGraphResources(const RenderHandleReference & handle,const array_view<const RenderHandleReference> inputs,const array_view<const RenderHandleReference> outputs)574 void RenderNodeGraphManager::SetRenderNodeGraphResources(const RenderHandleReference& handle,
575     const array_view<const RenderHandleReference> inputs, const array_view<const RenderHandleReference> outputs)
576 {
577     const RenderHandle rawHandle = handle.GetHandle();
578     if (RenderHandleType::RENDER_NODE_GRAPH != RenderHandleUtil::GetHandleType(rawHandle)) {
579         return;
580     }
581 
582     uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
583     const auto lock = std::lock_guard(mutex_);
584 
585     // NOTE: should lock and handle/touch only the client side data
586     if (index >= nodeGraphShareData_.size()) {
587         return; // early out
588     }
589     const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
590     const uint32_t storedGenerationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
591     if (generationIdx != storedGenerationIdx) {
592         PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")", generationIdx,
593             storedGenerationIdx, rawHandle.id);
594         return; // early out
595     }
596 
597 #if (RENDER_VALIDATION_ENABLED == 1)
598     if (inputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
599         PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource input count (%u) exceeds limit (%u)",
600             static_cast<uint32_t>(inputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
601     }
602     if (outputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
603         PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource output count (%u) exceeds limit (%u)",
604             static_cast<uint32_t>(outputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
605     }
606 #endif
607     auto& clientData = nodeGraphShareData_[index];
608     clientData = {};
609     clientData.inputCount =
610         Math::min(RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(inputs.size()));
611     clientData.outputCount =
612         Math::min(RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(outputs.size()));
613     for (uint32_t idx = 0; idx < clientData.inputCount; ++idx) {
614         clientData.inputs[idx] = inputs[idx];
615 #if (RENDER_VALIDATION_ENABLED == 1)
616         if (!inputs[idx]) {
617             PLUGIN_LOG_W("RENDER_VALIDATION: inv input handle (idx:%u) given as input to RNG", idx);
618         }
619 #endif
620     }
621     for (uint32_t idx = 0; idx < clientData.outputCount; ++idx) {
622         clientData.outputs[idx] = outputs[idx];
623 #if (RENDER_VALIDATION_ENABLED == 1)
624         if (!outputs[idx]) {
625             PLUGIN_LOG_W("RENDER_VALIDATION: inv output handle (idx:%u) given as output to RNG", idx);
626         }
627 #endif
628     }
629 }
630 
GetRenderNodeGraphResources(const RenderHandleReference & handle) const631 RenderNodeGraphResourceInfo RenderNodeGraphManager::GetRenderNodeGraphResources(
632     const RenderHandleReference& handle) const
633 {
634     const RenderHandle rawHandle = handle.GetHandle();
635     RenderHandleType const type = RenderHandleUtil::GetHandleType(rawHandle);
636     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
637         return {};
638     }
639     RenderNodeGraphResourceInfo info;
640 
641     uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
642     const auto lock = std::lock_guard(mutex_);
643 
644     // NOTE: should lock and handle/touch only the client side data
645     if (index >= nodeGraphShareData_.size()) {
646         return info; // early out
647     }
648     const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
649     const uint32_t storedGenerationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
650     if (generationIdx == storedGenerationIdx) {
651         if (nodeGraphData_[index]) {
652             const auto& clientData = nodeGraphShareData_[index];
653             for (uint32_t idx = 0; idx < clientData.inputCount; ++idx) {
654                 info.inputResources.push_back(clientData.inputs[idx]);
655             }
656             for (uint32_t idx = 0; idx < clientData.outputCount; ++idx) {
657                 info.outputResources.push_back(clientData.outputs[idx]);
658             }
659         }
660     } else {
661         PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")", generationIdx,
662             storedGenerationIdx, rawHandle.id);
663     }
664     return info;
665 }
666 
Get(RenderHandle handle)667 RenderNodeGraphNodeStore* RenderNodeGraphManager::Get(RenderHandle handle)
668 {
669     RenderHandleType const type = RenderHandleUtil::GetHandleType(handle);
670     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
671         return nullptr;
672     }
673 
674     {
675         uint32_t const index = RenderHandleUtil::GetIndexPart(handle);
676         const auto lock = std::lock_guard(mutex_);
677 
678         if (index < nodeGraphData_.size()) {
679             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
680             const uint32_t storedGenerationIdx =
681                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
682             if (generationIdx == storedGenerationIdx) {
683                 return nodeGraphData_[index].get();
684             } else {
685                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
686                     generationIdx, storedGenerationIdx, handle.id);
687             }
688         }
689     }
690 
691     return nullptr;
692 }
693 
GetRenderNodeManager() const694 RenderNodeManager& RenderNodeGraphManager::GetRenderNodeManager() const
695 {
696     return *renderNodeMgr_;
697 }
698 
Destroy(const string_view typeName)699 void RenderNodeGraphManager::Destroy(const string_view typeName)
700 {
701     device_.Activate();
702     for (const auto& store : nodeGraphData_) {
703         for (;;) {
704             auto pos = std::find_if(store->renderNodeData.begin(), store->renderNodeData.end(),
705                 [typeName](const RenderNodeGraphNodeStore::RenderNodeData& data) { return data.typeName == typeName; });
706             if (pos != store->renderNodeData.end()) {
707                 const auto index = std::distance(store->renderNodeData.begin(), pos);
708                 store->renderNodeData.erase(pos);
709                 store->renderNodeContextData.erase(store->renderNodeContextData.begin() + index);
710             } else {
711                 break;
712             }
713         }
714     }
715     device_.Deactivate();
716 }
717 RENDER_END_NAMESPACE()
718