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()