Shaders: Scan source code in as few passes as possible.

Improves loading time of crt-royale significantly.
This commit is contained in:
Brandon Wright 2019-01-30 10:25:19 -06:00
parent f825f14a06
commit fc31f47fc2
5 changed files with 121 additions and 175 deletions

View File

@ -7,6 +7,7 @@
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#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<std::string> &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<std::string> &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<std::string> &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<std::string> &lines,
@ -364,7 +464,7 @@ bool GLSLShader::load_shader(char *filename)
strcpy(p->filename, temp);
std::vector<std::string> 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");

View File

@ -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<std::string> &lines);
void read_shader_file_with_includes(std::string filename,
std::vector<std::string> &lines,
int p);
GLuint compile_shader(std::vector<std::string> &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<std::string> &lines,
std::string name);
void slang_parse_pragmas(std::vector<std::string> &lines, int p);
GLint slang_compile(std::vector<std::string> &lines, std::string stage);
void slang_introspect();
void slang_set_shader_vars(int p, bool inverted);

View File

@ -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<std::string> &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;
}

View File

@ -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<std::string> &lines);
#endif // __SHADER_HELPERS_H

View File

@ -25,7 +25,7 @@ std::string GLSLShader::slang_get_stage(std::vector<std::string> &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<std::string> &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<SlangUniform> &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<std::string> &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,