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_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         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
308         const uint32_t storedGenerationIdx =
309             RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
310         // silently ignore if not correct generation (might be destroyed already)
311         if (generationIdx == storedGenerationIdx) {
312             if (nodeGraphData_[index]) {
313 #if (RENDER_PERF_ENABLED == 1)
314                 if (auto* inst =
315                         CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
316                     inst) {
317                     if (CORE_NS::IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
318                         for (const auto& rnRef : nodeGraphData_[index]->renderNodeData)
319                             perfData->RemoveData(rnRef.fullName);
320                     }
321                 }
322 #endif
323                 // destroy all expect RenderNodeContextData which has command buffers and such
324                 // add to destruction queue
325                 pendingRenderNodeGraphDestructions_.push_back(PendingRenderNodeGraphDestruction {
326                     device_.GetFrameCount(), move(nodeGraphData_[index]->renderNodeContextData) });
327                 nodeGraphData_[index] = nullptr;
328                 nodeGraphHandles_[index] = {};
329                 nodeGraphShareData_[index] = {};
330 
331                 // NOTE: this does not erase the RenderNodeGraphNodeStore element from the nodeGraphData_
332                 // i.e. the data is invalidated in nodeGraphData_
333 
334                 availableHandleIds_.push_back(handle.id);
335             }
336         }
337     } else {
338         PLUGIN_LOG_E("invalid handle (%" PRIu64 ") given to render node Destroy", handle.id);
339     }
340 }
341 
342 // needs to be locked when called
PendingDeallocRenderNode(const RenderHandle nodeGraphHandle,const string_view renderNodeName)343 void RenderNodeGraphManager::PendingDeallocRenderNode(
344     const RenderHandle nodeGraphHandle, const string_view renderNodeName)
345 {
346     const uint32_t index = RenderHandleUtil::GetIndexPart(nodeGraphHandle);
347     if (index < nodeGraphData_.size()) {
348         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandle);
349         const uint32_t storedGenerationIdx =
350             RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
351         // silently ignore if not correct generation (render node graph might be destroyed already)
352         if (generationIdx == storedGenerationIdx) {
353             PLUGIN_ASSERT(nodeGraphData_[index]);
354             auto& nodeStoreRef = *nodeGraphData_[index];
355             if (nodeStoreRef.dynamic) {
356                 uint32_t eraseIndex = ~0u;
357                 for (size_t eraseIdx = 0; eraseIdx < nodeStoreRef.renderNodeData.size(); ++eraseIdx) {
358                     if (nodeStoreRef.renderNodeData[eraseIdx].node &&
359                         (nodeStoreRef.renderNodeData[eraseIdx].nodeName == renderNodeName)) {
360                         eraseIndex = static_cast<uint32_t>(eraseIdx);
361                         break;
362                     }
363                 }
364                 if (eraseIndex <= nodeStoreRef.renderNodeData.size()) {
365 #if (RENDER_PERF_ENABLED == 1)
366                     if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(
367                             CORE_NS::UID_PERFORMANCE_FACTORY);
368                         inst) {
369                         if (CORE_NS::IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
370                             perfData->RemoveData(nodeStoreRef.renderNodeData[eraseIndex].fullName);
371                         }
372                     }
373 #endif
374                     // only RenderNodeContextData needs deferred destruction
375                     pendingRenderNodeDestructions_.push_back({
376                         device_.GetFrameCount(),
377                         move(nodeStoreRef.renderNodeContextData[eraseIndex]),
378                     });
379                     // NOTE: this erases the elements from the vectors
380                     const int32_t iEraseIndex = static_cast<int32_t>(eraseIndex);
381                     nodeStoreRef.renderNodeData.erase(nodeStoreRef.renderNodeData.begin() + iEraseIndex);
382                     nodeStoreRef.renderNodeContextData.erase(nodeStoreRef.renderNodeContextData.begin() + iEraseIndex);
383                 } else {
384                     PLUGIN_LOG_E("invalid render node name for erase (%s)", renderNodeName.data());
385                 }
386             } else {
387                 PLUGIN_LOG_E(
388                     "render node (name:%s) cannot be erased from non-dynamic render node graph", renderNodeName.data());
389             }
390         }
391     }
392 }
393 
394 // needs to be locked when called
PendingAllocRenderNode(const RenderHandle nodeGraphHandle,const PendingRenderNode & pendingNode)395 void RenderNodeGraphManager::PendingAllocRenderNode(
396     const RenderHandle nodeGraphHandle, const PendingRenderNode& pendingNode)
397 {
398     if (const uint32_t index = RenderHandleUtil::GetIndexPart(nodeGraphHandle); index < nodeGraphData_.size()) {
399         const uint32_t genIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandle);
400         const uint32_t sGenIdx = RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
401         // silently ignore if not correct generation (render node graph might be destroyed already)
402         const auto& desc = pendingNode.renderNodeDesc;
403         if (genIdx == sGenIdx) {
404             PLUGIN_ASSERT(nodeGraphData_[index]);
405             auto& nsRef = *nodeGraphData_[index];
406             if (nsRef.dynamic) {
407                 const RenderDataConstants::RenderDataFixedString combinedNodeName =
408                     string_view(nsRef.renderNodeGraphName + desc.nodeName);
409                 if (auto node = renderNodeMgr_->CreateRenderNode(desc.typeName.c_str()); node) {
410                     uint32_t pos = ~0u;
411                     if (pendingNode.posType == PendingRenderNode::PosType::BACK) {
412                         pos = static_cast<uint32_t>(nsRef.renderNodeData.size());
413                     } else {
414                         for (uint32_t rnIdx = 0; rnIdx < nsRef.renderNodeData.size(); ++rnIdx) {
415                             const auto& currDataRef = nsRef.renderNodeData[rnIdx];
416                             if (currDataRef.node && (pendingNode.renderNodeName == currDataRef.nodeName)) {
417                                 pos = (pendingNode.posType == PendingRenderNode::PosType::AFTER) ? rnIdx + 1 : rnIdx;
418                                 break;
419                             }
420                         }
421                     }
422                     if ((pos <= static_cast<uint32_t>(nsRef.renderNodeData.size())) && (pos != ~0u)) {
423                         const RenderNodeManager::RenderNodeTypeInfoFlags tiFlags =
424                             renderNodeMgr_->GetRenderNodeTypeInfoFlags(desc.typeName.c_str());
425                         const IRenderNode::ClassType backendNode =
426                             static_cast<IRenderNode::ClassType>(tiFlags.classType);
427                         RenderNodeContextData rncd;
428                         rncd.renderBackendNode = (backendNode == IRenderNode::ClassType::CLASS_TYPE_BACKEND_NODE)
429                                                      ? reinterpret_cast<IRenderBackendNode*>(node.get())
430                                                      : nullptr;
431                         rncd.initialized = false;
432                         ValidateBackendFlags(desc.typeName, device_.GetBackendType(), tiFlags.backendFlags);
433                         nsRef.renderNodeContextData.insert(
434                             nsRef.renderNodeContextData.cbegin() + static_cast<ptrdiff_t>(pos), move(rncd));
435                         nsRef.renderNodeData.insert(nsRef.renderNodeData.cbegin() + static_cast<ptrdiff_t>(pos),
436                             { move(node), desc.typeName, combinedNodeName, desc.nodeName,
437                                 make_unique<RenderNodeGraphInputs>(desc.description), desc.nodeJson });
438                         // new node needs initialization and info on top-level (render node graph)
439                         nsRef.initialized = false;
440                     } else {
441                         PLUGIN_LOG_W("RNT: %s, named: %s, insert pos NF", desc.typeName.c_str(), desc.nodeName.c_str());
442                     }
443                 } else {
444                     PLUGIN_LOG_W("RN type: %s, named: %s, not found", desc.typeName.c_str(), desc.nodeName.c_str());
445                 }
446             } else {
447                 PLUGIN_LOG_E("RN (name:%s) cannot be add to non-dynamic render node graph", desc.nodeName.c_str());
448             }
449         }
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             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
548             const uint32_t storedGenerationIdx =
549                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
550             if (generationIdx == storedGenerationIdx) {
551                 if (nodeGraphData_[index]) {
552                     const auto& ngd = *nodeGraphData_[index];
553                     RenderNodeGraphDescInfo rngdi;
554                     rngdi.renderNodeGraphName = ngd.renderNodeGraphName;
555                     rngdi.renderNodeGraphDataStoreName = ngd.renderNodeGraphDataStoreName;
556                     rngdi.renderNodeGraphUri = ngd.renderNodeGraphUri;
557                     rngdi.nodes.resize(ngd.renderNodeData.size());
558                     for (size_t nodeIdx = 0; nodeIdx < ngd.renderNodeData.size(); ++nodeIdx) {
559                         if (ngd.renderNodeData[nodeIdx].node) {
560                             rngdi.nodes[nodeIdx].typeName = ngd.renderNodeData[nodeIdx].typeName;
561                             rngdi.nodes[nodeIdx].nodeName = ngd.renderNodeData[nodeIdx].nodeName;
562                             rngdi.nodes[nodeIdx].flags = 0u; // NOTE: not yet used
563                         }
564                     }
565                     return rngdi;
566                 }
567             } else {
568                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
569                     generationIdx, storedGenerationIdx, rawHandle.id);
570             }
571         }
572     }
573     return {};
574 }
575 
SetRenderNodeGraphResources(const RenderHandleReference & handle,const array_view<const RenderHandleReference> inputs,const array_view<const RenderHandleReference> outputs)576 void RenderNodeGraphManager::SetRenderNodeGraphResources(const RenderHandleReference& handle,
577     const array_view<const RenderHandleReference> inputs, const array_view<const RenderHandleReference> outputs)
578 {
579     const RenderHandle rawHandle = handle.GetHandle();
580     if (RenderHandleType::RENDER_NODE_GRAPH != RenderHandleUtil::GetHandleType(rawHandle)) {
581         return;
582     }
583 
584     uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
585     const auto lock = std::lock_guard(mutex_);
586 
587     // NOTE: should lock and handle/touch only the client side data
588     if (index < nodeGraphShareData_.size()) {
589         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
590         const uint32_t storedGenerationIdx =
591             RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
592         if (generationIdx == storedGenerationIdx) {
593 #if (RENDER_VALIDATION_ENABLED == 1)
594             if (inputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
595                 PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource input count (%u) exceeds limit (%u)",
596                     static_cast<uint32_t>(inputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
597             }
598             if (outputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
599                 PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource output count (%u) exceeds limit (%u)",
600                     static_cast<uint32_t>(outputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
601             }
602 #endif
603             auto& clientData = nodeGraphShareData_[index];
604             clientData = {};
605             clientData.inputCount = Math::min(
606                 RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(inputs.size()));
607             clientData.outputCount = Math::min(
608                 RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(outputs.size()));
609             for (uint32_t idx = 0; idx < clientData.inputCount; ++idx) {
610                 clientData.inputs[idx] = inputs[idx];
611 #if (RENDER_VALIDATION_ENABLED == 1)
612                 if (!inputs[idx]) {
613                     PLUGIN_LOG_W("RENDER_VALIDATION: inv input handle (idx:%u) given as input to RNG", idx);
614                 }
615 #endif
616             }
617             for (uint32_t idx = 0; idx < clientData.outputCount; ++idx) {
618                 clientData.outputs[idx] = outputs[idx];
619 #if (RENDER_VALIDATION_ENABLED == 1)
620                 if (!outputs[idx]) {
621                     PLUGIN_LOG_W("RENDER_VALIDATION: inv output handle (idx:%u) given as output to RNG", idx);
622                 }
623 #endif
624             }
625         } else {
626             PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
627                 generationIdx, storedGenerationIdx, rawHandle.id);
628         }
629     }
630 }
631 
GetRenderNodeGraphResources(const RenderHandleReference & handle) const632 RenderNodeGraphResourceInfo RenderNodeGraphManager::GetRenderNodeGraphResources(
633     const RenderHandleReference& handle) const
634 {
635     const RenderHandle rawHandle = handle.GetHandle();
636     RenderHandleType const type = RenderHandleUtil::GetHandleType(rawHandle);
637     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
638         return {};
639     }
640     RenderNodeGraphResourceInfo info;
641     {
642         uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
643         const auto lock = std::lock_guard(mutex_);
644 
645         // NOTE: should lock and handle/touch only the client side data
646         if (index < nodeGraphShareData_.size()) {
647             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
648             const uint32_t storedGenerationIdx =
649                 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 ")",
662                     generationIdx, storedGenerationIdx, rawHandle.id);
663             }
664         }
665     }
666     return info;
667 }
668 
Get(RenderHandle handle)669 RenderNodeGraphNodeStore* RenderNodeGraphManager::Get(RenderHandle handle)
670 {
671     RenderHandleType const type = RenderHandleUtil::GetHandleType(handle);
672     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
673         return nullptr;
674     }
675 
676     {
677         uint32_t const index = RenderHandleUtil::GetIndexPart(handle);
678         const auto lock = std::lock_guard(mutex_);
679 
680         if (index < nodeGraphData_.size()) {
681             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
682             const uint32_t storedGenerationIdx =
683                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
684             if (generationIdx == storedGenerationIdx) {
685                 return nodeGraphData_[index].get();
686             } else {
687                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
688                     generationIdx, storedGenerationIdx, handle.id);
689             }
690         }
691     }
692 
693     return nullptr;
694 }
695 
GetRenderNodeManager() const696 RenderNodeManager& RenderNodeGraphManager::GetRenderNodeManager() const
697 {
698     return *renderNodeMgr_;
699 }
700 
Destroy(const string_view typeName)701 void RenderNodeGraphManager::Destroy(const string_view typeName)
702 {
703     device_.Activate();
704     for (const auto& store : nodeGraphData_) {
705         for (;;) {
706             auto pos = std::find_if(store->renderNodeData.begin(), store->renderNodeData.end(),
707                 [typeName](const RenderNodeGraphNodeStore::RenderNodeData& data) { return data.typeName == typeName; });
708             if (pos != store->renderNodeData.end()) {
709                 const auto index = std::distance(store->renderNodeData.begin(), pos);
710                 store->renderNodeData.erase(pos);
711                 store->renderNodeContextData.erase(store->renderNodeContextData.begin() + index);
712             } else {
713                 break;
714             }
715         }
716     }
717     device_.Deactivate();
718 }
719 RENDER_END_NAMESPACE()
720