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