Shader_Preset_Simple_Save_Cleaned_2020_11_01

This commit is contained in:
HyperspaceMadness 2020-11-01 09:18:40 -05:00
parent a2a58147e7
commit 70bf90c5d8
14 changed files with 691 additions and 192 deletions

View file

@ -343,6 +343,10 @@
#define DEFAULT_SHADER_ENABLE false
#endif
/* When presets are saved they will be saved using the #reference
* directive by default */
#define DEFAULT_VIDEO_SHADER_PRESET_SAVE_REFERENCE_ENABLE true
#define DEFAULT_SHADER_DELAY 0
/* Only scale in integer steps.

View file

@ -1455,6 +1455,7 @@ static struct config_bool_setting *populate_settings_bool(
SETTING_BOOL("video_shader_enable", &settings->bools.video_shader_enable, true, DEFAULT_SHADER_ENABLE, false);
SETTING_BOOL("video_shader_watch_files", &settings->bools.video_shader_watch_files, true, DEFAULT_VIDEO_SHADER_WATCH_FILES, false);
SETTING_BOOL("video_shader_remember_last_dir", &settings->bools.video_shader_remember_last_dir, true, DEFAULT_VIDEO_SHADER_REMEMBER_LAST_DIR, false);
SETTING_BOOL("video_shader_preset_save_reference_enable", &settings->bools.video_shader_preset_save_reference_enable, true, DEFAULT_VIDEO_SHADER_PRESET_SAVE_REFERENCE_ENABLE, false);
/* Let implementation decide if automatic, or 1:1 PAR. */
SETTING_BOOL("video_aspect_ratio_auto", &settings->bools.video_aspect_ratio_auto, true, DEFAULT_ASPECT_RATIO_AUTO, false);

View file

@ -462,6 +462,7 @@ typedef struct settings
bool video_shader_enable;
bool video_shader_watch_files;
bool video_shader_remember_last_dir;
bool video_shader_preset_save_reference_enable;
bool video_threaded;
bool video_font_enable;
bool video_disable_composition;

View file

