• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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) : device_(device)
64 {
65     renderNodeMgr_ = make_unique<RenderNodeManager>();
66     renderNodeGraphLoader_ = make_unique<RenderNodeGraphLoader>(fileMgr);
67 }
68 
~RenderNodeGraphManager()69 RenderNodeGraphManager::~RenderNodeGraphManager()
70 {
71 #if (RENDER_VALIDATION_ENABLED == 1)
72     uint32_t aliveRngCounter = 0;
73     for (const auto& ref : nodeGraphHandles_) {
74         if (ref && (ref.GetRefCount() > 1)) {
75             aliveRngCounter++;
76         }
77     }
78     if (aliveRngCounter > 0) {
79         PLUGIN_LOG_W(
80             "RENDER_VALIDATION: Not all render node graph handle references released (count: %u)", aliveRngCounter);
81     }
82 #endif
83 }
84 
Get(const RenderHandle & handle) const85 RenderHandleReference RenderNodeGraphManager::Get(const RenderHandle& handle) const
86 {
87     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
88         const uint32_t arrayIndex = RenderHandleUtil::GetIndexPart(handle);
89         const auto lock = std::lock_guard(mutex_);
90 
91         if (arrayIndex < static_cast<uint32_t>(nodeGraphHandles_.size())) {
92             return nodeGraphHandles_[arrayIndex];
93         } else {
94             PLUGIN_LOG_E("invalid render node graph handle (id: %" PRIu64 ")", handle.id);
95         }
96     }
97     return RenderHandleReference {};
98 }
99 
LoadAndCreate(const RenderNodeGraphUsageType usage,const string_view uri)100 RenderHandleReference RenderNodeGraphManager::LoadAndCreate(const RenderNodeGraphUsageType usage, const string_view uri)
101 {
102     if (const auto result = renderNodeGraphLoader_->Load(uri); !result.error.empty()) {
103         PLUGIN_LOG_W("Load and create for render node graph failed: %s %s ", uri.data(), result.error.c_str());
104         return {};
105     } else {
106         return Create(usage, result.desc);
107     }
108 }
109 
GetRenderNodeGraphLoader()110 IRenderNodeGraphLoader& RenderNodeGraphManager::GetRenderNodeGraphLoader()
111 {
112     return *renderNodeGraphLoader_;
113 }
114 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc,const string_view renderNodeGraphName,const string_view renderNodeGraphDataStoreName)115 RenderHandleReference RenderNodeGraphManager::Create(const RenderNodeGraphUsageType usage,
116     const RenderNodeGraphDesc& desc, const string_view renderNodeGraphName,
117     const string_view renderNodeGraphDataStoreName)
118 {
119     const auto lock = std::lock_guard(mutex_);
120 
121     uint64_t handleId = INVALID_RESOURCE_HANDLE;
122     bool newHandle = true;
123     if (availableHandleIds_.empty()) { // no available indices
124         handleId = static_cast<uint64_t>(nodeGraphData_.size()) << RenderHandleUtil::RES_HANDLE_ID_SHIFT;
125         newHandle = true;
126     } else {
127         handleId = availableHandleIds_.back();
128         availableHandleIds_.pop_back();
129         newHandle = false;
130     }
131 
132     const uint32_t indexPart = RenderHandleUtil::GetIndexPart(handleId);
133     const uint32_t generationIndexPart = RenderHandleUtil::GetGenerationIndexPart(handleId) + 1; // next gen
134 
135     const RenderHandle handle =
136         RenderHandleUtil::CreateHandle(RenderHandleType::RENDER_NODE_GRAPH, indexPart, generationIndexPart);
137     RenderHandleReference rhr {
138         handle,
139         IRenderReferenceCounter::Ptr(new RenderReferenceCounter()),
140     };
141     if (newHandle) {
142         nodeGraphData_.emplace_back(); // deferred
143         nodeGraphHandles_.emplace_back(move(rhr));
144         nodeGraphShareData_.emplace_back();
145     } else {
146         nodeGraphData_[indexPart] = {}; // deferred
147         nodeGraphHandles_[indexPart] = move(rhr);
148         nodeGraphShareData_[indexPart] = {};
149     }
150     pendingRenderNodeGraphs_.push_back({
151         PendingRenderNodeGraph::Type::ALLOC,
152         handle,
153         renderNodeGraphName.empty() ? string_view(desc.renderNodeGraphName) : renderNodeGraphName,
154         renderNodeGraphDataStoreName.empty() ? string_view(desc.renderNodeGraphDataStoreName)
155                                              : renderNodeGraphDataStoreName,
156         desc.renderNodeGraphUri,
157         desc,
158         usage,
159     });
160 
161     PLUGIN_ASSERT(indexPart < static_cast<uint32_t>(nodeGraphHandles_.size()));
162     return nodeGraphHandles_[indexPart];
163 }
164 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc,const string_view renderNodeGraphName)165 RenderHandleReference RenderNodeGraphManager::Create(
166     const RenderNodeGraphUsageType usage, const RenderNodeGraphDesc& desc, const string_view renderNodeGraphName)
167 {
168     return Create(usage, desc, renderNodeGraphName, {});
169 }
170 
Create(const RenderNodeGraphUsageType usage,const RenderNodeGraphDesc & desc)171 RenderHandleReference RenderNodeGraphManager::Create(
172     const RenderNodeGraphUsageType usage, const RenderNodeGraphDesc& desc)
173 {
174     return Create(usage, desc, {}, {});
175 }
176 
Destroy(const RenderHandle handle)177 void RenderNodeGraphManager::Destroy(const RenderHandle handle)
178 {
179     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
180         const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
181         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
182         if (index < static_cast<uint32_t>(nodeGraphHandles_.size())) {
183             const uint32_t storedGenerationIdx =
184                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
185             // ignore if not correct generation index
186             if (generationIdx == storedGenerationIdx) {
187                 pendingRenderNodeGraphs_.push_back({ PendingRenderNodeGraph::Type::DEALLOC, handle, "", "", {}, {} });
188             }
189         }
190     }
191 }
192 
HandlePendingAllocations()193 void RenderNodeGraphManager::HandlePendingAllocations()
194 {
195     // deferred multi-frame destruction for RenderNodeContextData needed
196     const uint64_t minAge = static_cast<uint64_t>(device_.GetCommandBufferingCount()) + 1;
197     const uint64_t ageLimit = (device_.GetFrameCount() < minAge) ? 0 : (device_.GetFrameCount() - minAge);
198 
199     {
200         // needs to be locked the whole time
201         // methods access private members like nodeGraphData_
202         const auto lock = std::lock_guard(mutex_);
203 
204         // check render node graphs for destruction
205         for (auto& rngRef : nodeGraphHandles_) {
206             if (rngRef && (rngRef.GetRefCount() <= 1)) {
207                 Destroy(rngRef.GetHandle());
208             }
209         }
210 
211         // alloc/dealloc individual render node graphs
212         for (const auto& ref : pendingRenderNodeGraphs_) {
213             if (ref.type == PendingRenderNodeGraph::Type::ALLOC) {
214                 PendingCreate(ref);
215             } else if (ref.type == PendingRenderNodeGraph::Type::DEALLOC) {
216                 PendingDestroy(ref.renderNodeGraphHandle);
217             }
218         }
219         pendingRenderNodeGraphs_.clear();
220 
221         // alloc/dealloc individual render nodes
222         for (auto& ref : pendingRenderNodes_) {
223             if (ref.type == PendingRenderNode::Type::ALLOC) {
224                 PendingAllocRenderNode(ref.renderNodeGraphHandle, ref);
225             } else if (ref.type == PendingRenderNode::Type::DEALLOC) {
226                 PendingDeallocRenderNode(ref.renderNodeGraphHandle, ref.renderNodeDesc.nodeName);
227             }
228         }
229         pendingRenderNodes_.clear();
230 
231         // check for updated render node graph inputs / outputs
232         UpdateRenderNodeGraphResources();
233 
234         // multi-frame deferred destructions
235 
236         // render node graph destruction
237         if (!pendingRenderNodeGraphDestructions_.empty()) {
238             const auto oldResources =
239                 std::partition(pendingRenderNodeGraphDestructions_.begin(), pendingRenderNodeGraphDestructions_.end(),
240                     [ageLimit](const auto& destructionQueue) { return destructionQueue.frameIndex >= ageLimit; });
241             pendingRenderNodeGraphDestructions_.erase(oldResources, pendingRenderNodeGraphDestructions_.end());
242         }
243         // individual render node destruction
244         if (!pendingRenderNodeDestructions_.empty()) {
245             const auto oldResources =
246                 std::partition(pendingRenderNodeDestructions_.begin(), pendingRenderNodeDestructions_.end(),
247                     [ageLimit](const auto& destructionQueue) { return destructionQueue.frameIndex >= ageLimit; });
248             pendingRenderNodeDestructions_.erase(oldResources, pendingRenderNodeDestructions_.end());
249         }
250     }
251 }
252 
PendingCreate(const PendingRenderNodeGraph & renderNodeGraph)253 void RenderNodeGraphManager::PendingCreate(const PendingRenderNodeGraph& renderNodeGraph)
254 {
255     unique_ptr<RenderNodeGraphNodeStore> nodeStore = make_unique<RenderNodeGraphNodeStore>();
256     nodeStore->dynamic = (renderNodeGraph.usageType == RenderNodeGraphUsageType::RENDER_NODE_GRAPH_DYNAMIC);
257     nodeStore->initialized = false;
258     nodeStore->renderNodeGraphName = renderNodeGraph.renderNodeGraphName;
259     nodeStore->renderNodeGraphDataStoreName = renderNodeGraph.renderNodeGraphDataStoreName;
260     nodeStore->renderNodeGraphUri = renderNodeGraph.renderNodeGraphUri;
261     // many of the resources are not yet available as handles
262     nodeStore->renderNodeGraphShareDataMgr = make_unique<RenderNodeGraphShareDataManager>();
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_.emplace_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_.emplace_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(nsRef.renderNodeContextData.cbegin() + pos, move(rncd));
434                         nsRef.renderNodeData.insert(nsRef.renderNodeData.cbegin() + pos,
435                             { move(node), desc.typeName, combinedNodeName, desc.nodeName,
436                                 make_unique<RenderNodeGraphInputs>(desc.description), desc.nodeJson });
437                         // new node needs initialization and info on top-level (render node graph)
438                         nsRef.initialized = false;
439                     } else {
440                         PLUGIN_LOG_W("RNT: %s, named: %s, insert pos NF", desc.typeName.c_str(), desc.nodeName.c_str());
441                     }
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 
UpdateRenderNodeGraphResources()452 void RenderNodeGraphManager::UpdateRenderNodeGraphResources()
453 {
454     for (size_t index = 0; index < nodeGraphShareData_.size(); ++index) {
455         PLUGIN_ASSERT(nodeGraphData_.size() == nodeGraphShareData_.size());
456         auto& srcData = nodeGraphShareData_[index];
457         if (nodeGraphData_[index] && ((srcData.inputCount > 0) || (srcData.outputCount > 0))) {
458             auto& ngd = *nodeGraphData_[index];
459             auto& dstData = ngd.renderNodeGraphShareData;
460             dstData = {};
461             dstData.inputCount = srcData.inputCount;
462             dstData.outputCount = srcData.outputCount;
463             for (uint32_t idx = 0; idx < dstData.inputCount; ++idx) {
464                 dstData.inputs[idx] = srcData.inputs[idx].GetHandle();
465             }
466             for (uint32_t idx = 0; idx < dstData.outputCount; ++idx) {
467                 dstData.outputs[idx] = srcData.outputs[idx].GetHandle();
468             }
469         }
470     }
471 }
472 
DynamicRenderNodeOpImpl(const RenderHandle handle,const RenderNodeDesc & renderNodeDesc,const PendingRenderNode::Type type,const PendingRenderNode::PosType posType,const string_view renderNodeName)473 void RenderNodeGraphManager::DynamicRenderNodeOpImpl(const RenderHandle handle, const RenderNodeDesc& renderNodeDesc,
474     const PendingRenderNode::Type type, const PendingRenderNode::PosType posType, const string_view renderNodeName)
475 {
476     if (RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) {
477         const uint32_t index = RenderHandleUtil::GetIndexPart(handle);
478         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
479         const auto lock = std::lock_guard(mutex_);
480 
481         if (index < static_cast<uint32_t>(nodeGraphHandles_.size())) {
482             const uint32_t storedGenerationIdx =
483                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
484             // silently ignored if not current generation
485             if (generationIdx == storedGenerationIdx) {
486                 pendingRenderNodes_.push_back({ type, handle, renderNodeDesc, posType, renderNodeName });
487             }
488         }
489     } else {
490         PLUGIN_LOG_E("invalid render node graph handle for dynamic render node operation");
491     }
492 }
493 
PushBackRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc)494 void RenderNodeGraphManager::PushBackRenderNode(
495     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc)
496 {
497     const RenderHandle rawHandle = handle.GetHandle();
498     DynamicRenderNodeOpImpl(
499         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::BACK, {});
500 }
501 
InsertBeforeRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc,const string_view renderNodeName)502 void RenderNodeGraphManager::InsertBeforeRenderNode(
503     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc, const string_view renderNodeName)
504 {
505     const RenderHandle rawHandle = handle.GetHandle();
506     DynamicRenderNodeOpImpl(
507         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::BEFORE, renderNodeName);
508 }
509 
InsertAfterRenderNode(const RenderHandleReference & handle,const RenderNodeDesc & renderNodeDesc,const string_view renderNodeName)510 void RenderNodeGraphManager::InsertAfterRenderNode(
511     const RenderHandleReference& handle, const RenderNodeDesc& renderNodeDesc, const string_view renderNodeName)
512 {
513     const RenderHandle rawHandle = handle.GetHandle();
514     DynamicRenderNodeOpImpl(
515         rawHandle, renderNodeDesc, PendingRenderNode::Type::ALLOC, PendingRenderNode::PosType::AFTER, renderNodeName);
516 }
517 
EraseRenderNode(const RenderHandleReference & handle,const string_view renderNodeName)518 void RenderNodeGraphManager::EraseRenderNode(const RenderHandleReference& handle, const string_view renderNodeName)
519 {
520     const RenderHandle rawHandle = handle.GetHandle();
521     RenderNodeDesc desc;
522     desc.nodeName = renderNodeName;
523     DynamicRenderNodeOpImpl(
524         rawHandle, desc, PendingRenderNode::Type::DEALLOC, PendingRenderNode::PosType::BACK, renderNodeName);
525 }
526 
UpdateRenderNodeGraph(const RenderHandleReference &,const RenderNodeGraphDescInfo &)527 void RenderNodeGraphManager::UpdateRenderNodeGraph(const RenderHandleReference&, const RenderNodeGraphDescInfo&)
528 {
529     // NOTE: not yet implemented
530     // will provide flags for e.g. disabling render nodes
531 }
532 
GetInfo(const RenderHandleReference & handle) const533 RenderNodeGraphDescInfo RenderNodeGraphManager::GetInfo(const RenderHandleReference& handle) const
534 {
535     const RenderHandle rawHandle = handle.GetHandle();
536     RenderHandleType const type = RenderHandleUtil::GetHandleType(rawHandle);
537     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
538         return {};
539     }
540 
541     {
542         uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
543         const auto lock = std::lock_guard(mutex_);
544 
545         if (index < nodeGraphData_.size()) {
546             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
547             const uint32_t storedGenerationIdx =
548                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
549             if (generationIdx == storedGenerationIdx) {
550                 if (nodeGraphData_[index]) {
551                     const auto& ngd = *nodeGraphData_[index];
552                     RenderNodeGraphDescInfo rngdi;
553                     rngdi.renderNodeGraphName = ngd.renderNodeGraphName;
554                     rngdi.renderNodeGraphDataStoreName = ngd.renderNodeGraphDataStoreName;
555                     rngdi.renderNodeGraphUri = ngd.renderNodeGraphUri;
556                     rngdi.nodes.resize(ngd.renderNodeData.size());
557                     for (size_t nodeIdx = 0; nodeIdx < ngd.renderNodeData.size(); ++nodeIdx) {
558                         if (ngd.renderNodeData[nodeIdx].node) {
559                             rngdi.nodes[nodeIdx].typeName = ngd.renderNodeData[nodeIdx].typeName;
560                             rngdi.nodes[nodeIdx].nodeName = ngd.renderNodeData[nodeIdx].nodeName;
561                             rngdi.nodes[nodeIdx].flags = 0u; // NOTE: not yet used
562                         }
563                     }
564                     return rngdi;
565                 }
566             } else {
567                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
568                     generationIdx, storedGenerationIdx, rawHandle.id);
569             }
570         }
571     }
572     return {};
573 }
574 
SetRenderNodeGraphResources(const RenderHandleReference & handle,const array_view<const RenderHandleReference> inputs,const array_view<const RenderHandleReference> outputs)575 void RenderNodeGraphManager::SetRenderNodeGraphResources(const RenderHandleReference& handle,
576     const array_view<const RenderHandleReference> inputs, const array_view<const RenderHandleReference> outputs)
577 {
578     const RenderHandle rawHandle = handle.GetHandle();
579     if (RenderHandleType::RENDER_NODE_GRAPH != RenderHandleUtil::GetHandleType(rawHandle)) {
580         return;
581     }
582 
583     uint32_t const index = RenderHandleUtil::GetIndexPart(rawHandle);
584     const auto lock = std::lock_guard(mutex_);
585 
586     // NOTE: should lock and handle/touch only the client side data
587     if (index < nodeGraphShareData_.size()) {
588         const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
589         const uint32_t storedGenerationIdx =
590             RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
591         if (generationIdx == storedGenerationIdx) {
592 #if (RENDER_VALIDATION_ENABLED == 1)
593             if (inputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
594                 PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource input count (%u) exceeds limit (%u)",
595                     static_cast<uint32_t>(inputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
596             }
597             if (outputs.size() > RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT) {
598                 PLUGIN_LOG_W("RENDER_VALIDATION: render node graph resource output count (%u) exceeds limit (%u)",
599                     static_cast<uint32_t>(outputs.size()), RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT);
600             }
601 #endif
602             auto& clientData = nodeGraphShareData_[index];
603             clientData = {};
604             clientData.inputCount = Math::min(
605                 RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(inputs.size()));
606             clientData.outputCount = Math::min(
607                 RenderNodeGraphShareData::MAX_RENDER_NODE_GRAPH_RES_COUNT, static_cast<uint32_t>(outputs.size()));
608             for (uint32_t idx = 0; idx < clientData.inputCount; ++idx) {
609                 clientData.inputs[idx] = inputs[idx];
610 #if (RENDER_VALIDATION_ENABLED == 1)
611                 if (!inputs[idx]) {
612                     PLUGIN_LOG_W("RENDER_VALIDATION: inv input handle (idx:%u) given as input to RNG", idx);
613                 }
614 #endif
615             }
616             for (uint32_t idx = 0; idx < clientData.outputCount; ++idx) {
617                 clientData.outputs[idx] = outputs[idx];
618 #if (RENDER_VALIDATION_ENABLED == 1)
619                 if (!outputs[idx]) {
620                     PLUGIN_LOG_W("RENDER_VALIDATION: inv output handle (idx:%u) given as output to RNG", idx);
621                 }
622 #endif
623             }
624         } else {
625             PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
626                 generationIdx, storedGenerationIdx, rawHandle.id);
627         }
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             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(rawHandle);
647             const uint32_t storedGenerationIdx =
648                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
649             if (generationIdx == storedGenerationIdx) {
650                 if (nodeGraphData_[index]) {
651                     const auto& clientData = nodeGraphShareData_[index];
652                     for (uint32_t idx = 0; idx < clientData.inputCount; ++idx) {
653                         info.inputResources.emplace_back(clientData.inputs[idx]);
654                     }
655                     for (uint32_t idx = 0; idx < clientData.outputCount; ++idx) {
656                         info.outputResources.emplace_back(clientData.outputs[idx]);
657                     }
658                 }
659             } else {
660                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
661                     generationIdx, storedGenerationIdx, rawHandle.id);
662             }
663         }
664     }
665     return info;
666 }
667 
Get(RenderHandle handle)668 RenderNodeGraphNodeStore* RenderNodeGraphManager::Get(RenderHandle handle)
669 {
670     RenderHandleType const type = RenderHandleUtil::GetHandleType(handle);
671     if (RenderHandleType::RENDER_NODE_GRAPH != type) {
672         return nullptr;
673     }
674 
675     {
676         uint32_t const index = RenderHandleUtil::GetIndexPart(handle);
677         const auto lock = std::lock_guard(mutex_);
678 
679         if (index < nodeGraphData_.size()) {
680             const uint32_t generationIdx = RenderHandleUtil::GetGenerationIndexPart(handle);
681             const uint32_t storedGenerationIdx =
682                 RenderHandleUtil::GetGenerationIndexPart(nodeGraphHandles_[index].GetHandle());
683             if (generationIdx == storedGenerationIdx) {
684                 return nodeGraphData_[index].get();
685             } else {
686                 PLUGIN_LOG_E("invalid generation index (%u != %u) with render node graph handle (%" PRIu64 ")",
687                     generationIdx, storedGenerationIdx, handle.id);
688             }
689         }
690     }
691 
692     return nullptr;
693 }
694 
GetRenderNodeManager() const695 RenderNodeManager& RenderNodeGraphManager::GetRenderNodeManager() const
696 {
697     return *renderNodeMgr_;
698 }
699 
Destroy(const string_view typeName)700 void RenderNodeGraphManager::Destroy(const string_view typeName)
701 {
702     device_.Activate();
703     for (const auto& store : nodeGraphData_) {
704         for (;;) {
705             auto pos = std::find_if(store->renderNodeData.begin(), store->renderNodeData.end(),
706                 [typeName](const RenderNodeGraphNodeStore::RenderNodeData& data) { return data.typeName == typeName; });
707             if (pos != store->renderNodeData.end()) {
708                 const auto index = std::distance(store->renderNodeData.begin(), pos);
709                 store->renderNodeData.erase(pos);
710                 store->renderNodeContextData.erase(store->renderNodeContextData.begin() + index);
711             } else {
712                 break;
713             }
714         }
715     }
716     device_.Deactivate();
717 }
718 RENDER_END_NAMESPACE()
719