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