@ -417,6 +417,7 @@ static struct video_shader_parameter *video_shader_parse_find_parameter(
* @shader : Shader passes handle.
*
* Reads the current value for all parameters from config file.
* Checks for parameters in the parameter list which don't have a value set
*
* Returns: true (1) if successful, otherwise false (0).
**/
@ -440,6 +441,7 @@ bool video_shader_resolve_current_parameters(config_file_t *conf,
for ( id = strtok_r(parameters, ";", &save); id;
id = strtok_r(NULL, ";", &save))
{
/* Get the parameter in the shader matching this name */
struct video_shader_parameter *parameter =
(struct video_shader_parameter*)
video_shader_parse_find_parameter(
@ -465,6 +467,8 @@ bool video_shader_resolve_current_parameters(config_file_t *conf,
* @shader : Shader passes handle.
*
* Resolves all shader parameters belonging to shaders.
* Fills the parameter definition list of the shader
* Does not read any of the config parameter values
*
* Returns: true (1) if successful, otherwise false (0).
**/
@ -571,6 +575,375 @@ bool video_shader_resolve_parameters(config_file_t *conf,
return video_shader_resolve_current_parameters(conf, shader);
}
#ifdef _WIN32
static void make_relative_path_portable(char* path)
{
/* use '/' instead of '\' for maximum portability */
char* p;
for (p = path; *p; p++)
if (*p == '\\')
*p = '/';
}
#endif
/**
* video_shader_write_referenced_preset:
* @path : File to write to
* @shader : Shader preset to write
*
* Writes a referenced preset to disk
* A referenced preset is a preset which includes the #reference directive
* 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,
const struct video_shader *shader)
{
unsigned i;
bool ret = false;
bool continue_saving_reference = true;
char preset_dir[PATH_MAX_LENGTH];
config_file_t *conf;
char *absolute_root_preset_path = (char*)malloc(PATH_MAX_LENGTH);
char *absolute_new_preset_basedir = (char*)malloc(PATH_MAX_LENGTH);
char *relative_root_preset_path = (char*)malloc(PATH_MAX_LENGTH);
preset_dir[0] = '\0';
absolute_new_preset_basedir = strdup(path);
path_basedir(absolute_new_preset_basedir);
absolute_root_preset_path[0] = '\0';
relative_root_preset_path[0] = '\0';
/* Get the absolute path to the root preset, this is the one which is used in the #reference directive */
strlcpy(absolute_root_preset_path, shader->path, PATH_MAX_LENGTH);
if (string_is_empty(shader->path))
{
RARCH_WARN("[Shaders-Save Reference]: 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;
}
/* We can't save a reference to ourselves */
if (string_is_equal(shader->path, path))
{
RARCH_WARN("[Shaders-Save Reference]: Saving Full Preset because we can't save a preset "
"which would reference itself.\n");
continue_saving_reference = false;
}
/* Auto-shaders can be written as copies or references.
* If we write a reference to a copy, we could then overwrite the copy
* with any reference, thus creating a reference to a reference.
* To prevent this, we disallow saving references to auto-shaders. */
fill_pathname_join(preset_dir,
shader_dir,
"presets",
sizeof(preset_dir));
if (continue_saving_reference && !strncmp(preset_dir, absolute_root_preset_path, strlen(preset_dir)))
{
RARCH_WARN("[Shaders-Save Reference]: Saving Full Preset because we can't save a "
"reference to an auto-loaded shader (E.G. Game Preset, Core Preset).\n");
continue_saving_reference = false;
}
/* Don't ever create a reference to the ever-changing retroarch preset
* TODO remove once we don't write this preset anymore */
if (continue_saving_reference && !strncmp(path_basename(absolute_root_preset_path), "retroarch", STRLEN_CONST("retroarch")))
{
continue_saving_reference = false;
RARCH_WARN("[Shaders-Save Reference]: Saving Full Preset because we can't save a reference "
"to the ever-changing retroarch preset.\n");
}
if (continue_saving_reference)
{
config_file_t *root_conf;
path_relative_to(relative_root_preset_path,
absolute_root_preset_path,
absolute_new_preset_basedir,
PATH_MAX_LENGTH);
#ifdef _WIN32
if (!path_is_absolute(relative_root_preset_path))
make_relative_path_portable(relative_root_preset_path);
#endif
/* Create a new EMPTY config */
conf = config_file_new_alloc();
if (!(conf))
return false;
conf->path = strdup(path);
/* Add the reference path to the config */
config_file_set_reference_path(conf, relative_root_preset_path);
/* Set modified to true so when you run config_file_write it will save a file */
conf->modified = true;
/* Get a config from root preset which was defined by the #reference directive
* to compare the current shader against */
root_conf = config_file_new_from_path_to_string(absolute_root_preset_path);
/* root_conf could be NULL if the file was not found */
if (root_conf == NULL)
RARCH_WARN("[Shaders-Save Reference]: Saving Full Preset because we could not "
"load the Root Preset: %s.\n",
absolute_root_preset_path);
else
{
/*
Compare the shader to a shader created from the root config to see if
we can save a referenced preset and what parameters and textures of the
root_config are overridden
*/
struct video_shader *root_shader = NULL;
root_shader = (struct video_shader*) calloc(1, sizeof(*root_shader));
video_shader_read_conf_preset(root_conf, root_shader);
/* Check number of passes match */
if (shader->passes != root_shader->passes)
{
RARCH_WARN("[Shaders-Save Reference]: passes (Number of Passes)");
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)
{
/* 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 Reference]: Pass %u path", i);
continue_saving_reference = false;
}
if (continue_saving_reference && pass->filter != root_pass->filter)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u filter", i);
continue_saving_reference = false;
}
if (continue_saving_reference && pass->wrap != root_pass->wrap)
{
RARCH_WARN("[Shaders-Save Reference]: 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 Reference]: Pass %u frame_count", i);
continue_saving_reference = false;
}
if (continue_saving_reference && pass->mipmap != root_pass->mipmap)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u mipmap", i);
continue_saving_reference = false;
}
if (continue_saving_reference && !string_is_equal(pass->alias, root_pass->alias))
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u alias", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->type_x != root_fbo->type_x)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u type_x", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->type_y != root_fbo->type_y)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u type_y", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->scale_x != root_fbo->scale_x)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u scale_x", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->scale_y != root_fbo->scale_y)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u scale_y", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->fp_fbo != root_fbo->fp_fbo)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u fp_fbo", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->srgb_fbo != root_fbo->srgb_fbo)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u srgb_fbo", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->valid != root_fbo->valid)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u valid", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->abs_x != root_fbo->abs_x)
{
RARCH_WARN("[Shaders-Save Reference]: Pass %u abs_x", i);
continue_saving_reference = false;
}
if (continue_saving_reference && fbo->abs_y != root_fbo->abs_y)
{
RARCH_WARN("[Shaders-Save Reference]: 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");
}
}
if (continue_saving_reference)
{
const struct config_entry_list *entry = NULL;
/* If the shader has parameters */
if (shader->num_parameters)
{
size_t param_size = 4096 * sizeof(char);
char *override_parameters = (char*)malloc(param_size);
float parameter_value_reference;
param_size = 4096 * sizeof(char);
override_parameters[0] = '\0';
parameter_value_reference = 0.0f;
if (override_parameters)
{
unsigned i;
for (i = 0; i < shader->num_parameters; i++)
{
bool add_param_to_override = false;
entry = config_get_entry(root_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(root_conf, shader->parameters[i].id, &parameter_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 name to the parameters list */
if (add_param_to_override)
{
config_set_float(conf, shader->parameters[i].id, shader->parameters[i].current);
strlcat(override_parameters, ";", param_size);
strlcat(override_parameters, shader->parameters[i].id, param_size);
}
}
/* Write the list of override parameter names if there are any*/
if (!string_is_empty(override_parameters))
config_set_string(conf, "parameters", override_parameters);
}
free(override_parameters);
}
/* If the shader has textures */
if (shader->luts)
{
char *shader_tex_path = (char*)malloc(3*PATH_MAX_LENGTH);
char *shader_tex_relative_path = shader_tex_path + PATH_MAX_LENGTH;
char *shader_tex_base_path = shader_tex_path + 2*PATH_MAX_LENGTH;
char *referenced_tex_absolute_path = (char*)malloc(PATH_MAX_LENGTH);
char *referenced_tex_path = (char*)malloc(PATH_MAX_LENGTH);
size_t tex_size = 4096 * sizeof(char);
char *textures = (char*)malloc(tex_size);
unsigned i;
shader_tex_path[0] = '\0';
shader_tex_relative_path[0] = '\0';
shader_tex_base_path[0] = '\0';
textures[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(root_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,
root_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 Reference]: 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);
}
}
}
}
/* Write the file, return will be true if successful */
ret = config_file_write(conf, path, false);
if (!ret)
RARCH_WARN("[Shaders-Save Reference]: Failed writing Referenced Preset to %s - "
"Full Preset Will be Saved instead of Simple Preset\n", path);
}
config_file_free(root_conf);
}
config_file_free(conf);
}
free(relative_root_preset_path);
return ret;
}
/**
* video_shader_write_preset:
* @path : File to write to
@ -586,9 +959,9 @@ bool video_shader_write_preset(const char *path,
{
/* We need to clean up paths to be able to properly process them
* path and shader->path can use '/' on Windows due to Qt being Qt */
char clean_path[PATH_MAX_LENGTH];
char clean_shader_path[PATH_MAX_LENGTH];
char preset_dir[PATH_MAX_LENGTH];
config_file_t *conf;
bool ret;
if (!shader || string_is_empty(path))
return false;
@ -599,178 +972,160 @@ bool video_shader_write_preset(const char *path,
"presets",
sizeof(preset_dir));
strlcpy(clean_shader_path, shader->path, sizeof(clean_shader_path));
path_resolve_realpath(clean_shader_path, sizeof(clean_shader_path), false);
if (string_is_empty(shader->path))
reference = false;
/* Auto-shaders can be written as copies or references.
* If we write a reference to a copy, we could then overwrite the copy
* with any reference, thus creating a reference to a reference.
* To prevent this, we disallow saving references to auto-shaders. */
if (reference && !strncmp(preset_dir, clean_shader_path, strlen(preset_dir)))
reference = false;
/* Don't ever create a reference to the ever-changing retroarch preset
* TODO remove once we don't write this preset anymore */
if (reference && !strncmp(path_basename(clean_shader_path), "retroarch", STRLEN_CONST("retroarch")))
reference = false;
/* If we should still save a referenced preset do it now */
if (reference)
{
/* write a reference preset */
char buf[STRLEN_CONST("#reference \"") + PATH_MAX_LENGTH + 1] = "#reference \"";
size_t len = STRLEN_CONST("#reference \"");
char *preset_ref = buf + len;
if (video_shader_write_referenced_preset(path, shader_dir, shader))
return true;
strlcpy(clean_path, path, sizeof(clean_path));
path_resolve_realpath(clean_path, sizeof(clean_path), false);
/* If we aren't saving a referenced preset or weren't able to save one
* then save a full preset */
path_relative_to(preset_ref, clean_shader_path, clean_path, PATH_MAX_LENGTH);
len += strlen(preset_ref);
/* 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;
buf[len++] = '\"';
video_shader_write_conf_preset(conf, shader, path);
return filestream_write_file(clean_path, (void *)buf, len);
}
else
{
/* regular saving function */
config_file_t *conf;
bool ret;
ret = config_file_write(conf, path, false);
/* 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;
config_file_free(conf);
video_shader_write_conf_preset(conf, shader, path);
ret = config_file_write(conf, path, false);
config_file_free(conf);
return ret;
}
return ret;
}
/**
* video_shader_read_reference_path:
* @path : File to read
* override_config_values:
* @conf : Config file to be affected
* @override_conf : Config file who's values will be copied on top of conf
*
* Returns: the reference path of a preset if it exists,
* otherwise returns NULL.
* Takes values from override_config and overrides values of conf
* The 'parameters' value will be the combined parameter list from both configs
*
* The returned string needs to be freed.
*/
static char *video_shader_read_reference_path(const char *path)
* 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)
{
/* We want shader presets that point to other presets.
*
* While config_file_new_from_path_to_string() does support the
* #include directive, it will not rebase relative paths on
* the include path.
*
* There's a plethora of reasons why a general solution is hard:
* - it's impossible to distinguish a generic string from a (relative) path
* - config_file_new_from_path_to_string() doesn't return the include path,
* so we cannot rebase afterwards
* - #include is recursive, so we'd actually need to track the include path
* for every setting
*
* So instead, we use a custom #reference directive, which is just a
* one-time/non-recursive redirection, e.g.
*
* #reference "<path to config>"
* or
* #reference <path to config>
*
* which we will load as config_file_new_from_path_to_string(<path to config>).
*/
char *reference = NULL;
RFILE *file = NULL;
char *line = NULL;
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;
char *override_parameters = (char*)malloc(param_size);
if (string_is_empty(path) || !path_is_valid(path))
return NULL;
file = filestream_open(path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!file)
return NULL;
override_parameters[0] = '\0';
textures_in_conf[0] = '\0';
strlcpy(tmp_base, conf->path, tmp_size);
line = filestream_getline(file);
filestream_close(file);
if (conf == NULL || override_conf == NULL) return 0;
if (line && !strncmp("#reference", line, STRLEN_CONST("#reference")))
{
char *ref_path = line + STRLEN_CONST("#reference");
/* ---------------------------------------------------------------------------------
* ------------- Resolve Override texture paths to absolute paths-------------------
* --------------------------------------------------------------------------------- */
/* have at least 1 whitespace */
if (!isspace((unsigned char)*ref_path))
/* 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))
{
free(line);
return NULL;
}
ref_path++;
while (isspace((unsigned char)*ref_path))
ref_path++;
if (*ref_path == '\"')
{
/* remove "" */
char *p;
ref_path++;
p = ref_path;
while (*p != '\0' && *p != '\"')
p++;
if (*p == '\"')
*p = '\0';
else
for ( id = strtok_r(textures_in_conf, ";", &save);
id;
id = strtok_r(NULL, ";", &save))
{
/* if there's no second ", remove whitespace at the end */
p--;
while (isspace((unsigned char)*p))
*p-- = '\0';
/* 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;
}
}
}
else
/* ---------------------------------------------------------------------------------
* -------------Update Parameter List to include Override Parameters----------------
* --------------------------------------------------------------------------------- */
/* If there is a 'parameters' entry in the override config we want to add these parameters
* to the referenced config if they are not already there */
if (config_get_array(override_conf, "parameters", override_parameters, param_size))
{
/* remove whitespace at the end (e.g. carriage return) */
char *end = ref_path + strlen(ref_path) - 1;
while (isspace((unsigned char)*end))
*end-- = '\0';
/* Get the string for the parameters from the root config */
char *parameters = NULL;
parameters = (char*)malloc(param_size);
parameters[0] = '\0';
/* If there are is no parameters entry in the root config, add one */
if (!config_get_array(conf, "parameters", parameters, param_size))
{
config_set_string(conf, "parameters", "");
config_get_array(conf, "parameters", parameters, param_size);
}
/* Step through each parameter in override config */
for ( id = strtok_r(override_parameters, ";", &save);
id;
id = strtok_r(NULL, ";", &save))
{
/* If the parameter is not in the root config's parameter list add it */
if (!strstr(parameters, id))
{
strlcat(parameters, ";", param_size);
strlcat(parameters, id, param_size);
return_val = 1;
}
}
config_set_string(conf, "parameters", strdup(parameters));
free(parameters);
}
if (string_is_empty(ref_path))
/* ---------------------------------------------------------------------------------
* ------------- Update entries to match the override entries ----------------------
* --------------------------------------------------------------------------------- */
for (override_entry = override_conf->entries; override_entry; override_entry = override_entry->next)
{
free(line);
return NULL;
/* Only override an entry if the it's key is not "parameters", and not in list of textures */
if (!string_is_empty(override_entry->key) && !string_is_equal(override_entry->key, "parameters") && !string_is_equal(override_entry->key, "textures"))
{
RARCH_LOG("[Shaders-Load Reference]: Entry overridden %s = %s.\n",
override_entry->key, override_entry->value);
config_set_string(conf, override_entry->key, strdup(override_entry->value));
return_val = 1;
}
}
reference = (char *)malloc(PATH_MAX_LENGTH);
free(tmp);
free(resolved_path);
free(override_texture_path);
free(override_parameters);
free(textures_in_conf);
if (!reference)
{
free(line);
return NULL;
}
/* rebase relative reference path */
fill_pathname_resolve_relative(reference,
path, ref_path, PATH_MAX_LENGTH);
}
if (line)
free(line);
return reference;
return return_val;
}
/**
@ -787,15 +1142,52 @@ static char *video_shader_read_reference_path(const char *path)
**/
config_file_t *video_shader_read_preset(const char *path)
{
char *reference = video_shader_read_reference_path(path);
if (reference)
config_file_t *conf;
conf = config_file_new_from_path_to_string(path);
if (conf != NULL)
{
config_file_t *conf =
config_file_new_from_path_to_string(reference);
free(reference);
return conf;
/* If the original config had a reference then it was really
* the override config. We now load a new config from the reference
* then override it's values with the override config */
if (conf->reference)
{
char* root_preset_path = (char*)malloc(PATH_MAX_LENGTH);
/* Set override_conf to refer to the original config */
config_file_t *override_conf = conf;
/* Resolve the reference path relative to the config */
if (path_is_absolute(conf->reference))
strlcpy(root_preset_path, conf->reference, PATH_MAX_LENGTH);
else
fill_pathname_resolve_relative(root_preset_path,
conf->path,
conf->reference,
PATH_MAX_LENGTH);
/* Create a new config from the root preset */
conf = config_file_new_from_path_to_string(root_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("[ SHADER LOAD ] Could not read root shader preset in '#reference' line: %s\n", root_preset_path);
free(root_preset_path);
config_file_free(override_conf);
}
/* Set Path for originally loaded preset */
config_set_path(conf, "loaded_preset_path", path);
}
return config_file_new_from_path_to_string(path);
else
RARCH_WARN("[ SHADER LOAD ] Could not read preset: %s", path);
return conf;
}
/**
@ -815,6 +1207,7 @@ bool video_shader_read_conf_preset(config_file_t *conf,
unsigned shaders = 0;
settings_t *settings = config_get_ptr();
bool watch_files = settings->bools.video_shader_watch_files;
char loaded_preset_path[PATH_MAX_LENGTH];
memset(shader, 0, sizeof(*shader));
@ -826,7 +1219,7 @@ bool video_shader_read_conf_preset(config_file_t *conf,
if (!shaders)
{
RARCH_ERR("[Shaders]: Need to define at least 1 shader.\n");
RARCH_ERR("[Shaders]: Need to define at least 1 shader pass.\n");
return false;
}
@ -836,7 +1229,16 @@ bool video_shader_read_conf_preset(config_file_t *conf,
shader->passes = MIN(shaders, 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);
strlcpy( shader->loaded_preset_path,
loaded_preset_path,
sizeof(shader->loaded_preset_path));
if (watch_files)
{
@ -858,6 +1260,9 @@ bool video_shader_read_conf_preset(config_file_t *conf,
string_list_initialize(&file_list);
string_list_append(&file_list, conf->path, attr);
/* TODO We aren't currently watching the originally loaded preset
* We should probably watch it for changes too */
for (i = 0; i < shader->passes; i++)
{
if (!video_shader_parse_pass(conf, &shader->pass[i], i))
@ -944,17 +1349,6 @@ static void shader_write_fbo(config_file_t *conf,
fbo->scale_y, fbo->abs_y, i);
}
#ifdef _WIN32
static void make_relative_path_portable(char *path)
{
/* use '/' instead of '\' for maximum portability */
char *p;
for (p = path; *p; p++)
if (*p == '\\')
*p = '/';
}
#endif
/**
* video_shader_write_conf_preset:
* @conf : Preset file to write to.

View file

@ -153,8 +153,14 @@ struct video_shader
unsigned variables;
char prefix[64];
/* Path to the root preset */
char path[PATH_MAX_LENGTH];
/* Path to the original preset loaded, if this is a preset with the #reference
* directive then this will be different than the path*/
char loaded_preset_path[PATH_MAX_LENGTH];
bool modern; /* Only used for XML shaders. */
/* indicative of whether shader was modified -
* for instance from the menus */

View file

@ -3230,6 +3230,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE,
"video_shader_preset_save"
)
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
"video_shader_preset_save_reference"
)
MSG_HASH(
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS,
"video_shader_preset_save_as"

View file

@ -6674,6 +6674,16 @@ MSG_HASH(
/* Quick Menu > Shaders > Save */
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
"Save Simple Preset"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
"Saves a Shader Preset which has a link to the original preset loaded and includes only the parameter changes you made."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS,
"Save Shader Preset As"

View file

@ -181,7 +181,7 @@ static char *config_file_strip_comment(char *str)
*str = '\0';
return ++comment;
}
/* Comment character occurs at an offset:
* Search for the start of a string literal value */
literal_start = strchr(str, '\"');
@ -466,40 +466,48 @@ static bool config_file_parse_line(config_file_t *conf,
char real_path[PATH_MAX_LENGTH];
char *path = NULL;
char *include_line = NULL;
char *reference_line = NULL;
/* Starting a line with an 'include' directive
* appends a sub-config file
* > All other comments are ignored */
if (!string_starts_with_size(comment, "include ",
STRLEN_CONST("include ")))
STRLEN_CONST("include ")) &&
!string_starts_with_size(comment, "reference ",
STRLEN_CONST("reference ")))
return false;
include_line = comment + STRLEN_CONST("include ");
/* Starting a line with an 'include' directive
* appends a sub-config file */
if (string_starts_with_size(comment, "include ",
STRLEN_CONST("include ")))
{
include_line = comment + STRLEN_CONST("include ");
if (string_is_empty(include_line))
return false;
if (string_is_empty(include_line))
return false;
path = config_file_extract_value(include_line, false);
path = config_file_extract_value(include_line, false);
if (!path)
return false;
if (!path)
return false;
if ( string_is_empty(path)
|| conf->include_depth >= MAX_INCLUDE_DEPTH)
{
free(path);
return false;
}
{
free(path);
return false;
}
real_path[0] = '\0';
config_file_add_sub_conf(conf, path,
real_path[0] = '\0';
config_file_add_sub_conf(conf, path,
real_path, sizeof(real_path), cb);
config_file_initialize(&sub_conf);
config_file_initialize(&sub_conf);
switch (config_file_load_internal(&sub_conf, real_path,
conf->include_depth + 1, cb))
{
switch (config_file_load_internal(&sub_conf, real_path,
conf->include_depth + 1, cb))
{
case 0:
/* Pilfer internal list. */
config_file_add_child_list(conf, &sub_conf);
@ -510,6 +518,27 @@ static bool config_file_parse_line(config_file_t *conf,
case 1:
default:
break;
}
}
/* If it's a 'reference' directive */
if (string_starts_with_size(comment, "reference ",
STRLEN_CONST("reference ")))
{
reference_line = comment + STRLEN_CONST("reference ");
if (string_is_empty(reference_line))
return false;
path = config_file_extract_value(reference_line, false);
if (!path)
return false;
config_file_set_reference_path(conf, path);
if (!path)
return false;
}
free(path);
@ -617,6 +646,16 @@ static int config_file_from_string_internal(
return 0;
}
void config_file_set_reference_path(config_file_t *conf, char *path)
{
if (conf)
{
/* Assumes if you wanted a relative path the input path is
* already relative to the config
*/
conf->reference = strdup(path);
}
}
bool config_file_deinitialize(config_file_t *conf)
{
@ -774,6 +813,7 @@ void config_file_initialize(struct config_file *conf)
conf->entries = NULL;
conf->tail = NULL;
conf->last = NULL;
conf->reference = NULL;
conf->includes = NULL;
conf->include_depth = 0;
conf->guaranteed_no_duplicates = false;
@ -1245,6 +1285,10 @@ void config_file_dump_orbis(config_file_t *conf, int fd)
{
struct config_entry_list *list = NULL;
struct config_include_list *includes = conf->includes;
if (conf->reference)
fprintf(file, "#reference \"%s\"\n", conf->reference);
while (includes)
{
char cad[256];
@ -1278,6 +1322,9 @@ void config_file_dump(config_file_t *conf, FILE *file, bool sort)
struct config_entry_list *list = NULL;
struct config_include_list *includes = conf->includes;
if (conf->reference)
fprintf(file, "#reference \"%s\"\n", conf->reference);
while (includes)
{
fprintf(file, "#include \"%s\"\n", includes->path);

View file

@ -54,6 +54,7 @@ RETRO_BEGIN_DECLS
struct config_file
{
char *path;
char *reference;
struct config_entry_list *entries;
struct config_entry_list *tail;
struct config_entry_list *last;
@ -107,6 +108,8 @@ config_file_t *config_file_new_from_path_to_string(const char *path);
/* Frees config file. */
void config_file_free(config_file_t *conf);
void config_file_set_reference_path(config_file_t *conf, char *path);
bool config_file_deinitialize(config_file_t *conf);
/* Loads a new config, and appends its data to conf.

View file

@ -2893,6 +2893,11 @@ static int generic_action_ok_shader_preset_save(const char *path,
return 0;
}
/* Save Auto Preset and have it immediately reapply the preset
* TODO: This seems necessary so that the loaded shader gains a link to the file saved
* But this is slow and seems like a redundant way to do this
* It seems like it would be better to just set the path and shader_preset_loaded
* on the current shader */
if (menu_shader_manager_save_auto_preset(menu_shader_get(), preset_type,
dir_video_shader, dir_menu_config,
true))

View file

@ -5311,6 +5311,10 @@ unsigned menu_displaylist_build_list(
case DISPLAYLIST_SHADER_PRESET_SAVE:
{
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (menu_entries_append_enum(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS),
msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS),

View file

@ -9170,6 +9170,21 @@ static bool setting_append_list(
general_read_handler,
SD_FLAG_NONE);
CONFIG_BOOL(
list, list_info,
&settings->bools.video_shader_preset_save_reference_enable,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
DEFAULT_VIDEO_SHADER_PRESET_SAVE_REFERENCE_ENABLE,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
END_SUB_GROUP(list, list_info, parent_group);
END_GROUP(list, list_info, parent_group);
}

View file

@ -579,7 +579,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_NORD,
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_GRUVBOX_DARK,
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_BOYSENBERRY,
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_HACKING_THE_KERNEL,
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_HACKING_THE_KERNEL,
MENU_ENUM_LABEL_VALUE_OZONE_COLOR_THEME_TWILIGHT_ZONE,
MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME,
@ -2325,6 +2325,7 @@ enum msg_hash_enums
MENU_LABEL(VIDEO_SHADER_PRESET_REMOVE_PARENT),
MENU_LABEL(VIDEO_SHADER_PRESET_REMOVE_GAME),
MENU_LABEL(VIDEO_SHADER_PRESET_SAVE),
MENU_LABEL(VIDEO_SHADER_PRESET_SAVE_REFERENCE),
MENU_LABEL(VIDEO_SHADER_PRESET_SAVE_AS),
MENU_LABEL(VIDEO_SHADER_PRESET_SAVE_GLOBAL),
MENU_LABEL(VIDEO_SHADER_PRESET_SAVE_CORE),

View file

@ -8063,7 +8063,9 @@ bool menu_shader_manager_init(void)
video_shader_driver_get_current_shader(&shader_info);
if (shader_info.data)
path_shader = shader_info.data->path;
/* Use the path of the originally loaded preset because it could
* have been a preset with a #reference in it to another preset */
path_shader = shader_info.data->loaded_preset_path;
else
path_shader = retroarch_get_shader_preset();
@ -8195,9 +8197,10 @@ clear:
}
static bool menu_shader_manager_save_preset_internal(
const struct video_shader *shader, const char *basename,
const struct video_shader *shader,
const char *basename,
const char *dir_video_shader,
bool apply, bool save_reference,
bool apply,
const char **target_dirs,
size_t num_target_dirs)
{
@ -8208,6 +8211,10 @@ static bool menu_shader_manager_save_preset_internal(
char fullname[PATH_MAX_LENGTH];
char buffer[PATH_MAX_LENGTH];
struct rarch_state *p_rarch = &rarch_st;
settings_t *settings = p_rarch->configuration_settings;
bool save_reference = settings->bools.video_shader_preset_save_reference_enable;
fullname[0] = buffer[0] = '\0';
if (!shader || !shader->passes)
@ -8218,9 +8225,6 @@ static bool menu_shader_manager_save_preset_internal(
if (type == RARCH_SHADER_NONE)
return false;
if (shader->modified)
save_reference = false;
if (!string_is_empty(basename))
{
/* We are comparing against a fixed list of file
@ -8396,7 +8400,7 @@ static bool menu_shader_manager_operate_auto_preset(
return menu_shader_manager_save_preset_internal(
shader, file,
dir_video_shader,
apply, true,
apply,
auto_preset_dirs,
ARRAY_SIZE(auto_preset_dirs));
case AUTO_SHADER_OP_REMOVE:
@ -8546,7 +8550,7 @@ bool menu_shader_manager_save_preset(const struct video_shader *shader,
return menu_shader_manager_save_preset_internal(
shader, basename,
dir_video_shader,
apply, false,
apply,
preset_dirs,
ARRAY_SIZE(preset_dirs));
}