From fc31f47fc2e20c1ac93dc24b988677c25bc67cc3 Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Wed, 30 Jan 2019 10:25:19 -0600 Subject: [PATCH] Shaders: Scan source code in as few passes as possible. Improves loading time of crt-royale significantly. --- shaders/glsl.cpp | 138 +++++++++++++++++++++++++++++++------ shaders/glsl.h | 5 +- shaders/shader_helpers.cpp | 81 ---------------------- shaders/shader_helpers.h | 1 - shaders/slang.cpp | 71 +------------------ 5 files changed, 121 insertions(+), 175 deletions(-) diff --git a/shaders/glsl.cpp b/shaders/glsl.cpp index 0146389e..330db68e 100644 --- a/shaders/glsl.cpp +++ b/shaders/glsl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "glsl.h" #include "../../conffile.h" #include "shader_helpers.h" @@ -250,18 +251,99 @@ bool GLSLShader::load_shader_preset_file(char *filename) return true; } -void GLSLShader::strip_parameter_pragmas(std::vector &lines) +static std::string folder_from_path(std::string filename) { - // #pragma parameter lines tend to have " characters in them, - // which is not legal GLSL. - auto it = lines.begin(); - while (it != lines.end()) - { - if (it->find("#pragma parameter") != std::string::npos) + for (int i = filename.length() - 1; i >= 0; i--) + if (filename[i] == '\\' || filename[i] == '/') + return filename.substr(0, i); + + return std::string("."); +} + +static std::string canonicalize(const std::string &noncanonical) +{ + char *temp = realpath(noncanonical.c_str(), NULL); + std::string filename_string(temp); + free(temp); + return filename_string; +} + +static GLuint string_to_format(char *format) +{ +#define MATCH(s, f) \ + if (!strcmp(format, s)) \ + return f; + MATCH("R8_UNORM", GL_R8); + MATCH("R8_UINT", GL_R8UI); + MATCH("R8_SINT", GL_R8I); + MATCH("R8G8_UNORM", GL_RG8); + MATCH("R8G8_UINT", GL_RG8UI); + MATCH("R8G8_SINT", GL_RG8I); + MATCH("R8G8B8A8_UNORM", GL_RGBA8); + MATCH("R8G8B8A8_UINT", GL_RGBA8UI); + MATCH("R8G8B8A8_SINT", GL_RGBA8I); + MATCH("R8G8B8A8_SRGB", GL_SRGB8_ALPHA8); + + MATCH("A2B10G10R10_UNORM_PACK32", GL_RGB10_A2); + MATCH("A2B10G10R10_UINT_PACK32", GL_RGB10_A2UI); + + MATCH("R16_UINT", GL_R16UI); + MATCH("R16_SINT", GL_R16I); + MATCH("R16_SFLOAT", GL_R16F); + MATCH("R16G16_UINT", GL_RG16UI); + MATCH("R16G16_SINT", GL_RG16I); + MATCH("R16G16_SFLOAT", GL_RG16F); + MATCH("R16G16B16A16_UINT", GL_RGBA16UI); + MATCH("R16G16B16A16_SINT", GL_RGBA16I); + MATCH("R16G16B16A16_SFLOAT", GL_RGBA16F); + + MATCH("R32_UINT", GL_R32UI); + MATCH("R32_SINT", GL_R32I); + MATCH("R32_SFLOAT", GL_R32F); + MATCH("R32G32_UINT", GL_RG32UI); + MATCH("R32G32_SINT", GL_RG32I); + MATCH("R32G32_SFLOAT", GL_RG32F); + MATCH("R32G32B32A32_UINT", GL_RGBA32UI); + MATCH("R32G32B32A32_SINT", GL_RGBA32I); + MATCH("R32G32B32A32_SFLOAT", GL_RGBA32F); + + return GL_RGBA; +} + +// filename must be canonical +void GLSLShader::read_shader_file_with_includes(std::string filename, + std::vector &lines, + int p) +{ + std::ifstream ss(filename); + + if (ss.fail()) + { + printf ("Couldn't open file \"%s\"\n", filename.c_str()); + return; + } + + std::string line; + + while (std::getline(ss, line, '\n')) + { + if (line.empty()) + continue; + + if (line.compare(0, 8, "#include") == 0) + { + char tmp[PATH_MAX]; + sscanf(line.c_str(), "#include \"%[^\"]\"", tmp); + + std::string fullpath = canonicalize(folder_from_path(filename) + "/" + tmp); + read_shader_file_with_includes(fullpath.c_str(), lines, p); + continue; + } + else if (line.compare(0, 17, "#pragma parameter") == 0) { GLSLParam par; - sscanf(it->c_str(), "#pragma parameter %s \"%[^\"]\" %f %f %f %f", + sscanf(line.c_str(), "#pragma parameter %s \"%[^\"]\" %f %f %f %f", par.id, par.name, &par.val, &par.min, &par.max, &par.step); if (par.step == 0.0f) @@ -275,12 +357,30 @@ void GLSLShader::strip_parameter_pragmas(std::vector &lines) } if (i >= param.size()) param.push_back(par); - - it = lines.erase(it); + continue; } - else - ++it; - } +#ifdef USE_SLANG + else if (line.compare(0, 12, "#pragma name") == 0) + { + sscanf(line.c_str(), "#pragma name %255s", pass[p].alias); + continue; + } + else if (line.compare(0, 14, "#pragma format") == 0) + { + char format[256]; + sscanf(line.c_str(), "#pragma format %255s", format); + pass[p].format = string_to_format(format); + if (pass[p].format == GL_RGBA16F || pass[p].format == GL_RGBA32F) + pass[p].fp = TRUE; + else if (pass[p].format == GL_SRGB8_ALPHA8) + pass[p].srgb = TRUE; + continue; + } +#endif + lines.push_back(line); + } + + return; } GLuint GLSLShader::compile_shader(std::vector &lines, @@ -364,7 +464,7 @@ bool GLSLShader::load_shader(char *filename) strcpy(p->filename, temp); std::vector lines; - read_shader_file_with_includes(p->filename, lines); + read_shader_file_with_includes(p->filename, lines, i); if (lines.empty()) { @@ -372,13 +472,9 @@ bool GLSLShader::load_shader(char *filename) return false; } - strip_parameter_pragmas(lines); - #ifdef USE_SLANG if (using_slang) { - slang_parse_pragmas(lines, i); - GLint retval; retval = slang_compile(lines, "vertex"); if (retval < 0) @@ -1064,9 +1160,9 @@ void GLSLShader::clear_shader_vars() vaos.clear(); } -#define outs(s, v) fprintf (file, "%s%d = \"%s\"\n", s, i, v) -#define outf(s, v) fprintf (file, "%s%d = \"%f\"\n", s, i, v) -#define outd(s, v) fprintf (file, "%s%d = \"%d\"\n", s, i, v) +#define outs(s, v) fprintf(file, "%s%d = \"%s\"\n", s, i, v) +#define outf(s, v) fprintf(file, "%s%d = \"%f\"\n", s, i, v) +#define outd(s, v) fprintf(file, "%s%d = \"%d\"\n", s, i, v) void GLSLShader::save(const char *filename) { FILE *file = fopen(filename, "wb"); diff --git a/shaders/glsl.h b/shaders/glsl.h index 74441e58..33f005f1 100644 --- a/shaders/glsl.h +++ b/shaders/glsl.h @@ -163,7 +163,9 @@ typedef struct GLSLViewportCallback vpcallback); void set_shader_vars(unsigned int pass, bool inverted); void clear_shader_vars(); - void strip_parameter_pragmas(std::vector &lines); + void read_shader_file_with_includes(std::string filename, + std::vector &lines, + int p); GLuint compile_shader(std::vector &lines, const char *aliases, const char *defines, GLuint type, GLuint *out); void save(const char *filename); @@ -186,7 +188,6 @@ typedef struct #ifdef USE_SLANG std::string slang_get_stage(std::vector &lines, std::string name); - void slang_parse_pragmas(std::vector &lines, int p); GLint slang_compile(std::vector &lines, std::string stage); void slang_introspect(); void slang_set_shader_vars(int p, bool inverted); diff --git a/shaders/shader_helpers.cpp b/shaders/shader_helpers.cpp index 545f366d..76b6519f 100644 --- a/shaders/shader_helpers.cpp +++ b/shaders/shader_helpers.cpp @@ -242,85 +242,4 @@ void reduce_to_path(char *filename) } } -static std::string folder_from_path(std::string filename) -{ - for (int i = filename.length() - 1; i >= 0; i--) - if (filename[i] == '\\' || filename[i] == '/') - return filename.substr(0, i); - return std::string("."); -} - -static char *read_file(const char *filename) -{ - FILE *file = NULL; - int size; - char *contents; - - file = fopen(filename, "rb"); - if (!file) - { - printf ("File not found: \"%s\"\n", filename); - return NULL; - } - - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, 0, SEEK_SET); - - contents = new char[size + 1]; - fread(contents, size, 1, file); - contents[size] = '\0'; - fclose(file); - - return contents; -} - -static std::string canonicalize(const std::string &noncanonical) -{ - char *temp = realpath(noncanonical.c_str(), NULL); - std::string filename_string(temp); - free(temp); - return filename_string; -} - -// filename must be canonical -void read_shader_file_with_includes(std::string filename, - std::vector &lines) -{ - char *file_contents = read_file(filename.c_str()); - if (!file_contents) - return; - - std::string string_contents(file_contents); - delete[] file_contents; - - for (char &c : string_contents) - { - if (c == '\r') - c = '\n'; - } - - std::istringstream ss(string_contents); - std::string line; - - while (std::getline(ss, line, '\n')) - { - if (line.empty()) - continue; - - if (line.find("#include") == 0) - { - char tmp[PATH_MAX]; - sscanf(line.c_str(), "#include \"%[^\"]\"", tmp); - - std::string fullpath = canonicalize(folder_from_path(filename) + "/" + tmp); - read_shader_file_with_includes(fullpath.c_str(), lines); - continue; - } - - lines.push_back(line); - } - - return; -} diff --git a/shaders/shader_helpers.h b/shaders/shader_helpers.h index ca0a11ef..ce0e20f7 100644 --- a/shaders/shader_helpers.h +++ b/shaders/shader_helpers.h @@ -48,6 +48,5 @@ bool gl_srgb_available(); int gl_version(); bool gl_float_texture_available(); void reduce_to_path(char* filename); -void read_shader_file_with_includes(std::string filename, std::vector &lines); #endif // __SHADER_HELPERS_H diff --git a/shaders/slang.cpp b/shaders/slang.cpp index a61b886e..27b2ce4c 100644 --- a/shaders/slang.cpp +++ b/shaders/slang.cpp @@ -25,7 +25,7 @@ std::string GLSLShader::slang_get_stage(std::vector &lines, for (auto &line : lines) { - if (line.find("#pragma stage") != std::string::npos) + if (line.compare(0, 13, "#pragma stage") == 0) { if (line.find(std::string("#pragma stage ") + name) != std::string::npos) @@ -33,10 +33,6 @@ std::string GLSLShader::slang_get_stage(std::vector &lines, else in_stage = false; } - else if (line.find("#pragma name") != std::string::npos || - line.find("#pragma format") != std::string::npos) - { - } else if (in_stage) { output << line << '\n'; @@ -85,71 +81,6 @@ static void printuniforms(std::vector &unif) } } -static GLuint string_to_format(char *format) -{ -#define MATCH(s, f) \ - if (!strcmp(format, s)) \ - return f; - MATCH("R8_UNORM", GL_R8); - MATCH("R8_UINT", GL_R8UI); - MATCH("R8_SINT", GL_R8I); - MATCH("R8G8_UNORM", GL_RG8); - MATCH("R8G8_UINT", GL_RG8UI); - MATCH("R8G8_SINT", GL_RG8I); - MATCH("R8G8B8A8_UNORM", GL_RGBA8); - MATCH("R8G8B8A8_UINT", GL_RGBA8UI); - MATCH("R8G8B8A8_SINT", GL_RGBA8I); - MATCH("R8G8B8A8_SRGB", GL_SRGB8_ALPHA8); - - MATCH("A2B10G10R10_UNORM_PACK32", GL_RGB10_A2); - MATCH("A2B10G10R10_UINT_PACK32", GL_RGB10_A2UI); - - MATCH("R16_UINT", GL_R16UI); - MATCH("R16_SINT", GL_R16I); - MATCH("R16_SFLOAT", GL_R16F); - MATCH("R16G16_UINT", GL_RG16UI); - MATCH("R16G16_SINT", GL_RG16I); - MATCH("R16G16_SFLOAT", GL_RG16F); - MATCH("R16G16B16A16_UINT", GL_RGBA16UI); - MATCH("R16G16B16A16_SINT", GL_RGBA16I); - MATCH("R16G16B16A16_SFLOAT", GL_RGBA16F); - - MATCH("R32_UINT", GL_R32UI); - MATCH("R32_SINT", GL_R32I); - MATCH("R32_SFLOAT", GL_R32F); - MATCH("R32G32_UINT", GL_RG32UI); - MATCH("R32G32_SINT", GL_RG32I); - MATCH("R32G32_SFLOAT", GL_RG32F); - MATCH("R32G32B32A32_UINT", GL_RGBA32UI); - MATCH("R32G32B32A32_SINT", GL_RGBA32I); - MATCH("R32G32B32A32_SFLOAT", GL_RGBA32F); - - return GL_RGBA; -} - -void GLSLShader::slang_parse_pragmas(std::vector &lines, int p) -{ - pass[p].format = GL_RGBA; - - for (auto &line : lines) - { - if (line.find("#pragma name") != std::string::npos) - { - sscanf(line.c_str(), "#pragma name %255s", pass[p].alias); - } - else if (line.find("#pragma format") != std::string::npos) - { - char format[256]; - sscanf(line.c_str(), "#pragma format %255s", format); - pass[p].format = string_to_format(format); - if (pass[p].format == GL_RGBA16F || pass[p].format == GL_RGBA32F) - pass[p].fp = TRUE; - else if (pass[p].format == GL_SRGB8_ALPHA8) - pass[p].srgb = TRUE; - } - } -} - static const TBuiltInResource DefaultTBuiltInResource = { /* .MaxLights = */ 32, /* .MaxClipPlanes = */ 6,