diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index a0a691dea3..cf552a5348 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -99,6 +99,39 @@ static void fill_pathname_expanded_and_absolute(char *out_path, pathname_conform_slashes_to_os(out_path); } +static void gather_reference_path_list(struct path_linked_list *in_path_linked_list, + char *path, + int reference_depth) +{ + config_file_t *conf = NULL; + struct path_linked_list *reference_tmp = NULL; + + if (reference_depth > SHADER_MAX_REFERENCE_DEPTH) + return; + + conf = config_file_new_from_path_to_string(path); + if (conf) + { + reference_tmp = (struct path_linked_list*)conf->references; + while (reference_tmp) + { + char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH); + + fill_pathname_expanded_and_absolute(reference_preset_path, conf->path, reference_tmp->path); + gather_reference_path_list(in_path_linked_list, reference_preset_path, reference_depth + 1); + + free(reference_preset_path); + reference_tmp = reference_tmp->next; + } + path_linked_list_add_path(in_path_linked_list, path); + } + else + { + RARCH_WARN("\n [Shaders]: No Preset located at \"%s\".\n", path); + } + config_file_free(conf); +} + /** * wrap_mode_to_str: * @type : Wrap type. @@ -851,6 +884,17 @@ end: return ret; } +/* Check if the config is a valid shader chain config */ +static bool video_shader_is_shader_chain_config(config_file_t *conf) +{ + /* If the config has a shaders entry then it is considered + a shader chain config, vs a config which may only have + parameter values and texture overrides + */ + + return config_get_entry(conf, "shaders"); +} + static config_file_t *video_shader_get_root_preset_config(const char *path) { int reference_depth = 1; @@ -863,7 +907,7 @@ static config_file_t *video_shader_get_root_preset_config(const char *path) return NULL; } - while (conf->reference) + while (conf->references) { /* If we have reached the max depth of nested references, * stop attempting to read the next reference, @@ -882,7 +926,7 @@ static config_file_t *video_shader_get_root_preset_config(const char *path) } /* Get the absolute path for the reference */ - fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->reference); + fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->references->path); /* Create a new config from the referenced path */ config_file_free(conf); @@ -900,6 +944,7 @@ static config_file_t *video_shader_get_root_preset_config(const char *path) } free(nested_reference_path); + return conf; } @@ -950,7 +995,7 @@ static bool video_shader_check_reference_chain_for_save( { int reference_depth = 1; - while (conf->reference) + while (conf->references) { /* If we have reached the max depth of nested references stop attempting to read * the next reference because we are likely in a self referential loop. */ @@ -963,7 +1008,7 @@ static bool video_shader_check_reference_chain_for_save( } /* Get the absolute path for the reference */ - fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->reference); + fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->references->path); /* If one of the reference paths is the same as the file we want to save then this reference chain would be * self-referential / cyclical and we can't save this as a simple preset*/ @@ -1106,11 +1151,11 @@ static bool video_shader_write_referenced_preset( * If there is a reference in the initially loaded preset, * we should check it against the preset path we are currently * trying to save */ - if (reference_conf->reference) + if (reference_conf->references) { /* Get the absolute path for the reference */ fill_pathname_expanded_and_absolute(abs_temp_reference_path, - reference_conf->path, reference_conf->reference); + reference_conf->path, reference_conf->references->path); pathname_conform_slashes_to_os(abs_temp_reference_path); @@ -1142,16 +1187,16 @@ static bool video_shader_write_referenced_preset( /* If the reference path is the same as the path we want to save * or the reference path is in the config (auto shader) folder */ - if ( string_is_equal(path_to_reference, path_to_save_conformed) + if (string_is_equal(path_to_reference, path_to_save_conformed) || !strncmp(config_dir, path_to_reference, strlen(config_dir))) { /* If the config from the reference path has a reference in it, * we will use this same nested reference for the new preset */ - if (reference_conf->reference) + if (reference_conf->references) { /* Get the absolute path for the reference */ fill_pathname_expanded_and_absolute(path_to_reference, - reference_conf->path, reference_conf->reference); + reference_conf->path, reference_conf->references->path); /* If the reference path is also the same as what * we are trying to save @@ -1168,11 +1213,11 @@ static bool video_shader_write_referenced_preset( path_to_reference); /* If the reference also has a reference inside it */ - if (reference_conf->reference) + if (reference_conf->references) { /* Get the absolute path for the reference */ fill_pathname_expanded_and_absolute(path_to_reference, - reference_conf->path, reference_conf->reference); + reference_conf->path, reference_conf->references->path); } /* If the config referenced is a full preset */ else @@ -1232,7 +1277,7 @@ static bool video_shader_write_referenced_preset( pathname_make_slashes_portable(relative_temp_reference_path); /* Add the reference path to the config */ - config_file_set_reference_path(conf, path_to_reference); + config_file_add_reference(conf, path_to_reference); /* Set modified to true so when you run config_file_write * it will save a file */ @@ -1715,6 +1760,7 @@ bool video_shader_write_preset(const char *path, } + /** * video_shader_load_preset_into_shader: * @path : Path to preset file, could be a @@ -1731,117 +1777,124 @@ bool video_shader_load_preset_into_shader(const char *path, { unsigned i = 0; bool ret = true; - char override_conf_paths[SHADER_MAX_REFERENCE_DEPTH][PATH_MAX_LENGTH]; config_file_t *conf = NULL; - /* Get the root config, If we were able to get a root_config - * that means the reference chain is valid */ - config_file_t *root_conf = - video_shader_get_root_preset_config(path); + config_file_t *root_conf = video_shader_get_root_preset_config(path); + struct path_linked_list* override_paths_list = NULL; + struct path_linked_list* path_list_tmp = NULL; if (!root_conf) { -#ifdef DEBUG RARCH_LOG("\n"); RARCH_WARN("[Shaders]: Could not read root preset: \"%s\".\n", path); -#endif ret = false; goto end; } - /* If we were able to get a root_config that means that the - * whole reference chain is valid */ -#ifdef DEBUG - RARCH_DBG("\n"); -#endif - - video_shader_load_root_config_into_shader(root_conf, - config_get_ptr(), shader); - /* If the root_conf path matches the original path then - * there are no references so we just load it and go to the end */ - if (string_is_equal(root_conf->path, path)) + /* Check if the root preset is a valid shader chain */ + if (!video_shader_is_shader_chain_config(root_conf)) + { + RARCH_LOG("\n"); + RARCH_WARN("[Shaders]: Root preset is not a valid shader chain because it has no shaders entry: \"%s\".\n", path); + ret = false; goto end; + } + + /* If the root_conf path matches the original path then + * there are no references so we just load it and go to the end */ + if (string_is_equal(root_conf->path, path)) + { + /* Load the config from the shader chain from the first reference into the shader */ + video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader); + goto end; + } /* Get the config from the initial preset file * We don't need to check it's validity because it must * have been valid to get the root preset */ conf = config_file_new_from_path_to_string(path); - /* Set all override_conf_paths to empty so we know which - * ones have been filled */ - for (i = 0; i < SHADER_MAX_REFERENCE_DEPTH; i++) - override_conf_paths[i][0] = '\0'; - - i = 0; - #ifdef DEBUG - RARCH_DBG("\n"); - RARCH_DBG("[Shaders]: Crawl preset reference chain..\n"); + RARCH_DBG("\n[Shaders]: Crawl preset reference chain..\n"); #endif - /* If the config has a reference then we need gather all presets from the - * chain of references to apply their values later */ - while (conf->reference) + /** + * Check references starting with the second to make sure + * they do not have a shader chains in them + **/ + path_list_tmp = (struct path_linked_list*)conf->references->next; + while (path_list_tmp) { - char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH); - i++; + config_file_t *tmp_conf = NULL; + char *path_to_reference = (char*)malloc(PATH_MAX_LENGTH); -#ifdef DEBUG - RARCH_DBG("[Shaders]: Preset (depth %u): \"%s\".\n", i, conf->path); -#endif + fill_pathname_expanded_and_absolute(path_to_reference, conf->path, path_list_tmp->path); - /* Add the reference to the list */ - strlcpy(override_conf_paths[i], conf->path, PATH_MAX_LENGTH); - - /* Get the absolute path for the reference */ - fill_pathname_expanded_and_absolute(reference_preset_path, - conf->path, conf->reference); - -#ifdef DEBUG - RARCH_DBG("[Shaders]: #reference = \"%s\".\n", - reference_preset_path); -#endif - - /* Create a new config from this reference level */ - config_file_free(conf); - conf = config_file_new_from_path_to_string(reference_preset_path); - - free(reference_preset_path); + tmp_conf = video_shader_get_root_preset_config(path_to_reference); + if (tmp_conf) + { + if (video_shader_is_shader_chain_config(tmp_conf)) + { + RARCH_WARN("\n[Shaders]: Additional #reference entries pointing at shader chain presets are not supported: \"%s\".\n", path_to_reference); + config_file_free(tmp_conf); + ret = false; + goto end; + } + else + { + config_file_free(tmp_conf); + } + } + else + { + RARCH_WARN("\n[Shaders]: Could not load root preset for #reference entry: \"%s\".\n", path_to_reference); + ret = false; + goto end; + } + path_list_tmp = path_list_tmp->next; } - - /* Step back through the references starting with the one - * referencing the root config and apply overrides for each one */ + + /* Load the config from the shader chain from the first reference into the shader */ + video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader); + + /* Set Path for originally loaded preset because it is different than the root preset path */ + strlcpy(shader->loaded_preset_path, path, sizeof(shader->loaded_preset_path)); + #ifdef DEBUG - RARCH_DBG("\n"); - RARCH_DBG("[Shaders]: Start applying simple preset overrides..\n"); + RARCH_DBG("\n[Shaders]: Start applying simple preset overrides..\n"); #endif - while (i) + /* Gather all the paths of all of the presets in all reference chains */ + override_paths_list = path_linked_list_new(); + gather_reference_path_list(override_paths_list, conf->path, 0); + + /* + * Step through the references and apply overrides for each one + * Start on the second item since the first is empty + */ + path_list_tmp = (struct path_linked_list*)override_paths_list; + while (path_list_tmp) { - config_file_t *override_conf = config_file_new_from_path_to_string( - override_conf_paths[i]); + config_file_t *override_conf = NULL; + + override_conf = config_file_new_from_path_to_string(path_list_tmp->path); #ifdef DEBUG RARCH_DBG("[Shaders]: Depth %u apply overrides..\n", i); - RARCH_DBG("[Shaders]: Apply values from: \"%s\".\n", - override_conf->path); + RARCH_DBG("[Shaders]: Apply values from: \"%s\".\n", override_conf->path); #endif + override_shader_values(override_conf, shader); - config_file_free(override_conf); - i--; + path_list_tmp = path_list_tmp->next; } - + #ifdef DEBUG - RARCH_DBG("[Shaders]: End apply overrides.\n"); - RARCH_DBG("\n"); + RARCH_DBG("[Shaders]: End apply overrides.\n\n"); #endif - /* Set Path for originally loaded preset because it is - * different than the root preset path */ - strlcpy( shader->loaded_preset_path, path, - sizeof(shader->loaded_preset_path)); end: + path_linked_list_free(override_paths_list); config_file_free(conf); config_file_free(root_conf); diff --git a/libretro-common/file/config_file.c b/libretro-common/file/config_file.c index 507091a815..de9da1f9f2 100644 --- a/libretro-common/file/config_file.c +++ b/libretro-common/file/config_file.c @@ -39,12 +39,6 @@ #define MAX_INCLUDE_DEPTH 16 -struct config_include_list -{ - char *path; - struct config_include_list *next; -}; - /* Forward declaration */ static bool config_file_parse_line(config_file_t *conf, struct config_entry_list *list, char *line, config_file_cb_t *cb); @@ -383,29 +377,26 @@ static void config_file_get_realpath(char *s, size_t len, static void config_file_add_sub_conf(config_file_t *conf, char *path, char *real_path, size_t len, config_file_cb_t *cb) { - struct config_include_list *head = conf->includes; - struct config_include_list *node = (struct config_include_list*) - malloc(sizeof(*node)); + if (!conf->includes) + conf->includes = path_linked_list_new(); - if (node) - { - node->next = NULL; - /* Add include list */ - node->path = strdup(path); + path_linked_list_add_path(conf->includes, path); - if (head) - { - while (head->next) - head = head->next; + config_file_get_realpath(real_path, len, path, conf->path); +} - head->next = node; - } - else - conf->includes = node; - } +void config_file_add_reference(config_file_t *conf, char *path) +{ + /* It is expected that the conf has it's path already set */ + char short_path[PATH_MAX_LENGTH]; + + short_path[0] = '\0'; + + if (!conf->references) + conf->references = path_linked_list_new(); - config_file_get_realpath(real_path, len, path, - conf->path); + fill_pathname_abbreviated_or_relative(short_path, conf->path, path, sizeof(short_path)); + path_linked_list_add_path(conf->references, short_path); } static int config_file_load_internal( @@ -581,7 +572,7 @@ static bool config_file_parse_line(config_file_t *conf, if (!path) return false; - config_file_set_reference_path(conf, path); + config_file_add_reference(conf, path); if (!path) return false; @@ -702,31 +693,11 @@ static int config_file_from_string_internal( return 0; } -void config_file_set_reference_path(config_file_t *conf, char *path) -{ - /* It is expected that the conf has it's path already set */ - - char short_path[PATH_MAX_LENGTH]; - - short_path[0] = '\0'; - - if (!conf) - return; - - if (conf->reference) - { - free(conf->reference); - conf->reference = NULL; - } - - fill_pathname_abbreviated_or_relative(short_path, conf->path, path, sizeof(short_path)); - - conf->reference = strdup(short_path); -} bool config_file_deinitialize(config_file_t *conf) { - struct config_include_list *inc_tmp = NULL; + struct path_linked_list *inc_tmp = NULL; + struct path_linked_list *ref_tmp = NULL; struct config_entry_list *tmp = NULL; if (!conf) return false; @@ -750,20 +721,8 @@ bool config_file_deinitialize(config_file_t *conf) free(hold); } - inc_tmp = (struct config_include_list*)conf->includes; - while (inc_tmp) - { - struct config_include_list *hold = NULL; - if (inc_tmp->path) - free(inc_tmp->path); - hold = (struct config_include_list*)inc_tmp; - inc_tmp = inc_tmp->next; - if (hold) - free(hold); - } - - if (conf->reference) - free(conf->reference); + path_linked_list_free(conf->includes); + path_linked_list_free(conf->references); if (conf->path) free(conf->path); @@ -905,7 +864,7 @@ void config_file_initialize(struct config_file *conf) conf->entries = NULL; conf->tail = NULL; conf->last = NULL; - conf->reference = NULL; + conf->references = NULL; conf->includes = NULL; conf->include_depth = 0; conf->guaranteed_no_duplicates = false; @@ -1362,12 +1321,14 @@ bool config_file_write(config_file_t *conf, const char *path, bool sort) void config_file_dump(config_file_t *conf, FILE *file, bool sort) { struct config_entry_list *list = NULL; - struct config_include_list *includes = conf->includes; + struct path_linked_list *inc_tmp = conf->includes; + struct path_linked_list *ref_tmp = conf->references; - if (conf->reference) + while (ref_tmp) { - pathname_make_slashes_portable(conf->reference); - fprintf(file, "#reference \"%s\"\n", conf->reference); + pathname_make_slashes_portable(ref_tmp->path); + fprintf(file, "#reference \"%s\"\n", ref_tmp->path); + ref_tmp = ref_tmp->next; } if (sort) @@ -1392,10 +1353,10 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort) * '#include' directives must go *after* individual * config entries, otherwise they will override * any custom-set values */ - while (includes) + while (inc_tmp) { - fprintf(file, "#include \"%s\"\n", includes->path); - includes = includes->next; + fprintf(file, "#include \"%s\"\n", inc_tmp->path); + inc_tmp = inc_tmp->next; } } diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 320c5a2daa..36c20f1b09 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -70,6 +70,76 @@ #endif +/** + * Create a new linked list with one node in it + * The path on this node will be set to NULL +**/ +struct path_linked_list* path_linked_list_new() +{ + struct path_linked_list* paths_list = (struct path_linked_list*)malloc(sizeof(*paths_list)); + paths_list->next = NULL; + paths_list->path = NULL; + return paths_list; +} + +/* Free the entire linked list */ +bool path_linked_list_free(struct path_linked_list *in_path_linked_list) +{ + struct path_linked_list *node_tmp = NULL; + + node_tmp = (struct path_linked_list*)in_path_linked_list; + while (node_tmp) + { + struct path_linked_list *hold = NULL; + if (node_tmp->path) + free(node_tmp->path); + hold = (struct path_linked_list*)node_tmp; + node_tmp = node_tmp->next; + if (hold) + free(hold); + } + + return true; +} + +/** + * Add a node to the linked list with this path + * If the first node's path if it's not yet set the path + * on this node instead +**/ +void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path) +{ + /* If the first item does not have a path this is + a list which has just been created, so we just fill + the path for the first item + */ + if (!in_path_linked_list->path) + { + in_path_linked_list->path = strdup(path); + } + else + { + struct path_linked_list *head = in_path_linked_list; + struct path_linked_list *node = (struct path_linked_list*) malloc(sizeof(*node)); + + if (node) + { + node->next = NULL; + node->path = strdup(path); + + if (head) + { + while (head->next) + head = head->next; + + head->next = node; + } + else + in_path_linked_list = node; + } + } +} + /** * path_get_archive_delim: * @path : path diff --git a/libretro-common/include/file/config_file.h b/libretro-common/include/file/config_file.h index 014d5ba722..61ed615cc0 100644 --- a/libretro-common/include/file/config_file.h +++ b/libretro-common/include/file/config_file.h @@ -54,12 +54,12 @@ RETRO_BEGIN_DECLS struct config_file { char *path; - char *reference; struct config_entry_list **entries_map; struct config_entry_list *entries; struct config_entry_list *tail; struct config_entry_list *last; - struct config_include_list *includes; + struct path_linked_list *includes; + struct path_linked_list *references; unsigned include_depth; bool guaranteed_no_duplicates; bool modified; @@ -92,6 +92,8 @@ config_file_t *config_file_new_alloc(void); void config_file_initialize(struct config_file *conf); +void config_file_add_reference(config_file_t *conf, char *path); + /* Loads a config file. Returns NULL if file doesn't exist. * NULL path will create an empty config file. * Includes cb callbacks to run custom code during config file processing.*/ @@ -109,8 +111,6 @@ config_file_t *config_file_new_from_path_to_string(const char *path); /* Frees config file. */ void config_file_free(config_file_t *conf); -void config_file_set_reference_path(config_file_t *conf, char *path); - bool config_file_deinitialize(config_file_t *conf); /* Loads a new config, and appends its data to conf. diff --git a/libretro-common/include/file/file_path.h b/libretro-common/include/file/file_path.h index 452763fed2..4b54dc42d1 100644 --- a/libretro-common/include/file/file_path.h +++ b/libretro-common/include/file/file_path.h @@ -51,6 +51,28 @@ enum RARCH_FILE_UNSUPPORTED }; +struct path_linked_list +{ + char *path; + struct path_linked_list *next; +}; + +/** + * Create a new linked list with one item in it + * The path on this item will be set to NULL +**/ +struct path_linked_list* path_linked_list_new(); + +/* Free the entire linked list */ +bool path_linked_list_free(struct path_linked_list *in_path_linked_list); + +/** + * Add a node to the linked list with this path + * If the first node's path if it's not yet set, + * set this instead +**/ +void path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path); + /** * path_is_compressed_file: * @path : path