diff --git a/Makefile.common b/Makefile.common index 5d293e7198..6ff9d71cf5 100644 --- a/Makefile.common +++ b/Makefile.common @@ -822,11 +822,6 @@ ifeq ($(HAVE_LAKKA_SWITCH), 1) DEFINES += -DHAVE_LAKKA_SWITCH endif -# Does not depend on HAVE_MENU -ifeq ($(HAVE_SHADERS_COMMON), 1) - OBJ += menu/menu_shader.o -endif - ifeq ($(HAVE_MENU_COMMON), 1) OBJ += menu/menu_setting.o \ menu/widgets/menu_filebrowser.o \ diff --git a/griffin/griffin.c b/griffin/griffin.c index d5b1dc9d33..980d5f04a0 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1270,10 +1270,6 @@ PLAYLISTS /*============================================================ MENU ============================================================ */ -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) || defined(HAVE_SLANG) -#include "../menu/menu_shader.c" -#endif - #ifdef HAVE_GFX_WIDGETS #include "../gfx/gfx_widgets.c" #include "../gfx/widgets/gfx_widget_screenshot.c" diff --git a/menu/menu_driver.h b/menu/menu_driver.h index efa35471d2..5587380b1f 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -327,7 +327,6 @@ typedef struct } scratchpad; const menu_ctx_driver_t *driver_ctx; void *userdata; - struct video_shader *menu_driver_shader; } menu_handle_t; typedef struct menu_content_ctx_defer_info diff --git a/menu/menu_shader.c b/menu/menu_shader.c deleted file mode 100644 index 726ec8f013..0000000000 --- a/menu/menu_shader.c +++ /dev/null @@ -1,771 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2010-2014 - Hans-Kristian Arntzen - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include - -#include -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "menu_driver.h" -#include "menu_entries.h" -#include "menu_shader.h" - -#include "../command.h" -#include "../file_path_special.h" -#include "../paths.h" -#include "../retroarch.h" -#include "../verbosity.h" - -enum auto_shader_operation -{ - AUTO_SHADER_OP_SAVE = 0, - AUTO_SHADER_OP_REMOVE, - AUTO_SHADER_OP_EXISTS -}; - -static enum rarch_shader_type shader_types[] = -{ - RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG -}; - -struct video_shader *menu_shader_get(void) -{ - menu_handle_t *menu = menu_driver_get_ptr(); - if (video_shader_any_supported()) - if (menu) - return menu->menu_driver_shader; - return NULL; -} - -void menu_shader_manager_free(void *data) -{ - menu_handle_t *menu = (menu_handle_t*)data; - if (menu->menu_driver_shader) - free(menu->menu_driver_shader); - menu->menu_driver_shader = NULL; -} - -/** - * menu_shader_manager_init: - * - * Initializes shader manager. - **/ -bool menu_shader_manager_init(void) -{ - menu_handle_t *menu = menu_driver_get_ptr(); - enum rarch_shader_type type = RARCH_SHADER_NONE; - bool ret = true; - bool is_preset = false; - const char *path_shader = NULL; - struct video_shader *menu_shader = NULL; - - /* We get the shader preset directly from the video driver, so that - * we are in sync with it (it could fail loading an auto-shader) - * If we can't (e.g. get_current_shader is not implemented), - * we'll load retroarch_get_shader_preset() like always */ - video_shader_ctx_t shader_info = {0}; - - video_shader_driver_get_current_shader(&shader_info); - - if (shader_info.data) - path_shader = shader_info.data->path; - else - path_shader = retroarch_get_shader_preset(); - - menu_shader_manager_free(menu); - - menu_shader = (struct video_shader*) - calloc(1, sizeof(*menu_shader)); - - if (!menu_shader) - { - ret = false; - goto end; - } - - if (string_is_empty(path_shader)) - goto end; - - type = video_shader_get_type_from_ext(path_get_extension(path_shader), - &is_preset); - - if (!video_shader_is_supported(type)) - { - ret = false; - goto end; - } - - if (is_preset) - { - config_file_t *conf = NULL; - - conf = video_shader_read_preset(path_shader); - - if (!conf) - { - ret = false; - goto end; - } - - if (video_shader_read_conf_preset(conf, menu_shader)) - video_shader_resolve_parameters(conf, menu_shader); - - menu_shader->modified = false; - - config_file_free(conf); - } - else - { - strlcpy(menu_shader->pass[0].source.path, path_shader, - sizeof(menu_shader->pass[0].source.path)); - menu_shader->passes = 1; - } - -end: - menu->menu_driver_shader = menu_shader; - command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); - return ret; -} - -/** - * menu_shader_manager_set_preset: - * @shader : Shader handle. - * @type : Type of shader. - * @preset_path : Preset path to load from. - * @apply : Whether to apply the shader or just update shader information - * - * Sets shader preset. - **/ -bool menu_shader_manager_set_preset(struct video_shader *shader, - enum rarch_shader_type type, const char *preset_path, bool apply) -{ - config_file_t *conf = NULL; - bool refresh = false; - bool ret = false; - - if (apply && !retroarch_apply_shader(type, preset_path, true)) - goto clear; - - if (string_is_empty(preset_path)) - { - ret = true; - goto clear; - } - - if (!shader) - { - ret = false; - goto end; - } - - /* Load stored Preset into menu on success. - * Used when a preset is directly loaded. - * No point in updating when the Preset was - * created from the menu itself. */ - if (!(conf = video_shader_read_preset(preset_path))) - { - ret = false; - goto end; - } - - RARCH_LOG("Setting Menu shader: %s.\n", preset_path); - - if (video_shader_read_conf_preset(conf, shader)) - video_shader_resolve_parameters(conf, shader); - - if (conf) - config_file_free(conf); - - ret = true; - -end: -#ifdef HAVE_MENU - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); -#endif - command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); - return ret; - -clear: - /* We don't want to disable shaders entirely here, - * just reset number of passes - * > Note: Disabling shaders at this point would in - * fact be dangerous, since it changes the number of - * entries in the shader options menu which can in - * turn lead to the menu selection pointer going out - * of bounds. This causes undefined behaviour/segfaults */ - menu_shader_manager_clear_num_passes(shader); - command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); - return ret; -} - -static bool menu_shader_manager_save_preset_internal( - const struct video_shader *shader, const char *basename, - const char *dir_video_shader, - bool apply, bool save_reference, - const char **target_dirs, - size_t num_target_dirs) -{ - bool ret = false; - enum rarch_shader_type type = RARCH_SHADER_NONE; - char *preset_path = NULL; - size_t i = 0; - char fullname[PATH_MAX_LENGTH]; - char buffer[PATH_MAX_LENGTH]; - - fullname[0] = buffer[0] = '\0'; - - if (!shader || !shader->passes) - return false; - - type = menu_shader_manager_get_type(shader); - - if (type == RARCH_SHADER_NONE) - return false; - - if (shader->modified) - save_reference = false; - - if (!string_is_empty(basename)) - { - /* We are comparing against a fixed list of file - * extensions, the longest (slangp) being 6 characters - * in length. We therefore only need to extract the first - * 7 characters from the extension of the input path - * to correctly validate a match */ - char ext_lower[8]; - const char *ext = NULL; - - ext_lower[0] = '\0'; - - strlcpy(fullname, basename, sizeof(fullname)); - - /* Get file extension */ - ext = strrchr(basename, '.'); - - /* Copy and convert to lower case */ - if (ext && (*(++ext) != '\0')) - { - strlcpy(ext_lower, ext, sizeof(ext_lower)); - string_to_lower(ext_lower); - } - - /* Append extension automatically as appropriate. */ - if ( !string_is_equal(ext_lower, "cgp") - && !string_is_equal(ext_lower, "glslp") - && !string_is_equal(ext_lower, "slangp")) - { - const char *preset_ext = video_shader_get_preset_extension(type); - strlcat(fullname, preset_ext, sizeof(fullname)); - } - } - else - { - strlcpy(fullname, "retroarch", sizeof(fullname)); - strlcat(fullname, - video_shader_get_preset_extension(type), sizeof(fullname)); - } - - if (path_is_absolute(fullname)) - { - preset_path = fullname; - ret = video_shader_write_preset(preset_path, - dir_video_shader, - shader, save_reference); - - if (ret) - RARCH_LOG("Saved shader preset to %s.\n", preset_path); - else - RARCH_ERR("Failed writing shader preset to %s.\n", preset_path); - } - else - { - char basedir[PATH_MAX_LENGTH]; - - for (i = 0; i < num_target_dirs; i++) - { - if (string_is_empty(target_dirs[i])) - continue; - - fill_pathname_join(buffer, target_dirs[i], - fullname, sizeof(buffer)); - - strlcpy(basedir, buffer, sizeof(basedir)); - path_basedir(basedir); - - if (!path_is_directory(basedir)) - { - ret = path_mkdir(basedir); - - if (!ret) - { - RARCH_WARN("Failed to create preset directory %s.\n", basedir); - continue; - } - } - - preset_path = buffer; - - ret = video_shader_write_preset(preset_path, - dir_video_shader, - shader, save_reference); - - if (ret) - { - RARCH_LOG("Saved shader preset to %s.\n", preset_path); - break; - } - else - RARCH_WARN("Failed writing shader preset to %s.\n", preset_path); - } - - if (!ret) - RARCH_ERR("Failed to write shader preset. Make sure shader directory" - " and/or config directory are writable.\n"); - } - - if (ret && apply) - menu_shader_manager_set_preset(NULL, type, preset_path, true); - - return ret; -} - -static bool menu_shader_manager_operate_auto_preset( - enum auto_shader_operation op, - const struct video_shader *shader, - const char *dir_video_shader, - const char *dir_menu_config, - enum auto_shader_type type, bool apply) -{ - char old_presets_directory[PATH_MAX_LENGTH]; - char config_directory[PATH_MAX_LENGTH]; - char tmp[PATH_MAX_LENGTH]; - char file[PATH_MAX_LENGTH]; - struct retro_system_info *system = runloop_get_libretro_system_info(); - const char *core_name = system ? system->library_name : NULL; - const char *auto_preset_dirs[3] = {0}; - - old_presets_directory[0] = config_directory[0] = tmp[0] = file[0] = '\0'; - - if (type != SHADER_PRESET_GLOBAL && string_is_empty(core_name)) - return false; - - if (!path_is_empty(RARCH_PATH_CONFIG)) - fill_pathname_basedir( - config_directory, - path_get(RARCH_PATH_CONFIG), - sizeof(config_directory)); - - /* We are only including this directory for compatibility purposes with - * versions 1.8.7 and older. */ - if (op != AUTO_SHADER_OP_SAVE && !string_is_empty(dir_video_shader)) - fill_pathname_join( - old_presets_directory, - dir_video_shader, - "presets", - sizeof(old_presets_directory)); - - auto_preset_dirs[0] = dir_menu_config; - auto_preset_dirs[1] = config_directory; - auto_preset_dirs[2] = old_presets_directory; - - switch (type) - { - case SHADER_PRESET_GLOBAL: - strlcpy(file, "global", sizeof(file)); - break; - case SHADER_PRESET_CORE: - fill_pathname_join(file, core_name, core_name, sizeof(file)); - break; - case SHADER_PRESET_PARENT: - fill_pathname_parent_dir_name(tmp, - path_get(RARCH_PATH_BASENAME), sizeof(tmp)); - fill_pathname_join(file, core_name, tmp, sizeof(file)); - break; - case SHADER_PRESET_GAME: - { - const char *game_name = - path_basename(path_get(RARCH_PATH_BASENAME)); - if (string_is_empty(game_name)) - return false; - fill_pathname_join(file, core_name, game_name, sizeof(file)); - break; - } - default: - return false; - } - - switch (op) - { - case AUTO_SHADER_OP_SAVE: - return menu_shader_manager_save_preset_internal( - shader, file, - dir_video_shader, - apply, true, - auto_preset_dirs, - ARRAY_SIZE(auto_preset_dirs)); - case AUTO_SHADER_OP_REMOVE: - { - /* remove all supported auto-shaders of given type */ - char *end; - size_t i, j, n, m; - - char preset_path[PATH_MAX_LENGTH]; - - /* n = amount of relevant shader presets found - * m = amount of successfully deleted shader presets */ - n = m = 0; - - for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++) - { - if (string_is_empty(auto_preset_dirs[i])) - continue; - - fill_pathname_join(preset_path, - auto_preset_dirs[i], file, sizeof(preset_path)); - end = preset_path + strlen(preset_path); - - for (j = 0; j < ARRAY_SIZE(shader_types); j++) - { - const char *preset_ext; - - if (!video_shader_is_supported(shader_types[j])) - continue; - - preset_ext = video_shader_get_preset_extension(shader_types[j]); - strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path)); - - if (path_is_valid(preset_path)) - { - n++; - - if (!filestream_delete(preset_path)) - { - m++; - RARCH_LOG("Deleted shader preset from %s.\n", preset_path); - } - else - RARCH_WARN("Failed to remove shader preset at %s.\n", preset_path); - } - } - } - - return n == m; - } - case AUTO_SHADER_OP_EXISTS: - { - /* test if any supported auto-shaders of given type exists */ - char *end; - size_t i, j; - - char preset_path[PATH_MAX_LENGTH]; - - for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++) - { - if (string_is_empty(auto_preset_dirs[i])) - continue; - - fill_pathname_join(preset_path, - auto_preset_dirs[i], file, sizeof(preset_path)); - end = preset_path + strlen(preset_path); - - for (j = 0; j < ARRAY_SIZE(shader_types); j++) - { - const char *preset_ext; - - if (!video_shader_is_supported(shader_types[j])) - continue; - - preset_ext = video_shader_get_preset_extension(shader_types[j]); - strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path)); - - if (path_is_valid(preset_path)) - return true; - } - } - } - break; - } - - return false; -} - -/** - * menu_shader_manager_save_auto_preset: - * @shader : shader to save - * @type : type of shader preset which determines save path - * @apply : immediately set preset after saving - * - * Save a shader as an auto-shader to it's appropriate path: - * SHADER_PRESET_GLOBAL: /global - * SHADER_PRESET_CORE: // - * SHADER_PRESET_PARENT: // - * SHADER_PRESET_GAME: // - * Needs to be consistent with retroarch_load_shader_preset() - * Auto-shaders will be saved as a reference if possible - **/ -bool menu_shader_manager_save_auto_preset( - const struct video_shader *shader, - enum auto_shader_type type, - const char *dir_video_shader, - const char *dir_menu_config, - bool apply) -{ - return menu_shader_manager_operate_auto_preset( - AUTO_SHADER_OP_SAVE, shader, - dir_video_shader, - dir_menu_config, - type, apply); -} - -/** - * menu_shader_manager_save_preset: - * @shader : shader to save - * @type : type of shader preset which determines save path - * @basename : basename of preset - * @apply : immediately set preset after saving - * - * Save a shader preset to disk. - **/ -bool menu_shader_manager_save_preset(const struct video_shader *shader, - const char *basename, - const char *dir_video_shader, - const char *dir_menu_config, - bool apply) -{ - char config_directory[PATH_MAX_LENGTH]; - const char *preset_dirs[3] = {0}; - - config_directory[0] = '\0'; - - if (!path_is_empty(RARCH_PATH_CONFIG)) - fill_pathname_basedir( - config_directory, - path_get(RARCH_PATH_CONFIG), - sizeof(config_directory)); - - preset_dirs[0] = dir_video_shader; - preset_dirs[1] = dir_menu_config; - preset_dirs[2] = config_directory; - - return menu_shader_manager_save_preset_internal( - shader, basename, - dir_video_shader, - apply, false, - preset_dirs, - ARRAY_SIZE(preset_dirs)); -} - -/** - * menu_shader_manager_remove_auto_preset: - * @type : type of shader preset to delete - * - * Deletes an auto-shader. - **/ -bool menu_shader_manager_remove_auto_preset( - enum auto_shader_type type, - const char *dir_video_shader, - const char *dir_menu_config) -{ - return menu_shader_manager_operate_auto_preset( - AUTO_SHADER_OP_REMOVE, NULL, - dir_video_shader, - dir_menu_config, - type, false); -} - -/** - * menu_shader_manager_auto_preset_exists: - * @type : type of shader preset - * - * Tests if an auto-shader of the given type exists. - **/ -bool menu_shader_manager_auto_preset_exists( - enum auto_shader_type type, - const char *dir_video_shader, - const char *dir_menu_config) -{ - return menu_shader_manager_operate_auto_preset( - AUTO_SHADER_OP_EXISTS, NULL, - dir_video_shader, - dir_menu_config, - type, false); -} - -int menu_shader_manager_clear_num_passes(struct video_shader *shader) -{ - bool refresh = false; - - if (!shader) - return 0; - - shader->passes = 0; - -#ifdef HAVE_MENU - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); -#endif - - video_shader_resolve_parameters(NULL, shader); - - shader->modified = true; - - return 0; -} - -int menu_shader_manager_clear_parameter(struct video_shader *shader, - unsigned i) -{ - struct video_shader_parameter *param = shader ? - &shader->parameters[i] : NULL; - - if (!param) - return 0; - - param->current = param->initial; - param->current = MIN(MAX(param->minimum, - param->current), param->maximum); - - shader->modified = true; - - return 0; -} - -int menu_shader_manager_clear_pass_filter(struct video_shader *shader, - unsigned i) -{ - struct video_shader_pass *shader_pass = shader ? - &shader->pass[i] : NULL; - - if (!shader_pass) - return -1; - - shader_pass->filter = RARCH_FILTER_UNSPEC; - - shader->modified = true; - - return 0; -} - -void menu_shader_manager_clear_pass_scale(struct video_shader *shader, - unsigned i) -{ - struct video_shader_pass *shader_pass = shader ? - &shader->pass[i] : NULL; - - if (!shader_pass) - return; - - shader_pass->fbo.scale_x = 0; - shader_pass->fbo.scale_y = 0; - shader_pass->fbo.valid = false; - - shader->modified = true; -} - -void menu_shader_manager_clear_pass_path(struct video_shader *shader, - unsigned i) -{ - struct video_shader_pass *shader_pass = shader ? - &shader->pass[i] : NULL; - - if (shader_pass) - *shader_pass->source.path = '\0'; - - shader->modified = true; -} - -/** - * menu_shader_manager_get_type: - * @shader : shader handle - * - * Gets type of shader. - * - * Returns: type of shader. - **/ -enum rarch_shader_type menu_shader_manager_get_type( - const struct video_shader *shader) -{ - enum rarch_shader_type type = RARCH_SHADER_NONE; - /* All shader types must be the same, or we cannot use it. */ - size_t i = 0; - - if (!shader) - return RARCH_SHADER_NONE; - - type = video_shader_parse_type(shader->path); - - if (!shader->passes) - return type; - - if (type == RARCH_SHADER_NONE) - { - type = video_shader_parse_type(shader->pass[0].source.path); - i = 1; - } - - for (; i < shader->passes; i++) - { - enum rarch_shader_type pass_type = - video_shader_parse_type(shader->pass[i].source.path); - - switch (pass_type) - { - case RARCH_SHADER_CG: - case RARCH_SHADER_GLSL: - case RARCH_SHADER_SLANG: - if (type != pass_type) - return RARCH_SHADER_NONE; - break; - default: - break; - } - } - - return type; -} - -/** - * menu_shader_manager_apply_changes: - * - * Apply shader state changes. - **/ -void menu_shader_manager_apply_changes( - struct video_shader *shader, - const char *dir_video_shader, - const char *dir_menu_config) -{ - enum rarch_shader_type type = RARCH_SHADER_NONE; - - if (!shader) - return; - - type = menu_shader_manager_get_type(shader); - - if (shader->passes && type != RARCH_SHADER_NONE) - { - menu_shader_manager_save_preset(shader, NULL, - dir_video_shader, dir_menu_config, true); - return; - } - - menu_shader_manager_set_preset(NULL, type, NULL, true); -} diff --git a/retroarch.c b/retroarch.c index 699a324d20..deeffde308 100644 --- a/retroarch.c +++ b/retroarch.c @@ -147,10 +147,11 @@ #include "menu/menu_input.h" #include "menu/widgets/menu_dialog.h" #include "menu/widgets/menu_input_bind_dialog.h" +#endif + #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) #include "menu/menu_shader.h" #endif -#endif #ifdef HAVE_GFX_WIDGETS #include "gfx/gfx_widgets.h" @@ -1473,6 +1474,13 @@ enum poll_type_override_t POLL_TYPE_OVERRIDE_LATE }; +enum auto_shader_operation +{ + AUTO_SHADER_OP_SAVE = 0, + AUTO_SHADER_OP_REMOVE, + AUTO_SHADER_OP_EXISTS +}; + typedef struct runloop_ctx_msg_info { const char *msg; @@ -2400,6 +2408,9 @@ struct rarch_state /* Used while Netplay is running */ netplay_t *netplay_data; #endif +#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) + struct video_shader *menu_driver_shader; +#endif }; static struct rarch_state rarch_st; @@ -6027,7 +6038,7 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) playlist_free_cached(); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) - menu_shader_manager_free(p_rarch->menu_driver_data); + menu_shader_manager_free(p_rarch); #endif #ifdef HAVE_NETWORKING core_updater_list_free_cached(); @@ -6351,6 +6362,735 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) } #endif +#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) +static enum rarch_shader_type shader_types[] = +{ + RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG +}; + +struct video_shader *menu_shader_get(void) +{ + struct rarch_state *p_rarch = &rarch_st; + if (video_shader_any_supported()) + if (p_rarch) + return p_rarch->menu_driver_shader; + return NULL; +} + +void menu_shader_manager_free(void *data) +{ + struct rarch_state *p_rarch = (struct rarch_state*)data; + if (p_rarch->menu_driver_shader) + free(p_rarch->menu_driver_shader); + p_rarch->menu_driver_shader = NULL; +} + +/** + * menu_shader_manager_init: + * + * Initializes shader manager. + **/ +bool menu_shader_manager_init(void) +{ + struct rarch_state *p_rarch = &rarch_st; + enum rarch_shader_type type = RARCH_SHADER_NONE; + bool ret = true; + bool is_preset = false; + const char *path_shader = NULL; + struct video_shader *menu_shader = NULL; + + /* We get the shader preset directly from the video driver, so that + * we are in sync with it (it could fail loading an auto-shader) + * If we can't (e.g. get_current_shader is not implemented), + * we'll load retroarch_get_shader_preset() like always */ + video_shader_ctx_t shader_info = {0}; + + video_shader_driver_get_current_shader(&shader_info); + + if (shader_info.data) + path_shader = shader_info.data->path; + else + path_shader = retroarch_get_shader_preset(); + + menu_shader_manager_free(p_rarch); + + menu_shader = (struct video_shader*) + calloc(1, sizeof(*menu_shader)); + + if (!menu_shader) + { + ret = false; + goto end; + } + + if (string_is_empty(path_shader)) + goto end; + + type = video_shader_get_type_from_ext(path_get_extension(path_shader), + &is_preset); + + if (!video_shader_is_supported(type)) + { + ret = false; + goto end; + } + + if (is_preset) + { + config_file_t *conf = NULL; + + conf = video_shader_read_preset(path_shader); + + if (!conf) + { + ret = false; + goto end; + } + + if (video_shader_read_conf_preset(conf, menu_shader)) + video_shader_resolve_parameters(conf, menu_shader); + + menu_shader->modified = false; + + config_file_free(conf); + } + else + { + strlcpy(menu_shader->pass[0].source.path, path_shader, + sizeof(menu_shader->pass[0].source.path)); + menu_shader->passes = 1; + } + +end: + p_rarch->menu_driver_shader = menu_shader; + command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); + return ret; +} + +/** + * menu_shader_manager_set_preset: + * @shader : Shader handle. + * @type : Type of shader. + * @preset_path : Preset path to load from. + * @apply : Whether to apply the shader or just update shader information + * + * Sets shader preset. + **/ +bool menu_shader_manager_set_preset(struct video_shader *shader, + enum rarch_shader_type type, const char *preset_path, bool apply) +{ + config_file_t *conf = NULL; + bool refresh = false; + bool ret = false; + + if (apply && !retroarch_apply_shader(type, preset_path, true)) + goto clear; + + if (string_is_empty(preset_path)) + { + ret = true; + goto clear; + } + + if (!shader) + { + ret = false; + goto end; + } + + /* Load stored Preset into menu on success. + * Used when a preset is directly loaded. + * No point in updating when the Preset was + * created from the menu itself. */ + if (!(conf = video_shader_read_preset(preset_path))) + { + ret = false; + goto end; + } + + RARCH_LOG("Setting Menu shader: %s.\n", preset_path); + + if (video_shader_read_conf_preset(conf, shader)) + video_shader_resolve_parameters(conf, shader); + + if (conf) + config_file_free(conf); + + ret = true; + +end: +#ifdef HAVE_MENU + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); +#endif + command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); + return ret; + +clear: + /* We don't want to disable shaders entirely here, + * just reset number of passes + * > Note: Disabling shaders at this point would in + * fact be dangerous, since it changes the number of + * entries in the shader options menu which can in + * turn lead to the menu selection pointer going out + * of bounds. This causes undefined behaviour/segfaults */ + menu_shader_manager_clear_num_passes(shader); + command_event(CMD_EVENT_SHADER_PRESET_LOADED, NULL); + return ret; +} + +static bool menu_shader_manager_save_preset_internal( + const struct video_shader *shader, const char *basename, + const char *dir_video_shader, + bool apply, bool save_reference, + const char **target_dirs, + size_t num_target_dirs) +{ + bool ret = false; + enum rarch_shader_type type = RARCH_SHADER_NONE; + char *preset_path = NULL; + size_t i = 0; + char fullname[PATH_MAX_LENGTH]; + char buffer[PATH_MAX_LENGTH]; + + fullname[0] = buffer[0] = '\0'; + + if (!shader || !shader->passes) + return false; + + type = menu_shader_manager_get_type(shader); + + if (type == RARCH_SHADER_NONE) + return false; + + if (shader->modified) + save_reference = false; + + if (!string_is_empty(basename)) + { + /* We are comparing against a fixed list of file + * extensions, the longest (slangp) being 6 characters + * in length. We therefore only need to extract the first + * 7 characters from the extension of the input path + * to correctly validate a match */ + char ext_lower[8]; + const char *ext = NULL; + + ext_lower[0] = '\0'; + + strlcpy(fullname, basename, sizeof(fullname)); + + /* Get file extension */ + ext = strrchr(basename, '.'); + + /* Copy and convert to lower case */ + if (ext && (*(++ext) != '\0')) + { + strlcpy(ext_lower, ext, sizeof(ext_lower)); + string_to_lower(ext_lower); + } + + /* Append extension automatically as appropriate. */ + if ( !string_is_equal(ext_lower, "cgp") + && !string_is_equal(ext_lower, "glslp") + && !string_is_equal(ext_lower, "slangp")) + { + const char *preset_ext = video_shader_get_preset_extension(type); + strlcat(fullname, preset_ext, sizeof(fullname)); + } + } + else + { + strlcpy(fullname, "retroarch", sizeof(fullname)); + strlcat(fullname, + video_shader_get_preset_extension(type), sizeof(fullname)); + } + + if (path_is_absolute(fullname)) + { + preset_path = fullname; + ret = video_shader_write_preset(preset_path, + dir_video_shader, + shader, save_reference); + + if (ret) + RARCH_LOG("Saved shader preset to %s.\n", preset_path); + else + RARCH_ERR("Failed writing shader preset to %s.\n", preset_path); + } + else + { + char basedir[PATH_MAX_LENGTH]; + + for (i = 0; i < num_target_dirs; i++) + { + if (string_is_empty(target_dirs[i])) + continue; + + fill_pathname_join(buffer, target_dirs[i], + fullname, sizeof(buffer)); + + strlcpy(basedir, buffer, sizeof(basedir)); + path_basedir(basedir); + + if (!path_is_directory(basedir)) + { + ret = path_mkdir(basedir); + + if (!ret) + { + RARCH_WARN("Failed to create preset directory %s.\n", basedir); + continue; + } + } + + preset_path = buffer; + + ret = video_shader_write_preset(preset_path, + dir_video_shader, + shader, save_reference); + + if (ret) + { + RARCH_LOG("Saved shader preset to %s.\n", preset_path); + break; + } + else + RARCH_WARN("Failed writing shader preset to %s.\n", preset_path); + } + + if (!ret) + RARCH_ERR("Failed to write shader preset. Make sure shader directory" + " and/or config directory are writable.\n"); + } + + if (ret && apply) + menu_shader_manager_set_preset(NULL, type, preset_path, true); + + return ret; +} + +static bool menu_shader_manager_operate_auto_preset( + enum auto_shader_operation op, + const struct video_shader *shader, + const char *dir_video_shader, + const char *dir_menu_config, + enum auto_shader_type type, bool apply) +{ + char old_presets_directory[PATH_MAX_LENGTH]; + char config_directory[PATH_MAX_LENGTH]; + char tmp[PATH_MAX_LENGTH]; + char file[PATH_MAX_LENGTH]; + struct retro_system_info *system = runloop_get_libretro_system_info(); + const char *core_name = system ? system->library_name : NULL; + const char *auto_preset_dirs[3] = {0}; + + old_presets_directory[0] = config_directory[0] = tmp[0] = file[0] = '\0'; + + if (type != SHADER_PRESET_GLOBAL && string_is_empty(core_name)) + return false; + + if (!path_is_empty(RARCH_PATH_CONFIG)) + fill_pathname_basedir( + config_directory, + path_get(RARCH_PATH_CONFIG), + sizeof(config_directory)); + + /* We are only including this directory for compatibility purposes with + * versions 1.8.7 and older. */ + if (op != AUTO_SHADER_OP_SAVE && !string_is_empty(dir_video_shader)) + fill_pathname_join( + old_presets_directory, + dir_video_shader, + "presets", + sizeof(old_presets_directory)); + + auto_preset_dirs[0] = dir_menu_config; + auto_preset_dirs[1] = config_directory; + auto_preset_dirs[2] = old_presets_directory; + + switch (type) + { + case SHADER_PRESET_GLOBAL: + strlcpy(file, "global", sizeof(file)); + break; + case SHADER_PRESET_CORE: + fill_pathname_join(file, core_name, core_name, sizeof(file)); + break; + case SHADER_PRESET_PARENT: + fill_pathname_parent_dir_name(tmp, + path_get(RARCH_PATH_BASENAME), sizeof(tmp)); + fill_pathname_join(file, core_name, tmp, sizeof(file)); + break; + case SHADER_PRESET_GAME: + { + const char *game_name = + path_basename(path_get(RARCH_PATH_BASENAME)); + if (string_is_empty(game_name)) + return false; + fill_pathname_join(file, core_name, game_name, sizeof(file)); + break; + } + default: + return false; + } + + switch (op) + { + case AUTO_SHADER_OP_SAVE: + return menu_shader_manager_save_preset_internal( + shader, file, + dir_video_shader, + apply, true, + auto_preset_dirs, + ARRAY_SIZE(auto_preset_dirs)); + case AUTO_SHADER_OP_REMOVE: + { + /* remove all supported auto-shaders of given type */ + char *end; + size_t i, j, n, m; + + char preset_path[PATH_MAX_LENGTH]; + + /* n = amount of relevant shader presets found + * m = amount of successfully deleted shader presets */ + n = m = 0; + + for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++) + { + if (string_is_empty(auto_preset_dirs[i])) + continue; + + fill_pathname_join(preset_path, + auto_preset_dirs[i], file, sizeof(preset_path)); + end = preset_path + strlen(preset_path); + + for (j = 0; j < ARRAY_SIZE(shader_types); j++) + { + const char *preset_ext; + + if (!video_shader_is_supported(shader_types[j])) + continue; + + preset_ext = video_shader_get_preset_extension(shader_types[j]); + strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path)); + + if (path_is_valid(preset_path)) + { + n++; + + if (!filestream_delete(preset_path)) + { + m++; + RARCH_LOG("Deleted shader preset from %s.\n", preset_path); + } + else + RARCH_WARN("Failed to remove shader preset at %s.\n", preset_path); + } + } + } + + return n == m; + } + case AUTO_SHADER_OP_EXISTS: + { + /* test if any supported auto-shaders of given type exists */ + char *end; + size_t i, j; + + char preset_path[PATH_MAX_LENGTH]; + + for (i = 0; i < ARRAY_SIZE(auto_preset_dirs); i++) + { + if (string_is_empty(auto_preset_dirs[i])) + continue; + + fill_pathname_join(preset_path, + auto_preset_dirs[i], file, sizeof(preset_path)); + end = preset_path + strlen(preset_path); + + for (j = 0; j < ARRAY_SIZE(shader_types); j++) + { + const char *preset_ext; + + if (!video_shader_is_supported(shader_types[j])) + continue; + + preset_ext = video_shader_get_preset_extension(shader_types[j]); + strlcpy(end, preset_ext, sizeof(preset_path) - (end - preset_path)); + + if (path_is_valid(preset_path)) + return true; + } + } + } + break; + } + + return false; +} + +/** + * menu_shader_manager_save_auto_preset: + * @shader : shader to save + * @type : type of shader preset which determines save path + * @apply : immediately set preset after saving + * + * Save a shader as an auto-shader to it's appropriate path: + * SHADER_PRESET_GLOBAL: /global + * SHADER_PRESET_CORE: // + * SHADER_PRESET_PARENT: // + * SHADER_PRESET_GAME: // + * Needs to be consistent with retroarch_load_shader_preset() + * Auto-shaders will be saved as a reference if possible + **/ +bool menu_shader_manager_save_auto_preset( + const struct video_shader *shader, + enum auto_shader_type type, + const char *dir_video_shader, + const char *dir_menu_config, + bool apply) +{ + return menu_shader_manager_operate_auto_preset( + AUTO_SHADER_OP_SAVE, shader, + dir_video_shader, + dir_menu_config, + type, apply); +} + +/** + * menu_shader_manager_save_preset: + * @shader : shader to save + * @type : type of shader preset which determines save path + * @basename : basename of preset + * @apply : immediately set preset after saving + * + * Save a shader preset to disk. + **/ +bool menu_shader_manager_save_preset(const struct video_shader *shader, + const char *basename, + const char *dir_video_shader, + const char *dir_menu_config, + bool apply) +{ + char config_directory[PATH_MAX_LENGTH]; + const char *preset_dirs[3] = {0}; + + config_directory[0] = '\0'; + + if (!path_is_empty(RARCH_PATH_CONFIG)) + fill_pathname_basedir( + config_directory, + path_get(RARCH_PATH_CONFIG), + sizeof(config_directory)); + + preset_dirs[0] = dir_video_shader; + preset_dirs[1] = dir_menu_config; + preset_dirs[2] = config_directory; + + return menu_shader_manager_save_preset_internal( + shader, basename, + dir_video_shader, + apply, false, + preset_dirs, + ARRAY_SIZE(preset_dirs)); +} + +/** + * menu_shader_manager_remove_auto_preset: + * @type : type of shader preset to delete + * + * Deletes an auto-shader. + **/ +bool menu_shader_manager_remove_auto_preset( + enum auto_shader_type type, + const char *dir_video_shader, + const char *dir_menu_config) +{ + return menu_shader_manager_operate_auto_preset( + AUTO_SHADER_OP_REMOVE, NULL, + dir_video_shader, + dir_menu_config, + type, false); +} + +/** + * menu_shader_manager_auto_preset_exists: + * @type : type of shader preset + * + * Tests if an auto-shader of the given type exists. + **/ +bool menu_shader_manager_auto_preset_exists( + enum auto_shader_type type, + const char *dir_video_shader, + const char *dir_menu_config) +{ + return menu_shader_manager_operate_auto_preset( + AUTO_SHADER_OP_EXISTS, NULL, + dir_video_shader, + dir_menu_config, + type, false); +} + +int menu_shader_manager_clear_num_passes(struct video_shader *shader) +{ + bool refresh = false; + + if (!shader) + return 0; + + shader->passes = 0; + +#ifdef HAVE_MENU + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); +#endif + + video_shader_resolve_parameters(NULL, shader); + + shader->modified = true; + + return 0; +} + +int menu_shader_manager_clear_parameter(struct video_shader *shader, + unsigned i) +{ + struct video_shader_parameter *param = shader ? + &shader->parameters[i] : NULL; + + if (!param) + return 0; + + param->current = param->initial; + param->current = MIN(MAX(param->minimum, + param->current), param->maximum); + + shader->modified = true; + + return 0; +} + +int menu_shader_manager_clear_pass_filter(struct video_shader *shader, + unsigned i) +{ + struct video_shader_pass *shader_pass = shader ? + &shader->pass[i] : NULL; + + if (!shader_pass) + return -1; + + shader_pass->filter = RARCH_FILTER_UNSPEC; + + shader->modified = true; + + return 0; +} + +void menu_shader_manager_clear_pass_scale(struct video_shader *shader, + unsigned i) +{ + struct video_shader_pass *shader_pass = shader ? + &shader->pass[i] : NULL; + + if (!shader_pass) + return; + + shader_pass->fbo.scale_x = 0; + shader_pass->fbo.scale_y = 0; + shader_pass->fbo.valid = false; + + shader->modified = true; +} + +void menu_shader_manager_clear_pass_path(struct video_shader *shader, + unsigned i) +{ + struct video_shader_pass *shader_pass = shader ? + &shader->pass[i] : NULL; + + if (shader_pass) + *shader_pass->source.path = '\0'; + + shader->modified = true; +} + +/** + * menu_shader_manager_get_type: + * @shader : shader handle + * + * Gets type of shader. + * + * Returns: type of shader. + **/ +enum rarch_shader_type menu_shader_manager_get_type( + const struct video_shader *shader) +{ + enum rarch_shader_type type = RARCH_SHADER_NONE; + /* All shader types must be the same, or we cannot use it. */ + size_t i = 0; + + if (!shader) + return RARCH_SHADER_NONE; + + type = video_shader_parse_type(shader->path); + + if (!shader->passes) + return type; + + if (type == RARCH_SHADER_NONE) + { + type = video_shader_parse_type(shader->pass[0].source.path); + i = 1; + } + + for (; i < shader->passes; i++) + { + enum rarch_shader_type pass_type = + video_shader_parse_type(shader->pass[i].source.path); + + switch (pass_type) + { + case RARCH_SHADER_CG: + case RARCH_SHADER_GLSL: + case RARCH_SHADER_SLANG: + if (type != pass_type) + return RARCH_SHADER_NONE; + break; + default: + break; + } + } + + return type; +} + +/** + * menu_shader_manager_apply_changes: + * + * Apply shader state changes. + **/ +void menu_shader_manager_apply_changes( + struct video_shader *shader, + const char *dir_video_shader, + const char *dir_menu_config) +{ + enum rarch_shader_type type = RARCH_SHADER_NONE; + + if (!shader) + return; + + type = menu_shader_manager_get_type(shader); + + if (shader->passes && type != RARCH_SHADER_NONE) + { + menu_shader_manager_save_preset(shader, NULL, + dir_video_shader, dir_menu_config, true); + return; + } + + menu_shader_manager_set_preset(NULL, type, NULL, true); +} +#endif + #ifdef HAVE_DISCORD bool discord_is_ready(void) { @@ -21007,8 +21747,8 @@ static void input_driver_poll(void) { #ifdef HAVE_OVERLAY input_overlay_t *overlay_pointer = (input_overlay_t*)p_rarch->overlay_ptr; -#endif bool poll_overlay = (p_rarch->overlay_ptr && p_rarch->overlay_ptr->alive); +#endif input_mapper_t *handle = p_rarch->input_driver_mapper; const input_device_driver_t *joypad_driver = input_driver_get_joypad_driver();