• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 }, FragmentShadingRateCombinerOps { CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
181                                     CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
182             }
183 
184             for (const auto& shaderRef : ref.shaderBinders) {
185                 if (!shaderRef) {
186                     continue;
187                 }
188                 const auto& sRef = (const ShaderPipelineBinder&)(*shaderRef.get());
189                 IPipelineDescriptorSetBinder* binder = sRef.GetPipelineDescriptorSetBinder();
190                 if (!binder) {
191                     continue;
192                 }
193                 const PipelineLayout& pl = sRef.GetPipelineLayout();
194                 const RenderHandle psoHandle = GetPsoHandleGraphics(renderPass, sRef.GetShaderHandle().GetHandle(), pl);
195                 cmdList.BindPipeline(psoHandle);
196 
197                 // copy custom property data
198                 {
199                     IShaderPipelineBinder::PropertyBindingView cpbv = shaderRef->GetPropertyBindingView();
200                     if (!cpbv.data.empty()) {
201                         const uint32_t byteOffset = WriteLocalUboData(cpbv.data);
202                         BindableBuffer bRes;
203                         bRes.handle = uboData_.handle.GetHandle();
204                         bRes.byteOffset = byteOffset;
205                         binder->BindBuffer(cpbv.set, cpbv.binding, bRes);
206                     }
207                 }
208 
209                 // create single frame descriptor sets
210                 RenderHandle descriptorSetHandles[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] {};
211                 uint32_t setCount = 0U;
212                 for (uint32_t setIdx = 0U; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
213                     const auto& currSet = pl.descriptorSetLayouts[setIdx];
214                     if (currSet.set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
215                         descriptorSetHandles[setIdx] = descriptorSetMgr.CreateOneFrameDescriptorSet(currSet.bindings);
216                         cmdList.UpdateDescriptorSet(
217                             descriptorSetHandles[setIdx], binder->GetDescriptorSetLayoutBindingResources(currSet.set));
218                         setCount++;
219                     }
220                 }
221                 cmdList.BindDescriptorSets(binder->GetFirstSet(), { descriptorSetHandles, setCount });
222 
223                 // vertex buffers and draw
224                 const array_view<const VertexBufferWithHandleReference> vb = sRef.GetVertexBuffers();
225                 const IndexBufferWithHandleReference ib = sRef.GetIndexBuffer();
226                 const IShaderPipelineBinder::DrawCommand dc = sRef.GetDrawCommand();
227                 if (!vb.empty()) {
228                     VertexBuffer vbs[PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
229                     const uint32_t vbCount =
230                         Math::min(PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT, static_cast<uint32_t>(vb.size()));
231                     for (uint32_t vbIdx = 0; vbIdx < vbCount; ++vbIdx) {
232                         const auto& vr = vb[vbIdx];
233                         vbs[vbIdx] = { vr.bufferHandle.GetHandle(), vr.bufferOffset, vr.byteSize };
234                     }
235                     cmdList.BindVertexBuffers({ vbs, vbCount });
236                 }
237                 const RenderHandle iaHandle = dc.argsHandle.GetHandle();
238                 const bool indirectDraw = RenderHandleUtil::IsValid(iaHandle);
239                 if (ib.bufferHandle) {
240                     cmdList.BindIndexBuffer(
241                         { ib.bufferHandle.GetHandle(), ib.bufferOffset, ib.byteSize, ib.indexType });
242                     if (indirectDraw) {
243                         cmdList.DrawIndexedIndirect(iaHandle, dc.argsOffset, 1U, 0U);
244                     } else {
245                         cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0U, 0U, 0U);
246                     }
247                 } else {
248                     if (indirectDraw) {
249                         cmdList.DrawIndirect(iaHandle, dc.argsOffset, 1U, 0U);
250                     } else {
251                         cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
252                     }
253                 }
254             }
255 
256             cmdList.EndRenderPass();
257         }
258     }
259 }
260 
ExecuteFrameCompute(IRenderCommandList & cmdList)261 void RenderNodeShaderPassesGeneric::ExecuteFrameCompute(IRenderCommandList& cmdList)
262 {
263     if (!dsShaderPasses_) {
264         return;
265     }
266 
267     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
268     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
269 
270     const auto cData = dsShaderPasses_->GetComputeData();
271     for (const auto& ref : cData) {
272         for (const auto& shaderRef : ref.shaderBinders) {
273             if (!shaderRef) {
274                 continue;
275             }
276             const auto& sRef = (const ShaderPipelineBinder&)(*shaderRef.get());
277             IPipelineDescriptorSetBinder* binder = sRef.GetPipelineDescriptorSetBinder();
278             if (!binder) {
279                 continue;
280             }
281 
282             const RenderHandle shaderHandle = sRef.GetShaderHandle().GetHandle();
283             const PipelineLayout& pl = sRef.GetPipelineLayout();
284             const RenderHandle psoHandle = GetPsoHandleCompute(shaderHandle, pl);
285             cmdList.BindPipeline(psoHandle);
286 
287             // copy custom property data
288             {
289                 IShaderPipelineBinder::PropertyBindingView cpbv = shaderRef->GetPropertyBindingView();
290                 if (!cpbv.data.empty()) {
291                     const uint32_t byteOffset = WriteLocalUboData(cpbv.data);
292                     BindableBuffer bRes;
293                     bRes.handle = uboData_.handle.GetHandle();
294                     bRes.byteOffset = byteOffset;
295                     binder->BindBuffer(cpbv.set, cpbv.binding, bRes);
296                 }
297             }
298 
299             // create single frame descriptor sets
300             RenderHandle descriptorSetHandles[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] {};
301             uint32_t setCount = 0U;
302             for (uint32_t setIdx = 0U; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
303                 const auto& currSet = pl.descriptorSetLayouts[setIdx];
304                 if (currSet.set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
305                     descriptorSetHandles[setIdx] = descriptorSetMgr.CreateOneFrameDescriptorSet(currSet.bindings);
306                     cmdList.UpdateDescriptorSet(
307                         descriptorSetHandles[setIdx], binder->GetDescriptorSetLayoutBindingResources(currSet.set));
308                     setCount++;
309                 }
310             }
311             cmdList.BindDescriptorSets(binder->GetFirstSet(), { descriptorSetHandles, setCount });
312 
313             const IShaderPipelineBinder::DispatchCommand dc = sRef.GetDispatchCommand();
314             const RenderHandle dcHandle = dc.handle.GetHandle();
315             const RenderHandleType handleType = RenderHandleUtil::GetHandleType(dcHandle);
316             if (handleType == RenderHandleType::GPU_BUFFER) {
317                 cmdList.DispatchIndirect(dcHandle, dc.argsOffset);
318             } else if (handleType == RenderHandleType::GPU_IMAGE) {
319                 const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
320                 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(dcHandle);
321                 const Math::UVec3 targetSize = { desc.width, desc.height, desc.depth };
322                 const ShaderThreadGroup tgs = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
323                 cmdList.Dispatch((targetSize.x + tgs.x - 1u) / tgs.x, (targetSize.y + tgs.y - 1u) / tgs.y,
324                     (targetSize.z + tgs.z - 1u) / tgs.z);
325             } else {
326                 cmdList.Dispatch(dc.threadGroupCount.x, dc.threadGroupCount.y, dc.threadGroupCount.z);
327             }
328         }
329     }
330 }
331 
WriteLocalUboData(const array_view<const uint8_t> uboData)332 uint32_t RenderNodeShaderPassesGeneric::WriteLocalUboData(const array_view<const uint8_t> uboData)
333 {
334     uint32_t retOffset = 0U;
335     if (uboData_.mapData && (!uboData.empty())) {
336         retOffset = uboData_.currentOffset;
337         PLUGIN_ASSERT((uboData_.currentOffset + uboData.size_bytes()) < uboData_.byteSize);
338         if ((uboData_.currentOffset + uboData.size_bytes()) < uboData_.byteSize) {
339             uint8_t* currData = uboData_.mapData + uboData_.currentOffset;
340             const uint8_t* dataPtrEnd = uboData_.mapData + uboData_.byteSize;
341             const auto writeDataByteSize = static_cast<uint32_t>(uboData.size_bytes());
342             CloneData(currData, size_t(dataPtrEnd - currData), uboData.data(), uboData.size_bytes());
343 
344             uboData_.currentOffset = Align(uboData_.currentOffset + writeDataByteSize, OFFSET_ALIGNMENT);
345         }
346     }
347     return retOffset;
348 }
349 
GetPsoHandleGraphics(const RenderPass & renderPass,const RenderHandle & shader,const PipelineLayout & pipelineLayout)350 RenderHandle RenderNodeShaderPassesGeneric::GetPsoHandleGraphics(
351     const RenderPass& renderPass, const RenderHandle& shader, const PipelineLayout& pipelineLayout)
352 {
353     // controlled by count
354     constexpr DynamicStateEnum dynamicStates[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR,
355         CORE_DYNAMIC_STATE_ENUM_FRAGMENT_SHADING_RATE };
356     const uint32_t dynamicStateCount = (renderPass.subpassDesc.fragmentShadingRateAttachmentIndex != ~0u) ? 3u : 2u;
357     const RenderHandle gfxStateHandle =
358         renderNodeContextMgr_->GetShaderManager().GetGraphicsStateHandleByShaderHandle(shader);
359     return renderNodeContextMgr_->GetPsoManager().GetGraphicsPsoHandle(
360         shader, gfxStateHandle, pipelineLayout, {}, {}, { dynamicStates, dynamicStateCount });
361 }
362 
GetPsoHandleCompute(const RenderHandle & shader,const PipelineLayout & pipelineLayout)363 RenderHandle RenderNodeShaderPassesGeneric::GetPsoHandleCompute(
364     const RenderHandle& shader, const PipelineLayout& pipelineLayout)
365 {
366     return renderNodeContextMgr_->GetPsoManager().GetComputePsoHandle(shader, pipelineLayout, {});
367 }
368 
ParseRenderNodeInputs()369 void RenderNodeShaderPassesGeneric::ParseRenderNodeInputs()
370 {
371     const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
372     const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
373     jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
374 }
375 
ValidRenderPass(const RenderPassWithHandleReference & renderPass)376 bool RenderNodeShaderPassesGeneric::ValidRenderPass(const RenderPassWithHandleReference& renderPass)
377 {
378     if ((renderPass.renderPassDesc.attachmentCount > 0U) && renderPass.renderPassDesc.attachmentHandles[0U]) {
379         return true;
380     } else {
381 #if (RENDER_VALIDATION_ENABLED == 1)
382         PLUGIN_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_invalid_rp", "Invalid render pass in node: %s",
383             renderNodeContextMgr_->GetNodeName().data());
384 #endif
385         return false;
386     }
387 }
388 
389 // for plugin / factory interface
Create()390 IRenderNode* RenderNodeShaderPassesGeneric::Create()
391 {
392     return new RenderNodeShaderPassesGeneric();
393 }
394 
Destroy(IRenderNode * instance)395 void RenderNodeShaderPassesGeneric::Destroy(IRenderNode* instance)
396 {
397     delete static_cast<RenderNodeShaderPassesGeneric*>(instance);
398 }
399 RENDER_END_NAMESPACE()
400