mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 03:32:46 +00:00
Kill support for XML shaders.
Long overdue ...
This commit is contained in:
parent
42d501fae1
commit
25e56d8db0
@ -1354,8 +1354,8 @@ static int menu_common_iterate(void *data, unsigned action)
|
||||
else
|
||||
{
|
||||
unsigned pass = (menu_type - RGUI_SETTINGS_SHADER_0) / 3;
|
||||
fill_pathname_join(rgui->shader.pass[pass].source.cg,
|
||||
dir, path, sizeof(rgui->shader.pass[pass].source.cg));
|
||||
fill_pathname_join(rgui->shader.pass[pass].source.path,
|
||||
dir, path, sizeof(rgui->shader.pass[pass].source.path));
|
||||
}
|
||||
|
||||
// Pop stack until we hit shader manager again.
|
||||
@ -1662,8 +1662,8 @@ static void menu_common_shader_manager_init(void *data)
|
||||
}
|
||||
else if (strcmp(ext, "glsl") == 0 || strcmp(ext, "cg") == 0)
|
||||
{
|
||||
strlcpy(rgui->shader.pass[0].source.cg, g_settings.video.shader_path,
|
||||
sizeof(rgui->shader.pass[0].source.cg));
|
||||
strlcpy(rgui->shader.pass[0].source.path, g_settings.video.shader_path,
|
||||
sizeof(rgui->shader.pass[0].source.path));
|
||||
rgui->shader.passes = 1;
|
||||
}
|
||||
else
|
||||
@ -1749,9 +1749,9 @@ static void menu_common_shader_manager_get_str(void *data, char *type_str, size_
|
||||
switch ((type - RGUI_SETTINGS_SHADER_0) % 3)
|
||||
{
|
||||
case 0:
|
||||
if (*shader->pass[pass].source.cg)
|
||||
if (*shader->pass[pass].source.path)
|
||||
fill_pathname_base(type_str,
|
||||
shader->pass[pass].source.cg, type_str_size);
|
||||
shader->pass[pass].source.path, type_str_size);
|
||||
else
|
||||
strlcpy(type_str, "N/A", type_str_size);
|
||||
break;
|
||||
@ -1887,7 +1887,7 @@ static unsigned menu_common_shader_manager_get_type(void *data)
|
||||
|
||||
for (i = 0; i < shader->passes; i++)
|
||||
{
|
||||
enum rarch_shader_type pass_type = gfx_shader_parse_type(shader->pass[i].source.cg,
|
||||
enum rarch_shader_type pass_type = gfx_shader_parse_type(shader->pass[i].source.path,
|
||||
RARCH_SHADER_NONE);
|
||||
|
||||
switch (pass_type)
|
||||
@ -1960,7 +1960,7 @@ static int menu_common_shader_manager_setting_toggle(void *data, unsigned settin
|
||||
|
||||
case RGUI_ACTION_START:
|
||||
if (pass)
|
||||
*pass->source.cg = '\0';
|
||||
*pass->source.path = '\0';
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -479,7 +479,7 @@ static bool load_plain(const char *path)
|
||||
if (path)
|
||||
{
|
||||
RARCH_LOG("Loading Cg file: %s\n", path);
|
||||
strlcpy(cg_shader->pass[0].source.cg, path, sizeof(cg_shader->pass[0].source.cg));
|
||||
strlcpy(cg_shader->pass[0].source.path, path, sizeof(cg_shader->pass[0].source.path));
|
||||
if (!load_program(1, path, true))
|
||||
return false;
|
||||
}
|
||||
@ -546,9 +546,9 @@ static bool load_imports(void)
|
||||
static bool load_shader(unsigned i)
|
||||
{
|
||||
RARCH_LOG("Loading Cg shader: \"%s\".\n",
|
||||
cg_shader->pass[i].source.cg);
|
||||
cg_shader->pass[i].source.path);
|
||||
|
||||
if (!load_program(i + 1, cg_shader->pass[i].source.cg, true))
|
||||
if (!load_program(i + 1, cg_shader->pass[i].source.path, true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -415,11 +415,11 @@ static GLuint compile_program(const char *vertex, const char *fragment, unsigned
|
||||
|
||||
static bool load_source_path(struct gfx_shader_pass *pass, const char *path)
|
||||
{
|
||||
if (read_file(path, (void**)&pass->source.xml.vertex) <= 0)
|
||||
if (read_file(path, (void**)&pass->source.string.vertex) <= 0)
|
||||
return false;
|
||||
|
||||
pass->source.xml.fragment = strdup(pass->source.xml.vertex);
|
||||
return pass->source.xml.fragment && pass->source.xml.vertex;
|
||||
pass->source.string.fragment = strdup(pass->source.string.vertex);
|
||||
return pass->source.string.fragment && pass->source.string.vertex;
|
||||
}
|
||||
|
||||
static bool compile_programs(GLuint *gl_prog)
|
||||
@ -432,15 +432,15 @@ static bool compile_programs(GLuint *gl_prog)
|
||||
// If we load from GLSLP (CGP),
|
||||
// load the file here, and pretend
|
||||
// we were really using XML all along.
|
||||
if (*pass->source.cg && !load_source_path(pass, pass->source.cg))
|
||||
if (*pass->source.path && !load_source_path(pass, pass->source.path))
|
||||
{
|
||||
RARCH_ERR("Failed to load GLSL shader: %s.\n", pass->source.cg);
|
||||
RARCH_ERR("Failed to load GLSL shader: %s.\n", pass->source.path);
|
||||
return false;
|
||||
}
|
||||
*pass->source.cg = '\0';
|
||||
*pass->source.path = '\0';
|
||||
|
||||
const char *vertex = pass->source.xml.vertex;
|
||||
const char *fragment = pass->source.xml.fragment;
|
||||
const char *vertex = pass->source.string.vertex;
|
||||
const char *fragment = pass->source.string.fragment;
|
||||
|
||||
gl_prog[i] = compile_program(vertex, fragment, i);
|
||||
|
||||
@ -588,8 +588,8 @@ static void gl_glsl_free_shader(void)
|
||||
|
||||
for (i = 0; i < glsl_shader->passes; i++)
|
||||
{
|
||||
free(glsl_shader->pass[i].source.xml.vertex);
|
||||
free(glsl_shader->pass[i].source.xml.fragment);
|
||||
free(glsl_shader->pass[i].source.string.vertex);
|
||||
free(glsl_shader->pass[i].source.string.fragment);
|
||||
}
|
||||
|
||||
free(glsl_shader->script);
|
||||
@ -667,7 +667,7 @@ static bool gl_glsl_init(void *data, const char *path)
|
||||
bool ret;
|
||||
if (strcmp(path_get_extension(path), "glsl") == 0)
|
||||
{
|
||||
strlcpy(glsl_shader->pass[0].source.cg, path, sizeof(glsl_shader->pass[0].source.cg));
|
||||
strlcpy(glsl_shader->pass[0].source.path, path, sizeof(glsl_shader->pass[0].source.path));
|
||||
glsl_shader->passes = 1;
|
||||
glsl_shader->modern = true;
|
||||
ret = true;
|
||||
@ -685,7 +685,7 @@ static bool gl_glsl_init(void *data, const char *path)
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
ret = gfx_shader_read_xml(path, glsl_shader);
|
||||
ret = false;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
@ -697,8 +697,8 @@ static bool gl_glsl_init(void *data, const char *path)
|
||||
{
|
||||
RARCH_WARN("[GL]: Stock GLSL shaders will be used.\n");
|
||||
glsl_shader->passes = 1;
|
||||
glsl_shader->pass[0].source.xml.vertex = strdup(glsl_core ? stock_vertex_core : stock_vertex_modern);
|
||||
glsl_shader->pass[0].source.xml.fragment = strdup(glsl_core ? stock_fragment_core : stock_fragment_modern);
|
||||
glsl_shader->pass[0].source.string.vertex = strdup(glsl_core ? stock_vertex_core : stock_vertex_modern);
|
||||
glsl_shader->pass[0].source.string.fragment = strdup(glsl_core ? stock_fragment_core : stock_fragment_modern);
|
||||
glsl_shader->modern = true;
|
||||
}
|
||||
|
||||
|
@ -20,14 +20,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_LIBXML2
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#else
|
||||
#define RXML_LIBXML2_COMPAT
|
||||
#include "../compat/rxml/rxml.h"
|
||||
#endif
|
||||
|
||||
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
|
||||
|
||||
static const char *wrap_mode_to_str(enum gfx_wrap_type type)
|
||||
@ -71,7 +63,7 @@ static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass,
|
||||
// Source
|
||||
char shader_name[64];
|
||||
print_buf(shader_name, "shader%u", i);
|
||||
if (!config_get_path(conf, shader_name, pass->source.cg, sizeof(pass->source.cg)))
|
||||
if (!config_get_path(conf, shader_name, pass->source.path, sizeof(pass->source.path)))
|
||||
{
|
||||
RARCH_ERR("Couldn't parse shader source (%s).\n", shader_name);
|
||||
return false;
|
||||
@ -410,539 +402,6 @@ bool gfx_shader_read_conf_cgp(config_file_t *conf, struct gfx_shader *shader)
|
||||
return true;
|
||||
}
|
||||
|
||||
// XML shaders
|
||||
static bool xml_get_prop(char *buf, size_t size, xmlNodePtr node, const char *prop)
|
||||
{
|
||||
if (!size)
|
||||
return false;
|
||||
|
||||
xmlChar *p = xmlGetProp(node, (const xmlChar*)prop);
|
||||
if (p)
|
||||
{
|
||||
bool ret = strlcpy(buf, (const char*)p, size) < size;
|
||||
xmlFree(p);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static char *xml_get_content(xmlNodePtr node)
|
||||
{
|
||||
xmlChar *content = xmlNodeGetContent(node);
|
||||
if (!content)
|
||||
return NULL;
|
||||
|
||||
char *ret = strdup((const char*)content);
|
||||
xmlFree(content);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *xml_replace_if_file(char *content, const char *path, xmlNodePtr node, const char *src_prop)
|
||||
{
|
||||
char prop[PATH_MAX];
|
||||
if (!xml_get_prop(prop, sizeof(prop), node, src_prop))
|
||||
return content;
|
||||
|
||||
free(content);
|
||||
content = NULL;
|
||||
|
||||
char shader_path[PATH_MAX];
|
||||
fill_pathname_resolve_relative(shader_path, path, prop, sizeof(shader_path));
|
||||
|
||||
RARCH_LOG("Loading external source from \"%s\".\n", shader_path);
|
||||
if (read_file(shader_path, (void**)&content) >= 0)
|
||||
return content;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool get_xml_attrs(struct gfx_shader_pass *pass, xmlNodePtr ptr)
|
||||
{
|
||||
struct gfx_fbo_scale *fbo = &pass->fbo;
|
||||
pass->frame_count_mod = 0;
|
||||
pass->filter = RARCH_FILTER_UNSPEC;
|
||||
fbo->fp_fbo = false;
|
||||
fbo->scale_x = 1.0;
|
||||
fbo->scale_y = 1.0;
|
||||
fbo->type_x = pass->fbo.type_y = RARCH_SCALE_INPUT;
|
||||
fbo->valid = false;
|
||||
|
||||
// Check if shader forces a certain texture filtering.
|
||||
char attr[64];
|
||||
if (xml_get_prop(attr, sizeof(attr), ptr, "filter"))
|
||||
{
|
||||
if (strcmp(attr, "nearest") == 0)
|
||||
{
|
||||
pass->filter = RARCH_FILTER_NEAREST;
|
||||
RARCH_LOG("XML: Shader forces GL_NEAREST.\n");
|
||||
}
|
||||
else if (strcmp(attr, "linear") == 0)
|
||||
{
|
||||
pass->filter = RARCH_FILTER_LINEAR;
|
||||
RARCH_LOG("XML: Shader forces GL_LINEAR.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_WARN("XML: Invalid property for filter.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for scaling attributes *lots of code <_<*
|
||||
char attr_scale[64], attr_scale_x[64], attr_scale_y[64];
|
||||
char attr_size[64], attr_size_x[64], attr_size_y[64];
|
||||
char attr_outscale[64], attr_outscale_x[64], attr_outscale_y[64];
|
||||
char frame_count_mod[64], fp_fbo[64];
|
||||
|
||||
xml_get_prop(attr_scale, sizeof(attr_scale), ptr, "scale");
|
||||
xml_get_prop(attr_scale_x, sizeof(attr_scale_x), ptr, "scale_x");
|
||||
xml_get_prop(attr_scale_y, sizeof(attr_scale_y), ptr, "scale_y");
|
||||
xml_get_prop(attr_size, sizeof(attr_size), ptr, "size");
|
||||
xml_get_prop(attr_size_x, sizeof(attr_size_x), ptr, "size_x");
|
||||
xml_get_prop(attr_size_y, sizeof(attr_size_y), ptr, "size_y");
|
||||
xml_get_prop(attr_outscale, sizeof(attr_outscale), ptr, "outscale");
|
||||
xml_get_prop(attr_outscale_x, sizeof(attr_outscale_x), ptr, "outscale_x");
|
||||
xml_get_prop(attr_outscale_y, sizeof(attr_outscale_y), ptr, "outscale_y");
|
||||
xml_get_prop(frame_count_mod, sizeof(frame_count_mod), ptr, "frame_count_mod");
|
||||
xml_get_prop(fp_fbo, sizeof(fp_fbo), ptr, "float_framebuffer");
|
||||
|
||||
fbo->fp_fbo = strcmp(fp_fbo, "true") == 0;
|
||||
|
||||
unsigned x_attr_cnt = 0, y_attr_cnt = 0;
|
||||
|
||||
if (*frame_count_mod)
|
||||
{
|
||||
pass->frame_count_mod = strtoul(frame_count_mod, NULL, 0);
|
||||
RARCH_LOG("Got frame count mod attr: %u\n", pass->frame_count_mod);
|
||||
}
|
||||
|
||||
if (*attr_scale)
|
||||
{
|
||||
float scale = strtod(attr_scale, NULL);
|
||||
fbo->scale_x = scale;
|
||||
fbo->scale_y = scale;
|
||||
fbo->valid = true;
|
||||
RARCH_LOG("Got scale attr: %.1f\n", scale);
|
||||
x_attr_cnt++;
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_scale_x)
|
||||
{
|
||||
float scale = strtod(attr_scale_x, NULL);
|
||||
fbo->scale_x = scale;
|
||||
fbo->valid = true;
|
||||
RARCH_LOG("Got scale_x attr: %.1f\n", scale);
|
||||
x_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_scale_y)
|
||||
{
|
||||
float scale = strtod(attr_scale_y, NULL);
|
||||
fbo->scale_y = scale;
|
||||
fbo->valid = true;
|
||||
RARCH_LOG("Got scale_y attr: %.1f\n", scale);
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_size)
|
||||
{
|
||||
fbo->abs_x = fbo->abs_y = strtoul(attr_size, NULL, 0);
|
||||
fbo->valid = true;
|
||||
fbo->type_x = fbo->type_y = RARCH_SCALE_ABSOLUTE;
|
||||
RARCH_LOG("Got size attr: %u\n", fbo->abs_x);
|
||||
x_attr_cnt++;
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_size_x)
|
||||
{
|
||||
fbo->abs_x = strtoul(attr_size_x, NULL, 0);
|
||||
fbo->valid = true;
|
||||
fbo->type_x = RARCH_SCALE_ABSOLUTE;
|
||||
RARCH_LOG("Got size_x attr: %u\n", fbo->abs_x);
|
||||
x_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_size_y)
|
||||
{
|
||||
fbo->abs_y = strtoul(attr_size_y, NULL, 0);
|
||||
fbo->valid = true;
|
||||
fbo->type_y = RARCH_SCALE_ABSOLUTE;
|
||||
RARCH_LOG("Got size_y attr: %u\n", fbo->abs_y);
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_outscale)
|
||||
{
|
||||
float scale = strtod(attr_outscale, NULL);
|
||||
fbo->scale_x = fbo->scale_y = scale;
|
||||
fbo->valid = true;
|
||||
fbo->type_x = fbo->type_y = RARCH_SCALE_VIEWPORT;
|
||||
RARCH_LOG("Got outscale attr: %.1f\n", scale);
|
||||
x_attr_cnt++;
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_outscale_x)
|
||||
{
|
||||
float scale = strtod(attr_outscale_x, NULL);
|
||||
fbo->scale_x = scale;
|
||||
fbo->valid = true;
|
||||
fbo->type_x = RARCH_SCALE_VIEWPORT;
|
||||
RARCH_LOG("Got outscale_x attr: %.1f\n", scale);
|
||||
x_attr_cnt++;
|
||||
}
|
||||
|
||||
if (*attr_outscale_y)
|
||||
{
|
||||
float scale = strtod(attr_outscale_y, NULL);
|
||||
fbo->scale_y = scale;
|
||||
fbo->valid = true;
|
||||
fbo->type_y = RARCH_SCALE_VIEWPORT;
|
||||
RARCH_LOG("Got outscale_y attr: %.1f\n", scale);
|
||||
y_attr_cnt++;
|
||||
}
|
||||
|
||||
if (x_attr_cnt > 1)
|
||||
return false;
|
||||
if (y_attr_cnt > 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool add_texture_image(struct gfx_shader *shader,
|
||||
xmlNodePtr ptr)
|
||||
{
|
||||
if (shader->luts >= GFX_MAX_TEXTURES)
|
||||
{
|
||||
RARCH_WARN("Too many texture images. Ignoring ...\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
struct gfx_shader_lut *lut = &shader->lut[shader->luts];
|
||||
|
||||
xml_get_prop(lut->id, sizeof(lut->id), ptr, "id");
|
||||
xml_get_prop(lut->path, sizeof(lut->path), ptr, "file");
|
||||
|
||||
char filter[64] = {0};
|
||||
xml_get_prop(filter, sizeof(filter), ptr, "filter");
|
||||
|
||||
if (!*lut->id)
|
||||
{
|
||||
RARCH_ERR("Could not find ID in texture.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!*lut->path)
|
||||
{
|
||||
RARCH_ERR("Could not find filename in texture.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(filter, "linear") == 0)
|
||||
lut->filter = RARCH_FILTER_LINEAR;
|
||||
else if (strcmp(filter, "nearest") == 0)
|
||||
lut->filter = RARCH_FILTER_NEAREST;
|
||||
else if (!*filter)
|
||||
lut->filter = RARCH_FILTER_UNSPEC;
|
||||
else
|
||||
{
|
||||
RARCH_ERR("Invalid LUT filter type.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
shader->luts++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool add_import_value(struct gfx_shader *shader, xmlNodePtr ptr)
|
||||
{
|
||||
if (shader->variables >= GFX_MAX_VARIABLES)
|
||||
{
|
||||
RARCH_ERR("Too many import variables ...\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct state_tracker_uniform_info *var = &shader->variable[shader->variables];
|
||||
|
||||
char semantic[64], wram[64], input[64], bitmask[64], bitequal[64];
|
||||
xml_get_prop(var->id, sizeof(var->id), ptr, "id");
|
||||
xml_get_prop(semantic, sizeof(semantic), ptr, "semantic");
|
||||
xml_get_prop(wram, sizeof(wram), ptr, "wram");
|
||||
xml_get_prop(input, sizeof(input), ptr, "input_slot");
|
||||
xml_get_prop(bitmask, sizeof(bitmask), ptr, "mask");
|
||||
xml_get_prop(bitequal, sizeof(bitequal), ptr, "equal");
|
||||
|
||||
if (!*semantic || !*var->id)
|
||||
{
|
||||
RARCH_ERR("No semantic or ID for import value.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(semantic, "capture") == 0)
|
||||
var->type = RARCH_STATE_CAPTURE;
|
||||
else if (strcmp(semantic, "capture_previous") == 0)
|
||||
var->type = RARCH_STATE_CAPTURE_PREV;
|
||||
else if (strcmp(semantic, "transition") == 0)
|
||||
var->type = RARCH_STATE_TRANSITION;
|
||||
else if (strcmp(semantic, "transition_count") == 0)
|
||||
var->type = RARCH_STATE_TRANSITION_COUNT;
|
||||
else if (strcmp(semantic, "transition_previous") == 0)
|
||||
var->type = RARCH_STATE_TRANSITION_PREV;
|
||||
else if (strcmp(semantic, "python") == 0)
|
||||
var->type = RARCH_STATE_PYTHON;
|
||||
else
|
||||
{
|
||||
RARCH_ERR("Invalid semantic for import value.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (var->type != RARCH_STATE_PYTHON)
|
||||
{
|
||||
if (*input)
|
||||
{
|
||||
unsigned slot = strtoul(input, NULL, 0);
|
||||
switch (slot)
|
||||
{
|
||||
case 1:
|
||||
var->ram_type = RARCH_STATE_INPUT_SLOT1;
|
||||
break;
|
||||
case 2:
|
||||
var->ram_type = RARCH_STATE_INPUT_SLOT2;
|
||||
break;
|
||||
|
||||
default:
|
||||
RARCH_ERR("Invalid input slot for import.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (*wram)
|
||||
{
|
||||
var->addr = strtoul(wram, NULL, 16);
|
||||
var->ram_type = RARCH_STATE_WRAM;
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("No RAM address specificed for import value.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (*bitmask)
|
||||
var->mask = strtoul(bitmask, NULL, 16);
|
||||
if (*bitequal)
|
||||
var->equal = strtoul(bitequal, NULL, 16);
|
||||
|
||||
shader->variables++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_script(struct gfx_shader *shader, const char *path,
|
||||
xmlNodePtr ptr)
|
||||
{
|
||||
if (shader->script)
|
||||
{
|
||||
RARCH_ERR("Script already imported.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
xml_get_prop(shader->script_class, sizeof(shader->script_class), ptr, "class");
|
||||
|
||||
char language[64];
|
||||
xml_get_prop(language, sizeof(language), ptr, "language");
|
||||
if (strcmp(language, "python") != 0)
|
||||
{
|
||||
RARCH_ERR("Script language is not Python.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
shader->script = xml_get_content(ptr);
|
||||
if (!shader->script)
|
||||
return false;
|
||||
|
||||
shader->script = xml_replace_if_file(shader->script, path, ptr, "src");
|
||||
if (!shader->script)
|
||||
{
|
||||
RARCH_ERR("Cannot find Python script.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gfx_shader_read_xml(const char *path, struct gfx_shader *shader)
|
||||
{
|
||||
LIBXML_TEST_VERSION;
|
||||
|
||||
xmlParserCtxtPtr ctx = xmlNewParserCtxt();
|
||||
if (!ctx)
|
||||
{
|
||||
RARCH_ERR("Failed to load libxml2 context.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
RARCH_LOG("Loading XML shader: %s\n", path);
|
||||
xmlDocPtr doc = xmlCtxtReadFile(ctx, path, NULL, 0);
|
||||
xmlNodePtr head = NULL;
|
||||
xmlNodePtr cur = NULL;
|
||||
|
||||
if (!doc)
|
||||
{
|
||||
RARCH_ERR("Failed to parse XML file: %s\n", path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBXML2
|
||||
if (ctx->valid == 0)
|
||||
{
|
||||
RARCH_ERR("Cannot validate XML shader: %s\n", path);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
head = xmlDocGetRootElement(doc);
|
||||
|
||||
for (cur = head; cur; cur = cur->next)
|
||||
{
|
||||
if (cur->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
if (strcmp((const char*)cur->name, "shader") != 0)
|
||||
continue;
|
||||
|
||||
char attr[64];
|
||||
xml_get_prop(attr, sizeof(attr), cur, "language");
|
||||
|
||||
if (strcmp(attr, "GLSL") == 0)
|
||||
shader->type = RARCH_SHADER_GLSL;
|
||||
else
|
||||
continue;
|
||||
|
||||
xml_get_prop(attr, sizeof(attr), cur, "style");
|
||||
shader->modern = strcmp(attr, "GLES2") == 0;
|
||||
|
||||
if (xml_get_prop(shader->prefix, sizeof(shader->prefix), cur, "prefix"))
|
||||
RARCH_LOG("[GL]: Using uniform and attrib prefix: %s\n", shader->prefix);
|
||||
|
||||
if (shader->modern)
|
||||
RARCH_LOG("[GL]: Shader reports a GLES2 style shader.\n");
|
||||
else
|
||||
RARCH_WARN("[GL]: Legacy shaders are deprecated.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!cur) // We couldn't find any GLSL shader :(
|
||||
goto error;
|
||||
|
||||
// Iterate to check if we find fragment and/or vertex shaders.
|
||||
for (cur = cur->children; cur && shader->passes < GFX_MAX_SHADERS;
|
||||
cur = cur->next)
|
||||
{
|
||||
if (cur->type != XML_ELEMENT_NODE)
|
||||
continue;
|
||||
|
||||
char *content = xml_get_content(cur);
|
||||
if (!content)
|
||||
continue;
|
||||
|
||||
struct gfx_shader_pass *pass = &shader->pass[shader->passes];
|
||||
|
||||
if (strcmp((const char*)cur->name, "vertex") == 0)
|
||||
{
|
||||
if (pass->source.xml.vertex)
|
||||
{
|
||||
RARCH_ERR("Cannot have more than one vertex shader in a program.\n");
|
||||
free(content);
|
||||
goto error;
|
||||
}
|
||||
|
||||
content = xml_replace_if_file(content, path, cur, "src");
|
||||
if (!content)
|
||||
{
|
||||
RARCH_ERR("Shader source file was provided, but failed to read.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pass->source.xml.vertex = content;
|
||||
}
|
||||
else if (strcmp((const char*)cur->name, "fragment") == 0)
|
||||
{
|
||||
if (shader->modern && !pass->source.xml.vertex)
|
||||
{
|
||||
RARCH_ERR("Modern GLSL was chosen and vertex shader was not provided. This is an error.\n");
|
||||
free(content);
|
||||
goto error;
|
||||
}
|
||||
|
||||
content = xml_replace_if_file(content, path, cur, "src");
|
||||
if (!content)
|
||||
{
|
||||
RARCH_ERR("Shader source file was provided, but failed to read.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pass->source.xml.fragment = content;
|
||||
if (!get_xml_attrs(pass, cur))
|
||||
{
|
||||
RARCH_ERR("XML shader attributes do not comply with specifications.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
shader->passes++;
|
||||
}
|
||||
else if (strcmp((const char*)cur->name, "texture") == 0)
|
||||
{
|
||||
free(content);
|
||||
if (!add_texture_image(shader, cur))
|
||||
{
|
||||
RARCH_ERR("Texture image failed to load.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp((const char*)cur->name, "import") == 0)
|
||||
{
|
||||
free(content);
|
||||
if (!add_import_value(shader, cur))
|
||||
{
|
||||
RARCH_ERR("Import value is invalid.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp((const char*)cur->name, "script") == 0)
|
||||
{
|
||||
free(content);
|
||||
if (!get_script(shader, path, cur))
|
||||
{
|
||||
RARCH_ERR("Script is invalid.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shader->passes)
|
||||
{
|
||||
RARCH_ERR("Couldn't find vertex shader nor fragment shader in XML file.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctx);
|
||||
return true;
|
||||
|
||||
error:
|
||||
RARCH_ERR("Failed to load XML shader ...\n");
|
||||
if (doc)
|
||||
xmlFreeDoc(doc);
|
||||
xmlFreeParserCtxt(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// CGP store
|
||||
static const char *scale_type_to_str(enum gfx_scale_type type)
|
||||
{
|
||||
@ -1059,7 +518,7 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha
|
||||
|
||||
char key[64];
|
||||
print_buf(key, "shader%u", i);
|
||||
config_set_string(conf, key, pass->source.cg);
|
||||
config_set_string(conf, key, pass->source.path);
|
||||
|
||||
if (pass->filter != RARCH_FILTER_UNSPEC)
|
||||
{
|
||||
@ -1158,12 +617,12 @@ void gfx_shader_resolve_relative(struct gfx_shader *shader, const char *ref_path
|
||||
char tmp_path[PATH_MAX];
|
||||
for (i = 0; i < shader->passes; i++)
|
||||
{
|
||||
if (!*shader->pass[i].source.cg)
|
||||
if (!*shader->pass[i].source.path)
|
||||
continue;
|
||||
|
||||
strlcpy(tmp_path, shader->pass[i].source.cg, sizeof(tmp_path));
|
||||
fill_pathname_resolve_relative(shader->pass[i].source.cg,
|
||||
ref_path, tmp_path, sizeof(shader->pass[i].source.cg));
|
||||
strlcpy(tmp_path, shader->pass[i].source.path, sizeof(tmp_path));
|
||||
fill_pathname_resolve_relative(shader->pass[i].source.path,
|
||||
ref_path, tmp_path, sizeof(shader->pass[i].source.path));
|
||||
}
|
||||
|
||||
for (i = 0; i < shader->luts; i++)
|
||||
|
@ -69,12 +69,12 @@ struct gfx_shader_pass
|
||||
{
|
||||
struct
|
||||
{
|
||||
char cg[PATH_MAX];
|
||||
char path[PATH_MAX];
|
||||
struct
|
||||
{
|
||||
char *vertex; // Dynamically allocated. Must be free'd.
|
||||
char *fragment; // Dynamically allocated. Must be free'd.
|
||||
} xml;
|
||||
} string;
|
||||
} source;
|
||||
|
||||
struct gfx_fbo_scale fbo;
|
||||
@ -116,7 +116,6 @@ struct gfx_shader
|
||||
};
|
||||
|
||||
bool gfx_shader_read_conf_cgp(config_file_t *conf, struct gfx_shader *shader);
|
||||
bool gfx_shader_read_xml(const char *path, struct gfx_shader *shader);
|
||||
void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *shader);
|
||||
|
||||
void gfx_shader_resolve_relative(struct gfx_shader *shader, const char *ref_path);
|
||||
|
@ -159,8 +159,8 @@
|
||||
# Exact behavior of this option is implementation specific.
|
||||
# video_crop_overscan = true
|
||||
|
||||
# Path to shader. Shader can be either Cg, CGP (Cg preset) or XML/GLSL format if support is enabled.
|
||||
# video_shader = "/path/to/shader.{cg,cgp,shader}"
|
||||
# Path to shader. Shader can be either Cg, CGP (Cg preset) or GLSL, GLSLP (GLSL preset)
|
||||
# video_shader = "/path/to/shader.{cg,cgp,glsl,glslp}"
|
||||
|
||||
# Load video_shader on startup.
|
||||
# Other shaders can still be loaded later in runtime.
|
||||
|
Loading…
x
Reference in New Issue
Block a user