mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 08:27:17 +01:00
feat(vulkan): vulkan 1.4 core with the user interface and the launcher, shaders split into ogl46/vk14 with SPIR-V binaries loaded first
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
#!/bin/sh
|
||||
# Offline GLSL validator for shaders/ (the same preprocessing as gl::shader in the game, then glslangValidator).
|
||||
# Offline validator of the shaders (shaders/ogl46 and shaders/vk14): the same preprocessing as the game
|
||||
# (rendering/common/shadersource.cpp), 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).
|
||||
# Every .vert/.frag/.geom/.comp of shaders/ogl46 is compiled as the game compiles the source (features on and off, and the
|
||||
# variant of the multi draws) and to SPIR-V for opengl from the file as it is (as glslc makes the binaries of
|
||||
# shaders/ogl46bin); the constants written in shaders/ogl46/common.glsl are compared with those of the game. The shaders of
|
||||
# shaders/vk14 are compiled to SPIR-V for vulkan.
|
||||
# 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.
|
||||
# The validator's own stdafx.h and utilities/{Globals,Logs}.h stand in for the game's headers: its directory comes first
|
||||
# on the include path, before the repository root.
|
||||
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
|
||||
g++ -std=c++20 -O1 ../ref/glad/src/glad.c ../gl/glsl_common.cpp ../rendering/common/shadersource.cpp main.cpp -I. -I.. -I../ref/glad/include -I../ref/glm -o validateshaders
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "../gl/shader.h"
|
||||
#include "../gl/glsl_common.h"
|
||||
#include "rendering/common/shadersource.h"
|
||||
#include "utilities/Globals.h"
|
||||
#include "utilities/Logs.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
@@ -11,99 +12,123 @@
|
||||
|
||||
_global Global;
|
||||
|
||||
bool check_shader(std::string filename, std::string const &defines = {})
|
||||
namespace
|
||||
{
|
||||
gl::shader shader_processor;
|
||||
shader_processor.name = filename;
|
||||
|
||||
gl::glsl_common_setup();
|
||||
std::pair<GLuint, std::string> source = shader_processor.process_source(filename, "../shaders/", defines);
|
||||
std::string const ogl46_dir{"../shaders/ogl46/"};
|
||||
std::string const vk14_dir{"../shaders/vk14/"};
|
||||
// the vulkan environment glslang is asked for: 1.4 where it knows it
|
||||
std::string vulkan_env{"vulkan1.4"};
|
||||
|
||||
std::string stage;
|
||||
if (source.first == GL_VERTEX_SHADER)
|
||||
stage = "vert";
|
||||
else if (source.first == GL_FRAGMENT_SHADER)
|
||||
stage = "frag";
|
||||
else if (source.first == GL_GEOMETRY_SHADER)
|
||||
stage = "geom";
|
||||
else if (source.first == GL_COMPUTE_SHADER)
|
||||
stage = "comp";
|
||||
else
|
||||
return false;
|
||||
char const *stage_name(gfx::shader_stage const Stage)
|
||||
{
|
||||
switch (Stage)
|
||||
{
|
||||
case gfx::shader_stage::vertex:
|
||||
return "vert";
|
||||
case gfx::shader_stage::fragment:
|
||||
return "frag";
|
||||
case gfx::shader_stage::geometry:
|
||||
return "geom";
|
||||
case gfx::shader_stage::compute:
|
||||
return "comp";
|
||||
}
|
||||
return "vert";
|
||||
}
|
||||
|
||||
// Mode: the options of glslangValidator (empty: glsl of opengl, compiled from the source as the game does)
|
||||
bool check_text(gfx::shader_source const &Source, std::string const &Mode)
|
||||
{
|
||||
if (ErrorLogged)
|
||||
{
|
||||
ErrorLogged = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream file("/tmp/shader");
|
||||
file << source.second;
|
||||
file << Source.text;
|
||||
file.close();
|
||||
|
||||
int ret = system(("glslangValidator -S " + stage + " /tmp/shader").c_str());
|
||||
|
||||
// the output only when it fails (glslangValidator names the file it compiled to spir-v)
|
||||
auto const command{"glslangValidator " + Mode + " -S " + stage_name(Source.stage) + " /tmp/shader" + (Mode.empty() ? "" : " -o /tmp/shader.spv") + " > /tmp/shader.log 2>&1"};
|
||||
int ret = system(command.c_str());
|
||||
if (ret != 0)
|
||||
{
|
||||
std::ifstream log("/tmp/shader.log");
|
||||
std::cerr << std::endl << log.rdbuf();
|
||||
std::cerr << "(source strings:";
|
||||
for (std::size_t i = 0; i < Source.files.size(); ++i)
|
||||
std::cerr << " " << i << ": " << Source.files[i];
|
||||
std::cerr << ")" << std::endl;
|
||||
}
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
bool check_shader_allopts(std::string filename)
|
||||
void set_features(bool const Enabled)
|
||||
{
|
||||
Global.gfx_shadowmap_enabled = Enabled;
|
||||
Global.gfx_envmap_enabled = Enabled;
|
||||
Global.gfx_postfx_motionblur_enabled = Enabled;
|
||||
Global.gfx_skippipeline = !Enabled;
|
||||
Global.gfx_extraeffects = Enabled;
|
||||
Global.gfx_shadergamma = Enabled;
|
||||
}
|
||||
|
||||
// a shader of the opengl renderer: compiled from the source as the game does it (with the features on and off, and the variant
|
||||
// of the multi draws), and compiled to SPIR-V for opengl from the file as it is, as glslc makes the binaries of shaders/ogl46bin
|
||||
bool check_ogl46(std::string const &Name)
|
||||
{
|
||||
bool suc = true;
|
||||
auto const stage{gfx::shader_stage_of(Name)};
|
||||
auto const source = [&](std::string const &Defines, std::string const &Preamble) { return gfx::preprocess_shader(gfx::shader_api::opengl46, Name, Defines, Preamble, false, ogl46_dir); };
|
||||
|
||||
std::cout << "features on..." << std::flush;
|
||||
Global.gfx_shadowmap_enabled = true;
|
||||
Global.gfx_envmap_enabled = true;
|
||||
Global.gfx_postfx_motionblur_enabled = true;
|
||||
Global.gfx_skippipeline = false;
|
||||
Global.gfx_extraeffects = true;
|
||||
Global.gfx_shadergamma = true;
|
||||
if (!check_shader(filename))
|
||||
set_features(true);
|
||||
if (!check_text(source({}, gl::glsl_common + gl::glsl_settings_defines()), {}))
|
||||
suc = false;
|
||||
|
||||
std::cout << "done, features off..." << std::flush;
|
||||
Global.gfx_shadowmap_enabled = false;
|
||||
Global.gfx_envmap_enabled = false;
|
||||
Global.gfx_postfx_motionblur_enabled = false;
|
||||
Global.gfx_skippipeline = true;
|
||||
Global.gfx_extraeffects = false;
|
||||
Global.gfx_shadergamma = false;
|
||||
if (!check_shader(filename))
|
||||
set_features(false);
|
||||
if (!check_text(source({}, gl::glsl_common + gl::glsl_settings_defines()), {}))
|
||||
suc = false;
|
||||
|
||||
// the variant of the vertex and fragment stages the multi draws of the instances use (model blocks by gl_DrawID)
|
||||
auto const ext{std::filesystem::path(filename).extension()};
|
||||
if (ext == ".vert" || ext == ".frag")
|
||||
bool const variants{(stage == gfx::shader_stage::vertex) || (stage == gfx::shader_stage::fragment)};
|
||||
if (variants)
|
||||
{
|
||||
std::cout << "done, model draws..." << std::flush;
|
||||
Global.gfx_shadowmap_enabled = true;
|
||||
Global.gfx_envmap_enabled = true;
|
||||
Global.gfx_postfx_motionblur_enabled = true;
|
||||
Global.gfx_skippipeline = false;
|
||||
Global.gfx_extraeffects = true;
|
||||
Global.gfx_shadergamma = true;
|
||||
if (!check_shader(filename, "#define MODEL_DRAWS 1\n"))
|
||||
set_features(true);
|
||||
if (!check_text(source("#define MODEL_DRAWS 1\n", gl::glsl_common + gl::glsl_settings_defines()), {}))
|
||||
suc = false;
|
||||
}
|
||||
|
||||
std::cout << "done" << std::flush;
|
||||
|
||||
return suc;
|
||||
}
|
||||
|
||||
|
||||
bool check_shader_confs(std::string filename)
|
||||
{
|
||||
bool suc = true;
|
||||
|
||||
std::cout << "desktop GL: " << std::flush;
|
||||
if (!check_shader_allopts(filename))
|
||||
std::cout << "done, spir-v..." << std::flush;
|
||||
if (!check_text(source({}, {}), "-G"))
|
||||
suc = false;
|
||||
if (variants && !check_text(source("#define MODEL_DRAWS 1\n", {}), "-G"))
|
||||
suc = false;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "done" << std::flush;
|
||||
return suc;
|
||||
}
|
||||
|
||||
// a shader of the vulkan renderer, compiled to SPIR-V for vulkan as the game does it (and as glslc makes the binaries of
|
||||
// shaders/vk14bin)
|
||||
bool check_vk14(std::string const &Name)
|
||||
{
|
||||
std::cout << "spir-v..." << std::flush;
|
||||
auto const suc{check_text(gfx::preprocess_shader(gfx::shader_api::vulkan14, Name, {}, {}, false, vk14_dir), "-V --target-env " + vulkan_env)};
|
||||
std::cout << "done" << std::flush;
|
||||
return suc;
|
||||
}
|
||||
|
||||
bool is_stage(std::filesystem::path const &Path)
|
||||
{
|
||||
auto const ext = Path.extension();
|
||||
return (ext == ".frag" || ext == ".geom" || ext == ".vert" || ext == ".comp");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main()
|
||||
{
|
||||
if (system("glslangValidator --version > /dev/null 2>&1") != 0)
|
||||
@@ -111,23 +136,64 @@ int main()
|
||||
std::cerr << "glslangValidator not found in PATH" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
std::ofstream file("/tmp/shader_env.vert");
|
||||
file << "#version 460\nvoid main() { gl_Position = vec4(0.0); }\n";
|
||||
}
|
||||
if (system("glslangValidator -V --target-env vulkan1.4 /tmp/shader_env.vert -o /tmp/shader_env.spv > /dev/null 2>&1") != 0)
|
||||
{
|
||||
vulkan_env = "vulkan1.3";
|
||||
std::cout << "== glslangValidator doesn't know vulkan 1.4, the vulkan shaders are checked against vulkan 1.3" << std::endl;
|
||||
}
|
||||
|
||||
bool suc = true;
|
||||
std::vector<std::string> 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();
|
||||
auto const ext = f.path().extension();
|
||||
if (ext != ".frag" && ext != ".geom" && ext != ".vert" && ext != ".comp")
|
||||
continue;
|
||||
// the binaries are compiled with the constants written in common.glsl, the game compiles the sources with its own
|
||||
gl::glsl_common_setup();
|
||||
std::vector<std::string> differences;
|
||||
std::cout << "== constants of shaders/ogl46/common.glsl: " << std::flush;
|
||||
if (gl::glsl_common_matches(ogl46_dir, differences))
|
||||
{
|
||||
std::cout << "the same as in the game" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "not the same as in the game:" << std::endl;
|
||||
for (auto const &difference : differences)
|
||||
std::cout << " " << difference << std::endl;
|
||||
suc = false;
|
||||
failed.push_back("common.glsl");
|
||||
}
|
||||
|
||||
std::cout << "== validating shader " << relative << ": " << std::flush;
|
||||
if (!check_shader_confs(relative))
|
||||
for (auto const &[directory, api] : {std::pair{ogl46_dir, gfx::shader_api::opengl46}, std::pair{vk14_dir, gfx::shader_api::vulkan14}})
|
||||
{
|
||||
if (false == std::filesystem::is_directory(directory))
|
||||
continue;
|
||||
std::vector<std::string> names;
|
||||
for (auto &f : std::filesystem::directory_iterator(directory))
|
||||
if (f.is_regular_file() && is_stage(f.path()))
|
||||
names.push_back(f.path().filename().string());
|
||||
std::sort(names.begin(), names.end());
|
||||
for (auto const &name : names)
|
||||
{
|
||||
suc = false;
|
||||
failed.push_back(relative);
|
||||
auto const label{std::string(api == gfx::shader_api::opengl46 ? "ogl46/" : "vk14/") + name};
|
||||
std::cout << "== validating shader " << label << ": " << std::flush;
|
||||
bool ok{false};
|
||||
try
|
||||
{
|
||||
ok = (api == gfx::shader_api::opengl46 ? check_ogl46(name) : check_vk14(name));
|
||||
}
|
||||
catch (std::exception const &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
if (!ok)
|
||||
{
|
||||
suc = false;
|
||||
failed.push_back(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user