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 "renderer.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <cinttypes>
21 #include <utility>
22 
23 #include <base/containers/string.h>
24 #include <base/containers/string_view.h>
25 #include <base/containers/unordered_map.h>
26 #include <base/containers/vector.h>
27 #include <core/perf/intf_performance_data_manager.h>
28 #include <render/datastore/intf_render_data_store_default_staging.h>
29 #include <render/datastore/intf_render_data_store_manager.h>
30 #include <render/datastore/render_data_store_render_pods.h>
31 #include <render/intf_render_context.h>
32 #include <render/intf_renderer.h>
33 #include <render/namespace.h>
34 #include <render/nodecontext/intf_render_node.h>
35 #include <render/render_data_structures.h>
36 
37 #include "perf/cpu_perf_scope.h"
38 
39 #if (RENDER_DEV_ENABLED == 1)
40 #include <cinttypes>
41 #endif
42 
43 #include "datastore/render_data_store_manager.h"
44 #include "datastore/render_data_store_pod.h"
45 #include "default_engine_constants.h"
46 #include "device/device.h"
47 #include "device/gpu_resource_cache.h"
48 #include "device/gpu_resource_manager.h"
49 #include "device/gpu_resource_util.h"
50 #include "device/render_frame_sync.h"
51 #include "device/shader_manager.h"
52 #include "nodecontext/node_context_descriptor_set_manager.h"
53 #include "nodecontext/node_context_pso_manager.h"
54 #include "nodecontext/render_node_context_manager.h"
55 #include "nodecontext/render_node_graph_manager.h"
56 #include "nodecontext/render_node_graph_node_store.h"
57 #include "perf/cpu_timer.h"
58 #include "render_backend.h"
59 #include "render_context.h"
60 #include "render_graph.h"
61 #include "util/log.h"
62 #include "util/render_util.h"
63 
64 using namespace BASE_NS;
65 using namespace CORE_NS;
66 
67 RENDER_BEGIN_NAMESPACE()
68 namespace {
69 const string_view RENDER_DATA_STORE_DEFAULT_STAGING { "RenderDataStoreDefaultStaging" };
70 
71 // Helper class for running lambda as a ThreadPool task.
72 template<typename Fn>
73 class FunctionTask final : public IThreadPool::ITask {
74 public:
FunctionTask(Fn && func)75     explicit FunctionTask(Fn&& func) : func_(BASE_NS::move(func)) {};
76 
operator ()()77     void operator()() override
78     {
79         func_();
80     }
81 
82 protected:
Destroy()83     void Destroy() override
84     {
85         delete this;
86     }
87 
88 private:
89     Fn func_;
90 };
91 
92 template<typename Fn>
CreateFunctionTask(Fn && func)93 inline IThreadPool::ITask::Ptr CreateFunctionTask(Fn&& func)
94 {
95     return IThreadPool::ITask::Ptr { new FunctionTask<Fn>(BASE_NS::move(func)) };
96 }
97 
98 #if (RENDER_PERF_ENABLED == 1)
99 struct NodeTimerData {
100     CpuTimer timer;
101     string_view debugName;
102 };
103 #endif
104 
105 struct RenderNodeExecutionParameters {
106     const array_view<RenderNodeGraphNodeStore*> renderNodeGraphNodeStores;
107 #if (RENDER_PERF_ENABLED == 1)
108     vector<NodeTimerData>& nodeTimers;
109 #endif
110     ITaskQueue* queue;
111     IRenderDataStoreManager& renderData;
112     ShaderManager& shaderManager;
113     RenderingConfiguration& renderConfig;
114 };
115 
116 // Helper for Renderer::InitNodeGraph
InitializeRenderNodeContextData(IRenderContext & renderContext,RenderNodeGraphNodeStore & nodeStore,const bool enableMultiQueue,const RenderingConfiguration & renderConfig)117 unordered_map<string, uint32_t> InitializeRenderNodeContextData(IRenderContext& renderContext,
118     RenderNodeGraphNodeStore& nodeStore, const bool enableMultiQueue, const RenderingConfiguration& renderConfig)
119 {
120     unordered_map<string, uint32_t> renderNodeNameToIndex(nodeStore.renderNodeData.size());
121     vector<ContextInitDescription> contextInitDescs(nodeStore.renderNodeData.size());
122     for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
123         const auto& renderNodeData = nodeStore.renderNodeData[nodeIdx];
124         PLUGIN_ASSERT(renderNodeData.inputData);
125         PLUGIN_ASSERT(renderNodeData.node);
126         auto& inputData = *(renderNodeData.inputData);
127         auto& nodeContextData = nodeStore.renderNodeContextData[nodeIdx];
128 
129         renderNodeNameToIndex[renderNodeData.fullName] = (uint32_t)nodeIdx;
130 
131         // reset always, dependencies are redone with new nodes
132         nodeContextData.submitInfo.signalSemaphore = false;
133         nodeContextData.submitInfo.waitSemaphoreCount = 0;
134         nodeContextData.submitInfo.waitForSwapchainAcquireSignal = false;
135 
136         // with dynamic render node graphs, single nodes can be initialized
137         // set to true when doing the renderNode->InitNode();
138         if (nodeContextData.initialized) {
139             continue;
140         }
141 
142         auto& contextInitRef = contextInitDescs[nodeIdx];
143         contextInitRef.requestedQueue = inputData.queue;
144 
145         Device& device = (Device&)renderContext.GetDevice();
146         contextInitRef.requestedQueue = device.GetValidGpuQueue(contextInitRef.requestedQueue);
147 
148         ShaderManager& shaderMgr = (ShaderManager&)renderContext.GetDevice().GetShaderManager();
149         GpuResourceManager& gpuResourceMgr = (GpuResourceManager&)renderContext.GetDevice().GetGpuResourceManager();
150         // ordering is important
151         nodeContextData.nodeContextPsoMgr = make_unique<NodeContextPsoManager>(device, shaderMgr);
152         nodeContextData.nodeContextDescriptorSetMgr = device.CreateNodeContextDescriptorSetManager();
153         nodeContextData.renderCommandList =
154             make_unique<RenderCommandList>(renderNodeData.fullName, *nodeContextData.nodeContextDescriptorSetMgr,
155                 gpuResourceMgr, *nodeContextData.nodeContextPsoMgr, contextInitRef.requestedQueue, enableMultiQueue);
156         nodeContextData.nodeContextPoolMgr =
157             device.CreateNodeContextPoolManager(gpuResourceMgr, contextInitRef.requestedQueue);
158         RenderNodeGraphData rngd = { nodeStore.renderNodeGraphName, nodeStore.renderNodeGraphDataStoreName,
159             renderConfig };
160         RenderNodeContextManager::CreateInfo rncmci { renderContext, rngd, *renderNodeData.inputData,
161             renderNodeData.nodeName, renderNodeData.nodeJson, *nodeContextData.nodeContextDescriptorSetMgr,
162             *nodeContextData.nodeContextPsoMgr, *nodeContextData.renderCommandList,
163             *nodeStore.renderNodeGraphShareDataMgr };
164         nodeContextData.renderNodeContextManager = make_unique<RenderNodeContextManager>(rncmci);
165 #if ((RENDER_VALIDATION_ENABLED == 1) || (RENDER_VULKAN_VALIDATION_ENABLED == 1))
166         nodeContextData.nodeContextDescriptorSetMgr->SetValidationDebugName(renderNodeData.fullName);
167         nodeContextData.nodeContextPoolMgr->SetValidationDebugName(renderNodeData.fullName);
168 #endif
169         nodeContextData.renderBarrierList = make_unique<RenderBarrierList>(
170             (contextInitRef.requestedQueue.type != GpuQueue::QueueType::UNDEFINED) ? 4u : 0u);
171     }
172     return renderNodeNameToIndex;
173 }
174 
175 // Helper for Renderer::InitNodeGraph
PatchSignaling(RenderNodeGraphNodeStore & nodeStore,const unordered_map<string,uint32_t> & renderNodeNameToIndex)176 void PatchSignaling(RenderNodeGraphNodeStore& nodeStore, const unordered_map<string, uint32_t>& renderNodeNameToIndex)
177 {
178     PLUGIN_ASSERT(renderNodeNameToIndex.size() == nodeStore.renderNodeData.size());
179     for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
180         PLUGIN_ASSERT(nodeStore.renderNodeData[nodeIdx].inputData);
181         const auto& nodeInputDataRef = *(nodeStore.renderNodeData[nodeIdx].inputData);
182         auto& submitInfo = nodeStore.renderNodeContextData[nodeIdx].submitInfo;
183 
184         for (const auto& nodeNameRef : nodeInputDataRef.gpuQueueWaitForSignals.nodeNames) {
185             if (const auto iter = renderNodeNameToIndex.find(nodeNameRef); iter != renderNodeNameToIndex.cend()) {
186                 if (submitInfo.waitSemaphoreCount < PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) {
187                     const uint32_t index = iter->second;
188                     // mark node to signal
189                     nodeStore.renderNodeContextData[index].submitInfo.signalSemaphore = true;
190 
191                     submitInfo.waitSemaphoreNodeIndices[submitInfo.waitSemaphoreCount] = index;
192                     submitInfo.waitSemaphoreCount++;
193                 } else {
194                     PLUGIN_LOG_E("render node can wait only for (%u) render node signals",
195                         PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS);
196                     PLUGIN_ASSERT(false);
197                 }
198             } else {
199                 PLUGIN_LOG_E("invalid render node wait signal dependency");
200                 PLUGIN_ASSERT(false);
201             }
202         }
203     }
204 }
205 
206 // Helper for Renderer::RenderFrame
BeginRenderNodeGraph(RenderNodeGraphGlobalShareDataManager * rngGlobalShareDataMgr,const vector<RenderNodeGraphNodeStore * > & renderNodeGraphNodeStores,const RenderNodeContextManager::PerFrameTimings & timings)207 void BeginRenderNodeGraph(RenderNodeGraphGlobalShareDataManager* rngGlobalShareDataMgr,
208     const vector<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
209     const RenderNodeContextManager::PerFrameTimings& timings)
210 {
211     RenderNodeGraphShareDataManager* prevRngShareDataMgr = nullptr;
212     if (rngGlobalShareDataMgr) {
213         rngGlobalShareDataMgr->BeginFrame();
214     }
215     for (const RenderNodeGraphNodeStore* renderNodeDataStore : renderNodeGraphNodeStores) {
216         const uint32_t renderNodeCount = static_cast<uint32_t>(renderNodeDataStore->renderNodeContextData.size());
217         auto& rngShareData = renderNodeDataStore->renderNodeGraphShareData;
218         renderNodeDataStore->renderNodeGraphShareDataMgr->BeginFrame(rngGlobalShareDataMgr, prevRngShareDataMgr,
219             renderNodeCount, { rngShareData.inputs, rngShareData.inputCount },
220             { rngShareData.outputs, rngShareData.outputCount });
221         for (uint32_t idx = 0; idx < renderNodeCount; ++idx) {
222             const RenderNodeContextData& contextData = renderNodeDataStore->renderNodeContextData[idx];
223             contextData.renderCommandList->BeginFrame();
224             contextData.renderBarrierList->BeginFrame();
225             contextData.nodeContextPoolMgr->BeginFrame();
226             contextData.nodeContextDescriptorSetMgr->BeginFrame();
227             contextData.renderNodeContextManager->BeginFrame(idx, timings);
228         }
229         prevRngShareDataMgr = renderNodeDataStore->renderNodeGraphShareDataMgr.get();
230     }
231 }
232 
233 // Helper for Renderer::RenderFrame
FillRngNodeStores(array_view<const RenderHandle> inputs,RenderNodeGraphManager & renderNodeGraphMgr,vector<RenderNodeGraphNodeStore * > & rngNodeStores)234 inline void FillRngNodeStores(array_view<const RenderHandle> inputs, RenderNodeGraphManager& renderNodeGraphMgr,
235     vector<RenderNodeGraphNodeStore*>& rngNodeStores)
236 {
237     rngNodeStores.reserve(inputs.size());
238     for (auto const& input : inputs) {
239         rngNodeStores.push_back(renderNodeGraphMgr.Get(input));
240     }
241 }
242 
243 // Helper for Renderer::RenderFrame
WaitForFence(const Device & device,RenderFrameSync & renderFrameSync)244 inline bool WaitForFence(const Device& device, RenderFrameSync& renderFrameSync)
245 {
246     RENDER_CPU_PERF_SCOPE("Renderer", "Renderer", "WaitForFrameFence_Cpu");
247     renderFrameSync.WaitForFrameFence();
248 
249     return device.GetDeviceStatus();
250 }
251 
252 // Helper for Renderer::RenderFrame
ProcessRenderNodeGraph(Device & device,RenderGraph & renderGraph,array_view<RenderNodeGraphNodeStore * > graphNodeStoreView)253 inline void ProcessRenderNodeGraph(
254     Device& device, RenderGraph& renderGraph, array_view<RenderNodeGraphNodeStore*> graphNodeStoreView)
255 {
256     RENDER_CPU_PERF_SCOPE("Renderer", "Renderer", "RenderGraph_Cpu");
257     renderGraph.ProcessRenderNodeGraph(device.HasSwapchain(), graphNodeStoreView);
258 }
259 
260 // Helper for Renderer::ExecuteRenderNodes
CreateGpuResourcesWithRenderNodes(const array_view<RenderNodeGraphNodeStore * > & renderNodeGraphNodeStores,IRenderDataStoreManager & renderData,ShaderManager & shaderMgr)261 void CreateGpuResourcesWithRenderNodes(const array_view<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
262     IRenderDataStoreManager& renderData, ShaderManager& shaderMgr)
263 {
264     for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
265         PLUGIN_ASSERT(renderNodeGraphNodeStores[graphIdx]);
266 
267         RenderNodeGraphNodeStore const& nodeStore = *renderNodeGraphNodeStores[graphIdx];
268         for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
269             IRenderNode& renderNode = *(nodeStore.renderNodeData[nodeIdx].node);
270             renderNode.PreExecuteFrame();
271         }
272     }
273 }
274 
275 // Helper for Renderer::ExecuteRenderNodes
RenderNodeExecution(RenderNodeExecutionParameters & params)276 void RenderNodeExecution(RenderNodeExecutionParameters& params)
277 {
278 #if (RENDER_PERF_ENABLED == 1)
279     size_t allNodeIdx = 0;
280 #endif
281     uint64_t taskId = 0;
282     for (const auto* nodeStorePtr : params.renderNodeGraphNodeStores) {
283         // there shouldn't be nullptrs but let's play it safe
284         PLUGIN_ASSERT(nodeStorePtr);
285         if (nodeStorePtr) {
286             const auto& nodeStore = *nodeStorePtr;
287             for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
288                 PLUGIN_ASSERT(nodeStore.renderNodeData[nodeIdx].node);
289                 if (nodeStore.renderNodeData[nodeIdx].node) {
290                     IRenderNode& renderNode = *(nodeStore.renderNodeData[nodeIdx].node);
291                     RenderNodeContextData const& renderNodeContextData = nodeStore.renderNodeContextData[nodeIdx];
292                     PLUGIN_ASSERT(renderNodeContextData.renderCommandList);
293                     RenderCommandList& renderCommandList = *renderNodeContextData.renderCommandList;
294 
295                     // Do not run render node if the flag is set
296                     const uint32_t flags = renderNode.GetExecuteFlags();
297                     if ((renderNode.GetExecuteFlags() &
298                             IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE) == 0) {
299 #if (RENDER_PERF_ENABLED == 1)
300                         auto& timerRef = params.nodeTimers[allNodeIdx++];
301                         timerRef.debugName = nodeStore.renderNodeData[nodeIdx].fullName;
302                         params.queue->Submit(
303                             taskId++, CreateFunctionTask([&timerRef, &renderNode, &renderCommandList]() {
304                                 timerRef.timer.Begin();
305 
306                                 renderCommandList.BeforeRenderNodeExecuteFrame();
307                                 renderNode.ExecuteFrame(renderCommandList);
308                                 renderCommandList.AfterRenderNodeExecuteFrame();
309 
310                                 timerRef.timer.End();
311                             }));
312 #else
313                         params.queue->Submit(taskId++, CreateFunctionTask([&renderCommandList, &renderNode]() {
314                             renderCommandList.BeforeRenderNodeExecuteFrame();
315                             renderNode.ExecuteFrame(renderCommandList);
316                             renderCommandList.AfterRenderNodeExecuteFrame();
317                         }));
318 #endif
319                     }
320                 }
321             }
322         }
323     }
324 
325     // Execute and wait for completion.
326     params.queue->Execute();
327 }
328 
329 // Helper for Renderer::ExecuteRenderBackend
IterateRenderBackendNodeGraphNodeStores(const array_view<RenderNodeGraphNodeStore * > & renderNodeGraphNodeStores,const bool multiQueueEnabled,RenderCommandFrameData & rcfd)330 void IterateRenderBackendNodeGraphNodeStores(const array_view<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
331     const bool multiQueueEnabled, RenderCommandFrameData& rcfd)
332 {
333     for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
334         PLUGIN_ASSERT(renderNodeGraphNodeStores[graphIdx]);
335 
336         RenderNodeGraphNodeStore const& nodeStore = *renderNodeGraphNodeStores[graphIdx];
337 
338         unordered_map<uint32_t, uint32_t> nodeIdxToRenderCommandContextIdx;
339         const uint32_t multiQueuePatchBeginIdx = (uint32_t)rcfd.renderCommandContexts.size();
340         uint32_t multiQueuePatchCount = 0;
341         if (multiQueueEnabled) {
342             nodeIdxToRenderCommandContextIdx.reserve(nodeStore.renderNodeContextData.size());
343         }
344 
345         for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeContextData.size(); ++nodeIdx) {
346             const auto& ref = nodeStore.renderNodeContextData[nodeIdx];
347             PLUGIN_ASSERT((ref.renderCommandList != nullptr) && (ref.renderBarrierList != nullptr) &&
348                           (ref.nodeContextPsoMgr != nullptr) && (ref.nodeContextPoolMgr != nullptr));
349             const bool valid = (ref.renderCommandList->HasValidRenderCommands()) ? true : false;
350             if (valid) {
351                 if (multiQueueEnabled) {
352                     nodeIdxToRenderCommandContextIdx[(uint32_t)nodeIdx] = (uint32_t)rcfd.renderCommandContexts.size();
353                     multiQueuePatchCount++;
354                 }
355                 // get final backend node index of the first render node which uses the swapchain image
356                 const uint32_t backendNodeIdx = static_cast<uint32_t>(rcfd.renderCommandContexts.size());
357                 if ((rcfd.firstSwapchainNodeIdx > backendNodeIdx) && (ref.submitInfo.waitForSwapchainAcquireSignal)) {
358                     rcfd.firstSwapchainNodeIdx = static_cast<uint32_t>(rcfd.renderCommandContexts.size());
359                 }
360                 rcfd.renderCommandContexts.push_back({ ref.renderBackendNode, ref.renderCommandList.get(),
361                     ref.renderBarrierList.get(), ref.nodeContextPsoMgr.get(), ref.nodeContextDescriptorSetMgr.get(),
362                     ref.nodeContextPoolMgr.get(), (uint32_t)nodeIdx, ref.submitInfo,
363                     nodeStore.renderNodeData[nodeIdx].fullName });
364             }
365         }
366 
367         if (multiQueueEnabled) { // patch correct render command context indices
368             for (uint32_t idx = multiQueuePatchBeginIdx; idx < multiQueuePatchCount; ++idx) {
369                 auto& ref = rcfd.renderCommandContexts[idx];
370                 const auto& nodeContextRef = nodeStore.renderNodeContextData[ref.renderGraphRenderNodeIndex];
371 
372                 ref.submitDepencies.signalSemaphore = nodeContextRef.submitInfo.signalSemaphore;
373                 ref.submitDepencies.waitSemaphoreCount = nodeContextRef.submitInfo.waitSemaphoreCount;
374                 for (uint32_t waitIdx = 0; waitIdx < ref.submitDepencies.waitSemaphoreCount; ++waitIdx) {
375                     const uint32_t currRenderNodeIdx = nodeContextRef.submitInfo.waitSemaphoreNodeIndices[waitIdx];
376                     PLUGIN_ASSERT(nodeIdxToRenderCommandContextIdx.count(currRenderNodeIdx) == 1);
377 
378                     ref.submitDepencies.waitSemaphoreNodeIndices[waitIdx] =
379                         nodeIdxToRenderCommandContextIdx[currRenderNodeIdx];
380                 }
381             }
382         }
383     }
384 }
385 
386 template<typename T>
IsNull(T * ptr)387 inline bool IsNull(T* ptr)
388 {
389     return ptr == nullptr;
390 }
391 
GetTimeStampNow()392 inline int64_t GetTimeStampNow()
393 {
394     using namespace std::chrono;
395     using Clock = system_clock;
396     return Clock::now().time_since_epoch().count();
397 }
398 
CreateDefaultRenderNodeGraphs(const Device & device,RenderNodeGraphManager & rngMgr,RenderHandleReference & defaultStaging,RenderHandleReference & defaultEndFrameStaging)399 void CreateDefaultRenderNodeGraphs(const Device& device, RenderNodeGraphManager& rngMgr,
400     RenderHandleReference& defaultStaging, RenderHandleReference& defaultEndFrameStaging)
401 {
402     {
403         RenderNodeGraphDesc rngd;
404         {
405             RenderNodeDesc rnd;
406             rnd.typeName = "CORE_RN_STAGING";
407             rnd.nodeName = "CORE_RN_STAGING_I";
408             rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
409             rngd.nodes.push_back(move(rnd));
410         }
411 #if (RENDER_VULKAN_RT_ENABLED == 1)
412         if (device.GetBackendType() == DeviceBackendType::VULKAN) {
413             RenderNodeDesc rnd;
414             rnd.typeName = "CORE_RN_DEFAULT_ACCELERATION_STRUCTURE_STAGING";
415             rnd.nodeName = "CORE_RN_DEFAULT_ACCELERATION_STRUCTURE_STAGING_I";
416             rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
417             rngd.nodes.push_back(move(rnd));
418         }
419 #endif
420         defaultStaging =
421             rngMgr.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, rngd);
422     }
423     {
424         RenderNodeGraphDesc rngd;
425         {
426             RenderNodeDesc rnd;
427             rnd.typeName = "CORE_RN_END_FRAME_STAGING";
428             rnd.nodeName = "CORE_RN_END_FRAME_STAGING_I";
429             rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
430             rngd.nodes.push_back(move(rnd));
431         }
432         defaultEndFrameStaging =
433             rngMgr.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, rngd);
434     }
435 }
436 
437 constexpr uint32_t CHECK_RENDER_FLAGS { RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_BACKEND |
438                                         RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_PRESENT };
439 
440 } // namespace
441 
Renderer(IRenderContext & context)442 Renderer::Renderer(IRenderContext& context)
443     : renderContext_(context), device_(static_cast<Device&>(context.GetDevice())),
444       gpuResourceMgr_(static_cast<GpuResourceManager&>(device_.GetGpuResourceManager())),
445       shaderMgr_(static_cast<ShaderManager&>(device_.GetShaderManager())),
446       renderNodeGraphMgr_(static_cast<RenderNodeGraphManager&>(context.GetRenderNodeGraphManager())),
447       renderDataStoreMgr_(static_cast<RenderDataStoreManager&>(context.GetRenderDataStoreManager())),
448       renderUtil_(static_cast<RenderUtil&>(context.GetRenderUtil()))
449 
450 {
451     const RenderCreateInfo rci = ((const RenderContext&)renderContext_).GetCreateInfo();
452     if (rci.createFlags & RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_BACKEND) {
453         separatedRendering_.separateBackend = true;
454     }
455     if (rci.createFlags & RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_PRESENT) {
456         separatedRendering_.separatePresent = true;
457     }
458 
459     const auto factory = GetInstance<ITaskQueueFactory>(UID_TASK_QUEUE_FACTORY);
460     threadPool_ = factory->CreateThreadPool(factory->GetNumberOfCores());
461     parallelQueue_ = factory->CreateParallelTaskQueue(threadPool_);
462     sequentialQueue_ = factory->CreateSequentialTaskQueue(threadPool_);
463 
464     renderConfig_ = { device_.GetBackendType(), RenderingConfiguration::NdcOrigin::TOP_LEFT };
465 #if ((RENDER_HAS_GL_BACKEND) || (RENDER_HAS_GLES_BACKEND)) && (RENDER_GL_FLIP_Y_SWAPCHAIN == 0)
466     // The flag is for informative purposes only.
467     if ((renderConfig_.renderBackend == DeviceBackendType::OPENGL) ||
468         (renderConfig_.renderBackend == DeviceBackendType::OPENGLES)) {
469         renderConfig_.ndcOrigin = RenderingConfiguration::NdcOrigin::BOTTOM_LEFT;
470     }
471 #endif
472 
473     renderGraph_ = make_unique<RenderGraph>(gpuResourceMgr_);
474     renderBackend_ = device_.CreateRenderBackend(gpuResourceMgr_, parallelQueue_);
475     renderFrameSync_ = device_.CreateRenderFrameSync();
476     rngGlobalShareDataMgr_ = make_unique<RenderNodeGraphGlobalShareDataManager>();
477 
478     CreateDefaultRenderNodeGraphs(device_, renderNodeGraphMgr_, defaultStagingRng_, defaultEndFrameStagingRng_);
479 
480     dsStaging_ = static_cast<IRenderDataStoreDefaultStaging*>(
481         renderDataStoreMgr_.GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING));
482 }
483 
~Renderer()484 Renderer::~Renderer() {}
485 
InitNodeGraphs(const array_view<const RenderHandle> renderNodeGraphs)486 void Renderer::InitNodeGraphs(const array_view<const RenderHandle> renderNodeGraphs)
487 {
488     const RenderNodeGraphShareDataManager* prevRngShareDataMgr = nullptr;
489     for (const auto& rng : renderNodeGraphs) {
490         auto renderNodeDataStore = renderNodeGraphMgr_.Get(rng);
491         if (!renderNodeDataStore) {
492             continue;
493         }
494 
495         RenderNodeGraphNodeStore& nodeStore = *renderNodeDataStore;
496         if (nodeStore.initialized) {
497             continue;
498         }
499         nodeStore.initialized = true;
500 
501         const bool enableMultiQueue = (device_.GetGpuQueueCount() > 1);
502 
503         // serial, initialize render node context data
504         auto renderNodeNameToIndex =
505             InitializeRenderNodeContextData(renderContext_, nodeStore, enableMultiQueue, renderConfig_);
506 
507         if (enableMultiQueue) {
508             // patch gpu queue signaling
509             PatchSignaling(nodeStore, renderNodeNameToIndex);
510         }
511 
512         // NOTE: needs to be called once before init. every frame called in BeginRenderNodeGraph()
513         nodeStore.renderNodeGraphShareDataMgr->BeginFrame(rngGlobalShareDataMgr_.get(), prevRngShareDataMgr,
514             static_cast<uint32_t>(nodeStore.renderNodeData.size()),
515             { nodeStore.renderNodeGraphShareData.inputs, nodeStore.renderNodeGraphShareData.inputCount },
516             { nodeStore.renderNodeGraphShareData.outputs, nodeStore.renderNodeGraphShareData.outputCount });
517         prevRngShareDataMgr = nodeStore.renderNodeGraphShareDataMgr.get();
518 
519         const RenderNodeContextManager::PerFrameTimings timings { 0, 0, device_.GetFrameCount() };
520         for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
521             auto& nodeContextData = nodeStore.renderNodeContextData[nodeIdx];
522             if (nodeContextData.initialized) {
523                 continue;
524             }
525             nodeContextData.initialized = true;
526 
527             // NOTE: needs to be called once before init. every frame called in BeginRenderNodeGraph()
528             nodeContextData.renderNodeContextManager->BeginFrame(static_cast<uint32_t>(nodeIdx), timings);
529 
530             auto& renderNodeData = nodeStore.renderNodeData[nodeIdx];
531             PLUGIN_ASSERT(renderNodeData.inputData);
532             PLUGIN_ASSERT(renderNodeData.node);
533 
534             RENDER_CPU_PERF_SCOPE("Renderer", "Renderer_InitNode_Cpu", renderNodeData.fullName);
535             renderNodeData.node->InitNode(*(nodeContextData.renderNodeContextManager));
536         }
537     }
538 }
539 
540 // Helper for Renderer::RenderFrame
RemapBackBufferHandle(const IRenderDataStoreManager & renderData)541 void Renderer::RemapBackBufferHandle(const IRenderDataStoreManager& renderData)
542 {
543     const auto* dataStorePod =
544         static_cast<IRenderDataStorePod*>(renderData.GetRenderDataStore(RenderDataStorePod::TYPE_NAME));
545     if (dataStorePod) {
546         auto const dataView = dataStorePod->Get("NodeGraphBackBufferConfiguration");
547         const auto bb = reinterpret_cast<const NodeGraphBackBufferConfiguration*>(dataView.data());
548         if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::SWAPCHAIN) {
549             if (!device_.HasSwapchain()) {
550                 PLUGIN_LOG_E("Using swapchain rendering without swapchain");
551             }
552         } else if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::GPU_IMAGE) {
553             const RenderHandle handle = gpuResourceMgr_.GetImageRawHandle(bb->backBufferName);
554             if (RenderHandleUtil::IsValid(handle) && RenderHandleUtil::IsValid(bb->backBufferHandle)) {
555                 gpuResourceMgr_.RemapGpuImageHandle(handle, bb->backBufferHandle);
556             }
557         } else if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::GPU_IMAGE_BUFFER_COPY) {
558             const RenderHandle handle = gpuResourceMgr_.GetImageRawHandle(bb->backBufferName);
559             if (RenderHandleUtil::IsValid(handle) && RenderHandleUtil::IsValid(bb->backBufferHandle) &&
560                 RenderHandleUtil::IsValid(bb->gpuBufferHandle)) {
561                 gpuResourceMgr_.RemapGpuImageHandle(handle, bb->backBufferHandle);
562             }
563             // handle image to buffer copy via post frame staging
564             {
565                 RenderHandle backbufferHandle = bb->backBufferHandle;
566                 if (bb->backBufferName == DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER) {
567                     // we need to use the core default backbuffer handle and not the replaced handle in this situation
568                     backbufferHandle =
569                         gpuResourceMgr_.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER)
570                             .GetHandle();
571                 }
572                 const GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(backbufferHandle);
573                 const BufferImageCopy bic {
574                     0,                                                                // bufferOffset
575                     0,                                                                // bufferRowLength
576                     0,                                                                // bufferImageHeight
577                     ImageSubresourceLayers { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u }, // imageSubresource
578                     Size3D { 0, 0, 0 },                                               // imageOffset
579                     Size3D { desc.width, desc.height, 1u },                           // imageExtent
580                 };
581                 dsStaging_->CopyImageToBuffer(gpuResourceMgr_.Get(backbufferHandle),
582                     gpuResourceMgr_.Get(bb->gpuBufferHandle), bic,
583                     IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
584             }
585         }
586     }
587 }
588 
RenderFrameImpl(const array_view<const RenderHandle> renderNodeGraphs)589 void Renderer::RenderFrameImpl(const array_view<const RenderHandle> renderNodeGraphs)
590 {
591     if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
592         separatedRendering_.frontMtx.lock();
593     }
594 
595     Tick();
596     frameTimes_.begin = GetTimeStampNow();
597     RENDER_CPU_PERF_SCOPE("Renderer", "Frame", "RenderFrame");
598 
599     if (device_.GetDeviceStatus() == false) {
600         ProcessTimeStampEnd();
601 #if (RENDER_VALIDATION_ENABLED == 1)
602         PLUGIN_LOG_ONCE_E("invalid_device_status_render_frame", "invalid device for rendering");
603 #endif
604         return;
605     }
606     const IRenderDataStoreManager::RenderDataStoreFlags rdsFlags = renderDataStoreMgr_.GetRenderDataStoreFlags();
607     if (rdsFlags & IRenderDataStoreManager::DOUBLE_BUFFERED_RENDER_DATA_STORES) {
608 #if (RENDER_VALIDATION_ENABLED == 1)
609         renderDataStoreMgr_.ValidateCommitFrameData();
610 #endif
611     }
612     renderDataStoreMgr_.CommitFrameData();
613 
614     device_.Activate();
615     device_.FrameStart();
616     renderFrameTimeData_.frameIndex = device_.GetFrameCount();
617 
618     (static_cast<GpuResourceCache&>(gpuResourceMgr_.GetGpuResourceCache())).BeginFrame(device_.GetFrameCount());
619 
620     // handle utils (needs to be called before render data store pre renders)
621     renderUtil_.BeginFrame();
622 
623     // remap the default back buffer (needs to be called before render data store pre renders)
624     RemapBackBufferHandle(renderDataStoreMgr_);
625 
626     renderNodeGraphMgr_.HandlePendingAllocations();
627     renderDataStoreMgr_.PreRender();
628 
629     // create new shaders if any created this frame (needs to be called before render node init)
630     shaderMgr_.HandlePendingAllocations();
631 
632     auto& rngInputs = renderFrameTimeData_.rngInputs;
633     auto& rngNodeStores = renderFrameTimeData_.rngNodeStores;
634     PLUGIN_ASSERT(rngInputs.empty());
635     PLUGIN_ASSERT(rngNodeStores.empty());
636 
637     // update render node graphs with default staging
638     FillRngInputs(renderNodeGraphs, rngInputs);
639     const auto renderNodeGraphInputs = array_view(rngInputs.data(), rngInputs.size());
640 
641     InitNodeGraphs(renderNodeGraphInputs);
642     device_.Deactivate();
643 
644     renderGraph_->BeginFrame();
645 
646     FillRngNodeStores(renderNodeGraphInputs, renderNodeGraphMgr_, rngNodeStores);
647     if (std::any_of(rngNodeStores.begin(), rngNodeStores.end(), IsNull<RenderNodeGraphNodeStore>)) {
648         ProcessTimeStampEnd();
649         PLUGIN_LOG_W("invalid render node graphs for rendering");
650         return;
651     }
652 
653     // NodeContextPoolManagerGLES::BeginFrame may delete FBOs and device must be active.
654     device_.Activate();
655 
656     renderFrameSync_->BeginFrame();
657     // begin frame (advance ring buffers etc.)
658     const RenderNodeContextManager::PerFrameTimings timings { previousFrameTime_ - firstTime_, deltaTime_,
659         device_.GetFrameCount() };
660     BeginRenderNodeGraph(rngGlobalShareDataMgr_.get(), rngNodeStores, timings);
661 
662     // synchronize, needed for persistantly mapped gpu buffer writing
663     if (!WaitForFence(device_, *renderFrameSync_)) {
664         device_.Deactivate();
665         return; // possible lost device with frame fence
666     }
667 
668     // gpu resource allocation and deallocation
669     gpuResourceMgr_.HandlePendingAllocations();
670 
671     device_.Deactivate();
672 
673     const auto nodeStoresView = array_view<RenderNodeGraphNodeStore*>(rngNodeStores);
674     ExecuteRenderNodes(renderNodeGraphInputs, nodeStoresView);
675 
676     // render graph process for all render nodes of all render graphs
677     ProcessRenderNodeGraph(device_, *renderGraph_, nodeStoresView);
678 
679     renderDataStoreMgr_.PostRender();
680 
681     // set front-end index (before mutexes)
682     renderStatus_.frontEndIndex = renderFrameTimeData_.frameIndex;
683     if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
684         separatedRendering_.frontMtx.unlock();
685     }
686     if (!separatedRendering_.separateBackend) {
687         RenderFrameBackendImpl();
688     }
689 }
690 
RenderFrameBackendImpl()691 void Renderer::RenderFrameBackendImpl()
692 {
693     if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
694         separatedRendering_.frontMtx.lock();
695         separatedRendering_.backMtx.lock();
696     }
697 
698     auto& rngInputs = renderFrameTimeData_.rngInputs;
699     auto& rngNodeStores = renderFrameTimeData_.rngNodeStores;
700 
701     device_.SetLockResourceBackendAccess(true);
702     renderDataStoreMgr_.PreRenderBackend();
703 
704     size_t allRenderNodeCount = 0;
705     for (const auto* nodeStore : rngNodeStores) {
706         PLUGIN_ASSERT(nodeStore);
707         allRenderNodeCount += nodeStore->renderNodeData.size();
708     }
709 
710     RenderCommandFrameData rcfd;
711     PLUGIN_ASSERT(renderFrameSync_);
712     rcfd.renderFrameSync = renderFrameSync_.get();
713     rcfd.renderFrameUtil = &(static_cast<RenderFrameUtil&>(renderContext_.GetRenderUtil().GetRenderFrameUtil()));
714     rcfd.renderCommandContexts.reserve(allRenderNodeCount);
715 
716     const bool multiQueueEnabled = (device_.GetGpuQueueCount() > 1u);
717     IterateRenderBackendNodeGraphNodeStores(rngNodeStores, multiQueueEnabled, rcfd);
718 
719     // NOTE: by node graph name
720     // NOTE: deprecate this
721     const RenderGraph::SwapchainStates bbState = renderGraph_->GetSwapchainResourceStates();
722     RenderBackendBackBufferConfiguration config;
723     for (const auto& swapState : bbState.swapchains) {
724         config.swapchainData.push_back({ swapState.handle, swapState.state, swapState.layout, {} });
725     }
726     if (!config.swapchainData.empty()) {
727         // NOTE: this is a backwards compatibility for a single (default) swapchain config data
728         // should be removed
729         if (auto const dataStorePod = static_cast<IRenderDataStorePod const*>(
730                 renderDataStoreMgr_.GetRenderDataStore(RenderDataStorePod::TYPE_NAME));
731             dataStorePod) {
732             auto const dataView = dataStorePod->Get("NodeGraphBackBufferConfiguration");
733             if (dataView.size_bytes() == sizeof(NodeGraphBackBufferConfiguration)) {
734                 // expects to be the first swapchain in the list
735                 const NodeGraphBackBufferConfiguration* bb = (const NodeGraphBackBufferConfiguration*)dataView.data();
736                 config.swapchainData[0U].config = *bb;
737             }
738         }
739     }
740     renderFrameTimeData_.config = config;
741     renderFrameTimeData_.hasBackendWork = (!rcfd.renderCommandContexts.empty());
742 
743     device_.Activate();
744 
745     if (renderFrameTimeData_.hasBackendWork) { // do not execute backend with zero work
746         device_.SetRenderBackendRunning(true);
747 
748         frameTimes_.beginBackend = GetTimeStampNow();
749         renderBackend_->Render(rcfd, config);
750         frameTimes_.endBackend = GetTimeStampNow();
751 
752         device_.SetRenderBackendRunning(false);
753     }
754     gpuResourceMgr_.EndFrame();
755 
756     if (separatedRendering_.separatePresent) {
757         device_.Deactivate();
758     }
759 
760     device_.SetLockResourceBackendAccess(false);
761 
762     // clear
763     rngInputs.clear();
764     rngNodeStores.clear();
765 
766     // set backend-end index (before mutexes)
767     renderStatus_.backEndIndex = renderStatus_.frontEndIndex;
768     if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
769         separatedRendering_.frontMtx.unlock();
770         separatedRendering_.backMtx.unlock();
771     }
772     if (!separatedRendering_.separatePresent) {
773         RenderFramePresentImpl();
774     }
775 }
776 
RenderFramePresentImpl()777 void Renderer::RenderFramePresentImpl()
778 {
779     if (separatedRendering_.separatePresent) {
780         separatedRendering_.backMtx.lock();
781     }
782 
783     if (renderFrameTimeData_.hasBackendWork) { // do not execute backend with zero work
784         if (separatedRendering_.separatePresent) {
785             device_.Activate();
786         }
787 
788         frameTimes_.beginBackendPresent = GetTimeStampNow();
789         renderBackend_->Present(renderFrameTimeData_.config);
790         frameTimes_.endBackendPresent = GetTimeStampNow();
791 
792         if (separatedRendering_.separatePresent) {
793             device_.Deactivate();
794         }
795     }
796     if (!separatedRendering_.separatePresent) {
797         device_.Deactivate();
798     }
799 
800     renderDataStoreMgr_.PostRenderBackend();
801 
802     renderFrameTimeData_.config = {};
803 
804     // needs to be called after render data store post render
805     renderUtil_.EndFrame();
806 
807     // RenderFramePresentImpl() needs to be called every frame even thought there isn't presenting
808     device_.FrameEnd();
809     ProcessTimeStampEnd();
810 
811     // set presentation index (before mutexes)
812     renderStatus_.presentIndex = renderStatus_.backEndIndex;
813     if (separatedRendering_.separatePresent) {
814         separatedRendering_.backMtx.unlock();
815     }
816 }
817 
RenderFrame(const array_view<const RenderHandleReference> renderNodeGraphs)818 uint64_t Renderer::RenderFrame(const array_view<const RenderHandleReference> renderNodeGraphs)
819 {
820     const auto lock = std::lock_guard(renderMutex_);
821 
822     // add only unique and valid handles to list for rendering
823     vector<RenderHandle> rngs;
824     rngs.reserve(renderNodeGraphs.size());
825     for (size_t iIdx = 0; iIdx < renderNodeGraphs.size(); ++iIdx) {
826         const RenderHandle& handle = renderNodeGraphs[iIdx].GetHandle();
827         bool duplicate = false;
828         for (auto& ref : rngs) {
829             if (ref == handle) {
830                 duplicate = true;
831             }
832         }
833         if ((RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) && (!duplicate)) {
834             rngs.push_back(handle);
835         }
836 #if (RENDER_VALIDATION_ENABLED == 1)
837         if (duplicate) {
838             PLUGIN_LOG_ONCE_E("renderer_rf_duplicate_rng",
839                 "RENDER_VALIDATION: duplicate render node graphs are not supported (idx: %u, id: %" PRIx64,
840                 static_cast<uint32_t>(iIdx), handle.id);
841         }
842 #endif
843     }
844     device_.SetRenderFrameRunning(true);
845     // NOTE: this is the only place from where RenderFrameImpl is called
846     RenderFrameImpl(rngs);
847     device_.SetRenderFrameRunning(false);
848 
849     return renderStatus_.frontEndIndex;
850 }
851 
RenderDeferred(const array_view<const RenderHandleReference> renderNodeGraphs)852 uint64_t Renderer::RenderDeferred(const array_view<const RenderHandleReference> renderNodeGraphs)
853 {
854     const auto lock = std::lock_guard(deferredMutex_);
855     for (const auto& ref : renderNodeGraphs) {
856         deferredRenderNodeGraphs_.push_back(ref);
857     }
858     return renderStatusDeferred_ + 1;
859 }
860 
RenderDeferredFrame()861 uint64_t Renderer::RenderDeferredFrame()
862 {
863     deferredMutex_.lock();
864     decltype(deferredRenderNodeGraphs_) renderNodeGraphs = move(deferredRenderNodeGraphs_);
865     renderStatusDeferred_ = renderStatus_.frontEndIndex + 1;
866     deferredMutex_.unlock();
867     RenderFrame(renderNodeGraphs);
868 
869     return renderStatus_.frontEndIndex;
870 }
871 
ExecuteRenderNodes(const array_view<const RenderHandle> renderNodeGraphInputs,const array_view<RenderNodeGraphNodeStore * > renderNodeGraphNodeStores)872 void Renderer::ExecuteRenderNodes(const array_view<const RenderHandle> renderNodeGraphInputs,
873     const array_view<RenderNodeGraphNodeStore*> renderNodeGraphNodeStores)
874 {
875 #if (RENDER_PERF_ENABLED == 1)
876     RENDER_CPU_PERF_BEGIN(fullExecuteCpuTimer, "Renderer", "Renderer", "ExecuteAllNodes_Cpu");
877 
878     size_t allRenderNodeCount = 0;
879     for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
880         allRenderNodeCount += renderNodeGraphNodeStores[graphIdx]->renderNodeData.size();
881     }
882 
883     vector<NodeTimerData> nodeTimers(allRenderNodeCount);
884 #endif
885 
886     ITaskQueue* queue = nullptr;
887     if (device_.AllowThreadedProcessing()) {
888         queue = parallelQueue_.get();
889     } else {
890         queue = sequentialQueue_.get();
891     }
892 
893     // single threaded gpu resource creation with render nodes
894     CreateGpuResourcesWithRenderNodes(renderNodeGraphNodeStores, renderDataStoreMgr_, shaderMgr_);
895 
896     // lock staging data for this frame
897     // NOTE: should be done with double buffering earlier
898     gpuResourceMgr_.LockFrameStagingData();
899     // final gpu resource allocation and deallocation before render node execute, and render graph
900     device_.Activate();
901     gpuResourceMgr_.HandlePendingAllocations();
902     device_.Deactivate();
903 
904     // process render node graph render node share preparations
905     for (auto& ref : renderNodeGraphNodeStores) {
906         ref->renderNodeGraphShareDataMgr->PrepareExecuteFrame();
907     }
908 
909     RenderNodeExecutionParameters params = {
910         renderNodeGraphNodeStores,
911 #if (RENDER_PERF_ENABLED == 1)
912         nodeTimers,
913 #endif
914         queue,
915         renderDataStoreMgr_,
916         shaderMgr_,
917         renderConfig_
918     };
919 
920     // multi-threaded render node execution
921     RenderNodeExecution(params);
922 
923     // Remove tasks.
924     queue->Clear();
925 
926 #if (RENDER_PERF_ENABLED == 1)
927     RENDER_CPU_PERF_END(fullExecuteCpuTimer);
928 
929     if (auto* inst = GetInstance<IPerformanceDataManagerFactory>(UID_PERFORMANCE_FACTORY); inst) {
930         if (IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
931             for (size_t nodeIdx = 0; nodeIdx < nodeTimers.size(); ++nodeIdx) {
932                 const auto& timerRef = nodeTimers[nodeIdx];
933                 perfData->UpdateData(timerRef.debugName, "RenderNodeExecute_Cpu", timerRef.timer.GetMicroseconds());
934             }
935         }
936     }
937 #endif
938 }
939 
RenderFrameBackend(const RenderFrameBackendInfo & info)940 uint64_t Renderer::RenderFrameBackend(const RenderFrameBackendInfo& info)
941 {
942     if (separatedRendering_.separateBackend) {
943         RenderFrameBackendImpl();
944     } else {
945         PLUGIN_LOG_E("RenderFrameBackend called separately even though render context not created as separate");
946     }
947 
948     return renderStatus_.backEndIndex;
949 }
950 
RenderFramePresent(const RenderFramePresentInfo & info)951 uint64_t Renderer::RenderFramePresent(const RenderFramePresentInfo& info)
952 {
953     if (separatedRendering_.separatePresent) {
954         RenderFramePresentImpl();
955     } else {
956         PLUGIN_LOG_E("RenderFramePresent called separately even though render context not created as separate");
957     }
958 
959     return renderStatus_.presentIndex;
960 }
961 
GetFrameStatus() const962 IRenderer::RenderStatus Renderer::GetFrameStatus() const
963 {
964     return renderStatus_;
965 }
966 
FillRngInputs(const array_view<const RenderHandle> renderNodeGraphInputList,vector<RenderHandle> & rngInputs)967 void Renderer::FillRngInputs(
968     const array_view<const RenderHandle> renderNodeGraphInputList, vector<RenderHandle>& rngInputs)
969 {
970     constexpr size_t defaultRenderNodeGraphCount = 2;
971     rngInputs.reserve(renderNodeGraphInputList.size() + defaultRenderNodeGraphCount);
972     rngInputs.push_back(defaultStagingRng_.GetHandle());
973     rngInputs.insert(rngInputs.end(), renderNodeGraphInputList.begin().ptr(), renderNodeGraphInputList.end().ptr());
974     rngInputs.push_back(defaultEndFrameStagingRng_.GetHandle());
975 }
976 
ProcessTimeStampEnd()977 void Renderer::ProcessTimeStampEnd()
978 {
979     frameTimes_.end = GetTimeStampNow();
980 
981     int64_t finalTime = frameTimes_.begin;
982     finalTime = Math::max(finalTime, frameTimes_.beginBackend);
983     frameTimes_.beginBackend = finalTime;
984 
985     finalTime = Math::max(finalTime, frameTimes_.endBackend);
986     frameTimes_.endBackend = finalTime;
987 
988     finalTime = Math::max(finalTime, frameTimes_.beginBackendPresent);
989     frameTimes_.beginBackendPresent = finalTime;
990 
991     finalTime = Math::max(finalTime, frameTimes_.endBackendPresent);
992     frameTimes_.endBackendPresent = finalTime;
993 
994     finalTime = Math::max(finalTime, frameTimes_.end);
995     frameTimes_.end = finalTime;
996 
997     PLUGIN_ASSERT(frameTimes_.end >= frameTimes_.endBackend);
998     PLUGIN_ASSERT(frameTimes_.endBackend >= frameTimes_.beginBackend);
999     PLUGIN_ASSERT(frameTimes_.beginBackendPresent >= frameTimes_.beginBackend);
1000     PLUGIN_ASSERT(frameTimes_.endBackendPresent >= frameTimes_.beginBackendPresent);
1001 
1002     renderUtil_.SetRenderTimings(frameTimes_);
1003     frameTimes_ = {};
1004 }
1005 
Tick()1006 void Renderer::Tick()
1007 {
1008     using namespace std::chrono;
1009     const auto currentTime =
1010         static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
1011 
1012     if (firstTime_ == ~0u) {
1013         previousFrameTime_ = firstTime_ = currentTime;
1014     }
1015     deltaTime_ = currentTime - previousFrameTime_;
1016     constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
1017     if (deltaTime_ > limitHz) {
1018         deltaTime_ = limitHz; // clamp the time step to no longer than 15hz.
1019     }
1020     previousFrameTime_ = currentTime;
1021 }
1022 RENDER_END_NAMESPACE()
1023