diff --git a/command.c b/command.c index 6b9301f9d3..87e99f3a92 100644 --- a/command.c +++ b/command.c @@ -229,7 +229,7 @@ static bool cmd_set_shader(const char *arg) msg_queue_push(g_extern.msg_queue, msg, 1, 120); RARCH_LOG("Applying shader \"%s\".\n", arg); - return video_set_shader_func(type, arg, (1ULL << RARCH_SHADER_MULTIPASS)); + return video_set_shader_func(type, arg, RARCH_SHADER_INDEX_MULTIPASS); } static const struct cmd_action_map action_map[] = { diff --git a/driver.h b/driver.h index 81b93732a8..363d08e694 100644 --- a/driver.h +++ b/driver.h @@ -136,13 +136,11 @@ enum rarch_shader_type RARCH_SHADER_NONE }; -enum rarch_shader_mask +enum rarch_shader_index { - RARCH_SHADER_MULTIPASS = 1, - RARCH_SHADER_PASS0, - RARCH_SHADER_PASS0_STOCK, - RARCH_SHADER_PASS1, - RARCH_SHADER_PASS1_STOCK + RARCH_SHADER_INDEX_MULTIPASS = 0, + RARCH_SHADER_INDEX_PASS0 = 1, + RARCH_SHADER_INDEX_PASS1 = 2 }; typedef struct video_info @@ -233,7 +231,7 @@ typedef struct video_driver // Is the window still active? bool (*alive)(void *data); bool (*focus)(void *data); // Does the window have focus? - bool (*set_shader)(void *data, enum rarch_shader_type type, const char *path, unsigned mask); // Sets shader. Might not be implemented. + bool (*set_shader)(void *data, enum rarch_shader_type type, const char *path, unsigned index); // Sets shader. Might not be implemented. void (*free)(void *data); const char *ident; diff --git a/gfx/gl.c b/gfx/gl.c index ab2fa2bdc7..ad0290c2bf 100644 --- a/gfx/gl.c +++ b/gfx/gl.c @@ -1709,75 +1709,73 @@ static bool gl_focus(void *data) } #if defined(HAVE_GLSL) || defined(HAVE_CG) -static bool gl_set_shader(void *data, enum rarch_shader_type type, const char *path, unsigned mask) +static bool gl_set_shader(void *data, enum rarch_shader_type type, const char *path, unsigned index) { gl_t *gl = (gl_t*)data; - if (mask & (1ULL << RARCH_SHADER_MULTIPASS)) + if (type == RARCH_SHADER_NONE) + return false; + + if (index == RARCH_SHADER_INDEX_MULTIPASS && !path) { + RARCH_ERR("[GL]: Cannot set stock shader to multipass.\n"); + return false; + } + + if (!gl->shader && index != RARCH_SHADER_INDEX_MULTIPASS) + { + RARCH_ERR("[GL]: No shader core is init. Cannot set shader %s to pass %u.\n", path, index); + return false; + } + + if (gl->shader && gl->shader->type != type) + { + RARCH_ERR("[GL]: Trying to set a specific shader pass %u, but that particular shader core is not initialized.\n", index); + return false; + } + + // Need full teardown for multipass. + if (index == RARCH_SHADER_INDEX_MULTIPASS) + { + gl_shader_deinit(gl); + + switch (type) + { +#ifdef HAVE_GLSL + case RARCH_SHADER_GLSL: + gl->shader = &gl_glsl_backend; + break; +#endif +#ifdef HAVE_CG + case RARCH_SHADER_CG: + gl->shader = &gl_cg_backend; + break; +#endif + + default: + gl->shader = NULL; + break; + } + + if (!gl->shader) + { + RARCH_ERR("[GL]: Cannot find shader core for path: %s.\n", path); + return false; + } + #ifdef HAVE_FBO gl_deinit_fbo(gl); glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); #endif - gl_shader_deinit(gl); - } + bool ret = gl->shader->init(path); + if (!ret) + { + gl->shader = NULL; + RARCH_WARN("[GL]: Failed to set multipass shader. Falling back to stock.\n"); + return gl->shader->init(NULL); + } - switch (type) - { -#ifdef HAVE_GLSL - case RARCH_SHADER_GLSL: - if (mask & (1ULL << RARCH_SHADER_MULTIPASS)) - { - if (!gl_glsl_init(path)) - return false; - } - else if (mask & (1ULL << RARCH_SHADER_PASS0)) - { -#if 0 - /* TODO - doesn't seem to be added yet? */ - if (!gl_glsl_load_shader(1, (mask & (1ULL << RARCH_SHADER_PASS0_STOCK)) ? NULL : path)) -#endif - return false; - } - else if (mask & (1ULL << RARCH_SHADER_PASS1)) - { -#if 0 - /* TODO - doesn't seem to be added yet? */ - if (!gl_glsl_load_shader(2, (mask & (1ULL << RARCH_SHADER_PASS1_STOCK)) ? NULL : path)) -#endif - return false; - } - break; -#endif - -#ifdef HAVE_CG - case RARCH_SHADER_CG: - if (mask & (1ULL << RARCH_SHADER_MULTIPASS)) - { - if (!gl_cg_init(path)) - return false; - } - else if (mask & (1ULL << RARCH_SHADER_PASS0)) - { - if (!gl_cg_load_shader(1, (mask & (1ULL << RARCH_SHADER_PASS0_STOCK)) ? NULL : path)) - return false; - } - else if (mask & (1ULL << RARCH_SHADER_PASS1)) - { - if (!gl_cg_load_shader(2, (mask & (1ULL << RARCH_SHADER_PASS1_STOCK)) ? NULL : path)) - return false; - } - break; -#endif - - default: - RARCH_ERR("Invalid shader type in gl_set_shader().\n"); - return false; - } - - if (mask & (1ULL << RARCH_SHADER_MULTIPASS)) - { #ifdef HAVE_FBO // Set up render to texture again. gl_init_fbo(gl, gl->tex_w, gl->tex_h); @@ -1786,9 +1784,19 @@ static bool gl_set_shader(void *data, enum rarch_shader_type type, const char *p // Apparently need to set viewport for passes when we aren't using FBOs. gl_set_shader_viewport(gl, 0); gl_set_shader_viewport(gl, 1); + return true; } + else // Replace a currently loaded shader directly. + { + if (index > gl->shader->num_shaders()) + { + RARCH_ERR("Can only load shader for passes that already exist. " + "Attempted to set pass %u, but only %u passes exist.\n", index, gl->shader->num_shaders()); + return false; + } - return true; + return gl->shader->load_shader(index, path); + } } #endif diff --git a/gfx/shader_cg.c b/gfx/shader_cg.c index a80c1adec2..1a482eae9a 100644 --- a/gfx/shader_cg.c +++ b/gfx/shader_cg.c @@ -477,21 +477,30 @@ static bool load_plain(const char *path) if (!load_stock()) return false; - RARCH_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 (path) { - if (!load_program(2, g_settings.video.second_pass_shader, true)) + RARCH_LOG("Loading Cg file: %s\n", path); + + if (!load_program(1, path, true)) return false; - cg_shader_num = 2; + 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; + } } else { - prg[2] = prg[0]; + RARCH_LOG("Loading stock Cg file.\n"); + prg[2] = prg[1] = prg[0]; cg_shader_num = 1; } @@ -1360,5 +1369,8 @@ const gl_shader_backend_t gl_cg_backend = { gl_cg_shader_scale, gl_cg_set_coords, gl_cg_set_mvp, + + gl_cg_load_shader, + RARCH_SHADER_CG, }; diff --git a/gfx/shader_common.h b/gfx/shader_common.h index 9e30584d3f..582f84ac2f 100644 --- a/gfx/shader_common.h +++ b/gfx/shader_common.h @@ -39,6 +39,9 @@ struct gl_shader_backend void (*shader_scale)(unsigned index, struct gl_fbo_scale *scale); bool (*set_coords)(const struct gl_coords *coords); bool (*set_mvp)(const math_matrix *mat); + + bool (*load_shader)(unsigned index, const char *path); + enum rarch_shader_type type; }; #endif diff --git a/gfx/shader_glsl.c b/gfx/shader_glsl.c index 654d593cce..4de50804a2 100644 --- a/gfx/shader_glsl.c +++ b/gfx/shader_glsl.c @@ -894,6 +894,8 @@ static bool link_program(GLuint prog) static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size_t num) { + bool ret = true; + for (unsigned i = 0; i < num; i++) { gl_prog[i] = pglCreateProgram(); @@ -901,7 +903,8 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size if (gl_prog[i] == 0) { RARCH_ERR("Failed to create GL program #%u.\n", i); - return false; + ret = false; + goto end; } if (progs[i].vertex) @@ -911,11 +914,11 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size if (!compile_shader(shader, progs[i].vertex)) { RARCH_ERR("Failed to compile vertex shader #%u\n", i); - return false; + ret = false; + goto end; } pglAttachShader(gl_prog[i], shader); - free(progs[i].vertex); } if (progs[i].fragment) @@ -925,11 +928,11 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size if (!compile_shader(shader, progs[i].fragment)) { RARCH_ERR("Failed to compile fragment shader #%u\n", i); - return false; + ret = false; + goto end; } pglAttachShader(gl_prog[i], shader); - free(progs[i].fragment); } if (progs[i].vertex || progs[i].fragment) @@ -938,7 +941,8 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size if (!link_program(gl_prog[i])) { RARCH_ERR("Failed to link program #%u\n", i); - return false; + ret = false; + goto end; } GLint location = pglGetUniformLocation(gl_prog[i], "rubyTexture"); @@ -947,7 +951,16 @@ static bool compile_programs(GLuint *gl_prog, struct shader_program *progs, size } } - return true; +end: + for (unsigned i = 0; i < num; i++) + { + free(progs[i].vertex); + free(progs[i].fragment); + progs[i].vertex = NULL; + progs[i].fragment = NULL; + } + + return ret; } static void gl_glsl_reset_attrib(void) @@ -1014,6 +1027,56 @@ static void find_uniforms(GLuint prog, struct shader_uniforms *uni) pglUseProgram(0); } +static void gl_glsl_delete_shader(GLuint prog) +{ + GLsizei count; + GLuint shaders[2] = {0}; + + pglGetAttachedShaders(prog, 2, &count, shaders); + for (GLsizei i = 0; i < count; i++) + { + pglDetachShader(prog, shaders[i]); + pglDeleteShader(shaders[i]); + } + + pglDeleteProgram(prog); +} + +static bool gl_glsl_load_shader(unsigned index, const char *path) +{ + pglUseProgram(0); + + if (gl_program[index] != gl_program[0]) + { + gl_glsl_delete_shader(gl_program[index]); + gl_program[index] = 0; + } + + if (path) + { + struct shader_program prog = {0}; + unsigned progs = get_xml_shaders(path, &prog, 1); + if (progs != 1) + return false; + + if (!compile_programs(&gl_program[index], &prog, 1)) + { + RARCH_ERR("Failed to compile shader: %s.\n", path); + return false; + } + + find_uniforms(gl_program[index], &gl_uniforms[index]); + } + else + { + gl_program[index] = gl_program[0]; + gl_uniforms[index] = gl_uniforms[0]; + } + + pglUseProgram(gl_program[active_index]); + return true; +} + // Platforms with broken get_proc_address. // Assume functions are available without proc_address. #undef LOAD_GL_SYM @@ -1129,7 +1192,12 @@ bool gl_glsl_init(const char *path) unsigned secondary_progs = get_xml_shaders(g_settings.video.second_pass_shader, progs, 1); if (secondary_progs == 1) { - compile_programs(&gl_program[2], progs, 1); + if (!compile_programs(&gl_program[2], progs, 1)) + { + RARCH_ERR("Failed to compile second pass shader.\n"); + return false; + } + num_progs++; } else @@ -1185,17 +1253,7 @@ void gl_glsl_deinit(void) if (gl_program[i] == 0 || (i && gl_program[i] == gl_program[0])) continue; - GLsizei count; - GLuint shaders[2]; - - pglGetAttachedShaders(gl_program[i], 2, &count, shaders); - for (GLsizei j = 0; j < count; j++) - { - pglDetachShader(gl_program[i], shaders[j]); - pglDeleteShader(shaders[j]); - } - - pglDeleteProgram(gl_program[i]); + gl_glsl_delete_shader(gl_program[i]); } glDeleteTextures(gl_teximage_cnt, gl_teximage); @@ -1507,5 +1565,8 @@ const gl_shader_backend_t gl_glsl_backend = { gl_glsl_shader_scale, gl_glsl_set_coords, gl_glsl_set_mvp, + + gl_glsl_load_shader, + RARCH_SHADER_GLSL, }; diff --git a/retroarch.c b/retroarch.c index 42b983dbed..57057e15e4 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2342,7 +2342,7 @@ static void check_shader_dir(void) msg_queue_push(g_extern.msg_queue, msg, 1, 120); RARCH_LOG("Applying shader \"%s\".\n", shader); - if (!video_set_shader_func(type, shader, (1ULL << RARCH_SHADER_MULTIPASS))) + if (!video_set_shader_func(type, shader, RARCH_SHADER_INDEX_MULTIPASS)) RARCH_WARN("Failed to apply shader.\n"); }