diff --git a/README.md b/README.md index c45910f251efbd0c47ce3715ab0b8e83bc2685d2..f73ca45d3b0a5d94f9f9449a151cfc479f2caaa1 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,14 @@ the framework if used. You can configure/adjust the build using CMake if necessa - [Algorithm](modules/algorithm/README.md) - [Asset-Loader](modules/asset_loader/README.md) - [Camera](modules/asset_loader/README.md) - - [GUI](modules/gui/README.md) - [Effects](modules/effects/README.md) - [Geometry](modules/geometry/README.md) + - [GUI](modules/gui/README.md) - [Material](modules/material/README.md) - [Meshlet](modules/meshlet/README.md) - [Scene](modules/scene/README.md) - [Shader-Compiler](modules/shader_compiler/README.md) + - [Tone-Mapping](modules/tone_mapping/README.md) - [Upscaling](modules/upscaling/README.md) ### Projects (optional): diff --git a/include/vkcv/File.hpp b/include/vkcv/File.hpp index 51491b1b04a2a658f410e4872f7661237ca913b2..f6895d41bbefbedd2d6e9ac2c012c4f2a5ae3bb1 100644 --- a/include/vkcv/File.hpp +++ b/include/vkcv/File.hpp @@ -6,6 +6,7 @@ */ #include <filesystem> +#include <vector> namespace vkcv { @@ -22,5 +23,69 @@ namespace vkcv { * @return A unique path for a temporary directory */ std::filesystem::path generateTemporaryDirectoryPath(); + + /** + * @brief Write content data from a vector to a file at + * a given path. + * + * @param[in] path Path of file + * @param[in] content Custom data vector + * @return True on success, false otherwise + */ + bool writeContentToFile(const std::filesystem::path &path, + const std::vector<char>& content); + + /** + * @brief Write binary data from a vector to a file at + * a given path. + * + * @param[in] path Path of file + * @param[in] binary Custom binary vector + * @return True on success, false otherwise + */ + bool writeBinaryToFile(const std::filesystem::path &path, + const std::vector<uint32_t>& binary); + + /** + * @brief Write text to a file at a given path. + * + * @param[in] path Path of file + * @param[in] text Custom text as string + * @return True on success, false otherwise + */ + bool writeTextToFile(const std::filesystem::path &path, + const std::string& text); + + /** + * @brief Read content data from a file at a given path + * into a vector. + * + * @param[in] path Path of file + * @param[in] content Custom data vector reference + * @return True on success, false otherwise + */ + bool readContentFromFile(const std::filesystem::path &path, + std::vector<char>& content); + + /** + * @brief Read binary data from a file at a given path + * into a vector. + * + * @param[in] path Path of file + * @param[in] content Custom binary vector reference + * @return True on success, false otherwise + */ + bool readBinaryFromFile(const std::filesystem::path &path, + std::vector<uint32_t>& binary); + + /** + * @brief Read text from a file at a given path. + * + * @param[in] path Path of file + * @param[in] text Custom text as string reference + * @return True on success, false otherwise + */ + bool readTextFromFile(const std::filesystem::path &path, + std::string& text); } // namespace vkcv diff --git a/include/vkcv/ShaderProgram.hpp b/include/vkcv/ShaderProgram.hpp index 11156fdb5111da53df53ba7cbe80fa130d45b060..c14a36310ad7170251764e47f113df8869038da6 100644 --- a/include/vkcv/ShaderProgram.hpp +++ b/include/vkcv/ShaderProgram.hpp @@ -8,7 +8,6 @@ #include <algorithm> #include <filesystem> -#include <fstream> #include <iostream> #include <spirv_cross.hpp> #include <unordered_map> diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp index 051ae80d8d98e2ca5ce54f20d1e047b2151e87ca..21ea671ce93ebacaddf5c60bf24919455b63598e 100644 --- a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp +++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp @@ -96,53 +96,6 @@ namespace vkcv::algorithm { return descriptorBindings; } - static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { - std::ofstream file (shaderPath.string(), std::ios::out); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); - return false; - } - - file.seekp(0); - file.write(code.c_str(), static_cast<std::streamsize>(code.length())); - file.close(); - - return true; - } - - static bool compileSPDShader(vkcv::shader::GLSLCompiler& compiler, - const std::string &source, - const shader::ShaderCompiledFunction& compiled) { - std::filesystem::path directory = generateTemporaryDirectoryPath(); - - if (!std::filesystem::create_directory(directory)) { - vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str()); - return false; - } - - if (!writeShaderCode(directory / "ffx_a.h", FFX_A_H_SHADER)) { - return false; - } - - if (!writeShaderCode(directory / "ffx_spd.h", FFX_SPD_H_SHADER)) { - return false; - } - - return compiler.compileSource( - vkcv::ShaderStage::COMPUTE, - source.c_str(), - [&directory, &compiled] (vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - if (compiled) { - compiled(shaderStage, path); - } - - std::filesystem::remove_all(directory); - }, directory - ); - } - SinglePassDownsampler::SinglePassDownsampler(Core &core, const SamplerHandle &sampler) : vkcv::Downsampler(core), @@ -215,23 +168,19 @@ namespace vkcv::algorithm { } ShaderProgram program; - if (m_sampler) { - compileSPDShader( - compiler, - SPDINTEGRATIONLINEARSAMPLER_GLSL_SHADER, - [&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { - program.addShader(shaderStage, path); - } - ); - } else { - compileSPDShader( - compiler, + compiler.compileSourceWithHeaders( + ShaderStage::COMPUTE, + m_sampler? + SPDINTEGRATIONLINEARSAMPLER_GLSL_SHADER : SPDINTEGRATION_GLSL_SHADER, - [&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { - program.addShader(shaderStage, path); - } - ); - } + { + { "ffx_a.h", FFX_A_H_SHADER }, + { "ffx_spd.h", FFX_SPD_H_SHADER } + }, + [&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); m_pipeline = m_core.createComputePipeline(ComputePipelineConfig( program, diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp index 133b380095abc6c729ef94da675cc9f394475ab4..6f096ecd6d1f613587a17535a212e64396f254b1 100644 --- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp +++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp @@ -150,7 +150,7 @@ namespace vkcv::effects { ShaderProgram program; compiler.compileSource( vkcv::ShaderStage::COMPUTE, - shaderSource.c_str(), + shaderSource, [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { program.addShader(shaderStage, path); }, diff --git a/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp b/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp index 088a3dbd97ae9654cdbfe6355b4837310c51bddc..d97df3fdc596cc53d37054745ff510c58f2d57ac 100644 --- a/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp +++ b/modules/effects/src/vkcv/effects/GammaCorrectionEffect.cpp @@ -41,7 +41,7 @@ namespace vkcv::effects { compiler.compileSource( ShaderStage::COMPUTE, - GAMMACORRECTION_COMP_SHADER.c_str(), + GAMMACORRECTION_COMP_SHADER, [&program](ShaderStage stage, const std::filesystem::path &path) { program.addShader(stage, path); } diff --git a/modules/shader_compiler/config/GLSLANG.cmake b/modules/shader_compiler/config/GLSLANG.cmake index 98bd45497f9d7ed5196dbed486921f8e6ada12da..86bab2d3a770f62fddaac68168ea23977565598c 100644 --- a/modules/shader_compiler/config/GLSLANG.cmake +++ b/modules/shader_compiler/config/GLSLANG.cmake @@ -10,7 +10,7 @@ if (${glslang_status}) set(ENABLE_GLSLANG_WEBMIN_DEVEL OFF CACHE INTERNAL "") set(ENABLE_EMSCRIPTEN_SINGLE_FILE OFF CACHE INTERNAL "") set(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE OFF CACHE INTERNAL "") - set(ENABLE_HLSL OFF CACHE INTERNAL "") + set(ENABLE_HLSL ON CACHE INTERNAL "") set(ENABLE_RTTI OFF CACHE INTERNAL "") set(ENABLE_EXCEPTIONS OFF CACHE INTERNAL "") set(ENABLE_OPT OFF CACHE INTERNAL "") diff --git a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp index 8096e9e22c7e7df4d48e0e658fa3e70842bb7db6..e30cdb34437d79699fbaecd660efc6852d580edb 100644 --- a/modules/shader_compiler/include/vkcv/shader/Compiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/Compiler.hpp @@ -48,9 +48,30 @@ namespace vkcv::shader { * @param[in] includePath Include path for shaders * @return Result if the compilation succeeds */ - virtual bool compileSource(ShaderStage shaderStage, const char* shaderSource, + virtual bool compileSource(ShaderStage shaderStage, + const std::string& shaderSource, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath) = 0; + + /** + * Compile a shader from source for a target stage with some included headers + * as source as well and an event function called if the compilation completes. + * + * The included shaders will be stored temporarily for shader compilation in + * a directory which gets used as include path. So these files can be used via + * include instructions in the shader source code as if they were stored in the + * same directory. + * + * @param[in] shaderStage Shader pipeline stage + * @param[in] shaderSource Source of shader + * @param[in] shaderHeaders Headers of shader + * @param[in] compiled Shader compilation event + * @return Result if the compilation succeeds + */ + bool compileSourceWithHeaders(ShaderStage shaderStage, + const std::string& shaderSource, + const std::unordered_map<std::filesystem::path, std::string>& shaderHeaders, + const ShaderCompiledFunction& compiled); /** * Compile a shader from a specific file path for a target stage with @@ -81,8 +102,7 @@ namespace vkcv::shader { * @param[in] update Flag to update shaders during runtime */ void compileProgram(ShaderProgram& program, - const std::unordered_map<ShaderStage, - const std::filesystem::path>& stages, + const std::unordered_map<ShaderStage, const std::filesystem::path>& stages, const ShaderProgramCompiledFunction& compiled, const std::filesystem::path& includePath = "", bool update = false); diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp index 48b3024fc62fc3c2f9a0975384298d82d3e8b3ea..cebc8bb73297de07899d611b7bf467a93f2bffca 100644 --- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp @@ -45,7 +45,7 @@ namespace vkcv::shader { * @return Result if the compilation succeeds */ bool compileSource(ShaderStage shaderStage, - const char* shaderSource, + const std::string& shaderSource, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath = "") override; diff --git a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp index 79a86cf580f1de30e20e9b4e7eaff37f4896cddb..837b9b1dd5aea34386ac4060068ff61b22823f91 100644 --- a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp @@ -16,25 +16,6 @@ namespace vkcv::shader { * An abstract class to handle Glslang runtime shader compilation. */ class GlslangCompiler : public Compiler { - protected: - /** - * - * - * @param[in] shaderPath Filepath of shader - * @param[out] spirv - * @return - */ - static bool writeSpirvCode(const std::filesystem::path &shaderPath, - const std::vector<uint32_t>& spirv); - - /** - * - * - * @param[in] shaderPath Filepath of shader - * @return - */ - static std::vector<char> readShaderCode(const std::filesystem::path &shaderPath); - public: /** * The constructor of a runtime Glslang shader compiler instance. diff --git a/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp index 9baf2cbfdd7ad65fe5bb050e8749c39e96d83d4e..dad4c38b50b5fe8a774484ece5f5f92b900665f6 100644 --- a/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/HLSLCompiler.hpp @@ -42,7 +42,7 @@ namespace vkcv::shader { * @return Result if the compilation succeeds */ bool compileSource(ShaderStage shaderStage, - const char* shaderSource, + const std::string& shaderSource, const ShaderCompiledFunction& compiled, const std::filesystem::path& includePath = "") override; diff --git a/modules/shader_compiler/src/vkcv/shader/Compiler.cpp b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp index dcf9e5167c2b2fdd251e4e245a8ea7a6d7e62712..c7935f8905bb86b5f93c9f5fe98f2f6e3a6e85c2 100644 --- a/modules/shader_compiler/src/vkcv/shader/Compiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/Compiler.cpp @@ -1,8 +1,46 @@ #include "vkcv/shader/Compiler.hpp" +#include <vkcv/File.hpp> +#include <vkcv/Logger.hpp> + namespace vkcv::shader { + bool Compiler::compileSourceWithHeaders(ShaderStage shaderStage, + const std::string &shaderSource, + const std::unordered_map<std::filesystem::path, std::string> &shaderHeaders, + const ShaderCompiledFunction &compiled) { + const std::filesystem::path directory = generateTemporaryDirectoryPath(); + + if (!std::filesystem::create_directory(directory)) { + vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.c_str()); + return false; + } + + for (const auto& header : shaderHeaders) { + if (header.first.has_parent_path()) { + std::filesystem::create_directories(directory / header.first.parent_path()); + } + + if (!writeTextToFile(directory / header.first, header.second)) { + return false; + } + } + + return compileSource( + shaderStage, + shaderSource, + [&directory, &compiled] (vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + if (compiled) { + compiled(shaderStage, path); + } + + std::filesystem::remove_all(directory); + }, directory + ); + } + void Compiler::compileProgram(ShaderProgram& program, const std::unordered_map<ShaderStage, const std::filesystem::path>& stages, const ShaderProgramCompiledFunction& compiled, diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index 0f423557be7b91999dafce089abec6b98a538228..a3856076817380c67275b92a3a8239bdff667f5b 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -153,7 +153,7 @@ namespace vkcv::shader { } bool GLSLCompiler::compileSource(ShaderStage shaderStage, - const char* shaderSource, + const std::string& shaderSource, const ShaderCompiledFunction &compiled, const std::filesystem::path& includePath) { const EShLanguage language = findShaderLanguage(shaderStage); @@ -166,12 +166,12 @@ namespace vkcv::shader { glslang::TShader shader (language); switch (m_target) { case GLSLCompileTarget::SUBGROUP_OP: - shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_1); - shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_3); + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_1); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3); break; case GLSLCompileTarget::RAY_TRACING: - shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_2); - shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_4); + shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4); break; default: break; @@ -257,7 +257,7 @@ namespace vkcv::shader { const std::filesystem::path tmp_path = generateTemporaryFilePath(); - if (!writeSpirvCode(tmp_path, spirv)) { + if (!writeBinaryToFile(tmp_path, spirv)) { vkcv_log(LogLevel::ERROR, "Spir-V could not be written to disk"); return false; } diff --git a/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp index 9ee6952b067d182a5a92a034b07d695cbac7606b..1f20daaeaf98aaec251f163961b5bf377d760757 100644 --- a/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GlslangCompiler.cpp @@ -1,9 +1,9 @@ #include "vkcv/shader/GlslangCompiler.hpp" +#include <vkcv/File.hpp> #include <vkcv/Logger.hpp> -#include <fstream> #include <glslang/SPIRV/GlslangToSpv.h> namespace vkcv::shader { @@ -35,57 +35,22 @@ namespace vkcv::shader { return *this; } - bool GlslangCompiler::writeSpirvCode(const std::filesystem::path &shaderPath, - const std::vector<uint32_t>& spirv) { - std::ofstream file (shaderPath.string(), std::ios::out | std::ios::binary); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); - return false; - } - - const auto fileSize = static_cast<std::streamsize>( - sizeof(uint32_t) * spirv.size() - ); - - file.seekp(0); - file.write(reinterpret_cast<const char*>(spirv.data()), fileSize); - file.close(); - - return true; - } - - std::vector<char> GlslangCompiler::readShaderCode(const std::filesystem::path &shaderPath) { - std::ifstream file (shaderPath.string(), std::ios::ate); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); - return std::vector<char>{}; - } - - std::streamsize fileSize = file.tellg(); - std::vector<char> buffer (fileSize + 1); - - file.seekg(0); - file.read(buffer.data(), fileSize); - file.close(); - - buffer[fileSize] = '\0'; - return buffer; - } - void GlslangCompiler::compile(ShaderStage shaderStage, const std::filesystem::path &shaderPath, const ShaderCompiledFunction &compiled, const std::filesystem::path &includePath, bool update) { - const std::vector<char> code = readShaderCode(shaderPath); - bool result; + std::string shaderCode; + bool result = readTextFromFile(shaderPath, shaderCode); + + if (!result) { + vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str()); + } if (!includePath.empty()) { - result = compileSource(shaderStage, code.data(), compiled, includePath); + result = compileSource(shaderStage, shaderCode, compiled, includePath); } else { - result = compileSource(shaderStage, code.data(), compiled, shaderPath.parent_path()); + result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path()); } if (!result) { diff --git a/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp index 6724d008d34e45ac6cbcdde7ec523de25f2bbef1..629f941cdb5fa5e59d6f419374fff4d424aaafaa 100644 --- a/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/HLSLCompiler.cpp @@ -153,7 +153,7 @@ namespace vkcv::shader { } bool HLSLCompiler::compileSource(ShaderStage shaderStage, - const char* shaderSource, + const std::string& shaderSource, const ShaderCompiledFunction &compiled, const std::filesystem::path& includePath) { const EShLanguage language = findShaderLanguage(shaderStage); @@ -164,11 +164,22 @@ namespace vkcv::shader { } glslang::TShader shader (language); + shader.setEntryPoint("main"); + switch (m_target) { default: + shader.setEnvClient(glslang::EShClientNone, glslang::EShTargetVulkan_1_1); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_3); break; } + shader.setEnvInput( + glslang::EShSourceHlsl, + language, + glslang::EShClientNone, + 100 + ); + glslang::TProgram program; std::string source (shaderSource); @@ -204,7 +215,12 @@ namespace vkcv::shader { const auto messages = (EShMessages)( EShMsgSpvRules | - EShMsgVulkanRules + EShMsgVulkanRules | + EShMsgReadHlsl | + EShMsgHlslOffsets | + EShMsgHlslEnable16BitTypes | + EShMsgHlslLegalization | + EShMsgHlslDX9Compatible ); std::string preprocessedHLSL; @@ -249,7 +265,7 @@ namespace vkcv::shader { const std::filesystem::path tmp_path = generateTemporaryFilePath(); - if (!writeSpirvCode(tmp_path, spirv)) { + if (!writeBinaryToFile(tmp_path, spirv)) { vkcv_log(LogLevel::ERROR, "Spir-V could not be written to disk"); return false; } diff --git a/modules/tone_mapping/README.md b/modules/tone_mapping/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8a883001adb624b9eed89239e53abce42f93fca5 --- /dev/null +++ b/modules/tone_mapping/README.md @@ -0,0 +1,15 @@ +# Tone Mapping + +A VkCV module to use tone mapping on images in realtime after rendering + +## Build + +### Dependencies (required): + +| Name of dependency | Used as submodule | +|----------------------------------------------------------|-------------------| +| [glsl-tone-map](https://github.com/dmnsgn/glsl-tone-map) | ✅ | + +## Docs + +Here is a [link](https://userpages.uni-koblenz.de/~vkcv/doc/group__vkcv__tone.html) to this module. diff --git a/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp b/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp index 3323d8797c34afd2890c433c5849bd8fdf9c807e..7150d17210a7ca7047fd01f2ed3d37b37686a86c 100644 --- a/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp +++ b/modules/tone_mapping/src/vkcv/tone/ToneMapping.cpp @@ -65,7 +65,7 @@ namespace vkcv::tone { compiler.compileSource( ShaderStage::COMPUTE, - stream.str().c_str(), + stream.str(), [&](ShaderStage stage, const std::filesystem::path &path) { program.addShader(stage, path); } diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index bacb4ce0814ff0caec0c3d4d353ecf5019e0eda4..dd92b42a79c4320a464986b9337ed4bb87580a6e 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -13,7 +13,6 @@ #include "FSR_Pass.glsl.hxx" #include <vkcv/File.hpp> -#include <vkcv/Logger.hpp> #include <vkcv/shader/GLSLCompiler.hpp> namespace vkcv::upscaling { @@ -107,52 +106,6 @@ namespace vkcv::upscaling { return descriptorBindings; } - static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { - std::ofstream file (shaderPath.string(), std::ios::out); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); - return false; - } - - file.seekp(0); - file.write(code.c_str(), static_cast<std::streamsize>(code.length())); - file.close(); - - return true; - } - - static bool compileFSRShader(vkcv::shader::GLSLCompiler& compiler, - const shader::ShaderCompiledFunction& compiled) { - std::filesystem::path directory = generateTemporaryDirectoryPath(); - - if (!std::filesystem::create_directory(directory)) { - vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str()); - return false; - } - - if (!writeShaderCode(directory / "ffx_a.h", FFX_A_H_SHADER)) { - return false; - } - - if (!writeShaderCode(directory / "ffx_fsr1.h", FFX_FSR1_H_SHADER)) { - return false; - } - - return compiler.compileSource( - vkcv::ShaderStage::COMPUTE, - FSR_PASS_GLSL_SHADER.c_str(), - [&directory, &compiled] (vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - if (compiled) { - compiled(shaderStage, path); - } - - std::filesystem::remove_all(directory); - }, directory - ); - } - FSRUpscaling::FSRUpscaling(Core& core) : Upscaling(core), m_easuPipeline(), @@ -216,12 +169,20 @@ namespace vkcv::upscaling { { ShaderProgram program; - compileFSRShader(easuCompiler, [&program](vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - program.addShader(shaderStage, path); - }); + easuCompiler.compileSourceWithHeaders( + ShaderStage::COMPUTE, + FSR_PASS_GLSL_SHADER, + { + { "ffx_a.h", FFX_A_H_SHADER }, + { "ffx_fsr1.h", FFX_FSR1_H_SHADER } + }, + [&program](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); - m_easuPipeline = m_core.createComputePipeline({program,{ + m_easuPipeline = m_core.createComputePipeline({ program, { m_easuDescriptorSetLayout }}); @@ -238,10 +199,18 @@ namespace vkcv::upscaling { { ShaderProgram program; - compileFSRShader(rcasCompiler, [&program](vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - program.addShader(shaderStage, path); - }); + rcasCompiler.compileSourceWithHeaders( + ShaderStage::COMPUTE, + FSR_PASS_GLSL_SHADER, + { + { "ffx_a.h", FFX_A_H_SHADER }, + { "ffx_fsr1.h", FFX_FSR1_H_SHADER } + }, + [&program](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); m_rcasPipeline = m_core.createComputePipeline({ program, { m_rcasDescriptorSetLayout diff --git a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp index 8c3a973e6914f4cb9b31eef1acf805e6448237eb..40eb63ff4ffe867dce4b2a4dd4c95e5965360bff 100644 --- a/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/NISUpscaling.cpp @@ -89,48 +89,6 @@ namespace vkcv::upscaling { return image.getHandle(); } - static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { - std::ofstream file (shaderPath.string(), std::ios::out); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); - return false; - } - - file.seekp(0); - file.write(code.c_str(), static_cast<std::streamsize>(code.length())); - file.close(); - - return true; - } - - static bool compileNISShader(vkcv::shader::GLSLCompiler& compiler, - const shader::ShaderCompiledFunction& compiled) { - std::filesystem::path directory = generateTemporaryDirectoryPath(); - - if (!std::filesystem::create_directory(directory)) { - vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str()); - return false; - } - - if (!writeShaderCode(directory / "NIS_Scaler.h", NIS_SCALER_H_SHADER)) { - return false; - } - - return compiler.compileSource( - vkcv::ShaderStage::COMPUTE, - NIS_MAIN_GLSL_SHADER.c_str(), - [&directory, &compiled] (vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - if (compiled) { - compiled(shaderStage, path); - } - - std::filesystem::remove_all(directory); - }, directory - ); - } - NISUpscaling::NISUpscaling(Core &core) : Upscaling(core), m_scalerPipeline(), @@ -178,16 +136,22 @@ namespace vkcv::upscaling { { ShaderProgram program; - compileNISShader(scalerCompiler, [&program](vkcv::ShaderStage shaderStage, - const std::filesystem::path& path) { - program.addShader(shaderStage, path); - }); + scalerCompiler.compileSourceWithHeaders( + ShaderStage::COMPUTE, + NIS_MAIN_GLSL_SHADER, + { + { "NIS_Scaler.h", NIS_SCALER_H_SHADER } + }, + [&program](vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); m_scalerPipeline = m_core.createComputePipeline({program,{ m_scalerDescriptorSetLayout }}); - DescriptorWrites writes; writes.writeUniformBuffer( 0, m_scalerConstants.getHandle(), true diff --git a/src/vkcv/File.cpp b/src/vkcv/File.cpp index f840fdb06850d6943864ef119883996a461a13fe..32ded3e5dba876ed0c973f80ac3eb4203d0d68b2 100644 --- a/src/vkcv/File.cpp +++ b/src/vkcv/File.cpp @@ -9,6 +9,8 @@ #include <unistd.h> #endif +#include <fstream> + #include "vkcv/Logger.hpp" namespace vkcv { @@ -54,5 +56,124 @@ namespace vkcv { return tmp / name; } + + bool writeContentToFile(const std::filesystem::path &path, + const std::vector<char>& content) { + std::ofstream file (path.string(), std::ios::out); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + file.seekp(0); + file.write(content.data(), static_cast<std::streamsize>(content.size())); + file.close(); + + return true; + } + + bool writeBinaryToFile(const std::filesystem::path &path, + const std::vector<uint32_t>& binary) { + std::ofstream file (path.string(), std::ios::out); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + file.seekp(0); + file.write( + reinterpret_cast<const char*>(binary.data()), + static_cast<std::streamsize>(binary.size() * sizeof(uint32_t)) + ); + file.close(); + + return true; + } + + bool writeTextToFile(const std::filesystem::path &path, + const std::string& text) { + std::ofstream file (path.string(), std::ios::out); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + file.seekp(0); + file.write(text.c_str(), static_cast<std::streamsize>(text.length())); + file.close(); + + return true; + } + + bool readContentFromFile(const std::filesystem::path &path, + std::vector<char>& content) { + std::ifstream file (path.string(), std::ios::ate); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + const std::streamsize fileSize = file.tellg(); + content.resize(fileSize); + + file.seekg(0); + file.read(content.data(), fileSize); + file.close(); + + return true; + } + + bool readBinaryFromFile(const std::filesystem::path &path, + std::vector<uint32_t>& binary) { + std::ifstream file (path.string(), std::ios::ate); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + const std::streamsize fileSize = file.tellg(); + + if (fileSize % sizeof(uint32_t) != 0) { + vkcv_log(LogLevel::ERROR, "The file is not a valid binary: %s", path.c_str()); + return false; + } + + binary.resize(fileSize / sizeof(uint32_t)); + + file.seekg(0); + file.read( + reinterpret_cast<char*>(binary.data()), + static_cast<std::streamsize>(binary.size() * sizeof(uint32_t)) + ); + file.close(); + + return true; + } + + bool readTextFromFile(const std::filesystem::path &path, + std::string& text) { + std::ifstream file (path.string(), std::ios::ate); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", path.c_str()); + return false; + } + + const std::streamsize fileSize = file.tellg(); + std::vector<char> buffer (fileSize); + buffer.resize(fileSize); + + file.seekg(0); + file.read(buffer.data(), fileSize); + file.close(); + + text = std::string(buffer.data(), buffer.size()); + return true; + } } // namespace vkcv diff --git a/src/vkcv/ShaderProgram.cpp b/src/vkcv/ShaderProgram.cpp index 508f4de536fc193f9b213c87e7de7e3fe0679959..099af639a798938cf6de7a128b72bf9dbe7f7660 100644 --- a/src/vkcv/ShaderProgram.cpp +++ b/src/vkcv/ShaderProgram.cpp @@ -5,38 +5,11 @@ */ #include "vkcv/ShaderProgram.hpp" + +#include "vkcv/File.hpp" #include "vkcv/Logger.hpp" namespace vkcv { - /** - * Reads the file of a given shader code. - * Only used within the class. - * @param[in] relative path to the shader code - * @return vector of chars as a buffer for the code - */ - std::vector<uint32_t> readShaderCode(const std::filesystem::path &shaderPath) { - std::ifstream file(shaderPath.string(), std::ios::ate | std::ios::binary); - - if (!file.is_open()) { - vkcv_log(LogLevel::ERROR, "The file could not be opened: %s", shaderPath.c_str()); - return std::vector<uint32_t>(); - } - - size_t fileSize = (size_t)file.tellg(); - - if (fileSize % sizeof(uint32_t) != 0) { - vkcv_log(LogLevel::ERROR, "The file is not a valid shader: %s", shaderPath.c_str()); - return std::vector<uint32_t>(); - } - - std::vector<uint32_t> buffer(fileSize / sizeof(uint32_t)); - - file.seekg(0); - file.read(reinterpret_cast<char*>(buffer.data()), fileSize); - file.close(); - - return buffer; - } VertexAttachmentFormat convertFormat(spirv_cross::SPIRType::BaseType basetype, uint32_t vecsize) { @@ -85,15 +58,14 @@ namespace vkcv { vkcv_log(LogLevel::WARNING, "Overwriting existing shader stage"); } - const std::vector<uint32_t> shaderCode = readShaderCode(path); - - if (shaderCode.empty()) { + std::vector<uint32_t> shaderCode; + if ((!readBinaryFromFile(path, shaderCode)) || (shaderCode.empty())) { return false; - } else { - m_Shaders.insert(std::make_pair(stage, shaderCode)); - reflectShader(stage); - return true; } + + m_Shaders.insert(std::make_pair(stage, shaderCode)); + reflectShader(stage); + return true; } const std::vector<uint32_t> &ShaderProgram::getShaderBinary(ShaderStage stage) const {