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