diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index cd3676f45bf0891de97ab88ff74cdd980f6920da..21153c3f191e30b45a7f6a3d23ab7a887dba2263 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -163,7 +163,7 @@ namespace vkcv */ [[nodiscard]] PipelineHandle createComputePipeline( - const ShaderProgram &config, + const ShaderProgram &shaderProgram, const std::vector<vk::DescriptorSetLayout> &descriptorSetLayouts); /** diff --git a/modules/shader_compiler/CMakeLists.txt b/modules/shader_compiler/CMakeLists.txt index 4b674ec41ed4ea5f42dc73187c212e6a69952cec..6fee42bfb571168cd2371e21e231ce417efa41f0 100644 --- a/modules/shader_compiler/CMakeLists.txt +++ b/modules/shader_compiler/CMakeLists.txt @@ -10,6 +10,9 @@ set(vkcv_shader_compiler_include ${PROJECT_SOURCE_DIR}/include) # Add source and header files to the module set(vkcv_shader_compiler_sources + ${vkcv_shader_compiler_include}/vkcv/shader/Compiler.hpp + ${vkcv_shader_compiler_source}/vkcv/shader/Compiler.cpp + ${vkcv_shader_compiler_include}/vkcv/shader/GLSLCompiler.hpp ${vkcv_shader_compiler_source}/vkcv/shader/GLSLCompiler.cpp ) diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp index df22f23e761724369b2bb7f47088d011a2af6ee9..71771f7f3ec488e80070bce113586a694eea8e6a 100644 --- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp @@ -1,6 +1,11 @@ #pragma once +#include <filesystem> +#include <map> +#include <string> + #include <vkcv/Event.hpp> +#include <vkcv/ShaderStage.hpp> namespace vkcv::shader { @@ -8,6 +13,9 @@ namespace vkcv::shader { class Compiler { private: + protected: + std::unordered_map<std::string, std::string> m_defines; + public: virtual bool compileSource(ShaderStage shaderStage, const char* shaderSource, const ShaderCompiledFunction& compiled, @@ -17,6 +25,9 @@ namespace vkcv::shader { const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath, bool update) = 0; + std::string getDefine(const std::string& name) const; + + void setDefine(const std::string& name, const std::string& value); }; } diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp index 0a72c357065d80c7457808fbd21480fae49e9e0e..eca84def118625e21df1c645cfc71b6bcddf7393 100644 --- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp @@ -7,7 +7,7 @@ namespace vkcv::shader { - class GLSLCompiler : Compiler { + class GLSLCompiler : public Compiler { private: public: GLSLCompiler(); diff --git a/modules/shader_compiler/src/vkcv/shader/Compiler.cpp b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5ec0435ca8b82dc5f328921f43a39338d1be456 --- /dev/null +++ b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp @@ -0,0 +1,14 @@ + +#include "vkcv/shader/Compiler.hpp" + +namespace vkcv::shader { + + std::string Compiler::getDefine(const std::string &name) const { + return m_defines.at(name); + } + + void Compiler::setDefine(const std::string &name, const std::string &value) { + m_defines[name] = value; + } + +} diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index 5f177e93214e868275e7c1f9d094041a303adb82..ed2bf740f7dc5806b8872d5a718992a2b8632e6f 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -2,6 +2,7 @@ #include "vkcv/shader/GLSLCompiler.hpp" #include <fstream> +#include <strstream> #include <glslang/SPIRV/GlslangToSpv.h> #include <glslang/StandAlone/DirStackFileIncluder.h> @@ -12,7 +13,7 @@ namespace vkcv::shader { static uint32_t s_CompilerCount = 0; - GLSLCompiler::GLSLCompiler() { + GLSLCompiler::GLSLCompiler() : Compiler() { if (s_CompilerCount == 0) { glslang::InitializeProcess(); } @@ -20,7 +21,7 @@ namespace vkcv::shader { s_CompilerCount++; } - GLSLCompiler::GLSLCompiler(const GLSLCompiler &other) { + GLSLCompiler::GLSLCompiler(const GLSLCompiler &other) : Compiler(other) { s_CompilerCount++; } @@ -223,6 +224,11 @@ namespace vkcv::shader { EShMsgSpvRules | EShMsgVulkanRules ); + + std::strstream defines; + for (const auto& define : m_defines) { + defines << "#define " << define.first << " " << define.second << std::endl; + } std::string preprocessedGLSL; @@ -237,6 +243,19 @@ namespace vkcv::shader { return false; } + size_t pos = preprocessedGLSL.find("#version"); + if (pos >= preprocessedGLSL.length()) { + pos = 0; + } + + const size_t epos = preprocessedGLSL.find_last_of("#extension", pos); + if (epos < preprocessedGLSL.length()) { + pos = epos; + } + + pos = preprocessedGLSL.find('\n', pos) + 1; + preprocessedGLSL = preprocessedGLSL.insert(pos, defines.str()); + const char* preprocessedCString = preprocessedGLSL.c_str(); shader.setStrings(&preprocessedCString, 1); diff --git a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp index cb2dc6c18af4dd90b881a4fcc2d74a3792b6309c..6e07a0973a2ad49a53ab2c26b09c21408959eea5 100644 --- a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp +++ b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp @@ -1,15 +1,50 @@ #pragma once +#include <vkcv/Core.hpp> +#include <vkcv/Handles.hpp> #include <vkcv/ShaderProgram.hpp> namespace vkcv::upscaling { + struct FSRConstants { + uint32_t Const0 [4]; + uint32_t Const1 [4]; + uint32_t Const2 [4]; + uint32_t Const3 [4]; + uint32_t Sample [4]; + }; + class FSRUpscaling { private: - ShaderProgram m_program; + Core& m_core; + + PipelineHandle m_easuPipeline; + PipelineHandle m_rcasPipeline; + + DescriptorSetHandle m_descriptorSet; + Buffer<FSRConstants> m_constants; + ImageHandle m_intermediateImage; + SamplerHandle m_sampler; + + bool m_hdr; + float m_sharpness; public: - FSRUpscaling(); + explicit FSRUpscaling(Core& core); + + ~FSRUpscaling() = default; + + void recordUpscaling(const CommandStreamHandle& cmdStream, + const ImageHandle& input, + const ImageHandle& output); + + bool isHdrEnabled() const; + + void setHdrEnabled(bool enabled); + + float getSharpness() const; + + void setSharpness(float sharpness); }; diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 934d550cdf9fb31c90cc7ace41e1d9066f558cd7..6eba68684b9b0d133ec3a5bd0c88a60ce2715e2f 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -18,6 +18,15 @@ namespace vkcv::upscaling { + static std::vector<DescriptorBinding> getDescriptorBindings() { + return std::vector<DescriptorBinding>({ + DescriptorBinding(0, DescriptorType::UNIFORM_BUFFER, 1, ShaderStage::COMPUTE), + DescriptorBinding(1, DescriptorType::IMAGE_SAMPLED, 1, ShaderStage::COMPUTE), + DescriptorBinding(2, DescriptorType::IMAGE_STORAGE, 1, ShaderStage::COMPUTE), + DescriptorBinding(3, DescriptorType::SAMPLER, 1, ShaderStage::COMPUTE) + }); + } + static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { std::ofstream file (shaderPath.string(), std::ios::out); @@ -33,7 +42,8 @@ namespace vkcv::upscaling { return true; } - static bool compileFSRShaders(const shader::ShaderCompiledFunction& compiled) { + static bool compileFSRShader(vkcv::shader::GLSLCompiler& compiler, + const shader::ShaderCompiledFunction& compiled) { std::filesystem::path directory = generateTemporaryFilePath(); if (!std::filesystem::create_directory(directory)) { @@ -49,16 +59,185 @@ namespace vkcv::upscaling { return false; } - vkcv::shader::GLSLCompiler compiler; return compiler.compileSource(vkcv::ShaderStage::COMPUTE, FSR_PASS_GLSL_SHADER.c_str(), compiled, directory); } - FSRUpscaling::FSRUpscaling() { - compileFSRShaders([&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { - m_program.addShader(shaderStage, path); - }); + FSRUpscaling::FSRUpscaling(Core& core) : + m_core(core), + m_easuPipeline(), + m_rcasPipeline(), + m_descriptorSet(m_core.createDescriptorSet(getDescriptorBindings())), + m_constants(m_core.createBuffer<FSRConstants>( + BufferType::UNIFORM,1, + BufferMemoryType::HOST_VISIBLE + )), + m_intermediateImage(), + m_sampler(m_core.createSampler( + SamplerFilterType::LINEAR, + SamplerFilterType::LINEAR, + SamplerMipmapMode::NEAREST, + SamplerAddressMode::CLAMP_TO_EDGE + )), + m_hdr(false), + m_sharpness(1.0f) { + const auto descriptorSetLayout = m_core.getDescriptorSet(m_descriptorSet).layout; + + vkcv::shader::GLSLCompiler easuCompiler, rcasCompiler; + + easuCompiler.setDefine("SAMPLE_BILINEAR", "0"); + easuCompiler.setDefine("SAMPLE_RCAS", "0"); + easuCompiler.setDefine("SAMPLE_EASU", "1"); + + rcasCompiler.setDefine("SAMPLE_BILINEAR", "0"); + rcasCompiler.setDefine("SAMPLE_RCAS", "1"); + rcasCompiler.setDefine("SAMPLE_EASU", "0"); + + { + ShaderProgram program; + compileFSRShader(easuCompiler, [&program, &descriptorSetLayout](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + }); + + m_easuPipeline = m_core.createComputePipeline(program, { descriptorSetLayout }); + } + + { + ShaderProgram program; + compileFSRShader(rcasCompiler, [&program, &descriptorSetLayout](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + }); + + m_rcasPipeline = m_core.createComputePipeline(program, { descriptorSetLayout }); + } } - + + void FSRUpscaling::recordUpscaling(const CommandStreamHandle& cmdStream, + const ImageHandle& input, + const ImageHandle& output) { + const uint32_t inputWidth = m_core.getImageWidth(input); + const uint32_t inputHeight = m_core.getImageWidth(input); + + const uint32_t outputWidth = m_core.getImageWidth(output); + const uint32_t outputHeight = m_core.getImageWidth(output); + + if ((outputWidth != m_core.getImageWidth(m_intermediateImage)) || + (outputHeight != m_core.getImageHeight(m_intermediateImage))) { + m_intermediateImage = m_core.createImage( + vk::Format::eR8G8B8A8Srgb, + outputWidth, outputHeight,1, + false, + true + ).getHandle(); + } + + { + FSRConstants consts = {}; + + FsrEasuCon( + consts.Const0, consts.Const1, consts.Const2, consts.Const3, + static_cast<AF1>(inputWidth), static_cast<AF1>(inputHeight), + static_cast<AF1>(inputWidth), static_cast<AF1>(inputHeight), + static_cast<AF1>(outputWidth), static_cast<AF1>(outputHeight) + ); + + consts.Sample[0] = (((m_hdr) && (m_sharpness <= 0.0f)) ? 1 : 0); + m_constants.fill(&consts); + } + + static const uint32_t threadGroupWorkRegionDim = 16; + + const uint32_t dispatch[3] = { + (outputWidth + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim, + (outputHeight + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim, + 1 + }; + + m_core.recordImageMemoryBarrier(cmdStream, input); + + if (m_sharpness >= 0.0f) { + { + DescriptorWrites writes; + writes.sampledImageWrites.emplace_back(1, input); + writes.storageImageWrites.emplace_back(2, m_intermediateImage); + + m_core.writeDescriptorSet(m_descriptorSet, writes); + } + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_easuPipeline, + dispatch, + {DescriptorSetUsage(0, m_core.getDescriptorSet(m_descriptorSet).vulkanHandle)}, + PushConstants(0) + ); + + { + FSRConstants consts = {}; + + FsrRcasCon(consts.Const0, 1.0f / m_sharpness); + consts.Sample[0] = (m_hdr ? 1 : 0); + + m_constants.fill(&consts); + } + + m_core.prepareImageForSampling(cmdStream, m_intermediateImage); + + { + DescriptorWrites writes; + writes.sampledImageWrites.emplace_back(1, m_intermediateImage); + writes.storageImageWrites.emplace_back(2, output); + + m_core.writeDescriptorSet(m_descriptorSet, writes); + } + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_rcasPipeline, + dispatch, + {DescriptorSetUsage(0, m_core.getDescriptorSet(m_descriptorSet).vulkanHandle)}, + PushConstants(0) + ); + + m_core.prepareImageForStorage(cmdStream, m_intermediateImage); + } else { + { + DescriptorWrites writes; + writes.sampledImageWrites.emplace_back(1, input); + writes.storageImageWrites.emplace_back(2, output); + + m_core.writeDescriptorSet(m_descriptorSet, writes); + } + + m_core.recordComputeDispatchToCmdStream( + cmdStream, + m_rcasPipeline, + dispatch, + {DescriptorSetUsage(0, m_core.getDescriptorSet(m_descriptorSet).vulkanHandle)}, + PushConstants(0) + ); + } + + m_core.recordImageMemoryBarrier(cmdStream, output); + } + + bool FSRUpscaling::isHdrEnabled() const { + return m_hdr; + } + + void FSRUpscaling::setHdrEnabled(bool enabled) { + m_hdr = enabled; + } + + float FSRUpscaling::getSharpness() const { + return m_sharpness; + } + + void FSRUpscaling::setSharpness(float sharpness) { + m_sharpness = sharpness; + } + }