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_fullscreen_generic.h"
17 
18 #include <base/math/mathf.h>
19 #include <render/datastore/intf_render_data_store_manager.h>
20 #include <render/datastore/intf_render_data_store_pod.h>
21 #include <render/device/intf_gpu_resource_manager.h>
22 #include <render/device/intf_shader_manager.h>
23 #include <render/device/pipeline_layout_desc.h>
24 #include <render/device/pipeline_state_desc.h>
25 #include <render/namespace.h>
26 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
27 #include <render/nodecontext/intf_node_context_pso_manager.h>
28 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
29 #include <render/nodecontext/intf_render_command_list.h>
30 #include <render/nodecontext/intf_render_node_context_manager.h>
31 #include <render/nodecontext/intf_render_node_parser_util.h>
32 #include <render/nodecontext/intf_render_node_util.h>
33 
34 #include "util/log.h"
35 
36 using namespace BASE_NS;
37 
RENDER_BEGIN_NAMESPACE()38 RENDER_BEGIN_NAMESPACE()
39 void RenderNodeFullscreenGeneric::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
40 {
41     renderNodeContextMgr_ = &renderNodeContextMgr;
42     pipelineData_ = {};
43     ParseRenderNodeInputs();
44 
45     useDataStoreShaderSpecialization_ = !jsonInputs_.renderDataStoreSpecialization.dataStoreName.empty();
46 
47     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
48     if (RenderHandleUtil::GetHandleType(pipelineData_.shader) != RenderHandleType::SHADER_STATE_OBJECT) {
49         PLUGIN_LOG_E("RenderNodeFullscreenGeneric needs a valid shader handle");
50     }
51 
52     if (useDataStoreShaderSpecialization_) {
53         const ShaderSpecializationConstantView sscv = shaderMgr.GetReflectionSpecialization(pipelineData_.shader);
54         shaderSpecializationData_.constants.resize(sscv.constants.size());
55         shaderSpecializationData_.data.resize(sscv.constants.size());
56         for (size_t idx = 0; idx < shaderSpecializationData_.constants.size(); ++idx) {
57             shaderSpecializationData_.constants[idx] = sscv.constants[idx];
58             shaderSpecializationData_.data[idx] = ~0u;
59         }
60         useDataStoreShaderSpecialization_ = !sscv.constants.empty();
61     }
62 
63     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
64     pipelineData_.pipelineLayout = shaderMgr.GetPipelineLayoutHandleByShaderHandle(pipelineData_.shader);
65     if (!RenderHandleUtil::IsValid(pipelineData_.pipelineLayout)) {
66         pipelineData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayoutHandle(pipelineData_.shader);
67     }
68     pipelineData_.graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(pipelineData_.shader);
69     pipelineData_.pipelineLayoutData = shaderMgr.GetPipelineLayout(pipelineData_.pipelineLayout);
70     pipelineData_.pso = GetPsoHandle();
71 
72     {
73         const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineData_.pipelineLayoutData);
74         renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
75     }
76 
77     pipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(pipelineData_.pipelineLayoutData);
78     renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
79 
80     useDataStorePushConstant_ = (pipelineData_.pipelineLayoutData.pushConstant.byteSize > 0) &&
81                                 (!jsonInputs_.renderDataStore.dataStoreName.empty()) &&
82                                 (!jsonInputs_.renderDataStore.configurationName.empty());
83 }
84 
PreExecuteFrame()85 void RenderNodeFullscreenGeneric::PreExecuteFrame()
86 {
87     // re-create needed gpu resources
88 }
89 
ExecuteFrame(IRenderCommandList & cmdList)90 void RenderNodeFullscreenGeneric::ExecuteFrame(IRenderCommandList& cmdList)
91 {
92     if (!RENDER_NS::RenderHandleUtil::IsValid(pipelineData_.pso)) {
93         return;
94     }
95 
96     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
97     if (jsonInputs_.hasChangeableRenderPassHandles) {
98         inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
99     }
100     if (jsonInputs_.hasChangeableResourceHandles) {
101         inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
102         renderNodeUtil.BindResourcesToBinder(inputResources_, *pipelineDescriptorSetBinder_);
103     }
104 
105     const RenderPass renderPass = renderNodeUtil.CreateRenderPass(inputRenderPass_);
106     const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
107     const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
108 
109     const auto setIndices = pipelineDescriptorSetBinder_->GetSetIndices();
110     const uint32_t firstSetIndex = pipelineDescriptorSetBinder_->GetFirstSet();
111     for (auto refIndex : setIndices) {
112         const auto descHandle = pipelineDescriptorSetBinder_->GetDescriptorSetHandle(refIndex);
113         const auto bindings = pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(refIndex);
114         cmdList.UpdateDescriptorSet(descHandle, bindings);
115     }
116 #if (RENDER_VALIDATION_ENABLED == 1)
117     if (!pipelineDescriptorSetBinder_->GetPipelineDescriptorSetLayoutBindingValidity()) {
118         PLUGIN_LOG_ONCE_E(renderNodeContextMgr_->GetName() + "_RCL_UpdateDescriptorSet_invalid_",
119             "RENDER_VALIDATION: RenderNodeFullscreenGeneric: bindings missing (RN: %s)",
120             renderNodeContextMgr_->GetName().data());
121     }
122 #endif
123 
124     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
125 
126     const RenderHandle psoHandle = GetPsoHandle();
127     cmdList.BindPipeline(psoHandle);
128 
129     // bind all sets from the first on-wards
130     cmdList.BindDescriptorSets(firstSetIndex, pipelineDescriptorSetBinder_->GetDescriptorSetHandles());
131 
132     // dynamic state
133     cmdList.SetDynamicStateViewport(viewportDesc);
134     cmdList.SetDynamicStateScissor(scissorDesc);
135     if (renderPass.subpassDesc.fragmentShadingRateAttachmentCount > 0) {
136         cmdList.SetDynamicStateFragmentShadingRate(
137             { 1u, 1u }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
138                             CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
139     }
140 
141     // push constants
142     if (useDataStorePushConstant_) {
143         const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
144         const auto dataStore = static_cast<IRenderDataStorePod const*>(
145             renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
146         if (dataStore) {
147             const auto dataView = dataStore->Get(jsonInputs_.renderDataStore.configurationName);
148             if (!dataView.empty()) {
149                 cmdList.PushConstant(pipelineData_.pipelineLayoutData.pushConstant, dataView.data());
150             }
151         }
152     }
153 
154     cmdList.Draw(3u, 1u, 0u, 0u); // vertex count, instance count, first vertex, first instance
155     cmdList.EndRenderPass();
156 }
157 
GetPsoHandle()158 RenderHandle RenderNodeFullscreenGeneric::GetPsoHandle()
159 {
160     // controlled by count
161     constexpr DynamicStateEnum dynamicStates[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
162         CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
163     if (useDataStoreShaderSpecialization_) {
164         const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
165         const auto dataStore = static_cast<IRenderDataStorePod const*>(
166             renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStoreSpecialization.dataStoreName));
167         if (dataStore) {
168             const auto dataView = dataStore->Get(jsonInputs_.renderDataStoreSpecialization.configurationName);
169             if (dataView.data() && (dataView.size_bytes() == sizeof(ShaderSpecializationRenderPod))) {
170                 const auto* spec = reinterpret_cast<const ShaderSpecializationRenderPod*>(dataView.data());
171                 bool valuesChanged = false;
172                 const uint32_t specializationCount = Math::min(
173                     Math::min(spec->specializationConstantCount,
174                         static_cast<uint32_t>(shaderSpecializationData_.constants.size())),
175                     ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT);
176                 for (uint32_t idx = 0; idx < specializationCount; ++idx) {
177                     const auto& ref = shaderSpecializationData_.constants[idx];
178                     const uint32_t constantId = ref.offset / sizeof(uint32_t);
179                     const uint32_t specId = ref.id;
180                     if (specId < ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT) {
181                         if (shaderSpecializationData_.data[constantId] != spec->specializationFlags[specId].value) {
182                             shaderSpecializationData_.data[constantId] = spec->specializationFlags[specId].value;
183                             valuesChanged = true;
184                         }
185                     }
186                 }
187                 if (valuesChanged) {
188                     const ShaderSpecializationConstantDataView specialization {
189                         { shaderSpecializationData_.constants.data(), specializationCount },
190                         { shaderSpecializationData_.data.data(), specializationCount }
191                     };
192                     const uint32_t dynamicStateCount =
193                         (inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
194                     pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
195                         pipelineData_.shader, pipelineData_.graphicsState, pipelineData_.pipelineLayout, {},
196                         specialization, { dynamicStates, dynamicStateCount });
197                 }
198             } else {
199 #if (RENDER_VALIDATION_ENABLED == 1)
200                 const string logName = "RenderNodeFullscreenGeneric_ShaderSpecialization" +
201                                        string(jsonInputs_.renderDataStoreSpecialization.configurationName);
202                 PLUGIN_LOG_ONCE_E(logName.c_str(),
203                     "RENDER_VALIDATION: RenderNodeFullscreenGeneric shader specilization render data store size "
204                     "mismatch, name: %s, size:%u, podsize%u",
205                     jsonInputs_.renderDataStoreSpecialization.configurationName.c_str(),
206                     static_cast<uint32_t>(sizeof(ShaderSpecializationRenderPod)),
207                     static_cast<uint32_t>(dataView.size_bytes()));
208 #endif
209             }
210         }
211     } else if (!RenderHandleUtil::IsValid(pipelineData_.pso)) {
212         const uint32_t dynamicStateCount = (inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
213         pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(pipelineData_.shader,
214             pipelineData_.graphicsState, pipelineData_.pipelineLayout, {}, {}, { dynamicStates, dynamicStateCount });
215     }
216     return pipelineData_.pso;
217 }
218 
ParseRenderNodeInputs()219 void RenderNodeFullscreenGeneric::ParseRenderNodeInputs()
220 {
221     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
222     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
223     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
224     jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
225     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
226     jsonInputs_.renderDataStoreSpecialization =
227         parserUtil.GetRenderDataStore(jsonVal, "renderDataStoreShaderSpecialization");
228 
229     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
230     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
231     pipelineData_.shader = shaderMgr.GetShaderHandle(shaderName);
232 
233     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
234     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
235     inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
236 
237     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
238     jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
239 }
240 
241 // for plugin / factory interface
Create()242 IRenderNode* RenderNodeFullscreenGeneric::Create()
243 {
244     return new RenderNodeFullscreenGeneric();
245 }
246 
Destroy(IRenderNode * instance)247 void RenderNodeFullscreenGeneric::Destroy(IRenderNode* instance)
248 {
249     delete static_cast<RenderNodeFullscreenGeneric*>(instance);
250 }
251 RENDER_END_NAMESPACE()
252