18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "renderer.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <algorithm>
198bf80f4bSopenharmony_ci#include <chrono>
208bf80f4bSopenharmony_ci#include <cinttypes>
218bf80f4bSopenharmony_ci#include <utility>
228bf80f4bSopenharmony_ci
238bf80f4bSopenharmony_ci#include <base/containers/string.h>
248bf80f4bSopenharmony_ci#include <base/containers/string_view.h>
258bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h>
268bf80f4bSopenharmony_ci#include <base/containers/vector.h>
278bf80f4bSopenharmony_ci#include <core/perf/intf_performance_data_manager.h>
288bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_default_staging.h>
298bf80f4bSopenharmony_ci#include <render/datastore/intf_render_data_store_manager.h>
308bf80f4bSopenharmony_ci#include <render/datastore/render_data_store_render_pods.h>
318bf80f4bSopenharmony_ci#include <render/intf_render_context.h>
328bf80f4bSopenharmony_ci#include <render/intf_renderer.h>
338bf80f4bSopenharmony_ci#include <render/namespace.h>
348bf80f4bSopenharmony_ci#include <render/nodecontext/intf_render_node.h>
358bf80f4bSopenharmony_ci#include <render/render_data_structures.h>
368bf80f4bSopenharmony_ci
378bf80f4bSopenharmony_ci#include "perf/cpu_perf_scope.h"
388bf80f4bSopenharmony_ci
398bf80f4bSopenharmony_ci#if (RENDER_DEV_ENABLED == 1)
408bf80f4bSopenharmony_ci#include <cinttypes>
418bf80f4bSopenharmony_ci#endif
428bf80f4bSopenharmony_ci
438bf80f4bSopenharmony_ci#include "datastore/render_data_store_manager.h"
448bf80f4bSopenharmony_ci#include "datastore/render_data_store_pod.h"
458bf80f4bSopenharmony_ci#include "default_engine_constants.h"
468bf80f4bSopenharmony_ci#include "device/device.h"
478bf80f4bSopenharmony_ci#include "device/gpu_resource_cache.h"
488bf80f4bSopenharmony_ci#include "device/gpu_resource_manager.h"
498bf80f4bSopenharmony_ci#include "device/gpu_resource_util.h"
508bf80f4bSopenharmony_ci#include "device/render_frame_sync.h"
518bf80f4bSopenharmony_ci#include "device/shader_manager.h"
528bf80f4bSopenharmony_ci#include "nodecontext/node_context_descriptor_set_manager.h"
538bf80f4bSopenharmony_ci#include "nodecontext/node_context_pso_manager.h"
548bf80f4bSopenharmony_ci#include "nodecontext/render_node_context_manager.h"
558bf80f4bSopenharmony_ci#include "nodecontext/render_node_graph_manager.h"
568bf80f4bSopenharmony_ci#include "nodecontext/render_node_graph_node_store.h"
578bf80f4bSopenharmony_ci#include "perf/cpu_timer.h"
588bf80f4bSopenharmony_ci#include "render_backend.h"
598bf80f4bSopenharmony_ci#include "render_context.h"
608bf80f4bSopenharmony_ci#include "render_graph.h"
618bf80f4bSopenharmony_ci#include "util/log.h"
628bf80f4bSopenharmony_ci#include "util/render_util.h"
638bf80f4bSopenharmony_ci
648bf80f4bSopenharmony_ciusing namespace BASE_NS;
658bf80f4bSopenharmony_ciusing namespace CORE_NS;
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE()
688bf80f4bSopenharmony_cinamespace {
698bf80f4bSopenharmony_ciconst string_view RENDER_DATA_STORE_DEFAULT_STAGING { "RenderDataStoreDefaultStaging" };
708bf80f4bSopenharmony_ci
718bf80f4bSopenharmony_ci// Helper class for running lambda as a ThreadPool task.
728bf80f4bSopenharmony_citemplate<typename Fn>
738bf80f4bSopenharmony_ciclass FunctionTask final : public IThreadPool::ITask {
748bf80f4bSopenharmony_cipublic:
758bf80f4bSopenharmony_ci    explicit FunctionTask(Fn&& func) : func_(BASE_NS::move(func)) {};
768bf80f4bSopenharmony_ci
778bf80f4bSopenharmony_ci    void operator()() override
788bf80f4bSopenharmony_ci    {
798bf80f4bSopenharmony_ci        func_();
808bf80f4bSopenharmony_ci    }
818bf80f4bSopenharmony_ci
828bf80f4bSopenharmony_ciprotected:
838bf80f4bSopenharmony_ci    void Destroy() override
848bf80f4bSopenharmony_ci    {
858bf80f4bSopenharmony_ci        delete this;
868bf80f4bSopenharmony_ci    }
878bf80f4bSopenharmony_ci
888bf80f4bSopenharmony_ciprivate:
898bf80f4bSopenharmony_ci    Fn func_;
908bf80f4bSopenharmony_ci};
918bf80f4bSopenharmony_ci
928bf80f4bSopenharmony_citemplate<typename Fn>
938bf80f4bSopenharmony_ciinline IThreadPool::ITask::Ptr CreateFunctionTask(Fn&& func)
948bf80f4bSopenharmony_ci{
958bf80f4bSopenharmony_ci    return IThreadPool::ITask::Ptr { new FunctionTask<Fn>(BASE_NS::move(func)) };
968bf80f4bSopenharmony_ci}
978bf80f4bSopenharmony_ci
988bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
998bf80f4bSopenharmony_cistruct NodeTimerData {
1008bf80f4bSopenharmony_ci    CpuTimer timer;
1018bf80f4bSopenharmony_ci    string_view debugName;
1028bf80f4bSopenharmony_ci};
1038bf80f4bSopenharmony_ci#endif
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_cistruct RenderNodeExecutionParameters {
1068bf80f4bSopenharmony_ci    const array_view<RenderNodeGraphNodeStore*> renderNodeGraphNodeStores;
1078bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
1088bf80f4bSopenharmony_ci    vector<NodeTimerData>& nodeTimers;
1098bf80f4bSopenharmony_ci#endif
1108bf80f4bSopenharmony_ci    ITaskQueue* queue;
1118bf80f4bSopenharmony_ci    IRenderDataStoreManager& renderData;
1128bf80f4bSopenharmony_ci    ShaderManager& shaderManager;
1138bf80f4bSopenharmony_ci    RenderingConfiguration& renderConfig;
1148bf80f4bSopenharmony_ci};
1158bf80f4bSopenharmony_ci
1168bf80f4bSopenharmony_ci// Helper for Renderer::InitNodeGraph
1178bf80f4bSopenharmony_ciunordered_map<string, uint32_t> InitializeRenderNodeContextData(IRenderContext& renderContext,
1188bf80f4bSopenharmony_ci    RenderNodeGraphNodeStore& nodeStore, const bool enableMultiQueue, const RenderingConfiguration& renderConfig)
1198bf80f4bSopenharmony_ci{
1208bf80f4bSopenharmony_ci    unordered_map<string, uint32_t> renderNodeNameToIndex(nodeStore.renderNodeData.size());
1218bf80f4bSopenharmony_ci    vector<ContextInitDescription> contextInitDescs(nodeStore.renderNodeData.size());
1228bf80f4bSopenharmony_ci    for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
1238bf80f4bSopenharmony_ci        const auto& renderNodeData = nodeStore.renderNodeData[nodeIdx];
1248bf80f4bSopenharmony_ci        PLUGIN_ASSERT(renderNodeData.inputData);
1258bf80f4bSopenharmony_ci        PLUGIN_ASSERT(renderNodeData.node);
1268bf80f4bSopenharmony_ci        auto& inputData = *(renderNodeData.inputData);
1278bf80f4bSopenharmony_ci        auto& nodeContextData = nodeStore.renderNodeContextData[nodeIdx];
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci        renderNodeNameToIndex[renderNodeData.fullName] = (uint32_t)nodeIdx;
1308bf80f4bSopenharmony_ci
1318bf80f4bSopenharmony_ci        // reset always, dependencies are redone with new nodes
1328bf80f4bSopenharmony_ci        nodeContextData.submitInfo.signalSemaphore = false;
1338bf80f4bSopenharmony_ci        nodeContextData.submitInfo.waitSemaphoreCount = 0;
1348bf80f4bSopenharmony_ci        nodeContextData.submitInfo.waitForSwapchainAcquireSignal = false;
1358bf80f4bSopenharmony_ci
1368bf80f4bSopenharmony_ci        // with dynamic render node graphs, single nodes can be initialized
1378bf80f4bSopenharmony_ci        // set to true when doing the renderNode->InitNode();
1388bf80f4bSopenharmony_ci        if (nodeContextData.initialized) {
1398bf80f4bSopenharmony_ci            continue;
1408bf80f4bSopenharmony_ci        }
1418bf80f4bSopenharmony_ci
1428bf80f4bSopenharmony_ci        auto& contextInitRef = contextInitDescs[nodeIdx];
1438bf80f4bSopenharmony_ci        contextInitRef.requestedQueue = inputData.queue;
1448bf80f4bSopenharmony_ci
1458bf80f4bSopenharmony_ci        Device& device = (Device&)renderContext.GetDevice();
1468bf80f4bSopenharmony_ci        contextInitRef.requestedQueue = device.GetValidGpuQueue(contextInitRef.requestedQueue);
1478bf80f4bSopenharmony_ci
1488bf80f4bSopenharmony_ci        ShaderManager& shaderMgr = (ShaderManager&)renderContext.GetDevice().GetShaderManager();
1498bf80f4bSopenharmony_ci        GpuResourceManager& gpuResourceMgr = (GpuResourceManager&)renderContext.GetDevice().GetGpuResourceManager();
1508bf80f4bSopenharmony_ci        // ordering is important
1518bf80f4bSopenharmony_ci        nodeContextData.nodeContextPsoMgr = make_unique<NodeContextPsoManager>(device, shaderMgr);
1528bf80f4bSopenharmony_ci        nodeContextData.nodeContextDescriptorSetMgr = device.CreateNodeContextDescriptorSetManager();
1538bf80f4bSopenharmony_ci        nodeContextData.renderCommandList =
1548bf80f4bSopenharmony_ci            make_unique<RenderCommandList>(renderNodeData.fullName, *nodeContextData.nodeContextDescriptorSetMgr,
1558bf80f4bSopenharmony_ci                gpuResourceMgr, *nodeContextData.nodeContextPsoMgr, contextInitRef.requestedQueue, enableMultiQueue);
1568bf80f4bSopenharmony_ci        nodeContextData.nodeContextPoolMgr =
1578bf80f4bSopenharmony_ci            device.CreateNodeContextPoolManager(gpuResourceMgr, contextInitRef.requestedQueue);
1588bf80f4bSopenharmony_ci        RenderNodeGraphData rngd = { nodeStore.renderNodeGraphName, nodeStore.renderNodeGraphDataStoreName,
1598bf80f4bSopenharmony_ci            renderConfig };
1608bf80f4bSopenharmony_ci        RenderNodeContextManager::CreateInfo rncmci { renderContext, rngd, *renderNodeData.inputData,
1618bf80f4bSopenharmony_ci            renderNodeData.nodeName, renderNodeData.nodeJson, *nodeContextData.nodeContextDescriptorSetMgr,
1628bf80f4bSopenharmony_ci            *nodeContextData.nodeContextPsoMgr, *nodeContextData.renderCommandList,
1638bf80f4bSopenharmony_ci            *nodeStore.renderNodeGraphShareDataMgr };
1648bf80f4bSopenharmony_ci        nodeContextData.renderNodeContextManager = make_unique<RenderNodeContextManager>(rncmci);
1658bf80f4bSopenharmony_ci#if ((RENDER_VALIDATION_ENABLED == 1) || (RENDER_VULKAN_VALIDATION_ENABLED == 1))
1668bf80f4bSopenharmony_ci        nodeContextData.nodeContextDescriptorSetMgr->SetValidationDebugName(renderNodeData.fullName);
1678bf80f4bSopenharmony_ci        nodeContextData.nodeContextPoolMgr->SetValidationDebugName(renderNodeData.fullName);
1688bf80f4bSopenharmony_ci#endif
1698bf80f4bSopenharmony_ci        nodeContextData.renderBarrierList = make_unique<RenderBarrierList>(
1708bf80f4bSopenharmony_ci            (contextInitRef.requestedQueue.type != GpuQueue::QueueType::UNDEFINED) ? 4u : 0u);
1718bf80f4bSopenharmony_ci    }
1728bf80f4bSopenharmony_ci    return renderNodeNameToIndex;
1738bf80f4bSopenharmony_ci}
1748bf80f4bSopenharmony_ci
1758bf80f4bSopenharmony_ci// Helper for Renderer::InitNodeGraph
1768bf80f4bSopenharmony_civoid PatchSignaling(RenderNodeGraphNodeStore& nodeStore, const unordered_map<string, uint32_t>& renderNodeNameToIndex)
1778bf80f4bSopenharmony_ci{
1788bf80f4bSopenharmony_ci    PLUGIN_ASSERT(renderNodeNameToIndex.size() == nodeStore.renderNodeData.size());
1798bf80f4bSopenharmony_ci    for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
1808bf80f4bSopenharmony_ci        PLUGIN_ASSERT(nodeStore.renderNodeData[nodeIdx].inputData);
1818bf80f4bSopenharmony_ci        const auto& nodeInputDataRef = *(nodeStore.renderNodeData[nodeIdx].inputData);
1828bf80f4bSopenharmony_ci        auto& submitInfo = nodeStore.renderNodeContextData[nodeIdx].submitInfo;
1838bf80f4bSopenharmony_ci
1848bf80f4bSopenharmony_ci        for (const auto& nodeNameRef : nodeInputDataRef.gpuQueueWaitForSignals.nodeNames) {
1858bf80f4bSopenharmony_ci            if (const auto iter = renderNodeNameToIndex.find(nodeNameRef); iter != renderNodeNameToIndex.cend()) {
1868bf80f4bSopenharmony_ci                if (submitInfo.waitSemaphoreCount < PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS) {
1878bf80f4bSopenharmony_ci                    const uint32_t index = iter->second;
1888bf80f4bSopenharmony_ci                    // mark node to signal
1898bf80f4bSopenharmony_ci                    nodeStore.renderNodeContextData[index].submitInfo.signalSemaphore = true;
1908bf80f4bSopenharmony_ci
1918bf80f4bSopenharmony_ci                    submitInfo.waitSemaphoreNodeIndices[submitInfo.waitSemaphoreCount] = index;
1928bf80f4bSopenharmony_ci                    submitInfo.waitSemaphoreCount++;
1938bf80f4bSopenharmony_ci                } else {
1948bf80f4bSopenharmony_ci                    PLUGIN_LOG_E("render node can wait only for (%u) render node signals",
1958bf80f4bSopenharmony_ci                        PipelineStateConstants::MAX_RENDER_NODE_GPU_WAIT_SIGNALS);
1968bf80f4bSopenharmony_ci                    PLUGIN_ASSERT(false);
1978bf80f4bSopenharmony_ci                }
1988bf80f4bSopenharmony_ci            } else {
1998bf80f4bSopenharmony_ci                PLUGIN_LOG_E("invalid render node wait signal dependency");
2008bf80f4bSopenharmony_ci                PLUGIN_ASSERT(false);
2018bf80f4bSopenharmony_ci            }
2028bf80f4bSopenharmony_ci        }
2038bf80f4bSopenharmony_ci    }
2048bf80f4bSopenharmony_ci}
2058bf80f4bSopenharmony_ci
2068bf80f4bSopenharmony_ci// Helper for Renderer::RenderFrame
2078bf80f4bSopenharmony_civoid BeginRenderNodeGraph(RenderNodeGraphGlobalShareDataManager* rngGlobalShareDataMgr,
2088bf80f4bSopenharmony_ci    const vector<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
2098bf80f4bSopenharmony_ci    const RenderNodeContextManager::PerFrameTimings& timings)
2108bf80f4bSopenharmony_ci{
2118bf80f4bSopenharmony_ci    RenderNodeGraphShareDataManager* prevRngShareDataMgr = nullptr;
2128bf80f4bSopenharmony_ci    if (rngGlobalShareDataMgr) {
2138bf80f4bSopenharmony_ci        rngGlobalShareDataMgr->BeginFrame();
2148bf80f4bSopenharmony_ci    }
2158bf80f4bSopenharmony_ci    for (const RenderNodeGraphNodeStore* renderNodeDataStore : renderNodeGraphNodeStores) {
2168bf80f4bSopenharmony_ci        const uint32_t renderNodeCount = static_cast<uint32_t>(renderNodeDataStore->renderNodeContextData.size());
2178bf80f4bSopenharmony_ci        auto& rngShareData = renderNodeDataStore->renderNodeGraphShareData;
2188bf80f4bSopenharmony_ci        renderNodeDataStore->renderNodeGraphShareDataMgr->BeginFrame(rngGlobalShareDataMgr, prevRngShareDataMgr,
2198bf80f4bSopenharmony_ci            renderNodeCount, { rngShareData.inputs, rngShareData.inputCount },
2208bf80f4bSopenharmony_ci            { rngShareData.outputs, rngShareData.outputCount });
2218bf80f4bSopenharmony_ci        for (uint32_t idx = 0; idx < renderNodeCount; ++idx) {
2228bf80f4bSopenharmony_ci            const RenderNodeContextData& contextData = renderNodeDataStore->renderNodeContextData[idx];
2238bf80f4bSopenharmony_ci            contextData.renderCommandList->BeginFrame();
2248bf80f4bSopenharmony_ci            contextData.renderBarrierList->BeginFrame();
2258bf80f4bSopenharmony_ci            contextData.nodeContextPoolMgr->BeginFrame();
2268bf80f4bSopenharmony_ci            contextData.nodeContextDescriptorSetMgr->BeginFrame();
2278bf80f4bSopenharmony_ci            contextData.renderNodeContextManager->BeginFrame(idx, timings);
2288bf80f4bSopenharmony_ci        }
2298bf80f4bSopenharmony_ci        prevRngShareDataMgr = renderNodeDataStore->renderNodeGraphShareDataMgr.get();
2308bf80f4bSopenharmony_ci    }
2318bf80f4bSopenharmony_ci}
2328bf80f4bSopenharmony_ci
2338bf80f4bSopenharmony_ci// Helper for Renderer::RenderFrame
2348bf80f4bSopenharmony_ciinline void FillRngNodeStores(array_view<const RenderHandle> inputs, RenderNodeGraphManager& renderNodeGraphMgr,
2358bf80f4bSopenharmony_ci    vector<RenderNodeGraphNodeStore*>& rngNodeStores)
2368bf80f4bSopenharmony_ci{
2378bf80f4bSopenharmony_ci    rngNodeStores.reserve(inputs.size());
2388bf80f4bSopenharmony_ci    for (auto const& input : inputs) {
2398bf80f4bSopenharmony_ci        rngNodeStores.push_back(renderNodeGraphMgr.Get(input));
2408bf80f4bSopenharmony_ci    }
2418bf80f4bSopenharmony_ci}
2428bf80f4bSopenharmony_ci
2438bf80f4bSopenharmony_ci// Helper for Renderer::RenderFrame
2448bf80f4bSopenharmony_ciinline bool WaitForFence(const Device& device, RenderFrameSync& renderFrameSync)
2458bf80f4bSopenharmony_ci{
2468bf80f4bSopenharmony_ci    RENDER_CPU_PERF_SCOPE("Renderer", "Renderer", "WaitForFrameFence_Cpu");
2478bf80f4bSopenharmony_ci    renderFrameSync.WaitForFrameFence();
2488bf80f4bSopenharmony_ci
2498bf80f4bSopenharmony_ci    return device.GetDeviceStatus();
2508bf80f4bSopenharmony_ci}
2518bf80f4bSopenharmony_ci
2528bf80f4bSopenharmony_ci// Helper for Renderer::RenderFrame
2538bf80f4bSopenharmony_ciinline void ProcessRenderNodeGraph(
2548bf80f4bSopenharmony_ci    Device& device, RenderGraph& renderGraph, array_view<RenderNodeGraphNodeStore*> graphNodeStoreView)
2558bf80f4bSopenharmony_ci{
2568bf80f4bSopenharmony_ci    RENDER_CPU_PERF_SCOPE("Renderer", "Renderer", "RenderGraph_Cpu");
2578bf80f4bSopenharmony_ci    renderGraph.ProcessRenderNodeGraph(device.HasSwapchain(), graphNodeStoreView);
2588bf80f4bSopenharmony_ci}
2598bf80f4bSopenharmony_ci
2608bf80f4bSopenharmony_ci// Helper for Renderer::ExecuteRenderNodes
2618bf80f4bSopenharmony_civoid CreateGpuResourcesWithRenderNodes(const array_view<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
2628bf80f4bSopenharmony_ci    IRenderDataStoreManager& renderData, ShaderManager& shaderMgr)
2638bf80f4bSopenharmony_ci{
2648bf80f4bSopenharmony_ci    for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
2658bf80f4bSopenharmony_ci        PLUGIN_ASSERT(renderNodeGraphNodeStores[graphIdx]);
2668bf80f4bSopenharmony_ci
2678bf80f4bSopenharmony_ci        RenderNodeGraphNodeStore const& nodeStore = *renderNodeGraphNodeStores[graphIdx];
2688bf80f4bSopenharmony_ci        for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
2698bf80f4bSopenharmony_ci            IRenderNode& renderNode = *(nodeStore.renderNodeData[nodeIdx].node);
2708bf80f4bSopenharmony_ci            renderNode.PreExecuteFrame();
2718bf80f4bSopenharmony_ci        }
2728bf80f4bSopenharmony_ci    }
2738bf80f4bSopenharmony_ci}
2748bf80f4bSopenharmony_ci
2758bf80f4bSopenharmony_ci// Helper for Renderer::ExecuteRenderNodes
2768bf80f4bSopenharmony_civoid RenderNodeExecution(RenderNodeExecutionParameters& params)
2778bf80f4bSopenharmony_ci{
2788bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
2798bf80f4bSopenharmony_ci    size_t allNodeIdx = 0;
2808bf80f4bSopenharmony_ci#endif
2818bf80f4bSopenharmony_ci    uint64_t taskId = 0;
2828bf80f4bSopenharmony_ci    for (const auto* nodeStorePtr : params.renderNodeGraphNodeStores) {
2838bf80f4bSopenharmony_ci        // there shouldn't be nullptrs but let's play it safe
2848bf80f4bSopenharmony_ci        PLUGIN_ASSERT(nodeStorePtr);
2858bf80f4bSopenharmony_ci        if (nodeStorePtr) {
2868bf80f4bSopenharmony_ci            const auto& nodeStore = *nodeStorePtr;
2878bf80f4bSopenharmony_ci            for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
2888bf80f4bSopenharmony_ci                PLUGIN_ASSERT(nodeStore.renderNodeData[nodeIdx].node);
2898bf80f4bSopenharmony_ci                if (nodeStore.renderNodeData[nodeIdx].node) {
2908bf80f4bSopenharmony_ci                    IRenderNode& renderNode = *(nodeStore.renderNodeData[nodeIdx].node);
2918bf80f4bSopenharmony_ci                    RenderNodeContextData const& renderNodeContextData = nodeStore.renderNodeContextData[nodeIdx];
2928bf80f4bSopenharmony_ci                    PLUGIN_ASSERT(renderNodeContextData.renderCommandList);
2938bf80f4bSopenharmony_ci                    RenderCommandList& renderCommandList = *renderNodeContextData.renderCommandList;
2948bf80f4bSopenharmony_ci
2958bf80f4bSopenharmony_ci                    // Do not run render node if the flag is set
2968bf80f4bSopenharmony_ci                    const uint32_t flags = renderNode.GetExecuteFlags();
2978bf80f4bSopenharmony_ci                    if ((renderNode.GetExecuteFlags() &
2988bf80f4bSopenharmony_ci                            IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE) == 0) {
2998bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
3008bf80f4bSopenharmony_ci                        auto& timerRef = params.nodeTimers[allNodeIdx++];
3018bf80f4bSopenharmony_ci                        timerRef.debugName = nodeStore.renderNodeData[nodeIdx].fullName;
3028bf80f4bSopenharmony_ci                        params.queue->Submit(
3038bf80f4bSopenharmony_ci                            taskId++, CreateFunctionTask([&timerRef, &renderNode, &renderCommandList]() {
3048bf80f4bSopenharmony_ci                                timerRef.timer.Begin();
3058bf80f4bSopenharmony_ci
3068bf80f4bSopenharmony_ci                                renderCommandList.BeforeRenderNodeExecuteFrame();
3078bf80f4bSopenharmony_ci                                renderNode.ExecuteFrame(renderCommandList);
3088bf80f4bSopenharmony_ci                                renderCommandList.AfterRenderNodeExecuteFrame();
3098bf80f4bSopenharmony_ci
3108bf80f4bSopenharmony_ci                                timerRef.timer.End();
3118bf80f4bSopenharmony_ci                            }));
3128bf80f4bSopenharmony_ci#else
3138bf80f4bSopenharmony_ci                        params.queue->Submit(taskId++, CreateFunctionTask([&renderCommandList, &renderNode]() {
3148bf80f4bSopenharmony_ci                            renderCommandList.BeforeRenderNodeExecuteFrame();
3158bf80f4bSopenharmony_ci                            renderNode.ExecuteFrame(renderCommandList);
3168bf80f4bSopenharmony_ci                            renderCommandList.AfterRenderNodeExecuteFrame();
3178bf80f4bSopenharmony_ci                        }));
3188bf80f4bSopenharmony_ci#endif
3198bf80f4bSopenharmony_ci                    }
3208bf80f4bSopenharmony_ci                }
3218bf80f4bSopenharmony_ci            }
3228bf80f4bSopenharmony_ci        }
3238bf80f4bSopenharmony_ci    }
3248bf80f4bSopenharmony_ci
3258bf80f4bSopenharmony_ci    // Execute and wait for completion.
3268bf80f4bSopenharmony_ci    params.queue->Execute();
3278bf80f4bSopenharmony_ci}
3288bf80f4bSopenharmony_ci
3298bf80f4bSopenharmony_ci// Helper for Renderer::ExecuteRenderBackend
3308bf80f4bSopenharmony_civoid IterateRenderBackendNodeGraphNodeStores(const array_view<RenderNodeGraphNodeStore*>& renderNodeGraphNodeStores,
3318bf80f4bSopenharmony_ci    const bool multiQueueEnabled, RenderCommandFrameData& rcfd)
3328bf80f4bSopenharmony_ci{
3338bf80f4bSopenharmony_ci    for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
3348bf80f4bSopenharmony_ci        PLUGIN_ASSERT(renderNodeGraphNodeStores[graphIdx]);
3358bf80f4bSopenharmony_ci
3368bf80f4bSopenharmony_ci        RenderNodeGraphNodeStore const& nodeStore = *renderNodeGraphNodeStores[graphIdx];
3378bf80f4bSopenharmony_ci
3388bf80f4bSopenharmony_ci        unordered_map<uint32_t, uint32_t> nodeIdxToRenderCommandContextIdx;
3398bf80f4bSopenharmony_ci        const uint32_t multiQueuePatchBeginIdx = (uint32_t)rcfd.renderCommandContexts.size();
3408bf80f4bSopenharmony_ci        uint32_t multiQueuePatchCount = 0;
3418bf80f4bSopenharmony_ci        if (multiQueueEnabled) {
3428bf80f4bSopenharmony_ci            nodeIdxToRenderCommandContextIdx.reserve(nodeStore.renderNodeContextData.size());
3438bf80f4bSopenharmony_ci        }
3448bf80f4bSopenharmony_ci
3458bf80f4bSopenharmony_ci        for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeContextData.size(); ++nodeIdx) {
3468bf80f4bSopenharmony_ci            const auto& ref = nodeStore.renderNodeContextData[nodeIdx];
3478bf80f4bSopenharmony_ci            PLUGIN_ASSERT((ref.renderCommandList != nullptr) && (ref.renderBarrierList != nullptr) &&
3488bf80f4bSopenharmony_ci                          (ref.nodeContextPsoMgr != nullptr) && (ref.nodeContextPoolMgr != nullptr));
3498bf80f4bSopenharmony_ci            const bool valid = (ref.renderCommandList->HasValidRenderCommands()) ? true : false;
3508bf80f4bSopenharmony_ci            if (valid) {
3518bf80f4bSopenharmony_ci                if (multiQueueEnabled) {
3528bf80f4bSopenharmony_ci                    nodeIdxToRenderCommandContextIdx[(uint32_t)nodeIdx] = (uint32_t)rcfd.renderCommandContexts.size();
3538bf80f4bSopenharmony_ci                    multiQueuePatchCount++;
3548bf80f4bSopenharmony_ci                }
3558bf80f4bSopenharmony_ci                // get final backend node index of the first render node which uses the swapchain image
3568bf80f4bSopenharmony_ci                const uint32_t backendNodeIdx = static_cast<uint32_t>(rcfd.renderCommandContexts.size());
3578bf80f4bSopenharmony_ci                if ((rcfd.firstSwapchainNodeIdx > backendNodeIdx) && (ref.submitInfo.waitForSwapchainAcquireSignal)) {
3588bf80f4bSopenharmony_ci                    rcfd.firstSwapchainNodeIdx = static_cast<uint32_t>(rcfd.renderCommandContexts.size());
3598bf80f4bSopenharmony_ci                }
3608bf80f4bSopenharmony_ci                rcfd.renderCommandContexts.push_back({ ref.renderBackendNode, ref.renderCommandList.get(),
3618bf80f4bSopenharmony_ci                    ref.renderBarrierList.get(), ref.nodeContextPsoMgr.get(), ref.nodeContextDescriptorSetMgr.get(),
3628bf80f4bSopenharmony_ci                    ref.nodeContextPoolMgr.get(), (uint32_t)nodeIdx, ref.submitInfo,
3638bf80f4bSopenharmony_ci                    nodeStore.renderNodeData[nodeIdx].fullName });
3648bf80f4bSopenharmony_ci            }
3658bf80f4bSopenharmony_ci        }
3668bf80f4bSopenharmony_ci
3678bf80f4bSopenharmony_ci        if (multiQueueEnabled) { // patch correct render command context indices
3688bf80f4bSopenharmony_ci            for (uint32_t idx = multiQueuePatchBeginIdx; idx < multiQueuePatchCount; ++idx) {
3698bf80f4bSopenharmony_ci                auto& ref = rcfd.renderCommandContexts[idx];
3708bf80f4bSopenharmony_ci                const auto& nodeContextRef = nodeStore.renderNodeContextData[ref.renderGraphRenderNodeIndex];
3718bf80f4bSopenharmony_ci
3728bf80f4bSopenharmony_ci                ref.submitDepencies.signalSemaphore = nodeContextRef.submitInfo.signalSemaphore;
3738bf80f4bSopenharmony_ci                ref.submitDepencies.waitSemaphoreCount = nodeContextRef.submitInfo.waitSemaphoreCount;
3748bf80f4bSopenharmony_ci                for (uint32_t waitIdx = 0; waitIdx < ref.submitDepencies.waitSemaphoreCount; ++waitIdx) {
3758bf80f4bSopenharmony_ci                    const uint32_t currRenderNodeIdx = nodeContextRef.submitInfo.waitSemaphoreNodeIndices[waitIdx];
3768bf80f4bSopenharmony_ci                    PLUGIN_ASSERT(nodeIdxToRenderCommandContextIdx.count(currRenderNodeIdx) == 1);
3778bf80f4bSopenharmony_ci
3788bf80f4bSopenharmony_ci                    ref.submitDepencies.waitSemaphoreNodeIndices[waitIdx] =
3798bf80f4bSopenharmony_ci                        nodeIdxToRenderCommandContextIdx[currRenderNodeIdx];
3808bf80f4bSopenharmony_ci                }
3818bf80f4bSopenharmony_ci            }
3828bf80f4bSopenharmony_ci        }
3838bf80f4bSopenharmony_ci    }
3848bf80f4bSopenharmony_ci}
3858bf80f4bSopenharmony_ci
3868bf80f4bSopenharmony_citemplate<typename T>
3878bf80f4bSopenharmony_ciinline bool IsNull(T* ptr)
3888bf80f4bSopenharmony_ci{
3898bf80f4bSopenharmony_ci    return ptr == nullptr;
3908bf80f4bSopenharmony_ci}
3918bf80f4bSopenharmony_ci
3928bf80f4bSopenharmony_ciinline int64_t GetTimeStampNow()
3938bf80f4bSopenharmony_ci{
3948bf80f4bSopenharmony_ci    using namespace std::chrono;
3958bf80f4bSopenharmony_ci    using Clock = system_clock;
3968bf80f4bSopenharmony_ci    return Clock::now().time_since_epoch().count();
3978bf80f4bSopenharmony_ci}
3988bf80f4bSopenharmony_ci
3998bf80f4bSopenharmony_civoid CreateDefaultRenderNodeGraphs(const Device& device, RenderNodeGraphManager& rngMgr,
4008bf80f4bSopenharmony_ci    RenderHandleReference& defaultStaging, RenderHandleReference& defaultEndFrameStaging)
4018bf80f4bSopenharmony_ci{
4028bf80f4bSopenharmony_ci    {
4038bf80f4bSopenharmony_ci        RenderNodeGraphDesc rngd;
4048bf80f4bSopenharmony_ci        {
4058bf80f4bSopenharmony_ci            RenderNodeDesc rnd;
4068bf80f4bSopenharmony_ci            rnd.typeName = "CORE_RN_STAGING";
4078bf80f4bSopenharmony_ci            rnd.nodeName = "CORE_RN_STAGING_I";
4088bf80f4bSopenharmony_ci            rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
4098bf80f4bSopenharmony_ci            rngd.nodes.push_back(move(rnd));
4108bf80f4bSopenharmony_ci        }
4118bf80f4bSopenharmony_ci#if (RENDER_VULKAN_RT_ENABLED == 1)
4128bf80f4bSopenharmony_ci        if (device.GetBackendType() == DeviceBackendType::VULKAN) {
4138bf80f4bSopenharmony_ci            RenderNodeDesc rnd;
4148bf80f4bSopenharmony_ci            rnd.typeName = "CORE_RN_DEFAULT_ACCELERATION_STRUCTURE_STAGING";
4158bf80f4bSopenharmony_ci            rnd.nodeName = "CORE_RN_DEFAULT_ACCELERATION_STRUCTURE_STAGING_I";
4168bf80f4bSopenharmony_ci            rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
4178bf80f4bSopenharmony_ci            rngd.nodes.push_back(move(rnd));
4188bf80f4bSopenharmony_ci        }
4198bf80f4bSopenharmony_ci#endif
4208bf80f4bSopenharmony_ci        defaultStaging =
4218bf80f4bSopenharmony_ci            rngMgr.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, rngd);
4228bf80f4bSopenharmony_ci    }
4238bf80f4bSopenharmony_ci    {
4248bf80f4bSopenharmony_ci        RenderNodeGraphDesc rngd;
4258bf80f4bSopenharmony_ci        {
4268bf80f4bSopenharmony_ci            RenderNodeDesc rnd;
4278bf80f4bSopenharmony_ci            rnd.typeName = "CORE_RN_END_FRAME_STAGING";
4288bf80f4bSopenharmony_ci            rnd.nodeName = "CORE_RN_END_FRAME_STAGING_I";
4298bf80f4bSopenharmony_ci            rnd.description.queue = { GpuQueue::QueueType::GRAPHICS, 0u };
4308bf80f4bSopenharmony_ci            rngd.nodes.push_back(move(rnd));
4318bf80f4bSopenharmony_ci        }
4328bf80f4bSopenharmony_ci        defaultEndFrameStaging =
4338bf80f4bSopenharmony_ci            rngMgr.Create(IRenderNodeGraphManager::RenderNodeGraphUsageType::RENDER_NODE_GRAPH_STATIC, rngd);
4348bf80f4bSopenharmony_ci    }
4358bf80f4bSopenharmony_ci}
4368bf80f4bSopenharmony_ci
4378bf80f4bSopenharmony_ciconstexpr uint32_t CHECK_RENDER_FLAGS { RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_BACKEND |
4388bf80f4bSopenharmony_ci                                        RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_PRESENT };
4398bf80f4bSopenharmony_ci
4408bf80f4bSopenharmony_ci} // namespace
4418bf80f4bSopenharmony_ci
4428bf80f4bSopenharmony_ciRenderer::Renderer(IRenderContext& context)
4438bf80f4bSopenharmony_ci    : renderContext_(context), device_(static_cast<Device&>(context.GetDevice())),
4448bf80f4bSopenharmony_ci      gpuResourceMgr_(static_cast<GpuResourceManager&>(device_.GetGpuResourceManager())),
4458bf80f4bSopenharmony_ci      shaderMgr_(static_cast<ShaderManager&>(device_.GetShaderManager())),
4468bf80f4bSopenharmony_ci      renderNodeGraphMgr_(static_cast<RenderNodeGraphManager&>(context.GetRenderNodeGraphManager())),
4478bf80f4bSopenharmony_ci      renderDataStoreMgr_(static_cast<RenderDataStoreManager&>(context.GetRenderDataStoreManager())),
4488bf80f4bSopenharmony_ci      renderUtil_(static_cast<RenderUtil&>(context.GetRenderUtil()))
4498bf80f4bSopenharmony_ci
4508bf80f4bSopenharmony_ci{
4518bf80f4bSopenharmony_ci    const RenderCreateInfo rci = ((const RenderContext&)renderContext_).GetCreateInfo();
4528bf80f4bSopenharmony_ci    if (rci.createFlags & RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_BACKEND) {
4538bf80f4bSopenharmony_ci        separatedRendering_.separateBackend = true;
4548bf80f4bSopenharmony_ci    }
4558bf80f4bSopenharmony_ci    if (rci.createFlags & RenderCreateInfo::CreateInfoFlagBits::SEPARATE_RENDER_FRAME_PRESENT) {
4568bf80f4bSopenharmony_ci        separatedRendering_.separatePresent = true;
4578bf80f4bSopenharmony_ci    }
4588bf80f4bSopenharmony_ci
4598bf80f4bSopenharmony_ci    const auto factory = GetInstance<ITaskQueueFactory>(UID_TASK_QUEUE_FACTORY);
4608bf80f4bSopenharmony_ci    threadPool_ = factory->CreateThreadPool(factory->GetNumberOfCores());
4618bf80f4bSopenharmony_ci    parallelQueue_ = factory->CreateParallelTaskQueue(threadPool_);
4628bf80f4bSopenharmony_ci    sequentialQueue_ = factory->CreateSequentialTaskQueue(threadPool_);
4638bf80f4bSopenharmony_ci
4648bf80f4bSopenharmony_ci    renderConfig_ = { device_.GetBackendType(), RenderingConfiguration::NdcOrigin::TOP_LEFT };
4658bf80f4bSopenharmony_ci#if ((RENDER_HAS_GL_BACKEND) || (RENDER_HAS_GLES_BACKEND)) && (RENDER_GL_FLIP_Y_SWAPCHAIN == 0)
4668bf80f4bSopenharmony_ci    // The flag is for informative purposes only.
4678bf80f4bSopenharmony_ci    if ((renderConfig_.renderBackend == DeviceBackendType::OPENGL) ||
4688bf80f4bSopenharmony_ci        (renderConfig_.renderBackend == DeviceBackendType::OPENGLES)) {
4698bf80f4bSopenharmony_ci        renderConfig_.ndcOrigin = RenderingConfiguration::NdcOrigin::BOTTOM_LEFT;
4708bf80f4bSopenharmony_ci    }
4718bf80f4bSopenharmony_ci#endif
4728bf80f4bSopenharmony_ci
4738bf80f4bSopenharmony_ci    renderGraph_ = make_unique<RenderGraph>(gpuResourceMgr_);
4748bf80f4bSopenharmony_ci    renderBackend_ = device_.CreateRenderBackend(gpuResourceMgr_, parallelQueue_);
4758bf80f4bSopenharmony_ci    renderFrameSync_ = device_.CreateRenderFrameSync();
4768bf80f4bSopenharmony_ci    rngGlobalShareDataMgr_ = make_unique<RenderNodeGraphGlobalShareDataManager>();
4778bf80f4bSopenharmony_ci
4788bf80f4bSopenharmony_ci    CreateDefaultRenderNodeGraphs(device_, renderNodeGraphMgr_, defaultStagingRng_, defaultEndFrameStagingRng_);
4798bf80f4bSopenharmony_ci
4808bf80f4bSopenharmony_ci    dsStaging_ = static_cast<IRenderDataStoreDefaultStaging*>(
4818bf80f4bSopenharmony_ci        renderDataStoreMgr_.GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING));
4828bf80f4bSopenharmony_ci}
4838bf80f4bSopenharmony_ci
4848bf80f4bSopenharmony_ciRenderer::~Renderer() {}
4858bf80f4bSopenharmony_ci
4868bf80f4bSopenharmony_civoid Renderer::InitNodeGraphs(const array_view<const RenderHandle> renderNodeGraphs)
4878bf80f4bSopenharmony_ci{
4888bf80f4bSopenharmony_ci    const RenderNodeGraphShareDataManager* prevRngShareDataMgr = nullptr;
4898bf80f4bSopenharmony_ci    for (const auto& rng : renderNodeGraphs) {
4908bf80f4bSopenharmony_ci        auto renderNodeDataStore = renderNodeGraphMgr_.Get(rng);
4918bf80f4bSopenharmony_ci        if (!renderNodeDataStore) {
4928bf80f4bSopenharmony_ci            continue;
4938bf80f4bSopenharmony_ci        }
4948bf80f4bSopenharmony_ci
4958bf80f4bSopenharmony_ci        RenderNodeGraphNodeStore& nodeStore = *renderNodeDataStore;
4968bf80f4bSopenharmony_ci        if (nodeStore.initialized) {
4978bf80f4bSopenharmony_ci            continue;
4988bf80f4bSopenharmony_ci        }
4998bf80f4bSopenharmony_ci        nodeStore.initialized = true;
5008bf80f4bSopenharmony_ci
5018bf80f4bSopenharmony_ci        const bool enableMultiQueue = (device_.GetGpuQueueCount() > 1);
5028bf80f4bSopenharmony_ci
5038bf80f4bSopenharmony_ci        // serial, initialize render node context data
5048bf80f4bSopenharmony_ci        auto renderNodeNameToIndex =
5058bf80f4bSopenharmony_ci            InitializeRenderNodeContextData(renderContext_, nodeStore, enableMultiQueue, renderConfig_);
5068bf80f4bSopenharmony_ci
5078bf80f4bSopenharmony_ci        if (enableMultiQueue) {
5088bf80f4bSopenharmony_ci            // patch gpu queue signaling
5098bf80f4bSopenharmony_ci            PatchSignaling(nodeStore, renderNodeNameToIndex);
5108bf80f4bSopenharmony_ci        }
5118bf80f4bSopenharmony_ci
5128bf80f4bSopenharmony_ci        // NOTE: needs to be called once before init. every frame called in BeginRenderNodeGraph()
5138bf80f4bSopenharmony_ci        nodeStore.renderNodeGraphShareDataMgr->BeginFrame(rngGlobalShareDataMgr_.get(), prevRngShareDataMgr,
5148bf80f4bSopenharmony_ci            static_cast<uint32_t>(nodeStore.renderNodeData.size()),
5158bf80f4bSopenharmony_ci            { nodeStore.renderNodeGraphShareData.inputs, nodeStore.renderNodeGraphShareData.inputCount },
5168bf80f4bSopenharmony_ci            { nodeStore.renderNodeGraphShareData.outputs, nodeStore.renderNodeGraphShareData.outputCount });
5178bf80f4bSopenharmony_ci        prevRngShareDataMgr = nodeStore.renderNodeGraphShareDataMgr.get();
5188bf80f4bSopenharmony_ci
5198bf80f4bSopenharmony_ci        const RenderNodeContextManager::PerFrameTimings timings { 0, 0, device_.GetFrameCount() };
5208bf80f4bSopenharmony_ci        for (size_t nodeIdx = 0; nodeIdx < nodeStore.renderNodeData.size(); ++nodeIdx) {
5218bf80f4bSopenharmony_ci            auto& nodeContextData = nodeStore.renderNodeContextData[nodeIdx];
5228bf80f4bSopenharmony_ci            if (nodeContextData.initialized) {
5238bf80f4bSopenharmony_ci                continue;
5248bf80f4bSopenharmony_ci            }
5258bf80f4bSopenharmony_ci            nodeContextData.initialized = true;
5268bf80f4bSopenharmony_ci
5278bf80f4bSopenharmony_ci            // NOTE: needs to be called once before init. every frame called in BeginRenderNodeGraph()
5288bf80f4bSopenharmony_ci            nodeContextData.renderNodeContextManager->BeginFrame(static_cast<uint32_t>(nodeIdx), timings);
5298bf80f4bSopenharmony_ci
5308bf80f4bSopenharmony_ci            auto& renderNodeData = nodeStore.renderNodeData[nodeIdx];
5318bf80f4bSopenharmony_ci            PLUGIN_ASSERT(renderNodeData.inputData);
5328bf80f4bSopenharmony_ci            PLUGIN_ASSERT(renderNodeData.node);
5338bf80f4bSopenharmony_ci
5348bf80f4bSopenharmony_ci            RENDER_CPU_PERF_SCOPE("Renderer", "Renderer_InitNode_Cpu", renderNodeData.fullName);
5358bf80f4bSopenharmony_ci            renderNodeData.node->InitNode(*(nodeContextData.renderNodeContextManager));
5368bf80f4bSopenharmony_ci        }
5378bf80f4bSopenharmony_ci    }
5388bf80f4bSopenharmony_ci}
5398bf80f4bSopenharmony_ci
5408bf80f4bSopenharmony_ci// Helper for Renderer::RenderFrame
5418bf80f4bSopenharmony_civoid Renderer::RemapBackBufferHandle(const IRenderDataStoreManager& renderData)
5428bf80f4bSopenharmony_ci{
5438bf80f4bSopenharmony_ci    const auto* dataStorePod =
5448bf80f4bSopenharmony_ci        static_cast<IRenderDataStorePod*>(renderData.GetRenderDataStore(RenderDataStorePod::TYPE_NAME));
5458bf80f4bSopenharmony_ci    if (dataStorePod) {
5468bf80f4bSopenharmony_ci        auto const dataView = dataStorePod->Get("NodeGraphBackBufferConfiguration");
5478bf80f4bSopenharmony_ci        const auto bb = reinterpret_cast<const NodeGraphBackBufferConfiguration*>(dataView.data());
5488bf80f4bSopenharmony_ci        if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::SWAPCHAIN) {
5498bf80f4bSopenharmony_ci            if (!device_.HasSwapchain()) {
5508bf80f4bSopenharmony_ci                PLUGIN_LOG_E("Using swapchain rendering without swapchain");
5518bf80f4bSopenharmony_ci            }
5528bf80f4bSopenharmony_ci        } else if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::GPU_IMAGE) {
5538bf80f4bSopenharmony_ci            const RenderHandle handle = gpuResourceMgr_.GetImageRawHandle(bb->backBufferName);
5548bf80f4bSopenharmony_ci            if (RenderHandleUtil::IsValid(handle) && RenderHandleUtil::IsValid(bb->backBufferHandle)) {
5558bf80f4bSopenharmony_ci                gpuResourceMgr_.RemapGpuImageHandle(handle, bb->backBufferHandle);
5568bf80f4bSopenharmony_ci            }
5578bf80f4bSopenharmony_ci        } else if (bb->backBufferType == NodeGraphBackBufferConfiguration::BackBufferType::GPU_IMAGE_BUFFER_COPY) {
5588bf80f4bSopenharmony_ci            const RenderHandle handle = gpuResourceMgr_.GetImageRawHandle(bb->backBufferName);
5598bf80f4bSopenharmony_ci            if (RenderHandleUtil::IsValid(handle) && RenderHandleUtil::IsValid(bb->backBufferHandle) &&
5608bf80f4bSopenharmony_ci                RenderHandleUtil::IsValid(bb->gpuBufferHandle)) {
5618bf80f4bSopenharmony_ci                gpuResourceMgr_.RemapGpuImageHandle(handle, bb->backBufferHandle);
5628bf80f4bSopenharmony_ci            }
5638bf80f4bSopenharmony_ci            // handle image to buffer copy via post frame staging
5648bf80f4bSopenharmony_ci            {
5658bf80f4bSopenharmony_ci                RenderHandle backbufferHandle = bb->backBufferHandle;
5668bf80f4bSopenharmony_ci                if (bb->backBufferName == DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER) {
5678bf80f4bSopenharmony_ci                    // we need to use the core default backbuffer handle and not the replaced handle in this situation
5688bf80f4bSopenharmony_ci                    backbufferHandle =
5698bf80f4bSopenharmony_ci                        gpuResourceMgr_.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_BACKBUFFER)
5708bf80f4bSopenharmony_ci                            .GetHandle();
5718bf80f4bSopenharmony_ci                }
5728bf80f4bSopenharmony_ci                const GpuImageDesc desc = gpuResourceMgr_.GetImageDescriptor(backbufferHandle);
5738bf80f4bSopenharmony_ci                const BufferImageCopy bic {
5748bf80f4bSopenharmony_ci                    0,                                                                // bufferOffset
5758bf80f4bSopenharmony_ci                    0,                                                                // bufferRowLength
5768bf80f4bSopenharmony_ci                    0,                                                                // bufferImageHeight
5778bf80f4bSopenharmony_ci                    ImageSubresourceLayers { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u }, // imageSubresource
5788bf80f4bSopenharmony_ci                    Size3D { 0, 0, 0 },                                               // imageOffset
5798bf80f4bSopenharmony_ci                    Size3D { desc.width, desc.height, 1u },                           // imageExtent
5808bf80f4bSopenharmony_ci                };
5818bf80f4bSopenharmony_ci                dsStaging_->CopyImageToBuffer(gpuResourceMgr_.Get(backbufferHandle),
5828bf80f4bSopenharmony_ci                    gpuResourceMgr_.Get(bb->gpuBufferHandle), bic,
5838bf80f4bSopenharmony_ci                    IRenderDataStoreDefaultStaging::ResourceCopyInfo::END_FRAME);
5848bf80f4bSopenharmony_ci            }
5858bf80f4bSopenharmony_ci        }
5868bf80f4bSopenharmony_ci    }
5878bf80f4bSopenharmony_ci}
5888bf80f4bSopenharmony_ci
5898bf80f4bSopenharmony_civoid Renderer::RenderFrameImpl(const array_view<const RenderHandle> renderNodeGraphs)
5908bf80f4bSopenharmony_ci{
5918bf80f4bSopenharmony_ci    if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
5928bf80f4bSopenharmony_ci        separatedRendering_.frontMtx.lock();
5938bf80f4bSopenharmony_ci    }
5948bf80f4bSopenharmony_ci
5958bf80f4bSopenharmony_ci    Tick();
5968bf80f4bSopenharmony_ci    frameTimes_.begin = GetTimeStampNow();
5978bf80f4bSopenharmony_ci    RENDER_CPU_PERF_SCOPE("Renderer", "Frame", "RenderFrame");
5988bf80f4bSopenharmony_ci
5998bf80f4bSopenharmony_ci    if (device_.GetDeviceStatus() == false) {
6008bf80f4bSopenharmony_ci        ProcessTimeStampEnd();
6018bf80f4bSopenharmony_ci#if (RENDER_VALIDATION_ENABLED == 1)
6028bf80f4bSopenharmony_ci        PLUGIN_LOG_ONCE_E("invalid_device_status_render_frame", "invalid device for rendering");
6038bf80f4bSopenharmony_ci#endif
6048bf80f4bSopenharmony_ci        return;
6058bf80f4bSopenharmony_ci    }
6068bf80f4bSopenharmony_ci    const IRenderDataStoreManager::RenderDataStoreFlags rdsFlags = renderDataStoreMgr_.GetRenderDataStoreFlags();
6078bf80f4bSopenharmony_ci    if (rdsFlags & IRenderDataStoreManager::DOUBLE_BUFFERED_RENDER_DATA_STORES) {
6088bf80f4bSopenharmony_ci#if (RENDER_VALIDATION_ENABLED == 1)
6098bf80f4bSopenharmony_ci        renderDataStoreMgr_.ValidateCommitFrameData();
6108bf80f4bSopenharmony_ci#endif
6118bf80f4bSopenharmony_ci    }
6128bf80f4bSopenharmony_ci    renderDataStoreMgr_.CommitFrameData();
6138bf80f4bSopenharmony_ci
6148bf80f4bSopenharmony_ci    device_.Activate();
6158bf80f4bSopenharmony_ci    device_.FrameStart();
6168bf80f4bSopenharmony_ci    renderFrameTimeData_.frameIndex = device_.GetFrameCount();
6178bf80f4bSopenharmony_ci
6188bf80f4bSopenharmony_ci    (static_cast<GpuResourceCache&>(gpuResourceMgr_.GetGpuResourceCache())).BeginFrame(device_.GetFrameCount());
6198bf80f4bSopenharmony_ci
6208bf80f4bSopenharmony_ci    // handle utils (needs to be called before render data store pre renders)
6218bf80f4bSopenharmony_ci    renderUtil_.BeginFrame();
6228bf80f4bSopenharmony_ci
6238bf80f4bSopenharmony_ci    // remap the default back buffer (needs to be called before render data store pre renders)
6248bf80f4bSopenharmony_ci    RemapBackBufferHandle(renderDataStoreMgr_);
6258bf80f4bSopenharmony_ci
6268bf80f4bSopenharmony_ci    renderNodeGraphMgr_.HandlePendingAllocations();
6278bf80f4bSopenharmony_ci    renderDataStoreMgr_.PreRender();
6288bf80f4bSopenharmony_ci
6298bf80f4bSopenharmony_ci    // create new shaders if any created this frame (needs to be called before render node init)
6308bf80f4bSopenharmony_ci    shaderMgr_.HandlePendingAllocations();
6318bf80f4bSopenharmony_ci
6328bf80f4bSopenharmony_ci    auto& rngInputs = renderFrameTimeData_.rngInputs;
6338bf80f4bSopenharmony_ci    auto& rngNodeStores = renderFrameTimeData_.rngNodeStores;
6348bf80f4bSopenharmony_ci    PLUGIN_ASSERT(rngInputs.empty());
6358bf80f4bSopenharmony_ci    PLUGIN_ASSERT(rngNodeStores.empty());
6368bf80f4bSopenharmony_ci
6378bf80f4bSopenharmony_ci    // update render node graphs with default staging
6388bf80f4bSopenharmony_ci    FillRngInputs(renderNodeGraphs, rngInputs);
6398bf80f4bSopenharmony_ci    const auto renderNodeGraphInputs = array_view(rngInputs.data(), rngInputs.size());
6408bf80f4bSopenharmony_ci
6418bf80f4bSopenharmony_ci    InitNodeGraphs(renderNodeGraphInputs);
6428bf80f4bSopenharmony_ci    device_.Deactivate();
6438bf80f4bSopenharmony_ci
6448bf80f4bSopenharmony_ci    renderGraph_->BeginFrame();
6458bf80f4bSopenharmony_ci
6468bf80f4bSopenharmony_ci    FillRngNodeStores(renderNodeGraphInputs, renderNodeGraphMgr_, rngNodeStores);
6478bf80f4bSopenharmony_ci    if (std::any_of(rngNodeStores.begin(), rngNodeStores.end(), IsNull<RenderNodeGraphNodeStore>)) {
6488bf80f4bSopenharmony_ci        ProcessTimeStampEnd();
6498bf80f4bSopenharmony_ci        PLUGIN_LOG_W("invalid render node graphs for rendering");
6508bf80f4bSopenharmony_ci        return;
6518bf80f4bSopenharmony_ci    }
6528bf80f4bSopenharmony_ci
6538bf80f4bSopenharmony_ci    // NodeContextPoolManagerGLES::BeginFrame may delete FBOs and device must be active.
6548bf80f4bSopenharmony_ci    device_.Activate();
6558bf80f4bSopenharmony_ci
6568bf80f4bSopenharmony_ci    renderFrameSync_->BeginFrame();
6578bf80f4bSopenharmony_ci    // begin frame (advance ring buffers etc.)
6588bf80f4bSopenharmony_ci    const RenderNodeContextManager::PerFrameTimings timings { previousFrameTime_ - firstTime_, deltaTime_,
6598bf80f4bSopenharmony_ci        device_.GetFrameCount() };
6608bf80f4bSopenharmony_ci    BeginRenderNodeGraph(rngGlobalShareDataMgr_.get(), rngNodeStores, timings);
6618bf80f4bSopenharmony_ci
6628bf80f4bSopenharmony_ci    // synchronize, needed for persistantly mapped gpu buffer writing
6638bf80f4bSopenharmony_ci    if (!WaitForFence(device_, *renderFrameSync_)) {
6648bf80f4bSopenharmony_ci        device_.Deactivate();
6658bf80f4bSopenharmony_ci        return; // possible lost device with frame fence
6668bf80f4bSopenharmony_ci    }
6678bf80f4bSopenharmony_ci
6688bf80f4bSopenharmony_ci    // gpu resource allocation and deallocation
6698bf80f4bSopenharmony_ci    gpuResourceMgr_.HandlePendingAllocations();
6708bf80f4bSopenharmony_ci
6718bf80f4bSopenharmony_ci    device_.Deactivate();
6728bf80f4bSopenharmony_ci
6738bf80f4bSopenharmony_ci    const auto nodeStoresView = array_view<RenderNodeGraphNodeStore*>(rngNodeStores);
6748bf80f4bSopenharmony_ci    ExecuteRenderNodes(renderNodeGraphInputs, nodeStoresView);
6758bf80f4bSopenharmony_ci
6768bf80f4bSopenharmony_ci    // render graph process for all render nodes of all render graphs
6778bf80f4bSopenharmony_ci    ProcessRenderNodeGraph(device_, *renderGraph_, nodeStoresView);
6788bf80f4bSopenharmony_ci
6798bf80f4bSopenharmony_ci    renderDataStoreMgr_.PostRender();
6808bf80f4bSopenharmony_ci
6818bf80f4bSopenharmony_ci    // set front-end index (before mutexes)
6828bf80f4bSopenharmony_ci    renderStatus_.frontEndIndex = renderFrameTimeData_.frameIndex;
6838bf80f4bSopenharmony_ci    if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
6848bf80f4bSopenharmony_ci        separatedRendering_.frontMtx.unlock();
6858bf80f4bSopenharmony_ci    }
6868bf80f4bSopenharmony_ci    if (!separatedRendering_.separateBackend) {
6878bf80f4bSopenharmony_ci        RenderFrameBackendImpl();
6888bf80f4bSopenharmony_ci    }
6898bf80f4bSopenharmony_ci}
6908bf80f4bSopenharmony_ci
6918bf80f4bSopenharmony_civoid Renderer::RenderFrameBackendImpl()
6928bf80f4bSopenharmony_ci{
6938bf80f4bSopenharmony_ci    if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
6948bf80f4bSopenharmony_ci        separatedRendering_.frontMtx.lock();
6958bf80f4bSopenharmony_ci        separatedRendering_.backMtx.lock();
6968bf80f4bSopenharmony_ci    }
6978bf80f4bSopenharmony_ci
6988bf80f4bSopenharmony_ci    auto& rngInputs = renderFrameTimeData_.rngInputs;
6998bf80f4bSopenharmony_ci    auto& rngNodeStores = renderFrameTimeData_.rngNodeStores;
7008bf80f4bSopenharmony_ci
7018bf80f4bSopenharmony_ci    device_.SetLockResourceBackendAccess(true);
7028bf80f4bSopenharmony_ci    renderDataStoreMgr_.PreRenderBackend();
7038bf80f4bSopenharmony_ci
7048bf80f4bSopenharmony_ci    size_t allRenderNodeCount = 0;
7058bf80f4bSopenharmony_ci    for (const auto* nodeStore : rngNodeStores) {
7068bf80f4bSopenharmony_ci        PLUGIN_ASSERT(nodeStore);
7078bf80f4bSopenharmony_ci        allRenderNodeCount += nodeStore->renderNodeData.size();
7088bf80f4bSopenharmony_ci    }
7098bf80f4bSopenharmony_ci
7108bf80f4bSopenharmony_ci    RenderCommandFrameData rcfd;
7118bf80f4bSopenharmony_ci    PLUGIN_ASSERT(renderFrameSync_);
7128bf80f4bSopenharmony_ci    rcfd.renderFrameSync = renderFrameSync_.get();
7138bf80f4bSopenharmony_ci    rcfd.renderFrameUtil = &(static_cast<RenderFrameUtil&>(renderContext_.GetRenderUtil().GetRenderFrameUtil()));
7148bf80f4bSopenharmony_ci    rcfd.renderCommandContexts.reserve(allRenderNodeCount);
7158bf80f4bSopenharmony_ci
7168bf80f4bSopenharmony_ci    const bool multiQueueEnabled = (device_.GetGpuQueueCount() > 1u);
7178bf80f4bSopenharmony_ci    IterateRenderBackendNodeGraphNodeStores(rngNodeStores, multiQueueEnabled, rcfd);
7188bf80f4bSopenharmony_ci
7198bf80f4bSopenharmony_ci    // NOTE: by node graph name
7208bf80f4bSopenharmony_ci    // NOTE: deprecate this
7218bf80f4bSopenharmony_ci    const RenderGraph::SwapchainStates bbState = renderGraph_->GetSwapchainResourceStates();
7228bf80f4bSopenharmony_ci    RenderBackendBackBufferConfiguration config;
7238bf80f4bSopenharmony_ci    for (const auto& swapState : bbState.swapchains) {
7248bf80f4bSopenharmony_ci        config.swapchainData.push_back({ swapState.handle, swapState.state, swapState.layout, {} });
7258bf80f4bSopenharmony_ci    }
7268bf80f4bSopenharmony_ci    if (!config.swapchainData.empty()) {
7278bf80f4bSopenharmony_ci        // NOTE: this is a backwards compatibility for a single (default) swapchain config data
7288bf80f4bSopenharmony_ci        // should be removed
7298bf80f4bSopenharmony_ci        if (auto const dataStorePod = static_cast<IRenderDataStorePod const*>(
7308bf80f4bSopenharmony_ci                renderDataStoreMgr_.GetRenderDataStore(RenderDataStorePod::TYPE_NAME));
7318bf80f4bSopenharmony_ci            dataStorePod) {
7328bf80f4bSopenharmony_ci            auto const dataView = dataStorePod->Get("NodeGraphBackBufferConfiguration");
7338bf80f4bSopenharmony_ci            if (dataView.size_bytes() == sizeof(NodeGraphBackBufferConfiguration)) {
7348bf80f4bSopenharmony_ci                // expects to be the first swapchain in the list
7358bf80f4bSopenharmony_ci                const NodeGraphBackBufferConfiguration* bb = (const NodeGraphBackBufferConfiguration*)dataView.data();
7368bf80f4bSopenharmony_ci                config.swapchainData[0U].config = *bb;
7378bf80f4bSopenharmony_ci            }
7388bf80f4bSopenharmony_ci        }
7398bf80f4bSopenharmony_ci    }
7408bf80f4bSopenharmony_ci    renderFrameTimeData_.config = config;
7418bf80f4bSopenharmony_ci    renderFrameTimeData_.hasBackendWork = (!rcfd.renderCommandContexts.empty());
7428bf80f4bSopenharmony_ci
7438bf80f4bSopenharmony_ci    device_.Activate();
7448bf80f4bSopenharmony_ci
7458bf80f4bSopenharmony_ci    if (renderFrameTimeData_.hasBackendWork) { // do not execute backend with zero work
7468bf80f4bSopenharmony_ci        device_.SetRenderBackendRunning(true);
7478bf80f4bSopenharmony_ci
7488bf80f4bSopenharmony_ci        frameTimes_.beginBackend = GetTimeStampNow();
7498bf80f4bSopenharmony_ci        renderBackend_->Render(rcfd, config);
7508bf80f4bSopenharmony_ci        frameTimes_.endBackend = GetTimeStampNow();
7518bf80f4bSopenharmony_ci
7528bf80f4bSopenharmony_ci        device_.SetRenderBackendRunning(false);
7538bf80f4bSopenharmony_ci    }
7548bf80f4bSopenharmony_ci    gpuResourceMgr_.EndFrame();
7558bf80f4bSopenharmony_ci
7568bf80f4bSopenharmony_ci    if (separatedRendering_.separatePresent) {
7578bf80f4bSopenharmony_ci        device_.Deactivate();
7588bf80f4bSopenharmony_ci    }
7598bf80f4bSopenharmony_ci
7608bf80f4bSopenharmony_ci    device_.SetLockResourceBackendAccess(false);
7618bf80f4bSopenharmony_ci
7628bf80f4bSopenharmony_ci    // clear
7638bf80f4bSopenharmony_ci    rngInputs.clear();
7648bf80f4bSopenharmony_ci    rngNodeStores.clear();
7658bf80f4bSopenharmony_ci
7668bf80f4bSopenharmony_ci    // set backend-end index (before mutexes)
7678bf80f4bSopenharmony_ci    renderStatus_.backEndIndex = renderStatus_.frontEndIndex;
7688bf80f4bSopenharmony_ci    if (separatedRendering_.separateBackend || separatedRendering_.separatePresent) {
7698bf80f4bSopenharmony_ci        separatedRendering_.frontMtx.unlock();
7708bf80f4bSopenharmony_ci        separatedRendering_.backMtx.unlock();
7718bf80f4bSopenharmony_ci    }
7728bf80f4bSopenharmony_ci    if (!separatedRendering_.separatePresent) {
7738bf80f4bSopenharmony_ci        RenderFramePresentImpl();
7748bf80f4bSopenharmony_ci    }
7758bf80f4bSopenharmony_ci}
7768bf80f4bSopenharmony_ci
7778bf80f4bSopenharmony_civoid Renderer::RenderFramePresentImpl()
7788bf80f4bSopenharmony_ci{
7798bf80f4bSopenharmony_ci    if (separatedRendering_.separatePresent) {
7808bf80f4bSopenharmony_ci        separatedRendering_.backMtx.lock();
7818bf80f4bSopenharmony_ci    }
7828bf80f4bSopenharmony_ci
7838bf80f4bSopenharmony_ci    if (renderFrameTimeData_.hasBackendWork) { // do not execute backend with zero work
7848bf80f4bSopenharmony_ci        if (separatedRendering_.separatePresent) {
7858bf80f4bSopenharmony_ci            device_.Activate();
7868bf80f4bSopenharmony_ci        }
7878bf80f4bSopenharmony_ci
7888bf80f4bSopenharmony_ci        frameTimes_.beginBackendPresent = GetTimeStampNow();
7898bf80f4bSopenharmony_ci        renderBackend_->Present(renderFrameTimeData_.config);
7908bf80f4bSopenharmony_ci        frameTimes_.endBackendPresent = GetTimeStampNow();
7918bf80f4bSopenharmony_ci
7928bf80f4bSopenharmony_ci        if (separatedRendering_.separatePresent) {
7938bf80f4bSopenharmony_ci            device_.Deactivate();
7948bf80f4bSopenharmony_ci        }
7958bf80f4bSopenharmony_ci    }
7968bf80f4bSopenharmony_ci    if (!separatedRendering_.separatePresent) {
7978bf80f4bSopenharmony_ci        device_.Deactivate();
7988bf80f4bSopenharmony_ci    }
7998bf80f4bSopenharmony_ci
8008bf80f4bSopenharmony_ci    renderDataStoreMgr_.PostRenderBackend();
8018bf80f4bSopenharmony_ci
8028bf80f4bSopenharmony_ci    renderFrameTimeData_.config = {};
8038bf80f4bSopenharmony_ci
8048bf80f4bSopenharmony_ci    // needs to be called after render data store post render
8058bf80f4bSopenharmony_ci    renderUtil_.EndFrame();
8068bf80f4bSopenharmony_ci
8078bf80f4bSopenharmony_ci    // RenderFramePresentImpl() needs to be called every frame even thought there isn't presenting
8088bf80f4bSopenharmony_ci    device_.FrameEnd();
8098bf80f4bSopenharmony_ci    ProcessTimeStampEnd();
8108bf80f4bSopenharmony_ci
8118bf80f4bSopenharmony_ci    // set presentation index (before mutexes)
8128bf80f4bSopenharmony_ci    renderStatus_.presentIndex = renderStatus_.backEndIndex;
8138bf80f4bSopenharmony_ci    if (separatedRendering_.separatePresent) {
8148bf80f4bSopenharmony_ci        separatedRendering_.backMtx.unlock();
8158bf80f4bSopenharmony_ci    }
8168bf80f4bSopenharmony_ci}
8178bf80f4bSopenharmony_ci
8188bf80f4bSopenharmony_ciuint64_t Renderer::RenderFrame(const array_view<const RenderHandleReference> renderNodeGraphs)
8198bf80f4bSopenharmony_ci{
8208bf80f4bSopenharmony_ci    const auto lock = std::lock_guard(renderMutex_);
8218bf80f4bSopenharmony_ci
8228bf80f4bSopenharmony_ci    // add only unique and valid handles to list for rendering
8238bf80f4bSopenharmony_ci    vector<RenderHandle> rngs;
8248bf80f4bSopenharmony_ci    rngs.reserve(renderNodeGraphs.size());
8258bf80f4bSopenharmony_ci    for (size_t iIdx = 0; iIdx < renderNodeGraphs.size(); ++iIdx) {
8268bf80f4bSopenharmony_ci        const RenderHandle& handle = renderNodeGraphs[iIdx].GetHandle();
8278bf80f4bSopenharmony_ci        bool duplicate = false;
8288bf80f4bSopenharmony_ci        for (auto& ref : rngs) {
8298bf80f4bSopenharmony_ci            if (ref == handle) {
8308bf80f4bSopenharmony_ci                duplicate = true;
8318bf80f4bSopenharmony_ci            }
8328bf80f4bSopenharmony_ci        }
8338bf80f4bSopenharmony_ci        if ((RenderHandleUtil::GetHandleType(handle) == RenderHandleType::RENDER_NODE_GRAPH) && (!duplicate)) {
8348bf80f4bSopenharmony_ci            rngs.push_back(handle);
8358bf80f4bSopenharmony_ci        }
8368bf80f4bSopenharmony_ci#if (RENDER_VALIDATION_ENABLED == 1)
8378bf80f4bSopenharmony_ci        if (duplicate) {
8388bf80f4bSopenharmony_ci            PLUGIN_LOG_ONCE_E("renderer_rf_duplicate_rng",
8398bf80f4bSopenharmony_ci                "RENDER_VALIDATION: duplicate render node graphs are not supported (idx: %u, id: %" PRIx64,
8408bf80f4bSopenharmony_ci                static_cast<uint32_t>(iIdx), handle.id);
8418bf80f4bSopenharmony_ci        }
8428bf80f4bSopenharmony_ci#endif
8438bf80f4bSopenharmony_ci    }
8448bf80f4bSopenharmony_ci    device_.SetRenderFrameRunning(true);
8458bf80f4bSopenharmony_ci    // NOTE: this is the only place from where RenderFrameImpl is called
8468bf80f4bSopenharmony_ci    RenderFrameImpl(rngs);
8478bf80f4bSopenharmony_ci    device_.SetRenderFrameRunning(false);
8488bf80f4bSopenharmony_ci
8498bf80f4bSopenharmony_ci    return renderStatus_.frontEndIndex;
8508bf80f4bSopenharmony_ci}
8518bf80f4bSopenharmony_ci
8528bf80f4bSopenharmony_ciuint64_t Renderer::RenderDeferred(const array_view<const RenderHandleReference> renderNodeGraphs)
8538bf80f4bSopenharmony_ci{
8548bf80f4bSopenharmony_ci    const auto lock = std::lock_guard(deferredMutex_);
8558bf80f4bSopenharmony_ci    for (const auto& ref : renderNodeGraphs) {
8568bf80f4bSopenharmony_ci        deferredRenderNodeGraphs_.push_back(ref);
8578bf80f4bSopenharmony_ci    }
8588bf80f4bSopenharmony_ci    return renderStatusDeferred_ + 1;
8598bf80f4bSopenharmony_ci}
8608bf80f4bSopenharmony_ci
8618bf80f4bSopenharmony_ciuint64_t Renderer::RenderDeferredFrame()
8628bf80f4bSopenharmony_ci{
8638bf80f4bSopenharmony_ci    deferredMutex_.lock();
8648bf80f4bSopenharmony_ci    decltype(deferredRenderNodeGraphs_) renderNodeGraphs = move(deferredRenderNodeGraphs_);
8658bf80f4bSopenharmony_ci    renderStatusDeferred_ = renderStatus_.frontEndIndex + 1;
8668bf80f4bSopenharmony_ci    deferredMutex_.unlock();
8678bf80f4bSopenharmony_ci    RenderFrame(renderNodeGraphs);
8688bf80f4bSopenharmony_ci
8698bf80f4bSopenharmony_ci    return renderStatus_.frontEndIndex;
8708bf80f4bSopenharmony_ci}
8718bf80f4bSopenharmony_ci
8728bf80f4bSopenharmony_civoid Renderer::ExecuteRenderNodes(const array_view<const RenderHandle> renderNodeGraphInputs,
8738bf80f4bSopenharmony_ci    const array_view<RenderNodeGraphNodeStore*> renderNodeGraphNodeStores)
8748bf80f4bSopenharmony_ci{
8758bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
8768bf80f4bSopenharmony_ci    RENDER_CPU_PERF_BEGIN(fullExecuteCpuTimer, "Renderer", "Renderer", "ExecuteAllNodes_Cpu");
8778bf80f4bSopenharmony_ci
8788bf80f4bSopenharmony_ci    size_t allRenderNodeCount = 0;
8798bf80f4bSopenharmony_ci    for (size_t graphIdx = 0; graphIdx < renderNodeGraphNodeStores.size(); ++graphIdx) {
8808bf80f4bSopenharmony_ci        allRenderNodeCount += renderNodeGraphNodeStores[graphIdx]->renderNodeData.size();
8818bf80f4bSopenharmony_ci    }
8828bf80f4bSopenharmony_ci
8838bf80f4bSopenharmony_ci    vector<NodeTimerData> nodeTimers(allRenderNodeCount);
8848bf80f4bSopenharmony_ci#endif
8858bf80f4bSopenharmony_ci
8868bf80f4bSopenharmony_ci    ITaskQueue* queue = nullptr;
8878bf80f4bSopenharmony_ci    if (device_.AllowThreadedProcessing()) {
8888bf80f4bSopenharmony_ci        queue = parallelQueue_.get();
8898bf80f4bSopenharmony_ci    } else {
8908bf80f4bSopenharmony_ci        queue = sequentialQueue_.get();
8918bf80f4bSopenharmony_ci    }
8928bf80f4bSopenharmony_ci
8938bf80f4bSopenharmony_ci    // single threaded gpu resource creation with render nodes
8948bf80f4bSopenharmony_ci    CreateGpuResourcesWithRenderNodes(renderNodeGraphNodeStores, renderDataStoreMgr_, shaderMgr_);
8958bf80f4bSopenharmony_ci
8968bf80f4bSopenharmony_ci    // lock staging data for this frame
8978bf80f4bSopenharmony_ci    // NOTE: should be done with double buffering earlier
8988bf80f4bSopenharmony_ci    gpuResourceMgr_.LockFrameStagingData();
8998bf80f4bSopenharmony_ci    // final gpu resource allocation and deallocation before render node execute, and render graph
9008bf80f4bSopenharmony_ci    device_.Activate();
9018bf80f4bSopenharmony_ci    gpuResourceMgr_.HandlePendingAllocations();
9028bf80f4bSopenharmony_ci    device_.Deactivate();
9038bf80f4bSopenharmony_ci
9048bf80f4bSopenharmony_ci    // process render node graph render node share preparations
9058bf80f4bSopenharmony_ci    for (auto& ref : renderNodeGraphNodeStores) {
9068bf80f4bSopenharmony_ci        ref->renderNodeGraphShareDataMgr->PrepareExecuteFrame();
9078bf80f4bSopenharmony_ci    }
9088bf80f4bSopenharmony_ci
9098bf80f4bSopenharmony_ci    RenderNodeExecutionParameters params = {
9108bf80f4bSopenharmony_ci        renderNodeGraphNodeStores,
9118bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
9128bf80f4bSopenharmony_ci        nodeTimers,
9138bf80f4bSopenharmony_ci#endif
9148bf80f4bSopenharmony_ci        queue,
9158bf80f4bSopenharmony_ci        renderDataStoreMgr_,
9168bf80f4bSopenharmony_ci        shaderMgr_,
9178bf80f4bSopenharmony_ci        renderConfig_
9188bf80f4bSopenharmony_ci    };
9198bf80f4bSopenharmony_ci
9208bf80f4bSopenharmony_ci    // multi-threaded render node execution
9218bf80f4bSopenharmony_ci    RenderNodeExecution(params);
9228bf80f4bSopenharmony_ci
9238bf80f4bSopenharmony_ci    // Remove tasks.
9248bf80f4bSopenharmony_ci    queue->Clear();
9258bf80f4bSopenharmony_ci
9268bf80f4bSopenharmony_ci#if (RENDER_PERF_ENABLED == 1)
9278bf80f4bSopenharmony_ci    RENDER_CPU_PERF_END(fullExecuteCpuTimer);
9288bf80f4bSopenharmony_ci
9298bf80f4bSopenharmony_ci    if (auto* inst = GetInstance<IPerformanceDataManagerFactory>(UID_PERFORMANCE_FACTORY); inst) {
9308bf80f4bSopenharmony_ci        if (IPerformanceDataManager* perfData = inst->Get("RenderNode"); perfData) {
9318bf80f4bSopenharmony_ci            for (size_t nodeIdx = 0; nodeIdx < nodeTimers.size(); ++nodeIdx) {
9328bf80f4bSopenharmony_ci                const auto& timerRef = nodeTimers[nodeIdx];
9338bf80f4bSopenharmony_ci                perfData->UpdateData(timerRef.debugName, "RenderNodeExecute_Cpu", timerRef.timer.GetMicroseconds());
9348bf80f4bSopenharmony_ci            }
9358bf80f4bSopenharmony_ci        }
9368bf80f4bSopenharmony_ci    }
9378bf80f4bSopenharmony_ci#endif
9388bf80f4bSopenharmony_ci}
9398bf80f4bSopenharmony_ci
9408bf80f4bSopenharmony_ciuint64_t Renderer::RenderFrameBackend(const RenderFrameBackendInfo& info)
9418bf80f4bSopenharmony_ci{
9428bf80f4bSopenharmony_ci    if (separatedRendering_.separateBackend) {
9438bf80f4bSopenharmony_ci        RenderFrameBackendImpl();
9448bf80f4bSopenharmony_ci    } else {
9458bf80f4bSopenharmony_ci        PLUGIN_LOG_E("RenderFrameBackend called separately even though render context not created as separate");
9468bf80f4bSopenharmony_ci    }
9478bf80f4bSopenharmony_ci
9488bf80f4bSopenharmony_ci    return renderStatus_.backEndIndex;
9498bf80f4bSopenharmony_ci}
9508bf80f4bSopenharmony_ci
9518bf80f4bSopenharmony_ciuint64_t Renderer::RenderFramePresent(const RenderFramePresentInfo& info)
9528bf80f4bSopenharmony_ci{
9538bf80f4bSopenharmony_ci    if (separatedRendering_.separatePresent) {
9548bf80f4bSopenharmony_ci        RenderFramePresentImpl();
9558bf80f4bSopenharmony_ci    } else {
9568bf80f4bSopenharmony_ci        PLUGIN_LOG_E("RenderFramePresent called separately even though render context not created as separate");
9578bf80f4bSopenharmony_ci    }
9588bf80f4bSopenharmony_ci
9598bf80f4bSopenharmony_ci    return renderStatus_.presentIndex;
9608bf80f4bSopenharmony_ci}
9618bf80f4bSopenharmony_ci
9628bf80f4bSopenharmony_ciIRenderer::RenderStatus Renderer::GetFrameStatus() const
9638bf80f4bSopenharmony_ci{
9648bf80f4bSopenharmony_ci    return renderStatus_;
9658bf80f4bSopenharmony_ci}
9668bf80f4bSopenharmony_ci
9678bf80f4bSopenharmony_civoid Renderer::FillRngInputs(
9688bf80f4bSopenharmony_ci    const array_view<const RenderHandle> renderNodeGraphInputList, vector<RenderHandle>& rngInputs)
9698bf80f4bSopenharmony_ci{
9708bf80f4bSopenharmony_ci    constexpr size_t defaultRenderNodeGraphCount = 2;
9718bf80f4bSopenharmony_ci    rngInputs.reserve(renderNodeGraphInputList.size() + defaultRenderNodeGraphCount);
9728bf80f4bSopenharmony_ci    rngInputs.push_back(defaultStagingRng_.GetHandle());
9738bf80f4bSopenharmony_ci    rngInputs.insert(rngInputs.end(), renderNodeGraphInputList.begin().ptr(), renderNodeGraphInputList.end().ptr());
9748bf80f4bSopenharmony_ci    rngInputs.push_back(defaultEndFrameStagingRng_.GetHandle());
9758bf80f4bSopenharmony_ci}
9768bf80f4bSopenharmony_ci
9778bf80f4bSopenharmony_civoid Renderer::ProcessTimeStampEnd()
9788bf80f4bSopenharmony_ci{
9798bf80f4bSopenharmony_ci    frameTimes_.end = GetTimeStampNow();
9808bf80f4bSopenharmony_ci
9818bf80f4bSopenharmony_ci    int64_t finalTime = frameTimes_.begin;
9828bf80f4bSopenharmony_ci    finalTime = Math::max(finalTime, frameTimes_.beginBackend);
9838bf80f4bSopenharmony_ci    frameTimes_.beginBackend = finalTime;
9848bf80f4bSopenharmony_ci
9858bf80f4bSopenharmony_ci    finalTime = Math::max(finalTime, frameTimes_.endBackend);
9868bf80f4bSopenharmony_ci    frameTimes_.endBackend = finalTime;
9878bf80f4bSopenharmony_ci
9888bf80f4bSopenharmony_ci    finalTime = Math::max(finalTime, frameTimes_.beginBackendPresent);
9898bf80f4bSopenharmony_ci    frameTimes_.beginBackendPresent = finalTime;
9908bf80f4bSopenharmony_ci
9918bf80f4bSopenharmony_ci    finalTime = Math::max(finalTime, frameTimes_.endBackendPresent);
9928bf80f4bSopenharmony_ci    frameTimes_.endBackendPresent = finalTime;
9938bf80f4bSopenharmony_ci
9948bf80f4bSopenharmony_ci    finalTime = Math::max(finalTime, frameTimes_.end);
9958bf80f4bSopenharmony_ci    frameTimes_.end = finalTime;
9968bf80f4bSopenharmony_ci
9978bf80f4bSopenharmony_ci    PLUGIN_ASSERT(frameTimes_.end >= frameTimes_.endBackend);
9988bf80f4bSopenharmony_ci    PLUGIN_ASSERT(frameTimes_.endBackend >= frameTimes_.beginBackend);
9998bf80f4bSopenharmony_ci    PLUGIN_ASSERT(frameTimes_.beginBackendPresent >= frameTimes_.beginBackend);
10008bf80f4bSopenharmony_ci    PLUGIN_ASSERT(frameTimes_.endBackendPresent >= frameTimes_.beginBackendPresent);
10018bf80f4bSopenharmony_ci
10028bf80f4bSopenharmony_ci    renderUtil_.SetRenderTimings(frameTimes_);
10038bf80f4bSopenharmony_ci    frameTimes_ = {};
10048bf80f4bSopenharmony_ci}
10058bf80f4bSopenharmony_ci
10068bf80f4bSopenharmony_civoid Renderer::Tick()
10078bf80f4bSopenharmony_ci{
10088bf80f4bSopenharmony_ci    using namespace std::chrono;
10098bf80f4bSopenharmony_ci    const auto currentTime =
10108bf80f4bSopenharmony_ci        static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
10118bf80f4bSopenharmony_ci
10128bf80f4bSopenharmony_ci    if (firstTime_ == ~0u) {
10138bf80f4bSopenharmony_ci        previousFrameTime_ = firstTime_ = currentTime;
10148bf80f4bSopenharmony_ci    }
10158bf80f4bSopenharmony_ci    deltaTime_ = currentTime - previousFrameTime_;
10168bf80f4bSopenharmony_ci    constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
10178bf80f4bSopenharmony_ci    if (deltaTime_ > limitHz) {
10188bf80f4bSopenharmony_ci        deltaTime_ = limitHz; // clamp the time step to no longer than 15hz.
10198bf80f4bSopenharmony_ci    }
10208bf80f4bSopenharmony_ci    previousFrameTime_ = currentTime;
10218bf80f4bSopenharmony_ci}
10228bf80f4bSopenharmony_ciRENDER_END_NAMESPACE()
1023