From bb6821daa84991d967ed20c939a698b12fa91ae5 Mon Sep 17 00:00:00 2001 From: Artur Wasmut <awasmut@uni-koblenz.de> Date: Fri, 25 Jun 2021 19:32:40 +0200 Subject: [PATCH] create separate class for lens flares and bloom. --- include/vkcv/Image.hpp | 6 +- projects/bloom/CMakeLists.txt | 4 + projects/bloom/resources/shaders/comp.spv | Bin 0 -> 6192 bytes .../bloom/resources/shaders/composite.comp | 38 +++ .../resources/shaders/compositeBloom.comp | 29 -- .../shaders/{blur.comp => downsample.comp} | 1 - .../bloom/resources/shaders/lensFlares.comp | 109 +++++++ projects/bloom/src/BloomAndFlares.cpp | 271 ++++++++++++++++++ projects/bloom/src/BloomAndFlares.hpp | 47 +++ projects/bloom/src/main.cpp | 193 +------------ 10 files changed, 487 insertions(+), 211 deletions(-) create mode 100644 projects/bloom/resources/shaders/comp.spv create mode 100644 projects/bloom/resources/shaders/composite.comp delete mode 100644 projects/bloom/resources/shaders/compositeBloom.comp rename projects/bloom/resources/shaders/{blur.comp => downsample.comp} (99%) create mode 100644 projects/bloom/resources/shaders/lensFlares.comp create mode 100644 projects/bloom/src/BloomAndFlares.cpp create mode 100644 projects/bloom/src/BloomAndFlares.hpp diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 9e1f9708..eac96975 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -42,8 +42,10 @@ namespace vkcv { void generateMipChainImmediate(); void recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream); private: - ImageManager* const m_manager; - const ImageHandle m_handle; + // TODO: const qualifier removed, very hacky!!! + // Else you cannot recreate an image. Pls fix. + ImageManager* m_manager; + ImageHandle m_handle; Image(ImageManager* manager, const ImageHandle& handle); diff --git a/projects/bloom/CMakeLists.txt b/projects/bloom/CMakeLists.txt index cdb30af0..8171938e 100644 --- a/projects/bloom/CMakeLists.txt +++ b/projects/bloom/CMakeLists.txt @@ -11,6 +11,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) # adding source files to the project add_executable(bloom src/main.cpp) +target_sources(bloom PRIVATE + src/BloomAndFlares.cpp + src/BloomAndFlares.hpp) + # this should fix the execution path to load local files from the project (for MSVC) if(MSVC) set_target_properties(bloom PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/projects/bloom/resources/shaders/comp.spv b/projects/bloom/resources/shaders/comp.spv new file mode 100644 index 0000000000000000000000000000000000000000..85c7e74cfc0a89917bf6dd1a7ec449368274c1d3 GIT binary patch literal 6192 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 literal 0 HcmV?d00001 diff --git a/projects/bloom/resources/shaders/composite.comp b/projects/bloom/resources/shaders/composite.comp new file mode 100644 index 00000000..190bed06 --- /dev/null +++ b/projects/bloom/resources/shaders/composite.comp @@ -0,0 +1,38 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurImage; +layout(set=0, binding=1) uniform texture2D lensImage; +layout(set=0, binding=2) uniform sampler linearSampler; +layout(set=0, binding=3, r11f_g11f_b10f) uniform image2D colorBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); + vec2 UV = pixel_coord.xy * pixel_size; + + vec4 composite_color = vec4(0.0f); + + vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; + vec3 lens_color = texture(sampler2D(lensImage, linearSampler), UV).rgb; + vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; + + // composite blur and lens features + float bloom_weight = 0.25f; + float lens_weight = 0.25f; + float main_weight = 1 - (bloom_weight + lens_weight); + + composite_color.rgb = blur_color * bloom_weight + + lens_color * lens_weight + + main_color * main_weight; + + imageStore(colorBuffer, pixel_coord, composite_color); +} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/compositeBloom.comp b/projects/bloom/resources/shaders/compositeBloom.comp deleted file mode 100644 index 5435a240..00000000 --- a/projects/bloom/resources/shaders/compositeBloom.comp +++ /dev/null @@ -1,29 +0,0 @@ -#version 450 -#extension GL_ARB_separate_shader_objects : enable - -layout(set=0, binding=0) uniform texture2D blurImage; -layout(set=0, binding=1) uniform sampler linearSampler; -layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D colorBuffer; - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - - -void main() -{ - if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(colorBuffer)))){ - return; - } - - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); - vec2 pixel_size = vec2(1.0f) / textureSize(sampler2D(blurImage, linearSampler), 0); - vec2 UV = pixel_coord.xy * pixel_size; - - vec4 composite_color = vec4(0.0f); - - vec3 blur_color = texture(sampler2D(blurImage, linearSampler), UV).rgb; - vec3 main_color = imageLoad(colorBuffer, pixel_coord).rgb; - - composite_color.rgb = mix(main_color, blur_color, 0.25f); - - imageStore(colorBuffer, pixel_coord, composite_color); -} \ No newline at end of file diff --git a/projects/bloom/resources/shaders/blur.comp b/projects/bloom/resources/shaders/downsample.comp similarity index 99% rename from projects/bloom/resources/shaders/blur.comp rename to projects/bloom/resources/shaders/downsample.comp index 51834627..2ab00c7c 100644 --- a/projects/bloom/resources/shaders/blur.comp +++ b/projects/bloom/resources/shaders/downsample.comp @@ -14,7 +14,6 @@ void main() return; } - ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); vec2 pixel_size = vec2(1.0f) / imageSize(outBlurImage); vec2 UV = pixel_coord.xy * pixel_size; diff --git a/projects/bloom/resources/shaders/lensFlares.comp b/projects/bloom/resources/shaders/lensFlares.comp new file mode 100644 index 00000000..ce27d885 --- /dev/null +++ b/projects/bloom/resources/shaders/lensFlares.comp @@ -0,0 +1,109 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(set=0, binding=0) uniform texture2D blurBuffer; +layout(set=0, binding=1) uniform sampler linearSampler; +layout(set=0, binding=2, r11f_g11f_b10f) uniform image2D lensBuffer; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +vec3 sampleColorChromaticAberration(vec2 _uv) +{ + vec2 toCenter = (vec2(0.5) - _uv); + + vec3 colorScales = vec3(-1, 0, 1); + float aberrationScale = 0.1; + vec3 scaleFactors = colorScales * aberrationScale; + + float r = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.r).r; + float g = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.g).g; + float b = texture(sampler2D(blurBuffer, linearSampler), _uv + toCenter * scaleFactors.b).b; + return vec3(r, g, b); +} + +// _uv assumed to be flipped UV coordinates! +vec3 ghost_vectors(vec2 _uv) +{ + vec2 ghost_vec = (vec2(0.5f) - _uv); + + const uint c_ghost_count = 64; + const float c_ghost_spacing = length(ghost_vec) / c_ghost_count; + + ghost_vec *= c_ghost_spacing; + + vec3 ret_color = vec3(0.0f); + + for (uint i = 0; i < c_ghost_count; ++i) + { + // sample scene color + vec2 s_uv = fract(_uv + ghost_vec * vec2(i)); + vec3 s = sampleColorChromaticAberration(s_uv); + + // tint/weight + float d = distance(s_uv, vec2(0.5)); + float weight = 1.0f - smoothstep(0.0f, 0.75f, d); + s *= weight; + + ret_color += s; + } + + ret_color /= c_ghost_count; + return ret_color; +} + +vec3 halo(vec2 _uv) +{ + const float c_aspect_ratio = float(imageSize(lensBuffer).x) / float(imageSize(lensBuffer).y); + const float c_radius = 0.6f; + const float c_halo_thickness = 0.1f; + + vec2 halo_vec = vec2(0.5) - _uv; + //halo_vec.x /= c_aspect_ratio; + halo_vec = normalize(halo_vec); + //halo_vec.x *= c_aspect_ratio; + + + //vec2 w_uv = (_uv - vec2(0.5, 0.0)) * vec2(c_aspect_ratio, 1.0) + vec2(0.5, 0.0); + vec2 w_uv = _uv; + float d = distance(w_uv, vec2(0.5)); // distance to center + + float distance_to_halo = abs(d - c_radius); + + float halo_weight = 0.0f; + if(abs(d - c_radius) <= c_halo_thickness) + { + float distance_to_border = c_halo_thickness - distance_to_halo; + halo_weight = distance_to_border / c_halo_thickness; + + //halo_weight = clamp((halo_weight / 0.4f), 0.0f, 1.0f); + halo_weight = pow(halo_weight, 2.0f); + + + //halo_weight = 1.0f; + } + + return sampleColorChromaticAberration(_uv + halo_vec) * halo_weight; +} + + + +void main() +{ + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(lensBuffer)))){ + return; + } + + ivec2 pixel_coord = ivec2(gl_GlobalInvocationID.xy); + vec2 pixel_size = vec2(1.0f) / imageSize(lensBuffer); + vec2 UV = pixel_coord.xy * pixel_size; + + vec2 flipped_UV = vec2(1.0f) - UV; + + vec3 color = vec3(0.0f); + + color += ghost_vectors(flipped_UV); + color += halo(UV); + color *= 0.5f; + + imageStore(lensBuffer, pixel_coord, vec4(color, 0.0f)); +} \ No newline at end of file diff --git a/projects/bloom/src/BloomAndFlares.cpp b/projects/bloom/src/BloomAndFlares.cpp new file mode 100644 index 00000000..e4ca9357 --- /dev/null +++ b/projects/bloom/src/BloomAndFlares.cpp @@ -0,0 +1,271 @@ +#include "BloomAndFlares.hpp" +#include <vkcv/shader/GLSLCompiler.hpp> + +BloomAndFlares::BloomAndFlares( + vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height) : + + p_Core(p_Core), + m_ColorBufferFormat(colorBufferFormat), + m_Width(width), + m_Height(height), + m_LinearSampler(p_Core->createSampler(vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE)), + m_Blur(p_Core->createImage(colorBufferFormat, width, height, 1, true, true, false)), + m_LensFeatures(p_Core->createImage(colorBufferFormat, width, height, 1, false, true, false)) +{ + vkcv::shader::GLSLCompiler compiler; + + // DOWNSAMPLE + vkcv::ShaderProgram dsProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "resources/shaders/downsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + dsProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_DownsampleDescSets.push_back( + p_Core->createDescriptorSet(dsProg.getReflectedDescriptors()[0])); + } + m_DownsamplePipe = p_Core->createComputePipeline( + dsProg, { p_Core->getDescriptorSet(m_DownsampleDescSets[0]).layout }); + + // UPSAMPLE + vkcv::ShaderProgram usProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "resources/shaders/upsample.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + usProg.addShader(shaderStage, path); + }); + for(uint32_t mipLevel = 0; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + m_UpsampleDescSets.push_back( + p_Core->createDescriptorSet(usProg.getReflectedDescriptors()[0])); + } + m_UpsamplePipe = p_Core->createComputePipeline( + usProg, { p_Core->getDescriptorSet(m_UpsampleDescSets[0]).layout }); + + // LENS FEATURES + vkcv::ShaderProgram lensProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "resources/shaders/lensFlares.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + lensProg.addShader(shaderStage, path); + }); + m_LensFlareDescSet = p_Core->createDescriptorSet(lensProg.getReflectedDescriptors()[0]); + m_LensFlarePipe = p_Core->createComputePipeline( + lensProg, { p_Core->getDescriptorSet(m_LensFlareDescSet).layout }); + + // COMPOSITE + vkcv::ShaderProgram compProg; + compiler.compile(vkcv::ShaderStage::COMPUTE, + "resources/shaders/composite.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) + { + compProg.addShader(shaderStage, path); + }); + m_CompositeDescSet = p_Core->createDescriptorSet(compProg.getReflectedDescriptors()[0]); + m_CompositePipe = p_Core->createComputePipeline( + compProg, { p_Core->getDescriptorSet(m_CompositeDescSet).layout }); +} + +void BloomAndFlares::execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // blur dispatch + uint32_t initialDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // downsample dispatch of original color attachment + p_Core->prepareImageForSampling(cmdStream, colorAttachment); + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + vkcv::DescriptorWrites initialDownsampleWrites; + initialDownsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorAttachment)}; + initialDownsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + initialDownsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), 0) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[0], initialDownsampleWrites); + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + initialDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[0]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); + + // downsample dispatches of blur buffer's mip maps + float mipDispatchCountX = dispatchCountX; + float mipDispatchCountY = dispatchCountY; + for(uint32_t mipLevel = 1; mipLevel < m_Blur.getMipCount(); mipLevel++) + { + // mip descriptor writes + vkcv::DescriptorWrites mipDescriptorWrites; + mipDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel - 1, true)}; + mipDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel) }; + p_Core->writeDescriptorSet(m_DownsampleDescSets[mipLevel], mipDescriptorWrites); + + // mip dispatch calculation + mipDispatchCountX /= 2.0f; + mipDispatchCountY /= 2.0f; + + uint32_t mipDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(mipDispatchCountX)), + static_cast<uint32_t>(glm::ceil(mipDispatchCountY)), + 1 + }; + + if(mipDispatchCount[0] == 0) + mipDispatchCount[0] = 1; + if(mipDispatchCount[1] == 0) + mipDispatchCount[1] = 1; + + // mip blur dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_DownsamplePipe, + mipDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_DownsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); + + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // upsample dispatch + p_Core->prepareImageForStorage(cmdStream, m_Blur.getHandle()); + + uint32_t upsampleMipLevels = std::min(m_Blur.getMipCount(), static_cast<uint32_t>(5)); + + // upsample dispatch for each mip map + for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) + { + // mip descriptor writes + vkcv::DescriptorWrites mipUpsampleWrites; + mipUpsampleWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), mipLevel, true)}; + mipUpsampleWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + mipUpsampleWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_Blur.getHandle(), mipLevel - 1) }; + p_Core->writeDescriptorSet(m_UpsampleDescSets[mipLevel], mipUpsampleWrites); + + auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); + + auto upsampleDispatchX = static_cast<float>(m_Width) / mipDivisor; + auto upsampleDispatchY = static_cast<float>(m_Height) / mipDivisor; + upsampleDispatchX /= 8.0f; + upsampleDispatchY /= 8.0f; + + const uint32_t upsampleDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(upsampleDispatchX)), + static_cast<uint32_t>(glm::ceil(upsampleDispatchY)), + 1 + }; + + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_UpsamplePipe, + upsampleDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_UpsampleDescSets[mipLevel]).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0) + ); + // image barrier between mips + p_Core->recordImageMemoryBarrier(cmdStream, m_Blur.getHandle()); + } +} + +void BloomAndFlares::execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream) +{ + // lens feature generation descriptor writes + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForStorage(cmdStream, m_LensFeatures.getHandle()); + + vkcv::DescriptorWrites lensFeatureWrites; + lensFeatureWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle(), 0)}; + lensFeatureWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, m_LinearSampler)}; + lensFeatureWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, m_LensFeatures.getHandle(), 0)}; + p_Core->writeDescriptorSet(m_LensFlareDescSet, lensFeatureWrites); + + auto dispatchCountX = static_cast<float>(m_Width) / 8.0f; + auto dispatchCountY = static_cast<float>(m_Height) / 8.0f; + // lens feature generation dispatch + uint32_t lensFeatureDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_LensFlarePipe, + lensFeatureDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_LensFlareDescSet).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); +} + +void BloomAndFlares::execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + p_Core->prepareImageForSampling(cmdStream, m_Blur.getHandle()); + p_Core->prepareImageForSampling(cmdStream, m_LensFeatures.getHandle()); + p_Core->prepareImageForStorage(cmdStream, colorAttachment); + + // bloom composite descriptor write + vkcv::DescriptorWrites compositeWrites; + compositeWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, m_Blur.getHandle()), + vkcv::SampledImageDescriptorWrite(1, m_LensFeatures.getHandle())}; + compositeWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(2, m_LinearSampler)}; + compositeWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(3, colorAttachment)}; + p_Core->writeDescriptorSet(m_CompositeDescSet, compositeWrites); + + float dispatchCountX = static_cast<float>(m_Width) / 8.0f; + float dispatchCountY = static_cast<float>(m_Height) / 8.0f; + + uint32_t compositeDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(dispatchCountX)), + static_cast<uint32_t>(glm::ceil(dispatchCountY)), + 1 + }; + + // bloom composite dispatch + p_Core->recordComputeDispatchToCmdStream( + cmdStream, + m_CompositePipe, + compositeDispatchCount, + {vkcv::DescriptorSetUsage(0, p_Core->getDescriptorSet(m_CompositeDescSet).vulkanHandle)}, + vkcv::PushConstantData(nullptr, 0)); +} + +void BloomAndFlares::execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, + const vkcv::ImageHandle &colorAttachment) +{ + execDownsamplePipe(cmdStream, colorAttachment); + execUpsamplePipe(cmdStream); + execLensFeaturePipe(cmdStream); + execCompositePipe(cmdStream, colorAttachment); +} + +void BloomAndFlares::updateImageDimensions(uint32_t width, uint32_t height) +{ + m_Width = width; + m_Height = height; + + p_Core->getContext().getDevice().waitIdle(); + m_Blur = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, true, true, false); + m_LensFeatures = p_Core->createImage(m_ColorBufferFormat, m_Width, m_Height, 1, false, true, false); +} + + diff --git a/projects/bloom/src/BloomAndFlares.hpp b/projects/bloom/src/BloomAndFlares.hpp new file mode 100644 index 00000000..756b1ca1 --- /dev/null +++ b/projects/bloom/src/BloomAndFlares.hpp @@ -0,0 +1,47 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <glm/glm.hpp> + +class BloomAndFlares{ +public: + BloomAndFlares(vkcv::Core *p_Core, + vk::Format colorBufferFormat, + uint32_t width, + uint32_t height); + + void execWholePipeline(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + + void updateImageDimensions(uint32_t width, uint32_t height); + +private: + vkcv::Core *p_Core; + + vk::Format m_ColorBufferFormat; + uint32_t m_Width; + uint32_t m_Height; + + vkcv::SamplerHandle m_LinearSampler; + vkcv::Image m_Blur; + vkcv::Image m_LensFeatures; + + + vkcv::PipelineHandle m_DownsamplePipe; + std::vector<vkcv::DescriptorSetHandle> m_DownsampleDescSets; // per mip desc set + + vkcv::PipelineHandle m_UpsamplePipe; + std::vector<vkcv::DescriptorSetHandle> m_UpsampleDescSets; // per mip desc set + + vkcv::PipelineHandle m_LensFlarePipe; + vkcv::DescriptorSetHandle m_LensFlareDescSet; + + vkcv::PipelineHandle m_CompositePipe; + vkcv::DescriptorSetHandle m_CompositeDescSet; + + void execDownsamplePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); + void execUpsamplePipe(const vkcv::CommandStreamHandle &cmdStream); + void execLensFeaturePipe(const vkcv::CommandStreamHandle &cmdStream); + void execCompositePipe(const vkcv::CommandStreamHandle &cmdStream, const vkcv::ImageHandle &colorAttachment); +}; + + + diff --git a/projects/bloom/src/main.cpp b/projects/bloom/src/main.cpp index d93cbc28..278f1b8c 100644 --- a/projects/bloom/src/main.cpp +++ b/projects/bloom/src/main.cpp @@ -6,6 +6,7 @@ #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/Logger.hpp> +#include "BloomAndFlares.hpp" #include <glm/glm.hpp> int main(int argc, const char** argv) { @@ -224,11 +225,6 @@ int main(int argc, const char** argv) { vkcv::ImageHandle depthBuffer = core.createImage(depthBufferFormat, windowWidth, windowHeight).getHandle(); vkcv::ImageHandle colorBuffer = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, false, true, true).getHandle(); - vkcv::Image blurBuffer = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, true, true, false); - vkcv::SamplerHandle linearSampler = core.createSampler(vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerFilterType::LINEAR, - vkcv::SamplerMipmapMode::LINEAR, - vkcv::SamplerAddressMode::CLAMP_TO_EDGE); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -271,51 +267,8 @@ int main(int argc, const char** argv) { vkcv::PipelineHandle gammaCorrectionPipeline = core.createComputePipeline(gammaCorrectionProgram, { core.getDescriptorSet(gammaCorrectionDescriptorSet).layout }); - // blur compute shader - vkcv::ShaderProgram blurProgram; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "resources/shaders/blur.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - blurProgram.addShader(shaderStage, path); - }); - // create descriptor sets for each mip level - std::vector<vkcv::DescriptorSetHandle> blurDescriptorSets; - for(uint32_t mipLevel = 0; mipLevel < blurBuffer.getMipCount(); mipLevel++) - { - blurDescriptorSets.push_back(core.createDescriptorSet(blurProgram.getReflectedDescriptors()[0])); - } - vkcv::PipelineHandle blurPipeline = core.createComputePipeline(blurProgram, - { core.getDescriptorSet(blurDescriptorSets[0]).layout }); - - // upsample compute shader - vkcv::ShaderProgram upsampleProgram; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "resources/shaders/upsample.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - upsampleProgram.addShader(shaderStage, path); - }); - // create descriptor sets for each mip level - std::vector<vkcv::DescriptorSetHandle> upsampleDescriptorSets; - for(uint32_t mipLevel = 0; mipLevel < blurBuffer.getMipCount(); mipLevel++) - { - upsampleDescriptorSets.push_back(core.createDescriptorSet(upsampleProgram.getReflectedDescriptors()[0])); - } - vkcv::PipelineHandle upsamplePipeline = core.createComputePipeline(upsampleProgram, - { core.getDescriptorSet(upsampleDescriptorSets[0]).layout }); - - // bloom composite shader - vkcv::ShaderProgram compositeBloomProgram; - compiler.compile(vkcv::ShaderStage::COMPUTE, - "resources/shaders/compositeBloom.comp", - [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) - { - compositeBloomProgram.addShader(shaderStage, path); - }); - vkcv::DescriptorSetHandle compositeBloomDescriptorSet = core.createDescriptorSet(compositeBloomProgram.getReflectedDescriptors()[0]); - vkcv::PipelineHandle compositeBloomPipeline = core.createComputePipeline(compositeBloomProgram, - { core.getDescriptorSet(compositeBloomDescriptorSet).layout }); + BloomAndFlares baf(&core, colorBufferFormat, windowWidth, windowHeight); + // model matrices per mesh std::vector<glm::mat4> modelMatrices; @@ -360,7 +313,8 @@ int main(int argc, const char** argv) { if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight).getHandle(); colorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, true, true).getHandle(); - //blurBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, true, false).getHandle(); + + baf.updateImageDimensions(swapchainWidth, swapchainHeight); windowWidth = swapchainWidth; windowHeight = swapchainHeight; @@ -369,21 +323,6 @@ int main(int argc, const char** argv) { auto end = std::chrono::system_clock::now(); auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); - // update descriptor sets which use swapchain image - // composite bloom - vkcv::DescriptorWrites compositeBloomDescriptorWrites; - compositeBloomDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, blurBuffer.getHandle())}; - compositeBloomDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, linearSampler)}; - compositeBloomDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, colorBuffer, 0)}; - core.writeDescriptorSet(compositeBloomDescriptorSet, compositeBloomDescriptorWrites); - - // gamma correction - vkcv::DescriptorWrites gammaCorrectionDescriptorWrites; - gammaCorrectionDescriptorWrites.storageImageWrites = { - vkcv::StorageImageDescriptorWrite(0, colorBuffer), - vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; - core.writeDescriptorSet(gammaCorrectionDescriptorSet, gammaCorrectionDescriptorWrites); - start = end; cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); @@ -446,111 +385,6 @@ int main(int argc, const char** argv) { drawcalls, renderTargets); - - - auto windowWidthByLocalGroup = static_cast<float>(windowWidth) / 8.0f; - auto windowHeightByLocalGroup = static_cast<float>(windowHeight) / 8.0f; - - uint32_t initialBlurDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(windowWidthByLocalGroup)), - static_cast<uint32_t>(glm::ceil(windowHeightByLocalGroup)), - 1 - }; - // blur dispatch - core.prepareImageForSampling(cmdStream, colorBuffer); - core.prepareImageForStorage(cmdStream, blurBuffer.getHandle()); - // blur dispatch of original color attachment - vkcv::DescriptorWrites firstBlurDescriptorWrites; - firstBlurDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, colorBuffer)}; - firstBlurDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, linearSampler)}; - firstBlurDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, blurBuffer.getHandle(), 0) }; - core.writeDescriptorSet(blurDescriptorSets[0], firstBlurDescriptorWrites); - core.recordComputeDispatchToCmdStream( - cmdStream, - blurPipeline, - initialBlurDispatchCount, - {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(blurDescriptorSets[0]).vulkanHandle)}, - vkcv::PushConstantData(nullptr, 0)); - - // blur dispatches of blur buffer's mip maps - for(uint32_t mipLevel = 1; mipLevel < blurBuffer.getMipCount(); mipLevel++) - { - // mip descriptor writes - vkcv::DescriptorWrites mipBlurDescriptorWrites; - mipBlurDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, blurBuffer.getHandle(), mipLevel - 1, true)}; - mipBlurDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, linearSampler)}; - mipBlurDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, blurBuffer.getHandle(), mipLevel) }; - core.writeDescriptorSet(blurDescriptorSets[mipLevel], mipBlurDescriptorWrites); - - // mip dispatch calculation - windowWidthByLocalGroup /= 2.0f; - windowHeightByLocalGroup /= 2.0f; - - uint32_t mipBlurDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(windowWidthByLocalGroup)), - static_cast<uint32_t>(glm::ceil(windowHeightByLocalGroup)), - 1 - }; - - if(mipBlurDispatchCount[0] == 0) - mipBlurDispatchCount[0] = 1; - if(mipBlurDispatchCount[1] == 0) - mipBlurDispatchCount[1] = 1; - - // mip blur dispatch - core.recordComputeDispatchToCmdStream( - cmdStream, - blurPipeline, - mipBlurDispatchCount, - {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(blurDescriptorSets[mipLevel]).vulkanHandle)}, - vkcv::PushConstantData(nullptr, 0)); - - // image barrier between mips - core.recordImageMemoryBarrier(cmdStream, blurBuffer.getHandle()); - } - - // upsample dispatch - - uint32_t upsampleMipLevels = std::min(blurBuffer.getMipCount(), static_cast<uint32_t>(5)); - - // upsample dispatch for each mip map - for(uint32_t mipLevel = upsampleMipLevels; mipLevel > 0; mipLevel--) - { - // mip descriptor writes - vkcv::DescriptorWrites mipUpsampleDescriptorWrites; - mipUpsampleDescriptorWrites.sampledImageWrites = {vkcv::SampledImageDescriptorWrite(0, blurBuffer.getHandle(), mipLevel, true)}; - mipUpsampleDescriptorWrites.samplerWrites = {vkcv::SamplerDescriptorWrite(1, linearSampler)}; - mipUpsampleDescriptorWrites.storageImageWrites = {vkcv::StorageImageDescriptorWrite(2, blurBuffer.getHandle(), mipLevel - 1) }; - core.writeDescriptorSet(upsampleDescriptorSets[mipLevel], mipUpsampleDescriptorWrites); - - auto mipDivisor = glm::pow(2.0f, static_cast<float>(mipLevel) - 1.0f); - - auto upsampleDispatchWidth = static_cast<float>(windowWidth) / mipDivisor; - auto upsampleDispatchHeight = static_cast<float>(windowHeight) / mipDivisor; - - upsampleDispatchWidth /= 8.0f; - upsampleDispatchHeight /= 8.0f; - - const uint32_t upsampleDispatchCount[3] = { - static_cast<uint32_t>(glm::ceil(upsampleDispatchWidth)), - static_cast<uint32_t>(glm::ceil(upsampleDispatchHeight)), - 1 - }; - - core.recordComputeDispatchToCmdStream( - cmdStream, - upsamplePipeline, - upsampleDispatchCount, - {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(upsampleDescriptorSets[mipLevel]).vulkanHandle)}, - vkcv::PushConstantData(nullptr, 0) - ); - // image barrier between mips - core.recordImageMemoryBarrier(cmdStream, blurBuffer.getHandle()); - } - - core.prepareImageForStorage(cmdStream, colorBuffer); - core.prepareImageForSampling(cmdStream, blurBuffer.getHandle()); - const uint32_t gammaCorrectionLocalGroupSize = 8; const uint32_t gammaCorrectionDispatchCount[3] = { static_cast<uint32_t>(glm::ceil(static_cast<float>(windowWidth) / static_cast<float>(gammaCorrectionLocalGroupSize))), @@ -558,17 +392,18 @@ int main(int argc, const char** argv) { 1 }; - // bloom composite dispatch - core.recordComputeDispatchToCmdStream(cmdStream, - compositeBloomPipeline, - gammaCorrectionDispatchCount, - {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(compositeBloomDescriptorSet).vulkanHandle)}, - vkcv::PushConstantData(nullptr, 0)); + baf.execWholePipeline(cmdStream, colorBuffer); core.prepareImageForStorage(cmdStream, swapchainInput); + // gamma correction descriptor write + vkcv::DescriptorWrites gammaCorrectionDescriptorWrites; + gammaCorrectionDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, colorBuffer), + vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; + core.writeDescriptorSet(gammaCorrectionDescriptorSet, gammaCorrectionDescriptorWrites); - // gamma correction dispatch - core.recordComputeDispatchToCmdStream( + // gamma correction dispatch + core.recordComputeDispatchToCmdStream( cmdStream, gammaCorrectionPipeline, gammaCorrectionDispatchCount, -- GitLab