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