diff --git a/driver.h b/driver.h index da36180849..d7e92a21b0 100644 --- a/driver.h +++ b/driver.h @@ -358,6 +358,8 @@ typedef struct video_poke_interface void (*show_mouse)(void *data, bool state); void (*grab_mouse_toggle)(void *data); + + struct gfx_shader *(*get_current_shader)(void *data); } video_poke_interface_t; typedef struct video_driver diff --git a/frontend/menu/backend/menu_common_backend.c b/frontend/menu/backend/menu_common_backend.c index 12784f0239..802770b2dd 100644 --- a/frontend/menu/backend/menu_common_backend.c +++ b/frontend/menu/backend/menu_common_backend.c @@ -43,6 +43,17 @@ #endif #endif +#ifdef HAVE_SHADER_MANAGER +static inline struct gfx_shader *shader_manager_get_current_shader(rgui_handle_t *rgui, unsigned type) +{ + struct gfx_shader *shader = type == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS ? &rgui->shader : NULL; + if (!shader && driver.video_poke && driver.video_data && driver.video_poke->get_current_shader) + shader = driver.video_poke->get_current_shader(driver.video_data); + + return shader; +} +#endif + static void menu_common_entries_init(void *data, unsigned menu_type) { rgui_handle_t *rgui = (rgui_handle_t*)data; @@ -51,6 +62,18 @@ static void menu_common_entries_init(void *data, unsigned menu_type) switch (menu_type) { #ifdef HAVE_SHADER_MANAGER + case RGUI_SETTINGS_SHADER_PARAMETERS: + case RGUI_SETTINGS_SHADER_PRESET_PARAMETERS: + { + file_list_clear(rgui->selection_buf); + + struct gfx_shader *shader = shader_manager_get_current_shader(rgui, menu_type); + if (shader) + for (i = 0; i < shader->num_parameters; i++) + file_list_push(rgui->selection_buf, shader->parameters[i].desc, RGUI_SETTINGS_SHADER_PARAMETER_0 + i, 0); + rgui->parameter_shader = shader; + break; + } case RGUI_SETTINGS_SHADER_OPTIONS: file_list_clear(rgui->selection_buf); file_list_push(rgui->selection_buf, "Apply Shader Changes", @@ -60,6 +83,10 @@ static void menu_common_entries_init(void *data, unsigned menu_type) RGUI_SETTINGS_SHADER_PRESET, 0); file_list_push(rgui->selection_buf, "Save As Shader Preset", RGUI_SETTINGS_SHADER_PRESET_SAVE, 0); + file_list_push(rgui->selection_buf, "Parameters (Current)", + RGUI_SETTINGS_SHADER_PARAMETERS, 0); + file_list_push(rgui->selection_buf, "Parameters (RGUI)", + RGUI_SETTINGS_SHADER_PRESET_PARAMETERS, 0); file_list_push(rgui->selection_buf, "Shader Passes", RGUI_SETTINGS_SHADER_PASSES, 0); @@ -506,6 +533,8 @@ static unsigned menu_common_type_is(unsigned type) type == RGUI_SETTINGS_VIDEO_OPTIONS || type == RGUI_SETTINGS_FONT_OPTIONS || type == RGUI_SETTINGS_SHADER_OPTIONS || + type == RGUI_SETTINGS_SHADER_PARAMETERS || + type == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS || type == RGUI_SETTINGS_AUDIO_OPTIONS || type == RGUI_SETTINGS_DISK_OPTIONS || type == RGUI_SETTINGS_PATH_OPTIONS || @@ -673,7 +702,7 @@ static int menu_settings_iterate(void *data, unsigned action) file_list_get_last(rgui->menu_stack, &dir, &menu_type); if (rgui->need_refresh && !(menu_type == RGUI_FILE_DIRECTORY || - menu_common_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS|| + menu_common_type_is(menu_type) == RGUI_SETTINGS_SHADER_OPTIONS || menu_common_type_is(menu_type) == RGUI_FILE_DIRECTORY || menu_type == RGUI_SETTINGS_VIDEO_SOFTFILTER || menu_type == RGUI_SETTINGS_AUDIO_DSP_FILTER || @@ -700,6 +729,8 @@ static int menu_settings_iterate(void *data, unsigned action) || menu_type == RGUI_SETTINGS_VIDEO_OPTIONS || menu_type == RGUI_SETTINGS_FONT_OPTIONS || menu_type == RGUI_SETTINGS_SHADER_OPTIONS + || menu_type == RGUI_SETTINGS_SHADER_PARAMETERS + || menu_type == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS ) menu_common_entries_init(rgui, menu_type); else @@ -1363,6 +1394,9 @@ static int menu_common_iterate(void *data, unsigned action) unsigned pass = (menu_type - RGUI_SETTINGS_SHADER_0) / 3; fill_pathname_join(rgui->shader.pass[pass].source.path, dir, path, sizeof(rgui->shader.pass[pass].source.path)); + + // This will reset any changed parameters. + gfx_shader_resolve_parameters(NULL, &rgui->shader); } // Pop stack until we hit shader manager again. @@ -1673,7 +1707,10 @@ static void menu_common_shader_manager_init(void *data) if (conf) { if (gfx_shader_read_conf_cgp(conf, &rgui->shader)) + { gfx_shader_resolve_relative(&rgui->shader, g_settings.video.shader_path); + gfx_shader_resolve_parameters(conf, &rgui->shader); + } config_file_free(conf); } } @@ -1700,7 +1737,10 @@ static void menu_common_shader_manager_init(void *data) if (conf) { if (gfx_shader_read_conf_cgp(conf, &rgui->shader)) + { gfx_shader_resolve_relative(&rgui->shader, cgp_path); + gfx_shader_resolve_parameters(conf, &rgui->shader); + } config_file_free(conf); } } @@ -1733,6 +1773,7 @@ static void menu_common_shader_manager_set_preset(void *data, unsigned type, con { gfx_shader_read_conf_cgp(conf, shader); gfx_shader_resolve_relative(shader, path); + gfx_shader_resolve_parameters(conf, shader); config_file_free(conf); } @@ -1758,9 +1799,20 @@ static void menu_common_shader_manager_get_str(void *data, char *type_str, size_ struct gfx_shader *shader = (struct gfx_shader*)data; if (type == RGUI_SETTINGS_SHADER_APPLY) *type_str = '\0'; + else if (type >= RGUI_SETTINGS_SHADER_PARAMETER_0 && type <= RGUI_SETTINGS_SHADER_PARAMETER_LAST) + { + // rgui->parameter_shader here. + if (shader) + { + const struct gfx_shader_parameter *param = &shader->parameters[type - RGUI_SETTINGS_SHADER_PARAMETER_0]; + snprintf(type_str, type_str_size, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); + } + else + *type_str = '\0'; + } else if (type == RGUI_SETTINGS_SHADER_PASSES) snprintf(type_str, type_str_size, "%u", shader->passes); - else + else if (type >= RGUI_SETTINGS_SHADER_0 && type <= RGUI_SETTINGS_SHADER_LAST) { unsigned pass = (type - RGUI_SETTINGS_SHADER_0) / 3; switch ((type - RGUI_SETTINGS_SHADER_0) % 3) @@ -1801,6 +1853,8 @@ static void menu_common_shader_manager_get_str(void *data, char *type_str, size_ } } } + else + *type_str = '\0'; #endif } @@ -1959,10 +2013,42 @@ static int menu_common_shader_manager_setting_toggle(void *data, unsigned settin break; } } + else if ((setting == RGUI_SETTINGS_SHADER_PARAMETERS || setting == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS) && action == RGUI_ACTION_OK) + { + file_list_push(rgui->menu_stack, "", setting, rgui->selection_ptr); + menu_clear_navigation(rgui); + rgui->need_refresh = true; + } + else if (setting >= RGUI_SETTINGS_SHADER_PARAMETER_0 && setting <= RGUI_SETTINGS_SHADER_PARAMETER_LAST) + { + if (!rgui->parameter_shader) + return 0; + + struct gfx_shader_parameter *param = &rgui->parameter_shader->parameters[setting - RGUI_SETTINGS_SHADER_PARAMETER_0]; + switch (action) + { + case RGUI_ACTION_START: + param->current = param->initial; + break; + + case RGUI_ACTION_LEFT: + param->current -= param->step; + break; + + case RGUI_ACTION_RIGHT: + param->current += param->step; + break; + + default: + break; + } + + param->current = min(max(param->minimum, param->current), param->maximum); + } else if ((setting == RGUI_SETTINGS_SHADER_APPLY || setting == RGUI_SETTINGS_SHADER_PASSES) && (driver.menu_ctx && driver.menu_ctx->backend && driver.menu_ctx->backend->setting_set)) driver.menu_ctx->backend->setting_set(rgui, setting, action); - else if ((dist_shader % 3) == 0 || setting == RGUI_SETTINGS_SHADER_PRESET) + else if (((dist_shader % 3) == 0 || setting == RGUI_SETTINGS_SHADER_PRESET)) { dist_shader /= 3; struct gfx_shader_pass *pass = setting == RGUI_SETTINGS_SHADER_PRESET ? @@ -3603,6 +3689,7 @@ static int menu_common_setting_set(void *data, unsigned setting, unsigned action { case RGUI_ACTION_START: rgui->shader.passes = 0; + rgui->need_refresh = true; break; case RGUI_ACTION_LEFT: @@ -3626,9 +3713,8 @@ static int menu_common_setting_set(void *data, unsigned setting, unsigned action break; } -#ifndef HAVE_RMENU - rgui->need_refresh = true; -#endif + if (rgui->need_refresh) + gfx_shader_resolve_parameters(NULL, &rgui->shader); break; case RGUI_SETTINGS_SHADER_APPLY: { diff --git a/frontend/menu/backend/menu_common_backend.h b/frontend/menu/backend/menu_common_backend.h index 2a5960a877..841e2b1420 100644 --- a/frontend/menu/backend/menu_common_backend.h +++ b/frontend/menu/backend/menu_common_backend.h @@ -62,7 +62,11 @@ typedef enum RGUI_SETTINGS_SHADER_FILTER, RGUI_SETTINGS_SHADER_PRESET, RGUI_SETTINGS_SHADER_APPLY, + RGUI_SETTINGS_SHADER_PARAMETERS, // Modifies current shader directly. Will not get saved to CGP. + RGUI_SETTINGS_SHADER_PRESET_PARAMETERS, // Modifies shader preset currently in RGUI. RGUI_SETTINGS_SHADER_PASSES, + RGUI_SETTINGS_SHADER_PARAMETER_0, + RGUI_SETTINGS_SHADER_PARAMETER_LAST = RGUI_SETTINGS_SHADER_PARAMETER_0 + (GFX_MAX_PARAMETERS - 1), RGUI_SETTINGS_SHADER_0, RGUI_SETTINGS_SHADER_0_FILTER, RGUI_SETTINGS_SHADER_0_SCALE, diff --git a/frontend/menu/disp/rgui.c b/frontend/menu/disp/rgui.c index 7ba31ddd19..fe356f350c 100644 --- a/frontend/menu/disp/rgui.c +++ b/frontend/menu/disp/rgui.c @@ -316,6 +316,10 @@ static void rgui_render(void *data) #ifdef HAVE_SHADER_MANAGER else if (menu_type == RGUI_SETTINGS_SHADER_OPTIONS) strlcpy(title, "SHADER OPTIONS", sizeof(title)); + else if (menu_type == RGUI_SETTINGS_SHADER_PARAMETERS) + strlcpy(title, "SHADER PARAMETERS (CURRENT)", sizeof(title)); + else if (menu_type == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS) + strlcpy(title, "SHADER PARAMETERS (RGUI PRESET)", sizeof(title)); #endif else if (menu_type == RGUI_SETTINGS_FONT_OPTIONS) strlcpy(title, "FONT OPTIONS", sizeof(title)); @@ -453,13 +457,18 @@ static void rgui_render(void *data) strlcpy(type_str, "(DIR)", sizeof(type_str)); w = 5; } - else if (type == RGUI_SETTINGS_SHADER_OPTIONS || type == RGUI_SETTINGS_SHADER_PRESET) + else if (type == RGUI_SETTINGS_SHADER_OPTIONS || type == RGUI_SETTINGS_SHADER_PRESET || type == RGUI_SETTINGS_SHADER_PARAMETERS || type == RGUI_SETTINGS_SHADER_PRESET_PARAMETERS) strlcpy(type_str, "...", sizeof(type_str)); else if (type == RGUI_SETTINGS_SHADER_FILTER) snprintf(type_str, sizeof(type_str), "%s", g_settings.video.smooth ? "Linear" : "Nearest"); else if (driver.menu_ctx && driver.menu_ctx->backend && driver.menu_ctx->backend->shader_manager_get_str) - driver.menu_ctx->backend->shader_manager_get_str(&rgui->shader, type_str, sizeof(type_str), type); + { + if (type >= RGUI_SETTINGS_SHADER_PARAMETER_0 && type <= RGUI_SETTINGS_SHADER_PARAMETER_LAST) + driver.menu_ctx->backend->shader_manager_get_str(rgui->parameter_shader, type_str, sizeof(type_str), type); + else + driver.menu_ctx->backend->shader_manager_get_str(&rgui->shader, type_str, sizeof(type_str), type); + } } else #endif diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index 56c558edf0..d932c94ab8 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -164,6 +164,7 @@ typedef struct #ifdef HAVE_SHADER_MANAGER struct gfx_shader shader; + struct gfx_shader *parameter_shader; // Points to either shader or graphics driver current shader. #endif unsigned current_pad; diff --git a/gfx/gl.c b/gfx/gl.c index c8450ecf94..474235f047 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -978,6 +978,7 @@ static void gl_frame_fbo(void *data, const struct gl_tex_info *tex_info) fbo_info->tex_size[0] = prev_rect->width; fbo_info->tex_size[1] = prev_rect->height; memcpy(fbo_info->coord, fbo_tex_coords, sizeof(fbo_tex_coords)); + fbo_tex_info_cnt++; glBindFramebuffer(RARCH_GL_FRAMEBUFFER, gl->fbo[i]); @@ -1002,8 +1003,6 @@ static void gl_frame_fbo(void *data, const struct gl_tex_info *tex_info) gl_shader_set_coords(gl, &gl->coords, &gl->mvp); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - fbo_tex_info_cnt++; } #if defined(GL_FRAMEBUFFER_SRGB) && !defined(HAVE_OPENGLES) @@ -1018,6 +1017,16 @@ static void gl_frame_fbo(void *data, const struct gl_tex_info *tex_info) set_texture_coords(fbo_tex_coords, xamt, yamt); + // Push final FBO to list. + fbo_info = &fbo_tex_info[gl->fbo_pass - 1]; + fbo_info->tex = gl->fbo_texture[gl->fbo_pass - 1]; + fbo_info->input_size[0] = prev_rect->img_width; + fbo_info->input_size[1] = prev_rect->img_height; + fbo_info->tex_size[0] = prev_rect->width; + fbo_info->tex_size[1] = prev_rect->height; + memcpy(fbo_info->coord, fbo_tex_coords, sizeof(fbo_tex_coords)); + fbo_tex_info_cnt++; + // Render our FBO texture to back buffer. gl_bind_backbuffer(); if (gl->shader) @@ -2909,6 +2918,12 @@ static void gl_show_mouse(void *data, bool state) gl->ctx_driver->show_mouse(gl, state); } +static struct gfx_shader *gl_get_current_shader(void *data) +{ + gl_t *gl = (gl_t*)data; + return gl->shader ? gl->shader->get_current_shader() : NULL; +} + static const video_poke_interface_t gl_poke_interface = { NULL, #ifdef HAVE_FBO @@ -2924,6 +2939,9 @@ static const video_poke_interface_t gl_poke_interface = { gl_set_osd_msg, gl_show_mouse, + NULL, + + gl_get_current_shader, }; static void gl_get_poke_interface(void *data, const video_poke_interface_t **iface) diff --git a/gfx/shader_cg.c b/gfx/shader_cg.c index 5c3bcb6559..6b76079fab 100644 --- a/gfx/shader_cg.c +++ b/gfx/shader_cg.c @@ -132,7 +132,6 @@ struct cg_program }; static struct cg_program prg[GFX_MAX_SHADERS]; -static const char **cg_arguments; static bool cg_active; static CGprofile cgVProf, cgFProf; static unsigned active_index; @@ -145,6 +144,8 @@ static GLuint lut_textures[GFX_MAX_TEXTURES]; static CGparameter cg_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS]; static unsigned cg_attrib_index; +static char cg_alias_define[GFX_MAX_SHADERS][128]; + static void gl_cg_reset_attrib(void) { unsigned i; @@ -288,7 +289,7 @@ static void gl_cg_set_params(void *data, unsigned width, unsigned height, } // Set FBO textures. - if (active_index > 2) + if (active_index) { for (i = 0; i < fbo_info_cnt; i++) { @@ -313,6 +314,15 @@ static void gl_cg_set_params(void *data, unsigned width, unsigned height, } } + // #pragma parameters + for (i = 0; i < cg_shader->num_parameters; i++) + { + CGparameter param_v = cgGetNamedParameter(prg[active_index].vprg, cg_shader->parameters[i].id); + CGparameter param_f = cgGetNamedParameter(prg[active_index].fprg, cg_shader->parameters[i].id); + set_param_1f(param_v, cg_shader->parameters[i].current); + set_param_1f(param_f, cg_shader->parameters[i].current); + } + // Set state parameters if (state_tracker) { @@ -414,18 +424,30 @@ static bool load_program(unsigned index, const char *prog, bool path_is_file) char *listing_f = NULL; char *listing_v = NULL; + unsigned i, argc = 1; + const char *argv[2 + GFX_MAX_SHADERS] = { + "-DPARAMETER_UNIFORM", + NULL, + }; + + for (i = 0; i < GFX_MAX_SHADERS; i++) + { + if (*(cg_alias_define[i])) + argv[argc++] = cg_alias_define[i]; + } + if (path_is_file) { - prg[index].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); + prg[index].fprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", argv); SET_LISTING(f); - prg[index].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); + prg[index].vprg = cgCreateProgramFromFile(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", argv); SET_LISTING(v); } else { - prg[index].fprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", cg_arguments); + prg[index].fprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgFProf, "main_fragment", argv); SET_LISTING(f); - prg[index].vprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", cg_arguments); + prg[index].vprg = cgCreateProgram(cgCtx, CG_SOURCE, prog, cgVProf, "main_vertex", argv); SET_LISTING(v); } @@ -489,6 +511,7 @@ static bool load_plain(const char *path) prg[1] = prg[0]; } + gfx_shader_resolve_parameters(NULL, cg_shader); return true; } @@ -580,14 +603,20 @@ static bool load_preset(const char *path) return false; } - config_file_free(conf); gfx_shader_resolve_relative(cg_shader, path); + gfx_shader_resolve_parameters(conf, cg_shader); + config_file_free(conf); if (cg_shader->passes > GFX_MAX_SHADERS - 3) { RARCH_WARN("Too many shaders ... Capping shader amount to %d.\n", GFX_MAX_SHADERS - 3); cg_shader->passes = GFX_MAX_SHADERS - 3; } + + for (i = 0; i < cg_shader->passes; i++) + if (*cg_shader->pass[i].alias) + snprintf(cg_alias_define[i], sizeof(cg_alias_define[i]), "-D%s_ALIAS", cg_shader->pass[i].alias); + for (i = 0; i < cg_shader->passes; i++) { if (!load_shader(i)) @@ -741,13 +770,16 @@ static void set_program_attributes(unsigned i) prg[i].prev[j].coord = cgGetNamedParameter(prg[i].vprg, attr_buf_coord); } - for (j = 0; j < i - 1; j++) + for (j = 0; j + 1 < i; j++) { char pass_str[64]; snprintf(pass_str, sizeof(pass_str), "PASS%u", j + 1); set_pass_attrib(&prg[i], &prg[i].fbo[j], pass_str); snprintf(pass_str, sizeof(pass_str), "PASSPREV%u", i - (j + 1)); set_pass_attrib(&prg[i], &prg[i].fbo[j], pass_str); + + if (*cg_shader->pass[j].alias) + set_pass_attrib(&prg[i], &prg[i].fbo[j], cg_shader->pass[j].alias); } } @@ -789,6 +821,8 @@ static bool gl_cg_init(void *data, const char *path) cgGLEnableProfile(cgFProf); cgGLEnableProfile(cgVProf); + memset(cg_alias_define, 0, sizeof(cg_alias_define)); + if (path && strcmp(path_get_extension(path), "cgp") == 0) { if (!load_preset(path)) @@ -898,9 +932,9 @@ static bool gl_cg_mipmap_input(unsigned index) return false; } -void gl_cg_set_compiler_args(const char **argv) +static struct gfx_shader *gl_cg_get_current_shader(void) { - cg_arguments = argv; + return cg_active ? cg_shader : NULL; } void gl_cg_invalidate_context(void) @@ -921,6 +955,7 @@ const gl_shader_backend_t gl_cg_backend = { gl_cg_set_mvp, gl_cg_get_prev_textures, gl_cg_mipmap_input, + gl_cg_get_current_shader, RARCH_SHADER_CG, }; diff --git a/gfx/shader_cg.h b/gfx/shader_cg.h index fdb1396509..b1507f5c3b 100644 --- a/gfx/shader_cg.h +++ b/gfx/shader_cg.h @@ -20,7 +20,6 @@ #include "shader_common.h" #include -void gl_cg_set_compiler_args(const char **argv); void gl_cg_invalidate_context(void); // Call when resetting GL context on PS3. extern const gl_shader_backend_t gl_cg_backend; diff --git a/gfx/shader_common.h b/gfx/shader_common.h index 15e59ea1cc..d33713ff6d 100644 --- a/gfx/shader_common.h +++ b/gfx/shader_common.h @@ -54,6 +54,8 @@ struct gl_shader_backend unsigned (*get_prev_textures)(void); bool (*mipmap_input)(unsigned index); + struct gfx_shader *(*get_current_shader)(void); + enum rarch_shader_type type; }; diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c index 3ee2336751..a0bb9506c4 100644 --- a/gfx/shader_glsl.c +++ b/gfx/shader_glsl.c @@ -58,6 +58,8 @@ static state_tracker_t *gl_state_tracker; static GLint gl_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS]; static unsigned gl_attrib_index; +static char glsl_alias_define[1024]; + // Cache the VBO. struct cache_vbo { @@ -325,7 +327,7 @@ static bool compile_shader(GLuint shader, const char *define, const char *progra RARCH_LOG("[GL]: Using GLSL version %u.\n", version_no); } - const char *source[] = { version, define, program }; + const char *source[] = { version, define, glsl_alias_define, program }; glShaderSource(shader, ARRAY_SIZE(source), source, NULL); glCompileShader(shader); @@ -366,7 +368,7 @@ static GLuint compile_program(const char *vertex, const char *fragment, unsigned { RARCH_LOG("Found GLSL vertex shader.\n"); vert = glCreateShader(GL_VERTEX_SHADER); - if (!compile_shader(vert, "#define VERTEX\n", vertex)) + if (!compile_shader(vert, "#define VERTEX\n#define PARAMETER_UNIFORM\n", vertex)) { RARCH_ERR("Failed to compile vertex shader #%u\n", i); return false; @@ -379,7 +381,7 @@ static GLuint compile_program(const char *vertex, const char *fragment, unsigned { RARCH_LOG("Found GLSL fragment shader.\n"); frag = glCreateShader(GL_FRAGMENT_SHADER); - if (!compile_shader(frag, "#define FRAGMENT\n", fragment)) + if (!compile_shader(frag, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", fragment)) { RARCH_ERR("Failed to compile fragment shader #%u\n", i); return false; @@ -566,6 +568,9 @@ static void find_uniforms(unsigned pass, GLuint prog, struct shader_uniforms *un find_uniforms_frame(prog, &uni->pass[i], frame_base); snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass - (i + 1)); find_uniforms_frame(prog, &uni->pass[i], frame_base); + + if (*glsl_shader->pass[i].alias) + find_uniforms_frame(prog, &uni->pass[i], glsl_shader->pass[i].alias); } clear_uniforms_frame(&uni->prev[0]); @@ -662,6 +667,8 @@ static bool gl_glsl_init(void *data, const char *path) if (!glsl_shader) return false; + config_file_t *conf = NULL; + if (path) { bool ret; @@ -674,12 +681,11 @@ static bool gl_glsl_init(void *data, const char *path) } else if (strcmp(path_get_extension(path), "glslp") == 0) { - config_file_t *conf = config_file_new(path); + conf = config_file_new(path); if (conf) { ret = gfx_shader_read_conf_cgp(conf, glsl_shader); glsl_shader->modern = true; - config_file_free(conf); } else ret = false; @@ -703,6 +709,13 @@ static bool gl_glsl_init(void *data, const char *path) } gfx_shader_resolve_relative(glsl_shader, path); + gfx_shader_resolve_parameters(conf, glsl_shader); + + if (conf) + { + config_file_free(conf); + conf = NULL; + } const char *stock_vertex = glsl_shader->modern ? stock_vertex_modern : stock_vertex_legacy; @@ -729,6 +742,19 @@ static bool gl_glsl_init(void *data, const char *path) } #endif + // Find all aliases we use in our GLSLP and add #defines for them so + // that a shader can choose a fallback if we are not using a preset. + *glsl_alias_define = '\0'; + for (i = 0; i < glsl_shader->passes; i++) + { + if (*glsl_shader->pass[i].alias) + { + char define[128]; + snprintf(define, sizeof(define), "#define %s_ALIAS\n", glsl_shader->pass[i].alias); + strlcat(glsl_alias_define, define, sizeof(glsl_alias_define)); + } + } + if (!(gl_program[0] = compile_program(stock_vertex, stock_fragment, 0))) { RARCH_ERR("GLSL stock programs failed to compile.\n"); @@ -810,12 +836,6 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, const struct gl_tex_info *fbo_info, unsigned fbo_info_cnt) { (void)data; - // We enforce a certain layout for our various texture types in the texunits. - // - Regular frame (Texture) (always bound). - // - LUT textures (always bound). - // - Original texture (always bound if meaningful). - // - FBO textures (always bound if available). - // - Previous textures. if (!glsl_enable || (gl_program[active_index] == 0)) return; @@ -853,21 +873,22 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, if (uni->frame_direction >= 0) glUniform1i(uni->frame_direction, g_extern.frame_is_reverse ? -1 : 1); + unsigned texunit = 1; + for (i = 0; i < glsl_shader->luts; i++) { if (uni->lut_texture[i] >= 0) { // Have to rebind as HW render could override this. - glActiveTexture(GL_TEXTURE0 + i + 1); + glActiveTexture(GL_TEXTURE0 + texunit); glBindTexture(GL_TEXTURE_2D, gl_teximage[i]); - glUniform1i(uni->lut_texture[i], i + 1); + glUniform1i(uni->lut_texture[i], texunit); + texunit++; } } - unsigned texunit = glsl_shader->luts + 1; - - // Set original texture unless we're in first pass (pointless). - if (active_index > 1) + // Set original texture. + if (active_index) { if (uni->orig.texture >= 0) { @@ -875,10 +896,9 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, glActiveTexture(GL_TEXTURE0 + texunit); glUniform1i(uni->orig.texture, texunit); glBindTexture(GL_TEXTURE_2D, info->tex); + texunit++; } - texunit++; - if (uni->orig.texture_size >= 0) glUniform2fv(uni->orig.texture_size, 1, info->tex_size); @@ -898,20 +918,16 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, size += 8; } - // Bind new texture in the chain. - if (fbo_info_cnt > 0) - { - glActiveTexture(GL_TEXTURE0 + texunit + fbo_info_cnt - 1); - glBindTexture(GL_TEXTURE_2D, fbo_info[fbo_info_cnt - 1].tex); - } - // Bind FBO textures. for (i = 0; i < fbo_info_cnt; i++) { if (uni->pass[i].texture) + { + glActiveTexture(GL_TEXTURE0 + texunit); + glBindTexture(GL_TEXTURE_2D, fbo_info[i].tex); glUniform1i(uni->pass[i].texture, texunit); - - texunit++; + texunit++; + } if (uni->pass[i].texture_size >= 0) glUniform2fv(uni->pass[i].texture_size, 1, fbo_info[i].tex_size); @@ -932,23 +948,6 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, } } } - else - { - // First pass, so unbind everything to avoid collitions. - // Unbind ORIG. - glActiveTexture(GL_TEXTURE0 + texunit); - glBindTexture(GL_TEXTURE_2D, 0); - - GLuint base_tex = texunit + 1; - // Unbind any lurking FBO passes. - // Rendering to a texture that is bound to a texture unit - // sounds very shaky ... ;) - for (i = 0; i < glsl_shader->passes; i++) - { - glActiveTexture(GL_TEXTURE0 + base_tex + i); - glBindTexture(GL_TEXTURE_2D, 0); - } - } // Set previous textures. Only bind if they're actually used. for (i = 0; i < PREV_TEXTURES; i++) @@ -957,11 +956,10 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, { glActiveTexture(GL_TEXTURE0 + texunit); glBindTexture(GL_TEXTURE_2D, prev_info[i].tex); - glUniform1i(uni->prev[i].texture, texunit++); + glUniform1i(uni->prev[i].texture, texunit); + texunit++; } - texunit++; - if (uni->prev[i].texture_size >= 0) glUniform2fv(uni->prev[i].texture_size, 1, prev_info[i].tex_size); @@ -992,6 +990,14 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height, glActiveTexture(GL_TEXTURE0); + // #pragma parameters + for (i = 0; i < glsl_shader->num_parameters; i++) + { + int location = glGetUniformLocation(gl_program[active_index], glsl_shader->parameters[i].id); + glUniform1f(location, glsl_shader->parameters[i].current); + } + + // Set state parameters if (gl_state_tracker) { static struct state_tracker_uniform info[GFX_MAX_VARIABLES]; @@ -1163,6 +1169,11 @@ static bool gl_glsl_mipmap_input(unsigned index) return false; } +static struct gfx_shader *gl_glsl_get_current_shader(void) +{ + return glsl_enable ? glsl_shader : NULL; +} + void gl_glsl_set_get_proc_address(gfx_ctx_proc_t (*proc)(const char*)) { glsl_get_proc_address = proc; @@ -1188,6 +1199,7 @@ const gl_shader_backend_t gl_glsl_backend = { gl_glsl_set_mvp, gl_glsl_get_prev_textures, gl_glsl_mipmap_input, + gl_glsl_get_current_shader, RARCH_SHADER_GLSL, }; diff --git a/gfx/shader_hlsl.c b/gfx/shader_hlsl.c index 92980e8c09..3cf5d65e96 100644 --- a/gfx/shader_hlsl.c +++ b/gfx/shader_hlsl.c @@ -435,6 +435,11 @@ static bool hlsl_mipmap_input(unsigned index) return false; } +static struct gfx_shader *hlsl_get_current_shader(void) +{ + return NULL; +} + const gl_shader_backend_t hlsl_backend = { hlsl_init, hlsl_deinit, @@ -448,6 +453,7 @@ const gl_shader_backend_t hlsl_backend = { hlsl_set_mvp, NULL, /* hlsl_get_prev_textures */ hlsl_mipmap_input, + hlsl_get_current_shader, RARCH_SHADER_HLSL, }; diff --git a/gfx/shader_parse.c b/gfx/shader_parse.c index e084ffd39e..29f365284f 100644 --- a/gfx/shader_parse.c +++ b/gfx/shader_parse.c @@ -105,6 +105,11 @@ static bool shader_parse_pass(config_file_t *conf, struct gfx_shader_pass *pass, print_buf(mipmap_buf, "mipmap_input%u", i); config_get_bool(conf, mipmap_buf, &pass->mipmap); + char alias_buf[64]; + print_buf(alias_buf, "alias%u", i); + if (!config_get_array(conf, alias_buf, pass->alias, sizeof(pass->alias))) + *pass->alias = '\0'; + // Scale struct gfx_fbo_scale *scale = &pass->fbo; char scale_type[64] = {0}; @@ -268,10 +273,88 @@ static bool shader_parse_textures(config_file_t *conf, struct gfx_shader *shader return true; } +static struct gfx_shader_parameter *find_parameter(struct gfx_shader_parameter *params, unsigned num_params, const char *id) +{ + unsigned i; + for (i = 0; i < num_params; i++) + { + if (!strcmp(params[i].id, id)) + return ¶ms[i]; + } + return NULL; +} + +bool gfx_shader_resolve_parameters(config_file_t *conf, struct gfx_shader *shader) +{ + unsigned i; + + shader->num_parameters = 0; + struct gfx_shader_parameter *param = &shader->parameters[shader->num_parameters]; + + // Find all parameters in our shaders. + for (i = 0; i < shader->passes; i++) + { + char line[2048]; + FILE *file = fopen(shader->pass[i].source.path, "r"); + if (!file) + continue; + + while (shader->num_parameters < ARRAY_SIZE(shader->parameters) && fgets(line, sizeof(line), file)) + { + int ret = sscanf(line, "#pragma parameter %64s \"%64[^\"]\" %f %f %f %f", + param->id, param->desc, ¶m->initial, ¶m->minimum, ¶m->maximum, ¶m->step); + + if (ret >= 5) + { + param->id[63] = '\0'; + param->desc[63] = '\0'; + + if (ret == 5) + param->step = 0.1f * (param->maximum - param->minimum); + + RARCH_LOG("Found #pragma parameter %s (%s) %f %f %f %f\n", + param->desc, param->id, param->initial, param->minimum, param->maximum, param->step); + param->current = param->initial; + + shader->num_parameters++; + param++; + } + } + + fclose(file); + } + + // Read in parameters which override the defaults. + if (conf) + { + char parameters[1024]; + char *save = NULL; + const char *id; + + if (!config_get_array(conf, "parameters", parameters, sizeof(parameters))) + return true; + + for (id = strtok_r(parameters, ";", &save); id; id = strtok_r(NULL, ";", &save)) + { + struct gfx_shader_parameter *param = find_parameter(shader->parameters, shader->num_parameters, id); + if (!param) + { + RARCH_WARN("[CGP/GLSLP]: Parameter %s is set in the preset, but no shader uses this parameter, ignoring.\n", id); + continue; + } + + if (!config_get_float(conf, id, ¶m->current)) + RARCH_WARN("[CGP/GLSLP]: Parameter %s is not set in preset.\n", id); + } + } + + return true; +} + static bool shader_parse_imports(config_file_t *conf, struct gfx_shader *shader) { char imports[1024]; - char *save; + char *save = NULL; const char *id; if (!config_get_array(conf, "imports", imports, sizeof(imports))) return true; @@ -538,9 +621,32 @@ void gfx_shader_write_conf_cgp(config_file_t *conf, const struct gfx_shader *sha print_buf(key, "mipmap_input%u", i); config_set_bool(conf, key, pass->mipmap); + print_buf(key, "alias%u", i); + config_set_string(conf, key, pass->alias); + shader_write_fbo(conf, &pass->fbo, i); } + if (shader->num_parameters) + { + char parameters[4096] = {0}; + strlcpy(parameters, shader->parameters[0].id, sizeof(parameters)); + for (i = 1; i < shader->num_parameters; i++) + { + // O(n^2), but number of parameters is very limited. + strlcat(parameters, ";", sizeof(parameters)); + strlcat(parameters, shader->parameters[i].id, sizeof(parameters)); + } + + config_set_string(conf, "parameters", parameters); + + for (i = 0; i < shader->num_parameters; i++) + { + char key[64]; + config_set_float(conf, shader->parameters[i].id, shader->parameters[i].current); + } + } + if (shader->luts) { char textures[4096] = {0}; diff --git a/gfx/shader_parse.h b/gfx/shader_parse.h index e88d627c08..6fb8362f11 100644 --- a/gfx/shader_parse.h +++ b/gfx/shader_parse.h @@ -28,6 +28,7 @@ extern "C" { #define GFX_MAX_SHADERS 16 #define GFX_MAX_TEXTURES 8 #define GFX_MAX_VARIABLES 64 +#define GFX_MAX_PARAMETERS 64 enum gfx_scale_type { @@ -65,6 +66,17 @@ struct gfx_fbo_scale bool valid; }; +struct gfx_shader_parameter +{ + char id[64]; + char desc[64]; + float current; + float minimum; + float initial; + float maximum; + float step; +}; + struct gfx_shader_pass { struct @@ -77,6 +89,7 @@ struct gfx_shader_pass } string; } source; + char alias[64]; struct gfx_fbo_scale fbo; enum gfx_filter_type filter; enum gfx_wrap_type wrap; @@ -108,6 +121,9 @@ struct gfx_shader unsigned luts; struct gfx_shader_lut lut[GFX_MAX_TEXTURES]; + struct gfx_shader_parameter parameters[GFX_MAX_PARAMETERS]; + unsigned num_parameters; + unsigned variables; struct state_tracker_uniform_info variable[GFX_MAX_VARIABLES]; char script_path[PATH_MAX]; @@ -119,6 +135,7 @@ 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); void gfx_shader_resolve_relative(struct gfx_shader *shader, const char *ref_path); +bool gfx_shader_resolve_parameters(config_file_t *conf, struct gfx_shader *shader); enum rarch_shader_type gfx_shader_parse_type(const char *path, enum rarch_shader_type fallback); diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index ca8e574516..76f844c483 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -751,6 +751,13 @@ static void thread_apply_state_changes(void *data) slock_unlock(thr->frame.lock); } +// This is read-only state which should not have any kind of race condition. +static struct gfx_shader *thread_get_current_shader(void *data) +{ + thread_video_t *thr = (thread_video_t*)data; + return thr->poke ? thr->poke->get_current_shader(thr->driver_data) : NULL; +} + static const video_poke_interface_t thread_poke = { thread_set_filtering, #ifdef HAVE_FBO @@ -763,6 +770,12 @@ static const video_poke_interface_t thread_poke = { thread_set_texture_frame, thread_set_texture_enable, #endif + + NULL, + NULL, + NULL, + + thread_get_current_shader, }; static void thread_get_poke_interface(void *data, const video_poke_interface_t **iface)