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