diff --git a/Makefile.ps3 b/Makefile.ps3 index d587240c35..bb0280a983 100644 --- a/Makefile.ps3 +++ b/Makefile.ps3 @@ -56,7 +56,6 @@ PPU_SRCS = fifo_buffer.c \ movie.c \ netplay.c \ ps3/ps3_video_psgl.c \ - ps3/shader_cg.c \ gfx/snes_state.c \ patch.c \ audio/hermite.c \ diff --git a/ps3/menu.c b/ps3/menu.c index 05ac5a3840..88f7d3f8fb 100644 --- a/ps3/menu.c +++ b/ps3/menu.c @@ -36,7 +36,6 @@ #include "shared.h" #include "../file.h" #include "../general.h" -#include "../gfx/shader_cg.h" #include "menu-port-defines.h" #include "menu.h" diff --git a/ps3/ps3_video_psgl.c b/ps3/ps3_video_psgl.c index b29ed8dbd2..09c6a273c7 100644 --- a/ps3/ps3_video_psgl.c +++ b/ps3/ps3_video_psgl.c @@ -30,7 +30,9 @@ #include +#include "../gfx/snes_state.h" #include "../general.h" +#include "../compat/strl.h" #include "shared.h" #ifdef HAVE_CONFIG_H @@ -39,8 +41,6 @@ #include "../compat/strl.h" -#include "../gfx/shader_cg.h" - #define BLUE 0xffff0000u #define WHITE 0xffffffffu @@ -103,6 +103,1182 @@ bool g_quitting; unsigned g_frame_count; void *g_gl; +/*============================================================ + CG IMPLEMENTATION +============================================================ */ + +#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) + +// Used when we call deactivate() since just unbinding the program didn't seem to work... :( +static const char *stock_cg_program = + "void main_vertex" + "(" + " float4 position : POSITION," + " float2 texCoord : TEXCOORD0," + " float4 color : COLOR," + "" + " uniform float4x4 modelViewProj," + "" + " out float4 oPosition : POSITION," + " out float2 otexCoord : TEXCOORD0," + " out float4 oColor : COLOR" + ")" + "{" + " oPosition = mul(modelViewProj, position);" + " otexCoord = texCoord;" + " oColor = color;" + "}" + "" + "float4 main_fragment(in float4 color : COLOR, float2 tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0) : COLOR" + "{" + " return color * tex2D(s0, tex);" + "}"; + +static char *menu_cg_program; + +static CGcontext cgCtx; + +struct cg_fbo_params +{ + CGparameter vid_size_f; + CGparameter tex_size_f; + CGparameter vid_size_v; + CGparameter tex_size_v; + CGparameter tex; + CGparameter coord; +}; + +#define MAX_TEXTURES 8 +#define MAX_VARIABLES 64 +#define PREV_TEXTURES 7 + +struct cg_program +{ + CGprogram vprg; + CGprogram fprg; + CGparameter vid_size_f; + CGparameter tex_size_f; + CGparameter out_size_f; + CGparameter frame_cnt_f; + CGparameter frame_dir_f; + CGparameter vid_size_v; + CGparameter tex_size_v; + CGparameter out_size_v; + CGparameter frame_cnt_v; + CGparameter frame_dir_v; + CGparameter mvp; + + struct cg_fbo_params fbo[SSNES_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[SSNES_CG_MAX_SHADERS]; +static const char **cg_arguments; +static CGprofile cgVProf, cgFProf; +static unsigned active_index = 0; +static unsigned cg_shader_num = 0; +static struct gl_fbo_scale cg_scale[SSNES_CG_MAX_SHADERS]; +static unsigned fbo_smooth[SSNES_CG_MAX_SHADERS]; + +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 + SSNES_CG_MAX_SHADERS]; +static unsigned cg_attrib_index; + +static snes_tracker_t *snes_tracker = NULL; + +static void gl_cg_reset_attrib(void) +{ + for (unsigned i = 0; i < cg_attrib_index; i++) + cgGLDisableClientState(cg_attribs[i]); + cg_attrib_index = 0; +} + +#define set_param_2f(param, x, y) \ + if (param) cgGLSetParameter2f(param, x, y) +#define set_param_1f(param, x) \ + if (param) cgGLSetParameter1f(param, x) + +static inline void gl_cg_set_params(unsigned width, unsigned height, + unsigned tex_width, unsigned tex_height, + unsigned out_width, unsigned out_height, + unsigned frame_count, + const struct gl_tex_info *info, + const struct gl_tex_info *prev_info, + const struct gl_tex_info *fbo_info, + unsigned fbo_info_cnt) +{ + if (active_index == 0) + return; + + // Set frame. + set_param_2f(prg[active_index].vid_size_f, width, height); + set_param_2f(prg[active_index].tex_size_f, tex_width, tex_height); + set_param_2f(prg[active_index].out_size_f, out_width, out_height); + set_param_1f(prg[active_index].frame_cnt_f, (float)frame_count); + set_param_1f(prg[active_index].frame_dir_f, g_extern.frame_is_reverse ? -1.0 : 1.0); + + set_param_2f(prg[active_index].vid_size_v, width, height); + set_param_2f(prg[active_index].tex_size_v, tex_width, tex_height); + set_param_2f(prg[active_index].out_size_v, out_width, out_height); + set_param_1f(prg[active_index].frame_cnt_v, (float)frame_count); + set_param_1f(prg[active_index].frame_dir_v, g_extern.frame_is_reverse ? -1.0 : 1.0); + + if (active_index == SSNES_CG_MENU_SHADER_INDEX) + return; + + // Set orig texture. + CGparameter param = prg[active_index].orig.tex; + if (param) + { + cgGLSetTextureParameter(param, info->tex); + cgGLEnableTextureParameter(param); + } + + set_param_2f(prg[active_index].orig.vid_size_v, info->input_size[0], info->input_size[1]); + set_param_2f(prg[active_index].orig.vid_size_f, info->input_size[0], info->input_size[1]); + set_param_2f(prg[active_index].orig.tex_size_v, info->tex_size[0], info->tex_size[1]); + set_param_2f(prg[active_index].orig.tex_size_f, info->tex_size[0], info->tex_size[1]); + if (prg[active_index].orig.coord) + { + cgGLSetParameterPointer(prg[active_index].orig.coord, 2, GL_FLOAT, 0, info->coord); + cgGLEnableClientState(prg[active_index].orig.coord); + cg_attribs[cg_attrib_index++] = prg[active_index].orig.coord; + } + + // Set prev textures. + for (unsigned i = 0; i < PREV_TEXTURES; i++) + { + param = prg[active_index].prev[i].tex; + if (param) + { + cgGLSetTextureParameter(param, prev_info[i].tex); + cgGLEnableTextureParameter(param); + } + + set_param_2f(prg[active_index].prev[i].vid_size_v, prev_info[i].input_size[0], prev_info[i].input_size[1]); + set_param_2f(prg[active_index].prev[i].vid_size_f, prev_info[i].input_size[0], prev_info[i].input_size[1]); + set_param_2f(prg[active_index].prev[i].tex_size_v, prev_info[i].tex_size[0], prev_info[i].tex_size[1]); + set_param_2f(prg[active_index].prev[i].tex_size_f, prev_info[i].tex_size[0], prev_info[i].tex_size[1]); + + if (prg[active_index].prev[i].coord) + { + cgGLSetParameterPointer(prg[active_index].prev[i].coord, 2, GL_FLOAT, 0, prev_info[i].coord); + cgGLEnableClientState(prg[active_index].prev[i].coord); + cg_attribs[cg_attrib_index++] = prg[active_index].prev[i].coord; + } + } + + // Set lookup textures. + for (unsigned i = 0; i < lut_textures_num; i++) + { + CGparameter param = cgGetNamedParameter(prg[active_index].fprg, lut_textures_uniform[i]); + if (param) + { + cgGLSetTextureParameter(param, lut_textures[i]); + cgGLEnableTextureParameter(param); + } + } + + // Set FBO textures. + if (active_index > 2) + { + for (unsigned i = 0; i < fbo_info_cnt; i++) + { + if (prg[active_index].fbo[i].tex) + { + cgGLSetTextureParameter(prg[active_index].fbo[i].tex, fbo_info[i].tex); + cgGLEnableTextureParameter(prg[active_index].fbo[i].tex); + } + + set_param_2f(prg[active_index].fbo[i].vid_size_v, fbo_info[i].input_size[0], fbo_info[i].input_size[1]); + set_param_2f(prg[active_index].fbo[i].vid_size_f, fbo_info[i].input_size[0], fbo_info[i].input_size[1]); + + set_param_2f(prg[active_index].fbo[i].tex_size_v, fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); + set_param_2f(prg[active_index].fbo[i].tex_size_f, fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); + + if (prg[active_index].fbo[i].coord) + { + cgGLSetParameterPointer(prg[active_index].fbo[i].coord, 2, GL_FLOAT, 0, fbo_info[i].coord); + cgGLEnableClientState(prg[active_index].fbo[i].coord); + cg_attribs[cg_attrib_index++] = prg[active_index].fbo[i].coord; + } + } + } + + // Set state parameters + if (snes_tracker) + { + static struct snes_tracker_uniform info[MAX_VARIABLES]; + static unsigned cnt = 0; + + if (active_index == 1) + cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count); + + for (unsigned i = 0; i < cnt; i++) + { + CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, info[i].id); + CGparameter param_f = cgGetNamedParameter(prg[active_index].fprg, info[i].id); + set_param_1f(param_v, info[i].value); + set_param_1f(param_f, info[i].value); + } + } +} + +static void gl_cg_deinit_progs(void) +{ + cgGLUnbindProgram(cgFProf); + cgGLUnbindProgram(cgVProf); + + // Programs may alias [0]. + for (unsigned i = 1; i < SSNES_CG_MAX_SHADERS; i++) + { + if (prg[i].fprg != prg[0].fprg) + cgDestroyProgram(prg[i].fprg); + if (prg[i].vprg != prg[0].vprg) + cgDestroyProgram(prg[i].vprg); + } + + if (prg[0].fprg) + cgDestroyProgram(prg[0].fprg); + if (prg[0].vprg) + cgDestroyProgram(prg[0].vprg); + + memset(prg, 0, sizeof(prg)); +} + +static void gl_cg_deinit_state(void) +{ + gl_cg_reset_attrib(); + + 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 (snes_tracker) + { + snes_tracker_free(snes_tracker); + snes_tracker = NULL; + } +} + +// Final deinit. +static void gl_cg_deinit_context_state(void) +{ + if (menu_cg_program) + { + free(menu_cg_program); + menu_cg_program = NULL; + } +} + +// Full deinit. +static void gl_cg_deinit(void) +{ + gl_cg_deinit_state(); + gl_cg_deinit_context_state(); +} + +#define SET_LISTING(type) \ +{ \ + const char *list = cgGetLastListing(cgCtx); \ + if (list) \ + listing_##type = strdup(list); \ +} + +static bool load_program(unsigned index, const char *prog, bool path_is_file) +{ + bool ret = true; + char *listing_f = NULL; + char *listing_v = NULL; + + if (path_is_file) + { + prg[index].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); + SET_LISTING(f); + prg[index].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); + SET_LISTING(v); + } + else + { + prg[index].fprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); + SET_LISTING(f); + prg[index].vprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); + SET_LISTING(v); + } + + if (!prg[index].fprg || !prg[index].vprg) + { + SSNES_ERR("CG error: %s\n", cgGetErrorString(cgGetError())); + if (listing_f) + SSNES_ERR("Fragment:\n%s\n", listing_f); + else if (listing_v) + SSNES_ERR("Vertex:\n%s\n", listing_v); + + ret = false; + goto end; + } + + cgGLLoadProgram(prg[index].fprg); + cgGLLoadProgram(prg[index].vprg); + +end: + free(listing_f); + free(listing_v); + return ret; +} + +static bool load_stock(void) +{ + if (!load_program(0, stock_cg_program, false)) + { + SSNES_ERR("Failed to compile passthrough shader, is something wrong with your environment?\n"); + return false; + } + + return true; +} + +static bool load_shader_params(unsigned i, config_file_t *conf) +{ + bool ret = true; + char *scale_type = NULL; + char *scale_type_x = NULL; + char *scale_type_y = NULL; + bool has_scale_type; + bool has_scale_type_x; + bool has_scale_type_y; + + char scale_name_buf[64]; + print_buf(scale_name_buf, "scale_type%u", i); + has_scale_type = config_get_string(conf, scale_name_buf, &scale_type); + print_buf(scale_name_buf, "scale_type_x%u", i); + has_scale_type_x = config_get_string(conf, scale_name_buf, &scale_type_x); + print_buf(scale_name_buf, "scale_type_y%u", i); + has_scale_type_y = config_get_string(conf, scale_name_buf, &scale_type_y); + + if (!has_scale_type && !has_scale_type_x && !has_scale_type_y) + return true; + + if (has_scale_type) + { + free(scale_type_x); + free(scale_type_y); + + scale_type_x = strdup(scale_type); + scale_type_y = strdup(scale_type); + + free(scale_type); + scale_type = NULL; + } + + char attr_name_buf[64]; + float fattr; + int iattr; + struct gl_fbo_scale *scale = &cg_scale[i + 1]; // Shader 0 is passthrough shader. Start at 1. + + scale->valid = true; + scale->type_x = SSNES_SCALE_INPUT; + scale->type_y = SSNES_SCALE_INPUT; + scale->scale_x = 1.0; + scale->scale_y = 1.0; + scale->abs_x = g_extern.system.geom.base_width; + scale->abs_y = g_extern.system.geom.base_height; + + if (strcmp(scale_type_x, "source") == 0) + scale->type_x = SSNES_SCALE_INPUT; + else if (strcmp(scale_type_x, "viewport") == 0) + scale->type_x = SSNES_SCALE_VIEWPORT; + else if (strcmp(scale_type_x, "absolute") == 0) + scale->type_x = SSNES_SCALE_ABSOLUTE; + else + { + SSNES_ERR("Invalid attribute.\n"); + ret = false; + goto end; + } + + if (strcmp(scale_type_y, "source") == 0) + scale->type_y = SSNES_SCALE_INPUT; + else if (strcmp(scale_type_y, "viewport") == 0) + scale->type_y = SSNES_SCALE_VIEWPORT; + else if (strcmp(scale_type_y, "absolute") == 0) + scale->type_y = SSNES_SCALE_ABSOLUTE; + else + { + SSNES_ERR("Invalid attribute.\n"); + ret = false; + goto end; + } + + if (scale->type_x == SSNES_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 == SSNES_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; + } + } + +end: + free(scale_type); + free(scale_type_x); + free(scale_type_y); + return ret; +} + +static bool load_shader(const char *dir_path, unsigned i, config_file_t *conf) +{ + char *shader_path; + 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)) + { + strlcpy(path_buf, dir_path, sizeof(path_buf)); + strlcat(path_buf, shader_path, sizeof(path_buf)); + free(shader_path); + } + else + { + SSNES_ERR("Didn't find shader path in config ...\n"); + return false; + } + + SSNES_LOG("Loading Cg shader: \"%s\".\n", path_buf); + + if (!load_program(i + 1, path_buf, true)) + return false; + + return true; +} + +static void load_texture_data(GLuint *obj, const struct texture_image *img, bool smooth) +{ + glGenTextures(1, obj); + glBindTexture(GL_TEXTURE_2D, *obj); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, + 0, GL_ARGB_SCE, img->width, img->height, + 0, GL_ARGB_SCE, GL_UNSIGNED_INT_8_8_8_8, img->pixels); + + free(img->pixels); +} + +static bool load_textures(const char *dir_path, config_file_t *conf) +{ + bool ret = true; + char *textures = NULL; + if (!config_get_string(conf, "textures", &textures)) // No textures here ... + return true; + + const char *id = strtok(textures, ";");; + while (id && lut_textures_num < MAX_TEXTURES) + { + char path[PATH_MAX]; + if (!config_get_array(conf, id, path, sizeof(path))) + { + SSNES_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[512]; + if (absolute) + print_buf(image_path, "%s", path); + else + print_buf(image_path, "%s%s", dir_path, path); + + SSNES_LOG("Loading image from: \"%s\".\n", image_path); + struct texture_image img; + if (!texture_image_load(image_path, &img)) + { + SSNES_ERR("Failed to load picture ...\n"); + ret = false; + goto end; + } + + 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(NULL, ";"); + } + +end: + free(textures); + glBindTexture(GL_TEXTURE_2D, 0); + return ret; +} + +static bool load_imports(const char *dir_path, config_file_t *conf) +{ + bool ret = true; + char *imports = NULL; + + if (!config_get_string(conf, "imports", &imports)) + return true; + + struct snes_tracker_uniform_info info[MAX_VARIABLES]; + unsigned info_cnt = 0; + struct snes_tracker_info tracker_info = {0}; + + const char *id = strtok(imports, ";"); + while (id && info_cnt < MAX_VARIABLES) + { + char semantic_buf[64]; + char wram_buf[64]; + char input_slot_buf[64]; + char apuram_buf[64]; + char oam_buf[64]; + char cgram_buf[64]; + char vram_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(apuram_buf, "%s_apuram", id); + print_buf(oam_buf, "%s_oam", id); + print_buf(cgram_buf, "%s_cgram", id); + print_buf(vram_buf, "%s_vram", 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) + { + SSNES_ERR("No semantic for import variable.\n"); + ret = false; + goto end; + } + + enum snes_tracker_type tracker_type; + enum snes_ram_type ram_type = SSNES_STATE_NONE; + + if (strcmp(semantic, "capture") == 0) + tracker_type = SSNES_STATE_CAPTURE; + else if (strcmp(semantic, "transition") == 0) + tracker_type = SSNES_STATE_TRANSITION; + else if (strcmp(semantic, "transition_count") == 0) + tracker_type = SSNES_STATE_TRANSITION_COUNT; + else if (strcmp(semantic, "capture_previous") == 0) + tracker_type = SSNES_STATE_CAPTURE_PREV; + else if (strcmp(semantic, "transition_previous") == 0) + tracker_type = SSNES_STATE_TRANSITION_PREV; + else + { + SSNES_ERR("Invalid semantic.\n"); + ret = false; + goto end; + } + + unsigned addr = 0; + unsigned input_slot = 0; + if (config_get_hex(conf, input_slot_buf, &input_slot)) + { + switch (input_slot) + { + case 1: + ram_type = SSNES_STATE_INPUT_SLOT1; + break; + + case 2: + ram_type = SSNES_STATE_INPUT_SLOT2; + break; + + default: + SSNES_ERR("Invalid input slot for import.\n"); + ret = false; + goto end; + } + } + else if (config_get_hex(conf, wram_buf, &addr)) + ram_type = SSNES_STATE_WRAM; + else if (config_get_hex(conf, apuram_buf, &addr)) + ram_type = SSNES_STATE_APURAM; + else if (config_get_hex(conf, oam_buf, &addr)) + ram_type = SSNES_STATE_OAM; + else if (config_get_hex(conf, cgram_buf, &addr)) + ram_type = SSNES_STATE_CGRAM; + else if (config_get_hex(conf, vram_buf, &addr)) + ram_type = SSNES_STATE_VRAM; + else + { + SSNES_ERR("No address assigned to semantic.\n"); + ret = false; + goto end; + } + + unsigned memtype; + switch (ram_type) + { + case SSNES_STATE_WRAM: + memtype = SNES_MEMORY_WRAM; + break; + case SSNES_STATE_APURAM: + memtype = SNES_MEMORY_APURAM; + break; + case SSNES_STATE_VRAM: + memtype = SNES_MEMORY_VRAM; + break; + case SSNES_STATE_OAM: + memtype = SNES_MEMORY_OAM; + break; + case SSNES_STATE_CGRAM: + memtype = SNES_MEMORY_CGRAM; + break; + + default: + memtype = -1u; + } + + if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype))) + { + SSNES_ERR("Address out of bounds.\n"); + ret = false; + goto end; + } + + unsigned bitmask; + if (!config_get_hex(conf, mask_buf, &bitmask)) + bitmask = 0; + unsigned bitequal; + 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(NULL, ";"); + } + + tracker_info.wram = psnes_get_memory_data(SNES_MEMORY_WRAM); + tracker_info.vram = psnes_get_memory_data(SNES_MEMORY_VRAM); + tracker_info.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM); + tracker_info.oam = psnes_get_memory_data(SNES_MEMORY_OAM); + tracker_info.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM); + tracker_info.info = info; + tracker_info.info_elem = info_cnt; + + snes_tracker = snes_tracker_init(&tracker_info); + if (!snes_tracker) + SSNES_WARN("Failed to init SNES tracker.\n"); + +end: + free(imports); + return ret; +} + +static bool load_preset(const char *path) +{ + bool ret = true; + + if (!load_stock()) + return false; + + int shaders; + // Basedir. + char dir_path[PATH_MAX]; + char *ptr = NULL; + + SSNES_LOG("Loading Cg meta-shader: %s\n", path); + config_file_t *conf = config_file_new(path); + if (!conf) + { + SSNES_ERR("Failed to load preset.\n"); + ret = false; + goto end; + } + + if (!config_get_int(conf, "shaders", &shaders)) + { + SSNES_ERR("Cannot find \"shaders\" param.\n"); + ret = false; + goto end; + } + + if (shaders < 1) + { + SSNES_ERR("Need to define at least 1 shader.\n"); + ret = false; + goto end; + } + + cg_shader_num = shaders; + if (shaders > SSNES_CG_MAX_SHADERS - 3) + { + SSNES_WARN("Too many shaders ... Capping shader amount to %d.\n", SSNES_CG_MAX_SHADERS - 3); + cg_shader_num = shaders = SSNES_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]; + + // Check filter params. + for (int i = 0; i < shaders; i++) + { + bool smooth; + 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; + } + + strlcpy(dir_path, path, sizeof(dir_path)); + ptr = strrchr(dir_path, '/'); + if (!ptr) ptr = strrchr(dir_path, '\\'); + if (ptr) + ptr[1] = '\0'; + else // No directory. + dir_path[0] = '\0'; + + for (int i = 0; i < shaders; i++) + { + if (!load_shader_params(i, conf)) + { + SSNES_ERR("Failed to load shader params ...\n"); + ret = false; + goto end; + } + + if (!load_shader(dir_path, i, conf)) + { + SSNES_ERR("Failed to load shaders ...\n"); + ret = false; + goto end; + } + } + + if (!load_textures(dir_path, conf)) + { + SSNES_ERR("Failed to load lookup textures ...\n"); + ret = false; + goto end; + } + + if (!load_imports(dir_path, conf)) + { + SSNES_ERR("Failed to load imports ...\n"); + ret = false; + goto end; + } + +end: + if (conf) + config_file_free(conf); + return ret; + +} + +static bool load_plain(const char *path) +{ + if (!load_stock()) + return false; + + SSNES_LOG("Loading Cg file: %s\n", path); + + if (!load_program(1, path, true)) + return false; + + if (*g_settings.video.second_pass_shader && g_settings.video.render_to_texture) + { + if (!load_program(2, g_settings.video.second_pass_shader, true)) + return false; + + cg_shader_num = 2; + } + else + { + prg[2] = prg[0]; + cg_shader_num = 1; + } + + return true; +} + +static bool load_menu_shader(void) +{ + return load_program(SSNES_CG_MENU_SHADER_INDEX, menu_cg_program, true); +} + +static void set_program_attributes(unsigned i) +{ + cgGLBindProgram(prg[i].fprg); + cgGLBindProgram(prg[i].vprg); + + prg[i].vid_size_f = cgGetNamedParameter(prg[i].fprg, "IN.video_size"); + prg[i].tex_size_f = cgGetNamedParameter(prg[i].fprg, "IN.texture_size"); + prg[i].out_size_f = cgGetNamedParameter(prg[i].fprg, "IN.output_size"); + prg[i].frame_cnt_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_count"); + prg[i].frame_dir_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_direction"); + prg[i].vid_size_v = cgGetNamedParameter(prg[i].vprg, "IN.video_size"); + prg[i].tex_size_v = cgGetNamedParameter(prg[i].vprg, "IN.texture_size"); + prg[i].out_size_v = cgGetNamedParameter(prg[i].vprg, "IN.output_size"); + prg[i].frame_cnt_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_count"); + prg[i].frame_dir_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_direction"); + prg[i].mvp = cgGetNamedParameter(prg[i].vprg, "modelViewProj"); + if (prg[i].mvp) + cgGLSetStateMatrixParameter(prg[i].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + + if (i == SSNES_CG_MENU_SHADER_INDEX) + return; + + prg[i].orig.tex = cgGetNamedParameter(prg[i].fprg, "ORIG.texture"); + prg[i].orig.vid_size_v = cgGetNamedParameter(prg[i].vprg, "ORIG.video_size"); + prg[i].orig.vid_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.video_size"); + prg[i].orig.tex_size_v = cgGetNamedParameter(prg[i].vprg, "ORIG.texture_size"); + prg[i].orig.tex_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.texture_size"); + prg[i].orig.coord = cgGetNamedParameter(prg[i].vprg, "ORIG.tex_coord"); + + for (unsigned j = 0; j < PREV_TEXTURES; j++) + { + char attr_buf_tex[64]; + char attr_buf_vid_size[64]; + char attr_buf_tex_size[64]; + char attr_buf_coord[64]; + static const char *prev_names[PREV_TEXTURES] = { + "PREV", + "PREV1", + "PREV2", + "PREV3", + "PREV4", + "PREV5", + "PREV6", + }; + + snprintf(attr_buf_tex, sizeof(attr_buf_tex), "%s.texture", prev_names[j]); + snprintf(attr_buf_vid_size, sizeof(attr_buf_vid_size), "%s.video_size", prev_names[j]); + snprintf(attr_buf_tex_size, sizeof(attr_buf_tex_size), "%s.texture_size", prev_names[j]); + snprintf(attr_buf_coord, sizeof(attr_buf_coord), "%s.tex_coord", prev_names[j]); + + prg[i].prev[j].tex = cgGetNamedParameter(prg[i].fprg, attr_buf_tex); + + prg[i].prev[j].vid_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_vid_size); + prg[i].prev[j].vid_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_vid_size); + + prg[i].prev[j].tex_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_tex_size); + prg[i].prev[j].tex_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_tex_size); + + prg[i].prev[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf_coord); + } + + for (unsigned j = 0; j < i - 1; j++) + { + char attr_buf[64]; + + snprintf(attr_buf, sizeof(attr_buf), "PASS%u.texture", j + 1); + prg[i].fbo[j].tex = cgGetNamedParameter(prg[i].fprg, attr_buf); + + snprintf(attr_buf, sizeof(attr_buf), "PASS%u.video_size", j + 1); + prg[i].fbo[j].vid_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf); + prg[i].fbo[j].vid_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf); + + snprintf(attr_buf, sizeof(attr_buf), "PASS%u.texture_size", j + 1); + prg[i].fbo[j].tex_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf); + prg[i].fbo[j].tex_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf); + + snprintf(attr_buf, sizeof(attr_buf), "PASS%u.tex_coord", j + 1); + prg[i].fbo[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf); + } +} + +static bool gl_cg_init(const char *path) +{ + cgRTCgcInit(); + + if (!cgCtx) + cgCtx = cgCreateContext(); + + if (cgCtx == NULL) + { + SSNES_ERR("Failed to create Cg context\n"); + return false; + } + + cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); + cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX); + if (cgFProf == CG_PROFILE_UNKNOWN || cgVProf == CG_PROFILE_UNKNOWN) + { + SSNES_ERR("Invalid profile type\n"); + return false; + } + cgGLSetOptimalOptions(cgFProf); + cgGLSetOptimalOptions(cgVProf); + cgGLEnableProfile(cgFProf); + cgGLEnableProfile(cgVProf); + + if (strstr(path, ".cgp")) + { + if (!load_preset(path)) + return false; + } + else + { + if (!load_plain(path)) + return false; + } + + if (menu_cg_program && !load_menu_shader()) + return false; + + prg[0].mvp = cgGetNamedParameter(prg[0].vprg, "modelViewProj"); + if (prg[0].mvp) + cgGLSetStateMatrixParameter(prg[0].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); + + for (unsigned i = 1; i <= cg_shader_num; i++) + set_program_attributes(i); + + if (menu_cg_program) + set_program_attributes(SSNES_CG_MENU_SHADER_INDEX); + + cgGLBindProgram(prg[1].fprg); + cgGLBindProgram(prg[1].vprg); + + return true; +} + +// Deinit as much as possible without resetting context (broken on PS3), +// and reinit cleanly. +// If this fails, we're kinda screwed without resetting everything on PS3. +bool gl_cg_reinit(const char *path) +{ + gl_cg_deinit_state(); + + return gl_cg_init(path); +} + + +static void gl_cg_use(unsigned index) +{ + if (prg[index].vprg && prg[index].fprg) + { + gl_cg_reset_attrib(); + + active_index = index; + cgGLBindProgram(prg[index].vprg); + cgGLBindProgram(prg[index].fprg); + } +} + +static unsigned gl_cg_num(void) +{ + return cg_shader_num; +} + +static bool gl_cg_filter_type(unsigned index, bool *smooth) +{ + if (fbo_smooth[index] == FILTER_UNSPEC) + return false; + *smooth = (fbo_smooth[index] == FILTER_LINEAR); + return true; +} + +static void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale) +{ + *scale = cg_scale[index]; +} + +static void gl_cg_set_menu_shader(const char *path) +{ + if (menu_cg_program) + free(menu_cg_program); + + menu_cg_program = strdup(path); +} + +static void gl_cg_set_compiler_args(const char **argv) +{ + cg_arguments = argv; +} + +bool gl_cg_load_shader(unsigned index, const char *path) +{ + if (index == 0) + return false; + + if (prg[index].fprg) + { + cgGLUnbindProgram(cgFProf); + + if (prg[0].fprg != prg[index].fprg) + cgDestroyProgram(prg[index].fprg); + } + + if (prg[index].vprg) + { + cgGLUnbindProgram(cgVProf); + + if (prg[0].vprg != prg[index].vprg) + cgDestroyProgram(prg[index].vprg); + } + + memset(&prg[index], 0, sizeof(prg[index])); + + if (load_program(index, path, true)) + { + set_program_attributes(index); + return true; + } + else + { + // Always make sure we have a valid shader. + memcpy(&prg[index], &prg[0], sizeof(prg[0])); + return false; + } +} + +bool gl_cg_save_cgp(const char *path, const struct gl_cg_cgp_info *info) +{ + if (!info->shader[0] || !*info->shader[0]) + return false; + + FILE *file = fopen(path, "w"); + if (!file) + return false; + + unsigned shaders = info->shader[1] && *info->shader[1] ? 2 : 1; + fprintf(file, "shaders = %u\n", shaders); + + fprintf(file, "shader0 = \"%s\"\n", info->shader[0]); + if (shaders == 2) + fprintf(file, "shader1 = \"%s\"\n", info->shader[1]); + + fprintf(file, "filter_linear0 = %s\n", info->filter_linear[0] ? "true" : "false"); + + if (info->render_to_texture) + { + fprintf(file, "filter_linear1 = %s\n", info->filter_linear[1] ? "true" : "false"); + fprintf(file, "scale_type0 = source\n"); + fprintf(file, "scale0 = %.1f\n", info->fbo_scale); + } + + if (info->lut_texture_path && info->lut_texture_id) + { + fprintf(file, "textures = %s\n", info->lut_texture_id); + fprintf(file, "%s = \"%s\"\n", + info->lut_texture_id, info->lut_texture_path); + + fprintf(file, "%s_absolute = %s\n", + info->lut_texture_id, + info->lut_texture_absolute ? "true" : "false"); + } + + fclose(file); + return true; +} + +static void gl_cg_invalidate_context(void) +{ + cgCtx = NULL; +} + +unsigned gl_cg_get_lut_info(struct gl_cg_lut_info *info, unsigned elems) +{ + 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; +} + +/*============================================================ + GL IMPLEMENTATION +============================================================ */ + static bool gl_shader_init(void) { switch (g_settings.video.shader_type) @@ -465,7 +1641,8 @@ static void set_viewport(gl_t *gl, unsigned width, unsigned height, bool force_f glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - gl_cg_set_proj_matrix(); + if (prg[active_index].mvp) + cgGLSetStateMatrixParameter(prg[active_index].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); gl->vp_width = width; gl->vp_height = height; diff --git a/ps3/ps3_video_psgl.h b/ps3/ps3_video_psgl.h index c0dad9df0f..788c731533 100644 --- a/ps3/ps3_video_psgl.h +++ b/ps3/ps3_video_psgl.h @@ -41,6 +41,9 @@ #define IS_TIMER_EXPIRED(getter) (!(IS_TIMER_NOT_EXPIRED(getter))) #define SET_TIMER_EXPIRATION(setter, value) setter = g_frame_count + value; +#define SSNES_CG_MAX_SHADERS 16 +#define SSNES_CG_MENU_SHADER_INDEX (SSNES_CG_MAX_SHADERS - 1) + enum { ASPECT_RATIO_4_3, @@ -101,6 +104,24 @@ typedef struct gl void *empty_buf; } gl_t; +struct gl_cg_cgp_info +{ + const char *shader[2]; + bool filter_linear[2]; + bool render_to_texture; + float fbo_scale; + + const char *lut_texture_path; + const char *lut_texture_id; + bool lut_texture_absolute; +}; + +struct gl_cg_lut_info +{ + char id[64]; + GLuint tex; +}; + bool ps3_setup_texture(void); const char * ps3_get_resolution_label(uint32_t resolution); @@ -120,6 +141,13 @@ void ps3graphics_set_vsync(uint32_t vsync); void ps3graphics_video_init(bool get_all_resolutions); void ps3graphics_video_reinit(void); +bool gl_cg_reinit(const char *path); +bool gl_cg_save_cgp(const char *path, const struct gl_cg_cgp_info *info); +bool gl_cg_load_shader(unsigned index, const char *path); + + +unsigned gl_cg_get_lut_info(struct gl_cg_lut_info *info, unsigned elems); + extern void *g_gl; extern unsigned g_frame_count; diff --git a/ps3/shader_cg.c b/ps3/shader_cg.c deleted file mode 100644 index 427d317f25..0000000000 --- a/ps3/shader_cg.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. - * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * - * Some code herein may be based on code found in BSNES. - * - * SSNES 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. - * - * SSNES 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 SSNES. - * If not, see . - */ - -#include "shader_cg.h" -#include -#include -#include "../general.h" -#include -#include "../compat/strl.h" -#include "../conf/config_file.h" -#include "../gfx/image.h" -#include "../dynamic.h" -#include "../compat/posix_string.h" - -#ifdef HAVE_CONFIGFILE -#include "../gfx/snes_state.h" -#endif - -// Used when we call deactivate() since just unbinding the program didn't seem to work... :( -static const char *stock_cg_program = - "void main_vertex" - "(" - " float4 position : POSITION," - " float2 texCoord : TEXCOORD0," - " float4 color : COLOR," - "" - " uniform float4x4 modelViewProj," - "" - " out float4 oPosition : POSITION," - " out float2 otexCoord : TEXCOORD0," - " out float4 oColor : COLOR" - ")" - "{" - " oPosition = mul(modelViewProj, position);" - " otexCoord = texCoord;" - " oColor = color;" - "}" - "" - "float4 main_fragment(in float4 color : COLOR, float2 tex : TEXCOORD0, uniform sampler2D s0 : TEXUNIT0) : COLOR" - "{" - " return color * tex2D(s0, tex);" - "}"; - -static char *menu_cg_program; - -static CGcontext cgCtx; - -struct cg_fbo_params -{ - CGparameter vid_size_f; - CGparameter tex_size_f; - CGparameter vid_size_v; - CGparameter tex_size_v; - CGparameter tex; - CGparameter coord; -}; - -#define MAX_TEXTURES 8 -#define MAX_VARIABLES 64 -#define PREV_TEXTURES 7 - -struct cg_program -{ - CGprogram vprg; - CGprogram fprg; - CGparameter vid_size_f; - CGparameter tex_size_f; - CGparameter out_size_f; - CGparameter frame_cnt_f; - CGparameter frame_dir_f; - CGparameter vid_size_v; - CGparameter tex_size_v; - CGparameter out_size_v; - CGparameter frame_cnt_v; - CGparameter frame_dir_v; - CGparameter mvp; - - struct cg_fbo_params fbo[SSNES_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[SSNES_CG_MAX_SHADERS]; -static const char **cg_arguments; -static CGprofile cgVProf, cgFProf; -static unsigned active_index = 0; -static unsigned cg_shader_num = 0; -static struct gl_fbo_scale cg_scale[SSNES_CG_MAX_SHADERS]; -static unsigned fbo_smooth[SSNES_CG_MAX_SHADERS]; - -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 + SSNES_CG_MAX_SHADERS]; -static unsigned cg_attrib_index; - -#ifdef HAVE_CONFIGFILE -static snes_tracker_t *snes_tracker = NULL; -#endif - -static void gl_cg_reset_attrib(void) -{ - for (unsigned i = 0; i < cg_attrib_index; i++) - cgGLDisableClientState(cg_attribs[i]); - cg_attrib_index = 0; -} - -void gl_cg_set_proj_matrix(void) -{ - if (prg[active_index].mvp) - cgGLSetStateMatrixParameter(prg[active_index].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); -} - -#define set_param_2f(param, x, y) \ - if (param) cgGLSetParameter2f(param, x, y) -#define set_param_1f(param, x) \ - if (param) cgGLSetParameter1f(param, x) - -void gl_cg_set_params(unsigned width, unsigned height, - unsigned tex_width, unsigned tex_height, - unsigned out_width, unsigned out_height, - unsigned frame_count, - const struct gl_tex_info *info, - const struct gl_tex_info *prev_info, - const struct gl_tex_info *fbo_info, - unsigned fbo_info_cnt) -{ - if (active_index == 0) - return; - - // Set frame. - set_param_2f(prg[active_index].vid_size_f, width, height); - set_param_2f(prg[active_index].tex_size_f, tex_width, tex_height); - set_param_2f(prg[active_index].out_size_f, out_width, out_height); - set_param_1f(prg[active_index].frame_cnt_f, (float)frame_count); - set_param_1f(prg[active_index].frame_dir_f, g_extern.frame_is_reverse ? -1.0 : 1.0); - - set_param_2f(prg[active_index].vid_size_v, width, height); - set_param_2f(prg[active_index].tex_size_v, tex_width, tex_height); - set_param_2f(prg[active_index].out_size_v, out_width, out_height); - set_param_1f(prg[active_index].frame_cnt_v, (float)frame_count); - set_param_1f(prg[active_index].frame_dir_v, g_extern.frame_is_reverse ? -1.0 : 1.0); - - if (active_index == SSNES_CG_MENU_SHADER_INDEX) - return; - - // Set orig texture. - CGparameter param = prg[active_index].orig.tex; - if (param) - { - cgGLSetTextureParameter(param, info->tex); - cgGLEnableTextureParameter(param); - } - - set_param_2f(prg[active_index].orig.vid_size_v, info->input_size[0], info->input_size[1]); - set_param_2f(prg[active_index].orig.vid_size_f, info->input_size[0], info->input_size[1]); - set_param_2f(prg[active_index].orig.tex_size_v, info->tex_size[0], info->tex_size[1]); - set_param_2f(prg[active_index].orig.tex_size_f, info->tex_size[0], info->tex_size[1]); - if (prg[active_index].orig.coord) - { - cgGLSetParameterPointer(prg[active_index].orig.coord, 2, GL_FLOAT, 0, info->coord); - cgGLEnableClientState(prg[active_index].orig.coord); - cg_attribs[cg_attrib_index++] = prg[active_index].orig.coord; - } - - // Set prev textures. - for (unsigned i = 0; i < PREV_TEXTURES; i++) - { - param = prg[active_index].prev[i].tex; - if (param) - { - cgGLSetTextureParameter(param, prev_info[i].tex); - cgGLEnableTextureParameter(param); - } - - set_param_2f(prg[active_index].prev[i].vid_size_v, prev_info[i].input_size[0], prev_info[i].input_size[1]); - set_param_2f(prg[active_index].prev[i].vid_size_f, prev_info[i].input_size[0], prev_info[i].input_size[1]); - set_param_2f(prg[active_index].prev[i].tex_size_v, prev_info[i].tex_size[0], prev_info[i].tex_size[1]); - set_param_2f(prg[active_index].prev[i].tex_size_f, prev_info[i].tex_size[0], prev_info[i].tex_size[1]); - - if (prg[active_index].prev[i].coord) - { - cgGLSetParameterPointer(prg[active_index].prev[i].coord, 2, GL_FLOAT, 0, prev_info[i].coord); - cgGLEnableClientState(prg[active_index].prev[i].coord); - cg_attribs[cg_attrib_index++] = prg[active_index].prev[i].coord; - } - } - - // Set lookup textures. - for (unsigned i = 0; i < lut_textures_num; i++) - { - CGparameter param = cgGetNamedParameter(prg[active_index].fprg, lut_textures_uniform[i]); - if (param) - { - cgGLSetTextureParameter(param, lut_textures[i]); - cgGLEnableTextureParameter(param); - } - } - - // Set FBO textures. - if (active_index > 2) - { - for (unsigned i = 0; i < fbo_info_cnt; i++) - { - if (prg[active_index].fbo[i].tex) - { - cgGLSetTextureParameter(prg[active_index].fbo[i].tex, fbo_info[i].tex); - cgGLEnableTextureParameter(prg[active_index].fbo[i].tex); - } - - set_param_2f(prg[active_index].fbo[i].vid_size_v, fbo_info[i].input_size[0], fbo_info[i].input_size[1]); - set_param_2f(prg[active_index].fbo[i].vid_size_f, fbo_info[i].input_size[0], fbo_info[i].input_size[1]); - - set_param_2f(prg[active_index].fbo[i].tex_size_v, fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); - set_param_2f(prg[active_index].fbo[i].tex_size_f, fbo_info[i].tex_size[0], fbo_info[i].tex_size[1]); - - if (prg[active_index].fbo[i].coord) - { - cgGLSetParameterPointer(prg[active_index].fbo[i].coord, 2, GL_FLOAT, 0, fbo_info[i].coord); - cgGLEnableClientState(prg[active_index].fbo[i].coord); - cg_attribs[cg_attrib_index++] = prg[active_index].fbo[i].coord; - } - } - } - -#ifdef HAVE_CONFIGFILE - // Set state parameters - if (snes_tracker) - { - static struct snes_tracker_uniform info[MAX_VARIABLES]; - static unsigned cnt = 0; - - if (active_index == 1) - cnt = snes_get_uniform(snes_tracker, info, MAX_VARIABLES, frame_count); - - for (unsigned i = 0; i < cnt; i++) - { - CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, info[i].id); - CGparameter param_f = cgGetNamedParameter(prg[active_index].fprg, info[i].id); - set_param_1f(param_v, info[i].value); - set_param_1f(param_f, info[i].value); - } - } -#endif -} - -static void gl_cg_deinit_progs(void) -{ - cgGLUnbindProgram(cgFProf); - cgGLUnbindProgram(cgVProf); - - // Programs may alias [0]. - for (unsigned i = 1; i < SSNES_CG_MAX_SHADERS; i++) - { - if (prg[i].fprg != prg[0].fprg) - cgDestroyProgram(prg[i].fprg); - if (prg[i].vprg != prg[0].vprg) - cgDestroyProgram(prg[i].vprg); - } - - if (prg[0].fprg) - cgDestroyProgram(prg[0].fprg); - if (prg[0].vprg) - cgDestroyProgram(prg[0].vprg); - - memset(prg, 0, sizeof(prg)); -} - -static void gl_cg_deinit_state(void) -{ - gl_cg_reset_attrib(); - - 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; - -#ifdef HAVE_CONFIGFILE - if (snes_tracker) - { - snes_tracker_free(snes_tracker); - snes_tracker = NULL; - } -#endif -} - -// Final deinit. -static void gl_cg_deinit_context_state(void) -{ - if (menu_cg_program) - { - free(menu_cg_program); - menu_cg_program = NULL; - } -} - -// Full deinit. -void gl_cg_deinit(void) -{ - gl_cg_deinit_state(); - gl_cg_deinit_context_state(); -} - -// Deinit as much as possible without resetting context (broken on PS3), -// and reinit cleanly. -// If this fails, we're kinda screwed without resetting everything on PS3. -bool gl_cg_reinit(const char *path) -{ - gl_cg_deinit_state(); - - return gl_cg_init(path); -} - -#define SET_LISTING(type) \ -{ \ - const char *list = cgGetLastListing(cgCtx); \ - if (list) \ - listing_##type = strdup(list); \ -} - -static bool load_program(unsigned index, const char *prog, bool path_is_file) -{ - bool ret = true; - char *listing_f = NULL; - char *listing_v = NULL; - - if (path_is_file) - { - prg[index].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); - SET_LISTING(f); - prg[index].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); - SET_LISTING(v); - } - else - { - prg[index].fprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); - SET_LISTING(f); - prg[index].vprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); - SET_LISTING(v); - } - - if (!prg[index].fprg || !prg[index].vprg) - { - SSNES_ERR("CG error: %s\n", cgGetErrorString(cgGetError())); - if (listing_f) - SSNES_ERR("Fragment:\n%s\n", listing_f); - else if (listing_v) - SSNES_ERR("Vertex:\n%s\n", listing_v); - - ret = false; - goto end; - } - - cgGLLoadProgram(prg[index].fprg); - cgGLLoadProgram(prg[index].vprg); - -end: - free(listing_f); - free(listing_v); - return ret; -} - -static bool load_stock(void) -{ - if (!load_program(0, stock_cg_program, false)) - { - SSNES_ERR("Failed to compile passthrough shader, is something wrong with your environment?\n"); - return false; - } - - return true; -} - -static bool load_plain(const char *path) -{ - if (!load_stock()) - return false; - - SSNES_LOG("Loading Cg file: %s\n", path); - - if (!load_program(1, path, true)) - return false; - - if (*g_settings.video.second_pass_shader && g_settings.video.render_to_texture) - { - if (!load_program(2, g_settings.video.second_pass_shader, true)) - return false; - - cg_shader_num = 2; - } - else - { - prg[2] = prg[0]; - cg_shader_num = 1; - } - - return true; -} - -static bool load_menu_shader(void) -{ - return load_program(SSNES_CG_MENU_SHADER_INDEX, menu_cg_program, true); -} - -#define print_buf(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__) - -#ifdef HAVE_CONFIGFILE -static void load_texture_data(GLuint *obj, const struct texture_image *img, bool smooth) -{ - glGenTextures(1, obj); - glBindTexture(GL_TEXTURE_2D, *obj); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth ? GL_LINEAR : GL_NEAREST); - - glTexImage2D(GL_TEXTURE_2D, - 0, GL_ARGB_SCE, img->width, img->height, - 0, GL_ARGB_SCE, GL_UNSIGNED_INT_8_8_8_8, img->pixels); - - free(img->pixels); -} - -static bool load_textures(const char *dir_path, config_file_t *conf) -{ - bool ret = true; - char *textures = NULL; - if (!config_get_string(conf, "textures", &textures)) // No textures here ... - return true; - - const char *id = strtok(textures, ";");; - while (id && lut_textures_num < MAX_TEXTURES) - { - char path[PATH_MAX]; - if (!config_get_array(conf, id, path, sizeof(path))) - { - SSNES_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[512]; - if (absolute) - print_buf(image_path, "%s", path); - else - print_buf(image_path, "%s%s", dir_path, path); - - SSNES_LOG("Loading image from: \"%s\".\n", image_path); - struct texture_image img; - if (!texture_image_load(image_path, &img)) - { - SSNES_ERR("Failed to load picture ...\n"); - ret = false; - goto end; - } - - 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(NULL, ";"); - } - -end: - free(textures); - glBindTexture(GL_TEXTURE_2D, 0); - return ret; -} - -static bool load_imports(const char *dir_path, config_file_t *conf) -{ - bool ret = true; - char *imports = NULL; - - if (!config_get_string(conf, "imports", &imports)) - return true; - - struct snes_tracker_uniform_info info[MAX_VARIABLES]; - unsigned info_cnt = 0; - struct snes_tracker_info tracker_info = {0}; - - const char *id = strtok(imports, ";"); - while (id && info_cnt < MAX_VARIABLES) - { - char semantic_buf[64]; - char wram_buf[64]; - char input_slot_buf[64]; - char apuram_buf[64]; - char oam_buf[64]; - char cgram_buf[64]; - char vram_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(apuram_buf, "%s_apuram", id); - print_buf(oam_buf, "%s_oam", id); - print_buf(cgram_buf, "%s_cgram", id); - print_buf(vram_buf, "%s_vram", 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) - { - SSNES_ERR("No semantic for import variable.\n"); - ret = false; - goto end; - } - - enum snes_tracker_type tracker_type; - enum snes_ram_type ram_type = SSNES_STATE_NONE; - - if (strcmp(semantic, "capture") == 0) - tracker_type = SSNES_STATE_CAPTURE; - else if (strcmp(semantic, "transition") == 0) - tracker_type = SSNES_STATE_TRANSITION; - else if (strcmp(semantic, "transition_count") == 0) - tracker_type = SSNES_STATE_TRANSITION_COUNT; - else if (strcmp(semantic, "capture_previous") == 0) - tracker_type = SSNES_STATE_CAPTURE_PREV; - else if (strcmp(semantic, "transition_previous") == 0) - tracker_type = SSNES_STATE_TRANSITION_PREV; - else - { - SSNES_ERR("Invalid semantic.\n"); - ret = false; - goto end; - } - - unsigned addr = 0; - unsigned input_slot = 0; - if (config_get_hex(conf, input_slot_buf, &input_slot)) - { - switch (input_slot) - { - case 1: - ram_type = SSNES_STATE_INPUT_SLOT1; - break; - - case 2: - ram_type = SSNES_STATE_INPUT_SLOT2; - break; - - default: - SSNES_ERR("Invalid input slot for import.\n"); - ret = false; - goto end; - } - } - else if (config_get_hex(conf, wram_buf, &addr)) - ram_type = SSNES_STATE_WRAM; - else if (config_get_hex(conf, apuram_buf, &addr)) - ram_type = SSNES_STATE_APURAM; - else if (config_get_hex(conf, oam_buf, &addr)) - ram_type = SSNES_STATE_OAM; - else if (config_get_hex(conf, cgram_buf, &addr)) - ram_type = SSNES_STATE_CGRAM; - else if (config_get_hex(conf, vram_buf, &addr)) - ram_type = SSNES_STATE_VRAM; - else - { - SSNES_ERR("No address assigned to semantic.\n"); - ret = false; - goto end; - } - - unsigned memtype; - switch (ram_type) - { - case SSNES_STATE_WRAM: - memtype = SNES_MEMORY_WRAM; - break; - case SSNES_STATE_APURAM: - memtype = SNES_MEMORY_APURAM; - break; - case SSNES_STATE_VRAM: - memtype = SNES_MEMORY_VRAM; - break; - case SSNES_STATE_OAM: - memtype = SNES_MEMORY_OAM; - break; - case SSNES_STATE_CGRAM: - memtype = SNES_MEMORY_CGRAM; - break; - - default: - memtype = -1u; - } - - if ((memtype != -1u) && (addr >= psnes_get_memory_size(memtype))) - { - SSNES_ERR("Address out of bounds.\n"); - ret = false; - goto end; - } - - unsigned bitmask; - if (!config_get_hex(conf, mask_buf, &bitmask)) - bitmask = 0; - unsigned bitequal; - 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(NULL, ";"); - } - - tracker_info.wram = psnes_get_memory_data(SNES_MEMORY_WRAM); - tracker_info.vram = psnes_get_memory_data(SNES_MEMORY_VRAM); - tracker_info.cgram = psnes_get_memory_data(SNES_MEMORY_CGRAM); - tracker_info.oam = psnes_get_memory_data(SNES_MEMORY_OAM); - tracker_info.apuram = psnes_get_memory_data(SNES_MEMORY_APURAM); - tracker_info.info = info; - tracker_info.info_elem = info_cnt; - - snes_tracker = snes_tracker_init(&tracker_info); - if (!snes_tracker) - SSNES_WARN("Failed to init SNES tracker.\n"); - -end: - free(imports); - return ret; -} -#endif - -static bool load_shader(const char *dir_path, unsigned i, config_file_t *conf) -{ - char *shader_path; - 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)) - { - strlcpy(path_buf, dir_path, sizeof(path_buf)); - strlcat(path_buf, shader_path, sizeof(path_buf)); - free(shader_path); - } - else - { - SSNES_ERR("Didn't find shader path in config ...\n"); - return false; - } - - SSNES_LOG("Loading Cg shader: \"%s\".\n", path_buf); - - if (!load_program(i + 1, path_buf, true)) - return false; - - return true; -} - -static bool load_shader_params(unsigned i, config_file_t *conf) -{ - bool ret = true; - char *scale_type = NULL; - char *scale_type_x = NULL; - char *scale_type_y = NULL; - bool has_scale_type; - bool has_scale_type_x; - bool has_scale_type_y; - - char scale_name_buf[64]; - print_buf(scale_name_buf, "scale_type%u", i); - has_scale_type = config_get_string(conf, scale_name_buf, &scale_type); - print_buf(scale_name_buf, "scale_type_x%u", i); - has_scale_type_x = config_get_string(conf, scale_name_buf, &scale_type_x); - print_buf(scale_name_buf, "scale_type_y%u", i); - has_scale_type_y = config_get_string(conf, scale_name_buf, &scale_type_y); - - if (!has_scale_type && !has_scale_type_x && !has_scale_type_y) - return true; - - if (has_scale_type) - { - free(scale_type_x); - free(scale_type_y); - - scale_type_x = strdup(scale_type); - scale_type_y = strdup(scale_type); - - free(scale_type); - scale_type = NULL; - } - - char attr_name_buf[64]; - float fattr; - int iattr; - struct gl_fbo_scale *scale = &cg_scale[i + 1]; // Shader 0 is passthrough shader. Start at 1. - - scale->valid = true; - scale->type_x = SSNES_SCALE_INPUT; - scale->type_y = SSNES_SCALE_INPUT; - scale->scale_x = 1.0; - scale->scale_y = 1.0; - scale->abs_x = g_extern.system.geom.base_width; - scale->abs_y = g_extern.system.geom.base_height; - - if (strcmp(scale_type_x, "source") == 0) - scale->type_x = SSNES_SCALE_INPUT; - else if (strcmp(scale_type_x, "viewport") == 0) - scale->type_x = SSNES_SCALE_VIEWPORT; - else if (strcmp(scale_type_x, "absolute") == 0) - scale->type_x = SSNES_SCALE_ABSOLUTE; - else - { - SSNES_ERR("Invalid attribute.\n"); - ret = false; - goto end; - } - - if (strcmp(scale_type_y, "source") == 0) - scale->type_y = SSNES_SCALE_INPUT; - else if (strcmp(scale_type_y, "viewport") == 0) - scale->type_y = SSNES_SCALE_VIEWPORT; - else if (strcmp(scale_type_y, "absolute") == 0) - scale->type_y = SSNES_SCALE_ABSOLUTE; - else - { - SSNES_ERR("Invalid attribute.\n"); - ret = false; - goto end; - } - - if (scale->type_x == SSNES_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 == SSNES_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; - } - } - -end: - free(scale_type); - free(scale_type_x); - free(scale_type_y); - return ret; -} - -static bool load_preset(const char *path) -{ -#ifdef HAVE_CONFIGFILE - bool ret = true; - - if (!load_stock()) - return false; - - int shaders; - // Basedir. - char dir_path[PATH_MAX]; - char *ptr = NULL; - - SSNES_LOG("Loading Cg meta-shader: %s\n", path); - config_file_t *conf = config_file_new(path); - if (!conf) - { - SSNES_ERR("Failed to load preset.\n"); - ret = false; - goto end; - } - - if (!config_get_int(conf, "shaders", &shaders)) - { - SSNES_ERR("Cannot find \"shaders\" param.\n"); - ret = false; - goto end; - } - - if (shaders < 1) - { - SSNES_ERR("Need to define at least 1 shader.\n"); - ret = false; - goto end; - } - - cg_shader_num = shaders; - if (shaders > SSNES_CG_MAX_SHADERS - 3) - { - SSNES_WARN("Too many shaders ... Capping shader amount to %d.\n", SSNES_CG_MAX_SHADERS - 3); - cg_shader_num = shaders = SSNES_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]; - - // Check filter params. - for (int i = 0; i < shaders; i++) - { - bool smooth; - 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; - } - - strlcpy(dir_path, path, sizeof(dir_path)); - ptr = strrchr(dir_path, '/'); - if (!ptr) ptr = strrchr(dir_path, '\\'); - if (ptr) - ptr[1] = '\0'; - else // No directory. - dir_path[0] = '\0'; - - for (int i = 0; i < shaders; i++) - { - if (!load_shader_params(i, conf)) - { - SSNES_ERR("Failed to load shader params ...\n"); - ret = false; - goto end; - } - - if (!load_shader(dir_path, i, conf)) - { - SSNES_ERR("Failed to load shaders ...\n"); - ret = false; - goto end; - } - } - - if (!load_textures(dir_path, conf)) - { - SSNES_ERR("Failed to load lookup textures ...\n"); - ret = false; - goto end; - } - - if (!load_imports(dir_path, conf)) - { - SSNES_ERR("Failed to load imports ...\n"); - ret = false; - goto end; - } - -end: - if (conf) - config_file_free(conf); - return ret; - -#else - (void)path; - SSNES_ERR("No config file support compiled in.\n"); - return false; -#endif -} - -static void set_program_attributes(unsigned i) -{ - cgGLBindProgram(prg[i].fprg); - cgGLBindProgram(prg[i].vprg); - - prg[i].vid_size_f = cgGetNamedParameter(prg[i].fprg, "IN.video_size"); - prg[i].tex_size_f = cgGetNamedParameter(prg[i].fprg, "IN.texture_size"); - prg[i].out_size_f = cgGetNamedParameter(prg[i].fprg, "IN.output_size"); - prg[i].frame_cnt_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_count"); - prg[i].frame_dir_f = cgGetNamedParameter(prg[i].fprg, "IN.frame_direction"); - prg[i].vid_size_v = cgGetNamedParameter(prg[i].vprg, "IN.video_size"); - prg[i].tex_size_v = cgGetNamedParameter(prg[i].vprg, "IN.texture_size"); - prg[i].out_size_v = cgGetNamedParameter(prg[i].vprg, "IN.output_size"); - prg[i].frame_cnt_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_count"); - prg[i].frame_dir_v = cgGetNamedParameter(prg[i].vprg, "IN.frame_direction"); - prg[i].mvp = cgGetNamedParameter(prg[i].vprg, "modelViewProj"); - if (prg[i].mvp) - cgGLSetStateMatrixParameter(prg[i].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); - - if (i == SSNES_CG_MENU_SHADER_INDEX) - return; - - prg[i].orig.tex = cgGetNamedParameter(prg[i].fprg, "ORIG.texture"); - prg[i].orig.vid_size_v = cgGetNamedParameter(prg[i].vprg, "ORIG.video_size"); - prg[i].orig.vid_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.video_size"); - prg[i].orig.tex_size_v = cgGetNamedParameter(prg[i].vprg, "ORIG.texture_size"); - prg[i].orig.tex_size_f = cgGetNamedParameter(prg[i].fprg, "ORIG.texture_size"); - prg[i].orig.coord = cgGetNamedParameter(prg[i].vprg, "ORIG.tex_coord"); - - for (unsigned j = 0; j < PREV_TEXTURES; j++) - { - char attr_buf_tex[64]; - char attr_buf_vid_size[64]; - char attr_buf_tex_size[64]; - char attr_buf_coord[64]; - static const char *prev_names[PREV_TEXTURES] = { - "PREV", - "PREV1", - "PREV2", - "PREV3", - "PREV4", - "PREV5", - "PREV6", - }; - - snprintf(attr_buf_tex, sizeof(attr_buf_tex), "%s.texture", prev_names[j]); - snprintf(attr_buf_vid_size, sizeof(attr_buf_vid_size), "%s.video_size", prev_names[j]); - snprintf(attr_buf_tex_size, sizeof(attr_buf_tex_size), "%s.texture_size", prev_names[j]); - snprintf(attr_buf_coord, sizeof(attr_buf_coord), "%s.tex_coord", prev_names[j]); - - prg[i].prev[j].tex = cgGetNamedParameter(prg[i].fprg, attr_buf_tex); - - prg[i].prev[j].vid_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_vid_size); - prg[i].prev[j].vid_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_vid_size); - - prg[i].prev[j].tex_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf_tex_size); - prg[i].prev[j].tex_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf_tex_size); - - prg[i].prev[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf_coord); - } - - for (unsigned j = 0; j < i - 1; j++) - { - char attr_buf[64]; - - snprintf(attr_buf, sizeof(attr_buf), "PASS%u.texture", j + 1); - prg[i].fbo[j].tex = cgGetNamedParameter(prg[i].fprg, attr_buf); - - snprintf(attr_buf, sizeof(attr_buf), "PASS%u.video_size", j + 1); - prg[i].fbo[j].vid_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf); - prg[i].fbo[j].vid_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf); - - snprintf(attr_buf, sizeof(attr_buf), "PASS%u.texture_size", j + 1); - prg[i].fbo[j].tex_size_v = cgGetNamedParameter(prg[i].vprg, attr_buf); - prg[i].fbo[j].tex_size_f = cgGetNamedParameter(prg[i].fprg, attr_buf); - - snprintf(attr_buf, sizeof(attr_buf), "PASS%u.tex_coord", j + 1); - prg[i].fbo[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf); - } -} - -bool gl_cg_init(const char *path) -{ - cgRTCgcInit(); - - if (!cgCtx) - cgCtx = cgCreateContext(); - - if (cgCtx == NULL) - { - SSNES_ERR("Failed to create Cg context\n"); - return false; - } - - cgFProf = cgGLGetLatestProfile(CG_GL_FRAGMENT); - cgVProf = cgGLGetLatestProfile(CG_GL_VERTEX); - if (cgFProf == CG_PROFILE_UNKNOWN || cgVProf == CG_PROFILE_UNKNOWN) - { - SSNES_ERR("Invalid profile type\n"); - return false; - } - cgGLSetOptimalOptions(cgFProf); - cgGLSetOptimalOptions(cgVProf); - cgGLEnableProfile(cgFProf); - cgGLEnableProfile(cgVProf); - - if (strstr(path, ".cgp")) - { - if (!load_preset(path)) - return false; - } - else - { - if (!load_plain(path)) - return false; - } - - if (menu_cg_program && !load_menu_shader()) - return false; - - prg[0].mvp = cgGetNamedParameter(prg[0].vprg, "modelViewProj"); - if (prg[0].mvp) - cgGLSetStateMatrixParameter(prg[0].mvp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); - - for (unsigned i = 1; i <= cg_shader_num; i++) - set_program_attributes(i); - - if (menu_cg_program) - set_program_attributes(SSNES_CG_MENU_SHADER_INDEX); - - cgGLBindProgram(prg[1].fprg); - cgGLBindProgram(prg[1].vprg); - - return true; -} - -void gl_cg_use(unsigned index) -{ - if (prg[index].vprg && prg[index].fprg) - { - gl_cg_reset_attrib(); - - active_index = index; - cgGLBindProgram(prg[index].vprg); - cgGLBindProgram(prg[index].fprg); - } -} - -unsigned gl_cg_num(void) -{ - return cg_shader_num; -} - -bool gl_cg_filter_type(unsigned index, bool *smooth) -{ - if (fbo_smooth[index] == FILTER_UNSPEC) - return false; - *smooth = (fbo_smooth[index] == FILTER_LINEAR); - return true; -} - -void gl_cg_shader_scale(unsigned index, struct gl_fbo_scale *scale) -{ - *scale = cg_scale[index]; -} - -void gl_cg_set_menu_shader(const char *path) -{ - if (menu_cg_program) - free(menu_cg_program); - - menu_cg_program = strdup(path); -} - -void gl_cg_set_compiler_args(const char **argv) -{ - cg_arguments = argv; -} - -bool gl_cg_load_shader(unsigned index, const char *path) -{ - if (index == 0) - return false; - - if (prg[index].fprg) - { - cgGLUnbindProgram(cgFProf); - - if (prg[0].fprg != prg[index].fprg) - cgDestroyProgram(prg[index].fprg); - } - - if (prg[index].vprg) - { - cgGLUnbindProgram(cgVProf); - - if (prg[0].vprg != prg[index].vprg) - cgDestroyProgram(prg[index].vprg); - } - - memset(&prg[index], 0, sizeof(prg[index])); - - if (load_program(index, path, true)) - { - set_program_attributes(index); - return true; - } - else - { - // Always make sure we have a valid shader. - memcpy(&prg[index], &prg[0], sizeof(prg[0])); - return false; - } -} - -bool gl_cg_save_cgp(const char *path, const struct gl_cg_cgp_info *info) -{ - if (!info->shader[0] || !*info->shader[0]) - return false; - - FILE *file = fopen(path, "w"); - if (!file) - return false; - - unsigned shaders = info->shader[1] && *info->shader[1] ? 2 : 1; - fprintf(file, "shaders = %u\n", shaders); - - fprintf(file, "shader0 = \"%s\"\n", info->shader[0]); - if (shaders == 2) - fprintf(file, "shader1 = \"%s\"\n", info->shader[1]); - - fprintf(file, "filter_linear0 = %s\n", info->filter_linear[0] ? "true" : "false"); - - if (info->render_to_texture) - { - fprintf(file, "filter_linear1 = %s\n", info->filter_linear[1] ? "true" : "false"); - fprintf(file, "scale_type0 = source\n"); - fprintf(file, "scale0 = %.1f\n", info->fbo_scale); - } - - if (info->lut_texture_path && info->lut_texture_id) - { - fprintf(file, "textures = %s\n", info->lut_texture_id); - fprintf(file, "%s = \"%s\"\n", - info->lut_texture_id, info->lut_texture_path); - - fprintf(file, "%s_absolute = %s\n", - info->lut_texture_id, - info->lut_texture_absolute ? "true" : "false"); - } - - fclose(file); - return true; -} - -void gl_cg_invalidate_context(void) -{ - cgCtx = NULL; -} - -unsigned gl_cg_get_lut_info(struct gl_cg_lut_info *info, unsigned elems) -{ - 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; -} - diff --git a/ps3/shader_cg.h b/ps3/shader_cg.h deleted file mode 100644 index bb69cc8c38..0000000000 --- a/ps3/shader_cg.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. - * Copyright (C) 2010-2012 - Hans-Kristian Arntzen - * - * Some code herein may be based on code found in BSNES. - * - * SSNES 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. - * - * SSNES 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 SSNES. - * If not, see . - */ - - -#ifndef __SSNES_CG_H -#define __SSNES_CG_H - -#include "../boolean.h" -#include "../gfx/gl_common.h" -#include - -bool gl_cg_init(const char *path); -bool gl_cg_reinit(const char *path); - -void gl_cg_deinit(void); - -void gl_cg_set_proj_matrix(void); - -void gl_cg_set_params(unsigned width, unsigned height, - unsigned tex_width, unsigned tex_height, - unsigned out_width, unsigned out_height, - unsigned frame_count, - const struct gl_tex_info *info, - const struct gl_tex_info *prev_info, - const struct gl_tex_info *fbo_info, - unsigned fbo_info_cnt); - -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); - -// Used on PS3, but not really platform specific. - -#define SSNES_CG_MAX_SHADERS 16 -#define SSNES_CG_MENU_SHADER_INDEX (SSNES_CG_MAX_SHADERS - 1) -void gl_cg_set_menu_shader(const char *path); -void gl_cg_set_compiler_args(const char **argv); - -bool gl_cg_load_shader(unsigned index, const char *path); - -struct gl_cg_cgp_info -{ - const char *shader[2]; - bool filter_linear[2]; - bool render_to_texture; - float fbo_scale; - - const char *lut_texture_path; - const char *lut_texture_id; - bool lut_texture_absolute; -}; - -bool gl_cg_save_cgp(const char *path, const struct gl_cg_cgp_info *info); -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); - -#endif