1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "render_node_back_buffer.h"
17 
18 #include <base/containers/string.h>
19 #include <render/datastore/intf_render_data_store_manager.h>
20 #include <render/datastore/intf_render_data_store_pod.h>
21 #include <render/datastore/render_data_store_render_pods.h>
22 #include <render/device/intf_gpu_resource_manager.h>
23 #include <render/device/intf_shader_manager.h>
24 #include <render/device/pipeline_layout_desc.h>
25 #include <render/device/pipeline_state_desc.h>
26 #include <render/namespace.h>
27 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
28 #include <render/nodecontext/intf_node_context_pso_manager.h>
29 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
30 #include <render/nodecontext/intf_render_command_list.h>
31 #include <render/nodecontext/intf_render_node_context_manager.h>
32 #include <render/nodecontext/intf_render_node_parser_util.h>
33 #include <render/nodecontext/intf_render_node_util.h>
34 #include <render/render_data_structures.h>
35 #include <render/resource_handle.h>
36 
37 #include "device/gpu_resource_handle_util.h"
38 #include "util/log.h"
39 
40 // shaders
41 #include "render/shaders/common/render_post_process_structs_common.h"
42 
43 RENDER_BEGIN_NAMESPACE()
44 namespace {
45 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
46 
FillPushConstant(const GpuImageDesc & dstImageDesc,const RenderPostProcessConfiguration & currentRenderPostProcessConfiguration_)47 PostProcessTonemapStruct FillPushConstant(
48     const GpuImageDesc& dstImageDesc, const RenderPostProcessConfiguration& currentRenderPostProcessConfiguration_)
49 {
50     PostProcessTonemapStruct pushData;
51 
52     const float fWidth = static_cast<float>(dstImageDesc.width);
53     const float fHeight = static_cast<float>(dstImageDesc.height);
54 
55     pushData.texSizeInvTexSize[0u] = fWidth;
56     pushData.texSizeInvTexSize[1u] = fHeight;
57     pushData.texSizeInvTexSize[2u] = 1.0f / fWidth;
58     pushData.texSizeInvTexSize[3u] = 1.0f / fHeight;
59     pushData.flags = currentRenderPostProcessConfiguration_.flags;
60     pushData.tonemap = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_TONEMAP];
61     pushData.vignette = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_VIGNETTE];
62     pushData.colorFringe = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_COLOR_FRINGE];
63     pushData.dither = currentRenderPostProcessConfiguration_.factors[PostProcessConfiguration::INDEX_DITHER];
64     return pushData;
65 }
66 } // namespace
67 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)68 void RenderNodeBackBuffer::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
69 {
70     renderNodeContextMgr_ = &renderNodeContextMgr;
71     ParseRenderNodeInputs();
72 
73     psoHandle_ = {};
74 
75     if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
76         PLUGIN_LOG_V("RenderNodeBackBuffer: render data store configuration not set in render node graph");
77     }
78 
79     const auto& renderNodeUtil = renderNodeContextMgr.GetRenderNodeUtil();
80     renderPass_ = renderNodeUtil.CreateRenderPass(inputRenderPass_);
81 
82     pipelineLayout_ = renderNodeUtil.CreatePipelineLayout(shader_);
83     {
84         const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineLayout_);
85         renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
86     }
87 
88     pipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(pipelineLayout_);
89     renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
90 }
91 
ExecuteFrame(IRenderCommandList & cmdList)92 void RenderNodeBackBuffer::ExecuteFrame(IRenderCommandList& cmdList)
93 {
94     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
95     const PostProcessConfiguration ppConfig = GetPostProcessConfiguration(renderDataStoreMgr);
96 
97     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
98     if (jsonInputs_.hasChangeableRenderPassHandles) {
99         inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
100     }
101     if (jsonInputs_.hasChangeableResourceHandles) {
102         inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
103         renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
104     }
105 
106     // Size update mut be done before specialization
107     const RenderHandle dstImageHandle = UpdateColorAttachmentSize();
108 
109     CheckForPsoSpecilization(ppConfig);
110 
111     const uint32_t firstSetIndex = pipelineDescriptorSetBinder_->GetFirstSet();
112     for (auto refIndex : pipelineDescriptorSetBinder_->GetSetIndices()) {
113         const auto descHandle = pipelineDescriptorSetBinder_->GetDescriptorSetHandle(refIndex);
114         const auto bindings = pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(refIndex);
115         cmdList.UpdateDescriptorSet(descHandle, bindings);
116     }
117 
118     cmdList.BeginRenderPass(renderPass_.renderPassDesc, renderPass_.subpassStartIndex, renderPass_.subpassDesc);
119     cmdList.BindPipeline(psoHandle_);
120 
121     // bind all sets
122     cmdList.BindDescriptorSets(firstSetIndex, pipelineDescriptorSetBinder_->GetDescriptorSetHandles());
123 
124     // dynamic state
125     cmdList.SetDynamicStateViewport(currentViewportDesc_);
126     cmdList.SetDynamicStateScissor(currentScissorDesc_);
127 
128     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
129     const GpuImageDesc dstImageDesc = gpuResourceMgr.GetImageDescriptor(dstImageHandle);
130 
131     if (pipelineLayout_.pushConstant.byteSize > 0) {
132         const PostProcessTonemapStruct pushData =
133             FillPushConstant(dstImageDesc, currentRenderPostProcessConfiguration_);
134         cmdList.PushConstant(pipelineLayout_.pushConstant, reinterpret_cast<const uint8_t*>(&pushData));
135     }
136 
137     cmdList.Draw(3u, 1u, 0u, 0u); // vertexCount 3, drawing one triangle
138     cmdList.EndRenderPass();
139 }
140 
CheckForPsoSpecilization(const PostProcessConfiguration & postProcessConfiguration)141 void RenderNodeBackBuffer::CheckForPsoSpecilization(const PostProcessConfiguration& postProcessConfiguration)
142 {
143     const RenderPostProcessConfiguration renderPostProcessConfiguration =
144         renderNodeContextMgr_->GetRenderNodeUtil().GetRenderPostProcessConfiguration(postProcessConfiguration);
145     if (!RenderHandleUtil::IsValid(psoHandle_)) {
146         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
147         const RenderHandle graphicsState =
148             renderNodeContextMgr_->GetShaderManager().GetGraphicsStateHandleByShaderHandle(shader_);
149         psoHandle_ = psoMgr.GetGraphicsPsoHandle(
150             shader_, graphicsState, pipelineLayout_, {}, {}, { DYNAMIC_STATES, BASE_NS::countof(DYNAMIC_STATES) });
151     }
152 
153     // store new values
154     currentRenderPostProcessConfiguration_ = renderPostProcessConfiguration;
155 }
156 
GetPostProcessConfiguration(const IRenderNodeRenderDataStoreManager & dataStoreMgr)157 PostProcessConfiguration RenderNodeBackBuffer::GetPostProcessConfiguration(
158     const IRenderNodeRenderDataStoreManager& dataStoreMgr)
159 {
160     if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
161         auto const dataStore = static_cast<IRenderDataStorePod const*>(
162             dataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
163         if (dataStore) {
164             auto const dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
165             const PostProcessConfiguration* data = (const PostProcessConfiguration*)dataView.data();
166             if (data) {
167                 return *data;
168             }
169         }
170     }
171     return {};
172 }
173 
UpdateColorAttachmentSize()174 RenderHandle RenderNodeBackBuffer::UpdateColorAttachmentSize()
175 {
176     const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
177     RenderHandle dstImageHandle;
178     if (!inputRenderPass_.attachments.empty()) {
179         dstImageHandle = inputRenderPass_.attachments[0].handle;
180 
181         const GpuImageDesc& desc = gpuResourceMgr.GetImageDescriptor(inputRenderPass_.attachments[0].handle);
182         if (desc.width != currentBackBuffer_.width || desc.height != currentBackBuffer_.height ||
183             desc.format != currentBackBuffer_.format) {
184             currentBackBuffer_.width = desc.width;
185             currentBackBuffer_.height = desc.height;
186             currentBackBuffer_.format = desc.format;
187 
188             // re-create render pass (swapchain/backbuffer size may have changed)
189             const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
190             renderPass_ = renderNodeUtil.CreateRenderPass(inputRenderPass_);
191 
192             currentViewportDesc_.x = 0.0f;
193             currentViewportDesc_.y = 0.0f;
194             currentViewportDesc_.width = static_cast<float>(currentBackBuffer_.width);
195             currentViewportDesc_.height = static_cast<float>(currentBackBuffer_.height);
196 
197             currentScissorDesc_.offsetX = 0;
198             currentScissorDesc_.offsetY = 0;
199             currentScissorDesc_.extentWidth = currentBackBuffer_.width;
200             currentScissorDesc_.extentHeight = currentBackBuffer_.height;
201         }
202     }
203     return dstImageHandle;
204 }
205 
ParseRenderNodeInputs()206 void RenderNodeBackBuffer::ParseRenderNodeInputs()
207 {
208     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
209     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
210     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
211     jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
212     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
213 
214     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
215     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
216     shader_ = shaderMgr.GetShaderHandle(shaderName);
217 
218     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
219     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
220     inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
221 
222     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
223     jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
224 }
225 
226 // for plugin / factory interface
Create()227 IRenderNode* RenderNodeBackBuffer::Create()
228 {
229     return new RenderNodeBackBuffer();
230 }
231 
Destroy(IRenderNode * instance)232 void RenderNodeBackBuffer::Destroy(IRenderNode* instance)
233 {
234     delete static_cast<RenderNodeBackBuffer*>(instance);
235 }
236 RENDER_END_NAMESPACE()
237