• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_shader_passes_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 "datastore/render_data_store_shader_passes.h"
35 #include "device/shader_pipeline_binder.h"
36 #include "util/log.h"
37 
38 using namespace BASE_NS;
39 
40 RENDER_BEGIN_NAMESPACE()
41 namespace {
42 constexpr uint32_t OFFSET_ALIGNMENT { PipelineLayoutConstants::MIN_UBO_BIND_OFFSET_ALIGNMENT_BYTE_SIZE };
43 constexpr uint32_t OVERESTIMATE_COUNT { 4U };
44 
Align(uint32_t value,uint32_t align)45 constexpr uint32_t Align(uint32_t value, uint32_t align)
46 {
47     if (value == 0) {
48         return 0;
49     }
50     return ((value + align) / align) * align;
51 }
52 
ConvertToLowLevelRenderPass(const RenderPassWithHandleReference & renderPassInput)53 RenderPass ConvertToLowLevelRenderPass(const RenderPassWithHandleReference& renderPassInput)
54 {
55     RenderPass rp;
56     rp.subpassDesc = renderPassInput.subpassDesc;
57     rp.subpassStartIndex = renderPassInput.subpassStartIndex;
58     const uint32_t attachmentCount = Math::min(
59         PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT, renderPassInput.renderPassDesc.attachmentCount);
60     rp.renderPassDesc.attachmentCount = attachmentCount;
61     CloneData(rp.renderPassDesc.attachments, sizeof(rp.renderPassDesc.attachments),
62         renderPassInput.renderPassDesc.attachments, sizeof(renderPassInput.renderPassDesc.attachments));
63     rp.renderPassDesc.renderArea = renderPassInput.renderPassDesc.renderArea;
64     rp.renderPassDesc.subpassCount = renderPassInput.renderPassDesc.subpassCount;
65     for (uint32_t idx = 0U; idx < attachmentCount; ++idx) {
66         rp.renderPassDesc.attachmentHandles[idx] = renderPassInput.renderPassDesc.attachmentHandles[idx].GetHandle();
67     }
68     return rp;
69 }
70 } // namespace
71 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)72 void RenderNodeShaderPassesGeneric::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
73 {
74     valid_ = true;
75     uboData_ = {};
76 
77     renderNodeContextMgr_ = &renderNodeContextMgr;
78     ParseRenderNodeInputs();
79 
80     if (!jsonInputs_.renderDataStore.dataStoreName.empty()) {
81         if (jsonInputs_.renderDataStore.typeName != RenderDataStoreShaderPasses::TYPE_NAME) {
82             PLUGIN_LOG_W("RENDER_VALIDATION: RenderNodeShaderPassesGeneric only supports render data store with "
83                          "typename RenderDataStoreShaderPasses (typename: %s)",
84                 jsonInputs_.renderDataStore.typeName.c_str());
85             valid_ = false;
86         }
87     }
88     if (jsonInputs_.renderDataStore.dataStoreName.empty()) {
89         // use default if not given
90         jsonInputs_.renderDataStore.dataStoreName = RenderDataStoreShaderPasses::TYPE_NAME;
91         jsonInputs_.renderDataStore.typeName = RenderDataStoreShaderPasses::TYPE_NAME;
92     }
93 }
94 
PreExecuteFrame()95 void RenderNodeShaderPassesGeneric::PreExecuteFrame()
96 {
97     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
98     dsShaderPasses_ = static_cast<RenderDataStoreShaderPasses*>(
99         renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
100     if (!dsShaderPasses_) {
101         return;
102     }
103 
104     // process amount of data needed for UBO
105     uint32_t uboByteSize = 0U;
106     uboByteSize += dsShaderPasses_->GetRenderPropertyBindingInfo().alignedByteSize;
107     uboByteSize += dsShaderPasses_->GetComputePropertyBindingInfo().alignedByteSize;
108     // create the built-in buffer even if the bytesize would be zero
109     if ((uboByteSize > uboData_.byteSize) || (uboData_.byteSize == 0U)) {
110         uboData_.byteSize = uboByteSize + (OFFSET_ALIGNMENT * OVERESTIMATE_COUNT);
111         uboData_.byteSize = static_cast<uint32_t>(Align(uboData_.byteSize, OFFSET_ALIGNMENT));
112 
113         IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
114         uboData_.handle = gpuResourceMgr.Create(
115             uboData_.handle, GpuBufferDesc { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
116                                  (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
117                                  CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, uboData_.byteSize });
118     }
119 }
120 
ExecuteFrame(IRenderCommandList & cmdList)121 void RenderNodeShaderPassesGeneric::ExecuteFrame(IRenderCommandList& cmdList)
122 {
123     if (!valid_) {
124         return;
125     }
126     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
127     dsShaderPasses_ = static_cast<RenderDataStoreShaderPasses*>(
128         renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
129     if (!dsShaderPasses_) {
130         return;
131     }
132 
133     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
134     if (uboData_.handle) {
135         uboData_.mapData = static_cast<uint8_t*>(gpuResourceMgr.MapBuffer(uboData_.handle.GetHandle()));
136         uboData_.currentOffset = 0U;
137     }
138 
139     ProcessExecuteData();
140     ExecuteFrameGraphics(cmdList);
141     ExecuteFrameCompute(cmdList);
142 
143     if (uboData_.handle) {
144         gpuResourceMgr.UnmapBuffer(uboData_.handle.GetHandle());
145     }
146     uboData_.mapData = nullptr;
147     uboData_.currentOffset = 0U;
148 }
149 
ProcessExecuteData()150 void RenderNodeShaderPassesGeneric::ProcessExecuteData()
151 {
152     if (!dsShaderPasses_) {
153         return;
154     }
155 
156     // NOTE: does not process descriptors, uses one frame descriptors at the moment
157 }
158 
ExecuteFrameGraphics(IRenderCommandList & cmdList)159 void RenderNodeShaderPassesGeneric::ExecuteFrameGraphics(IRenderCommandList& cmdList)
160 {
161     if (!dsShaderPasses_) {
162         return;
163     }
164 
165     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
166     const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
167 
168     const auto rpData = dsShaderPasses_->GetRenderData();
169     for (const auto& ref : rpData) {
170         if (ValidRenderPass(ref.renderPass)) {
171             const RenderPass renderPass = ConvertToLowLevelRenderPass(ref.renderPass);
172             cmdList.BeginRenderPass(renderPass.renderPassDesc, { &renderPass.subpassDesc, 1U });
173 
174             const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
175             const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
176             cmdList.SetDynamicStateViewport(viewportDesc);
177             cmdList.SetDynamicStateScissor(scissorDesc);
178             if (ref.renderPass.subpassDesc.fragmentShadingRateAttachmentCount > 0) {
179                 cmdList.SetDynamicStateFragmentShadingRate(
180                     { 1u, 1u },
181                     FragmentShadingRateCombinerOps {
182                         CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
183                         CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE
184 		    });
185             }
186 
187             for (const auto& shaderRef : ref.shaderBinders) {
188                 if (!shaderRef) {
189                     continue;
190                 }
191                 const auto& sRef = (const ShaderPipelineBinder&)(*shaderRef.get());
192                 IPipelineDescriptorSetBinder* binder = sRef.GetPipelineDescriptorSetBinder();
193                 if (!binder) {
194                     continue;
195                 }
196                 const PipelineLayout& pl = sRef.GetPipelineLayout();
197                 const RenderHandle psoHandle = GetPsoHandleGraphics(renderPass, sRef.GetShaderHandle().GetHandle(), pl);
198                 cmdList.BindPipeline(psoHandle);
199 
200                 // copy custom property data
201                 {
202                     IShaderPipelineBinder::PropertyBindingView cpbv = shaderRef->GetPropertyBindingView();
203                     if (!cpbv.data.empty()) {
204                         const uint32_t byteOffset = WriteLocalUboData(cpbv.data);
205                         BindableBuffer bRes;
206                         bRes.handle = uboData_.handle.GetHandle();
207                         bRes.byteOffset = byteOffset;
208                         binder->BindBuffer(cpbv.set, cpbv.binding, bRes);
209                     }
210                 }
211 
212                 // create single frame descriptor sets
213                 RenderHandle descriptorSetHandles[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] {};
214                 uint32_t setCount = 0U;
215                 for (uint32_t setIdx = 0U; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
216                     const auto& currSet = pl.descriptorSetLayouts[setIdx];
217                     if (currSet.set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
218                         descriptorSetHandles[setIdx] = descriptorSetMgr.CreateOneFrameDescriptorSet(currSet.bindings);
219                         cmdList.UpdateDescriptorSet(
220                             descriptorSetHandles[setIdx], binder->GetDescriptorSetLayoutBindingResources(currSet.set));
221                         setCount++;
222                     }
223                 }
224                 cmdList.BindDescriptorSets(binder->GetFirstSet(), { descriptorSetHandles, setCount });
225 
226                 // vertex buffers and draw
227                 const array_view<const VertexBufferWithHandleReference> vb = sRef.GetVertexBuffers();
228                 const IndexBufferWithHandleReference ib = sRef.GetIndexBuffer();
229                 const IShaderPipelineBinder::DrawCommand dc = sRef.GetDrawCommand();
230                 if (!vb.empty()) {
231                     VertexBuffer vbs[PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
232                     const uint32_t vbCount =
233                         Math::min(PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT, static_cast<uint32_t>(vb.size()));
234                     for (uint32_t vbIdx = 0; vbIdx < vbCount; ++vbIdx) {
235                         const auto& vr = vb[vbIdx];
236                         vbs[vbIdx] = { vr.bufferHandle.GetHandle(), vr.bufferOffset, vr.byteSize };
237                     }
238                     cmdList.BindVertexBuffers({ vbs, vbCount });
239                 }
240                 const RenderHandle iaHandle = dc.argsHandle.GetHandle();
241                 const bool indirectDraw = RenderHandleUtil::IsValid(iaHandle);
242                 if (ib.bufferHandle) {
243                     cmdList.BindIndexBuffer(
244                         { ib.bufferHandle.GetHandle(), ib.bufferOffset, ib.byteSize, ib.indexType });
245                     if (indirectDraw) {
246                         cmdList.DrawIndexedIndirect(iaHandle, dc.argsOffset, 1U, 0U);
247                     } else {
248                         cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0U, 0U, 0U);
249                     }
250                 } else {
251                     if (indirectDraw) {
252                         cmdList.DrawIndirect(iaHandle, dc.argsOffset, 1U, 0U);
253                     } else {
254                         cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
255                     }
256                 }
257             }
258 
259             cmdList.EndRenderPass();
260         }
261     }
262 }
263 
ExecuteFrameCompute(IRenderCommandList & cmdList)264 void RenderNodeShaderPassesGeneric::ExecuteFrameCompute(IRenderCommandList& cmdList)
265 {
266     if (!dsShaderPasses_) {
267         return;
268     }
269 
270     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
271     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
272 
273     const auto cData = dsShaderPasses_->GetComputeData();
274     for (const auto& ref : cData) {
275         for (const auto& shaderRef : ref.shaderBinders) {
276             if (!shaderRef) {
277                 continue;
278             }
279             const auto& sRef = (const ShaderPipelineBinder&)(*shaderRef.get());
280             IPipelineDescriptorSetBinder* binder = sRef.GetPipelineDescriptorSetBinder();
281             if (!binder) {
282                 continue;
283             }
284 
285             const RenderHandle shaderHandle = sRef.GetShaderHandle().GetHandle();
286             const PipelineLayout& pl = sRef.GetPipelineLayout();
287             const RenderHandle psoHandle = GetPsoHandleCompute(shaderHandle, pl);
288             cmdList.BindPipeline(psoHandle);
289 
290             // copy custom property data
291             {
292                 IShaderPipelineBinder::PropertyBindingView cpbv = shaderRef->GetPropertyBindingView();
293                 if (!cpbv.data.empty()) {
294                     const uint32_t byteOffset = WriteLocalUboData(cpbv.data);
295                     BindableBuffer bRes;
296                     bRes.handle = uboData_.handle.GetHandle();
297                     bRes.byteOffset = byteOffset;
298                     binder->BindBuffer(cpbv.set, cpbv.binding, bRes);
299                 }
300             }
301 
302             // create single frame descriptor sets
303             RenderHandle descriptorSetHandles[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] {};
304             uint32_t setCount = 0U;
305             for (uint32_t setIdx = 0U; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
306                 const auto& currSet = pl.descriptorSetLayouts[setIdx];
307                 if (currSet.set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
308                     descriptorSetHandles[setIdx] = descriptorSetMgr.CreateOneFrameDescriptorSet(currSet.bindings);
309                     cmdList.UpdateDescriptorSet(
310                         descriptorSetHandles[setIdx], binder->GetDescriptorSetLayoutBindingResources(currSet.set));
311                     setCount++;
312                 }
313             }
314             cmdList.BindDescriptorSets(binder->GetFirstSet(), { descriptorSetHandles, setCount });
315 
316             const IShaderPipelineBinder::DispatchCommand dc = sRef.GetDispatchCommand();
317             const RenderHandle dcHandle = dc.handle.GetHandle();
318             const RenderHandleType handleType = RenderHandleUtil::GetHandleType(dcHandle);
319             if (handleType == RenderHandleType::GPU_BUFFER) {
320                 cmdList.DispatchIndirect(dcHandle, dc.argsOffset);
321             } else if (handleType == RenderHandleType::GPU_IMAGE) {
322                 const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
323                 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(dcHandle);
324                 const Math::UVec3 targetSize = { desc.width, desc.height, desc.depth };
325                 const ShaderThreadGroup tgs = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
326                 cmdList.Dispatch((targetSize.x + tgs.x - 1u) / tgs.x, (targetSize.y + tgs.y - 1u) / tgs.y,
327                     (targetSize.z + tgs.z - 1u) / tgs.z);
328             } else {
329                 cmdList.Dispatch(dc.threadGroupCount.x, dc.threadGroupCount.y, dc.threadGroupCount.z);
330             }
331         }
332     }
333 }
334 
WriteLocalUboData(const array_view<const uint8_t> uboData)335 uint32_t RenderNodeShaderPassesGeneric::WriteLocalUboData(const array_view<const uint8_t> uboData)
336 {
337     uint32_t retOffset = 0U;
338     if (uboData_.mapData && (!uboData.empty())) {
339         retOffset = uboData_.currentOffset;
340         PLUGIN_ASSERT((uboData_.currentOffset + uboData.size_bytes()) < uboData_.byteSize);
341         if ((uboData_.currentOffset + uboData.size_bytes()) < uboData_.byteSize) {
342             uint8_t* currData = uboData_.mapData + uboData_.currentOffset;
343             const uint8_t* dataPtrEnd = uboData_.mapData + uboData_.byteSize;
344             const auto writeDataByteSize = static_cast<uint32_t>(uboData.size_bytes());
345             CloneData(currData, size_t(dataPtrEnd - currData), uboData.data(), uboData.size_bytes());
346 
347             uboData_.currentOffset = Align(uboData_.currentOffset + writeDataByteSize, OFFSET_ALIGNMENT);
348         }
349     }
350     return retOffset;
351 }
352 
GetPsoHandleGraphics(const RenderPass & renderPass,const RenderHandle & shader,const PipelineLayout & pipelineLayout)353 RenderHandle RenderNodeShaderPassesGeneric::GetPsoHandleGraphics(
354     const RenderPass& renderPass, const RenderHandle& shader, const PipelineLayout& pipelineLayout)
355 {
356     // controlled by count
357     constexpr DynamicStateEnum dynamicStates[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
358         CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
359     const uint32_t dynamicStateCount = (renderPass.subpassDesc.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
360     const RenderHandle gfxStateHandle =
361         renderNodeContextMgr_->GetShaderManager().GetGraphicsStateHandleByShaderHandle(shader);
362     return renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
363         shader, gfxStateHandle, pipelineLayout, {}, {}, { dynamicStates, dynamicStateCount });
364 }
365 
GetPsoHandleCompute(const RenderHandle & shader,const PipelineLayout & pipelineLayout)366 RenderHandle RenderNodeShaderPassesGeneric::GetPsoHandleCompute(
367     const RenderHandle& shader, const PipelineLayout& pipelineLayout)
368 {
369     return renderNodeContextMgr_->GetPsoManager().GetComputePsoHandle(shader, pipelineLayout, {});
370 }
371 
ParseRenderNodeInputs()372 void RenderNodeShaderPassesGeneric::ParseRenderNodeInputs()
373 {
374     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
375     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
376     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
377 }
378 
ValidRenderPass(const RenderPassWithHandleReference & renderPass)379 bool RenderNodeShaderPassesGeneric::ValidRenderPass(const RenderPassWithHandleReference& renderPass)
380 {
381     if ((renderPass.renderPassDesc.attachmentCount > 0U) && renderPass.renderPassDesc.attachmentHandles[0U]) {
382         return true;
383     } else {
384 #if (RENDER_VALIDATION_ENABLED == 1)
385         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_invalid_rp", "Invalid render pass in node: %s",
386             renderNodeContextMgr_->GetNodeName().data());
387 #endif
388         return false;
389     }
390 }
391 
392 // for plugin / factory interface
Create()393 IRenderNode* RenderNodeShaderPassesGeneric::Create()
394 {
395     return new RenderNodeShaderPassesGeneric();
396 }
397 
Destroy(IRenderNode * instance)398 void RenderNodeShaderPassesGeneric::Destroy(IRenderNode* instance)
399 {
400     delete static_cast<RenderNodeShaderPassesGeneric*>(instance);
401 }
402 RENDER_END_NAMESPACE()
403