18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "render_blur.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h>
198bf80f4bSopenharmony_ci#include <render/device/intf_shader_manager.h>
208bf80f4bSopenharmony_ci#include <render/device/pipeline_layout_desc.h>
218bf80f4bSopenharmony_ci#include <render/device/pipeline_state_desc.h>
228bf80f4bSopenharmony_ci#include <render/namespace.h>
238bf80f4bSopenharmony_ci#include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
248bf80f4bSopenharmony_ci#include <render/nodecontext/intf_node_context_pso_manager.h>
258bf80f4bSopenharmony_ci#include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
268bf80f4bSopenharmony_ci#include <render/nodecontext/intf_render_command_list.h>
278bf80f4bSopenharmony_ci#include <render/nodecontext/intf_render_node_context_manager.h>
288bf80f4bSopenharmony_ci#include <render/nodecontext/intf_render_node_util.h>
298bf80f4bSopenharmony_ci#include <render/shaders/common/render_blur_common.h>
308bf80f4bSopenharmony_ci
318bf80f4bSopenharmony_ci#include "default_engine_constants.h"
328bf80f4bSopenharmony_ci#include "device/gpu_resource_handle_util.h"
338bf80f4bSopenharmony_ci#include "render/shaders/common/render_post_process_structs_common.h"
348bf80f4bSopenharmony_ci#include "util/log.h"
358bf80f4bSopenharmony_ci
368bf80f4bSopenharmony_ciusing namespace BASE_NS;
378bf80f4bSopenharmony_ci
388bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE()
398bf80f4bSopenharmony_cinamespace {
408bf80f4bSopenharmony_ciconstexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
418bf80f4bSopenharmony_ci
428bf80f4bSopenharmony_ciconstexpr uint32_t MAX_MIP_COUNT { 16u };
438bf80f4bSopenharmony_ciconstexpr uint32_t MAX_PASS_PER_LEVEL_COUNT { 3u };
448bf80f4bSopenharmony_ciconstexpr bool GAUSSIAN_TYPE { true };
458bf80f4bSopenharmony_ci} // namespace
468bf80f4bSopenharmony_ci
478bf80f4bSopenharmony_civoid RenderBlur::Init(IRenderNodeContextManager& renderNodeContextMgr, const BlurInfo& blurInfo)
488bf80f4bSopenharmony_ci{
498bf80f4bSopenharmony_ci    blurInfo_ = blurInfo;
508bf80f4bSopenharmony_ci    {
518bf80f4bSopenharmony_ci        const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr.GetShaderManager();
528bf80f4bSopenharmony_ci        renderData_ = {};
538bf80f4bSopenharmony_ci        renderData_.shader = shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_blur.shader");
548bf80f4bSopenharmony_ci        renderData_.pipelineLayout = shaderMgr.GetReflectionPipelineLayout(renderData_.shader);
558bf80f4bSopenharmony_ci    }
568bf80f4bSopenharmony_ci    {
578bf80f4bSopenharmony_ci        imageData_ = {};
588bf80f4bSopenharmony_ci        imageData_.mipImage = blurInfo.blurTarget.handle;
598bf80f4bSopenharmony_ci        samplerHandle_ = renderNodeContextMgr.GetGpuResourceManager().GetSamplerHandle(
608bf80f4bSopenharmony_ci            DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
618bf80f4bSopenharmony_ci    }
628bf80f4bSopenharmony_ci    {
638bf80f4bSopenharmony_ci        constexpr uint32_t globalSet = 0u;
648bf80f4bSopenharmony_ci        constexpr uint32_t localSet = 1u;
658bf80f4bSopenharmony_ci
668bf80f4bSopenharmony_ci        constexpr uint32_t maxBinderCount = MAX_MIP_COUNT * MAX_PASS_PER_LEVEL_COUNT;
678bf80f4bSopenharmony_ci        binders_.clear();
688bf80f4bSopenharmony_ci        binders_.resize(maxBinderCount);
698bf80f4bSopenharmony_ci
708bf80f4bSopenharmony_ci        INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
718bf80f4bSopenharmony_ci        {
728bf80f4bSopenharmony_ci            const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[globalSet].bindings;
738bf80f4bSopenharmony_ci            const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
748bf80f4bSopenharmony_ci            globalSet0_ = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
758bf80f4bSopenharmony_ci        }
768bf80f4bSopenharmony_ci        const auto& bindings = renderData_.pipelineLayout.descriptorSetLayouts[localSet].bindings;
778bf80f4bSopenharmony_ci        for (uint32_t idx = 0; idx < maxBinderCount; ++idx) {
788bf80f4bSopenharmony_ci            const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
798bf80f4bSopenharmony_ci            binders_[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
808bf80f4bSopenharmony_ci        }
818bf80f4bSopenharmony_ci    }
828bf80f4bSopenharmony_ci}
838bf80f4bSopenharmony_ci
848bf80f4bSopenharmony_civoid RenderBlur::PreExecute(
858bf80f4bSopenharmony_ci    IRenderNodeContextManager& renderNodeContextMgr, const BlurInfo& blurInfo, const PostProcessConfiguration& ppConfig)
868bf80f4bSopenharmony_ci{
878bf80f4bSopenharmony_ci    blurInfo_ = blurInfo;
888bf80f4bSopenharmony_ci    imageData_.mipImage = blurInfo.blurTarget.handle;
898bf80f4bSopenharmony_ci    globalUbo_ = blurInfo.globalUbo;
908bf80f4bSopenharmony_ci
918bf80f4bSopenharmony_ci    const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
928bf80f4bSopenharmony_ci    const GpuImageDesc imageDesc = gpuResourceMgr.GetImageDescriptor(imageData_.mipImage);
938bf80f4bSopenharmony_ci    imageData_.mipCount = imageDesc.mipCount;
948bf80f4bSopenharmony_ci    imageData_.format = imageDesc.format;
958bf80f4bSopenharmony_ci    imageData_.size = { imageDesc.width, imageDesc.height };
968bf80f4bSopenharmony_ci    if (GAUSSIAN_TYPE) {
978bf80f4bSopenharmony_ci        CreateTargets(renderNodeContextMgr, imageData_.size);
988bf80f4bSopenharmony_ci    }
998bf80f4bSopenharmony_ci}
1008bf80f4bSopenharmony_ci
1018bf80f4bSopenharmony_civoid RenderBlur::Execute(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
1028bf80f4bSopenharmony_ci    const PostProcessConfiguration& ppConfig)
1038bf80f4bSopenharmony_ci{
1048bf80f4bSopenharmony_ci    if (!RenderHandleUtil::IsGpuImage(imageData_.mipImage)) {
1058bf80f4bSopenharmony_ci        return;
1068bf80f4bSopenharmony_ci    }
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci    UpdateGlobalSet(cmdList);
1098bf80f4bSopenharmony_ci
1108bf80f4bSopenharmony_ci    RenderPass renderPass;
1118bf80f4bSopenharmony_ci    renderPass.renderPassDesc.attachmentCount = 1;
1128bf80f4bSopenharmony_ci    renderPass.renderPassDesc.renderArea = { 0, 0, imageData_.size.x, imageData_.size.y };
1138bf80f4bSopenharmony_ci    renderPass.renderPassDesc.subpassCount = 1;
1148bf80f4bSopenharmony_ci    renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
1158bf80f4bSopenharmony_ci    renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
1168bf80f4bSopenharmony_ci    renderPass.renderPassDesc.attachmentHandles[0] = imageData_.mipImage;
1178bf80f4bSopenharmony_ci    renderPass.subpassStartIndex = 0;
1188bf80f4bSopenharmony_ci    auto& subpass = renderPass.subpassDesc;
1198bf80f4bSopenharmony_ci    subpass.colorAttachmentCount = 1;
1208bf80f4bSopenharmony_ci    subpass.colorAttachmentIndices[0] = 0;
1218bf80f4bSopenharmony_ci
1228bf80f4bSopenharmony_ci    if (!RenderHandleUtil::IsValid(renderData_.psoScale)) {
1238bf80f4bSopenharmony_ci        const auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
1248bf80f4bSopenharmony_ci        const ShaderSpecializationConstantView sscv = shaderMgr.GetReflectionSpecialization(renderData_.shader);
1258bf80f4bSopenharmony_ci        const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(renderData_.shader);
1268bf80f4bSopenharmony_ci        {
1278bf80f4bSopenharmony_ci            const uint32_t specializationFlags[] = { blurInfo_.scaleType };
1288bf80f4bSopenharmony_ci            const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
1298bf80f4bSopenharmony_ci            renderData_.psoScale =
1308bf80f4bSopenharmony_ci                renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
1318bf80f4bSopenharmony_ci                    renderData_.pipelineLayout, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
1328bf80f4bSopenharmony_ci        }
1338bf80f4bSopenharmony_ci        {
1348bf80f4bSopenharmony_ci            const uint32_t specializationFlags[] = { blurInfo_.blurType };
1358bf80f4bSopenharmony_ci            const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
1368bf80f4bSopenharmony_ci            renderData_.psoBlur =
1378bf80f4bSopenharmony_ci                renderNodeContextMgr.GetPsoManager().GetGraphicsPsoHandle(renderData_.shader, graphicsState,
1388bf80f4bSopenharmony_ci                    renderData_.pipelineLayout, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
1398bf80f4bSopenharmony_ci        }
1408bf80f4bSopenharmony_ci    }
1418bf80f4bSopenharmony_ci
1428bf80f4bSopenharmony_ci    if (GAUSSIAN_TYPE) {
1438bf80f4bSopenharmony_ci        RenderGaussian(renderNodeContextMgr, cmdList, renderPass, ppConfig);
1448bf80f4bSopenharmony_ci    } else {
1458bf80f4bSopenharmony_ci        RenderData(renderNodeContextMgr, cmdList, renderPass, ppConfig);
1468bf80f4bSopenharmony_ci    }
1478bf80f4bSopenharmony_ci}
1488bf80f4bSopenharmony_ci
1498bf80f4bSopenharmony_civoid RenderBlur::UpdateGlobalSet(IRenderCommandList& cmdList)
1508bf80f4bSopenharmony_ci{
1518bf80f4bSopenharmony_ci    auto& binder = *globalSet0_;
1528bf80f4bSopenharmony_ci    binder.ClearBindings();
1538bf80f4bSopenharmony_ci    uint32_t binding = 0u;
1548bf80f4bSopenharmony_ci    binder.BindBuffer(binding++, globalUbo_, 0);
1558bf80f4bSopenharmony_ci    binder.BindBuffer(binding++, globalUbo_, sizeof(GlobalPostProcessStruct));
1568bf80f4bSopenharmony_ci    cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
1578bf80f4bSopenharmony_ci}
1588bf80f4bSopenharmony_ci
1598bf80f4bSopenharmony_ciDescriptorCounts RenderBlur::GetDescriptorCounts() const
1608bf80f4bSopenharmony_ci{
1618bf80f4bSopenharmony_ci    // expected high max mip count
1628bf80f4bSopenharmony_ci    return DescriptorCounts { {
1638bf80f4bSopenharmony_ci        { CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MAX_MIP_COUNT },
1648bf80f4bSopenharmony_ci        { CORE_DESCRIPTOR_TYPE_SAMPLER, MAX_MIP_COUNT },
1658bf80f4bSopenharmony_ci        { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u * MAX_MIP_COUNT },
1668bf80f4bSopenharmony_ci    } };
1678bf80f4bSopenharmony_ci}
1688bf80f4bSopenharmony_ci
1698bf80f4bSopenharmony_ci// constants for RenderBlur::RenderData
1708bf80f4bSopenharmony_cinamespace {
1718bf80f4bSopenharmony_ciconstexpr bool USE_CUSTOM_BARRIERS = true;
1728bf80f4bSopenharmony_ci
1738bf80f4bSopenharmony_ciconstexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
1748bf80f4bSopenharmony_ciconstexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1758bf80f4bSopenharmony_ci    CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1768bf80f4bSopenharmony_ciconstexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
1778bf80f4bSopenharmony_ci    CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
1788bf80f4bSopenharmony_ci// transition the final mip level to read only as well
1798bf80f4bSopenharmony_ciconstexpr ImageResourceBarrier FINAL_SRC { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1808bf80f4bSopenharmony_ci    CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1818bf80f4bSopenharmony_ci    CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1828bf80f4bSopenharmony_ciconstexpr ImageResourceBarrier FINAL_DST { CORE_ACCESS_SHADER_READ_BIT,
1838bf80f4bSopenharmony_ci    CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // first possible shader read stage
1848bf80f4bSopenharmony_ci    CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
1858bf80f4bSopenharmony_ci} // namespace
1868bf80f4bSopenharmony_ci
1878bf80f4bSopenharmony_civoid RenderBlur::RenderData(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
1888bf80f4bSopenharmony_ci    const RenderPass& renderPassBase, const PostProcessConfiguration& ppConfig)
1898bf80f4bSopenharmony_ci{
1908bf80f4bSopenharmony_ci    RenderPass renderPass = renderPassBase;
1918bf80f4bSopenharmony_ci    const GpuImageDesc imageDesc = renderNodeContextMgr.GetGpuResourceManager().GetImageDescriptor(imageData_.mipImage);
1928bf80f4bSopenharmony_ci
1938bf80f4bSopenharmony_ci    if (USE_CUSTOM_BARRIERS) {
1948bf80f4bSopenharmony_ci        cmdList.BeginDisableAutomaticBarrierPoints();
1958bf80f4bSopenharmony_ci    }
1968bf80f4bSopenharmony_ci
1978bf80f4bSopenharmony_ci    RenderHandle sets[2u] {};
1988bf80f4bSopenharmony_ci    sets[0] = globalSet0_->GetDescriptorSetHandle();
1998bf80f4bSopenharmony_ci
2008bf80f4bSopenharmony_ci    const uint32_t blurCount = Math::min(ppConfig.blurConfiguration.maxMipLevel, imageData_.mipCount);
2018bf80f4bSopenharmony_ci    // NOTE: for smoother results, first downscale -> then horiz / vert -> downscale and so on
2028bf80f4bSopenharmony_ci    ImageSubresourceRange imageSubresourceRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
2038bf80f4bSopenharmony_ci        PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
2048bf80f4bSopenharmony_ci    for (uint32_t idx = 1; idx < blurCount; ++idx) {
2058bf80f4bSopenharmony_ci        const uint32_t renderPassMipLevel = blurInfo_.upScale ? (blurCount - idx - 1) : idx;
2068bf80f4bSopenharmony_ci        const uint32_t inputMipLevel = blurInfo_.upScale ? (blurCount - idx) : (idx - 1);
2078bf80f4bSopenharmony_ci
2088bf80f4bSopenharmony_ci        const uint32_t currWidth = Math::max(1u, imageDesc.width >> renderPassMipLevel);
2098bf80f4bSopenharmony_ci        const uint32_t currHeight = Math::max(1u, imageDesc.height >> renderPassMipLevel);
2108bf80f4bSopenharmony_ci        const float fCurrWidth = static_cast<float>(currWidth);
2118bf80f4bSopenharmony_ci        const float fCurrHeight = static_cast<float>(currHeight);
2128bf80f4bSopenharmony_ci
2138bf80f4bSopenharmony_ci        renderPass.renderPassDesc.renderArea = { 0, 0, currWidth, currHeight };
2148bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachments[0].mipLevel = renderPassMipLevel;
2158bf80f4bSopenharmony_ci
2168bf80f4bSopenharmony_ci        if (USE_CUSTOM_BARRIERS) {
2178bf80f4bSopenharmony_ci            imageSubresourceRange.baseMipLevel = renderPassMipLevel;
2188bf80f4bSopenharmony_ci            cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, COL_ATTACHMENT, imageSubresourceRange);
2198bf80f4bSopenharmony_ci            imageSubresourceRange.baseMipLevel = inputMipLevel;
2208bf80f4bSopenharmony_ci            if (inputMipLevel == 0) {
2218bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, SHDR_READ, imageSubresourceRange);
2228bf80f4bSopenharmony_ci            } else {
2238bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, COL_ATTACHMENT, SHDR_READ, imageSubresourceRange);
2248bf80f4bSopenharmony_ci            }
2258bf80f4bSopenharmony_ci            cmdList.AddCustomBarrierPoint();
2268bf80f4bSopenharmony_ci        }
2278bf80f4bSopenharmony_ci
2288bf80f4bSopenharmony_ci        cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
2298bf80f4bSopenharmony_ci
2308bf80f4bSopenharmony_ci        cmdList.SetDynamicStateViewport(ViewportDesc { 0.0f, 0.0f, fCurrWidth, fCurrHeight, 0.0f, 0.0f });
2318bf80f4bSopenharmony_ci        cmdList.SetDynamicStateScissor(ScissorDesc { 0, 0, currWidth, currHeight });
2328bf80f4bSopenharmony_ci
2338bf80f4bSopenharmony_ci        cmdList.BindPipeline(renderData_.psoScale);
2348bf80f4bSopenharmony_ci
2358bf80f4bSopenharmony_ci        {
2368bf80f4bSopenharmony_ci            auto& binder = *binders_[idx];
2378bf80f4bSopenharmony_ci            sets[1u] = binder.GetDescriptorSetHandle();
2388bf80f4bSopenharmony_ci            binder.ClearBindings();
2398bf80f4bSopenharmony_ci            binder.BindSampler(0, samplerHandle_);
2408bf80f4bSopenharmony_ci            binder.BindImage(1, { imageData_.mipImage, inputMipLevel });
2418bf80f4bSopenharmony_ci            cmdList.UpdateDescriptorSet(
2428bf80f4bSopenharmony_ci                binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
2438bf80f4bSopenharmony_ci        }
2448bf80f4bSopenharmony_ci        cmdList.BindDescriptorSets(0u, sets);
2458bf80f4bSopenharmony_ci
2468bf80f4bSopenharmony_ci        const LocalPostProcessPushConstantStruct pc {
2478bf80f4bSopenharmony_ci            { fCurrWidth, fCurrHeight, 1.0f / (fCurrWidth), 1.0f / (fCurrHeight) }, { 1.0f, 0.0f, 0.0f, 0.0f }
2488bf80f4bSopenharmony_ci        };
2498bf80f4bSopenharmony_ci        cmdList.PushConstant(renderData_.pipelineLayout.pushConstant, reinterpret_cast<const uint8_t*>(&pc));
2508bf80f4bSopenharmony_ci
2518bf80f4bSopenharmony_ci        cmdList.Draw(3u, 1u, 0u, 0u);
2528bf80f4bSopenharmony_ci        cmdList.EndRenderPass();
2538bf80f4bSopenharmony_ci    }
2548bf80f4bSopenharmony_ci
2558bf80f4bSopenharmony_ci    if (USE_CUSTOM_BARRIERS) {
2568bf80f4bSopenharmony_ci        if (imageData_.mipCount > 1u) {
2578bf80f4bSopenharmony_ci            // transition the final used mip level
2588bf80f4bSopenharmony_ci            if (blurCount > 0) {
2598bf80f4bSopenharmony_ci                const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount - 1, 1, 0,
2608bf80f4bSopenharmony_ci                    PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
2618bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, FINAL_SRC, FINAL_DST, imgRange);
2628bf80f4bSopenharmony_ci            }
2638bf80f4bSopenharmony_ci            if (blurCount < imageData_.mipCount) {
2648bf80f4bSopenharmony_ci                // transition the final levels which might be in undefined state
2658bf80f4bSopenharmony_ci                const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount,
2668bf80f4bSopenharmony_ci                    imageData_.mipCount - blurCount, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
2678bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, FINAL_DST, imgRange);
2688bf80f4bSopenharmony_ci            }
2698bf80f4bSopenharmony_ci        }
2708bf80f4bSopenharmony_ci        cmdList.AddCustomBarrierPoint();
2718bf80f4bSopenharmony_ci        cmdList.EndDisableAutomaticBarrierPoints();
2728bf80f4bSopenharmony_ci    }
2738bf80f4bSopenharmony_ci}
2748bf80f4bSopenharmony_ci
2758bf80f4bSopenharmony_cinamespace {
2768bf80f4bSopenharmony_civoid DownscaleBarrier(IRenderCommandList& cmdList, const RenderHandle image, const uint32_t mipLevel)
2778bf80f4bSopenharmony_ci{
2788bf80f4bSopenharmony_ci    ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
2798bf80f4bSopenharmony_ci        PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
2808bf80f4bSopenharmony_ci    imgRange.baseMipLevel = mipLevel;
2818bf80f4bSopenharmony_ci    cmdList.CustomImageBarrier(image, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
2828bf80f4bSopenharmony_ci    const uint32_t inputMipLevel = mipLevel - 1u;
2838bf80f4bSopenharmony_ci    imgRange.baseMipLevel = inputMipLevel;
2848bf80f4bSopenharmony_ci    if (inputMipLevel == 0) {
2858bf80f4bSopenharmony_ci        cmdList.CustomImageBarrier(image, SHDR_READ, imgRange);
2868bf80f4bSopenharmony_ci    } else {
2878bf80f4bSopenharmony_ci        cmdList.CustomImageBarrier(image, COL_ATTACHMENT, SHDR_READ, imgRange);
2888bf80f4bSopenharmony_ci    }
2898bf80f4bSopenharmony_ci    cmdList.AddCustomBarrierPoint();
2908bf80f4bSopenharmony_ci}
2918bf80f4bSopenharmony_ci
2928bf80f4bSopenharmony_civoid BlurHorizontalBarrier(
2938bf80f4bSopenharmony_ci    IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
2948bf80f4bSopenharmony_ci{
2958bf80f4bSopenharmony_ci    ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
2968bf80f4bSopenharmony_ci        PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
2978bf80f4bSopenharmony_ci    imgRange.baseMipLevel = mipLevel;
2988bf80f4bSopenharmony_ci    cmdList.CustomImageBarrier(realImage, COL_ATTACHMENT, SHDR_READ, imgRange);
2998bf80f4bSopenharmony_ci    imgRange.baseMipLevel = mipLevel - 1;
3008bf80f4bSopenharmony_ci    cmdList.CustomImageBarrier(tmpImage, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
3018bf80f4bSopenharmony_ci    cmdList.AddCustomBarrierPoint();
3028bf80f4bSopenharmony_ci}
3038bf80f4bSopenharmony_ci
3048bf80f4bSopenharmony_civoid BlurVerticalBarrier(
3058bf80f4bSopenharmony_ci    IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
3068bf80f4bSopenharmony_ci{
3078bf80f4bSopenharmony_ci    ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
3088bf80f4bSopenharmony_ci        PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
3098bf80f4bSopenharmony_ci    imgRange.baseMipLevel = mipLevel;
3108bf80f4bSopenharmony_ci    cmdList.CustomImageBarrier(realImage, SHDR_READ, COL_ATTACHMENT, imgRange);
3118bf80f4bSopenharmony_ci    imgRange.baseMipLevel = mipLevel - 1;
3128bf80f4bSopenharmony_ci    cmdList.CustomImageBarrier(tmpImage, COL_ATTACHMENT, SHDR_READ, imgRange);
3138bf80f4bSopenharmony_ci    cmdList.AddCustomBarrierPoint();
3148bf80f4bSopenharmony_ci}
3158bf80f4bSopenharmony_ci
3168bf80f4bSopenharmony_cistruct ConstDrawInput {
3178bf80f4bSopenharmony_ci    IRenderCommandList& cmdList;
3188bf80f4bSopenharmony_ci    const RenderPass& renderPass;
3198bf80f4bSopenharmony_ci    const PushConstant& pushConstant;
3208bf80f4bSopenharmony_ci    const LocalPostProcessPushConstantStruct& pc;
3218bf80f4bSopenharmony_ci    RenderHandle sampler;
3228bf80f4bSopenharmony_ci};
3238bf80f4bSopenharmony_civoid BlurPass(const ConstDrawInput& di, IDescriptorSetBinder& binder, IDescriptorSetBinder& globalBinder,
3248bf80f4bSopenharmony_ci    const RenderHandle psoHandle, const RenderHandle image, const uint32_t inputMipLevel)
3258bf80f4bSopenharmony_ci{
3268bf80f4bSopenharmony_ci    di.cmdList.BeginRenderPass(
3278bf80f4bSopenharmony_ci        di.renderPass.renderPassDesc, di.renderPass.subpassStartIndex, di.renderPass.subpassDesc);
3288bf80f4bSopenharmony_ci    di.cmdList.BindPipeline(psoHandle);
3298bf80f4bSopenharmony_ci
3308bf80f4bSopenharmony_ci    RenderHandle sets[2u] {};
3318bf80f4bSopenharmony_ci    sets[0] = globalBinder.GetDescriptorSetHandle();
3328bf80f4bSopenharmony_ci    {
3338bf80f4bSopenharmony_ci        binder.ClearBindings();
3348bf80f4bSopenharmony_ci        sets[1u] = binder.GetDescriptorSetHandle();
3358bf80f4bSopenharmony_ci        binder.BindSampler(0, di.sampler);
3368bf80f4bSopenharmony_ci        binder.BindImage(1u, { image, inputMipLevel });
3378bf80f4bSopenharmony_ci        di.cmdList.UpdateDescriptorSet(
3388bf80f4bSopenharmony_ci            binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
3398bf80f4bSopenharmony_ci    }
3408bf80f4bSopenharmony_ci    di.cmdList.BindDescriptorSets(0, sets);
3418bf80f4bSopenharmony_ci
3428bf80f4bSopenharmony_ci    di.cmdList.PushConstant(di.pushConstant, reinterpret_cast<const uint8_t*>(&di.pc));
3438bf80f4bSopenharmony_ci    di.cmdList.Draw(3u, 1u, 0u, 0u);
3448bf80f4bSopenharmony_ci    di.cmdList.EndRenderPass();
3458bf80f4bSopenharmony_ci}
3468bf80f4bSopenharmony_ci} // namespace
3478bf80f4bSopenharmony_ci
3488bf80f4bSopenharmony_civoid RenderBlur::RenderGaussian(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
3498bf80f4bSopenharmony_ci    const RenderPass& renderPassBase, const PostProcessConfiguration& ppConfig)
3508bf80f4bSopenharmony_ci{
3518bf80f4bSopenharmony_ci    RenderPass renderPass = renderPassBase;
3528bf80f4bSopenharmony_ci    if (USE_CUSTOM_BARRIERS) {
3538bf80f4bSopenharmony_ci        cmdList.BeginDisableAutomaticBarrierPoints();
3548bf80f4bSopenharmony_ci    }
3558bf80f4bSopenharmony_ci
3568bf80f4bSopenharmony_ci    // with every mip, first we do a downscale
3578bf80f4bSopenharmony_ci    // then a single horizontal and a single vertical blur
3588bf80f4bSopenharmony_ci    LocalPostProcessPushConstantStruct pc { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } };
3598bf80f4bSopenharmony_ci    uint32_t descIdx = 0;
3608bf80f4bSopenharmony_ci    const uint32_t blurCount = Math::min(ppConfig.blurConfiguration.maxMipLevel, imageData_.mipCount);
3618bf80f4bSopenharmony_ci    const ConstDrawInput di { cmdList, renderPass, renderData_.pipelineLayout.pushConstant, pc, samplerHandle_ };
3628bf80f4bSopenharmony_ci    for (uint32_t idx = 1; idx < blurCount; ++idx) {
3638bf80f4bSopenharmony_ci        const uint32_t mip = idx;
3648bf80f4bSopenharmony_ci
3658bf80f4bSopenharmony_ci        const Math::UVec2 size = { Math::max(1u, imageData_.size.x >> mip), Math::max(1u, imageData_.size.y >> mip) };
3668bf80f4bSopenharmony_ci        const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
3678bf80f4bSopenharmony_ci        const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
3688bf80f4bSopenharmony_ci        pc = { texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f } };
3698bf80f4bSopenharmony_ci
3708bf80f4bSopenharmony_ci        renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
3718bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachments[0].mipLevel = mip;
3728bf80f4bSopenharmony_ci
3738bf80f4bSopenharmony_ci        cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
3748bf80f4bSopenharmony_ci        cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
3758bf80f4bSopenharmony_ci
3768bf80f4bSopenharmony_ci        // downscale
3778bf80f4bSopenharmony_ci        if (USE_CUSTOM_BARRIERS) {
3788bf80f4bSopenharmony_ci            DownscaleBarrier(cmdList, imageData_.mipImage, mip);
3798bf80f4bSopenharmony_ci        }
3808bf80f4bSopenharmony_ci        BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoScale, imageData_.mipImage, mip - 1u);
3818bf80f4bSopenharmony_ci
3828bf80f4bSopenharmony_ci        // horizontal (from real image to temp)
3838bf80f4bSopenharmony_ci        if (USE_CUSTOM_BARRIERS) {
3848bf80f4bSopenharmony_ci            BlurHorizontalBarrier(cmdList, imageData_.mipImage, mip, tempTarget_.tex.GetHandle());
3858bf80f4bSopenharmony_ci        }
3868bf80f4bSopenharmony_ci
3878bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachmentHandles[0] = tempTarget_.tex.GetHandle();
3888bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachments[0].mipLevel = mip - 1u;
3898bf80f4bSopenharmony_ci        BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoBlur, imageData_.mipImage, mip);
3908bf80f4bSopenharmony_ci
3918bf80f4bSopenharmony_ci        // vertical
3928bf80f4bSopenharmony_ci        if (USE_CUSTOM_BARRIERS) {
3938bf80f4bSopenharmony_ci            BlurVerticalBarrier(cmdList, imageData_.mipImage, mip, tempTarget_.tex.GetHandle());
3948bf80f4bSopenharmony_ci        }
3958bf80f4bSopenharmony_ci
3968bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachmentHandles[0] = imageData_.mipImage;
3978bf80f4bSopenharmony_ci        renderPass.renderPassDesc.attachments[0].mipLevel = mip;
3988bf80f4bSopenharmony_ci        pc.factor = { 0.0f, 1.0f, 0.0f, 0.0f };
3998bf80f4bSopenharmony_ci        BlurPass(di, *binders_[descIdx++], *globalSet0_, renderData_.psoBlur, tempTarget_.tex.GetHandle(), mip - 1);
4008bf80f4bSopenharmony_ci    }
4018bf80f4bSopenharmony_ci
4028bf80f4bSopenharmony_ci    if (USE_CUSTOM_BARRIERS) {
4038bf80f4bSopenharmony_ci        if (imageData_.mipCount > 1u) {
4048bf80f4bSopenharmony_ci            // transition the final used mip level
4058bf80f4bSopenharmony_ci            if (blurCount > 0) {
4068bf80f4bSopenharmony_ci                const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount - 1, 1, 0,
4078bf80f4bSopenharmony_ci                    PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
4088bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, FINAL_SRC, FINAL_DST, imgRange);
4098bf80f4bSopenharmony_ci            }
4108bf80f4bSopenharmony_ci            if (blurCount < imageData_.mipCount) {
4118bf80f4bSopenharmony_ci                // transition the final levels which might be in undefined state
4128bf80f4bSopenharmony_ci                const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount,
4138bf80f4bSopenharmony_ci                    imageData_.mipCount - blurCount, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
4148bf80f4bSopenharmony_ci                cmdList.CustomImageBarrier(imageData_.mipImage, SRC_UNDEFINED, FINAL_DST, imgRange);
4158bf80f4bSopenharmony_ci            }
4168bf80f4bSopenharmony_ci        }
4178bf80f4bSopenharmony_ci        cmdList.AddCustomBarrierPoint();
4188bf80f4bSopenharmony_ci        cmdList.EndDisableAutomaticBarrierPoints();
4198bf80f4bSopenharmony_ci    }
4208bf80f4bSopenharmony_ci}
4218bf80f4bSopenharmony_ci
4228bf80f4bSopenharmony_civoid RenderBlur::CreateTargets(IRenderNodeContextManager& renderNodeContextMgr, const Math::UVec2 baseSize)
4238bf80f4bSopenharmony_ci{
4248bf80f4bSopenharmony_ci    Math::UVec2 texSize = baseSize / 2u;
4258bf80f4bSopenharmony_ci    texSize.x = Math::max(1u, texSize.x);
4268bf80f4bSopenharmony_ci    texSize.y = Math::max(1u, texSize.y);
4278bf80f4bSopenharmony_ci    if (texSize.x != tempTarget_.texSize.x || texSize.y != tempTarget_.texSize.y) {
4288bf80f4bSopenharmony_ci        tempTarget_.texSize = texSize;
4298bf80f4bSopenharmony_ci        tempTarget_.format = imageData_.format;
4308bf80f4bSopenharmony_ci
4318bf80f4bSopenharmony_ci        constexpr ImageUsageFlags usageFlags = ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
4328bf80f4bSopenharmony_ci                                               ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT |
4338bf80f4bSopenharmony_ci                                               ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
4348bf80f4bSopenharmony_ci
4358bf80f4bSopenharmony_ci        const GpuImageDesc desc {
4368bf80f4bSopenharmony_ci            ImageType::CORE_IMAGE_TYPE_2D,
4378bf80f4bSopenharmony_ci            ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
4388bf80f4bSopenharmony_ci            tempTarget_.format,
4398bf80f4bSopenharmony_ci            ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
4408bf80f4bSopenharmony_ci            usageFlags,
4418bf80f4bSopenharmony_ci            MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
4428bf80f4bSopenharmony_ci            0,
4438bf80f4bSopenharmony_ci            EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS,
4448bf80f4bSopenharmony_ci            tempTarget_.texSize.x,
4458bf80f4bSopenharmony_ci            tempTarget_.texSize.y,
4468bf80f4bSopenharmony_ci            1u,
4478bf80f4bSopenharmony_ci            Math::max(1u, (imageData_.mipCount - 1u)),
4488bf80f4bSopenharmony_ci            1u,
4498bf80f4bSopenharmony_ci            SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
4508bf80f4bSopenharmony_ci            {},
4518bf80f4bSopenharmony_ci        };
4528bf80f4bSopenharmony_ci#if (RENDER_VALIDATION_ENABLED == 1)
4538bf80f4bSopenharmony_ci        tempTarget_.tex =
4548bf80f4bSopenharmony_ci            renderNodeContextMgr.GetGpuResourceManager().Create(renderNodeContextMgr.GetName() + "_BLUR_TARGET", desc);
4558bf80f4bSopenharmony_ci#else
4568bf80f4bSopenharmony_ci        tempTarget_.tex = renderNodeContextMgr.GetGpuResourceManager().Create(tempTarget_.tex, desc);
4578bf80f4bSopenharmony_ci#endif
4588bf80f4bSopenharmony_ci    }
4598bf80f4bSopenharmony_ci}
4608bf80f4bSopenharmony_ciRENDER_END_NAMESPACE()
461