• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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 
30 #include "default_engine_constants.h"
31 #include "device/gpu_resource_handle_util.h"
32 #include "render/shaders/common/render_post_process_structs_common.h"
33 
34 using namespace BASE_NS;
35 
36 RENDER_BEGIN_NAMESPACE()
37 namespace {
38 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
39 
40 constexpr uint32_t MAX_MIP_COUNT { 16u };
41 constexpr uint32_t MAX_PASS_PER_LEVEL_COUNT { 3u };
42 constexpr bool GAUSSIAN_TYPE { true };
43 } // namespace
44 
Init(IRenderNodeContextManager & renderNodeContextMgr,const BlurInfo & blurInfo)45 void RenderBlur::Init(IRenderNodeContextManager& renderNodeContextMgr, const BlurInfo& blurInfo)
46 {
47     blurInfo_ = blurInfo;
48     {
49         const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr.GetShaderManager();
50         renderData_ = {};
51         renderData_.shader = shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_blur.shader");
52         renderData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderData_.shader);
53     }
54     {
55         imageData_ = {};
56         imageData_.mipImage = blurInfo.blurTarget.handle;
57         samplerHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
58             DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
59     }
60     {
61         constexpr uint32_t globalSet = 0u;
62         constexpr uint32_t localSet = 1u;
63 
64         constexpr uint32_t maxBinderCount = MAX_MIP_COUNT * MAX_PASS_PER_LEVEL_COUNT;
65         binders_.clear();
66         binders_.resize(maxBinderCount);
67 
68         INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
69         {
70             const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[globalSet].bindings;
71             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
72             globalSet0_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
73         }
74         const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
75         for (uint32_t idx = 0; idx < maxBinderCount; ++idx) {
76             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
77             binders_[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
78         }
79     }
80 }
81 
PreExecute(IRenderNodeContextManager & renderNodeContextMgr,const BlurInfo & blurInfo)82 void RenderBlur::PreExecute(IRenderNodeContextManager& renderNodeContextMgr, const BlurInfo& blurInfo)
83 {
84     blurInfo_ = blurInfo;
85     imageData_.mipImage = blurInfo.blurTarget.handle;
86     globalUbo_ = blurInfo.globalUbo;
87 
88     const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
89     const GpuImageDesc imageDesc = gpuResourceMgr.GetImageDescriptor(imageData_.mipImage);
90     imageData_.mipCount = Math::min(imageDesc.mipCount, MAX_MIP_COUNT);
91     imageData_.format = imageDesc.format;
92     imageData_.size = { imageDesc.width, imageDesc.height };
93     if constexpr (GAUSSIAN_TYPE) {
94         CreateTargets(renderNodeContextMgr, imageData_.size);
95     }
96 }
97 
Execute(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList,const PostProcessConfiguration & ppConfig)98 void RenderBlur::Execute(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
99     const PostProcessConfiguration& ppConfig)
100 {
101     if (!RenderHandleUtil::IsGpuImage(imageData_.mipImage)) {
102         return;
103     }
104 
105     RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderBlur", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
106 
107     UpdateGlobalSet(cmdList);
108 
109     RenderPass renderPass;
110     renderPass.renderPassDesc.attachmentCount = 1;
111     renderPass.renderPassDesc.renderArea = { 0, 0, imageData_.size.x, imageData_.size.y };
112     renderPass.renderPassDesc.subpassCount = 1;
113     renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
114     renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
115     renderPass.renderPassDesc.attachmentHandles[0] = imageData_.mipImage;
116     renderPass.subpassStartIndex = 0;
117     auto& subpass = renderPass.subpassDesc;
118     subpass.colorAttachmentCount = 1;
119     subpass.colorAttachmentIndices[0] = 0;
120 
121     if (!RenderHandleUtil::IsValid(renderData_.psoScale)) {
122         const auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
123         const ShaderSpecializationConstantView sscv = shaderMgr.GetReflectionSpecialization(renderData_.shader);
124         const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderData_.shader);
125         {
126             const uint32_t specializationFlags[] = { blurInfo_.scaleType };
127             const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
128             renderData_.psoScale =
129                 renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
130                     renderData_.pipelineLayout, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
131         }
132         {
133             const uint32_t specializationFlags[] = { blurInfo_.blurType };
134             const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
135             renderData_.psoBlur =
136                 renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
137                     renderData_.pipelineLayout, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
138         }
139     }
140 
141     if constexpr (GAUSSIAN_TYPE) {
142         RenderGaussian(cmdList, renderPass, ppConfig);
143     } else {
144         RenderData(renderNodeContextMgr, cmdList, renderPass, ppConfig);
145     }
146 }
147 
UpdateGlobalSet(IRenderCommandList & cmdList)148 void RenderBlur::UpdateGlobalSet(IRenderCommandList& cmdList)
149 {
150     auto& binder = *globalSet0_;
151     binder.ClearBindings();
152     uint32_t binding = 0u;
153     binder.BindBuffer(binding++, globalUbo_, 0);
154     binder.BindBuffer(binding++, globalUbo_, sizeof(GlobalPostProcessStruct));
155     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
156 }
157 
GetDescriptorCounts()158 DescriptorCounts RenderBlur::GetDescriptorCounts()
159 {
160     // expected high max mip count
161     return DescriptorCounts { {
162         { CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MAX_MIP_COUNT },
163         { CORE_DESCRIPTOR_TYPE_SAMPLER, MAX_MIP_COUNT },
164         { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u * MAX_MIP_COUNT },
165     } };
166 }
167 
168 // constants for RenderBlur::RenderData
169 namespace {
170 constexpr bool USE_CUSTOM_BARRIERS = true;
171 
172 constexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
173 constexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
174     CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
175 constexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
176     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
177 // transition the final mip level to read only as well
178 constexpr ImageResourceBarrier FINAL_SRC { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
179     CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
180     CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
181 constexpr ImageResourceBarrier FINAL_DST { CORE_ACCESS_SHADER_READ_BIT,
182     CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // first possible shader read stage
183     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
184 } // namespace
185 
RenderData(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList,const RenderPass & renderPassBase,const PostProcessConfiguration & ppConfig)186 void RenderBlur::RenderData(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
187     const RenderPass& renderPassBase, const PostProcessConfiguration& ppConfig)
188 {
189     RenderPass renderPass = renderPassBase;
190     const GpuImageDesc imageDesc = renderNodeContextMgr.GetGpuResourceManager().GetImageDescriptor(imageData_.mipImage);
191 
192     if constexpr (USE_CUSTOM_BARRIERS) {
193         cmdList.BeginDisableAutomaticBarrierPoints();
194     }
195 
196     RenderHandle sets[2u] {};
197     sets[0] = globalSet0_->GetDescriptorSetHandle();
198 
199     const uint32_t blurCount = Math::min(ppConfig.blurConfiguration.maxMipLevel, imageData_.mipCount);
200     // NOTE: for smoother results, first downscale -> then horiz / vert -> downscale and so on
201     ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
202         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
203     for (uint32_t idx = 1; idx < blurCount; ++idx) {
204         const uint32_t renderPassMipLevel = blurInfo_.upScale ? (blurCount - idx - 1) : idx;
205         const uint32_t inputMipLevel = blurInfo_.upScale ? (blurCount - idx) : (idx - 1);
206 
207         const uint32_t currWidth = Math::max(1u, imageDesc.width >> renderPassMipLevel);
208         const uint32_t currHeight = Math::max(1u, imageDesc.height >> renderPassMipLevel);
209         const auto fCurrWidth = static_cast<float>(currWidth);
210         const auto fCurrHeight = static_cast<float>(currHeight);
211 
212         renderPass.renderPassDesc.renderArea = { 0, 0, currWidth, currHeight };
213         renderPass.renderPassDesc.attachments[0].mipLevel = renderPassMipLevel;
214 
215         if constexpr (USE_CUSTOM_BARRIERS) {
216             imageSubresourceRange.baseMipLevel = renderPassMipLevel;
217             cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, COL_ATTACHMENT, imageSubresourceRange);
218             imageSubresourceRange.baseMipLevel = inputMipLevel;
219             if (inputMipLevel == 0) {
220                 cmdList.CustomImageBarrier(imageData_.mipImage, SHDR_READ, imageSubresourceRange);
221             } else {
222                 cmdList.CustomImageBarrier(imageData_.mipImage, COL_ATTACHMENT, SHDR_READ, imageSubresourceRange);
223             }
224             cmdList.AddCustomBarrierPoint();
225         }
226 
227         cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
228 
229         cmdList.SetDynamicStateViewport(ViewportDesc { 0.0f, 0.0f, fCurrWidth, fCurrHeight, 0.0f, 0.0f });
230         cmdList.SetDynamicStateScissor(ScissorDesc { 0, 0, currWidth, currHeight });
231 
232         cmdList.BindPipeline(renderData_.psoScale);
233 
234         {
235             auto& binder = *binders_[idx];
236             sets[1u] = binder.GetDescriptorSetHandle();
237             binder.ClearBindings();
238             binder.BindSampler(0, samplerHandle_);
239             binder.BindImage(1, { imageData_.mipImage, inputMipLevel });
240             cmdList.UpdateDescriptorSet(
241                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
242         }
243         cmdList.BindDescriptorSets(0u, sets);
244 
245         const LocalPostProcessPushConstantStruct pc {
246             { fCurrWidth, fCurrHeight, 1.0f / (fCurrWidth), 1.0f / (fCurrHeight) }, { 1.0f, 0.0f, 0.0f, 0.0f }
247         };
248         cmdList.PushConstant(renderData_.pipelineLayout.pushConstant, reinterpret_cast<const uint8_t*>(&pc));
249 
250         cmdList.Draw(3u, 1u, 0u, 0u);
251         cmdList.EndRenderPass();
252     }
253 
254     if constexpr (USE_CUSTOM_BARRIERS) {
255         if (imageData_.mipCount > 1u) {
256             // transition the final used mip level
257             if (blurCount > 0) {
258                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount - 1, 1, 0,
259                     PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
260                 cmdList.CustomImageBarrier(imageData_.mipImage, FINAL_SRC, FINAL_DST, imgRange);
261             }
262             if (blurCount < imageData_.mipCount) {
263                 // transition the final levels which might be in undefined state
264                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount,
265                     imageData_.mipCount - blurCount, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
266                 cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, FINAL_DST, imgRange);
267             }
268         }
269         cmdList.AddCustomBarrierPoint();
270         cmdList.EndDisableAutomaticBarrierPoints();
271     }
272 }
273 
274 namespace {
DownscaleBarrier(IRenderCommandList & cmdList,const RenderHandle image,const uint32_t mipLevel)275 void DownscaleBarrier(IRenderCommandList& cmdList, const RenderHandle image, const uint32_t mipLevel)
276 {
277     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
278         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
279     imgRange.baseMipLevel = mipLevel;
280     cmdList.CustomImageBarrier(image, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
281     const uint32_t inputMipLevel = mipLevel - 1u;
282     imgRange.baseMipLevel = inputMipLevel;
283     if (inputMipLevel == 0) {
284         cmdList.CustomImageBarrier(image, SHDR_READ, imgRange);
285     } else {
286         cmdList.CustomImageBarrier(image, COL_ATTACHMENT, SHDR_READ, imgRange);
287     }
288     cmdList.AddCustomBarrierPoint();
289 }
290 
BlurHorizontalBarrier(IRenderCommandList & cmdList,const RenderHandle realImage,const uint32_t mipLevel,const RenderHandle tmpImage)291 void BlurHorizontalBarrier(
292     IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
293 {
294     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
295         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
296     imgRange.baseMipLevel = mipLevel;
297     cmdList.CustomImageBarrier(realImage, COL_ATTACHMENT, SHDR_READ, imgRange);
298     imgRange.baseMipLevel = mipLevel - 1;
299     cmdList.CustomImageBarrier(tmpImage, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
300     cmdList.AddCustomBarrierPoint();
301 }
302 
BlurVerticalBarrier(IRenderCommandList & cmdList,const RenderHandle realImage,const uint32_t mipLevel,const RenderHandle tmpImage)303 void BlurVerticalBarrier(
304     IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
305 {
306     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
307         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
308     imgRange.baseMipLevel = mipLevel;
309     cmdList.CustomImageBarrier(realImage, SHDR_READ, COL_ATTACHMENT, imgRange);
310     imgRange.baseMipLevel = mipLevel - 1;
311     cmdList.CustomImageBarrier(tmpImage, COL_ATTACHMENT, SHDR_READ, imgRange);
312     cmdList.AddCustomBarrierPoint();
313 }
314 
315 struct ConstDrawInput {
316     IRenderCommandList& cmdList;
317     const RenderPass& renderPass;
318     const PushConstant& pushConstant;
319     const LocalPostProcessPushConstantStruct& pc;
320     RenderHandle sampler;
321 };
BlurPass(const ConstDrawInput & di,IDescriptorSetBinder & binder,IDescriptorSetBinder & globalBinder,const RenderHandle psoHandle,const RenderHandle image,const uint32_t inputMipLevel)322 void BlurPass(const ConstDrawInput& di, IDescriptorSetBinder& binder, IDescriptorSetBinder& globalBinder,
323     const RenderHandle psoHandle, const RenderHandle image, const uint32_t inputMipLevel)
324 {
325     di.cmdList.BeginRenderPass(
326         di.renderPass.renderPassDesc, di.renderPass.subpassStartIndex, di.renderPass.subpassDesc);
327     di.cmdList.BindPipeline(psoHandle);
328 
329     RenderHandle sets[2u] {};
330     sets[0] = globalBinder.GetDescriptorSetHandle();
331     {
332         binder.ClearBindings();
333         sets[1u] = binder.GetDescriptorSetHandle();
334         binder.BindSampler(0, di.sampler);
335         binder.BindImage(1u, { image, inputMipLevel });
336         di.cmdList.UpdateDescriptorSet(
337             binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
338     }
339     di.cmdList.BindDescriptorSets(0, sets);
340 
341     di.cmdList.PushConstant(di.pushConstant, reinterpret_cast<const uint8_t*>(&di.pc));
342     di.cmdList.Draw(3u, 1u, 0u, 0u);
343     di.cmdList.EndRenderPass();
344 }
345 } // namespace
346 
RenderGaussian(IRenderCommandList & cmdList,const RenderPass & renderPassBase,const PostProcessConfiguration & ppConfig)347 void RenderBlur::RenderGaussian(
348     IRenderCommandList& cmdList, const RenderPass& renderPassBase, const PostProcessConfiguration& ppConfig)
349 {
350     RenderPass renderPass = renderPassBase;
351     if constexpr (USE_CUSTOM_BARRIERS) {
352         cmdList.BeginDisableAutomaticBarrierPoints();
353     }
354 
355     // with every mip, first we do a downscale
356     // then a single horizontal and a single vertical blur
357     LocalPostProcessPushConstantStruct pc { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } };
358     uint32_t descIdx = 0;
359     const uint32_t blurCount = Math::min(ppConfig.blurConfiguration.maxMipLevel, imageData_.mipCount);
360     const ConstDrawInput di { cmdList, renderPass, renderData_.pipelineLayout.pushConstant, pc, samplerHandle_ };
361     for (uint32_t idx = 1; idx < blurCount; ++idx) {
362         const uint32_t mip = idx;
363 
364         const Math::UVec2 size = { Math::max(1u, imageData_.size.x >> mip), Math::max(1u, imageData_.size.y >> mip) };
365         const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
366         const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
367         pc = { texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f } };
368 
369         renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
370         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
371 
372         cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
373         cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
374 
375         // downscale
376         if constexpr (USE_CUSTOM_BARRIERS) {
377             DownscaleBarrier(cmdList, imageData_.mipImage, mip);
378         }
379         BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoScale, imageData_.mipImage, mip - 1u);
380 
381         // horizontal (from real image to temp)
382         if constexpr (USE_CUSTOM_BARRIERS) {
383             BlurHorizontalBarrier(cmdList, imageData_.mipImage, mip, tempTarget_.tex.GetHandle());
384         }
385 
386         renderPass.renderPassDesc.attachmentHandles[0] = tempTarget_.tex.GetHandle();
387         renderPass.renderPassDesc.attachments[0].mipLevel = mip - 1u;
388         BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoBlur, imageData_.mipImage, mip);
389 
390         // vertical
391         if constexpr (USE_CUSTOM_BARRIERS) {
392             BlurVerticalBarrier(cmdList, imageData_.mipImage, mip, tempTarget_.tex.GetHandle());
393         }
394 
395         renderPass.renderPassDesc.attachmentHandles[0] = imageData_.mipImage;
396         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
397         pc.factor = { 0.0f, 1.0f, 0.0f, 0.0f };
398         BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoBlur, tempTarget_.tex.GetHandle(), mip - 1);
399     }
400 
401     if constexpr (USE_CUSTOM_BARRIERS) {
402         if (imageData_.mipCount > 1u) {
403             // transition the final used mip level
404             if (blurCount > 0) {
405                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount - 1, 1, 0,
406                     PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
407                 cmdList.CustomImageBarrier(imageData_.mipImage, FINAL_SRC, FINAL_DST, imgRange);
408             }
409             if (blurCount < imageData_.mipCount) {
410                 // transition the final levels which might be in undefined state
411                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount,
412                     imageData_.mipCount - blurCount, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
413                 cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, FINAL_DST, imgRange);
414             }
415         }
416         cmdList.AddCustomBarrierPoint();
417         cmdList.EndDisableAutomaticBarrierPoints();
418     }
419 }
420 
CreateTargets(IRenderNodeContextManager & renderNodeContextMgr,const Math::UVec2 baseSize)421 void RenderBlur::CreateTargets(IRenderNodeContextManager& renderNodeContextMgr, const Math::UVec2 baseSize)
422 {
423     Math::UVec2 texSize = baseSize / 2u;
424     texSize.x = Math::max(1u, texSize.x);
425     texSize.y = Math::max(1u, texSize.y);
426     if (texSize.x != tempTarget_.texSize.x || texSize.y != tempTarget_.texSize.y) {
427         tempTarget_.texSize = texSize;
428         tempTarget_.format = imageData_.format;
429 
430         constexpr ImageUsageFlags usageFlags = ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
431                                                ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT |
432                                                ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
433 
434         const GpuImageDesc desc {
435             ImageType::CORE_IMAGE_TYPE_2D,
436             ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
437             tempTarget_.format,
438             ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
439             usageFlags,
440             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
441             0,
442             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS,
443             tempTarget_.texSize.x,
444             tempTarget_.texSize.y,
445             1u,
446             Math::max(1u, (imageData_.mipCount - 1u)),
447             1u,
448             SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
449             {},
450         };
451 #if (RENDER_VALIDATION_ENABLED == 1)
452         tempTarget_.tex =
453             renderNodeContextMgr.GetGpuResourceManager().Create(renderNodeContextMgr.GetName() + "_BLUR_TARGET", desc);
454 #else
455         tempTarget_.tex = renderNodeContextMgr.GetGpuResourceManager().Create(tempTarget_.tex, desc);
456 #endif
457     }
458 }
459 RENDER_END_NAMESPACE()
460