Reintroduce CGP refactor.

Fix several issues that caused crashes.
This commit is contained in:
Themaister 2013-04-06 11:30:56 +02:00
parent c3ac3028b5
commit e649db253c
15 changed files with 733 additions and 505 deletions

View File

@ -23,6 +23,7 @@ OBJ = frontend/frontend.o \
conf/config_file.o \
screenshot.o \
gfx/scaler/scaler.o \
gfx/shader_parse.o \
gfx/scaler/pixconv.o \
gfx/scaler/scaler_int.o \
gfx/scaler/filter.o \

View File

@ -29,6 +29,7 @@ OBJ = frontend/frontend.o \
gfx/scaler/scaler_int.o \
gfx/scaler/filter.o \
gfx/state_tracker.o \
gfx/shader_parse.o \
gfx/fonts/fonts.o \
gfx/fonts/bitmapfont.o \
gfx/image.o \

View File

@ -696,6 +696,13 @@ void config_set_int(config_file_t *conf, const char *key, int val)
config_set_string(conf, key, buf);
}
void config_set_hex(config_file_t *conf, const char *key, unsigned val)
{
char buf[128];
snprintf(buf, sizeof(buf), "%x", val);
config_set_string(conf, key, buf);
}
void config_set_uint64(config_file_t *conf, const char *key, uint64_t val)
{
char buf[128];

View File

@ -92,6 +92,7 @@ bool config_get_bool(config_file_t *conf, const char *entry, bool *in);
void config_set_double(config_file_t *conf, const char *entry, double value);
void config_set_float(config_file_t *conf, const char *entry, float value);
void config_set_int(config_file_t *conf, const char *entry, int val);
void config_set_hex(config_file_t *conf, const char *entry, unsigned val);
void config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);
void config_set_char(config_file_t *conf, const char *entry, char val);
void config_set_string(config_file_t *conf, const char *entry, const char *val);

View File

