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