Refactor code for glslang shader presets - buffer entire file

into memory before passing it on
This commit is contained in:
twinaphex 2019-08-08 04:55:22 +02:00
parent 05fecc4e15
commit 0fee6a9ef4
5 changed files with 127 additions and 24 deletions

View File

@ -38,7 +38,7 @@
using namespace std; using namespace std;
bool glslang_read_shader_file(const char *path, vector<string> *output, bool root_file) static bool glslang_read_shader_file(const char *path, vector<string> *output, bool root_file)
{ {
vector<const char *> lines; vector<const char *> lines;
char include_path[PATH_MAX_LENGTH]; char include_path[PATH_MAX_LENGTH];
@ -283,6 +283,113 @@ static glslang_format glslang_find_format(const char *fmt)
return SLANG_FORMAT_UNKNOWN; return SLANG_FORMAT_UNKNOWN;
} }
bool glslang_parse_meta(void *data, glslang_meta *meta)
{
char id[64];
char desc[64];
size_t line_index = 0;
struct string_list *lines = (struct string_list*)data;
id[0] = desc[0] = '\0';
*meta = glslang_meta{};
while (line_index < lines->size)
{
const char *line_c = lines->elems[line_index].data;
line_index++;
if (!strncmp("#pragma name", line_c, STRLEN_CONST("#pragma name")))
{
const char *str = NULL;
if (!meta->name.empty())
{
RARCH_ERR("[slang]: Trying to declare multiple names for file.\n");
string_list_free(lines);
return false;
}
str = line_c + STRLEN_CONST("#pragma name ");
while (*str == ' ')
str++;
meta->name = str;
}
if (!strncmp("#pragma parameter", line_c, STRLEN_CONST("#pragma parameter")))
{
float initial, minimum, maximum, step;
int ret = sscanf(line_c, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f",
id, desc, &initial, &minimum, &maximum, &step);
if (ret == 5)
{
step = 0.1f * (maximum - minimum);
ret = 6;
}
if (ret == 6)
{
auto itr = find_if(begin(meta->parameters), end(meta->parameters), [&](const glslang_parameter &param) {
return param.id == id;
});
/* Allow duplicate #pragma parameter, but only
* if they are exactly the same. */
if (itr != end(meta->parameters))
{
if ( itr->desc != desc ||
itr->initial != initial ||
itr->minimum != minimum ||
itr->maximum != maximum ||
itr->step != step
)
{
RARCH_ERR("[slang]: Duplicate parameters found for \"%s\", but arguments do not match.\n", id);
string_list_free(lines);
return false;
}
}
else
meta->parameters.push_back({ id, desc, initial, minimum, maximum, step });
}
else
{
RARCH_ERR("[slang]: Invalid #pragma parameter line: \"%s\".\n", line_c);
string_list_free(lines);
return false;
}
}
else if (!strncmp("#pragma format", line_c, STRLEN_CONST("#pragma format")))
{
const char *str = NULL;
if (meta->rt_format != SLANG_FORMAT_UNKNOWN)
{
RARCH_ERR("[slang]: Trying to declare format multiple times for file.\n");
string_list_free(lines);
return false;
}
str = line_c + STRLEN_CONST("#pragma format ");
while (*str == ' ')
str++;
meta->rt_format = glslang_find_format(str);
if (meta->rt_format == SLANG_FORMAT_UNKNOWN)
{
RARCH_ERR("[slang]: Failed to find format \"%s\".\n", str);
string_list_free(lines);
return false;
}
}
}
string_list_free(lines);
return true;
}
bool glslang_parse_meta(const vector<string> &lines, glslang_meta *meta) bool glslang_parse_meta(const vector<string> &lines, glslang_meta *meta)
{ {
char id[64]; char id[64];

View File

@ -105,9 +105,8 @@ struct glslang_output
bool glslang_compile_shader(const char *shader_path, glslang_output *output); bool glslang_compile_shader(const char *shader_path, glslang_output *output);
/* Helpers for internal use. */
bool glslang_read_shader_file(const char *path, std::vector<std::string> *output, bool root_file);
bool glslang_parse_meta(const std::vector<std::string> &lines, glslang_meta *meta); bool glslang_parse_meta(const std::vector<std::string> &lines, glslang_meta *meta);
bool glslang_parse_meta(void *data, glslang_meta *meta);
#endif #endif
void *config_file_new_wrapper(const char *path); void *config_file_new_wrapper(const char *path);

View File

@ -89,14 +89,11 @@ bool slang_preprocess_parse_parameters(glslang_meta& meta,
return true; return true;
} }
bool slang_preprocess_parse_parameters(const char *shader_path, bool slang_preprocess_parse_parameters(void *data, struct video_shader *shader)
struct video_shader *shader)
{ {
glslang_meta meta; glslang_meta meta;
vector<string> lines; struct string_list *lines = (struct string_list*)data;
if (!glslang_read_shader_file(shader_path, &lines, true))
return false;
if (!glslang_parse_meta(lines, &meta)) if (!glslang_parse_meta(lines, &meta))
return false; return false;
return slang_preprocess_parse_parameters(meta, shader); return slang_preprocess_parse_parameters(meta, shader);

View File

@ -26,7 +26,7 @@ RETRO_BEGIN_DECLS
/* Utility function to implement the same parameter reflection /* Utility function to implement the same parameter reflection
* which happens in the slang backend. * which happens in the slang backend.
* This does preprocess over the input file to handle #includes and so on. */ * This does preprocess over the input file to handle #includes and so on. */
bool slang_preprocess_parse_parameters(const char *shader_path, bool slang_preprocess_parse_parameters(void *data,
struct video_shader *shader); struct video_shader *shader);
RETRO_END_DECLS RETRO_END_DECLS

View File

@ -496,20 +496,6 @@ bool video_shader_resolve_parameters(config_file_t *conf,
if (!path_is_valid(path)) if (!path_is_valid(path))
continue; continue;
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
/* First try to use the more robust slang
* implementation to support #includes. */
/* FIXME: The check for slang can be removed
* if it's sufficiently tested for
* GLSL/Cg as well, it should be the same implementation. */
if (string_is_equal(path_get_extension(path), "slang") &&
slang_preprocess_parse_parameters(path, shader))
continue;
/* If that doesn't work, fallback to the old path.
* Ideally, we'd get rid of this path sooner or later. */
#endif
/* Read file contents */ /* Read file contents */
if (!filestream_read_file(path, (void**)&buf, &buf_len)) if (!filestream_read_file(path, (void**)&buf, &buf_len))
continue; continue;
@ -525,7 +511,21 @@ bool video_shader_resolve_parameters(config_file_t *conf,
if (!lines) if (!lines)
continue; continue;
/* even though the pass is set in the loop too, not all passes have parameters */ #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
/* First try to use the more robust slang
* implementation to support #includes. */
/* FIXME: The check for slang can be removed
* if it's sufficiently tested for
* GLSL/Cg as well, it should be the same implementation. */
if (string_is_equal(path_get_extension(path), "slang") &&
slang_preprocess_parse_parameters(lines, shader))
continue;
/* If that doesn't work, fallback to the old path.
* Ideally, we'd get rid of this path sooner or later. */
#endif
/* even though the pass is set in the loop too, not all
* passes have parameters */
param->pass = i; param->pass = i;
while ((shader->num_parameters < ARRAY_SIZE(shader->parameters)) && while ((shader->num_parameters < ARRAY_SIZE(shader->parameters)) &&