@ -439,7 +439,7 @@ static bool gl_shader_filter_type(void *data, unsigned index, bool *smooth)
}
#ifdef HAVE_FBO
static void gl_shader_scale(void *data, unsigned index, struct gl_fbo_scale *scale)
static void gl_shader_scale(void *data, unsigned index, struct gfx_fbo_scale *scale)
{
gl_t *gl = (gl_t*)data;
@ -674,7 +674,7 @@ void gl_init_fbo(void *data, unsigned width, unsigned height)
return;
#endif
struct gl_fbo_scale scale, scale_last;
struct gfx_fbo_scale scale, scale_last;
gl_shader_scale(gl, 1, &scale);
gl_shader_scale(gl, gl_shader_num_func(gl), &scale_last);

View File

@ -22,6 +22,7 @@
#include "gfx_context.h"
#include "scaler/scaler.h"
#include "fonts/gl_font.h"
#include "shader_parse.h"
#ifdef HAVE_CONFIG_H
#include "../config.h"
@ -160,25 +161,6 @@ struct gl_fbo_rect
unsigned height;
};
enum gl_scale_type
{
RARCH_SCALE_ABSOLUTE,
RARCH_SCALE_INPUT,
RARCH_SCALE_VIEWPORT
};
struct gl_fbo_scale
{
bool fp_fbo;
enum gl_scale_type type_x;
enum gl_scale_type type_y;
float scale_x;
float scale_y;
unsigned abs_x;
unsigned abs_y;
bool valid;
};
struct gl_ortho
{
GLfloat left;
@ -239,7 +221,7 @@ typedef struct gl
GLuint fbo[MAX_SHADERS];
GLuint fbo_texture[MAX_SHADERS];
struct gl_fbo_rect fbo_rect[MAX_SHADERS];
struct gl_fbo_scale fbo_scale[MAX_SHADERS];
struct gfx_fbo_scale fbo_scale[MAX_SHADERS];
int fbo_pass;
bool fbo_inited;

View File

@ -123,35 +123,25 @@ struct cg_program
CGparameter frame_dir_v;
CGparameter mvp;
unsigned frame_count_mod;
struct cg_fbo_params fbo[RARCH_CG_MAX_SHADERS];
struct cg_fbo_params orig;
struct cg_fbo_params prev[PREV_TEXTURES];
};
#define FILTER_UNSPEC 0
#define FILTER_LINEAR 1
#define FILTER_NEAREST 2
static struct cg_program prg[RARCH_CG_MAX_SHADERS];
static const char **cg_arguments;
static bool cg_active = false;
static bool cg_active;
static CGprofile cgVProf, cgFProf;
static unsigned active_index = 0;
static unsigned cg_shader_num = 0;
static struct gl_fbo_scale cg_scale[RARCH_CG_MAX_SHADERS];
static unsigned fbo_smooth[RARCH_CG_MAX_SHADERS];
static unsigned active_index;
static struct gfx_shader *cg_shader;
static state_tracker_t *state_tracker;
static GLuint lut_textures[MAX_TEXTURES];
static unsigned lut_textures_num = 0;
static char lut_textures_uniform[MAX_TEXTURES][64];
static CGparameter cg_attribs[PREV_TEXTURES + 1 + 4 + RARCH_CG_MAX_SHADERS];
static unsigned cg_attrib_index;
static state_tracker_t *state_tracker = NULL;
static void gl_cg_reset_attrib(void)
{
for (unsigned i = 0; i < cg_attrib_index; i++)
@ -222,8 +212,9 @@ void gl_cg_set_params(unsigned width, unsigned height,
if (prg[active_index].frame_cnt_f || prg[active_index].frame_cnt_v)
{
if (prg[active_index].frame_count_mod)
frame_count %= prg[active_index].frame_count_mod;
unsigned modulo = cg_shader->pass[active_index - 1].frame_count_mod;
if (modulo)
frame_count %= modulo;
set_param_1f(prg[active_index].frame_cnt_f, (float)frame_count);
set_param_1f(prg[active_index].frame_cnt_v, (float)frame_count);
@ -275,9 +266,9 @@ void gl_cg_set_params(unsigned width, unsigned height,
}
// Set lookup textures.
for (unsigned i = 0; i < lut_textures_num; i++)
for (unsigned i = 0; i < cg_shader->luts; i++)
{
CGparameter param = cgGetNamedParameter(prg[active_index].fprg, lut_textures_uniform[i]);
CGparameter param = cgGetNamedParameter(prg[active_index].fprg, cg_shader->lut[i].id);
if (param)
{
cgGLSetTextureParameter(param, lut_textures[i]);
@ -357,23 +348,24 @@ static void gl_cg_deinit_progs(void)
static void gl_cg_deinit_state(void)
{
gl_cg_reset_attrib();
cg_active = false;
cg_shader_num = 0;
gl_cg_deinit_progs();
memset(cg_scale, 0, sizeof(cg_scale));
memset(fbo_smooth, 0, sizeof(fbo_smooth));
glDeleteTextures(lut_textures_num, lut_textures);
lut_textures_num = 0;
if (cg_shader && cg_shader->luts)
{
glDeleteTextures(cg_shader->luts, lut_textures);
memset(lut_textures, 0, sizeof(lut_textures));
}
if (state_tracker)
{
state_tracker_free(state_tracker);
state_tracker = NULL;
}
free(cg_shader);
cg_shader = NULL;
}
// Final deinit.
@ -486,10 +478,16 @@ static bool load_plain(const char *path)
if (!load_stock())
return false;
cg_shader = (struct gfx_shader*)calloc(1, sizeof(*cg_shader));
if (!cg_shader)
return false;
cg_shader->passes = 1;
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));
if (!load_program(1, path, true))
return false;
}
@ -499,8 +497,6 @@ static bool load_plain(const char *path)
prg[1] = prg[0];
}
cg_shader_num = 1;
return true;
}
@ -517,10 +513,9 @@ static bool load_menu_shader(void)
#define BORDER_FUNC GL_CLAMP_TO_BORDER
#endif
static void load_texture_data(GLuint *obj, const struct texture_image *img, bool smooth)
static void load_texture_data(GLuint obj, const struct texture_image *img, bool smooth)
{
glGenTextures(1, obj);
glBindTexture(GL_TEXTURE_2D, *obj);
glBindTexture(GL_TEXTURE_2D, obj);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, BORDER_FUNC);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, BORDER_FUNC);
@ -537,41 +532,18 @@ static void load_texture_data(GLuint *obj, const struct texture_image *img, bool
free(img->pixels);
}
static bool load_textures(const char *cgp_path, config_file_t *conf)
static bool load_textures(const char *cgp_path)
{
bool ret = true;
char *textures = NULL;
if (!config_get_string(conf, "textures", &textures)) // No textures here ...
if (!cg_shader->luts)
return true;
char *save;
const char *id = strtok_r(textures, ";", &save);
while (id && lut_textures_num < MAX_TEXTURES)
glGenTextures(cg_shader->luts, lut_textures);
for (unsigned i = 0; i < cg_shader->luts; i++)
{
char path[PATH_MAX];
if (!config_get_array(conf, id, path, sizeof(path)))
{
RARCH_ERR("Cannot find path to texture \"%s\" ...\n", id);
ret = false;
goto end;
}
char id_filter[64];
print_buf(id_filter, "%s_linear", id);
bool smooth = true;
if (!config_get_bool(conf, id_filter, &smooth))
smooth = true;
char id_absolute[64];
print_buf(id_absolute, "%s_absolute", id);
bool absolute = false;
if (!config_get_bool(conf, id_absolute, &absolute))
absolute = false;
char image_path[PATH_MAX];
fill_pathname_resolve_relative(image_path, cgp_path, path, sizeof(image_path));
fill_pathname_resolve_relative(image_path, cgp_path,
cg_shader->lut[i].path, sizeof(image_path));
RARCH_LOG("Loading image from: \"%s\".\n", image_path);
@ -579,130 +551,25 @@ static bool load_textures(const char *cgp_path, config_file_t *conf)
if (!texture_image_load(image_path, &img))
{
RARCH_ERR("Failed to load picture ...\n");
ret = false;
goto end;
return false;
}
strlcpy(lut_textures_uniform[lut_textures_num],
id, sizeof(lut_textures_uniform[lut_textures_num]));
load_texture_data(&lut_textures[lut_textures_num], &img, smooth);
lut_textures_num++;
id = strtok_r(NULL, ";", &save);
load_texture_data(lut_textures[i], &img,
cg_shader->lut[i].filter != RARCH_FILTER_NEAREST);
}
end:
free(textures);
glBindTexture(GL_TEXTURE_2D, 0);
return ret;
return true;
}
static bool load_imports(const char *cgp_path, config_file_t *conf)
static bool load_imports(const char *cgp_path)
{
bool ret = true;
char *imports = NULL;
if (!config_get_string(conf, "imports", &imports))
return true;
struct state_tracker_uniform_info info[MAX_VARIABLES];
unsigned info_cnt = 0;
struct state_tracker_info tracker_info = {0};
#ifdef HAVE_PYTHON
char script_path[PATH_MAX];
char *script = NULL;
char *script_class = NULL;
#endif
char *save;
const char *id = strtok_r(imports, ";", &save);
while (id && info_cnt < MAX_VARIABLES)
for (unsigned i = 0; i < cg_shader->variables; i++)
{
char semantic_buf[64];
char wram_buf[64];
char input_slot_buf[64];
char mask_buf[64];
char equal_buf[64];
print_buf(semantic_buf, "%s_semantic", id);
print_buf(wram_buf, "%s_wram", id);
print_buf(input_slot_buf, "%s_input_slot", id);
print_buf(mask_buf, "%s_mask", id);
print_buf(equal_buf, "%s_equal", id);
char *semantic = NULL;
config_get_string(conf, semantic_buf, &semantic);
if (!semantic)
{
RARCH_ERR("No semantic for import variable.\n");
ret = false;
goto end;
}
enum state_tracker_type tracker_type;
enum state_ram_type ram_type = RARCH_STATE_NONE;
if (strcmp(semantic, "capture") == 0)
tracker_type = RARCH_STATE_CAPTURE;
else if (strcmp(semantic, "transition") == 0)
tracker_type = RARCH_STATE_TRANSITION;
else if (strcmp(semantic, "transition_count") == 0)
tracker_type = RARCH_STATE_TRANSITION_COUNT;
else if (strcmp(semantic, "capture_previous") == 0)
tracker_type = RARCH_STATE_CAPTURE_PREV;
else if (strcmp(semantic, "transition_previous") == 0)
tracker_type = RARCH_STATE_TRANSITION_PREV;
#ifdef HAVE_PYTHON
else if (strcmp(semantic, "python") == 0)
tracker_type = RARCH_STATE_PYTHON;
#endif
else
{
RARCH_ERR("Invalid semantic.\n");
ret = false;
goto end;
}
unsigned addr = 0;
#ifdef HAVE_PYTHON
if (tracker_type != RARCH_STATE_PYTHON)
#endif
{
unsigned input_slot = 0;
if (config_get_hex(conf, input_slot_buf, &input_slot))
{
switch (input_slot)
{
case 1:
ram_type = RARCH_STATE_INPUT_SLOT1;
break;
case 2:
ram_type = RARCH_STATE_INPUT_SLOT2;
break;
default:
RARCH_ERR("Invalid input slot for import.\n");
ret = false;
goto end;
}
}
else if (config_get_hex(conf, wram_buf, &addr))
ram_type = RARCH_STATE_WRAM;
else
{
RARCH_ERR("No address assigned to semantic.\n");
ret = false;
goto end;
}
}
unsigned memtype;
switch (ram_type)
switch (cg_shader->variable[i].ram_type)
{
case RARCH_STATE_WRAM:
memtype = RETRO_MEMORY_SYSTEM_RAM;
@ -712,336 +579,118 @@ static bool load_imports(const char *cgp_path, config_file_t *conf)
memtype = -1u;
}
if ((memtype != -1u) && (addr >= pretro_get_memory_size(memtype)))
if ((memtype != -1u) && (cg_shader->variable[i].addr >= pretro_get_memory_size(memtype)))
{
RARCH_ERR("Address out of bounds.\n");
ret = false;
goto end;
return false;
}
unsigned bitmask = 0;
if (!config_get_hex(conf, mask_buf, &bitmask))
bitmask = 0;
unsigned bitequal = 0;
if (!config_get_hex(conf, equal_buf, &bitequal))
bitequal = 0;
strlcpy(info[info_cnt].id, id, sizeof(info[info_cnt].id));
info[info_cnt].addr = addr;
info[info_cnt].type = tracker_type;
info[info_cnt].ram_type = ram_type;
info[info_cnt].mask = bitmask;
info[info_cnt].equal = bitequal;
info_cnt++;
free(semantic);
id = strtok_r(NULL, ";", &save);
}
tracker_info.wram = (uint8_t*)pretro_get_memory_data(RETRO_MEMORY_SYSTEM_RAM);
tracker_info.info = info;
tracker_info.info_elem = info_cnt;
tracker_info.info = cg_shader->variable;
tracker_info.info_elem = cg_shader->variables;
#ifdef HAVE_PYTHON
if (config_get_string(conf, "import_script", &script))
if (*cg_shader->script_path)
{
fill_pathname_resolve_relative(script_path, cgp_path, script, sizeof(script_path));
char script_path[PATH_MAX];
fill_pathname_resolve_relative(script_path, cgp_path,
cg_shader->script_path, sizeof(script_path));
tracker_info.script = script_path;
tracker_info.script_is_file = true;
}
if (config_get_string(conf, "import_script_class", &script_class))
tracker_info.script_class = script_class;
tracker_info.script_is_file = true;
tracker_info.script_class = *cg_shader->script_class ? cg_shader->script_class : NULL;
#endif
state_tracker = state_tracker_init(&tracker_info);
if (!state_tracker)
RARCH_WARN("Failed to initialize state tracker.\n");
#ifdef HAVE_PYTHON
if (script)
free(script);
if (script_class)
free(script_class);
#endif
end:
free(imports);
return ret;
return true;
}
static bool load_shader(const char *cgp_path, unsigned i, config_file_t *conf)
static bool load_shader(const char *cgp_path, unsigned i)
{
char *shader_path = NULL;
char attr_buf[64];
char path_buf[PATH_MAX];
print_buf(attr_buf, "shader%u", i);
if (config_get_string(conf, attr_buf, &shader_path))
{
fill_pathname_resolve_relative(path_buf, cgp_path, shader_path, sizeof(path_buf));
free(shader_path);
}
else
{
RARCH_ERR("Didn't find shader path in config ...\n");
return false;
}
fill_pathname_resolve_relative(path_buf, cgp_path,
cg_shader->pass[i].source.cg, sizeof(path_buf));
RARCH_LOG("Loading Cg shader: \"%s\".\n", path_buf);
if (!load_program(i + 1, path_buf, true))
return false;
#ifdef HAVE_RMENU
// In RMenu, need to display shaders in menu.
switch (i)
{
case 0:
strlcpy(g_settings.video.cg_shader_path,
path_buf, sizeof(g_settings.video.cg_shader_path));
break;
}
#endif
return true;
}
static bool load_shader_params(unsigned i, config_file_t *conf)
{
char scale_type[64] = {0};
char scale_type_x[64] = {0};
char scale_type_y[64] = {0};
prg[i + 1].frame_count_mod = 0;
char frame_count_mod[64] = {0};
char frame_count_mod_buf[64];
print_buf(frame_count_mod_buf, "frame_count_mod%u", i);
if (config_get_array(conf, frame_count_mod_buf, frame_count_mod, sizeof(frame_count_mod)))
prg[i + 1].frame_count_mod = strtoul(frame_count_mod, NULL, 0);
char scale_name_buf[64];
print_buf(scale_name_buf, "scale_type%u", i);
config_get_array(conf, scale_name_buf, scale_type, sizeof(scale_type));
print_buf(scale_name_buf, "scale_type_x%u", i);
config_get_array(conf, scale_name_buf, scale_type_x, sizeof(scale_type_x));
print_buf(scale_name_buf, "scale_type_y%u", i);
config_get_array(conf, scale_name_buf, scale_type_y, sizeof(scale_type_y));
if (!*scale_type && !*scale_type_x && !*scale_type_y)
return true;
if (*scale_type)
{
strlcpy(scale_type_x, scale_type, sizeof(scale_type_x));
strlcpy(scale_type_y, scale_type, sizeof(scale_type_y));
}
char attr_name_buf[64];
float fattr = 0.0f;
int iattr = 0;
struct gl_fbo_scale *scale = &cg_scale[i + 1]; // Shader 0 is passthrough shader. Start at 1.
scale->valid = true;
scale->type_x = RARCH_SCALE_INPUT;
scale->type_y = RARCH_SCALE_INPUT;
scale->scale_x = 1.0;
scale->scale_y = 1.0;
char fp_fbo_buf[64];
print_buf(fp_fbo_buf, "float_framebuffer%u", i);
scale->fp_fbo = false;
config_get_bool(conf, fp_fbo_buf, &scale->fp_fbo);
const struct retro_game_geometry *geom = &g_extern.system.av_info.geometry;
scale->abs_x = geom->base_width;
scale->abs_y = geom->base_height;
if (*scale_type_x)
{
if (strcmp(scale_type_x, "source") == 0)
scale->type_x = RARCH_SCALE_INPUT;
else if (strcmp(scale_type_x, "viewport") == 0)
scale->type_x = RARCH_SCALE_VIEWPORT;
else if (strcmp(scale_type_x, "absolute") == 0)
scale->type_x = RARCH_SCALE_ABSOLUTE;
else
{
RARCH_ERR("Invalid attribute.\n");
return false;
}
}
if (*scale_type_y)
{
if (strcmp(scale_type_y, "source") == 0)
scale->type_y = RARCH_SCALE_INPUT;
else if (strcmp(scale_type_y, "viewport") == 0)
scale->type_y = RARCH_SCALE_VIEWPORT;
else if (strcmp(scale_type_y, "absolute") == 0)
scale->type_y = RARCH_SCALE_ABSOLUTE;
else
{
RARCH_ERR("Invalid attribute.\n");
return false;
}
}
if (scale->type_x == RARCH_SCALE_ABSOLUTE)
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
else
{
print_buf(attr_name_buf, "scale_x%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
}
}
else
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
else
{
print_buf(attr_name_buf, "scale_x%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
}
}
if (scale->type_y == RARCH_SCALE_ABSOLUTE)
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
else
{
print_buf(attr_name_buf, "scale_y%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
}
}
else
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
else
{
print_buf(attr_name_buf, "scale_y%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
}
}
return true;
}
static bool load_preset(const char *path)
{
bool ret = true;
if (!load_stock())
return false;
int shaders = 0;
RARCH_LOG("Loading Cg meta-shader: %s\n", path);
config_file_t *conf = config_file_new(path);
if (!conf)
{
RARCH_ERR("Failed to load preset.\n");
ret = false;
goto end;
return false;
}
if (!config_get_int(conf, "shaders", &shaders))
if (!cg_shader)
cg_shader = (struct gfx_shader*)calloc(1, sizeof(*cg_shader));
if (!cg_shader)
return false;
if (!gfx_shader_read_conf_cgp(conf, cg_shader))
{
RARCH_ERR("Cannot find \"shaders\" param.\n");
ret = false;
goto end;
RARCH_ERR("Failed to parse CGP file.\n");
config_file_free(conf);
return false;
}
if (shaders < 1)
{
RARCH_ERR("Need to define at least 1 shader.\n");
ret = false;
goto end;
}
config_file_free(conf);
cg_shader_num = shaders;
if (shaders > RARCH_CG_MAX_SHADERS - 3)
#if 0 // Debugging
config_file_t *save_test = config_file_new(NULL);
gfx_shader_write_conf_cgp(conf, cg_shader);
config_file_write(save_test, "/tmp/load.cgp");
config_file_free(save_test);
#endif
if (cg_shader->passes > RARCH_CG_MAX_SHADERS - 3)
{
RARCH_WARN("Too many shaders ... Capping shader amount to %d.\n", RARCH_CG_MAX_SHADERS - 3);
cg_shader_num = shaders = RARCH_CG_MAX_SHADERS - 3;
cg_shader->passes = RARCH_CG_MAX_SHADERS - 3;
}
// If we aren't using last pass non-FBO shader,
// this shader will be assumed to be "fixed-function".
// Just use prg[0] for that pass, which will be
// pass-through.
prg[shaders + 1] = prg[0];
prg[cg_shader->passes + 1] = prg[0];
// Check filter params.
for (int i = 0; i < shaders; i++)
for (unsigned i = 0; i < cg_shader->passes; i++)
{
bool smooth = false;
char filter_name_buf[64];
print_buf(filter_name_buf, "filter_linear%u", i);
if (config_get_bool(conf, filter_name_buf, &smooth))
fbo_smooth[i + 1] = smooth ? FILTER_LINEAR : FILTER_NEAREST;
#ifdef HAVE_RMENU
// In RMenu, need to set smoothing for first and second passes.
switch (i)
{
case 0:
g_settings.video.smooth = fbo_smooth[1] == FILTER_LINEAR;
break;
}
#endif
}
for (int i = 0; i < shaders; i++)
{
if (!load_shader_params(i, conf))
{
RARCH_ERR("Failed to load shader params ...\n");
ret = false;
goto end;
}
if (!load_shader(path, i, conf))
if (!load_shader(path, i))
{
RARCH_ERR("Failed to load shaders ...\n");
ret = false;
goto end;
return false;
}
}
if (!load_textures(path, conf))
if (!load_textures(path))
{
RARCH_ERR("Failed to load lookup textures ...\n");
ret = false;
goto end;
return false;
}
if (!load_imports(path, conf))
if (!load_imports(path))
{
RARCH_ERR("Failed to load imports ...\n");
ret = false;
goto end;
return false;
}
end:
if (conf)
config_file_free(conf);
return ret;
return true;
}
static void set_program_base_attrib(unsigned i)
@ -1202,7 +851,7 @@ bool gl_cg_init(const char *path)
prg[0].mvp = cgGetNamedParameter(prg[0].vprg, "modelViewProj");
for (unsigned i = 1; i <= cg_shader_num; i++)
for (unsigned i = 1; i <= cg_shader->passes; i++)
set_program_attributes(i);
if (menu_cg_program)
@ -1230,37 +879,35 @@ void gl_cg_use(unsigned index)
unsigned gl_cg_num(void)
{
if (cg_active)
return cg_shader_num;
return cg_shader->passes;
else
return 0;
}
bool gl_cg_filter_type(unsigned index, bool *smooth)
{
if (cg_active)
if (cg_active && index)
{
if (fbo_smooth[index] == FILTER_UNSPEC)
if (cg_shader->pass[index - 1].filter == RARCH_FILTER_UNSPEC)
return false;
*smooth = (fbo_smooth[index] == FILTER_LINEAR);
*smooth = cg_shader->pass[index - 1].filter == RARCH_FILTER_LINEAR;
return true;
}
else
return false;
}
void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale)
void gl_cg_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (cg_active)
*scale = cg_scale[index];
if (cg_active && index)
*scale = cg_shader->pass[index - 1].fbo;
else
scale->valid = false;
}
void gl_cg_set_menu_shader(const char *path)
{
if (menu_cg_program)
free(menu_cg_program);
free(menu_cg_program);
menu_cg_program = strdup(path);
}
@ -1321,22 +968,6 @@ void gl_cg_invalidate_context(void)
cgCtx = NULL;
}
unsigned gl_cg_get_lut_info(struct gl_cg_lut_info *info, unsigned elems)
{
if (!cg_active)
return 0;
elems = elems > lut_textures_num ? lut_textures_num : elems;
for (unsigned i = 0; i < elems; i++)
{
strlcpy(info[i].id, lut_textures_uniform[i], sizeof(info[i].id));
info[i].tex = lut_textures[i];
}
return elems;
}
const gl_shader_backend_t gl_cg_backend = {
gl_cg_init,
gl_cg_deinit,

View File

@ -38,7 +38,7 @@ void gl_cg_use(unsigned index);
unsigned gl_cg_num(void);
bool gl_cg_filter_type(unsigned index, bool *smooth);
void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale);
void gl_cg_shader_scale(unsigned index, struct gfx_fbo_scale *scale);
bool gl_cg_set_mvp(const math_matrix *mat);
bool gl_cg_set_coords(const struct gl_coords *coords);
@ -54,15 +54,6 @@ void gl_cg_set_compiler_args(const char **argv);
bool gl_cg_load_shader(unsigned index, const char *path);
void gl_cg_invalidate_context(void); // Call when resetting GL context on PS3.
struct gl_cg_lut_info
{
char id[64];
GLuint tex;
};
unsigned gl_cg_get_lut_info(struct gl_cg_lut_info *info, unsigned elems);
extern const gl_shader_backend_t gl_cg_backend;
#endif

