• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_dotfield_simulation.h"
17 
18 #include <array>
19 
20 #include <3d/implementation_uids.h>
21 #include <3d/render/intf_render_data_store_default_scene.h>
22 #include <3d/render/intf_render_node_scene_util.h>
23 #include <base/containers/array_view.h>
24 #include <base/containers/vector.h>
25 #include <base/math/mathf.h>
26 #include <base/math/vector.h>
27 #include <core/log.h>
28 #include <render/datastore/intf_render_data_store_manager.h>
29 #include <render/datastore/intf_render_data_store_pod.h>
30 #include <render/datastore/render_data_store_render_pods.h>
31 #include <render/device/gpu_resource_desc.h>
32 #include <render/device/intf_gpu_resource_manager.h>
33 #include <render/device/intf_shader_manager.h>
34 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
35 #include <render/nodecontext/intf_node_context_pso_manager.h>
36 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
37 #include <render/nodecontext/intf_render_command_list.h>
38 #include <render/nodecontext/intf_render_node_context_manager.h>
39 #include <render/nodecontext/intf_render_node_util.h>
40 
41 #include "render_data_store_default_dotfield.h"
42 
43 namespace {
44 #include "app/shaders/common/dotfield_common.h"
45 #include "app/shaders/common/dotfield_struct_common.h"
46 } // namespace
47 
48 using namespace BASE_NS;
49 using namespace CORE_NS;
50 using namespace RENDER_NS;
51 
52 namespace Dotfield {
53 constexpr string_view DEFAULT_DOTFIELD_RENDER_DATA_STORE_NAME_POST_FIX = "RenderDataStoreDefaultDotfield";
54 
55 namespace {
CreateBinders(const IRenderNodeShaderManager & shaderMgr,INodeContextDescriptorSetManager & descriptorSetMgr,RenderNodeDotfieldSimulation::Binders & binders)56 void CreateBinders(const IRenderNodeShaderManager& shaderMgr, INodeContextDescriptorSetManager& descriptorSetMgr,
57     RenderNodeDotfieldSimulation::Binders& binders)
58 {
59     {
60         constexpr uint32_t prevBuffersSet1 = 0;
61         constexpr uint32_t currBuffersset2 = 1;
62 
63         auto createDescriptorSet = [](INodeContextDescriptorSetManager& descriptorSetMgr, PipelineLayout& pl,
64                                        uint32_t bufferSetIndex, IDescriptorSetBinder::Ptr& setBinder) {
65             const RenderHandle setDescHandle = descriptorSetMgr.CreateDescriptorSet(bufferSetIndex, pl);
66             setBinder = descriptorSetMgr.CreateDescriptorSetBinder(
67                 setDescHandle, pl.descriptorSetLayouts[bufferSetIndex].bindings);
68         };
69 
70         auto createDescriptorSets = [&createDescriptorSet](INodeContextDescriptorSetManager& descriptorSetMgr,
71                                         PipelineLayout& pl, uint32_t bufferSetIndex,
72                                         vector<IDescriptorSetBinder::Ptr>& setBinders) {
73             for (auto& binder : setBinders) {
74                 createDescriptorSet(descriptorSetMgr, pl, bufferSetIndex, binder);
75             }
76         };
77         { // simulate
78             auto& currBinders = binders.simulate;
79             currBinders.prevBuffersSet1.resize(DOTFIELD_EFFECT_MAX_COUNT);
80             currBinders.currBuffersSet2.resize(DOTFIELD_EFFECT_MAX_COUNT);
81             currBinders.pl = shaderMgr.GetPipelineLayout(
82                 shaderMgr.GetPipelineLayoutHandle("dotfieldpipelinelayouts://dotfield_simulation.shaderpl"));
83             PipelineLayout& pl = currBinders.pl;
84             CORE_ASSERT(pl.pushConstant.byteSize == sizeof(DotfieldSimulationPushConstantStruct));
85 
86             createDescriptorSets(descriptorSetMgr, pl, prevBuffersSet1, currBinders.prevBuffersSet1);
87             createDescriptorSets(descriptorSetMgr, pl, currBuffersset2, currBinders.currBuffersSet2);
88         }
89     }
90 }
91 } // namespace
92 
InitNode(IRenderNodeContextManager & renderNodeContextMgr)93 void RenderNodeDotfieldSimulation::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
94 {
95     renderNodeContextMgr_ = &renderNodeContextMgr;
96     {
97         // (sim(currFrame + prevFrame) * effectcount;
98         constexpr uint32_t dataBufferCountPerFrame = (2u + 2u) * DOTFIELD_EFFECT_MAX_COUNT;
99         const DescriptorCounts dc { {
100             { CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, dataBufferCountPerFrame },
101         } };
102         renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
103     }
104 
105     specializationToPsoData_.clear();
106 
107     shaderHandle_ = renderNodeContextMgr.GetShaderManager().GetShaderHandle(
108         "dotfieldshaders://computeshader/dotfield_simulation.shader");
109     CreateBinders(renderNodeContextMgr.GetShaderManager(), renderNodeContextMgr.GetDescriptorSetManager(), binders_);
110 
111     IClassRegister* classRegister = renderNodeContextMgr_->GetRenderContext().GetInterface<IClassRegister>();
112     if (classRegister) {
113         if (auto* renderNodeSceneUtil = CORE_NS::GetInstance<CORE3D_NS::IRenderNodeSceneUtil>(
114                 *classRegister, CORE3D_NS::UID_RENDER_NODE_SCENE_UTIL);
115             renderNodeSceneUtil) {
116             const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
117             stores_ = renderNodeSceneUtil->GetSceneRenderDataStores(
118                 renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
119         }
120     }
121 }
122 
PreExecuteFrame()123 void RenderNodeDotfieldSimulation::PreExecuteFrame() {}
124 
ExecuteFrame(IRenderCommandList & cmdList)125 void RenderNodeDotfieldSimulation::ExecuteFrame(IRenderCommandList& cmdList)
126 {
127     ComputeSimulate(*renderNodeContextMgr_, cmdList);
128 }
129 
ComputeSimulate(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList)130 void RenderNodeDotfieldSimulation::ComputeSimulate(
131     IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList)
132 {
133     const RenderDataStoreDefaultDotfield* dataStore = static_cast<RenderDataStoreDefaultDotfield*>(
134         renderNodeContextMgr.GetRenderDataStoreManager().GetRenderDataStore(
135             stores_.dataStoreNamePrefix + DEFAULT_DOTFIELD_RENDER_DATA_STORE_NAME_POST_FIX.data()));
136     if (!dataStore) {
137         return;
138     }
139 
140     const auto& dotfieldPrimitives = dataStore->GetDotfieldPrimitives();
141     if (dotfieldPrimitives.empty()) {
142         return;
143     }
144     const auto& bufferData = dataStore->GetBufferData();
145 
146     const uint32_t currFrameIndex = bufferData.currFrameIndex;
147     const uint32_t prevFrameIndex = 1 - currFrameIndex;
148     const uint32_t primitiveCount = static_cast<uint32_t>(dotfieldPrimitives.size());
149 
150     const auto& currBinders = binders_.simulate;
151 
152     RenderHandle pso;
153     for (uint32_t idx = 0; idx < primitiveCount; ++idx) {
154         const auto& dotfieldPrimitive = dotfieldPrimitives[idx];
155         const RenderDataDefaultDotfield::BufferData::Buffer& effect = bufferData.buffers[idx];
156 
157         PsoData psoData = GetPsoData(renderNodeContextMgr, currBinders.pl, shaderHandle_, firstFrame_);
158         if (pso != psoData.psoHandle) {
159             pso = psoData.psoHandle;
160             cmdList.BindPipeline(psoData.psoHandle);
161         }
162 
163         {
164             auto& prevBinder = *currBinders.prevBuffersSet1[idx];
165             prevBinder.BindBuffer(0, effect.dataBuffer[prevFrameIndex].GetHandle(), 0);
166             cmdList.UpdateDescriptorSet(
167                 prevBinder.GetDescriptorSetHandle(), prevBinder.GetDescriptorSetLayoutBindingResources());
168 
169             auto& currBinder = *currBinders.currBuffersSet2[idx];
170             currBinder.BindBuffer(0, effect.dataBuffer[currFrameIndex].GetHandle(), 0);
171             cmdList.UpdateDescriptorSet(
172                 currBinder.GetDescriptorSetHandle(), currBinder.GetDescriptorSetLayoutBindingResources());
173 
174             const RenderHandle descHandles[2] = { prevBinder.GetDescriptorSetHandle(),
175                 currBinder.GetDescriptorSetHandle() };
176             cmdList.BindDescriptorSets(0, { descHandles, 2u });
177         }
178         // push constant
179         const DotfieldSimulationPushConstantStruct pc = { { dotfieldPrimitive.size.x, dotfieldPrimitive.size.y, 0, 0 },
180             { dotfieldPrimitive.touch.x, dotfieldPrimitive.touch.y, dotfieldPrimitive.touchRadius, 0.f },
181             { dotfieldPrimitive.touchDirection.x, dotfieldPrimitive.touchDirection.y,
182                 dotfieldPrimitive.touchDirection.z, 0.f } };
183         cmdList.PushConstant(psoData.pushConstant, reinterpret_cast<const uint8_t*>(&pc));
184 
185         const uint32_t tgcX = (dotfieldPrimitive.size.x * dotfieldPrimitive.size.y + (DOTFIELD_SIMULATION_TGS - 1)) /
186                               DOTFIELD_SIMULATION_TGS;
187         cmdList.Dispatch(tgcX, 1, 1);
188 
189         {
190             // add custom memory barrier
191             constexpr GeneralBarrier src { AccessFlagBits::CORE_ACCESS_SHADER_WRITE_BIT,
192                 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
193             constexpr GeneralBarrier dst { AccessFlagBits::CORE_ACCESS_INDIRECT_COMMAND_READ_BIT,
194                 PipelineStageFlagBits::CORE_PIPELINE_STAGE_DRAW_INDIRECT_BIT };
195 
196             cmdList.CustomMemoryBarrier(src, dst);
197             cmdList.AddCustomBarrierPoint();
198         }
199     }
200     firstFrame_ = false;
201 }
202 
GetPsoData(IRenderNodeContextManager & renderNodeContextMgr,const PipelineLayout & pl,const RenderHandle & shaderHandle,bool firstFrame)203 RenderNodeDotfieldSimulation::PsoData RenderNodeDotfieldSimulation::GetPsoData(
204     IRenderNodeContextManager& renderNodeContextMgr, const PipelineLayout& pl, const RenderHandle& shaderHandle,
205     bool firstFrame)
206 {
207     uint32_t constantData = firstFrame ? 1u : 0u;
208 
209     if (const auto iter = specializationToPsoData_.find(constantData); iter != specializationToPsoData_.cend()) {
210         return iter->second;
211     } else { // new
212         const ShaderSpecializationConstantView sscv =
213             renderNodeContextMgr.GetShaderManager().GetReflectionSpecialization(shaderHandle);
214         const ShaderSpecializationConstantDataView specDataView {
215             sscv.constants,
216             { &constantData, 1 },
217         };
218         RenderHandle psoHandle =
219             renderNodeContextMgr.GetPsoManager().GetComputePsoHandle(shaderHandle, pl, specDataView);
220         PsoData psoData = { psoHandle, pl.pushConstant };
221         specializationToPsoData_[constantData] = psoData;
222         return psoData;
223     }
224 }
225 
226 // for plugin / factory interface
Create()227 IRenderNode* RenderNodeDotfieldSimulation::Create()
228 {
229     return new RenderNodeDotfieldSimulation();
230 }
231 
Destroy(IRenderNode * instance)232 void RenderNodeDotfieldSimulation::Destroy(IRenderNode* instance)
233 {
234     delete (RenderNodeDotfieldSimulation*)instance;
235 }
236 } // namespace Dotfield
237