From b65b38051b48b796b8345ea2a8c3118ca50ad263 Mon Sep 17 00:00:00 2001 From: Lucas Alber Date: Thu, 21 Nov 2024 13:33:32 +0100 Subject: [PATCH] merian: ShaderCompiler: Allow additional includes and macros --- include/merian/vk/shader/shader_compiler.hpp | 65 ++++++++++++++----- .../vk/shader/shader_compiler_shaderc.hpp | 11 ++-- ...hader_compiler_system_glslangValidator.hpp | 9 ++- .../shader/shader_compiler_system_glslc.hpp | 9 ++- .../nodes/shadertoy/shadertoy.cpp | 13 ++-- src/merian/vk/shader/shader_compiler.cpp | 11 ++-- .../vk/shader/shader_compiler_shaderc.cpp | 35 ++++++---- .../shader/shader_compiler_shaderc_stub.cpp | 12 ++-- ...hader_compiler_system_glslangValidator.cpp | 20 ++++-- .../shader/shader_compiler_system_glslc.cpp | 20 ++++-- 10 files changed, 141 insertions(+), 64 deletions(-) diff --git a/include/merian/vk/shader/shader_compiler.hpp b/include/merian/vk/shader/shader_compiler.hpp index 8a3cf2c..81c7f4f 100644 --- a/include/merian/vk/shader/shader_compiler.hpp +++ b/include/merian/vk/shader/shader_compiler.hpp @@ -78,34 +78,46 @@ class ShaderCompiler { // Attempt to guess the shader_kind from the file extension if shader_kind = std::nullopt. // // May throw compilation_failed. - virtual std::vector - compile_glsl(const std::filesystem::path& path, - const std::optional optional_shader_kind = std::nullopt) { + virtual std::vector compile_glsl( + const std::filesystem::path& path, + const std::optional optional_shader_kind = std::nullopt, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const { return compile_glsl(FileLoader::load_file(path), path.string(), - optional_shader_kind.value_or(guess_kind(path))); + optional_shader_kind.value_or(guess_kind(path)), + additional_include_paths, additional_macro_definitions); } // May throw compilation_failed. - virtual std::vector compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) = 0; + virtual std::vector compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const = 0; // ------------------------------------------------ ShaderModuleHandle compile_glsl_to_shadermodule( const ContextHandle& context, const std::filesystem::path& path, - const std::optional optional_shader_kind = std::nullopt) { + const std::optional optional_shader_kind = std::nullopt, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const { const vk::ShaderStageFlagBits shader_kind = optional_shader_kind.value_or(guess_kind(path)); - return std::make_shared(context, compile_glsl(path, shader_kind), - shader_kind); + return std::make_shared( + context, + compile_glsl(path, shader_kind, additional_include_paths, additional_macro_definitions), + shader_kind); } // uses the file_loader provided from context. ShaderModuleHandle find_compile_glsl_to_shadermodule( const ContextHandle& context, const std::filesystem::path& path, - const std::optional optional_shader_kind = std::nullopt) { + const std::optional optional_shader_kind = std::nullopt, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const { const std::optional resolved = context->file_loader.find_file(path); if (!resolved) { @@ -114,20 +126,37 @@ class ShaderCompiler { const vk::ShaderStageFlagBits shader_kind = optional_shader_kind.value_or(guess_kind(*resolved)); - return std::make_shared(context, compile_glsl(*resolved, shader_kind), + return std::make_shared(context, + compile_glsl(*resolved, shader_kind, + additional_include_paths, + additional_macro_definitions), shader_kind); } - ShaderModuleHandle compile_glsl_to_shadermodule(const ContextHandle& context, - const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) { - return std::make_shared( - context, compile_glsl(source, source_name, shader_kind), shader_kind); + ShaderModuleHandle compile_glsl_to_shadermodule( + const ContextHandle& context, + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const { + return std::make_shared(context, + compile_glsl(source, source_name, shader_kind, + additional_include_paths, + additional_macro_definitions), + shader_kind); } // ------------------------------------------------ + void add_include_path(const std::string& include_path) { + include_paths.emplace_back(include_path); + } + + void add_macro_definition(const std::string& key, const std::string& value) { + macro_definitions.emplace(key, value); + } + const std::vector& get_include_paths() const { return include_paths; } diff --git a/include/merian/vk/shader/shader_compiler_shaderc.hpp b/include/merian/vk/shader/shader_compiler_shaderc.hpp index 6e5b3b5..a0df2ee 100644 --- a/include/merian/vk/shader/shader_compiler_shaderc.hpp +++ b/include/merian/vk/shader/shader_compiler_shaderc.hpp @@ -17,16 +17,19 @@ class ShadercCompiler : public ShaderCompiler { ~ShadercCompiler(); - std::vector compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) override; + std::vector compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const override; bool available() const override; private: + const uint32_t vk_api_version; #ifdef MERIAN_SHADERC_FOUND shaderc::Compiler shader_compiler; - shaderc::CompileOptions compile_options; #endif }; diff --git a/include/merian/vk/shader/shader_compiler_system_glslangValidator.hpp b/include/merian/vk/shader/shader_compiler_system_glslangValidator.hpp index f74b67e..4f5e47c 100644 --- a/include/merian/vk/shader/shader_compiler_system_glslangValidator.hpp +++ b/include/merian/vk/shader/shader_compiler_system_glslangValidator.hpp @@ -16,9 +16,12 @@ class SystemGlslangValidatorCompiler : public ShaderCompiler { ~SystemGlslangValidatorCompiler(); - std::vector compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) override; + std::vector compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const override; bool available() const override; diff --git a/include/merian/vk/shader/shader_compiler_system_glslc.hpp b/include/merian/vk/shader/shader_compiler_system_glslc.hpp index 5177f22..4e172e5 100644 --- a/include/merian/vk/shader/shader_compiler_system_glslc.hpp +++ b/include/merian/vk/shader/shader_compiler_system_glslc.hpp @@ -15,9 +15,12 @@ class SystemGlslcCompiler : public ShaderCompiler { ~SystemGlslcCompiler(); - std::vector compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) override; + std::vector compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) const override; bool available() const override; diff --git a/src/merian-nodes/nodes/shadertoy/shadertoy.cpp b/src/merian-nodes/nodes/shadertoy/shadertoy.cpp index 23fdf26..54e527a 100644 --- a/src/merian-nodes/nodes/shadertoy/shadertoy.cpp +++ b/src/merian-nodes/nodes/shadertoy/shadertoy.cpp @@ -65,12 +65,17 @@ class ShadertoyInjectCompiler : public ShaderCompiler { ~ShadertoyInjectCompiler() {} - std::vector compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) final override { + std::vector + compile_glsl(const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths = {}, + const std::map& additional_macro_definitions = {}) + const final override { SPDLOG_INFO("(re-)compiling {}", source_name); return forwarding_compiler->compile_glsl(shadertoy_pre + source + shadertoy_post, - source_name, shader_kind); + source_name, shader_kind, additional_include_paths, + additional_macro_definitions); } bool available() const override { diff --git a/src/merian/vk/shader/shader_compiler.cpp b/src/merian/vk/shader/shader_compiler.cpp index c38590b..cae52a6 100644 --- a/src/merian/vk/shader/shader_compiler.cpp +++ b/src/merian/vk/shader/shader_compiler.cpp @@ -19,7 +19,10 @@ class DummyShaderCompiler : public ShaderCompiler { std::vector compile_glsl([[maybe_unused]] const std::string& source, [[maybe_unused]] const std::string& source_name, - [[maybe_unused]] const vk::ShaderStageFlagBits shader_kind) override { + [[maybe_unused]] const vk::ShaderStageFlagBits shader_kind, + [[maybe_unused]] const std::vector& additional_include_paths = {}, + [[maybe_unused]] const std::map& + additional_macro_definitions = {}) const override { throw compilation_failed{"compiler not available"}; } @@ -47,8 +50,7 @@ ShaderCompiler::get(const ContextHandle& context, } ShaderCompilerHandle glslc = - std::make_shared(context, user_include_paths, - user_macro_definitions); + std::make_shared(context, user_include_paths, user_macro_definitions); if (glslc->available()) { SPDLOG_DEBUG("using installed glslc as default compiler"); return glslc; @@ -62,7 +64,8 @@ ShaderCompiler::get(const ContextHandle& context, ShaderCompiler::ShaderCompiler(const ContextHandle& context, const std::vector& user_include_paths, const std::map& user_macro_definitions) - : include_paths(user_include_paths), macro_definitions(user_macro_definitions) { + : include_paths(user_include_paths.begin(), user_include_paths.end()), + macro_definitions(user_macro_definitions) { insert_all(include_paths, context->get_default_shader_include_paths()); macro_definitions.insert(context->get_default_shader_macro_definitions().begin(), diff --git a/src/merian/vk/shader/shader_compiler_shaderc.cpp b/src/merian/vk/shader/shader_compiler_shaderc.cpp index c63f291..58e891c 100644 --- a/src/merian/vk/shader/shader_compiler_shaderc.cpp +++ b/src/merian/vk/shader/shader_compiler_shaderc.cpp @@ -111,41 +111,52 @@ shaderc_shader_kind_for_stage_flag_bit(const vk::ShaderStageFlagBits shader_kind ShadercCompiler::ShadercCompiler(const ContextHandle& context, const std::vector& user_include_paths, const std::map& user_macro_definitions) - : ShaderCompiler(context, user_include_paths, user_macro_definitions) { + : ShaderCompiler(context, user_include_paths, user_macro_definitions), + vk_api_version(context->vk_api_version) {} + +ShadercCompiler::~ShadercCompiler() {} + +std::vector ShadercCompiler::compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths, + const std::map& additional_macro_definitions) const { + const shaderc_shader_kind kind = shaderc_shader_kind_for_stage_flag_bit(shader_kind); + + shaderc::CompileOptions compile_options; for (const auto& [key, value] : get_macro_definitions()) { compile_options.AddMacroDefinition(key, value); } + for (const auto& [key, value] : additional_macro_definitions) { + compile_options.AddMacroDefinition(key, value); + } auto includer = std::make_unique(); for (const auto& include_path : get_include_paths()) { includer->get_file_loader().add_search_path(include_path); } + for (const auto& include_path : additional_include_paths) { + includer->get_file_loader().add_search_path(include_path); + } compile_options.SetIncluder(std::move(includer)); compile_options.SetOptimizationLevel( shaderc_optimization_level::shaderc_optimization_level_performance); - if (context->vk_api_version == VK_API_VERSION_1_0) { + if (vk_api_version == VK_API_VERSION_1_0) { compile_options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_0); - } else if (context->vk_api_version == VK_API_VERSION_1_1) { + } else if (vk_api_version == VK_API_VERSION_1_1) { compile_options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_1); - } else if (context->vk_api_version == VK_API_VERSION_1_2) { + } else if (vk_api_version == VK_API_VERSION_1_2) { compile_options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); } else { compile_options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); } -} - -ShadercCompiler::~ShadercCompiler() {} - -std::vector ShadercCompiler::compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) { - const shaderc_shader_kind kind = shaderc_shader_kind_for_stage_flag_bit(shader_kind); SPDLOG_DEBUG("preprocess {}", source_name); const auto preprocess_result = diff --git a/src/merian/vk/shader/shader_compiler_shaderc_stub.cpp b/src/merian/vk/shader/shader_compiler_shaderc_stub.cpp index bf4bc16..8ca62d3 100644 --- a/src/merian/vk/shader/shader_compiler_shaderc_stub.cpp +++ b/src/merian/vk/shader/shader_compiler_shaderc_stub.cpp @@ -7,14 +7,16 @@ namespace merian { ShadercCompiler::ShadercCompiler(const ContextHandle& context, const std::vector& include_paths, const std::map& macro_definitions) - : ShaderCompiler(context, include_paths, macro_definitions) {} + : ShaderCompiler(context, include_paths, macro_definitions), vk_api_version(-1) {} ShadercCompiler::~ShadercCompiler() {} -std::vector -ShadercCompiler::compile_glsl([[maybe_unused]] const std::string& source, - [[maybe_unused]] const std::string& source_name, - [[maybe_unused]] const vk::ShaderStageFlagBits shader_kind) { +std::vector ShadercCompiler::compile_glsl( + [[maybe_unused]] const std::string& source, + [[maybe_unused]] const std::string& source_name, + [[maybe_unused]] const vk::ShaderStageFlagBits shader_kind, + [[maybe_unused]] const std::vector& additional_include_paths, + [[maybe_unused]] const std::map& additional_macro_definitions) const { throw merian::ShaderCompiler::compilation_failed{ "shaderc is not available (was not found or enabled at compile time)"}; } diff --git a/src/merian/vk/shader/shader_compiler_system_glslangValidator.cpp b/src/merian/vk/shader/shader_compiler_system_glslangValidator.cpp index 1b50832..970c8f9 100644 --- a/src/merian/vk/shader/shader_compiler_system_glslangValidator.cpp +++ b/src/merian/vk/shader/shader_compiler_system_glslangValidator.cpp @@ -28,10 +28,12 @@ SystemGlslangValidatorCompiler::SystemGlslangValidatorCompiler( SystemGlslangValidatorCompiler::~SystemGlslangValidatorCompiler() {} -std::vector -SystemGlslangValidatorCompiler::compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) { +std::vector SystemGlslangValidatorCompiler::compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths, + const std::map& additional_macro_definitions) const { if (compiler_executable.empty()) { throw compilation_failed{"compiler not available"}; } @@ -59,8 +61,14 @@ SystemGlslangValidatorCompiler::compile_glsl(const std::string& source, for (const auto& inc_dir : get_include_paths()) { command.emplace_back(fmt::format("-I{}", inc_dir)); } - for (const auto& macro_def : get_macro_definitions()) { - command.emplace_back(fmt::format("-D{}={}", macro_def.first, macro_def.second)); + for (const auto& inc_dir : additional_include_paths) { + command.emplace_back(fmt::format("-I{}", inc_dir)); + } + for (const auto& [key, value] : get_macro_definitions()) { + command.emplace_back(fmt::format("-D{}={}", key, value)); + } + for (const auto& [key, value] : additional_macro_definitions) { + command.emplace_back(fmt::format("-D{}={}", key, value)); } const std::string output_file = temporary_file(); diff --git a/src/merian/vk/shader/shader_compiler_system_glslc.cpp b/src/merian/vk/shader/shader_compiler_system_glslc.cpp index e183efd..9c29c54 100644 --- a/src/merian/vk/shader/shader_compiler_system_glslc.cpp +++ b/src/merian/vk/shader/shader_compiler_system_glslc.cpp @@ -28,9 +28,12 @@ SystemGlslcCompiler::SystemGlslcCompiler( SystemGlslcCompiler::~SystemGlslcCompiler() {} -std::vector SystemGlslcCompiler::compile_glsl(const std::string& source, - const std::string& source_name, - const vk::ShaderStageFlagBits shader_kind) { +std::vector SystemGlslcCompiler::compile_glsl( + const std::string& source, + const std::string& source_name, + const vk::ShaderStageFlagBits shader_kind, + const std::vector& additional_include_paths, + const std::map& additional_macro_definitions) const { if (compiler_executable.empty()) { throw compilation_failed{"compiler not available"}; } @@ -57,8 +60,15 @@ std::vector SystemGlslcCompiler::compile_glsl(const std::string& sourc command.emplace_back("-I"); command.emplace_back(inc_dir); } - for (const auto& macro_def : get_macro_definitions()) { - command.emplace_back(fmt::format("-D{}={}", macro_def.first, macro_def.second)); + for (const auto& inc_dir : additional_include_paths) { + command.emplace_back("-I"); + command.emplace_back(inc_dir); + } + for (const auto& [key, value] : get_macro_definitions()) { + command.emplace_back(fmt::format("-D{}={}", key, value)); + } + for (const auto& [key, value] : additional_macro_definitions) { + command.emplace_back(fmt::format("-D{}={}", key, value)); } // turn on optimization