View File

@ -19,6 +19,7 @@
#include "../boolean.h"
#include "gl_common.h"
#include "gfx_context.h"
#include "shader_parse.h"
#include "math/matrix.h"
struct gl_shader_backend
@ -36,7 +37,7 @@ struct gl_shader_backend
void (*use)(unsigned index);
unsigned (*num_shaders)(void);
bool (*filter_type)(unsigned index, bool *smooth);
void (*shader_scale)(unsigned index, struct gl_fbo_scale *scale);
void (*shader_scale)(unsigned index, struct gfx_fbo_scale *scale);
bool (*set_coords)(const struct gl_coords *coords);
bool (*set_mvp)(const math_matrix *mat);

View File

@ -143,7 +143,7 @@ static bool glsl_enable;
static bool glsl_modern;
static GLuint gl_program[RARCH_GLSL_MAX_SHADERS];
static enum filter_type gl_filter_type[RARCH_GLSL_MAX_SHADERS];
static struct gl_fbo_scale gl_scale[RARCH_GLSL_MAX_SHADERS];
static struct gfx_fbo_scale gl_scale[RARCH_GLSL_MAX_SHADERS];
static unsigned gl_num_programs;
static unsigned active_index;
@ -174,8 +174,8 @@ struct shader_program
float scale_y;
unsigned abs_x;
unsigned abs_y;
enum gl_scale_type type_x;
enum gl_scale_type type_y;
enum gfx_scale_type type_x;
enum gfx_scale_type type_y;
unsigned frame_count_mod;
bool valid_scale;
@ -1591,7 +1591,7 @@ bool gl_glsl_filter_type(unsigned index, bool *smooth)
}
}
void gl_glsl_shader_scale(unsigned index, struct gl_fbo_scale *scale)
void gl_glsl_shader_scale(unsigned index, struct gfx_fbo_scale *scale)
{
if (glsl_enable)
*scale = gl_scale[index];

View File

@ -39,7 +39,7 @@ void gl_glsl_use(unsigned index);
unsigned gl_glsl_num(void);
bool gl_glsl_filter_type(unsigned index, bool *smooth);
void gl_glsl_shader_scale(unsigned index, struct gl_fbo_scale *scale);
void gl_glsl_shader_scale(unsigned index, struct gfx_fbo_scale *scale);
bool gl_glsl_set_coords(const struct gl_coords *coords);
bool gl_glsl_set_mvp(const math_matrix *mat);

513
gfx/shader_parse.c Normal file
View File

@ -0,0 +1,513 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "shader_parse.h"
#include "../compat/posix_string.h"
#include "../msvc/msvc_compat.h"
#include <stdlib.h>
#include <string.h>
#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass, unsigned i)
{
// 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)))
{
RARCH_ERR("Couldn't parse shader source (%s).\n", shader_name);
return false;
}
// Smooth
char filter_name_buf[64];
print_buf(filter_name_buf, "filter_linear%u", i);
bool smooth = false;
if (config_get_bool(conf, filter_name_buf, &smooth))
pass->filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST;
else
pass->filter = RARCH_FILTER_UNSPEC;
// Frame count mod
char frame_count_mod[64] = {0};
char frame_count_mod_buf[64];
print_buf(frame_count_mod_buf, "frame_count_mod%u", i);
if (config_get_array(conf, frame_count_mod_buf, frame_count_mod, sizeof(frame_count_mod)))
pass->frame_count_mod = strtoul(frame_count_mod, NULL, 0);
// Scale
struct gfx_fbo_scale *scale = &pass->fbo;
char scale_type[64] = {0};
char scale_type_x[64] = {0};
char scale_type_y[64] = {0};
char scale_name_buf[64];
print_buf(scale_name_buf, "scale_type%u", i);
config_get_array(conf, scale_name_buf, scale_type, sizeof(scale_type));
print_buf(scale_name_buf, "scale_type_x%u", i);
config_get_array(conf, scale_name_buf, scale_type_x, sizeof(scale_type_x));
print_buf(scale_name_buf, "scale_type_y%u", i);
config_get_array(conf, scale_name_buf, scale_type_y, sizeof(scale_type_y));
if (!*scale_type && !*scale_type_x && !*scale_type_y)
return true;
if (*scale_type)
{
strlcpy(scale_type_x, scale_type, sizeof(scale_type_x));
strlcpy(scale_type_y, scale_type, sizeof(scale_type_y));
}
char attr_name_buf[64];
float fattr = 0.0f;
int iattr = 0;
scale->valid = true;
scale->type_x = RARCH_SCALE_INPUT;
scale->type_y = RARCH_SCALE_INPUT;
scale->scale_x = 1.0;
scale->scale_y = 1.0;
char fp_fbo_buf[64];
print_buf(fp_fbo_buf, "float_framebuffer%u", i);
config_get_bool(conf, fp_fbo_buf, &scale->fp_fbo);
if (*scale_type_x)
{
if (strcmp(scale_type_x, "source") == 0)
scale->type_x = RARCH_SCALE_INPUT;
else if (strcmp(scale_type_x, "viewport") == 0)
scale->type_x = RARCH_SCALE_VIEWPORT;
else if (strcmp(scale_type_x, "absolute") == 0)
scale->type_x = RARCH_SCALE_ABSOLUTE;
else
{
RARCH_ERR("Invalid attribute.\n");
return false;
}
}
if (*scale_type_y)
{
if (strcmp(scale_type_y, "source") == 0)
scale->type_y = RARCH_SCALE_INPUT;
else if (strcmp(scale_type_y, "viewport") == 0)
scale->type_y = RARCH_SCALE_VIEWPORT;
else if (strcmp(scale_type_y, "absolute") == 0)
scale->type_y = RARCH_SCALE_ABSOLUTE;
else
{
RARCH_ERR("Invalid attribute.\n");
return false;
}
}
if (scale->type_x == RARCH_SCALE_ABSOLUTE)
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
else
{
print_buf(attr_name_buf, "scale_x%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
}
}
else
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
else
{
print_buf(attr_name_buf, "scale_x%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
}
}
if (scale->type_y == RARCH_SCALE_ABSOLUTE)
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
else
{
print_buf(attr_name_buf, "scale_y%u", i);
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
}
}
else
{
print_buf(attr_name_buf, "scale%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
else
{
print_buf(attr_name_buf, "scale_y%u", i);
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
}
}
return true;
}
static bool shader_parse_textures(config_file_t *conf, struct gfx_shader *shader)
{
char textures[1024];
if (!config_get_array(conf, "textures", textures, sizeof(textures)))
return true;
char *save;
for (const char *id = strtok_r(textures, ";", &save);
id && shader->luts < GFX_MAX_TEXTURES;
shader->luts++, id = strtok_r(NULL, ";", &save))
{
if (!config_get_array(conf, id, shader->lut[shader->luts].path, sizeof(shader->lut[shader->luts].path)))
{
RARCH_ERR("Cannot find path to texture \"%s\" ...\n", id);
return false;
}
strlcpy(shader->lut[shader->luts].id, id, sizeof(shader->lut[shader->luts].id));
char id_filter[64];
print_buf(id_filter, "%s_linear", id);
bool smooth = false;
if (config_get_bool(conf, id_filter, &smooth))
shader->lut[shader->luts].filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST;
else
shader->lut[shader->luts].filter = RARCH_FILTER_UNSPEC;
}
return true;
}
static bool shader_parse_imports(config_file_t *conf, struct gfx_shader *shader)
{
char imports[1024];
if (!config_get_array(conf, "imports", imports, sizeof(imports)))
return true;
char *save;
const char *id = strtok_r(imports, ";", &save);
for (const char *id = strtok_r(imports, ";", &save);
id && shader->variables < GFX_MAX_VARIABLES;
shader->variables++, id = strtok_r(NULL, ";", &save))
{
struct state_tracker_uniform_info *var = &shader->variable[shader->variables];
strlcpy(var->id, id, sizeof(var->id));
char semantic_buf[64];
char wram_buf[64];
char input_slot_buf[64];
char mask_buf[64];
char equal_buf[64];
print_buf(semantic_buf, "%s_semantic", id);
print_buf(wram_buf, "%s_wram", id);
print_buf(input_slot_buf, "%s_input_slot", id);
print_buf(mask_buf, "%s_mask", id);
print_buf(equal_buf, "%s_equal", id);
char semantic[64];
if (!config_get_array(conf, semantic_buf, semantic, sizeof(semantic)))
{
RARCH_ERR("No semantic for import variable.\n");
return false;
}
enum state_ram_type ram_type = RARCH_STATE_NONE;
if (strcmp(semantic, "capture") == 0)
var->type = RARCH_STATE_CAPTURE;
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, "capture_previous") == 0)
var->type = RARCH_STATE_CAPTURE_PREV;
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.\n");
return false;
}
unsigned addr = 0, mask = 0, equal = 0;
if (var->type != RARCH_STATE_PYTHON)
{
unsigned input_slot = 0;
if (config_get_uint(conf, input_slot_buf, &input_slot))
{
switch (input_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 (config_get_hex(conf, wram_buf, &addr))
{
var->ram_type = RARCH_STATE_WRAM;
var->addr = addr;
}
else
{
RARCH_ERR("No address assigned to semantic.\n");
return false;
}
}
if (config_get_hex(conf, mask_buf, &mask))
var->mask = mask;
if (config_get_hex(conf, equal_buf, &equal))
var->equal = equal;
}
config_get_path(conf, "import_script", shader->script_path, sizeof(shader->script_path));
config_get_array(conf, "import_script_class", shader->script_class, sizeof(shader->script_class));
return true;
}
bool gfx_shader_read_conf_cgp(config_file_t *conf, struct gfx_shader *shader)
{
memset(shader, 0, sizeof(*shader));
unsigned shaders = 0;
if (!config_get_uint(conf, "shaders", &shaders))
{
RARCH_ERR("Cannot find \"shaders\" param.\n");
return false;
}
if (!shaders)
{
RARCH_ERR("Need to define at least 1 shader.\n");
return false;
}
shader->passes = min(shaders, GFX_MAX_SHADERS);
for (unsigned i = 0; i < shader->passes; i++)
{
if (!shader_parse_pass(conf, &shader->pass[i], i))
return false;
}
if (!shader_parse_textures(conf, shader))
return false;
if (!shader_parse_imports(conf, shader))
return false;
return true;
}
static const char *scale_type_to_str(enum gfx_scale_type type)
{
switch (type)
{
case RARCH_SCALE_INPUT:
return "source";
case RARCH_SCALE_VIEWPORT:
return "viewport";
case RARCH_SCALE_ABSOLUTE:
return "absolute";
default:
return "?";
}
}
static void shader_write_scale_dim(config_file_t *conf, const char *dim,
enum gfx_scale_type type, float scale, unsigned abs, unsigned i)
{
char key[64];
print_buf(key, "scale_type_%s%u", dim, i);
config_set_string(conf, key, scale_type_to_str(type));
print_buf(key, "scale_%s%u", dim, i);
if (type == RARCH_SCALE_ABSOLUTE)
config_set_int(conf, key, abs);
else
config_set_float(conf, key, scale);
}
static void shader_write_fbo(config_file_t *conf, const struct gfx_fbo_scale *fbo, unsigned i)
{
char key[64];
print_buf(key, "float_framebuffer%u", i);
config_set_bool(conf, key, fbo->fp_fbo);
if (!fbo->valid)
return;
shader_write_scale_dim(conf, "x", fbo->type_x, fbo->scale_x, fbo->abs_x, i);
shader_write_scale_dim(conf, "y", fbo->type_y, fbo->scale_y, fbo->abs_y, i);
}
static const char *import_semantic_to_string(enum state_tracker_type type)
{
switch (type)
{
case RARCH_STATE_CAPTURE:
return "capture";
case RARCH_STATE_TRANSITION:
return "transition";
case RARCH_STATE_TRANSITION_COUNT:
return "transition_count";
case RARCH_STATE_CAPTURE_PREV:
return "capture_previous";
case RARCH_STATE_TRANSITION_PREV:
return "transition_previous";
case RARCH_STATE_PYTHON:
return "python";
default:
return "?";
}
}
static void shader_write_variable(config_file_t *conf, const struct state_tracker_uniform_info *info)
{
const char *id = info->id;
char semantic_buf[64];
char wram_buf[64];
char input_slot_buf[64];
char mask_buf[64];
char equal_buf[64];
print_buf(semantic_buf, "%s_semantic", id);
print_buf(wram_buf, "%s_wram", id);
print_buf(input_slot_buf, "%s_input_slot", id);
print_buf(mask_buf, "%s_mask", id);
print_buf(equal_buf, "%s_equal", id);
config_set_string(conf, semantic_buf, import_semantic_to_string(info->type));
config_set_hex(conf, mask_buf, info->mask);
config_set_hex(conf, equal_buf, info->equal);
switch (info->ram_type)
{
case RARCH_STATE_INPUT_SLOT1:
config_set_int(conf, input_slot_buf, 1);
break;
case RARCH_STATE_INPUT_SLOT2:
config_set_int(conf, input_slot_buf, 2);
break;
case RARCH_STATE_WRAM:
config_set_hex(conf, wram_buf, info->addr);
break;
default:
break;
}
}
void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *shader)
{
config_set_int(conf, "shaders", shader->passes);
for (unsigned i = 0; i < shader->passes; i++)
{
const struct gfx_shader_pass *pass = &shader->pass[i];
char key[64];
print_buf(key, "shader%u", i);
config_set_string(conf, key, pass->source.cg);
if (pass->filter != RARCH_FILTER_UNSPEC)
{
print_buf(key, "filter_linear%u", i);
config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR);
}
if (pass->frame_count_mod)
{
print_buf(key, "frame_count_mod%u", i);
config_set_int(conf, key, pass->frame_count_mod);
}
shader_write_fbo(conf, &pass->fbo, i);
}
if (shader->luts)
{
char textures[4096] = {0};
strlcpy(textures, shader->lut[0].id, sizeof(textures));
for (unsigned i = 1; i < shader->luts; i++)
{
// O(n^2), but number of textures is very limited.
strlcat(textures, ";", sizeof(textures));
strlcat(textures, shader->lut[i].id, sizeof(textures));
}
config_set_string(conf, "textures", textures);
for (unsigned i = 0; i < shader->luts; i++)
{
char key[64];
if (shader->lut[i].filter != RARCH_FILTER_UNSPEC)
{
print_buf(key, "%s_linear", shader->lut[i].id);
config_set_bool(conf, key, shader->lut[i].filter != RARCH_FILTER_LINEAR);
}
}
}
if (*shader->script_path)
config_set_string(conf, "import_script", shader->script_path);
if (*shader->script_class)
config_set_string(conf, "import_script_class", shader->script_class);
if (shader->variables)
{
char variables[4096] = {0};
strlcpy(variables, shader->variable[0].id, sizeof(variables));
for (unsigned i = 1; i < shader->variables; i++)
{
strlcat(variables, ";", sizeof(variables));
strlcat(variables, shader->variable[i].id, sizeof(variables));
}
config_set_string(conf, "imports", variables);
for (unsigned i = 0; i < shader->variables; i++)
shader_write_variable(conf, &shader->variable[i]);
}
}

