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