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     if (uboByteSize > uboData_.byteSize) {
109         uboData_.byteSize = uboByteSize + (OFFSET_ALIGNMENT * OVERESTIMATE_COUNT);
110         uboData_.byteSize = static_cast<uint32_t>(Align(uboData_.byteSize, OFFSET_ALIGNMENT));
111 
112         IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
113         uboData_.handle = gpuResourceMgr.Create(
114             uboData_.handle, GpuBufferDesc { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
115                                 (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
116                                 CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, uboData_.byteSize });
117     }
118 }
119 
ExecuteFrame(IRenderCommandList & cmdList)120 void RenderNodeShaderPassesGeneric::ExecuteFrame(IRenderCommandList& cmdList)
121 {
122     if (!valid_) {
123         return;
124     }
125     const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
126     dsShaderPasses_ = static_cast<RenderDataStoreShaderPasses*>(
127         renderDataStoreMgr.GetRenderDataStore(jsonInputs_.renderDataStore.dataStoreName));
128     if (!dsShaderPasses_) {
129         return;
130     }
131 
132     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
133     if (uboData_.handle) {
134         uboData_.mapData = static_cast<uint8_t*>(gpuResourceMgr.MapBuffer(uboData_.handle.GetHandle()));
135         uboData_.currentOffset = 0U;
136     }
137 
138     ProcessExecuteData();
139     ExecuteFrameGraphics(cmdList);
140     ExecuteFrameCompute(cmdList);
141 
142     if (uboData_.handle) {
143         gpuResourceMgr.UnmapBuffer(uboData_.handle.GetHandle());
144     }
145     uboData_.mapData = nullptr;
146     uboData_.currentOffset = 0U;
147 }
148 
ProcessExecuteData()149 void RenderNodeShaderPassesGeneric::ProcessExecuteData()
150 {
151     if (!dsShaderPasses_) {
152         return;
153     }
154 
155     // NOTE: does not process descriptors, uses one frame descriptors at the moment
156 }
157 
ExecuteFrameGraphics(IRenderCommandList & cmdList)158 void RenderNodeShaderPassesGeneric::ExecuteFrameGraphics(IRenderCommandList& cmdList)
159 {
160     if (!dsShaderPasses_) {
161         return;
162     }
163 
164     INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
165     const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
166 
167     const auto rpData = dsShaderPasses_->GetRenderData();
168     for (const auto& ref : rpData) {
169         if (ValidRenderPass(ref.renderPass)) {
170             const RenderPass renderPass = ConvertToLowLevelRenderPass(ref.renderPass);
171             cmdList.BeginRenderPass(renderPass.renderPassDesc, { &renderPass.subpassDesc, 1U });
172 
173             const ViewportDesc viewportDesc = renderNodeUtil.CreateDefaultViewport(renderPass);
174             const ScissorDesc scissorDesc = renderNodeUtil.CreateDefaultScissor(renderPass);
175             cmdList.SetDynamicStateViewport(viewportDesc);
176             cmdList.SetDynamicStateScissor(scissorDesc);
177             if (ref.renderPass.subpassDesc.fragmentShadingRateAttachmentCount > 0) {
178                 cmdList.SetDynamicStateFragmentShadingRate(
179                     { 1u, 1u },
180                     FragmentShadingRateCombinerOps {
181                         CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE,
182                         CORE_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE });
183             }
184 
185             for (const auto& shaderRef : ref.shaderBinders) {
186                 if (!shaderRef) {
187                     continue;
188                 }
189                 const auto& sRef = (const ShaderPipelineBinder&)(*shaderRef.get());
190                 IPipelineDescriptorSetBinder* binder = sRef.GetPipelineDescriptorSetBinder();
191                 if (!binder) {
192                     continue;
193                 }
194                 const PipelineLayout& pl = sRef.GetPipelineLayout();
195                 const RenderHandle psoHandle = GetPsoHandleGraphics(renderPass, sRef.GetShaderHandle().GetHandle(), pl);
196                 cmdList.BindPipeline(psoHandle);
197 
198                 // copy custom property data
199                 {
200                     IShaderPipelineBinder::PropertyBindingView cpbv = shaderRef->GetPropertyBindingView();
201                     if (!cpbv.data.empty()) {
202                         const uint32_t byteOffset = WriteLocalUboData(cpbv.data);
203                         BindableBuffer bRes;
204                         bRes.handle = uboData_.handle.GetHandle();
205                         bRes.byteOffset = byteOffset;
206                         binder->BindBuffer(cpbv.set, cpbv.binding, bRes);
207                     }
208                 }
209 
210                 // create single frame descriptor sets
211                 RenderHandle descriptorSetHandles[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] {};
212                 uint32_t setCount = 0U;
213                 for (uint32_t setIdx = 0U; setIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++setIdx) {
214                     const auto& currSet = pl.descriptorSetLayouts[setIdx];
215                     if (currSet.set < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) {
216                         descriptorSetHandles[setIdx] = descriptorSetMgr.CreateOneFrameDescriptorSet(currSet.bindings);
217                         cmdList.UpdateDescriptorSet(
218                             descriptorSetHandles[setIdx], binder->GetDescriptorSetLayoutBindingResources(currSet.set));
219                         setCount++;
220                     }
221                 }
222                 cmdList.BindDescriptorSets(binder->GetFirstSet(), { descriptorSetHandles, setCount });
223 
224                 // vertex buffers and draw
225                 const array_view<const VertexBufferWithHandleReference> vb = sRef.GetVertexBuffers();
226                 const IndexBufferWithHandleReference ib = sRef.GetIndexBuffer();
227                 const IShaderPipelineBinder::DrawCommand dc = sRef.GetDrawCommand();
228                 if (!vb.empty()) {
229                     VertexBuffer vbs[PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT];
230                     const uint32_t vbCount =
231                         Math::min(PipelineStateConstants::MAX_VERTEX_BUFFER_COUNT, static_cast<uint32_t>(vb.size()));
232                     for (uint32_t vbIdx = 0; vbIdx < vbCount; ++vbIdx) {
233                         const auto& vr = vb[vbIdx];
234                         vbs[vbIdx] = { vr.bufferHandle.GetHandle(), vr.bufferOffset, vr.byteSize };
235                     }
236                     cmdList.BindVertexBuffers({ vbs, vbCount });
237                 }
238                 const RenderHandle iaHandle = dc.argsHandle.GetHandle();
239                 const bool indirectDraw = RenderHandleUtil::IsValid(iaHandle);
240                 if (ib.bufferHandle) {
241                     cmdList.BindIndexBuffer(
242                         { ib.bufferHandle.GetHandle(), ib.bufferOffset, ib.byteSize, ib.indexType });
243                     if (indirectDraw) {
244                         cmdList.DrawIndexedIndirect(iaHandle, dc.argsOffset, 1U, 0U);
245                     } else {
246                         cmdList.DrawIndexed(dc.indexCount, dc.instanceCount, 0U, 0U, 0U);
247                     }
248                 } else {
249                     if (indirectDraw) {
250                         cmdList.DrawIndirect(iaHandle, dc.argsOffset, 1U, 0U);
251                     } else {
252                         cmdList.Draw(dc.vertexCount, dc.instanceCount, 0, 0);
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 uint32_t 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()