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