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