From 0c526b6498de61f0bcfb19ceb03bf57419ab6ec4 Mon Sep 17 00:00:00 2001 From: HyperspaceMadness Date: Sat, 26 Dec 2020 21:09:27 -0500 Subject: [PATCH] Shaders Load Refactor and Fix Referenced Texture Loading Partial update to work with shaders directly More Edits More changes more shader fixes More Fixes Compiling, reference load still wrong Added Feedback & things are working Logging Fixes Log Fix More Fixes Added Feedback Logging Fixes for file pathing in Linux Fix GLCore and Crash in QT Saving Code Cleanup Removed Unused Function filepath.c Code Cleanup --- gfx/common/metal_common.m | 11 +- gfx/drivers/d3d10.c | 9 +- gfx/drivers/d3d11.c | 9 +- gfx/drivers/d3d12.c | 9 +- gfx/drivers/d3d9.c | 14 +- gfx/drivers/gl.c | 4 +- gfx/drivers/gx2_gfx.c | 12 +- gfx/drivers_shader/shader_gl_cg.c | 17 +- gfx/drivers_shader/shader_gl_core.cpp | 23 +- gfx/drivers_shader/shader_glsl.c | 19 +- gfx/drivers_shader/shader_vulkan.cpp | 26 +- gfx/video_shader_parse.c | 1670 +++++++++++----------- gfx/video_shader_parse.h | 113 +- libretro-common/file/config_file.c | 19 +- libretro-common/file/file_path.c | 94 ++ libretro-common/include/file/file_path.h | 6 + menu/cbs/menu_cbs_left.c | 2 +- menu/cbs/menu_cbs_ok.c | 4 +- menu/cbs/menu_cbs_right.c | 2 +- retroarch.c | 28 +- ui/drivers/qt/shaderparamsdialog.cpp | 2 +- 21 files changed, 1022 insertions(+), 1071 deletions(-) diff --git a/gfx/common/metal_common.m b/gfx/common/metal_common.m index f2d4ac35df..e8637fbf32 100644 --- a/gfx/common/metal_common.m +++ b/gfx/common/metal_common.m @@ -1219,7 +1219,6 @@ typedef struct MTLALIGN(16) [self _freeVideoShader:_shader]; _shader = nil; - config_file_t *conf = video_shader_read_preset(path.UTF8String); struct video_shader *shader = (struct video_shader *)calloc(1, sizeof(*shader)); settings_t *settings = config_get_ptr(); const char *dir_video_shader = settings->paths.directory_video_shader; @@ -1229,7 +1228,7 @@ typedef struct MTLALIGN(16) { unsigned i; texture_t *source = NULL; - if (!video_shader_read_conf_preset(conf, shader)) + if (!video_shader_load_preset_into_shader(path.UTF8String, shader)) return NO; source = &_engine.frame.texture[0]; @@ -1429,8 +1428,6 @@ typedef struct MTLALIGN(16) /* TODO(sgc): generate mip maps */ image_texture_free(&image); } - - video_shader_resolve_current_parameters(conf, shader); _shader = shader; shader = nil; } @@ -1440,12 +1437,6 @@ typedef struct MTLALIGN(16) { [self _freeVideoShader:shader]; } - - if (conf) - { - config_file_free(conf); - conf = nil; - } } resize_render_targets = YES; diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index d7f97b75ec..4d95dcce05 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -336,7 +336,6 @@ static bool d3d10_gfx_set_shader(void* data, enum rarch_shader_type type, const { #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) unsigned i; - config_file_t* conf = NULL; d3d10_texture_t* source = NULL; d3d10_video_t* d3d10 = (d3d10_video_t*)data; @@ -355,12 +354,9 @@ static bool d3d10_gfx_set_shader(void* data, enum rarch_shader_type type, const return false; } - if (!(conf = video_shader_read_preset(path))) - return false; - d3d10->shader_preset = (struct video_shader*)calloc(1, sizeof(*d3d10->shader_preset)); - if (!video_shader_read_conf_preset(conf, d3d10->shader_preset)) + if (!video_shader_load_preset_into_shader(path, d3d10->shader_preset)) goto error; source = &d3d10->frame.texture[0]; @@ -508,9 +504,6 @@ static bool d3d10_gfx_set_shader(void* data, enum rarch_shader_type type, const image_texture_free(&image); } - video_shader_resolve_current_parameters(conf, d3d10->shader_preset); - config_file_free(conf); - d3d10->resize_render_targets = true; d3d10->init_history = true; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 8b6ee3ad1d..19620b0f66 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -359,7 +359,6 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const { #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) unsigned i; - config_file_t* conf = NULL; d3d11_texture_t* source = NULL; d3d11_video_t* d3d11 = (d3d11_video_t*)data; @@ -378,12 +377,9 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const return false; } - if (!(conf = video_shader_read_preset(path))) - return false; - d3d11->shader_preset = (struct video_shader*)calloc(1, sizeof(*d3d11->shader_preset)); - if (!video_shader_read_conf_preset(conf, d3d11->shader_preset)) + if (!video_shader_load_preset_into_shader(path, d3d11->shader_preset)) goto error; source = &d3d11->frame.texture[0]; @@ -529,9 +525,6 @@ static bool d3d11_gfx_set_shader(void* data, enum rarch_shader_type type, const image_texture_free(&image); } - video_shader_resolve_current_parameters(conf, d3d11->shader_preset); - config_file_free(conf); - d3d11->resize_render_targets = true; d3d11->init_history = true; diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 806241b58f..b1b0210a63 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -343,7 +343,6 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const { #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) unsigned i; - config_file_t* conf = NULL; d3d12_texture_t* source = NULL; d3d12_video_t* d3d12 = (d3d12_video_t*)data; @@ -362,12 +361,9 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const return false; } - if (!(conf = video_shader_read_preset(path))) - return false; - d3d12->shader_preset = (struct video_shader*)calloc(1, sizeof(*d3d12->shader_preset)); - if (!video_shader_read_conf_preset(conf, d3d12->shader_preset)) + if (!video_shader_load_preset_into_shader(path, d3d12->shader_preset)) goto error; source = &d3d12->frame.texture[0]; @@ -535,9 +531,6 @@ static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const image_texture_free(&image); } - video_shader_resolve_current_parameters(conf, d3d12->shader_preset); - config_file_free(conf); - d3d12->resize_render_targets = true; d3d12->init_history = true; diff --git a/gfx/drivers/d3d9.c b/gfx/drivers/d3d9.c index f05e74d56d..6f43460fce 100644 --- a/gfx/drivers/d3d9.c +++ b/gfx/drivers/d3d9.c @@ -324,25 +324,15 @@ static bool d3d9_init_multipass(d3d9_video_t *d3d, const char *shader_path) unsigned i; bool use_extra_pass = false; struct video_shader_pass *pass = NULL; - config_file_t *conf = video_shader_read_preset(shader_path); - - if (!conf) - { - RARCH_ERR("[D3D9]: Failed to load preset.\n"); - return false; - } memset(&d3d->shader, 0, sizeof(d3d->shader)); - if (!video_shader_read_conf_preset(conf, &d3d->shader)) + if (!video_shader_load_preset_into_shader(shader_path, &d3d->shader)) { - config_file_free(conf); RARCH_ERR("[D3D9]: Failed to parse shader preset.\n"); return false; } - config_file_free(conf); - RARCH_LOG("[D3D9]: Found %u shaders.\n", d3d->shader.passes); for (i = 0; i < d3d->shader.passes; i++) @@ -1732,7 +1722,7 @@ static bool d3d9_set_shader(void *data, if (type != supported_shader_type) { RARCH_WARN("[D3D9]: Shader preset %s is using unsupported shader type %s, falling back to stock %s.\n", - path, video_shader_to_str(type), video_shader_to_str(supported_shader_type)); + path, video_shader_type_to_str(type), video_shader_type_to_str(supported_shader_type)); break; } diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 346dce5555..4bee995ac1 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -2041,7 +2041,7 @@ static bool gl2_shader_init(gl_t *gl, const gfx_ctx_driver_t *ctx_driver, { if (!string_is_empty(shader_path)) RARCH_WARN("[GL] Shader preset %s is using unsupported shader type %s, falling back to stock %s.\n", - shader_path, video_shader_to_str(parse_type), video_shader_to_str(type)); + shader_path, video_shader_type_to_str(parse_type), video_shader_type_to_str(type)); shader_path = NULL; } @@ -4089,7 +4089,7 @@ static bool gl2_set_shader(void *data, if (type != fallback) { RARCH_ERR("[GL]: %s shader not supported, falling back to stock %s\n", - video_shader_to_str(type), video_shader_to_str(fallback)); + video_shader_type_to_str(type), video_shader_type_to_str(fallback)); path = NULL; } diff --git a/gfx/drivers/gx2_gfx.c b/gfx/drivers/gx2_gfx.c index 834caec0fe..88c3125c47 100644 --- a/gfx/drivers/gx2_gfx.c +++ b/gfx/drivers/gx2_gfx.c @@ -1428,7 +1428,6 @@ static bool wiiu_gfx_set_shader(void *data, enum rarch_shader_type type, const char *path) { unsigned i; - config_file_t *conf = NULL; wiiu_video_t *wiiu = (wiiu_video_t *)data; if (!wiiu) @@ -1446,24 +1445,15 @@ static bool wiiu_gfx_set_shader(void *data, return false; } - if (!(conf = video_shader_read_preset(path))) - return false; - wiiu->shader_preset = calloc(1, sizeof(*wiiu->shader_preset)); - if (!video_shader_read_conf_preset(conf, wiiu->shader_preset)) + if (!video_shader_load_preset_into_shader(path, wiiu->shader_preset)) { free(wiiu->shader_preset); wiiu->shader_preset = NULL; return false; } - for (i = 0; i < wiiu->shader_preset->passes; i++) - slang_preprocess_parse_parameters(wiiu->shader_preset->pass[i].source.path, wiiu->shader_preset); - - video_shader_resolve_current_parameters(conf, wiiu->shader_preset); - config_file_free(conf); - for (i = 0; i < wiiu->shader_preset->passes; i++) { unsigned j; diff --git a/gfx/drivers_shader/shader_gl_cg.c b/gfx/drivers_shader/shader_gl_cg.c index e8f06f74e0..429fbcff2a 100644 --- a/gfx/drivers_shader/shader_gl_cg.c +++ b/gfx/drivers_shader/shader_gl_cg.c @@ -664,7 +664,8 @@ static bool gl_cg_load_plain(void *data, const char *path) return false; } - video_shader_resolve_parameters(NULL, cg->shader); + video_shader_resolve_parameters(cg->shader); + video_shader_load_current_parameter_values(NULL, cg->shader); return true; } @@ -688,37 +689,25 @@ static bool gl_cg_load_shader(void *data, unsigned i) static bool gl_cg_load_preset(void *data, const char *path) { unsigned i; - config_file_t *conf = NULL; cg_shader_data_t *cg = (cg_shader_data_t*)data; if (!gl_cg_load_stock(cg)) return false; RARCH_LOG("[CG]: Loading Cg meta-shader: %s\n", path); - conf = video_shader_read_preset(path); - if (!conf) - { - RARCH_ERR("Failed to load preset.\n"); - return false; - } cg->shader = (struct video_shader*)calloc(1, sizeof(*cg->shader)); if (!cg->shader) { - config_file_free(conf); return false; } - if (!video_shader_read_conf_preset(conf, cg->shader)) + if (!video_shader_load_preset_into_shader(path, cg->shader)) { RARCH_ERR("Failed to parse CGP file.\n"); - config_file_free(conf); return false; } - video_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", diff --git a/gfx/drivers_shader/shader_gl_core.cpp b/gfx/drivers_shader/shader_gl_core.cpp index a8baa5ce89..ca6f8cd286 100644 --- a/gfx/drivers_shader/shader_gl_core.cpp +++ b/gfx/drivers_shader/shader_gl_core.cpp @@ -2158,20 +2158,13 @@ gl_core_filter_chain_t *gl_core_filter_chain_create_from_preset( const char *path, glslang_filter_chain_filter filter) { unsigned i; - config_file_t *conf = NULL; unique_ptr shader{ new video_shader() }; if (!shader) return nullptr; - if (!(conf = video_shader_read_preset(path))) + if (!video_shader_load_preset_into_shader(path, shader.get())) return nullptr; - if (!video_shader_read_conf_preset(conf, shader.get())) - { - config_file_free(conf); - return nullptr; - } - bool last_pass_is_fbo = shader->pass[shader->passes - 1].fbo.valid; unique_ptr chain{ new gl_core_filter_chain(shader->passes + (last_pass_is_fbo ? 1 : 0)) }; @@ -2203,7 +2196,7 @@ gl_core_filter_chain_t *gl_core_filter_chain_create_from_preset( if (!glslang_compile_shader(pass->source.path, &output)) { - RARCH_ERR("Failed to compile shader: \"%s\".\n", + RARCH_ERR("[GLCore]: Failed to compile shader: \"%s\".\n", pass->source.path); goto error; } @@ -2212,7 +2205,7 @@ gl_core_filter_chain_t *gl_core_filter_chain_create_from_preset( { if (shader->num_parameters >= GFX_MAX_PARAMETERS) { - RARCH_ERR("[GLCore]: Exceeded maximum number of parameters.\n"); + RARCH_ERR("[GLCore]: Exceeded maximum number of parameters (%u).\n", GFX_MAX_PARAMETERS); goto error; } @@ -2243,11 +2236,6 @@ gl_core_filter_chain_t *gl_core_filter_chain_create_from_preset( video_shader_parameter *param = &shader->parameters[shader->num_parameters]; strlcpy(param->id, meta_param.id.c_str(), sizeof(param->id)); strlcpy(param->desc, meta_param.desc.c_str(), sizeof(param->desc)); - param->current = meta_param.initial; - param->initial = meta_param.initial; - param->minimum = meta_param.minimum; - param->maximum = meta_param.maximum; - param->step = meta_param.step; chain->add_parameter(i, shader->num_parameters, meta_param.id); shader->num_parameters++; } @@ -2415,19 +2403,14 @@ gl_core_filter_chain_t *gl_core_filter_chain_create_from_preset( sizeof(gl_core_shader::opaque_frag) / sizeof(uint32_t)); } - if (!video_shader_resolve_current_parameters(conf, shader.get())) - goto error; - chain->set_shader_preset(move(shader)); if (!chain->init()) goto error; - config_file_free(conf); return chain.release(); error: - config_file_free(conf); return nullptr; } diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 9f4b7756cd..28b5135bbb 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -856,7 +856,6 @@ static void *gl_glsl_init(void *data, const char *path) #ifdef GLSL_DEBUG char *error_string = NULL; #endif - config_file_t *conf = NULL; const char *stock_vertex = NULL; const char *stock_fragment = NULL; glsl_shader_data_t *glsl = (glsl_shader_data_t*) @@ -910,12 +909,8 @@ static void *gl_glsl_init(void *data, const char *path) if (is_preset) { - conf = video_shader_read_preset(path); - if (conf) - { - ret = video_shader_read_conf_preset(conf, glsl->shader); - glsl->shader->modern = true; - } + ret = video_shader_load_preset_into_shader(path, glsl->shader); + glsl->shader->modern = true; } else { @@ -944,14 +939,6 @@ static void *gl_glsl_init(void *data, const char *path) } } - video_shader_resolve_parameters(conf, glsl->shader); - - if (conf) - { - config_file_free(conf); - conf = NULL; - } - stock_vertex = (glsl->shader->modern) ? stock_vertex_modern : stock_vertex_legacy; stock_fragment = (glsl->shader->modern) ? @@ -1067,8 +1054,6 @@ static void *gl_glsl_init(void *data, const char *path) error: gl_glsl_destroy_resources(glsl); - if (conf) - config_file_free(conf); if (glsl) free(glsl); diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index 72c4dae5a8..d349c5a821 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -2565,19 +2565,13 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( const char *path, glslang_filter_chain_filter filter) { unsigned i; - config_file_t *conf = NULL; unique_ptr shader{ new video_shader() }; + if (!shader) return nullptr; - if (!(conf = video_shader_read_preset(path))) - return nullptr; - - if (!video_shader_read_conf_preset(conf, shader.get())) - { - config_file_free(conf); - return nullptr; - } + if (!video_shader_load_preset_into_shader(path, shader.get())) + return nullptr; bool last_pass_is_fbo = shader->pass[shader->passes - 1].fbo.valid; auto tmpinfo = *info; @@ -2612,7 +2606,7 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( if (!glslang_compile_shader(pass->source.path, &output)) { - RARCH_ERR("Failed to compile shader: \"%s\".\n", + RARCH_ERR("[Vulkan]: Failed to compile shader: \"%s\".\n", pass->source.path); goto error; } @@ -2621,7 +2615,7 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( { if (shader->num_parameters >= GFX_MAX_PARAMETERS) { - RARCH_ERR("[Vulkan]: Exceeded maximum number of parameters.\n"); + RARCH_ERR("[Vulkan]: Exceeded maximum number of parameters (%u).\n", GFX_MAX_PARAMETERS); goto error; } @@ -2652,11 +2646,6 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( video_shader_parameter *param = &shader->parameters[shader->num_parameters]; strlcpy(param->id, meta_param.id.c_str(), sizeof(param->id)); strlcpy(param->desc, meta_param.desc.c_str(), sizeof(param->desc)); - param->current = meta_param.initial; - param->initial = meta_param.initial; - param->minimum = meta_param.minimum; - param->maximum = meta_param.maximum; - param->step = meta_param.step; chain->add_parameter(i, shader->num_parameters, meta_param.id); shader->num_parameters++; } @@ -2820,19 +2809,14 @@ vulkan_filter_chain_t *vulkan_filter_chain_create_from_preset( sizeof(opaque_frag) / sizeof(uint32_t)); } - if (!video_shader_resolve_current_parameters(conf, shader.get())) - goto error; - chain->set_shader_preset(move(shader)); if (!chain->init()) goto error; - config_file_free(conf); return chain.release(); error: - config_file_free(conf); return nullptr; } diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index 11159f61a4..37743a9704 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -43,9 +43,42 @@ #include "drivers_shader/slang_process.h" #endif +/* Maximum depth of chain of referenced shader presets. + * 16 seems to be a very large number of references at the moment. */ +#define SHADER_MAX_REFERENCE_DEPTH 16 + /* TODO/FIXME - global state - perhaps move outside this file */ static path_change_data_t *file_change_data = NULL; +/** + * fill_pathname_expanded_and_absolute: + * @out_path : string to write into + * @in_refpath : used to get the base path if in_path is relative + * @in_path : path to turn into an absolute path + * + * Takes a path and returns an absolute path, + * It will expand it if the path was using the root path format e.g. :\shaders + * If the path was relative it will take this path and get the absolute path using in_refpath + * as the path to extract a base path + * + * out_path is filled with the absolute path + **/ +void fill_pathname_expanded_and_absolute(char *out_path, const char *in_refpath, const char *in_path) +{ + char expanded_path[PATH_MAX_LENGTH]; + + expanded_path[0] = '\0'; + + /* Expand paths which start with :\ to an absolute path */ + fill_pathname_expand_special(expanded_path, in_path, sizeof(expanded_path)); + + /* Resolve the reference path relative to the config */ + if (path_is_absolute(expanded_path)) + strlcpy(out_path, expanded_path, PATH_MAX_LENGTH); + else + fill_pathname_resolve_relative(out_path, in_refpath, in_path, PATH_MAX_LENGTH); +} + /** * wrap_mode_to_str: * @type : Wrap type. @@ -108,8 +141,7 @@ static enum gfx_wrap_type wrap_str_to_mode(const char *wrap_mode) * * Returns: true (1) if successful, otherwise false (0). **/ -static bool video_shader_parse_pass(config_file_t *conf, - struct video_shader_pass *pass, unsigned i) +static bool video_shader_parse_pass(config_file_t *conf, struct video_shader_pass *pass, unsigned i) { char shader_name[64]; char filter_name_buf[64]; @@ -125,12 +157,11 @@ static bool video_shader_parse_pass(config_file_t *conf, char scale_type_x[64]; char scale_type_y[64]; char tmp_path[PATH_MAX_LENGTH]; - struct gfx_fbo_scale *scale = NULL; - bool tmp_bool = false; - float fattr = 0.0f; - int iattr = 0; - struct config_entry_list - *entry = NULL; + struct gfx_fbo_scale *scale = NULL; + bool tmp_bool = false; + float fattr = 0.0f; + int iattr = 0; + struct config_entry_list *entry = NULL; fp_fbo_buf[0] = mipmap_buf[0] = alias_buf[0] = scale_name_buf[0] = attr_name_buf[0] = scale_type[0] = @@ -146,8 +177,8 @@ static bool video_shader_parse_pass(config_file_t *conf, return false; } - fill_pathname_resolve_relative(pass->source.path, - conf->path, tmp_path, sizeof(pass->source.path)); + /* Get the absolute path */ + fill_pathname_expanded_and_absolute(pass->source.path, conf->path, tmp_path); /* Smooth */ snprintf(filter_name_buf, sizeof(filter_name_buf), "filter_linear%u", i); @@ -161,18 +192,14 @@ static bool video_shader_parse_pass(config_file_t *conf, pass->filter = RARCH_FILTER_UNSPEC; /* Wrapping mode */ - snprintf(wrap_name_buf, - sizeof(wrap_name_buf), "wrap_mode%u", i); - if ((entry = config_get_entry(conf, wrap_name_buf)) - && !string_is_empty(entry->value)) + snprintf(wrap_name_buf, sizeof(wrap_name_buf), "wrap_mode%u", i); + if ((entry = config_get_entry(conf, wrap_name_buf)) && !string_is_empty(entry->value)) pass->wrap = wrap_str_to_mode(entry->value); entry = NULL; /* Frame count mod */ - snprintf(frame_count_mod_buf, - sizeof(frame_count_mod_buf), "frame_count_mod%u", i); - if ((entry = config_get_entry(conf, frame_count_mod_buf)) - && !string_is_empty(entry->value)) + snprintf(frame_count_mod_buf, sizeof(frame_count_mod_buf), "frame_count_mod%u", i); + if ((entry = config_get_entry(conf, frame_count_mod_buf)) && !string_is_empty(entry->value)) pass->frame_count_mod = (unsigned)strtoul(entry->value, NULL, 0); entry = NULL; @@ -311,18 +338,19 @@ static bool video_shader_parse_pass(config_file_t *conf, * * Returns: true (1) if successful, otherwise false (0). **/ -static bool video_shader_parse_textures(config_file_t *conf, - struct video_shader *shader) +static bool video_shader_parse_textures(config_file_t *conf, struct video_shader *shader) { size_t path_size = PATH_MAX_LENGTH; const char *id = NULL; char *save = NULL; char *textures = (char*)malloc(1024 + path_size); + char texture_path[PATH_MAX_LENGTH]; if (!textures) return false; textures[0] = '\0'; + texture_path[0] = '\0'; if (!config_get_array(conf, "textures", textures, 1024)) { @@ -352,8 +380,11 @@ static bool video_shader_parse_textures(config_file_t *conf, return false; } - fill_pathname_resolve_relative(shader->lut[shader->luts].path, - conf->path, entry->value, sizeof(shader->lut[shader->luts].path)); + config_get_path(conf, id, texture_path, sizeof(texture_path)); + + /* Get the absolute path */ + fill_pathname_expanded_and_absolute(shader->lut[shader->luts].path, conf->path, texture_path); + entry = NULL; strlcpy(shader->lut[shader->luts].id, id, @@ -362,15 +393,13 @@ static bool video_shader_parse_textures(config_file_t *conf, strlcpy(id_filter, id, sizeof(id_filter)); strlcat(id_filter, "_linear", sizeof(id_filter)); if (config_get_bool(conf, id_filter, &smooth)) - shader->lut[shader->luts].filter = smooth ? - RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST; + shader->lut[shader->luts].filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST; else shader->lut[shader->luts].filter = RARCH_FILTER_UNSPEC; strlcpy(id_wrap, id, sizeof(id_wrap)); strlcat(id_wrap, "_wrap_mode", sizeof(id_wrap)); - if ((entry = config_get_entry(conf, id_wrap)) - && !string_is_empty(entry->value)) + if ((entry = config_get_entry(conf, id_wrap)) && !string_is_empty(entry->value)) shader->lut[shader->luts].wrap = wrap_str_to_mode(entry->value); entry = NULL; @@ -396,9 +425,8 @@ static bool video_shader_parse_textures(config_file_t *conf, * * Returns: handle to shader parameter if successful, otherwise NULL. **/ -static struct video_shader_parameter *video_shader_parse_find_parameter( - struct video_shader_parameter *params, - unsigned num_params, const char *id) +static struct video_shader_parameter *video_shader_parse_find_parameter(struct video_shader_parameter *params, + unsigned num_params, const char *id) { unsigned i; @@ -411,64 +439,17 @@ static struct video_shader_parameter *video_shader_parse_find_parameter( return NULL; } -/** - * video_shader_set_current_parameters: - * @conf : Preset file to read from. - * @shader : Shader passes handle. - * - * For each parameter in the shader, if a value is set in the config file - * load this value to the parameter's current value. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -bool video_shader_resolve_current_parameters(config_file_t *conf, - struct video_shader *shader) -{ - unsigned i; - const struct config_entry_list *entry = NULL; - - if (!conf) - return false; - - /* For all parameters in the shader see if there is any config value set */ - for (i = 0; i < shader->num_parameters; i++) - { - entry = config_get_entry(conf, shader->parameters[i].id); - - /* Only try to load the parameter value if an entry exists in the config */ - if (entry) - { - struct video_shader_parameter *parameter = - (struct video_shader_parameter*) - video_shader_parse_find_parameter( - shader->parameters, shader->num_parameters, shader->parameters[i].id); - - if (config_get_float(conf, shader->parameters[i].id, ¶meter->current)) - RARCH_LOG("[ Shaders - Load Parameter Values]: %s = %f.\n", - shader->parameters[i].id, parameter->current); - else - RARCH_WARN("[ Shaders - Load Parameter Values]: Name %s is set in preset " - "but couldn't load its value.\n", shader->parameters[i].id); - } - } - - return true; -} - /** * video_shader_resolve_parameters: * @conf : Preset file to read from. * @shader : Shader passes handle. * - * Resolves all shader parameters belonging to shaders. - * Fills the parameter definition list of the shader - * then calls video_shader_resolve_current_parameters to - * read in the config parameter values + * Resolves all shader parameters belonging to shaders + * from the #pragma parameter lines in the shader for each pass. * * Returns: true (1) if successful, otherwise false (0). **/ -bool video_shader_resolve_parameters(config_file_t *conf, - struct video_shader *shader) +bool video_shader_resolve_parameters(struct video_shader *shader) { unsigned i; struct video_shader_parameter *param = &shader->parameters[0]; @@ -477,6 +458,8 @@ bool video_shader_resolve_parameters(config_file_t *conf, /* Find all parameters in our shaders. */ + RARCH_LOG("[ Shaders ]: Finding Parameters in Shader Passes (#pragma parameter)\n"); + for (i = 0; i < shader->passes; i++) { const char *path = shader->pass[i].source.path; @@ -492,18 +475,15 @@ bool video_shader_resolve_parameters(config_file_t *conf, if (!path_is_valid(path)) continue; +/* First try to use the more robust slang implementation to support #includes. */ #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) - /* First try to use the more robust slang - * implementation to support #includes. */ /* FIXME: The check for slang can be removed - * if it's sufficiently tested for - * GLSL/Cg as well, it should be the same implementation. */ - if (string_is_equal(path_get_extension(path), "slang") && - slang_preprocess_parse_parameters(path, shader)) - continue; + * if it's sufficiently tested for GLSL/Cg as well, it should be the same implementation. + * The problem with switching currently is that it looks for a #version string in the + * first line of the file which glsl doesn't have */ - /* If that doesn't work, fallback to the old path. - * Ideally, we'd get rid of this path sooner or later. */ + if (string_is_equal(path_get_extension(path), "slang") && slang_preprocess_parse_parameters(path, shader)) + continue; #endif /* Read file contents */ @@ -527,22 +507,20 @@ bool video_shader_resolve_parameters(config_file_t *conf, /* even though the pass is set in the loop too, not all passes have parameters */ param->pass = i; - while ((shader->num_parameters < ARRAY_SIZE(shader->parameters)) && - (line_index < lines.size)) + while ((shader->num_parameters < ARRAY_SIZE(shader->parameters)) && (line_index < lines.size)) { int ret; const char *line = lines.elems[line_index].data; line_index++; /* Check if this is a '#pragma parameter' line */ - if (strncmp("#pragma parameter", line, - STRLEN_CONST("#pragma parameter"))) + if (strncmp("#pragma parameter", line, STRLEN_CONST("#pragma parameter"))) continue; /* Parse line */ ret = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", - param->id, param->desc, ¶m->initial, - ¶m->minimum, ¶m->maximum, ¶m->step); + param->id, param->desc, ¶m->initial, + ¶m->minimum, ¶m->maximum, ¶m->step); if (ret < 5) continue; @@ -555,7 +533,7 @@ bool video_shader_resolve_parameters(config_file_t *conf, param->pass = i; - RARCH_LOG("[ Shaders ]: Found #pragma parameter %s (%s) %f %f %f %f in pass %d\n", + RARCH_LOG("[ Shaders ]: Found #pragma parameter %s (%s) %f %f %f %f in pass %d\n", param->desc, param->id, param->initial, param->minimum, param->maximum, param->step, param->pass); param->current = param->initial; @@ -567,19 +545,329 @@ bool video_shader_resolve_parameters(config_file_t *conf, string_list_deinitialize(&lines); } - return video_shader_resolve_current_parameters(conf, shader); + return true; } -#ifdef _WIN32 -static void make_relative_path_portable(char* path) + +/** + * video_shader_load_current_parameter_values: + * @conf : Preset file to read from. + * @shader : Shader passes handle. + * + * For each parameter in the shader, if a value is set in the config file + * load this value to the parameter's current value. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool video_shader_load_current_parameter_values(config_file_t *conf, struct video_shader *shader) { - /* use '/' instead of '\' for maximum portability */ - char* p; - for (p = path; *p; p++) - if (*p == '\\') - *p = '/'; + unsigned i; + bool load_parameter_message_shown = false; + const struct config_entry_list *entry = NULL; + + if (!conf) + { + RARCH_ERR("[ Shaders ]: Load Parameter Values - Config is Null.\n"); + return false; + } + + /* For all parameters in the shader see if there is any config value set */ + for (i = 0; i < shader->num_parameters; i++) + { + entry = config_get_entry(conf, shader->parameters[i].id); + + /* Only try to load the parameter value if an entry exists in the config */ + if (entry) + { + struct video_shader_parameter *parameter = (struct video_shader_parameter*) + video_shader_parse_find_parameter(shader->parameters, + shader->num_parameters, + shader->parameters[i].id); + /* Log the message for loading parameter values only once*/ + if (!load_parameter_message_shown) + { + RARCH_LOG("[ Shaders ]: Loading base parameter values\n"); + load_parameter_message_shown = true; + } + + /* Log each parameter read */ + if (config_get_float(conf, shader->parameters[i].id, ¶meter->current)) + RARCH_LOG("[ Shaders ]: Load parameter value: %s = %f.\n", shader->parameters[i].id, parameter->current); + else + RARCH_WARN("[ Shaders ]: Load parameter value: name %s is set in preset but couldn't load its value.\n", + shader->parameters[i].id); + } + } + + return true; +} + +static const char *scale_type_to_str(enum gfx_scale_type type) +{ + switch (type) + { + case RARCH_SCALE_INPUT: + return "source"; + case RARCH_SCALE_VIEWPORT: + return "viewport"; + case RARCH_SCALE_ABSOLUTE: + return "absolute"; + default: + break; + } + + return "?"; +} + +static void shader_write_scale_dim(config_file_t *conf, + const char *dim, + enum gfx_scale_type type, + float scale, + unsigned absolute, + unsigned i) +{ + char key[64]; + + key[0] = '\0'; + + snprintf(key, sizeof(key), "scale_type_%s%u", dim, i); + config_set_string(conf, key, scale_type_to_str(type)); + + snprintf(key, sizeof(key), "scale_%s%u", dim, i); + if (type == RARCH_SCALE_ABSOLUTE) + config_set_int(conf, key, absolute); + else + config_set_float(conf, key, scale); +} + +static void shader_write_fbo(config_file_t *conf, const struct gfx_fbo_scale *fbo, unsigned i) +{ + char key[64]; + + key[0] = '\0'; + + snprintf(key, sizeof(key), "float_framebuffer%u", i); + config_set_bool(conf, key, fbo->fp_fbo); + snprintf(key, sizeof(key), "srgb_framebuffer%u", i); + config_set_bool(conf, key, fbo->srgb_fbo); + + if (!fbo->valid) + return; + + shader_write_scale_dim(conf, "x", fbo->type_x, fbo->scale_x, fbo->abs_x, i); + shader_write_scale_dim(conf, "y", fbo->type_y, fbo->scale_y, fbo->abs_y, i); +} + +/** + * video_shader_write_root_preset: + * @conf : Preset file to write to. + * @shader : Shader passes handle. + * @preset_path : Optional path to where the preset will be written. + * + * Writes preset and all associated state (passes, textures, imports, etc) into @conf. + * If @preset_path is not NULL, shader paths are saved relative to it. + **/ +bool video_shader_write_root_preset(const struct video_shader *shader, const char *path) +{ + bool ret = true; + unsigned i; + char key[64]; + size_t tmp_size = PATH_MAX_LENGTH; + char *tmp = (char*)malloc(3*tmp_size); + char *tmp_rel = tmp + tmp_size; + char *tmp_base = tmp + 2*tmp_size; + config_file_t *conf = NULL; + + if (!path) + { + ret = false; + goto end; + } + + if (!(conf = config_file_new_alloc())) + { + ret = false; + goto end; + } + + if (!tmp) + { + ret = false; + goto end; + } + + RARCH_LOG("[ Shaders ]: Saving FULL PRESET to: %s\n", path); + + config_set_int(conf, "shaders", shader->passes); + if (shader->feedback_pass >= 0) + config_set_int(conf, "feedback_pass", shader->feedback_pass); + + strlcpy(tmp_base, path, tmp_size); + + /* ensure we use a clean base like the shader passes and texture paths do */ + path_resolve_realpath(tmp_base, tmp_size, false); + path_basedir(tmp_base); + + for (i = 0; i < shader->passes; i++) + { + const struct video_shader_pass *pass = &shader->pass[i]; + + snprintf(key, sizeof(key), "shader%u", i); + + strlcpy(tmp, pass->source.path, tmp_size); + path_relative_to(tmp_rel, tmp, tmp_base, tmp_size); + + pathname_make_slashes_portable(tmp_rel); + + config_set_path(conf, key, tmp_rel); + + + if (pass->filter != RARCH_FILTER_UNSPEC) + { + snprintf(key, sizeof(key), "filter_linear%u", i); + config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR); + } + + snprintf(key, sizeof(key), "wrap_mode%u", i); + config_set_string(conf, key, wrap_mode_to_str(pass->wrap)); + + if (pass->frame_count_mod) + { + snprintf(key, sizeof(key), "frame_count_mod%u", i); + config_set_int(conf, key, pass->frame_count_mod); + } + + snprintf(key, sizeof(key), "mipmap_input%u", i); + config_set_bool(conf, key, pass->mipmap); + + snprintf(key, sizeof(key), "alias%u", i); + config_set_string(conf, key, pass->alias); + + shader_write_fbo(conf, &pass->fbo, i); + } + + /* Write shader parameters which are different than the default shader values */ + if (shader->num_parameters) + for (i = 0; i < shader->num_parameters; i++) + if (shader->parameters[i].current != shader->parameters[i].initial) + config_set_float(conf, shader->parameters[i].id, shader->parameters[i].current); + + if (shader->luts) + { + char textures[4096]; + + textures[0] = '\0'; + + /* Names of the textures */ + strlcpy(textures, shader->lut[0].id, sizeof(textures)); + + for (i = 1; i < shader->luts; i++) + { + /* O(n^2), but number of textures is very limited. */ + strlcat(textures, ";", sizeof(textures)); + strlcat(textures, shader->lut[i].id, sizeof(textures)); + } + + config_set_string(conf, "textures", textures); + + /* Step through the textures in the shader */ + for (i = 0; i < shader->luts; i++) + { + fill_pathname_abbreviated_or_relative(tmp_rel, tmp_base, shader->lut[i].path, PATH_MAX_LENGTH); + pathname_make_slashes_portable(tmp_rel); + config_set_string(conf, shader->lut[i].id, tmp_rel); + + /* Linear filter ON or OFF */ + if (shader->lut[i].filter != RARCH_FILTER_UNSPEC) + { + char key[128]; + key[0] = '\0'; + strlcpy(key, shader->lut[i].id, sizeof(key)); + strlcat(key, "_linear", sizeof(key)); + config_set_bool(conf, key, shader->lut[i].filter == RARCH_FILTER_LINEAR); + } + + /* Wrap Mode */ + { + char key[128]; + key[0] = '\0'; + strlcpy(key, shader->lut[i].id, sizeof(key)); + strlcat(key, "_wrap_mode", sizeof(key)); + config_set_string(conf, key, wrap_mode_to_str(shader->lut[i].wrap)); + } + + /* Mipmap On or Off */ + { + char key[128]; + key[0] = '\0'; + strlcpy(key, shader->lut[i].id, sizeof(key)); + strlcat(key, "_mipmap", sizeof(key)); + config_set_bool(conf, key, shader->lut[i].mipmap); + } + } + } + + /* Write the File! */ + ret = config_file_write(conf, path, false); + + end: + + config_file_free(conf); + free(tmp); + + return ret; +} + + +config_file_t *video_shader_get_root_preset_config(const char *path) +{ + config_file_t *conf = config_file_new_from_path_to_string(path); + char* nested_reference_path = (char*)malloc(PATH_MAX_LENGTH); + + if (!conf) + goto end; + else + { + int reference_depth = 1; + + while (conf->reference) + { + /* 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. + * SHADER_MAX_REFERENCE_DEPTH references deep seems like more than enough depth for expected usage */ + if (reference_depth > SHADER_MAX_REFERENCE_DEPTH) + { + RARCH_ERR("[ Shaders - Get Root Preset ]: Exceeded maximum reference depth(%u) without finding a full preset. " + "This chain of referenced presets is likely cyclical.\n", SHADER_MAX_REFERENCE_DEPTH); + config_file_free(conf); + conf = NULL; + goto end; + } + + /* Get the absolute path for the reference */ + fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->reference); + + /* Create a new config from the referenced path */ + config_file_free(conf); + conf = config_file_new_from_path_to_string(nested_reference_path); + + /* If we can't read the reference preset */ + if (!conf) + { + RARCH_WARN("[ Shaders ]: Could not read shader preset in #reference line: %s\n", nested_reference_path); + goto end; + } + + reference_depth += 1; + } + } + + end: + + free(nested_reference_path); + + return conf; } -#endif /** * video_shader_check_reference_chain: @@ -615,6 +903,7 @@ bool video_shader_check_reference_chain_for_save(const char *path_to_save, const if (!conf) { + RARCH_ERR("[ Shaders ]: Could not read the #reference preset: %s\n", reference_path); return_val = false; } else @@ -624,32 +913,23 @@ bool video_shader_check_reference_chain_for_save(const char *path_to_save, const while (conf->reference) { /* 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. - * 16 references deep seems like more than enough depth for expected usage */ - if (reference_depth > 16) + * the next reference because we are likely in a self referential loop. */ + if (reference_depth > SHADER_MAX_REFERENCE_DEPTH) { - RARCH_ERR("[ Shaders - Save Simple Preset ]: Exceeded maximum reference " - "depth(16) without finding a full preset. " - "This chain of referenced presets is likely cyclical.\n"); + RARCH_ERR("[ Shaders - Check Reference Chain for Save]: Exceeded maximum reference depth(%u) without " + "finding a full preset. This chain of referenced presets is likely cyclical.\n", SHADER_MAX_REFERENCE_DEPTH); return_val = false; break; } - /* Resolve the reference path relative to the config */ - if (path_is_absolute(conf->reference)) - strlcpy(nested_reference_path, conf->reference, PATH_MAX_LENGTH); - else - fill_pathname_resolve_relative(nested_reference_path, - conf->path, - conf->reference, - PATH_MAX_LENGTH); + /* Get the absolute path for the reference */ + fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->reference); - /* 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*/ + /* 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*/ if (string_is_equal(nested_reference_path, path_to_save)) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving preset:\n" + RARCH_WARN("[ Shaders ]: Saving preset:\n" " %s\n" " With a #reference of:\n" " %s\n" @@ -669,8 +949,8 @@ bool video_shader_check_reference_chain_for_save(const char *path_to_save, const /* If we can't read the reference preset */ if (!conf) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Could not read shader preset " - "in #reference line: %s\n", nested_reference_path); + RARCH_WARN("[ Shaders ]: Could not read shader preset in #reference line: %s\n", + nested_reference_path); return_val = false; break; } @@ -696,7 +976,6 @@ bool video_shader_check_reference_chain_for_save(const char *path_to_save, const * as it's first line to specify a root preset and can also include parameter * and texture values to override the values of the root preset * Returns false if a referenced preset cannot be saved - * See: video_shader_read_preset **/ bool video_shader_write_referenced_preset(const char *path, const char *shader_dir, @@ -705,6 +984,7 @@ bool video_shader_write_referenced_preset(const char *path, unsigned i; config_file_t *conf = NULL; config_file_t *reference_conf = NULL; + struct video_shader *referenced_shader = (struct video_shader*) calloc(1, sizeof(*referenced_shader)); bool ret = false; bool continue_saving_reference = true; char *new_preset_basedir = strdup(path); @@ -722,28 +1002,22 @@ bool video_shader_write_referenced_preset(const char *path, /* Get the retroarch config dir where the automatically loaded presets are located * and where Save Game Preset, Save Core Preset, Save Global Preset save to */ - fill_pathname_application_special(config_dir, - PATH_MAX_LENGTH, - APPLICATION_SPECIAL_DIRECTORY_CONFIG); + fill_pathname_application_special(config_dir, PATH_MAX_LENGTH, APPLICATION_SPECIAL_DIRECTORY_CONFIG); /* If there is no initial preset path loaded */ if (!shader->loaded_preset_path) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because the " - "loaded Shader does not have a path to a previously loaded preset " - "file on disk.\n"); - continue_saving_reference = false; - goto end; + RARCH_WARN("[ Shaders ]: Saving Full Preset because the loaded Shader does not have " + "a path to a previously loaded preset file on disk.\n"); + goto end; } /* If the initial preset loaded is the ever-changing retroarch preset don't save a reference - * TODO remove once we don't write this preset anymore */ + * TODO remove once we don't write this preset anymore */ if (!strncmp(path_basename(shader->loaded_preset_path), "retroarch", STRLEN_CONST("retroarch"))) { - continue_saving_reference = false; - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because we can't " - "save a reference to the ever-changing retroarch preset.\n"); - continue_saving_reference = false; + RARCH_WARN("[ Shaders ]: Saving Full Preset because we can't save a reference to the " + "ever-changing retroarch preset.\n"); goto end; } @@ -755,10 +1029,8 @@ bool video_shader_write_referenced_preset(const char *path, /* If the original preset can't be loaded, probably because it isn't there anymore */ if (!reference_conf) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because the " - "initially loaded preset can't be loaded. It was likely " - "renamed or deleted.\n"); - continue_saving_reference = false; + RARCH_WARN("[ Shaders ]: Saving Full Preset because the initially loaded preset can't be loaded. " + "It was likely renamed or deleted.\n"); goto end; } @@ -770,14 +1042,8 @@ bool video_shader_write_referenced_preset(const char *path, * the preset path we are currently trying to save */ if (reference_conf->reference) { - /* Get the absolute reference path in the initially loaded preset file*/ - if (!path_is_absolute(reference_conf->reference)) - fill_pathname_resolve_relative(abs_temp_reference_path, - reference_conf->path, - reference_conf->reference, - PATH_MAX_LENGTH); - else - abs_temp_reference_path = strdup(reference_conf->reference); + /* Get the absolute path for the reference */ + fill_pathname_expanded_and_absolute(abs_temp_reference_path, reference_conf->path, reference_conf->reference); /* If the reference is the same as the path we are trying to save to then this should be used as the reference to save */ @@ -802,21 +1068,14 @@ bool video_shader_write_referenced_preset(const char *path, /* 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) || - !strncmp(config_dir, path_to_reference, strlen(config_dir))) + if (string_is_equal(path_to_reference, path) || !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) { /* Get the absolute path for the reference */ - if (!path_is_absolute(reference_conf->reference)) - fill_pathname_resolve_relative(path_to_reference, - reference_conf->path, - reference_conf->reference, - PATH_MAX_LENGTH); - else - strlcpy(path_to_reference, reference_conf->reference, PATH_MAX_LENGTH); + fill_pathname_expanded_and_absolute(path_to_reference, reference_conf->path, reference_conf->reference); /* If the reference path is also the same as what we are trying to save This can easily happen @@ -834,20 +1093,13 @@ bool video_shader_write_referenced_preset(const char *path, if (reference_conf->reference) { /* Get the absolute path for the reference */ - if (!path_is_absolute(reference_conf->reference)) - fill_pathname_resolve_relative(path_to_reference, - reference_conf->path, - reference_conf->reference, - PATH_MAX_LENGTH); - else - strlcpy(path_to_reference, reference_conf->reference, PATH_MAX_LENGTH); + fill_pathname_expanded_and_absolute(path_to_reference, reference_conf->path, reference_conf->reference); } /* If the config referenced is a full preset */ else { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because we " - "can't save a preset which would reference itself.\n"); - continue_saving_reference = false; + RARCH_WARN("[ Shaders ]: Saving Full Preset because we can't save a preset which " + "would reference itself.\n"); goto end; } } @@ -856,9 +1108,8 @@ bool video_shader_write_referenced_preset(const char *path, else { /* We can't save a reference to ourselves */ - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because we " - "can't save a preset which would reference itself.\n"); - continue_saving_reference = false; + RARCH_WARN("[ Shaders ]: Saving Full Preset because we can't save a preset which " + "would reference itself.\n"); goto end; } } @@ -866,287 +1117,204 @@ bool video_shader_write_referenced_preset(const char *path, /* Check the reference chain that we would be saving to make sure it is valid */ if (!video_shader_check_reference_chain_for_save(path, path_to_reference)) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because " - "saving a Simple Preset would result in a cyclical reference, " - "or a preset in the reference chain could not be read.\n"); - continue_saving_reference = false; + RARCH_WARN("[ Shaders ]: Saving Full Preset because saving a Simple Preset would result " + "in a cyclical reference, or a preset in the reference chain could not be read.\n"); goto end; } + RARCH_LOG("[ Shaders ]: Reading Preset to Compare with Current Values: %s\n", path); + + /* Load the preset referenced in the preset into the shader */ + if (!video_shader_load_preset_into_shader(path_to_reference, referenced_shader)) + { + RARCH_WARN("[ Shaders ]: Saving Full Preset because we could not load the preset from the #reference line: %s.\n", + path_to_reference); + goto end; + } + + /* Create a new EMPTY config */ + conf = config_file_new_alloc(); + + if (!(conf)) + goto end; + + conf->path = strdup(path); + + pathname_make_slashes_portable(relative_temp_reference_path); + + /* Add the reference path to the config */ + config_file_set_reference_path(conf, path_to_reference); + + /* Set modified to true so when you run config_file_write it will save a file */ + conf->modified = true; + + /* + Compare the shader to a shader created from the referenced config to see if + we can save a referenced preset and what parameters and textures of the + root_config are overridden + */ + + /* Check number of passes match */ + if (shader->passes != referenced_shader->passes) + { + RARCH_WARN("[ Shaders ]: passes (Number of Passes) " + "Current Value doesn't match Referenced Value - Full Preset will be Saved instead of Simple Preset\n"); + continue_saving_reference = false; + } + + /* Compare all passes from the shader, if anything is different then we should not + * save a reference and instead save a full preset instead + */ if (continue_saving_reference) { - - path_relative_to(relative_temp_reference_path, - path_to_reference, - new_preset_basedir, - PATH_MAX_LENGTH); -#ifdef _WIN32 - if (!path_is_absolute(relative_temp_reference_path)) - make_relative_path_portable(relative_temp_reference_path); -#endif - - /* Create a new EMPTY config */ - conf = config_file_new_alloc(); - if (!(conf)) - goto end; - conf->path = strdup(path); - - /* Add the reference path to the config */ - config_file_set_reference_path(conf, relative_temp_reference_path); - - /* Set modified to true so when you run config_file_write it will save a file */ - conf->modified = true; - - /* Get a config from the #reference line in the preset - * We will compare the current shader against this config */ - config_file_free(reference_conf); - reference_conf = video_shader_read_preset(path_to_reference); - - /* reference_conf could be NULL if the file was not found or if the - * chain of references was too deep */ - if (reference_conf == NULL) + /* Step through each pass comparing all the properties to make sure they match */ + for (i = 0; (i < shader->passes && continue_saving_reference == true); i++) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Saving Full Preset because we " - "could not load the preset from the #reference line: %s.\n", - path_to_reference); - continue_saving_reference = false; - } - else - { - /* - Compare the shader to a shader created from the referenced config to see if - we can save a referenced preset and what parameters and textures of the - root_config are overridden - */ + const struct video_shader_pass *pass = &shader->pass[i]; + const struct video_shader_pass *root_pass = &referenced_shader->pass[i]; + const struct gfx_fbo_scale *fbo = &pass->fbo; + const struct gfx_fbo_scale *root_fbo = &root_pass->fbo; - struct video_shader *root_shader = NULL; - root_shader = (struct video_shader*) calloc(1, sizeof(*root_shader)); - video_shader_read_conf_preset(reference_conf, root_shader); - - /* Check number of passes match */ - if (shader->passes != root_shader->passes) + if (!string_is_equal(pass->source.path, root_pass->source.path)) { - RARCH_WARN("[ Shaders - Save Simple Preset ]: passes (Number of Passes) " - "Current Value doesn't match Referenced Value - Full Preset " - "will be Saved instead of Simple Preset\n"); + RARCH_WARN("[ Shaders ]: Pass %u path", i); continue_saving_reference = false; } - /* - Compare all passes from the shader - if anything is different then we should not save a reference - and save instead safe a full preset instead - */ - if (continue_saving_reference) + if (continue_saving_reference && pass->filter != root_pass->filter) { - /* Step through each pass comparing all the properties to make sure they match */ - for (i = 0; (i < shader->passes && continue_saving_reference == true); i++) - { - const struct video_shader_pass *pass = &shader->pass[i]; - const struct video_shader_pass *root_pass = &root_shader->pass[i]; - const struct gfx_fbo_scale *fbo = &pass->fbo; - const struct gfx_fbo_scale *root_fbo = &root_pass->fbo; - - if (!string_is_equal(pass->source.path, root_pass->source.path)) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u path", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && pass->filter != root_pass->filter) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u filter", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && pass->wrap != root_pass->wrap) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u wrap", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && pass->frame_count_mod != root_pass->frame_count_mod) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u frame_count", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && pass->mipmap != root_pass->mipmap) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u mipmap", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && !string_is_equal(pass->alias, root_pass->alias)) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u alias", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->type_x != root_fbo->type_x) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u type_x", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->type_y != root_fbo->type_y) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u type_y", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->scale_x != root_fbo->scale_x) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u scale_x", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->scale_y != root_fbo->scale_y) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u scale_y", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->fp_fbo != root_fbo->fp_fbo) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u fp_fbo", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->srgb_fbo != root_fbo->srgb_fbo) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u srgb_fbo", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->valid != root_fbo->valid) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u valid", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->abs_x != root_fbo->abs_x) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u abs_x", i); - continue_saving_reference = false; - } - - if (continue_saving_reference && fbo->abs_y != root_fbo->abs_y) - { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Pass %u abs_y", i); - continue_saving_reference = false; - } - - if (!continue_saving_reference) - RARCH_WARN(" Current Value doesn't match Referenced Value - " - "Full Preset Will be Saved instead of Simple Preset\n"); - } + RARCH_WARN("[ Shaders ]: Pass %u filter", i); + continue_saving_reference = false; } - if (continue_saving_reference) + if (continue_saving_reference && pass->wrap != root_pass->wrap) { - const struct config_entry_list *entry = NULL; - - /* If the shader has parameters */ - if (shader->num_parameters) - { - unsigned i; - float parameter_value_reference = 0.0f; - - - for (i = 0; i < shader->num_parameters; i++) - { - bool add_param_to_override = false; - - entry = config_get_entry(reference_conf, shader->parameters[i].id); - - /* If the parameter is in the reference config */ - if (entry) - { - /* If the current param value is different than the referenced preset's value */ - config_get_float(reference_conf, shader->parameters[i].id, ¶meter_value_reference); - if (shader->parameters[i].current != parameter_value_reference) - add_param_to_override = true; - } - /* If it's not in the reference config, but it's different than the - initial value of the shader */ - else if (shader->parameters[i].current != shader->parameters[i].initial) - add_param_to_override = true; - - /* Add the parameter value to the config */ - if (add_param_to_override) - config_set_float(conf, shader->parameters[i].id, shader->parameters[i].current); - } - } - - /* If the shader has textures */ - if (shader->luts) - { - char *shader_tex_path = (char*)malloc(PATH_MAX_LENGTH); - char *shader_tex_relative_path = (char*)malloc(PATH_MAX_LENGTH); - char *shader_tex_base_path = (char*)malloc(PATH_MAX_LENGTH); - char *referenced_tex_absolute_path = (char*)malloc(PATH_MAX_LENGTH); - char *referenced_tex_path = (char*)malloc(PATH_MAX_LENGTH); - unsigned i; - - shader_tex_path[0] = '\0'; - shader_tex_relative_path[0] = '\0'; - shader_tex_base_path[0] = '\0'; - referenced_tex_absolute_path[0] = '\0'; - referenced_tex_path[0] = '\0'; - - for (i = 0; i < shader->luts; i++) - { - /* If the texture is defined in the reference config */ - entry = config_get_entry(reference_conf, shader->lut[i].id); - if (entry) - { - /* Texture path from shader is already absolute */ - strlcpy(shader_tex_path, shader->lut[i].path, PATH_MAX_LENGTH); - strlcpy(referenced_tex_path, entry->value, PATH_MAX_LENGTH); - - /* Resolve the texture's path relative to the override config */ - if (!path_is_absolute(referenced_tex_path)) - fill_pathname_resolve_relative(referenced_tex_absolute_path, - reference_conf->path, - entry->value, - PATH_MAX_LENGTH); - else - strlcpy(referenced_tex_absolute_path, referenced_tex_path, PATH_MAX_LENGTH); - - /* If the current shader texture path is different than the referenced paths then - * write the current path into the new preset */ - if (!string_is_equal(referenced_tex_absolute_path, shader->lut[i].path)) - { - /* Get the texture path relative to the new preset */ - path_relative_to(shader_tex_relative_path, shader_tex_path, path_basename(path), PATH_MAX_LENGTH); - - RARCH_LOG("[ Shaders - Save Simple Preset ]: Texture override %s = %s.\n", - shader->lut[i].id, - shader->lut[i].path); - config_set_path(conf, shader->lut[i].id, shader->lut[i].path); - } - } - } - - free(shader_tex_path); - free(shader_tex_relative_path); - free(shader_tex_base_path); - free(referenced_tex_absolute_path); - free(referenced_tex_path); - } - /* Write the file, return will be true if successful */ - RARCH_LOG("[ Shaders - Save Simple Preset ]: Saving simple preset to: %s\n", path); - ret = config_file_write(conf, path, false); + RARCH_WARN("[ Shaders ]: Pass %u wrap", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && pass->frame_count_mod != root_pass->frame_count_mod) + { + RARCH_WARN("[ Shaders ]: Pass %u frame_count", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && pass->mipmap != root_pass->mipmap) + { + RARCH_WARN("[ Shaders ]: Pass %u mipmap", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && !string_is_equal(pass->alias, root_pass->alias)) + { + RARCH_WARN("[ Shaders ]: Pass %u alias", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->type_x != root_fbo->type_x) + { + RARCH_WARN("[ Shaders ]: Pass %u type_x", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->type_y != root_fbo->type_y) + { + RARCH_WARN("[ Shaders ]: Pass %u type_y", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->scale_x != root_fbo->scale_x) + { + RARCH_WARN("[ Shaders ]: Pass %u scale_x", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->scale_y != root_fbo->scale_y) + { + RARCH_WARN("[ Shaders ]: Pass %u scale_y", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->fp_fbo != root_fbo->fp_fbo) + { + RARCH_WARN("[ Shaders ]: Pass %u fp_fbo", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->srgb_fbo != root_fbo->srgb_fbo) + { + RARCH_WARN("[ Shaders ]: Pass %u srgb_fbo", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->valid != root_fbo->valid) + { + RARCH_WARN("[ Shaders ]: Pass %u valid", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->abs_x != root_fbo->abs_x) + { + RARCH_WARN("[ Shaders ]: Pass %u abs_x", i); + continue_saving_reference = false; + } + + if (continue_saving_reference && fbo->abs_y != root_fbo->abs_y) + { + RARCH_WARN("[ Shaders ]: Pass %u abs_y", i); + continue_saving_reference = false; + } + + if (!continue_saving_reference) + { + RARCH_WARN(" Current Value doesn't match Referenced Value - Full Preset Will be Saved instead of Simple Preset\n"); + goto end; } - free(root_shader); } } + /* If the shader has parameters */ + if (shader->num_parameters) + { + for (i = 0; i < shader->num_parameters; i++) + { + /* If the parameter's current value is different than the referenced shader + * then write the value into the new preset */ + if (shader->parameters[i].current != referenced_shader->parameters[i].current) + config_set_float(conf, shader->parameters[i].id, shader->parameters[i].current); + } + } + + /* If the shader has textures */ + if (shader->luts) + { + for (i = 0; i < shader->luts; i++) + { + /* If the current shader texture path is different than the referenced shader texture then + * write the current path into the new preset */ + if (!string_is_equal(referenced_shader->lut[i].path, shader->lut[i].path)) + { + char *path_for_save = (char*)malloc(PATH_MAX_LENGTH); + + fill_pathname_abbreviated_or_relative(path_for_save, conf->path, shader->lut[i].path, PATH_MAX_LENGTH); + pathname_make_slashes_portable(path_for_save); + config_set_string(conf, shader->lut[i].id, path_for_save); + RARCH_LOG("[ Shaders ]: Texture override %s = %s.\n", shader->lut[i].id, path_for_save); + + free(path_for_save); + } + } + } + + /* Write the file, return will be true if successful */ + RARCH_LOG("[ Shaders ]: Saving simple preset to: %s\n", path); + ret = config_file_write(conf, path, false); + end: config_file_free(conf); config_file_free(reference_conf); + free(referenced_shader); free(abs_temp_reference_path); free(relative_temp_reference_path); free(new_preset_basedir); @@ -1159,30 +1327,25 @@ end: /** * video_shader_write_preset: * @path : File to write to - * @shader : Shader preset to write - * @reference : Whether a reference preset should be written + * @shader : Shader to write + * @reference : Whether a simple preset should be written with the #reference to another preset in it * - * Writes a preset to disk. Can be written as a reference preset. - * See: video_shader_read_preset + * Writes a preset to disk. Can be written as a simple preset (With the #reference directive in it) or a full preset. **/ bool video_shader_write_preset(const char *path, - const char *shader_dir, - const struct video_shader *shader, bool reference) + const char *shader_dir, + const struct video_shader *shader, + bool reference) { /* We need to clean up paths to be able to properly process them * path and shader->loaded_preset_path can use '/' on Windows due to Qt being Qt */ char preset_dir[PATH_MAX_LENGTH]; - config_file_t *conf; bool ret; if (!shader || string_is_empty(path)) return false; - fill_pathname_join( - preset_dir, - shader_dir, - "presets", - sizeof(preset_dir)); + fill_pathname_join(preset_dir, shader_dir, "presets", sizeof(preset_dir)); /* If we should still save a referenced preset do it now */ if (reference) @@ -1193,262 +1356,65 @@ bool video_shader_write_preset(const char *path, } else { - RARCH_WARN("[ Shaders - Save Simple Preset ]: Failed writing Simple " - "Preset to %s - Full Preset Will be Saved instead.\n", path); + RARCH_WARN("[ Shaders ]: Failed writing Simple Preset to %s - " + "Full Preset Will be Saved instead.\n", path); } } /* If we aren't saving a referenced preset or weren't able to save one * then save a full preset */ - - /* Note: We always create a new/blank config - * file here. Loading and updating an existing - * file could leave us with unwanted/invalid - * parameters. */ - if (!(conf = config_file_new_alloc())) - return false; - - video_shader_write_conf_preset(conf, shader, path); - - ret = config_file_write(conf, path, false); - - config_file_free(conf); + ret = video_shader_write_root_preset(shader, path); return ret; } /** - * override_config_values: - * @conf : Config file to be affected - * @override_conf : Config file who's values will be copied on top of conf - * - * Takes values from override_config and overrides values of conf - * The 'parameters' value will be the combined parameter list from both configs - * - * Returns 0 if nothing is overridden - * Returns 1 if something is overridden - **/ -bool override_config_values(config_file_t *conf, config_file_t *override_conf) -{ - int return_val = 0; - size_t param_size = 4096 * sizeof(char); - const char *id = NULL; - char *save = NULL; - size_t path_size = PATH_MAX_LENGTH; - char *override_texture_path = (char*)malloc(path_size); - char *resolved_path = (char*)malloc(path_size); - char *textures_in_conf = (char*)malloc(param_size); - size_t tmp_size = PATH_MAX_LENGTH; - char *tmp = (char*)malloc(3*tmp_size); - char *tmp_rel = tmp + tmp_size; - char *tmp_base = tmp + 2*tmp_size; - struct config_entry_list *override_entry = NULL; - - textures_in_conf[0] = '\0'; - strlcpy(tmp_base, conf->path, tmp_size); - - if (conf == NULL || override_conf == NULL) return 0; - - /* --------------------------------------------------------------------------------- - * ------------- Resolve Override texture paths to absolute paths------------------- - * --------------------------------------------------------------------------------- */ - - /* ensure we use a clean base like the shader passes and texture paths do */ - path_resolve_realpath(tmp_base, tmp_size, false); - path_basedir(tmp_base); - - /* If there are textures in the referenced config */ - if (config_get_array(conf, "textures", textures_in_conf, param_size)) - { - for ( id = strtok_r(textures_in_conf, ";", &save); - id; - id = strtok_r(NULL, ";", &save)) - { - /* Get the texture path from the override config */ - if (config_get_path(override_conf, id, override_texture_path, path_size)) - { - /* Resolve the texture's path relative to the override config */ - if (!path_is_absolute(override_texture_path)) - fill_pathname_resolve_relative(resolved_path, - override_conf->path, - override_texture_path, - PATH_MAX_LENGTH); - else - strlcpy(resolved_path, override_texture_path, path_size); - - path_relative_to(tmp_rel, resolved_path, tmp_base, tmp_size); - config_set_path(override_conf, id, tmp_rel); - - return_val = 1; - } - } - } - - /* --------------------------------------------------------------------------------- - * ------------- Update entries to match the override entries ---------------------- - * --------------------------------------------------------------------------------- */ - - for (override_entry = override_conf->entries; override_entry; override_entry = override_entry->next) - /* Only override an entry if the its key is not "textures" */ - if (!string_is_empty(override_entry->key) && !string_is_equal(override_entry->key, "textures")) - { - RARCH_LOG("[ Shaders - Read Simple Preset ]: Parameter/Entry overridden %s = %s.\n", - override_entry->key, override_entry->value); - config_set_string(conf, override_entry->key, override_entry->value); - return_val = 1; - } - - free(tmp); - free(resolved_path); - free(override_texture_path); - free(textures_in_conf); - - return return_val; -} - -/** - * video_shader_read_preset: - * @path : File to read - * - * Reads a preset from disk. - * If the preset is a reference preset, the referenced preset - * is loaded instead. - * - * Returns the read preset as a config object. - * - * The returned config object needs to be freed. - **/ -config_file_t *video_shader_read_preset(const char *path) -{ - config_file_t *conf; - conf = config_file_new_from_path_to_string(path); - - if (conf != NULL) - { - int reference_depth = 1; - - if (conf->reference) - RARCH_LOG("[ Shaders - Read Preset ]: Start reading SIMPLE Preset: %s\n", path); - else - RARCH_LOG("[ Shaders - Read Preset ]: Start reading FULL Preset: %s\n", path); - - /* If the config has a reference then it is really an override config. - * We now load a new config from the reference then override it's values - * with the override config */ - while (conf->reference) - { - char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH); - /* Set override_conf to refer to the original config */ - config_file_t *override_conf = conf; - - /* Stop attempting to read the next reference when we have visited many links - * in the reference chain because we are likely in a self referential loop. - * 16 references deep seems like more than enough depth for expected usage */ - if (reference_depth > 16) - { - RARCH_ERR("[ Shaders - Read Simple Preset ]: Exceeded maximum reference " - "depth(16) without finding a full preset\n"); - free(reference_preset_path); - config_file_free(conf); - conf = NULL; - return NULL; - } - - /* Resolve the reference path relative to the config */ - if (path_is_absolute(conf->reference)) - strlcpy(reference_preset_path, conf->reference, PATH_MAX_LENGTH); - else - fill_pathname_resolve_relative(reference_preset_path, - conf->path, - conf->reference, - PATH_MAX_LENGTH); - - RARCH_LOG("[ Shaders - Read Simple Preset ]: #reference preset read " - "(Depth %u): %s\n", reference_depth, reference_preset_path); - - /* Create a new config from the root preset */ - conf = config_file_new_from_path_to_string(reference_preset_path); - - /* Only try to override values if the config is not NULL - * If it is NULL there is no shader*/ - if (conf != NULL) - /* override_conf is from the initial file we loaded which - * has the #reference directive*/ - override_config_values(conf, override_conf); - else - { - RARCH_WARN("[ Shaders - Read Simple Preset ]: Could not read shader preset " - "in #reference line: %s\n", reference_preset_path); - free(reference_preset_path); - config_file_free(override_conf); - break; - } - - reference_depth += 1; - - free(reference_preset_path); - config_file_free(override_conf); - } - - /* Set Path for originally loaded preset */ - config_set_path(conf, "loaded_preset_path", path); - } - else - RARCH_WARN("[ Shaders - Read Preset ]: Could not read preset: %s \n", path); - - return conf; -} - -/** - * video_shader_read_conf_preset: + * video_shader_load_root_config_into_shader: * @conf : Preset file to read from. - * @shader : Shader passes handle. + * @shader : Shader handle. * - * Loads preset file and all associated state (passes, - * textures, imports, etc). + * Loads preset file and all associated state (passes, textures, imports, etc). * * Returns: true (1) if successful, otherwise false (0). **/ -bool video_shader_read_conf_preset(config_file_t *conf, - struct video_shader *shader) +bool video_shader_load_root_config_into_shader(config_file_t *conf, struct video_shader *shader) { unsigned i; - unsigned shaders = 0; + unsigned num_passes = 0; settings_t *settings = config_get_ptr(); bool watch_files = settings->bools.video_shader_watch_files; - char loaded_preset_path[PATH_MAX_LENGTH]; + /* This sets the shader to empty */ memset(shader, 0, sizeof(*shader)); - if (!config_get_uint(conf, "shaders", &shaders)) + RARCH_LOG("\n"); + RARCH_LOG("[ Shaders ]: Reading ROOT PRESET: %s\n", conf->path); + + if (!config_get_uint(conf, "shaders", &num_passes)) { - RARCH_ERR("[ Shaders - Read Preset ]: Cannot find \"shaders\" param. " - "Preset is invalid.\n"); - return false; + RARCH_ERR("[ Shaders ]: Cannot find \"shaders\" param. Preset is invalid.\n"); + goto fail; } - if (!shaders) + if (!num_passes) { - RARCH_ERR("[ Shaders - Read Preset ]: Need to define at least 1 shader pass. " - "Preset is invalid.\n"); - return false; + RARCH_ERR("[ Shaders ]: Need to define at least 1 shader pass. Preset is invalid.\n"); + goto fail; } - if (!config_get_int(conf, "feedback_pass", - &shader->feedback_pass)) + if (!config_get_int(conf, "feedback_pass", &shader->feedback_pass)) shader->feedback_pass = -1; - shader->passes = MIN(shaders, GFX_MAX_SHADERS); + shader->passes = MIN(num_passes, GFX_MAX_SHADERS); /* Set the path of the root preset for this shader */ strlcpy(shader->path, conf->path, sizeof(shader->path)); - - /* Set the path of the original preset which was loaded, this would be - * different than the root preset in the case preset of use of the #reference directive - * in the original preset loaded */ - config_get_path(conf, "loaded_preset_path", loaded_preset_path, PATH_MAX_LENGTH); + + /* Set the path of the original preset which was loaded, for a full preset config this is the same as the root config + * For simple presets (using #reference) this different than the root preset and it is the path to the + * simple preset originally loaded, but that is set inside video_shader_load_preset_into_shader*/ strlcpy( shader->loaded_preset_path, - loaded_preset_path, + conf->path, sizeof(shader->loaded_preset_path)); if (watch_files) @@ -1464,8 +1430,7 @@ bool video_shader_read_conf_preset(config_file_t *conf, attr.i = 0; if (file_change_data) - frontend_driver_watch_path_for_changes(NULL, - 0, &file_change_data); + frontend_driver_watch_path_for_changes(NULL, 0, &file_change_data); file_change_data = NULL; string_list_initialize(&file_list); @@ -1479,15 +1444,13 @@ bool video_shader_read_conf_preset(config_file_t *conf, if (!video_shader_parse_pass(conf, &shader->pass[i], i)) { string_list_deinitialize(&file_list); - return false; + goto fail; } - string_list_append(&file_list, - shader->pass[i].source.path, attr); + string_list_append(&file_list, shader->pass[i].source.path, attr); } - frontend_driver_watch_path_for_changes(&file_list, - flags, &file_change_data); + frontend_driver_watch_path_for_changes(&file_list, flags, &file_change_data); string_list_deinitialize(&file_list); } else @@ -1495,230 +1458,234 @@ bool video_shader_read_conf_preset(config_file_t *conf, for (i = 0; i < shader->passes; i++) { if (!video_shader_parse_pass(conf, &shader->pass[i], i)) - return false; + goto fail; } } - return video_shader_parse_textures(conf, shader); + if (!video_shader_parse_textures(conf, shader)) + goto fail; + + /* Load the parameter values */ + video_shader_resolve_parameters(shader); + + /* Load the parameter values */ + video_shader_load_current_parameter_values(conf, shader); + + RARCH_LOG("[ Shaders ]: Number of Passes: %u\n", shader->passes); + RARCH_LOG("[ Shaders ]: Number of Textures: %u\n", shader->luts); + + /* Log Texture Names & Paths */ + for (i = 0; i < shader->luts; i++) + RARCH_LOG("[ Shaders ]: %s = %s.\n", shader->lut[i].id, shader->lut[i].path); + + return true; + + fail: + return false; } -/* CGP store */ -static const char *scale_type_to_str(enum gfx_scale_type type) + +/** + * override_shader_values: + * @override_conf : Config file who's values will be copied on top of conf + * @shader : Shader to be affected + * + * Takes values from override_config and overrides values of the shader + * + * Returns 0 if nothing is overridden + * Returns 1 if something is overridden + **/ +bool override_shader_values(config_file_t *override_conf, struct video_shader *shader) { - switch (type) + bool return_val = false; + unsigned i; + struct config_entry_list *entry = NULL; + char *override_tex_path = (char*)malloc(PATH_MAX_LENGTH); + + override_tex_path[0] = '\0'; + + if (shader == NULL || override_conf == NULL) return 0; + + /* If the shader has parameters */ + if (shader->num_parameters) { - case RARCH_SCALE_INPUT: - return "source"; - case RARCH_SCALE_VIEWPORT: - return "viewport"; - case RARCH_SCALE_ABSOLUTE: - return "absolute"; - default: - break; + /* Step through the parameters in the shader and see if there is an entry + * for each in the override config */ + for (i = 0; i < shader->num_parameters; i++) + { + entry = config_get_entry(override_conf, shader->parameters[i].id); + + /* If the parameter is in the reference config */ + if (entry) + { + struct video_shader_parameter *parameter = (struct video_shader_parameter*) + video_shader_parse_find_parameter( + shader->parameters, + shader->num_parameters, + shader->parameters[i].id); + + /* Set the shader's parameter value */ + config_get_float(override_conf, shader->parameters[i].id, ¶meter->current); + + RARCH_LOG("[ Shaders ]: Parameter: %s = %f.\n", + shader->parameters[i].id, + shader->parameters[i].current); + + return_val = true; + } + } } - return "?"; -} + /* --------------------------------------------------------------------------------- + * ------------- Resolve Override texture paths to absolute paths------------------- + * --------------------------------------------------------------------------------- */ -static void shader_write_scale_dim(config_file_t *conf, - const char *dim, - enum gfx_scale_type type, float scale, - unsigned absolute, unsigned i) -{ - char key[64]; + /* If the shader has textures */ + if (shader->luts) + { + /* Step through the textures in the shader and see if there is an entry + * for each in the override config */ + for (i = 0; i < shader->luts; i++) + { + entry = config_get_entry(override_conf, shader->lut[i].id); - key[0] = '\0'; + /* If the texture is defined in the reference config */ + if (entry) + { + /* Texture path from shader the config */ + config_get_path(override_conf, shader->lut[i].id, override_tex_path, PATH_MAX_LENGTH); - snprintf(key, sizeof(key), "scale_type_%s%u", dim, i); - config_set_string(conf, key, scale_type_to_str(type)); + /* Get the absolute path */ + fill_pathname_expanded_and_absolute(shader->lut[i].path, override_conf->path, override_tex_path); - snprintf(key, sizeof(key), "scale_%s%u", dim, i); - if (type == RARCH_SCALE_ABSOLUTE) - config_set_int(conf, key, absolute); - else - config_set_float(conf, key, scale); -} + RARCH_LOG("[ Shaders ]: Texture: %s = %s.\n", + shader->lut[i].id, + shader->lut[i].path); -static void shader_write_fbo(config_file_t *conf, - const struct gfx_fbo_scale *fbo, unsigned i) -{ - char key[64]; + return_val = true; + } + } - key[0] = '\0'; + free(override_tex_path); + } - snprintf(key, sizeof(key), "float_framebuffer%u", i); - config_set_bool(conf, key, fbo->fp_fbo); - snprintf(key, sizeof(key), "srgb_framebuffer%u", i); - config_set_bool(conf, key, fbo->srgb_fbo); - - if (!fbo->valid) - return; - - shader_write_scale_dim(conf, "x", fbo->type_x, - fbo->scale_x, fbo->abs_x, i); - shader_write_scale_dim(conf, "y", fbo->type_y, - fbo->scale_y, fbo->abs_y, i); + return return_val; } /** - * video_shader_write_conf_preset: - * @conf : Preset file to write to. - * @shader : Shader passes handle. - * @preset_path : Optional path to where the preset will be written. + * video_shader_load_preset_into_shader: + * @path : Path to preset file, could be a Simple Preset (including a #reference) or Full Preset + * @shader : Shader * - * Writes preset and all associated state (passes, - * textures, imports, etc) into @conf. - * If @preset_path is not NULL, shader paths are saved - * relative to it. + * Loads preset file to a shader including passes, textures and parameters + * + * Returns: true (1) if successful, otherwise false (0). **/ -void video_shader_write_conf_preset(config_file_t *conf, - const struct video_shader *shader, const char *preset_path) +bool video_shader_load_preset_into_shader(const char *path, struct video_shader *shader) { - unsigned i; - char key[64]; - size_t tmp_size = PATH_MAX_LENGTH; - char *tmp = (char*)malloc(3*tmp_size); - char *tmp_rel = tmp + tmp_size; - char *tmp_base = tmp + 2*tmp_size; + unsigned i = 0; + bool ret = true; + int reference_depth = 1; + char override_conf_paths[SHADER_MAX_REFERENCE_DEPTH][PATH_MAX_LENGTH]; + config_file_t *conf = NULL; + config_file_t *root_conf = NULL; + + /* Get the root config, If we were able to get a root_config that means the reference chain is valid */ + root_conf = video_shader_get_root_preset_config(path); - if (!tmp) - return; - - RARCH_LOG("[ Shaders - Save Full Preset ]: Saving full preset to: %s\n", preset_path); - - config_set_int(conf, "shaders", shader->passes); - if (shader->feedback_pass >= 0) - config_set_int(conf, "feedback_pass", shader->feedback_pass); - - if (preset_path) + if (!root_conf) { - strlcpy(tmp_base, preset_path, tmp_size); - - /* ensure we use a clean base like the shader passes and texture paths do */ - path_resolve_realpath(tmp_base, tmp_size, false); - path_basedir(tmp_base); + RARCH_LOG("\n"); + RARCH_WARN("[ Shaders ]: Could not read root preset: %s \n", path); + ret = false; + goto end; } - for (i = 0; i < shader->passes; i++) + /* If we were able to get a root_config that means that the whole reference chain is valid */ + + /* 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)) { - const struct video_shader_pass *pass = &shader->pass[i]; + RARCH_LOG("\n"); + RARCH_LOG("[ Shaders ]: Start reading FULL Preset: %s\n", path); + video_shader_load_root_config_into_shader(root_conf, shader); + goto end; + } + /* Otherwise this is a Simple Preset with a #reference in it */ + else + { + RARCH_LOG("\n"); + RARCH_LOG("[ Shaders ]: Start reading SIMPLE Preset: %s\n", path); + /* Load the root full preset into the shader which should be empty at this point */ + video_shader_load_root_config_into_shader(root_conf, shader); + } + + /* 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); - snprintf(key, sizeof(key), "shader%u", i); + /* 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'; - if (preset_path) - { - strlcpy(tmp, pass->source.path, tmp_size); - path_relative_to(tmp_rel, tmp, tmp_base, tmp_size); -#ifdef _WIN32 - if (!path_is_absolute(tmp_rel)) - make_relative_path_portable(tmp_rel); -#endif + i = 0; - config_set_path(conf, key, tmp_rel); - } - else - config_set_path(conf, key, pass->source.path); + RARCH_LOG("\n"); + RARCH_LOG("[ Shaders ]: Crawl Preset Reference Chain\n"); + /* 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) + { + char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH); + i++; - if (pass->filter != RARCH_FILTER_UNSPEC) - { - snprintf(key, sizeof(key), "filter_linear%u", i); - config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR); - } + RARCH_LOG("[ Shaders ]: #reference preset read (Depth %u): %s\n", i, conf->path); - snprintf(key, sizeof(key), "wrap_mode%u", i); - config_set_string(conf, key, wrap_mode_to_str(pass->wrap)); + /* Add the reference to the list */ + strcpy(override_conf_paths[i], conf->path); - if (pass->frame_count_mod) - { - snprintf(key, sizeof(key), "frame_count_mod%u", i); - config_set_int(conf, key, pass->frame_count_mod); - } + /* Get the absolute path for the reference */ + fill_pathname_expanded_and_absolute(reference_preset_path, conf->path, conf->reference); - snprintf(key, sizeof(key), "mipmap_input%u", i); - config_set_bool(conf, key, pass->mipmap); + /* Create a new config from this reference level */ + conf = config_file_new_from_path_to_string(reference_preset_path); - snprintf(key, sizeof(key), "alias%u", i); - config_set_string(conf, key, pass->alias); + free(reference_preset_path); + } + + /* Step back through the references starting with the one referencing the root config and apply overrides for each one */ + + RARCH_LOG("\n"); + RARCH_LOG("[ Shaders ]: Start Applying Simple Preset Overrides\n"); - shader_write_fbo(conf, &pass->fbo, i); + while (i) + { + config_file_t *override_conf = config_file_new_from_path_to_string(override_conf_paths[i]); + + RARCH_LOG("[ Shaders ]: Depth %u Apply Overrides\n", i); + RARCH_LOG("[ Shaders ]: Apply values from: %s\n", override_conf->path); + override_shader_values(override_conf, shader); + + config_file_free(override_conf); + i--; } - /* Write shader parameters which are different than the default - * shader values */ - if (shader->num_parameters) - for (i = 0; i < shader->num_parameters; i++) - if (shader->parameters[i].current != shader->parameters[i].initial) - config_set_float(conf, shader->parameters[i].id, - shader->parameters[i].current); + RARCH_LOG("[ Shaders ]: End Apply Overrides\n"); + RARCH_LOG("\n"); - if (shader->luts) - { - char textures[4096]; + /* 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)); - textures[0] = '\0'; + end: - strlcpy(textures, shader->lut[0].id, sizeof(textures)); + config_file_free(conf); + config_file_free(root_conf); - for (i = 1; i < shader->luts; i++) - { - /* O(n^2), but number of textures is very limited. */ - strlcat(textures, ";", sizeof(textures)); - strlcat(textures, shader->lut[i].id, sizeof(textures)); - } - - config_set_string(conf, "textures", textures); - - for (i = 0; i < shader->luts; i++) - { - if (preset_path) - { - strlcpy(tmp, shader->lut[i].path, tmp_size); - path_relative_to(tmp_rel, tmp, tmp_base, tmp_size); -#ifdef _WIN32 - if (!path_is_absolute(tmp_rel)) - make_relative_path_portable(tmp_rel); -#endif - - config_set_path(conf, shader->lut[i].id, tmp_rel); - } - else - config_set_path(conf, shader->lut[i].id, shader->lut[i].path); - - if (shader->lut[i].filter != RARCH_FILTER_UNSPEC) - { - char key[128]; - key[0] = '\0'; - strlcpy(key, shader->lut[i].id, sizeof(key)); - strlcat(key, "_linear", sizeof(key)); - config_set_bool(conf, key, - shader->lut[i].filter == RARCH_FILTER_LINEAR); - } - - { - char key[128]; - key[0] = '\0'; - strlcpy(key, shader->lut[i].id, sizeof(key)); - strlcat(key, "_wrap_mode", sizeof(key)); - config_set_string(conf, key, - wrap_mode_to_str(shader->lut[i].wrap)); - } - - { - char key[128]; - key[0] = '\0'; - strlcpy(key, shader->lut[i].id, sizeof(key)); - strlcat(key, "_mipmap", sizeof(key)); - config_set_bool(conf, key, - shader->lut[i].mipmap); - } - } - } - - free(tmp); + return ret; } -const char *video_shader_to_str(enum rarch_shader_type type) +const char *video_shader_type_to_str(enum rarch_shader_type type) { switch (type) { @@ -1807,8 +1774,7 @@ bool video_shader_any_supported(void) BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_HLSL); } -enum rarch_shader_type video_shader_get_type_from_ext(const char *ext, - bool *is_preset) +enum rarch_shader_type video_shader_get_type_from_ext(const char *ext, bool *is_preset) { if (string_is_empty(ext)) return RARCH_SHADER_NONE; diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index 2a079afb99..b581170994 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -33,10 +33,6 @@ RETRO_BEGIN_DECLS #define GFX_MAX_TEXTURES 64 #endif -#ifndef GFX_MAX_VARIABLES -#define GFX_MAX_VARIABLES 64 -#endif - #ifndef GFX_MAX_PARAMETERS #define GFX_MAX_PARAMETERS 512 #endif @@ -167,47 +163,59 @@ struct video_shader bool modified; }; -/** - * video_shader_write_preset: - * @path : File to write to - * @shader : Shader preset to write - * @reference : Whether a reference preset should be written - * - * Writes a preset to disk. Can be written as a reference preset. - * See: video_shader_read_preset - **/ -bool video_shader_write_preset(const char *path, - const char *shader_dir, - const struct video_shader *shader, bool reference); /** - * video_shader_read_preset: - * @path : File to read - * - * Reads a preset from disk. - * If the preset is a reference preset, the referenced preset - * is loaded instead. - * - * Returns: the read preset as a config object. - * - * The returned config object needs to be freed. - **/ -config_file_t *video_shader_read_preset(const char *path); - -/** - * video_shader_read_conf_preset: + * video_shader_resolve_parameters: * @conf : Preset file to read from. * @shader : Shader passes handle. + * + * Resolves all shader parameters belonging to shaders + * from the #pragma parameter lines in the shader for each pass. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool video_shader_resolve_parameters(struct video_shader *shader); + + +/** + * video_shader_load_current_parameter_values: + * @conf : Preset file to read from. + * @shader : Shader passes handle. + * + * Reads the current value for all parameters from config file. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool video_shader_load_current_parameter_values(config_file_t *conf, struct video_shader *shader); + + +/** + * video_shader_load_root_config_into_shader: + * @conf : Preset file to read from. + * @shader : Shader handle. + * * Loads preset file and all associated state (passes, * textures, imports, etc). * * Returns: true (1) if successful, otherwise false (0). **/ -bool video_shader_read_conf_preset(config_file_t *conf, - struct video_shader *shader); +bool video_shader_load_root_config_into_shader(config_file_t *conf, struct video_shader *shader); + /** - * video_shader_write_conf_preset: + * video_shader_load_preset_into_shader: + * @path : Path to preset file, could be a Simple Preset (including a #reference) or Full Preset + * @shader : Shader + * + * Loads preset file to a shader including passes, textures and parameters + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool video_shader_load_preset_into_shader(const char *path, struct video_shader *shader); + + +/** + * video_shader_write_root_preset: * @conf : Preset file to write to. * @shader : Shader passes handle. * @preset_path : Optional path to where the preset will be written. @@ -217,35 +225,24 @@ bool video_shader_read_conf_preset(config_file_t *conf, * If @preset_path is not NULL, shader paths are saved * relative to it. **/ -void video_shader_write_conf_preset(config_file_t *conf, - const struct video_shader *shader, const char *preset_path); +bool video_shader_write_root_preset(const struct video_shader *shader, const char *preset_path); + /** - * video_shader_resolve_parameters: - * @conf : Preset file to read from. - * @shader : Shader passes handle. + * video_shader_write_preset: + * @path : File to write to + * @shader : Shader to write + * @reference : Whether a simple preset should be written with the #reference to another preset in it * - * Reads the current value for all parameters from config file. - * - * Returns: true (1) if successful, otherwise false (0). + * Writes a preset to disk. Can be written as a simple preset (With the #reference directive in it) or a full preset. **/ -bool video_shader_resolve_current_parameters(config_file_t *conf, - struct video_shader *shader); +bool video_shader_write_preset(const char *path, + const char *shader_dir, + const struct video_shader *shader, + bool reference); -/** - * video_shader_resolve_parameters: - * @conf : Preset file to read from. - * @shader : Shader passes handle. - * - * Resolves all shader parameters belonging to shaders. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -bool video_shader_resolve_parameters(config_file_t *conf, - struct video_shader *shader); -enum rarch_shader_type video_shader_get_type_from_ext(const char *ext, - bool *is_preset); +enum rarch_shader_type video_shader_get_type_from_ext(const char *ext, bool *is_preset); /** * video_shader_parse_type: @@ -264,7 +261,7 @@ bool video_shader_any_supported(void); bool video_shader_check_for_changes(void); -const char *video_shader_to_str(enum rarch_shader_type type); +const char *video_shader_type_to_str(enum rarch_shader_type type); const char *video_shader_get_preset_extension(enum rarch_shader_type type); diff --git a/libretro-common/file/config_file.c b/libretro-common/file/config_file.c index c9bb71f0ac..9f12fe19a6 100644 --- a/libretro-common/file/config_file.c +++ b/libretro-common/file/config_file.c @@ -648,8 +648,12 @@ static int config_file_from_string_internal( void config_file_set_reference_path(config_file_t *conf, char *path) { - /* If a relative path the input path is desired the caller is - * responsible for preparing and supplying the relative 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; @@ -659,8 +663,9 @@ void config_file_set_reference_path(config_file_t *conf, char *path) conf->reference = NULL; } - - conf->reference = strdup(path); + 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) @@ -1295,7 +1300,10 @@ void config_file_dump_orbis(config_file_t *conf, int fd) struct config_include_list *includes = conf->includes; if (conf->reference) + { + pathname_make_slashes_portable(conf->reference); fprintf(file, "#reference \"%s\"\n", conf->reference); + } list = config_file_merge_sort_linked_list( @@ -1338,7 +1346,10 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort) struct config_include_list *includes = conf->includes; if (conf->reference) + { + pathname_make_slashes_portable(conf->reference); fprintf(file, "#reference \"%s\"\n", conf->reference); + } if (sort) list = config_file_merge_sort_linked_list( diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 44ceb7249a..0ab95453da 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -1110,6 +1110,100 @@ void fill_pathname_abbreviate_special(char *out_path, retro_assert(strlcpy(out_path, in_path, size) < size); } +/* Changes the slashes to the correct kind for the os + * So forward slash on linux and backslash on Windows */ +void pathname_conform_slashes_to_os(char *path) +{ + /* Conform slashes to os standard so we get proper matching */ + char* p; + for (p = path; *p; p++) + if (*p == '/' || *p == '\\') + *p = PATH_DEFAULT_SLASH_C(); +} + +/* Change all shashes to forward so they are more portable between windows and linux */ +void pathname_make_slashes_portable(char *path) +{ + /* Conform slashes to os standard so we get proper matching */ + char* p; + for (p = path; *p; p++) + if (*p == '/' || *p == '\\') + *p = '/'; +} + +/* Get the number of slashes in a path, returns an integer */ +int get_pathname_num_slashes(const char *in_path) +{ + int num_slashes = 0; + int i = 0; + + for (i = 0; i < PATH_MAX_LENGTH; i++) + { + if (PATH_CHAR_IS_SLASH(in_path[i])) + num_slashes++; + if (in_path[i] == '\0') + break; + } + + return num_slashes; +} + +/* Fills the supplied path with either the abbreviated path or the relative path, which ever + * one is has less depth / number of slashes + * If lengths of abbreviated and relative paths are the same the relative path will be used + * in_path can be an absolute, relative or abbreviated path */ +void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size) +{ + unsigned relative_length = 0; + unsigned abbreviated_length = 0; + + char in_path_conformed[PATH_MAX_LENGTH]; + char in_refpath_conformed[PATH_MAX_LENGTH]; + char expanded_path[PATH_MAX_LENGTH]; + char absolute_path[PATH_MAX_LENGTH]; + char relative_path[PATH_MAX_LENGTH]; + char abbreviated_path[PATH_MAX_LENGTH]; + + in_path_conformed[0] = '\0'; + in_refpath_conformed[0] = '\0'; + absolute_path[0] = '\0'; + relative_path[0] = '\0'; + abbreviated_path[0] = '\0'; + + strcpy(in_path_conformed, in_path); + strcpy(in_refpath_conformed, in_refpath); + + pathname_conform_slashes_to_os(in_path_conformed); + pathname_conform_slashes_to_os(in_refpath_conformed); + + /* Expand paths which start with :\ to an absolute path */ + fill_pathname_expand_special(expanded_path, in_path_conformed, sizeof(expanded_path)); + + /* Get the absolute path if it is not already */ + if (path_is_absolute(expanded_path)) + strlcpy(absolute_path, expanded_path, PATH_MAX_LENGTH); + else + fill_pathname_resolve_relative(absolute_path, in_refpath_conformed, in_path_conformed, PATH_MAX_LENGTH); + + pathname_conform_slashes_to_os(absolute_path); + + /* Get the relative path and see how many directories long it is */ + path_relative_to(relative_path, absolute_path, in_refpath_conformed, sizeof(relative_path)); + + /* Get the abbreviated path and see how many directories long it is */ + fill_pathname_abbreviate_special(abbreviated_path, absolute_path, sizeof(abbreviated_path)); + + /* Use the shortest path, preferring the relative path*/ + if (get_pathname_num_slashes(relative_path) <= get_pathname_num_slashes(abbreviated_path)) + { + retro_assert(strlcpy(out_path, relative_path, size) < size); + } + else + { + retro_assert(strlcpy(out_path, abbreviated_path, size) < size); + } +} + /** * path_basedir: * @path : path diff --git a/libretro-common/include/file/file_path.h b/libretro-common/include/file/file_path.h index 6f1918d136..4d5ed1e219 100644 --- a/libretro-common/include/file/file_path.h +++ b/libretro-common/include/file/file_path.h @@ -442,6 +442,12 @@ void fill_pathname_expand_special(char *out_path, void fill_pathname_abbreviate_special(char *out_path, const char *in_path, size_t size); +void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size); + +void pathname_conform_slashes_to_os(char *path); + +void pathname_make_slashes_portable(char *path); + /** * path_basedir: * @path : path diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c index 265a15b4df..72827157bb 100644 --- a/menu/cbs/menu_cbs_left.c +++ b/menu/cbs/menu_cbs_left.c @@ -364,7 +364,7 @@ static int action_left_shader_num_passes(unsigned type, const char *label, menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); - video_shader_resolve_parameters(NULL, shader); + video_shader_resolve_parameters(shader); shader->modified = true; diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 5093e55f91..0028bf7d6a 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1752,7 +1752,7 @@ static int generic_action_ok(const char *path, shader_pass->source.path, action_path, sizeof(shader_pass->source.path)); - video_shader_resolve_parameters(NULL, shader); + video_shader_resolve_parameters(shader); shader->modified = true; } @@ -5995,7 +5995,7 @@ static int action_ok_push_dropdown_item_video_shader_num_pass(const char *path, shader->passes = idx; - video_shader_resolve_parameters(NULL, shader); + video_shader_resolve_parameters(shader); shader->modified = true; diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c index fd5fd82e10..acc698f14f 100644 --- a/menu/cbs/menu_cbs_right.c +++ b/menu/cbs/menu_cbs_right.c @@ -380,7 +380,7 @@ static int action_right_shader_num_passes(unsigned type, const char *label, menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); - video_shader_resolve_parameters(NULL, shader); + video_shader_resolve_parameters(shader); shader->modified = true; diff --git a/retroarch.c b/retroarch.c index 0893172b38..f439e2ba10 100644 --- a/retroarch.c +++ b/retroarch.c @@ -5183,22 +5183,12 @@ bool menu_shader_manager_init(void) if (is_preset) { - config_file_t *conf = NULL; - - conf = video_shader_read_preset(path_shader); - - if (!conf) + if (!video_shader_load_preset_into_shader(path_shader, menu_shader)) { 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 { @@ -5225,7 +5215,6 @@ end: 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; @@ -5249,19 +5238,13 @@ bool menu_shader_manager_set_preset(struct video_shader *shader, * No point in updating when the Preset was * created from the menu itself. */ if ( !shader || - !(conf = video_shader_read_preset(preset_path))) + !(video_shader_load_preset_into_shader(preset_path, shader))) { 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); + RARCH_LOG("Menu shader set to: %s.\n", preset_path); ret = true; @@ -5694,7 +5677,7 @@ int menu_shader_manager_clear_num_passes(struct video_shader *shader) menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); #endif - video_shader_resolve_parameters(NULL, shader); + video_shader_resolve_parameters(shader); shader->modified = true; @@ -10410,6 +10393,9 @@ bool retroarch_apply_shader( if (!string_is_empty(preset_path)) preset_file = path_basename(preset_path); + /* TODO This loads the shader into the video driver + * But then we load the shader from disk twice more to put it in the menu + * We need to reconfigure this at some point to only load it once */ if (p_rarch->current_video->set_shader) ret = p_rarch->current_video->set_shader( p_rarch->video_driver_data, type, preset_path); diff --git a/ui/drivers/qt/shaderparamsdialog.cpp b/ui/drivers/qt/shaderparamsdialog.cpp index a428938eb2..1114394626 100644 --- a/ui/drivers/qt/shaderparamsdialog.cpp +++ b/ui/drivers/qt/shaderparamsdialog.cpp @@ -707,7 +707,7 @@ void ShaderParamsDialog::onShaderAddPassClicked() menu_driver_set_last_shader_pass_dir(pathData); #endif - video_shader_resolve_parameters(NULL, menu_shader); + video_shader_resolve_parameters(menu_shader); command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL); }