From 96a94aa33cdc51e3741aa8152e91998bc3a76777 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 2 Jul 2025 23:02:50 +0300 Subject: [PATCH] feat: recompiling shaders --- res/shaders/lib/shadows.glsl | 8 +-- src/assets/assetload_funcs.cpp | 27 +++++---- src/graphics/core/Shader.cpp | 87 +++++++++++++++++++-------- src/graphics/core/Shader.hpp | 24 +++++--- src/graphics/render/WorldRenderer.cpp | 8 ++- 5 files changed, 102 insertions(+), 52 deletions(-) diff --git a/res/shaders/lib/shadows.glsl b/res/shaders/lib/shadows.glsl index e21afc22..fa6b9b54 100644 --- a/res/shaders/lib/shadows.glsl +++ b/res/shaders/lib/shadows.glsl @@ -11,10 +11,7 @@ uniform float u_shadowsOpacity; uniform float u_shadowsSoftness; float calc_shadow() { - if (!u_enableShadows) { - return 1.0; - } - +#ifdef ENABLE_SHADOWS float step = 1.0 / float(u_shadowsRes); float s = pow(abs(cos(u_dayTime * PI2)), 0.25) * u_shadowsOpacity; vec3 normalOffset = a_realnormal * (a_distance > 64.0 ? 0.2 : 0.04); @@ -39,6 +36,9 @@ float calc_shadow() { shadow = 0.5; } return 0.5 * (1.0 + s * shadow); +#else + return 1.0; +#endif } #endif // SHADOWS_GLSL_ diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 4bd30416..78d89a0b 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -76,6 +76,14 @@ static auto process_program(const ResPaths& paths, const std::string& filename) return std::make_pair(vertex, fragment); } +static auto read_program(const ResPaths& paths, const std::string& filename) { + io::path vertexFile = paths.find(filename + ".glslv"); + io::path fragmentFile = paths.find(filename + ".glslf"); + return std::make_pair( + io::read_string(vertexFile), io::read_string(fragmentFile) + ); +} + assetload::postfunc assetload::shader( AssetsLoader*, const ResPaths& paths, @@ -83,21 +91,18 @@ assetload::postfunc assetload::shader( const std::string& name, const std::shared_ptr& ) { - auto [vertex, fragment] = process_program(paths, filename); + auto result = read_program(paths, filename); + auto vertex = result.first; + auto fragment = result.second; io::path vertexFile = paths.find(filename + ".glslv"); io::path fragmentFile = paths.find(filename + ".glslf"); - std::string vertexSource = std::move(vertex.code); - std::string fragmentSource = std::move(fragment.code); - return [=](auto assets) { assets->store( Shader::create( - vertexFile.string(), - fragmentFile.string(), - vertexSource, - fragmentSource + {vertexFile.string(), vertex}, + {fragmentFile.string(), fragment} ), name ); @@ -127,10 +132,8 @@ assetload::postfunc assetload::posteffect( return [=](auto assets) { auto program = Shader::create( - effectFile.string(), - effectFile.string(), - vertexSource, - fragmentSource + {effectFile.string(), vertexSource}, + {effectFile.string(), fragmentSource} ); bool advanced = false; if (settings) { diff --git a/src/graphics/core/Shader.cpp b/src/graphics/core/Shader.cpp index df02a5c0..24ea0241 100644 --- a/src/graphics/core/Shader.cpp +++ b/src/graphics/core/Shader.cpp @@ -12,20 +12,25 @@ #include #include "coders/GLSLExtension.hpp" +#include "debug/Logger.hpp" + +static debug::Logger logger("gl-shader"); namespace fs = std::filesystem; GLSLExtension* Shader::preprocessor = new GLSLExtension(); Shader* Shader::used = nullptr; -Shader::Shader(uint id) : id(id){ -} +Shader::Shader(uint id, Source&& vertexSource, Source&& fragmentSource) + : id(id), + vertexSource(std::move(vertexSource)), + fragmentSource(std::move(fragmentSource)) {} -Shader::~Shader(){ +Shader::~Shader() { glDeleteProgram(id); } -void Shader::use(){ +void Shader::use() { used = this; glUseProgram(id); } @@ -40,8 +45,10 @@ uint Shader::getUniformLocation(const std::string& name) { return found->second; } -void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix){ - glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix)); +void Shader::uniformMatrix(const std::string& name, const glm::mat4& matrix) { + glUniformMatrix4fv( + getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(matrix) + ); } void Shader::uniform1i(const std::string& name, int x){ @@ -96,7 +103,7 @@ void Shader::uniform4v(const std::string& name, int length, const float* v) { glUniform4fv(getUniformLocation(name), length, v); } -inline auto shader_deleter = [](GLuint* shader) { +static inline auto shader_deleter = [](GLuint* shader) { glDeleteShader(*shader); delete shader; }; @@ -112,45 +119,73 @@ glshader compile_shader(GLenum type, const GLchar* source, const std::string& fi glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success){ + if (!success) { GLchar infoLog[GL_LOG_LEN]; glGetShaderInfoLog(shader, GL_LOG_LEN, nullptr, infoLog); glDeleteShader(shader); throw std::runtime_error( - "vertex shader compilation failed ("+file+"):\n"+std::string(infoLog) + "vertex shader compilation failed (" + file + "):\n" + + std::string(infoLog) ); - } + } return glshader(new GLuint(shader), shader_deleter); //-V508 } -std::unique_ptr Shader::create( - const std::string& vertexFile, - const std::string& fragmentFile, - const std::string& vertexCode, - const std::string& fragmentCode +static GLuint compile_program( + const Shader::Source& vertexSource, const Shader::Source& fragmentSource ) { + auto& preprocessor = *Shader::preprocessor; + + auto vertexCode = std::move( + preprocessor.process(vertexSource.file, vertexSource.code).code + ); + auto fragmentCode = std::move( + preprocessor.process(fragmentSource.file, fragmentSource.code).code + ); + const GLchar* vCode = vertexCode.c_str(); const GLchar* fCode = fragmentCode.c_str(); - glshader vertex = compile_shader(GL_VERTEX_SHADER, vCode, vertexFile); - glshader fragment = compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentFile); + glshader vertex = + compile_shader(GL_VERTEX_SHADER, vCode, vertexSource.file); + glshader fragment = + compile_shader(GL_FRAGMENT_SHADER, fCode, fragmentSource.file); // Shader Program GLint success; - GLuint id = glCreateProgram(); - glAttachShader(id, *vertex); - glAttachShader(id, *fragment); - glLinkProgram(id); + GLuint program = glCreateProgram(); + glAttachShader(program, *vertex); + glAttachShader(program, *fragment); + glLinkProgram(program); - glGetProgramiv(id, GL_LINK_STATUS, &success); - if (!success){ + glGetProgramiv(program, GL_LINK_STATUS, &success); + + if (!success) { GLchar infoLog[GL_LOG_LEN]; - glGetProgramInfoLog(id, GL_LOG_LEN, nullptr, infoLog); + glGetProgramInfoLog(program, GL_LOG_LEN, nullptr, infoLog); throw std::runtime_error( - "shader program linking failed:\n"+std::string(infoLog) + "shader program linking failed:\n" + std::string(infoLog) ); } - return std::make_unique(id); + return program; +} + +void Shader::recompile() { + GLuint newProgram = compile_program(vertexSource, fragmentSource); + glDeleteProgram(id); + id = newProgram; + uniformLocations.clear(); + logger.info() << "shader " << id << " has been recompiled"; +} + +std::unique_ptr Shader::create( + Source&& vertexSource, Source&& fragmentSource +) { + return std::make_unique( + compile_program(vertexSource, fragmentSource), + std::move(vertexSource), + std::move(fragmentSource) + ); } Shader& Shader::getUsed() { diff --git a/src/graphics/core/Shader.hpp b/src/graphics/core/Shader.hpp index d50ccb46..8f1aeb33 100644 --- a/src/graphics/core/Shader.hpp +++ b/src/graphics/core/Shader.hpp @@ -10,15 +10,25 @@ class GLSLExtension; class Shader { +public: + struct Source { + std::string file; + std::string code; + }; +private: static Shader* used; uint id; std::unordered_map uniformLocations; + // source code used for re-compiling shaders after updating defines + Source vertexSource; + Source fragmentSource; + uint getUniformLocation(const std::string& name); public: static GLSLExtension* preprocessor; - Shader(uint id); + Shader(uint id, Source&& vertexSource, Source&& fragmentSource); ~Shader(); void use(); @@ -38,17 +48,13 @@ public: void uniform3v(const std::string& name, int length, const float* v); void uniform4v(const std::string& name, int length, const float* v); + /// @brief Re-preprocess source code and re-compile shader program + void recompile(); + /// @brief Create shader program using vertex and fragment shaders source. - /// @param vertexFile vertex shader file name - /// @param fragmentFile fragment shader file name - /// @param vertexSource vertex shader source code - /// @param fragmentSource fragment shader source code /// @return linked shader program containing vertex and fragment shaders static std::unique_ptr create( - const std::string& vertexFile, - const std::string& fragmentFile, - const std::string& vertexSource, - const std::string& fragmentSource + Source&& vertexSource, Source&& fragmentSource ); static Shader& getUsed(); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index e2b3dbef..bc24fd27 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -11,6 +11,7 @@ #include "assets/assets_util.hpp" #include "content/Content.hpp" #include "engine/Engine.hpp" +#include "coders/GLSLExtension.hpp" #include "frontend/LevelFrontend.hpp" #include "frontend/ContentGfxCache.hpp" #include "items/Inventory.hpp" @@ -434,6 +435,7 @@ void WorldRenderer::draw( const auto& vp = pctx.getViewport(); camera.setAspectRatio(vp.x / static_cast(vp.y)); + auto& mainShader = assets.require("main"); const auto& settings = engine.getSettings(); gbufferPipeline = settings.graphics.advancedRender.get(); int shadowsQuality = settings.graphics.shadowsQuality.get(); @@ -442,10 +444,14 @@ void WorldRenderer::draw( shadowMap = std::make_unique(resolution); wideShadowMap = std::make_unique(resolution); shadows = true; - } else if (shadowsQuality == 0) { + Shader::preprocessor->define("ENABLE_SHADOWS", "true"); + mainShader.recompile(); + } else if (shadowsQuality == 0 && shadows) { shadowMap.reset(); wideShadowMap.reset(); shadows = false; + Shader::preprocessor->undefine("ENABLE_SHADOWS"); + mainShader.recompile(); } if (shadows && shadowMap->getResolution() != resolution) { shadowMap = std::make_unique(resolution);