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