diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 78d89a0b..88dd66bd 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -71,8 +71,8 @@ static auto process_program(const ResPaths& paths, const std::string& filename) auto& preprocessor = *Shader::preprocessor; - auto vertex = preprocessor.process(vertexFile, vertexSource); - auto fragment = preprocessor.process(fragmentFile, fragmentSource); + auto vertex = preprocessor.process(vertexFile, vertexSource, false, {}); + auto fragment = preprocessor.process(fragmentFile, fragmentSource, false, {}); return std::make_pair(vertex, fragment); } @@ -121,7 +121,7 @@ assetload::postfunc assetload::posteffect( auto& preprocessor = *Shader::preprocessor; preprocessor.addHeader( - "__effect__", preprocessor.process(effectFile, effectSource, true) + "__effect__", preprocessor.process(effectFile, effectSource, true, {}) ); auto [vertex, fragment] = process_program(paths, SHADERS_FOLDER + "/effect"); diff --git a/src/coders/GLSLExtension.cpp b/src/coders/GLSLExtension.cpp index 8105b09e..5d53cb35 100644 --- a/src/coders/GLSLExtension.cpp +++ b/src/coders/GLSLExtension.cpp @@ -22,6 +22,10 @@ void GLSLExtension::setPaths(const ResPaths* paths) { this->paths = paths; } +void GLSLExtension::setTraceOutput(bool enabled) { + this->traceOutput = enabled; +} + void GLSLExtension::loadHeader(const std::string& name) { if (paths == nullptr) { return; @@ -29,7 +33,7 @@ void GLSLExtension::loadHeader(const std::string& name) { io::path file = paths->find("shaders/lib/" + name + ".glsl"); std::string source = io::read_string(file); addHeader(name, {}); - addHeader(name, process(file, source, true)); + addHeader(name, process(file, source, true, {})); } void GLSLExtension::addHeader(const std::string& name, ProcessingResult header) { @@ -123,13 +127,22 @@ static Value default_value_for(Type type) { class GLSLParser : public BasicParser { public: - GLSLParser(GLSLExtension& glsl, std::string_view file, std::string_view source, bool header) + GLSLParser( + GLSLExtension& glsl, + std::string_view file, + std::string_view source, + bool header, + const std::vector& defines + ) : BasicParser(file, source), glsl(glsl) { if (!header) { ss << "#version " << GLSLExtension::VERSION << '\n'; - } - for (auto& entry : glsl.getDefines()) { - ss << "#define " << entry.first << " " << entry.second << '\n'; + for (auto& entry : defines) { + ss << "#define " << entry << '\n'; + } + for (auto& entry : defines) { + ss << "#define " << entry << '\n'; + } } uint linenum = 1; source_line(ss, linenum); @@ -289,10 +302,34 @@ private: std::stringstream ss; }; +static void trace_output( + const io::path& file, + const std::string& source, + const GLSLExtension::ProcessingResult& result +) { + std::stringstream ss; + ss << "export:trace/" << file.name(); + io::path outfile = ss.str(); + try { + io::create_directories(outfile.parent()); + io::write_string(outfile, result.code); + } catch (const std::runtime_error& err) { + logger.error() << "error on saving GLSLExtension::preprocess output (" + << outfile.string() << "): " << err.what(); + } +} + GLSLExtension::ProcessingResult GLSLExtension::process( - const io::path& file, const std::string& source, bool header + const io::path& file, + const std::string& source, + bool header, + const std::vector& defines ) { std::string filename = file.string(); - GLSLParser parser(*this, filename, source, header); - return parser.process(); + GLSLParser parser(*this, filename, source, header, defines); + auto result = parser.process(); + if (traceOutput) { + trace_output(file, source, result); + } + return result; } diff --git a/src/coders/GLSLExtension.hpp b/src/coders/GLSLExtension.hpp index b61ca512..53f52930 100644 --- a/src/coders/GLSLExtension.hpp +++ b/src/coders/GLSLExtension.hpp @@ -5,6 +5,7 @@ #include #include "io/io.hpp" +#include "data/setting.hpp" #include "graphics/core/PostEffect.hpp" class ResPaths; @@ -19,6 +20,7 @@ public: }; void setPaths(const ResPaths* paths); + void setTraceOutput(bool enabled); void define(const std::string& name, std::string value); void undefine(const std::string& name); @@ -37,7 +39,8 @@ public: ProcessingResult process( const io::path& file, const std::string& source, - bool header = false + bool header, + const std::vector& defines ); static inline std::string VERSION = "330 core"; @@ -46,4 +49,5 @@ private: std::unordered_map defines; const ResPaths* paths = nullptr; + bool traceOutput = false; }; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 0288d609..212765f3 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -143,6 +143,12 @@ void Engine::initializeClient() { }, true )); + keepAlive(settings.debug.doTraceShaders.observe( + [](bool value) { + Shader::preprocessor->setTraceOutput(value); + }, + true + )); } void Engine::initialize(CoreParameters coreParameters) { diff --git a/src/graphics/core/Shader.cpp b/src/graphics/core/Shader.cpp index da6ea342..8cc6f202 100644 --- a/src/graphics/core/Shader.cpp +++ b/src/graphics/core/Shader.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -138,15 +137,21 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi } static GLuint compile_program( - const Shader::Source& vertexSource, const Shader::Source& fragmentSource + const Shader::Source& vertexSource, + const Shader::Source& fragmentSource, + const std::vector& defines ) { auto& preprocessor = *Shader::preprocessor; auto vertexCode = std::move( - preprocessor.process(vertexSource.file, vertexSource.code).code + preprocessor + .process(vertexSource.file, vertexSource.code, false, defines) + .code ); auto fragmentCode = std::move( - preprocessor.process(fragmentSource.file, fragmentSource.code).code + preprocessor + .process(fragmentSource.file, fragmentSource.code, false, defines) + .code ); const GLchar* vCode = vertexCode.c_str(); @@ -176,8 +181,8 @@ static GLuint compile_program( return program; } -void Shader::recompile() { - GLuint newProgram = compile_program(vertexSource, fragmentSource); +void Shader::recompile(const std::vector& defines) { + GLuint newProgram = compile_program(vertexSource, fragmentSource, defines); glDeleteProgram(id); id = newProgram; uniformLocations.clear(); @@ -188,7 +193,7 @@ std::unique_ptr Shader::create( Source&& vertexSource, Source&& fragmentSource ) { return std::make_unique( - compile_program(vertexSource, fragmentSource), + compile_program(vertexSource, fragmentSource, {}), std::move(vertexSource), std::move(fragmentSource) ); diff --git a/src/graphics/core/Shader.hpp b/src/graphics/core/Shader.hpp index 4808172e..62698063 100644 --- a/src/graphics/core/Shader.hpp +++ b/src/graphics/core/Shader.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -50,7 +51,7 @@ public: void uniform4v(const std::string& name, int length, const float* v); /// @brief Re-preprocess source code and re-compile shader program - void recompile(); + void recompile(const std::vector& defines); /// @brief Create shader program using vertex and fragment shaders source. /// @return linked shader program containing vertex and fragment shaders diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 099dd989..faa8fdc6 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -321,11 +321,13 @@ void WorldRenderer::renderFrame( prevCTShaderSettings.shadows != currentSettings.shadows || prevCTShaderSettings.ssao != currentSettings.ssao ) { - Shader::preprocessor->setDefined("ENABLE_SHADOWS", currentSettings.shadows); - Shader::preprocessor->setDefined("ENABLE_SSAO", currentSettings.ssao); - Shader::preprocessor->setDefined("ADVANCED_RENDER", currentSettings.advancedRender); + std::vector defines; + if (currentSettings.shadows) defines.emplace_back("ENABLE_SHADOWS"); + if (currentSettings.ssao) defines.emplace_back("ENABLE_SSAO"); + if (currentSettings.advancedRender) defines.emplace_back("ADVANCED_RENDER"); + for (auto shader : affectedShaders) { - shader->recompile(); + shader->recompile(defines); } prevCTShaderSettings = currentSettings; } diff --git a/src/io/settings_io.cpp b/src/io/settings_io.cpp index 53a669ad..ea9a7bf5 100644 --- a/src/io/settings_io.cpp +++ b/src/io/settings_io.cpp @@ -89,6 +89,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) { builder.section("debug"); builder.add("generator-test-mode", &settings.debug.generatorTestMode); builder.add("do-write-lights", &settings.debug.doWriteLights); + builder.add("do-trace-shaders", &settings.debug.doTraceShaders); builder.add("enable-experimental", &settings.debug.enableExperimental); } diff --git a/src/settings.hpp b/src/settings.hpp index 0cb680f0..966e9758 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -95,6 +95,8 @@ struct DebugSettings { FlagSetting generatorTestMode {false}; /// @brief Write lights cache FlagSetting doWriteLights {true}; + /// @brief Write preprocessed shaders code to user:export + FlagSetting doTraceShaders {false}; /// @brief Enable experimental optimizations and features FlagSetting enableExperimental {false}; }; diff --git a/test/coders/GLSLExtension.cpp b/test/coders/GLSLExtension.cpp index bcdd5316..c6936da4 100644 --- a/test/coders/GLSLExtension.cpp +++ b/test/coders/GLSLExtension.cpp @@ -11,7 +11,7 @@ TEST(GLSLExtension, processing) { "float sum(float a, float b) {\n" " return a + b;\n" "}\n", - true + true, {} ) ); try { @@ -27,7 +27,7 @@ TEST(GLSLExtension, processing) { " vec4 color = texture(u_screen, v_uv);\n" " return mix(color, 1.0 - color, p_intensity);\n" "}\n", - false); + false, {}); std::cout << processed.code << std::endl; } catch (const parsing_error& err) { std::cerr << err.errorLog() << std::endl;