• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_post_process_motion_blur_node.h"
17 
18 #include <base/containers/fixed_string.h>
19 #include <base/containers/unordered_map.h>
20 #include <base/math/vector.h>
21 #include <core/property/property_types.h>
22 #include <core/property_tools/property_api_impl.inl>
23 #include <render/datastore/intf_render_data_store_manager.h>
24 #include <render/datastore/intf_render_data_store_pod.h>
25 #include <render/datastore/render_data_store_render_pods.h>
26 #include <render/device/intf_gpu_resource_manager.h>
27 #include <render/device/intf_shader_manager.h>
28 #include <render/namespace.h>
29 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
30 #include <render/nodecontext/intf_node_context_pso_manager.h>
31 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
32 #include <render/nodecontext/intf_render_command_list.h>
33 #include <render/nodecontext/intf_render_node_context_manager.h>
34 #include <render/nodecontext/intf_render_node_util.h>
35 #include <render/property/property_types.h>
36 
37 #include "datastore/render_data_store_pod.h"
38 #include "datastore/render_data_store_post_process.h"
39 #include "default_engine_constants.h"
40 #include "device/gpu_resource_handle_util.h"
41 #include "render_post_process_motion_blur.h"
42 #include "util/log.h"
43 
44 // shaders
45 #include <render/shaders/common/render_post_process_structs_common.h>
46 
47 using namespace BASE_NS;
48 using namespace CORE_NS;
49 using namespace RENDER_NS;
50 
51 CORE_BEGIN_NAMESPACE()
52 DATA_TYPE_METADATA(RenderPostProcessMotionBlurNode::NodeInputs, MEMBER_PROPERTY(input, "input", 0),
53     MEMBER_PROPERTY(velocity, "velocity", 0), MEMBER_PROPERTY(depth, "depth", 0))
54 DATA_TYPE_METADATA(RenderPostProcessMotionBlurNode::NodeOutputs, MEMBER_PROPERTY(output, "output", 0))
55 CORE_END_NAMESPACE()
56 
57 RENDER_BEGIN_NAMESPACE()
58 namespace {
59 constexpr uint32_t CORE_SPREAD_TYPE_NEIGHBORHOOD { 0U };
60 constexpr uint32_t CORE_SPREAD_TYPE_HORIZONTAL { 1U };
61 constexpr uint32_t CORE_SPREAD_TYPE_VERTICAL { 2U };
62 constexpr uint32_t VELOCITY_TILE_SIZE { 8U };
63 
64 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
65 
66 constexpr uint32_t MAX_PASS_COUNT { 3u };
67 
68 constexpr int32_t BUFFER_SIZE_IN_BYTES = sizeof(BASE_NS::Math::Vec4);
69 constexpr GpuBufferDesc BUFFER_DESC { CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
70     (CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT),
71     CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER, 0U };
72 
CreateGpuBuffers(IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandleReference & handle)73 RenderHandleReference CreateGpuBuffers(
74     IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandleReference& handle)
75 {
76     // Create buffer for the shader data.
77     GpuBufferDesc desc = BUFFER_DESC;
78     desc.byteSize = BUFFER_SIZE_IN_BYTES;
79     return gpuResourceMgr.Create(handle, desc);
80 }
81 
UpdateBuffer(IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandle & handle,const BASE_NS::Math::Vec4 & shaderParameters)82 void UpdateBuffer(IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandle& handle,
83     const BASE_NS::Math::Vec4& shaderParameters)
84 {
85     if (void* data = gpuResourceMgr.MapBuffer(handle); data) {
86         CloneData(data, sizeof(BASE_NS::Math::Vec4), &shaderParameters, sizeof(BASE_NS::Math::Vec4));
87         gpuResourceMgr.UnmapBuffer(handle);
88     }
89 }
90 } // namespace
91 
RenderPostProcessMotionBlurNode()92 RenderPostProcessMotionBlurNode::RenderPostProcessMotionBlurNode()
93     : inputProperties_(
94           &nodeInputsData, array_view(PropertyType::DataType<RenderPostProcessMotionBlurNode::NodeInputs>::properties)),
95       outputProperties_(&nodeOutputsData,
96           array_view(PropertyType::DataType<RenderPostProcessMotionBlurNode::NodeOutputs>::properties))
97 
98 {}
99 
GetRenderInputProperties()100 IPropertyHandle* RenderPostProcessMotionBlurNode::GetRenderInputProperties()
101 {
102     return inputProperties_.GetData();
103 }
104 
GetRenderOutputProperties()105 IPropertyHandle* RenderPostProcessMotionBlurNode::GetRenderOutputProperties()
106 {
107     return outputProperties_.GetData();
108 }
109 
SetRenderAreaRequest(const RenderAreaRequest & renderAreaRequest)110 void RenderPostProcessMotionBlurNode::SetRenderAreaRequest(const RenderAreaRequest& renderAreaRequest)
111 {
112     useRequestedRenderArea_ = true;
113     renderAreaRequest_ = renderAreaRequest;
114 }
115 
GetExecuteFlags() const116 IRenderNode::ExecuteFlags RenderPostProcessMotionBlurNode::GetExecuteFlags() const
117 {
118     if (effectProperties_.enabled) {
119         return 0;
120     } else {
121         return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
122     }
123 }
124 
Init(const IRenderPostProcess::Ptr & postProcess,IRenderNodeContextManager & renderNodeContextMgr)125 void RenderPostProcessMotionBlurNode::Init(
126     const IRenderPostProcess::Ptr& postProcess, IRenderNodeContextManager& renderNodeContextMgr)
127 {
128     renderNodeContextMgr_ = &renderNodeContextMgr;
129     postProcess_ = postProcess;
130 
131     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr.GetShaderManager();
132     {
133         renderData_ = {};
134         renderData_.shader = shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur.shader");
135         renderData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderData_.shader);
136         const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderData_.shader);
137         renderData_.pso = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
138             renderData_.pipelineLayout, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
139     }
140     {
141         renderTileMaxData_ = {};
142         renderTileMaxData_.shader =
143             shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur_tile_max.shader");
144         renderTileMaxData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderTileMaxData_.shader);
145         const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderTileMaxData_.shader);
146         renderTileMaxData_.pso = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderTileMaxData_.shader,
147             graphicsState, renderTileMaxData_.pipelineLayout, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
148     }
149     {
150         renderTileNeighborData_ = {};
151         renderTileNeighborData_.shader =
152             shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_motion_blur_tile_neighborhood.shader");
153         renderTileNeighborData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderTileNeighborData_.shader);
154         const RenderHandle graphicsState =
155             shaderMgr.GetGraphicsStateHandleByShaderHandle(renderTileNeighborData_.shader);
156         const ShaderSpecializationConstantView specView =
157             shaderMgr.GetReflectionSpecialization(renderTileNeighborData_.shader);
158         {
159             const uint32_t specFlags[] = { CORE_SPREAD_TYPE_NEIGHBORHOOD };
160             const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
161             renderTileNeighborData_.psoNeighborhood = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
162                 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
163                 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
164         }
165         {
166             const uint32_t specFlags[] = { CORE_SPREAD_TYPE_HORIZONTAL };
167             const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
168             renderTileNeighborData_.psoHorizontal = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
169                 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
170                 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
171         }
172         {
173             const uint32_t specFlags[] = { CORE_SPREAD_TYPE_VERTICAL };
174             const ShaderSpecializationConstantDataView specDataView { specView.constants, specFlags };
175             renderTileNeighborData_.psoVertical = renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(
176                 renderTileNeighborData_.shader, graphicsState, renderTileNeighborData_.pipelineLayout, {}, specDataView,
177                 { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
178         }
179     }
180 
181     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
182     samplerHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
183         DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
184     samplerNearestHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
185         DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_NEAREST_CLAMP);
186     gpuBuffer_ = CreateGpuBuffers(gpuResourceMgr, gpuBuffer_);
187 
188     valid_ = true;
189 }
190 
PreExecute()191 void RenderPostProcessMotionBlurNode::PreExecute()
192 {
193     if (valid_ && postProcess_) {
194         const array_view<const uint8_t> propertyView = postProcess_->GetData();
195         // this node is directly dependant
196         PLUGIN_ASSERT(propertyView.size_bytes() == sizeof(RenderPostProcessMotionBlurNode::EffectProperties));
197         if (propertyView.size_bytes() == sizeof(RenderPostProcessMotionBlurNode::EffectProperties)) {
198             effectProperties_ = (const RenderPostProcessMotionBlurNode::EffectProperties&)(*propertyView.data());
199             if ((effectProperties_.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::MEDIUM) ||
200                 (effectProperties_.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::HIGH)) {
201                 const uint32_t compSizeX = (effectProperties_.size.x + VELOCITY_TILE_SIZE - 1U) / VELOCITY_TILE_SIZE;
202                 const uint32_t compSizeY = (effectProperties_.size.y + VELOCITY_TILE_SIZE - 1U) / VELOCITY_TILE_SIZE;
203                 if ((!tileVelocityImages_[0U]) || (tileImageSize_.x != compSizeX) || (tileImageSize_.y != compSizeY)) {
204                     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
205                     GpuImageDesc desc = renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(
206                         nodeInputsData.velocity.handle);
207                     desc.engineCreationFlags = CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
208                                                CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS;
209                     desc.usageFlags = CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
210                     desc.mipCount = 1U;
211                     desc.layerCount = 1U;
212                     desc.width = compSizeX;
213                     desc.height = compSizeY;
214                     tileVelocityImages_[0U] = gpuResourceMgr.Create(tileVelocityImages_[0U], desc);
215                     tileVelocityImages_[1U] = gpuResourceMgr.Create(tileVelocityImages_[1U], desc);
216 
217                     tileImageSize_ = { compSizeX, compSizeY };
218                 }
219             }
220         }
221     } else {
222         effectProperties_.enabled = false;
223     }
224 }
225 
Execute(IRenderCommandList & cmdList)226 void RenderPostProcessMotionBlurNode::Execute(IRenderCommandList& cmdList)
227 {
228     if (!RenderHandleUtil::IsGpuImage(nodeOutputsData.output.handle)) {
229         return;
230     }
231 
232     CheckDescriptorSetNeed();
233 
234     RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderMotionBlur", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
235 
236     const RenderHandle velocity = nodeInputsData.velocity.handle;
237     RenderHandle tileVelocity = nodeInputsData.velocity.handle;
238     if ((effectProperties_.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::MEDIUM) ||
239         (effectProperties_.motionBlurConfiguration.quality == MotionBlurConfiguration::Quality::HIGH)) {
240         ExecuteTileVelocity(cmdList);
241         const RenderHandle tv = GetTileVelocityForMotionBlur();
242         tileVelocity = RenderHandleUtil::IsValid(tv) ? tv : velocity;
243     }
244 
245     const auto& renderData = renderData_;
246 
247     RenderPass renderPass;
248     renderPass.renderPassDesc.attachmentCount = 1;
249     renderPass.renderPassDesc.renderArea = { 0, 0, effectProperties_.size.x, effectProperties_.size.y };
250     renderPass.renderPassDesc.subpassCount = 1;
251     renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
252     renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
253     renderPass.renderPassDesc.attachmentHandles[0] = nodeOutputsData.output.handle;
254     renderPass.subpassStartIndex = 0;
255     auto& subpass = renderPass.subpassDesc;
256     subpass.colorAttachmentCount = 1;
257     subpass.colorAttachmentIndices[0] = 0;
258 
259     cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
260     cmdList.BindPipeline(renderData.pso);
261 
262     shaderParameters_ = GetFactorMotionBlur();
263     UpdateBuffer(renderNodeContextMgr_->GetGpuResourceManager(), gpuBuffer_.GetHandle(), shaderParameters_);
264 
265     {
266         auto& binder = *binders_.localSet0;
267         binder.ClearBindings();
268         uint32_t binding = 0u;
269         binder.BindImage(binding++, nodeInputsData.input.handle, samplerHandle_);
270         binder.BindImage(binding++, nodeInputsData.depth.handle, samplerNearestHandle_);
271         binder.BindImage(binding++, velocity, samplerHandle_);
272         binder.BindImage(binding++, tileVelocity, samplerHandle_);
273         binder.BindBuffer(binding++, gpuBuffer_.GetHandle(), 0u);
274 
275         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
276         cmdList.BindDescriptorSet(0u, binder.GetDescriptorSetHandle());
277     }
278 
279     if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
280         const auto fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
281         const auto fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
282         const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
283         cmdList.PushConstantData(renderData_.pipelineLayout.pushConstant, arrayviewU8(pc));
284     }
285 
286     // dynamic state
287     cmdList.SetDynamicStateViewport(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass));
288     cmdList.SetDynamicStateScissor(renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass));
289 
290     cmdList.Draw(3u, 1u, 0u, 0u);
291     cmdList.EndRenderPass();
292 }
293 
ExecuteTileVelocity(IRenderCommandList & cmdList)294 void RenderPostProcessMotionBlurNode::ExecuteTileVelocity(IRenderCommandList& cmdList)
295 {
296     if ((!RenderHandleUtil::IsGpuImage(nodeOutputsData.output.handle)) || (!tileVelocityImages_[0U])) {
297         return;
298     }
299 
300     RenderPass renderPass;
301     renderPass.renderPassDesc.attachmentCount = 1;
302     renderPass.renderPassDesc.renderArea = { 0, 0, tileImageSize_.x, tileImageSize_.y };
303     renderPass.renderPassDesc.subpassCount = 1;
304     renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
305     renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
306     renderPass.subpassStartIndex = 0;
307     auto& subpass = renderPass.subpassDesc;
308     subpass.colorAttachmentCount = 1;
309     subpass.colorAttachmentIndices[0] = 0;
310 
311     const RenderHandle vel0 = tileVelocityImages_[0U].GetHandle();
312     const RenderHandle vel1 = tileVelocityImages_[1U].GetHandle();
313 
314     const ViewportDesc viewport = renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultViewport(renderPass);
315     const ScissorDesc scissor = renderNodeContextMgr_->GetRenderNodeUtil().CreateDefaultScissor(renderPass);
316 
317     const auto fWidth = static_cast<float>(renderPass.renderPassDesc.renderArea.extentWidth);
318     const auto fHeight = static_cast<float>(renderPass.renderPassDesc.renderArea.extentHeight);
319     const LocalPostProcessPushConstantStruct pc { { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight }, {} };
320 
321     // tile max pass
322     {
323         const auto& renderData = renderTileMaxData_;
324         renderPass.renderPassDesc.attachmentHandles[0] = vel0;
325 
326         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
327         cmdList.BindPipeline(renderData.pso);
328 
329         {
330             auto& binder = *binders_.localTileMaxSet0;
331             binder.ClearBindings();
332             binder.BindImage(0U, nodeInputsData.velocity.handle, samplerHandle_);
333             cmdList.UpdateDescriptorSet(
334                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
335             cmdList.BindDescriptorSet(0u, binder.GetDescriptorSetHandle());
336         }
337 
338         if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
339             cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
340         }
341 
342         // dynamic state
343         cmdList.SetDynamicStateViewport(viewport);
344         cmdList.SetDynamicStateScissor(scissor);
345 
346         cmdList.Draw(3U, 1U, 0U, 0U);
347         cmdList.EndRenderPass();
348     }
349     // tile neighborhood pass
350     {
351         const auto& renderData = renderTileNeighborData_;
352         {
353             const RenderHandle pso =
354                 renderTileNeighborData_.doublePass ? renderData.psoHorizontal : renderData.psoNeighborhood;
355 
356             renderPass.renderPassDesc.attachmentHandles[0] = vel1;
357 
358             cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
359             cmdList.BindPipeline(pso);
360 
361             {
362                 auto& binder = *binders_.localTileNeighborhoodSet0[0U];
363                 binder.ClearBindings();
364                 binder.BindImage(0U, vel0, samplerHandle_);
365                 cmdList.UpdateDescriptorSet(
366                     binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
367                 cmdList.BindDescriptorSet(0u, binder.GetDescriptorSetHandle());
368             }
369 
370             if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
371                 cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
372             }
373 
374             // dynamic state
375             cmdList.SetDynamicStateViewport(viewport);
376             cmdList.SetDynamicStateScissor(scissor);
377 
378             cmdList.Draw(3U, 1U, 0U, 0U);
379             cmdList.EndRenderPass();
380         }
381         if (renderTileNeighborData_.doublePass) {
382             const RenderHandle pso = renderData.psoVertical;
383 
384             renderPass.renderPassDesc.attachmentHandles[0] = vel0;
385 
386             cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
387             cmdList.BindPipeline(pso);
388 
389             {
390                 auto& binder = *binders_.localTileNeighborhoodSet0[1U];
391                 binder.ClearBindings();
392                 binder.BindImage(0U, vel1, samplerHandle_);
393                 cmdList.UpdateDescriptorSet(
394                     binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
395                 cmdList.BindDescriptorSet(0u, binder.GetDescriptorSetHandle());
396             }
397 
398             if (renderData.pipelineLayout.pushConstant.byteSize > 0) {
399                 cmdList.PushConstant(renderData.pipelineLayout.pushConstant, arrayviewU8(pc).data());
400             }
401 
402             // dynamic state
403             cmdList.SetDynamicStateViewport(viewport);
404             cmdList.SetDynamicStateScissor(scissor);
405 
406             cmdList.Draw(3U, 1U, 0U, 0U);
407             cmdList.EndRenderPass();
408         }
409     }
410 }
411 
GetFactorMotionBlur() const412 BASE_NS::Math::Vec4 RenderPostProcessMotionBlurNode::GetFactorMotionBlur() const
413 {
414     return {
415         static_cast<float>(effectProperties_.motionBlurConfiguration.sharpness),
416         static_cast<float>(effectProperties_.motionBlurConfiguration.quality),
417         effectProperties_.motionBlurConfiguration.alpha,
418         effectProperties_.motionBlurConfiguration.velocityCoefficient,
419     };
420 }
421 
GetTileVelocityForMotionBlur() const422 RenderHandle RenderPostProcessMotionBlurNode::GetTileVelocityForMotionBlur() const
423 {
424     return renderTileNeighborData_.doublePass ? tileVelocityImages_[0U].GetHandle()
425                                               : tileVelocityImages_[1U].GetHandle();
426 }
427 
GetRenderDescriptorCounts() const428 DescriptorCounts RenderPostProcessMotionBlurNode::GetRenderDescriptorCounts() const
429 {
430     // expected high max mip count
431     return DescriptorCounts { {
432         { CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_PASS_COUNT },
433         { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u * MAX_PASS_COUNT },
434     } };
435 }
436 
CheckDescriptorSetNeed()437 void RenderPostProcessMotionBlurNode::CheckDescriptorSetNeed()
438 {
439     if (!binders_.localSet0) {
440         constexpr uint32_t localSet = 0u;
441         INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
442         {
443             const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
444             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
445             binders_.localSet0 = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
446         }
447         {
448             const auto& bindings = renderTileMaxData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
449             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
450             binders_.localTileMaxSet0 = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
451         }
452         {
453             const auto& bindings = renderTileNeighborData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
454             {
455                 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
456                 binders_.localTileNeighborhoodSet0[0U] =
457                     descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
458             }
459             {
460                 const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
461                 binders_.localTileNeighborhoodSet0[1U] =
462                     descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
463             }
464         }
465     }
466 }
467 
468 RENDER_END_NAMESPACE()
469