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