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_motion_blur.h"
17
18 #include <render/device/intf_gpu_resource_manager.h>
19 #include <render/device/intf_shader_manager.h>
20 #include <render/device/pipeline_state_desc.h>
21 #include <render/namespace.h>
22 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
23 #include <render/nodecontext/intf_node_context_pso_manager.h>
24 #include <render/nodecontext/intf_render_command_list.h>
25 #include <render/nodecontext/intf_render_node_context_manager.h>
26 #include <render/nodecontext/intf_render_node_util.h>
27
28 #include "default_engine_constants.h"
29 #include "device/gpu_resource_handle_util.h"
30 #include "render/shaders/common/render_post_process_structs_common.h"
31
32 using namespace BASE_NS;
33
34 RENDER_BEGIN_NAMESPACE()
35 namespace {
36 // needs to match motion blur shaders
37 constexpr uint32_t CORE_SPREAD_TYPE_NEIGHBORHOOD { 0U };
38 constexpr uint32_t CORE_SPREAD_TYPE_HORIZONTAL { 1U };
39 constexpr uint32_t CORE_SPREAD_TYPE_VERTICAL { 2U };
40 constexpr uint32_t VELOCITY_TILE_SIZE { 8U };
41
42 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
43
44 constexpr uint32_t MAX_PASS_COUNT { 3u };
45 } // namespace
46
Init(IRenderNodeContextManager & renderNodeContextMgr,const MotionBlurInfo & motionBlurInfo)47 void RenderMotionBlur::Init(IRenderNodeContextManager& renderNodeContextMgr, const MotionBlurInfo& motionBlurInfo)
48 {
49 motionBlurInfo_ = motionBlurInfo;
50 const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr.GetShaderManager();
51 {
52 renderData_ = {};
53 renderData_.shader = shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur.shader");
54 renderData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderData_.shader);
55 const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderData_.shader);
56 renderData_.pso = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
57 renderData_.pipelineLayout, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
58 }
59 {
60 renderTileMaxData_ = {};
61 renderTileMaxData_.shader =
62 shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur_tile_max.shader");
63 renderTileMaxData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderTileMaxData_.shader);
64 const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderTileMaxData_.shader);
65 renderTileMaxData_.pso = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderTileMaxData_.shader,
66 graphicsState, renderTileMaxData_.pipelineLayout, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
67 }
68 {
69 renderTileNeighborData_ = {};
70 renderTileNeighborData_.shader =
71 shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur_tile_neighborhood.shader");
72 renderTileNeighborData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderTileNeighborData_.shader);
73 const RenderHandle graphicsState =
74 shaderMgr.GetGraphicsStateHandleByShaderHandle(renderTileNeighborData_.shader);
75 const ShaderSpecializationConstantView specView =
76 shaderMgr.GetReflectionSpecialization(renderTileNeighborData_.shader);
77 {
78 const uint32_t specFlags[] = { CORE_SPREAD_TYPE_NEIGHBORHOOD };
79 const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
80 renderTileNeighborData_.psoNeighborhood = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
81 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
82 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
83 }
84 {
85 const uint32_t specFlags[] = { CORE_SPREAD_TYPE_HORIZONTAL };
86 const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
87 renderTileNeighborData_.psoHorizontal = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
88 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
89 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
90 }
91 {
92 const uint32_t specFlags[] = { CORE_SPREAD_TYPE_VERTICAL };
93 const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
94 renderTileNeighborData_.psoVertical = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
95 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
96 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
97 }
98 }
99 samplerHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
100 DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
101 samplerNearestHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
102 DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP);
103 {
104 constexpr uint32_t globalSet = 0u;
105 constexpr uint32_t localSet = 1u;
106
107 INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
108 {
109 const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[globalSet].bindings;
110 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
111 globalSet0_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
112 }
113 {
114 const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
115 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
116 localSet1_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
117 }
118 {
119 const auto& bindings = renderTileMaxData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
120 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
121 localTileMaxSet1_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
122 }
123 {
124 const auto& bindings = renderTileNeighborData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
125 {
126 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
127 localTileNeighborhoodSet1_[0U] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
128 }
129 {
130 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
131 localTileNeighborhoodSet1_[1U] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
132 }
133 }
134 }
135 }
136
PreExecute(IRenderNodeContextManager & renderNodeContextMgr,const MotionBlurInfo & blurInfo,const PostProcessConfiguration & ppConfig)137 void RenderMotionBlur::PreExecute(IRenderNodeContextManager& renderNodeContextMgr, const MotionBlurInfo& blurInfo,
138 const PostProcessConfiguration& ppConfig)
139 {
140 motionBlurInfo_ = blurInfo;
141
142 if ((ppConfig.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::MEDIUM) ||
143 (ppConfig.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::HIGH)) {
144 const uint32_t compSizeX = (motionBlurInfo_.size.x + VELOCITY_TILE_SIZE - 1U) / VELOCITY_TILE_SIZE;
145 const uint32_t compSizeY = (motionBlurInfo_.size.y + VELOCITY_TILE_SIZE - 1U) / VELOCITY_TILE_SIZE;
146 if ((!tileVelocityImages_[0U]) || (tileImageSize_.x != compSizeX) || (tileImageSize_.y != compSizeY)) {
147 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
148 GpuImageDesc desc = renderNodeContextMgr.GetGpuResourceManager().GetImageDescriptor(blurInfo.velocity);
149 desc.engineCreationFlags =
150 CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS | CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS;
151 desc.usageFlags = CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
152 desc.mipCount = 1U;
153 desc.layerCount = 1U;
154 desc.width = compSizeX;
155 desc.height = compSizeY;
156 tileVelocityImages_[0U] = gpuResourceMgr.Create(tileVelocityImages_[0U], desc);
157 tileVelocityImages_[1U] = gpuResourceMgr.Create(tileVelocityImages_[1U], desc);
158
159 tileImageSize_ = { compSizeX, compSizeY };
160 }
161 }
162 }
163
Execute(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList,const MotionBlurInfo & blurInfo,const PostProcessConfiguration & ppConfig)164 void RenderMotionBlur::Execute(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
165 const MotionBlurInfo& blurInfo, const PostProcessConfiguration& ppConfig)
166 {
167 if (!RenderHandleUtil::IsGpuImage(blurInfo.output)) {
168 return;
169 }
170
171 RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderMotionBlur", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
172
173 // Update global descriptor set 0 for both passes
174 UpdateDescriptorSet0(cmdList, blurInfo);
175
176 const RenderHandle velocity = blurInfo.velocity;
177 RenderHandle tileVelocity = blurInfo.velocity;
178 if ((ppConfig.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::MEDIUM) ||
179 (ppConfig.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::HIGH)) {
180 ExecuteTileVelocity(renderNodeContextMgr, cmdList, blurInfo);
181 const RenderHandle tv = GetTileVelocityForMotionBlur();
182 tileVelocity = RenderHandleUtil::IsValid(tv) ? tv : velocity;
183 }
184
185 const auto& renderData = renderData_;
186
187 RenderPass renderPass;
188 renderPass.renderPassDesc.attachmentCount = 1;
189 renderPass.renderPassDesc.renderArea = { 0, 0, motionBlurInfo_.size.x, motionBlurInfo_.size.y };
190 renderPass.renderPassDesc.subpassCount = 1;
191 renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
192 renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
193 renderPass.renderPassDesc.attachmentHandles[0] = blurInfo.output;
194 renderPass.subpassStartIndex = 0;
195 auto& subpass = renderPass.subpassDesc;
196 subpass.colorAttachmentCount = 1;
197 subpass.colorAttachmentIndices[0] = 0;
198
199 cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
200 cmdList.BindPipeline(renderData.pso);
201
202 RenderHandle sets[2u] {};
203 {
204 auto& binder = *globalSet0_;
205 sets[0u] = binder.GetDescriptorSetHandle();
206 }
207 {
208 auto& binder = *localSet1_;
209 binder.ClearBindings();
210 uint32_t binding = 0u;
211 binder.BindImage(binding++, blurInfo.input, samplerHandle_);
212 binder.BindImage(binding++, blurInfo.depth, samplerNearestHandle_);
213 binder.BindImage(binding++, velocity, samplerHandle_);
214 binder.BindImage(binding++, tileVelocity, samplerHandle_);
215 cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
216 sets[1u] = binder.GetDescriptorSetHandle();
217 }
218 cmdList.BindDescriptorSets(0u, sets);
219
220 if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
221 const auto fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
222 const auto fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
223 const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
224 cmdList.PushConstantData(renderData_.pipelineLayout.pushConstant, arrayviewU8(pc));
225 }
226
227 // dynamic state
228 cmdList.SetDynamicStateViewport(renderNodeContextMgr.GetRenderNodeUtil().CreateDefaultViewport(renderPass));
229 cmdList.SetDynamicStateScissor(renderNodeContextMgr.GetRenderNodeUtil().CreateDefaultScissor(renderPass));
230
231 cmdList.Draw(3u, 1u, 0u, 0u);
232 cmdList.EndRenderPass();
233 }
234
ExecuteTileVelocity(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList,const MotionBlurInfo & blurInfo)235 void RenderMotionBlur::ExecuteTileVelocity(
236 IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList, const MotionBlurInfo& blurInfo)
237 {
238 if ((!RenderHandleUtil::IsGpuImage(blurInfo.output)) || (!tileVelocityImages_[0U])) {
239 return;
240 }
241
242 RenderPass renderPass;
243 renderPass.renderPassDesc.attachmentCount = 1;
244 renderPass.renderPassDesc.renderArea = { 0, 0, tileImageSize_.x, tileImageSize_.y };
245 renderPass.renderPassDesc.subpassCount = 1;
246 renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
247 renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
248 renderPass.subpassStartIndex = 0;
249 auto& subpass = renderPass.subpassDesc;
250 subpass.colorAttachmentCount = 1;
251 subpass.colorAttachmentIndices[0] = 0;
252
253 const RenderHandle vel0 = tileVelocityImages_[0U].GetHandle();
254 const RenderHandle vel1 = tileVelocityImages_[1U].GetHandle();
255
256 const ViewportDesc viewport = renderNodeContextMgr.GetRenderNodeUtil().CreateDefaultViewport(renderPass);
257 const ScissorDesc scissor = renderNodeContextMgr.GetRenderNodeUtil().CreateDefaultScissor(renderPass);
258
259 const auto fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
260 const auto fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
261 const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
262
263 RenderHandle sets[2u] {};
264 {
265 auto& binder = *globalSet0_;
266 sets[0u] = binder.GetDescriptorSetHandle();
267 }
268
269 // tile max pass
270 {
271 const auto& renderData = renderTileMaxData_;
272 renderPass.renderPassDesc.attachmentHandles[0] = vel0;
273
274 cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
275 cmdList.BindPipeline(renderData.pso);
276
277 {
278 auto& binder = *localTileMaxSet1_;
279 binder.ClearBindings();
280 binder.BindImage(0U, blurInfo.velocity, samplerHandle_);
281 cmdList.UpdateDescriptorSet(
282 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
283 sets[1u] = binder.GetDescriptorSetHandle();
284 }
285 cmdList.BindDescriptorSets(0u, sets);
286
287 if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
288 cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
289 }
290
291 // dynamic state
292 cmdList.SetDynamicStateViewport(viewport);
293 cmdList.SetDynamicStateScissor(scissor);
294
295 cmdList.Draw(3U, 1U, 0U, 0U);
296 cmdList.EndRenderPass();
297 }
298 // tile neighborhood pass
299 {
300 const auto& renderData = renderTileNeighborData_;
301 {
302 const RenderHandle pso =
303 renderTileNeighborData_.doublePass ? renderData.psoHorizontal : renderData.psoNeighborhood;
304
305 renderPass.renderPassDesc.attachmentHandles[0] = vel1;
306
307 cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
308 cmdList.BindPipeline(pso);
309
310 {
311 auto& binder = *localTileNeighborhoodSet1_[0U];
312 binder.ClearBindings();
313 binder.BindImage(0U, vel0, samplerHandle_);
314 cmdList.UpdateDescriptorSet(
315 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
316 sets[1u] = binder.GetDescriptorSetHandle();
317 }
318 cmdList.BindDescriptorSets(0u, sets);
319
320 if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
321 cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
322 }
323
324 // dynamic state
325 cmdList.SetDynamicStateViewport(viewport);
326 cmdList.SetDynamicStateScissor(scissor);
327
328 cmdList.Draw(3U, 1U, 0U, 0U);
329 cmdList.EndRenderPass();
330 }
331 if (renderTileNeighborData_.doublePass) {
332 const RenderHandle pso = renderData.psoVertical;
333
334 renderPass.renderPassDesc.attachmentHandles[0] = vel0;
335
336 cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
337 cmdList.BindPipeline(pso);
338
339 {
340 auto& binder = *localTileNeighborhoodSet1_[1U];
341 binder.ClearBindings();
342 binder.BindImage(0U, vel1, samplerHandle_);
343 cmdList.UpdateDescriptorSet(
344 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
345 sets[1u] = binder.GetDescriptorSetHandle();
346 }
347 cmdList.BindDescriptorSets(0u, sets);
348
349 if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
350 cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
351 }
352
353 // dynamic state
354 cmdList.SetDynamicStateViewport(viewport);
355 cmdList.SetDynamicStateScissor(scissor);
356
357 cmdList.Draw(3U, 1U, 0U, 0U);
358 cmdList.EndRenderPass();
359 }
360 }
361 }
362
UpdateDescriptorSet0(IRenderCommandList & cmdList,const MotionBlurInfo & blurInfo)363 void RenderMotionBlur::UpdateDescriptorSet0(IRenderCommandList& cmdList, const MotionBlurInfo& blurInfo)
364 {
365 const RenderHandle ubo = blurInfo.globalUbo;
366 auto& binder = *globalSet0_;
367 binder.ClearBindings();
368 uint32_t binding = 0u;
369 binder.BindBuffer(binding++, ubo, 0u);
370 binder.BindBuffer(binding++, ubo, blurInfo.globalUboByteOffset, sizeof(GlobalPostProcessStruct));
371 cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
372 }
373
GetTileVelocityForMotionBlur() const374 RenderHandle RenderMotionBlur::GetTileVelocityForMotionBlur() const
375 {
376 return renderTileNeighborData_.doublePass ? tileVelocityImages_[0U].GetHandle()
377 : tileVelocityImages_[1U].GetHandle();
378 }
379
GetDescriptorCounts()380 DescriptorCounts RenderMotionBlur::GetDescriptorCounts()
381 {
382 // expected high max mip count
383 return DescriptorCounts { {
384 { CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_PASS_COUNT },
385 { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u * MAX_PASS_COUNT },
386 } };
387 }
388 RENDER_END_NAMESPACE()
389