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