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