diff --git a/ci_shadervalidator/Logs.h b/ci_shadervalidator/Logs.h deleted file mode 100644 index d5c87b7e..00000000 --- a/ci_shadervalidator/Logs.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -enum class logtype : unsigned int { - shader -}; - -inline void ErrorLog(const std::string &, logtype const) -{ -} diff --git a/ci_shadervalidator/build.sh b/ci_shadervalidator/build.sh index b0207f6e..450b2b98 100755 --- a/ci_shadervalidator/build.sh +++ b/ci_shadervalidator/build.sh @@ -1,2 +1,16 @@ #!/bin/sh -g++ -std=c++17 -O2 -DSHADERVALIDATOR_STANDALONE ../ref/glad/src/glad.c ../gl/glsl_common.cpp ../gl/shader.cpp main.cpp -I../ref/glad/include -I../ref/glm -I. -o validateshaders +# Offline GLSL validator for shaders/ (the same preprocessing as gl::shader in the game, then glslangValidator). +# +# Requirements: g++ with C++20, glslangValidator in PATH (Debian/Ubuntu: apt install glslang-tools), +# submodule ref/glm (git submodule update --init ref/glm). +# Usage (Linux; build.sh works from any directory, validateshaders reads ../shaders/ so it runs from here): +# ci_shadervalidator/build.sh +# cd ci_shadervalidator && ./validateshaders +# Every .vert/.frag/.geom/.comp under shaders/ is checked twice (features on and off). +# Exit code is 0 when all shaders pass, 1 otherwise; failing shaders are listed at the end. +# +# The validator's own stdafx.h and utilities/{Globals,Logs}.h stand in for the game's headers, +# so the repository root must not be on the include path. +set -e +cd "$(dirname "$0")" +g++ -std=c++20 -O1 -DSHADERVALIDATOR_STANDALONE ../ref/glad/src/glad.c ../gl/glsl_common.cpp ../gl/shader.cpp main.cpp -I. -I../ref/glad/include -I../ref/glm -o validateshaders diff --git a/ci_shadervalidator/main.cpp b/ci_shadervalidator/main.cpp index 65b1f159..37c70cd0 100644 --- a/ci_shadervalidator/main.cpp +++ b/ci_shadervalidator/main.cpp @@ -1,17 +1,20 @@ #include "stdafx.h" #include "../gl/shader.h" #include "../gl/glsl_common.h" -#include "Globals.h" +#include "utilities/Globals.h" +#include "utilities/Logs.h" #include #include #include #include +#include _global Global; bool check_shader(std::string filename) { gl::shader shader_processor; + shader_processor.name = filename; gl::glsl_common_setup(); std::pair source = shader_processor.process_source(filename, "../shaders/"); @@ -23,9 +26,17 @@ bool check_shader(std::string filename) stage = "frag"; else if (source.first == GL_GEOMETRY_SHADER) stage = "geom"; + else if (source.first == GL_COMPUTE_SHADER) + stage = "comp"; else return false; + if (ErrorLogged) + { + ErrorLogged = false; + return false; + } + std::ofstream file("/tmp/shader"); file << source.second; file.close(); @@ -80,24 +91,38 @@ bool check_shader_confs(std::string filename) int main() { + if (system("glslangValidator --version > /dev/null 2>&1") != 0) + { + std::cerr << "glslangValidator not found in PATH" << std::endl; + return 1; + } + bool suc = true; + std::vector failed; for (auto &f : std::filesystem::recursive_directory_iterator("../shaders/")) { if (!f.is_regular_file()) continue; std::string relative = std::filesystem::relative(f.path(), "../shaders/").string(); - if (f.path().extension() != ".frag" && f.path().extension() != ".geom" && f.path().extension() != ".vert") + auto const ext = f.path().extension(); + if (ext != ".frag" && ext != ".geom" && ext != ".vert" && ext != ".comp") continue; std::cout << "== validating shader " << relative << ": " << std::flush; if (!check_shader_confs(relative)) + { suc = false; + failed.push_back(relative); + } } if (suc) std::cout << "==== all checks ok" << std::endl; else { - std::cout << "==== checks failed" << std::endl; + std::cout << "==== checks failed:"; + for (auto const &name : failed) + std::cout << " " << name; + std::cout << std::endl; return 1; } diff --git a/ci_shadervalidator/Globals.h b/ci_shadervalidator/utilities/Globals.h similarity index 100% rename from ci_shadervalidator/Globals.h rename to ci_shadervalidator/utilities/Globals.h diff --git a/ci_shadervalidator/utilities/Logs.h b/ci_shadervalidator/utilities/Logs.h new file mode 100644 index 00000000..e227fa88 --- /dev/null +++ b/ci_shadervalidator/utilities/Logs.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +enum class logtype : unsigned int { + shader +}; + +// gl::shader reports #texture/#param parse errors through ErrorLog; the validator counts them as failures +inline bool ErrorLogged = false; + +inline void ErrorLog(const std::string &str, logtype const) +{ + std::cerr << str << std::endl; + ErrorLogged = true; +} diff --git a/gl/shader.cpp b/gl/shader.cpp index ebb55da0..c40c79dc 100644 --- a/gl/shader.cpp +++ b/gl/shader.cpp @@ -86,6 +86,8 @@ std::pair gl::shader::process_source(const std::string &fil type = GL_FRAGMENT_SHADER; else if (strcend(filename, ".geom")) type = GL_GEOMETRY_SHADER; + else if (strcend(filename, ".comp")) + type = GL_COMPUTE_SHADER; else throw shader_exception("unknown shader " + filename); @@ -96,6 +98,7 @@ std::pair gl::shader::process_source(const std::string &fil if (type == GL_VERTEX_SHADER) str += "#define STAGE_VERTEX 1\n"; else if (type == GL_FRAGMENT_SHADER) str += "#define STAGE_FRAGMENT 1\n"; else if (type == GL_GEOMETRY_SHADER) str += "#define STAGE_GEOMETRY 1\n"; + else if (type == GL_COMPUTE_SHADER) str += "#define STAGE_COMPUTE 1\n"; str += "vec4 FBOUT(vec4 x) { return " + (Global.gfx_shadergamma ? std::string("vec4(pow(x.rgb, vec3(1.0 / 2.2)), x.a)") : std::string("x")) + "; }\n"; str += read_file(basedir + filename);