98
gfx/shader_parse.h Normal file
View File

@ -0,0 +1,98 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2013 - Hans-Kristian Arntzen
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SHADER_PARSE_H
#define SHADER_PARSE_H
#include "boolean.h"
#include "../conf/config_file.h"
#include "state_tracker.h"
#include "../general.h"
#define GFX_MAX_SHADERS 16
#define GFX_MAX_TEXTURES 8
#define GFX_MAX_VARIABLES 64
enum gfx_scale_type
{
RARCH_SCALE_INPUT = 0,
RARCH_SCALE_ABSOLUTE,
RARCH_SCALE_VIEWPORT
};
enum gfx_filter_type
{
RARCH_FILTER_UNSPEC = 0,
RARCH_FILTER_LINEAR,
RARCH_FILTER_NEAREST,
};
struct gfx_fbo_scale
{
bool valid;
enum gfx_scale_type type_x;
enum gfx_scale_type type_y;
float scale_x;
float scale_y;
unsigned abs_x;
unsigned abs_y;
bool fp_fbo;
};
struct gfx_shader_pass
{
union
{
char cg[PATH_MAX];
struct
{
char vertex[PATH_MAX];
char fragment[PATH_MAX];
} glsl;
} source;
struct gfx_fbo_scale fbo;
enum gfx_filter_type filter;
unsigned frame_count_mod;
};
struct gfx_shader_lut
{
char id[64];
char path[PATH_MAX];
enum gfx_filter_type filter;
};
// This is pretty big, shouldn't be put on the stack.
// Avoid lots of allocation for convenience.
struct gfx_shader
{
unsigned passes;
struct gfx_shader_pass pass[GFX_MAX_SHADERS];
unsigned luts;
struct gfx_shader_lut lut[GFX_MAX_TEXTURES];
unsigned variables;
struct state_tracker_uniform_info variable[GFX_MAX_VARIABLES];
char script_path[PATH_MAX];
char script_class[512];
};
bool gfx_shader_read_conf_cgp(config_file_t *conf, struct gfx_shader *shader);
void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *shader);
#endif

View File

@ -29,14 +29,12 @@ extern "C" {
enum state_tracker_type
{
#ifdef HAVE_PYTHON
RARCH_STATE_PYTHON,
#endif
RARCH_STATE_CAPTURE,
RARCH_STATE_CAPTURE = 0,
RARCH_STATE_CAPTURE_PREV,
RARCH_STATE_TRANSITION,
RARCH_STATE_TRANSITION_COUNT,
RARCH_STATE_TRANSITION_PREV
RARCH_STATE_TRANSITION_PREV,
RARCH_STATE_PYTHON
};
enum state_ram_type

View File

@ -109,6 +109,10 @@ VIDEO CONTEXT
VIDEO SHADERS
============================================================ */
#if defined(HAVE_CG) || defined(HAVE_HLSL)
#include "../gfx/shader_parse.c"
#endif
#ifdef HAVE_CG
#include "../gfx/shader_cg.c"
#endif