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 
38 RENDER_BEGIN_NAMESPACE()
InitNode(IRenderNodeContextManager& renderNodeContextMgr)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, (uint32_t)shaderSpecializationData_.constants.size()),
174                     ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT);
175                 for (uint32_t idx = 0; idx < specializationCount; ++idx) {
176                     const auto& ref = shaderSpecializationData_.constants[idx];
177                     const uint32_t constantId = ref.offset / sizeof(uint32_t);
178                     const uint32_t specId = ref.id;
179                     if (specId < ShaderSpecializationRenderPod::MAX_SPECIALIZATION_CONSTANT_COUNT) {
180                         if (shaderSpecializationData_.data[constantId] != spec->specializationFlags[specId].value) {
181                             shaderSpecializationData_.data[constantId] = spec->specializationFlags[specId].value;
182                             valuesChanged = true;
183                         }
184                     }
185                 }
186                 if (valuesChanged) {
187                     const ShaderSpecializationConstantDataView specialization {
188                         { shaderSpecializationData_.constants.data(), specializationCount },
189                         { shaderSpecializationData_.data.data(), specializationCount }
190                     };
191                     const uint32_t dynamicStateCount =
192                         (inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
193                     pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
194                         pipelineData_.shader, pipelineData_.graphicsState, pipelineData_.pipelineLayout, {},
195                         specialization, { dynamicStates, dynamicStateCount });
196                 }
197             } else {
198 #if (RENDER_VALIDATION_ENABLED == 1)
199                 const string logName = "RenderNodeFullscreenGeneric_ShaderSpecialization" +
200                                        string(jsonInputs_.renderDataStoreSpecialization.configurationName);
201                 PLUGIN_LOG_ONCE_E(logName.c_str(),
202                     "RENDER_VALIDATION: RenderNodeFullscreenGeneric shader specilization render data store size "
203                     "mismatch, name: %s, size:%u, podsize%u",
204                     jsonInputs_.renderDataStoreSpecialization.configurationName.c_str(),
205                     static_cast<uint32_t>(sizeof(ShaderSpecializationRenderPod)),
206                     static_cast<uint32_t>(dataView.size_bytes()));
207 #endif
208             }
209         }
210     } else if (!RenderHandleUtil::IsValid(pipelineData_.pso)) {
211         const uint32_t dynamicStateCount = (inputRenderPass_.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
212         pipelineData_.pso = renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(pipelineData_.shader,
213             pipelineData_.graphicsState, pipelineData_.pipelineLayout, {}, {}, { dynamicStates, dynamicStateCount });
214     }
215     return pipelineData_.pso;
216 }
217 
ParseRenderNodeInputs()218 void RenderNodeFullscreenGeneric::ParseRenderNodeInputs()
219 {
220     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
221     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
222     jsonInputs_.renderPass = parserUtil.GetInputRenderPass(jsonVal, "renderPass");
223     jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
224     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
225     jsonInputs_.renderDataStoreSpecialization =
226         parserUtil.GetRenderDataStore(jsonVal, "renderDataStoreShaderSpecialization");
227 
228     const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
229     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
230     pipelineData_.shader = shaderMgr.GetShaderHandle(shaderName);
231 
232     const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
233     inputRenderPass_ = renderNodeUtil.CreateInputRenderPass(jsonInputs_.renderPass);
234     inputResources_ = renderNodeUtil.CreateInputResources(jsonInputs_.resources);
235 
236     jsonInputs_.hasChangeableRenderPassHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.renderPass);
237     jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
238 }
239 
240 // for plugin / factory interface
Create()241 IRenderNode* RenderNodeFullscreenGeneric::Create()
242 {
243     return new RenderNodeFullscreenGeneric();
244 }
245 
Destroy(IRenderNode* instance)246 void RenderNodeFullscreenGeneric::Destroy(IRenderNode* instance)
247 {
248     delete static_cast<RenderNodeFullscreenGeneric*>(instance);
249 }
250 RENDER_END_NAMESPACE()
251