1 /*
2 * Copyright (c) 2022 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_weather_simulation.h"
17
18 #include <3d/render/intf_render_data_store_default_scene.h>
19 #include <3d/render/intf_render_node_scene_util.h>
20 #include <base/math/mathf.h>
21 #include <base/math/vector.h>
22 #include <core/log.h>
23 #include <render/datastore/intf_render_data_store.h>
24 #include <render/datastore/intf_render_data_store_manager.h>
25 #include <render/datastore/intf_render_data_store_pod.h>
26 #include <render/datastore/render_data_store_render_pods.h>
27 #include <render/device/intf_gpu_resource_manager.h>
28 #include <render/device/intf_shader_manager.h>
29 #include <render/namespace.h>
30 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
31 #include <render/nodecontext/intf_node_context_pso_manager.h>
32 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
33 #include <render/nodecontext/intf_render_command_list.h>
34 #include <render/nodecontext/intf_render_node_context_manager.h>
35 #include <render/nodecontext/intf_render_node_parser_util.h>
36 #include <render/nodecontext/intf_render_node_util.h>
37
38 #include "3d/shaders/common/water_ripple_common.h"
39
40 CORE3D_BEGIN_NAMESPACE()
41 using namespace BASE_NS;
42 using namespace RENDER_NS;
43
InitNode(IRenderNodeContextManager & renderNodeContextMgr)44 void RenderNodeWeatherSimulation ::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
45 {
46 renderNodeContextMgr_ = &renderNodeContextMgr;
47 const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
48 ParseRenderNodeInputs();
49
50 auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
51 const auto& renderNodeUtil = renderNodeContextMgr.GetRenderNodeUtil();
52 if (!shaderMgr.IsValid(shader_) || !shaderMgr.IsValid(initShader_)) {
53 CORE_LOG_E("RenderNodeRippleSimulation needs a valid shader handle");
54 }
55
56 // simulate shader
57 {
58 pipelineLayout_ = renderNodeContextMgr.GetRenderNodeUtil().CreatePipelineLayout(shader_);
59 psoHandle_ = renderNodeContextMgr.GetPsoManager().GetComputePsoHandle(shader_, pipelineLayout_, {});
60
61 {
62 const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(pipelineLayout_);
63 renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
64 }
65
66 // create pipeline descriptor set
67 pipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(pipelineLayout_);
68 }
69
70 // initialization shader
71 {
72 initPipelineLayout_ = renderNodeContextMgr.GetRenderNodeUtil().CreatePipelineLayout(initShader_);
73 initPsoHandle_ = renderNodeContextMgr.GetPsoManager().GetComputePsoHandle(initShader_, initPipelineLayout_, {});
74
75 {
76 const DescriptorCounts dc = renderNodeUtil.GetDescriptorCounts(initPipelineLayout_);
77 renderNodeContextMgr.GetDescriptorSetManager().ResetAndReserve(dc);
78 }
79
80 // create pipeline descriptor set
81 initPipelineDescriptorSetBinder_ = renderNodeUtil.CreatePipelineDescriptorSetBinder(initPipelineLayout_);
82 }
83
84 defaultMaterialSam_ = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
85 rippleTextureHandle_ = gpuResourceMgr.GetImageHandle("RIPPLE_RENDER_NODE_TEXTURE_0");
86 rippleTextureHandle1_ = gpuResourceMgr.GetImageHandle("RIPPLE_RENDER_NODE_TEXTURE_1");
87 rippleInputArgsBuffer_ = gpuResourceMgr.GetBufferHandle("RIPPLE_RENDER_NODE_INPUTBUFFER");
88 }
89
PreExecuteFrame()90 void RenderNodeWeatherSimulation ::PreExecuteFrame()
91 {
92 // re-create needed gpu resources
93 }
94
ExecuteFrame(IRenderCommandList & cmdList)95 void RenderNodeWeatherSimulation::ExecuteFrame(IRenderCommandList& cmdList)
96 {
97 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
98 dataStoreWeather_ =
99 static_cast<RenderDataStoreWeather*>(renderDataStoreMgr.GetRenderDataStore("RenderDataStoreWeather"));
100 const IRenderDataStoreDefaultScene* dataStoreScene = static_cast<CORE3D_NS::IRenderDataStoreDefaultScene*>(
101 renderDataStoreMgr.GetRenderDataStore("RenderDataStoreDefaultScene"));
102 if ((!dataStoreWeather_) || (!dataStoreScene)) {
103 return;
104 }
105
106 if (!RenderHandleUtil::IsValid(shader_)) {
107 return; // invalid shader
108 }
109
110 if (!areTextureInit) {
111 InitializeRippleBuffers(cmdList);
112 areTextureInit = true;
113 return;
114 }
115
116 const auto& effectData = dataStoreWeather_->GetWaterEffectData();
117 if (effectData.empty()) {
118 return;
119 }
120
121 const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
122 const auto TextureImageDesc = gpuResourceMgr.GetImageDescriptor(rippleTextureHandle_);
123
124 const auto scene = dataStoreScene->GetScene();
125 {
126 auto& pipelineDescriptorSetBinder = *pipelineDescriptorSetBinder_;
127 pipelineDescriptorSetBinder.ClearBindings();
128
129 // bind the input args buffer
130 {
131 BindableBuffer bindable;
132 bindable.handle = rippleInputArgsBuffer_;
133 bindable.byteOffset = 0;
134 bindable.byteSize = sizeof(DefaultWaterRippleDataStruct);
135 pipelineDescriptorSetBinder.BindBuffer(0, 0, bindable);
136 }
137
138 // bind the ripple storage src texture
139 {
140 BindableImage bindable;
141 if (pingPongIdx == 0) {
142 bindable.handle = rippleTextureHandle_;
143 } else {
144 bindable.handle = rippleTextureHandle1_;
145 }
146 pipelineDescriptorSetBinder.BindImage(0, 1, bindable);
147 }
148
149 // bind the ripple storage dst texture
150 {
151 BindableImage bindable;
152 if (pingPongIdx == 1) {
153 bindable.handle = rippleTextureHandle_;
154 } else {
155 bindable.handle = rippleTextureHandle1_;
156 }
157 pipelineDescriptorSetBinder.BindImage(0, 2, bindable);
158 }
159
160 const auto descHandle = pipelineDescriptorSetBinder_->GetDescriptorSetHandle(0);
161 const auto bindings = pipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(0);
162 cmdList.UpdateDescriptorSet(descHandle, bindings);
163 }
164
165 cmdList.BindPipeline(psoHandle_);
166
167 // bind all sets
168 {
169 const auto descHandles = pipelineDescriptorSetBinder_->GetDescriptorSetHandles();
170 cmdList.BindDescriptorSets(0, descHandles);
171 }
172
173 BASE_NS::Math::Vec4 pc { scene.deltaTime / 1000.0f, 0, 0, 0 };
174
175 // NOTE: fix the hard-coded
176 // Add plane offcet to pc
177 pc.z = effectData[0U].planeOffset.x;
178 pc.w = effectData[0U].planeOffset.y;
179
180 cmdList.PushConstant(pipelineLayout_.pushConstant, arrayviewU8(pc).data());
181
182 // dispatch compute shader
183 if (TextureImageDesc.width > 1u && TextureImageDesc.height > 1u) {
184 const Math::UVec3 targetSize = { TextureImageDesc.width, TextureImageDesc.height, 1 };
185
186 const uint32_t tgcX = (targetSize.x + WATER_RIPPLE_TGS - 1u) / WATER_RIPPLE_TGS;
187 const uint32_t tgcY = (targetSize.y + WATER_RIPPLE_TGS - 1u) / WATER_RIPPLE_TGS;
188
189 cmdList.Dispatch(tgcX, tgcY, 1);
190 } else {
191 CORE_LOG_W("RenderNodeRippleSimulation: dispatchResources needed");
192 }
193
194 {
195 // add barrier for memory
196 constexpr GeneralBarrier src { AccessFlagBits::CORE_ACCESS_SHADER_WRITE_BIT,
197 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
198 constexpr GeneralBarrier dst { AccessFlagBits::CORE_ACCESS_INDIRECT_COMMAND_READ_BIT |
199 AccessFlagBits::CORE_ACCESS_SHADER_WRITE_BIT,
200 PipelineStageFlagBits::CORE_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
201 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
202
203 cmdList.CustomMemoryBarrier(src, dst);
204 cmdList.AddCustomBarrierPoint();
205 }
206
207 // copy from 1 to 0
208 if (pingPongIdx == 0U) {
209 ImageCopy imageCopy;
210 imageCopy.srcSubresource = { RENDER_NS::ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u };
211 imageCopy.srcOffset = { 0, 0, 0 };
212 imageCopy.dstSubresource = { RENDER_NS::ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1u };
213 imageCopy.dstOffset = { 0, 0, 0 };
214 imageCopy.extent = { TextureImageDesc.width, TextureImageDesc.height, 1u };
215
216 cmdList.CopyImageToImage(rippleTextureHandle1_, rippleTextureHandle_, imageCopy);
217 }
218
219 pingPongIdx = (pingPongIdx == 0U) ? 1U : 0U;
220 }
221
InitializeRippleBuffers(RENDER_NS::IRenderCommandList & cmdList)222 void RenderNodeWeatherSimulation::InitializeRippleBuffers(RENDER_NS::IRenderCommandList& cmdList)
223 {
224 const auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
225 const auto TextureImageDesc = gpuResourceMgr.GetImageDescriptor(rippleTextureHandle_);
226
227 {
228 auto& pipelineDescriptorSetBinder = *initPipelineDescriptorSetBinder_;
229 pipelineDescriptorSetBinder.ClearBindings();
230
231 // bind the input args buffer
232 {
233 BindableBuffer bindable;
234 bindable.handle = rippleInputArgsBuffer_;
235 bindable.byteOffset = 0;
236 bindable.byteSize = sizeof(DefaultWaterRippleDataStruct);
237 pipelineDescriptorSetBinder.BindBuffer(0, 0, bindable);
238 }
239
240 // bind the ripple storage src texture
241 {
242 BindableImage bindable;
243 bindable.handle = rippleTextureHandle_;
244 bindable.samplerHandle = rippleTextureHandle_;
245 pipelineDescriptorSetBinder.BindImage(0, 1, bindable);
246 }
247
248 // bind the ripple storage dst texture
249 {
250 BindableImage bindable;
251 bindable.handle = rippleTextureHandle1_;
252 bindable.samplerHandle = rippleTextureHandle1_;
253 pipelineDescriptorSetBinder.BindImage(0, 2, bindable);
254 }
255
256 const auto descHandle = initPipelineDescriptorSetBinder_->GetDescriptorSetHandle(0);
257 const auto bindings = initPipelineDescriptorSetBinder_->GetDescriptorSetLayoutBindingResources(0);
258 cmdList.UpdateDescriptorSet(descHandle, bindings);
259 }
260
261 cmdList.BindPipeline(initPsoHandle_);
262
263 // bind all sets
264 {
265 const auto descHandles = initPipelineDescriptorSetBinder_->GetDescriptorSetHandles();
266 cmdList.BindDescriptorSets(0, descHandles);
267 }
268
269 // dispatch compute shader
270 if (TextureImageDesc.width > 1u && TextureImageDesc.height > 1u) {
271 const Math::UVec3 targetSize = { TextureImageDesc.width, TextureImageDesc.height, 1 };
272
273 const uint32_t tgcX = (targetSize.x + WATER_RIPPLE_TGS - 1u) / WATER_RIPPLE_TGS;
274 const uint32_t tgcY = (targetSize.y + WATER_RIPPLE_TGS - 1u) / WATER_RIPPLE_TGS;
275
276 cmdList.Dispatch(tgcX, tgcY, 1);
277 } else {
278 CORE_LOG_W("RenderNodeRippleSimulation: dispatchResources needed");
279 }
280
281 {
282 // add barrier for memory
283 constexpr GeneralBarrier src { AccessFlagBits::CORE_ACCESS_SHADER_WRITE_BIT,
284 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
285 constexpr GeneralBarrier dst { AccessFlagBits::CORE_ACCESS_INDIRECT_COMMAND_READ_BIT |
286 AccessFlagBits::CORE_ACCESS_SHADER_WRITE_BIT,
287 PipelineStageFlagBits::CORE_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
288 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COMPUTE_SHADER_BIT };
289
290 cmdList.CustomMemoryBarrier(src, dst);
291 cmdList.AddCustomBarrierPoint();
292 }
293 }
294
ParseRenderNodeInputs()295 void RenderNodeWeatherSimulation ::ParseRenderNodeInputs()
296 {
297 const IRenderNodeParserUtil& parserUtil = renderNodeContextMgr_->GetRenderNodeParserUtil();
298 const auto jsonVal = renderNodeContextMgr_->GetNodeJson();
299 jsonInputs_.resources = parserUtil.GetInputResources(jsonVal, "resources");
300 jsonInputs_.dispatchResources = parserUtil.GetInputResources(jsonVal, "dispatchResources");
301 jsonInputs_.renderDataStore = parserUtil.GetRenderDataStore(jsonVal, "renderDataStore");
302 jsonInputs_.renderDataStoreSpecialization =
303 parserUtil.GetRenderDataStore(jsonVal, "renderDataStoreShaderSpecialization");
304
305 const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
306
307 // simulate shader
308 {
309 const auto shaderName = parserUtil.GetStringValue(jsonVal, "shader");
310 shader_ = shaderMgr.GetShaderHandle(shaderName);
311 }
312
313 // init shader
314 {
315 initShader_ = shaderMgr.GetShaderHandle("3dshaders://computeshader/water_ripple_initialize.shader");
316 }
317
318 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
319 jsonInputs_.hasChangeableResourceHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.resources);
320 jsonInputs_.hasChangeableDispatchHandles = renderNodeUtil.HasChangeableResources(jsonInputs_.dispatchResources);
321 }
322
323 // for plugin / factory interface
Create()324 IRenderNode* RenderNodeWeatherSimulation ::Create()
325 {
326 return new RenderNodeWeatherSimulation();
327 }
328
Destroy(IRenderNode * instance)329 void RenderNodeWeatherSimulation::Destroy(IRenderNode* instance)
330 {
331 delete static_cast<RenderNodeWeatherSimulation*>(instance);
332 }
333 CORE3D_END_NAMESPACE()
334