RetroArch/gfx/video_shader_parse.c

3203 lines
106 KiB
C
Raw Normal View History

/* RetroArch - A frontend for libretro.
2014-01-01 01:50:59 +01:00
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2017-01-22 13:40:32 +01:00
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http:www.gnu.org/licenses/>.
*/
2014-06-17 20:42:38 +02:00
#include <stdlib.h>
#include <string.h>
2015-10-31 20:53:08 +01:00
2018-03-02 01:41:05 +01:00
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
2017-12-15 00:31:37 +01:00
#include <libretro.h>
2014-10-21 07:58:58 +02:00
#include <compat/posix_string.h>
#include <compat/msvc.h>
#include <compat/strl.h>
2014-10-22 00:23:06 +02:00
#include <file/file_path.h>
#include <lrc_hash.h>
2016-01-20 04:07:24 +01:00
#include <string/stdstring.h>
#include <streams/file_stream.h>
#include <lists/dir_list.h>
#include <lists/string_list.h>
2015-06-14 19:02:53 +02:00
#ifdef HAVE_MENU
#include "../menu/menu_driver.h"
#include "../menu/menu_shader.h"
#endif
#include "../configuration.h"
#include "../verbosity.h"
#include "../frontend/frontend_driver.h"
#include "../command.h"
2021-10-15 14:32:07 +02:00
#include "../list_special.h"
#include "../file_path_special.h"
#include "../paths.h"
2020-02-17 12:27:08 +01:00
#include "../retroarch.h"
2021-10-29 14:13:16 +02:00
#if defined(HAVE_GFX_WIDGETS)
#include "gfx_widgets.h"
#endif
2015-06-14 19:02:53 +02:00
#include "video_shader_parse.h"
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
#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
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
#define SHADER_NUM_WILDCARDS 15
struct wildcard_token wildcard_tokens[SHADER_NUM_WILDCARDS] = {
{RARCH_WILDCARD_CONTENT_DIR, "$CONTENT-DIR$"},
{RARCH_WILDCARD_CORE, "$CORE$"},
{RARCH_WILDCARD_GAME, "$GAME$"},
{RARCH_WILDCARD_VIDEO_DRIVER, "$VID-DRV$"},
{RARCH_WILDCARD_VIDEO_DRIVER_PRESET_EXT, "$VID-DRV-PRESET-EXT$"},
{RARCH_WILDCARD_VIDEO_DRIVER_SHADER_EXT, "$VID-DRV-SHADER-EXT$"},
{RARCH_WILDCARD_CORE_REQUESTED_ROTATION, "$CORE-REQ-ROT$"},
{RARCH_WILDCARD_VIDEO_ALLOW_CORE_ROTATION, "$VID-ALLOW-CORE-ROT$"},
{RARCH_WILDCARD_VIDEO_USER_ROTATION, "$VID-USER-ROT$"},
{RARCH_WILDCARD_VIDEO_FINAL_ROTATION, "$VID-FINAL-ROT$"},
{RARCH_WILDCARD_SCREEN_ORIENTATION, "$SCREEN-ORIENT$"},
{RARCH_WILDCARD_VIEWPORT_ASPECT_ORIENTATION, "$VIEW-ASPECT-ORIENT$"},
{RARCH_WILDCARD_CORE_ASPECT_ORIENTATION, "$CORE-ASPECT-ORIENT$"},
{RARCH_WILDCARD_PRESET_DIR, "$PRESET-DIR$"},
{RARCH_WILDCARD_PRESET, "$PRESET$"},
};
2020-05-29 06:17:39 +02:00
/* TODO/FIXME - global state - perhaps move outside this file */
static path_change_data_t *file_change_data = NULL;
/**
* fill_pathname_expanded_and_absolute:
2022-07-15 01:12:04 +02:00
* @param out_path
* String to write into.
* @param in_refpath
* Used to get the base path if in_path is relative.
* @param in_path
* Path to turn into an absolute path.
*
2022-07-15 01:12:04 +02:00
* 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
2022-07-15 01:12:04 +02:00
* absolute path using in_refpath as the path to extract a base path.
*
* out_path is filled with the absolute path
**/
static void fill_pathname_expanded_and_absolute(char *out_path,
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
const char *in_refpath,
const char *in_path)
{
char expanded_path[PATH_MAX_LENGTH];
2022-08-12 22:09:33 +02:00
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);
2020-12-27 20:32:43 -05:00
pathname_conform_slashes_to_os(out_path);
}
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/**
* replace_wildcards:
*
* @param inout_absolute_path
* Absolute path to replace wildcards in
*
* @param in_preset_path
* Path of the preset that this path is being used in
*
* All the wildcards are replaced by the live values which come from retroarch
* or the preset context
*
* Possible wildcards/tokens to be replaced:
*
* $CONTENT-DIR$ -> Content Directory of the game rom
*
* $CORE$ -> Core name
*
* $GAME$ -> Game ROM's name
*
* $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values:
* glcore
* gl
* vulkan
* d3d11
* d3d9_hlsl
* "N/A"
*
* $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver:
* cg
* glsl
* slang
*
* $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver:
* cgp
* glslp
* slangp
*
* $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values:
* CORE-REQ-ROT-0
* CORE-REQ-ROT-90
* CORE-REQ-ROT-180
* CORE-REQ-ROT-270
*
* $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflect's Retroarch's setting allowing the core requested rotation to affect the final rotation:
* VID-ALLOW-CORE-ROT-OFF
* VID-ALLOW-CORE-ROT-ON
*
* $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI:
* VID-USER-ROT-0
* VID-USER-ROT-90
* VID-USER-ROT-180
* VID-USER-ROT-270
*
* $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI:
* VID-FINAL-ROT-0
* VID-FINAL-ROT-90
* VID-FINAL-ROT-180
* VID-FINAL-ROT-270
*
* $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI:
* SCREEN-ORIENT-0
* SCREEN-ORIENT-90
* SCREEN-ORIENT-180
* SCREEN-ORIENT-270
*
* $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the retroarch viewport
* VIEW-ASPECT-ORIENT-HORZ
* VIEW-ASPECT-ORIENT-VERT
*
* $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core
* CORE-ASPECT-ORIENT-HORZ
* CORE-ASPECT-ORIENT-VERT
*
* $PRESET_DIR$ -> Preset directory's name
*
* $PRESET$ -> Preset's name
*
* If no wildcards are found within the path, or the path
* after replacing the wildcards does not exist on disk,
* the path returned will be uneffected.
**/
static void replace_wildcards(char *inout_absolute_path, const unsigned in_absolute_path_length, char *in_preset_path)
{
int i = 0;
char replaced_path[PATH_MAX_LENGTH] = "";
if (!strstr(inout_absolute_path, RARCH_WILDCARD_DELIMITER))
return;
strlcpy(replaced_path, inout_absolute_path, sizeof(replaced_path));
/* Step through the wildcards while we can still find the
* delimiter in the replaced path
*/
for (i = 0; (i < SHADER_NUM_WILDCARDS) && (strstr(replaced_path, RARCH_WILDCARD_DELIMITER)); i++)
{
/* If the wildcard text is in the path then process it */
if (strstr(replaced_path, wildcard_tokens[i].token_name))
{
char replace_text[PATH_MAX_LENGTH] = "";
switch (wildcard_tokens[i].token_id)
{
case RARCH_WILDCARD_CONTENT_DIR:
{
char content_dir_name[PATH_MAX_LENGTH] = "";
const char* rarch_path_basename = path_get(RARCH_PATH_BASENAME);
if (rarch_path_basename)
{
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename,
sizeof(content_dir_name));
}
if (string_is_not_equal_fast(content_dir_name, "", sizeof("")))
{
strlcpy(content_dir_name,
path_basename_nocompression(content_dir_name),
sizeof(content_dir_name));
}
if (string_is_not_equal_fast(content_dir_name, "", sizeof("")))
path_remove_extension(content_dir_name);
if (string_is_not_equal_fast(content_dir_name, "", sizeof("")))
strlcpy(replace_text, content_dir_name, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_CORE:
{
runloop_state_t* runloop_st = runloop_state_get_ptr();
strlcpy(replace_text, runloop_st->system.info.library_name, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_GAME:
{
const char* path_basename = path_get(RARCH_PATH_BASENAME);
if (path_basename)
path_basename = path_basename_nocompression(path_basename);
if (path_basename)
strlcpy(replace_text, path_basename, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_DRIVER:
{
strlcpy(replace_text, config_get_ptr()->arrays.video_driver, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_CORE_REQUESTED_ROTATION:
{
char rotation_replace_strings[4][PATH_MAX_LENGTH] = {
"CORE-REQ-ROT-0",
"CORE-REQ-ROT-90",
"CORE-REQ-ROT-180",
"CORE-REQ-ROT-270"
};
strlcpy(replace_text, rotation_replace_strings[retroarch_get_core_requested_rotation()], sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_ALLOW_CORE_ROTATION:
{
if (config_get_ptr()->bools.video_allow_rotate)
strlcpy(replace_text, "VID-ALLOW-CORE-ROT-ON", sizeof(replace_text));
else
strlcpy(replace_text, "VID-ALLOW-CORE-ROT-OFF", sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_USER_ROTATION:
{
char rotation_replace_strings[4][PATH_MAX_LENGTH] = {
"VID-USER-ROT-0",
"VID-USER-ROT-90",
"VID-USER-ROT-180",
"VID-USER-ROT-270"
};
strlcpy(replace_text, rotation_replace_strings[retroarch_get_video_rotation()], sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_FINAL_ROTATION:
{
char rotation_replace_strings[4][PATH_MAX_LENGTH] = {
"VID-FINAL-ROT-0",
"VID-FINAL-ROT-90",
"VID-FINAL-ROT-180",
"VID-FINAL-ROT-270"
};
strlcpy(replace_text, rotation_replace_strings[retroarch_get_rotation()], sizeof(replace_text));
break;
}
case RARCH_WILDCARD_SCREEN_ORIENTATION:
{
char rotation_replace_strings[4][PATH_MAX_LENGTH] = {
"SCREEN-ORIENT-0",
"SCREEN-ORIENT-90",
"SCREEN-ORIENT-180",
"SCREEN-ORIENT-270"
};
strlcpy(replace_text, rotation_replace_strings[config_get_ptr()->uints.screen_orientation], sizeof(replace_text));
break;
}
case RARCH_WILDCARD_CORE_ASPECT_ORIENTATION:
{
const int requested_rotation = retroarch_get_core_requested_rotation();
strlcpy(replace_text, (video_driver_get_core_aspect() < 1 || requested_rotation == 1 || requested_rotation == 3) ?
"CORE-ASPECT-ORIENT-VERT" :
"CORE-ASPECT-ORIENT-HORZ",
sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIEWPORT_ASPECT_ORIENTATION:
{
unsigned viewport_width = 0;
unsigned viewport_height = 0;
video_driver_get_size(&viewport_width, &viewport_height);
strlcpy(replace_text, ((float)viewport_width / viewport_height < 1) ?
"VIEW-ASPECT-ORIENT-VERT" :
"VIEW-ASPECT-ORIENT-HORZ",
sizeof(replace_text));
break;
}
case RARCH_WILDCARD_PRESET_DIR:
{
char preset_dir_name[PATH_MAX_LENGTH] = "";
fill_pathname_parent_dir_name(preset_dir_name, in_preset_path, sizeof(preset_dir_name));
if (string_is_not_equal_fast(preset_dir_name, "", sizeof("")))
strlcpy(preset_dir_name, path_basename_nocompression(preset_dir_name), sizeof(preset_dir_name));
if (string_is_not_equal_fast(preset_dir_name, "", sizeof("")))
path_remove_extension(preset_dir_name);
if (string_is_not_equal_fast(preset_dir_name, "", sizeof("")))
strlcpy(replace_text, preset_dir_name, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_PRESET:
{
char preset_name[PATH_MAX_LENGTH] = "";
strlcpy(preset_name, path_basename_nocompression(in_preset_path), sizeof(preset_name));
if (string_is_not_equal_fast(preset_name, "", sizeof("")))
path_remove_extension(preset_name);
if (string_is_not_equal_fast(preset_name, "", sizeof("")))
strlcpy(replace_text, preset_name, sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_DRIVER_SHADER_EXT:
{
if (video_shader_is_supported(RARCH_SHADER_CG))
strlcpy(replace_text, "cg", sizeof(replace_text));
else if (video_shader_is_supported(RARCH_SHADER_GLSL))
strlcpy(replace_text, "glsl", sizeof(replace_text));
else if (video_shader_is_supported(RARCH_SHADER_SLANG))
strlcpy(replace_text, "slang", sizeof(replace_text));
break;
}
case RARCH_WILDCARD_VIDEO_DRIVER_PRESET_EXT:
{
if (video_shader_is_supported(RARCH_SHADER_CG))
strlcpy(replace_text, "cgp", sizeof(replace_text));
else if (video_shader_is_supported(RARCH_SHADER_GLSL))
strlcpy(replace_text, "glslp", sizeof(replace_text));
else if (video_shader_is_supported(RARCH_SHADER_SLANG))
strlcpy(replace_text, "slangp", sizeof(replace_text));
break;
}
}
{
char *replace_output = NULL;
replace_output = string_replace_substring(replaced_path,
wildcard_tokens[i].token_name, strlen(wildcard_tokens[i].token_name),
replace_text, strlen(replace_text));
strlcpy(replaced_path, replace_output, PATH_MAX_LENGTH);
free(replace_output);
}
}
}
/* If a file does not exist at the location of the replaced path
* then output the original path instead */
if (!path_is_valid(replaced_path))
{
RARCH_DBG("\n[Shaders]: Filepath after wildcard replacement can't be found:\n");
RARCH_DBG(" \"%s\" \n", replaced_path);
RARCH_DBG(" Falling back to original Filepath\n");
RARCH_DBG(" \"%s\" \n\n", inout_absolute_path);
}
else
{
strlcpy(inout_absolute_path, replaced_path, in_absolute_path_length);
}
return;
}
/**
* gather_reference_path_list:
*
* @param path_linked_list
* List of paths which accrues as we move down the chain of references
* @param path
* Current path of preset to process
* @param reference_depth
* This is used to check against the SHADER_MAX_REFERENCE_DEPTH
*
* @return void
**/
static void gather_reference_path_list(
struct path_linked_list *in_path_linked_list,
char *path,
int reference_depth)
{
config_file_t *conf = NULL;
if (reference_depth > SHADER_MAX_REFERENCE_DEPTH)
return;
if ((conf = config_file_new_from_path_to_string(path)))
{
struct path_linked_list *ref_tmp = (struct path_linked_list*)conf->references;
while (ref_tmp)
{
char* reference_preset_path = (char*)malloc(PATH_MAX_LENGTH);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(reference_preset_path, conf->path, ref_tmp->path);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
replace_wildcards(reference_preset_path, PATH_MAX_LENGTH, conf->path);
gather_reference_path_list(in_path_linked_list, reference_preset_path, reference_depth + 1);
free(reference_preset_path);
ref_tmp = ref_tmp->next;
}
path_linked_list_add_path(in_path_linked_list, path);
}
else
{
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
RARCH_WARN("\n[Shaders]: No Preset located at \"%s\".\n", path);
}
config_file_free(conf);
}
2015-01-11 19:59:59 +01:00
/**
* wrap_mode_to_str:
2022-07-15 01:12:04 +02:00
* @param type
* Wrap type.
2015-01-11 19:59:59 +01:00
*
* Translates wrap mode to human-readable string identifier.
*
2022-07-15 01:12:04 +02:00
* @return human-readable string identifier of wrap mode.
2015-01-11 19:59:59 +01:00
**/
static const char *wrap_mode_to_str(enum gfx_wrap_type type)
{
switch (type)
{
case RARCH_WRAP_BORDER:
return "clamp_to_border";
case RARCH_WRAP_EDGE:
return "clamp_to_edge";
case RARCH_WRAP_REPEAT:
return "repeat";
case RARCH_WRAP_MIRRORED_REPEAT:
return "mirrored_repeat";
default:
2015-10-11 09:31:04 +02:00
break;
}
2015-10-11 09:31:04 +02:00
return "???";
}
/**
2015-01-11 19:59:59 +01:00
* wrap_str_to_mode:
2022-07-15 01:12:04 +02:00
* @param type
* Wrap type in human-readable string format.
2015-01-11 19:59:59 +01:00
*
* Translates wrap mode from human-readable string to enum mode value.
*
2022-07-15 01:12:04 +02:00
* @return enum mode value of wrap type.
2015-01-11 19:59:59 +01:00
**/
static enum gfx_wrap_type wrap_str_to_mode(const char *wrap_mode)
{
if (string_is_equal(wrap_mode, "clamp_to_border"))
2018-02-25 01:07:14 +01:00
return RARCH_WRAP_BORDER;
else if (string_is_equal(wrap_mode, "clamp_to_edge"))
2018-02-25 01:07:14 +01:00
return RARCH_WRAP_EDGE;
else if (string_is_equal(wrap_mode, "repeat"))
2018-02-25 01:07:14 +01:00
return RARCH_WRAP_REPEAT;
else if (string_is_equal(wrap_mode, "mirrored_repeat"))
2018-02-25 01:07:14 +01:00
return RARCH_WRAP_MIRRORED_REPEAT;
2014-09-05 21:06:41 +02:00
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Invalid wrapping type \"%s\". Valid ones are: \"clamp_to_border\" "
"(default), \"clamp_to_edge\", \"repeat\" and \"mirrored_repeat\". Falling back to default.\n",
2014-09-05 21:06:41 +02:00
wrap_mode);
return RARCH_WRAP_DEFAULT;
}
/**
* video_shader_parse_pass:
2022-07-15 01:12:04 +02:00
* @param conf
* Preset file to read from.
* @param pass
* Shader passes handle.
* @param i
* Index of shader pass.
2015-01-11 19:59:59 +01:00
*
* Parses shader pass from preset file.
*
2022-07-15 01:12:04 +02:00
* @return true if successful, otherwise false.
2015-01-11 19:59:59 +01:00
**/
static bool video_shader_parse_pass(config_file_t *conf,
struct video_shader_pass *pass, unsigned i)
{
2016-10-21 06:10:58 +02:00
char shader_name[64];
char filter_name_buf[64];
char wrap_name_buf[64];
char frame_count_mod_buf[64];
char srgb_output_buf[64];
2016-12-19 19:17:23 +01:00
char fp_fbo_buf[64];
char mipmap_buf[64];
char alias_buf[64];
char scale_name_buf[64];
char attr_name_buf[64];
char scale_type[64];
char scale_type_x[64];
char scale_type_y[64];
char formatted_num[8];
char tmp_path[PATH_MAX_LENGTH];
struct gfx_fbo_scale *scale = NULL;
bool tmp_bool = false;
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] =
scale_type_x[0] = scale_type_y[0] =
shader_name[0] = filter_name_buf[0] = wrap_name_buf[0] =
frame_count_mod_buf[0] = srgb_output_buf[0] = '\0';
formatted_num[0] = '\0';
snprintf(formatted_num, sizeof(formatted_num), "%u", i);
2016-10-21 06:10:58 +02:00
2014-09-09 05:56:12 +02:00
/* Source */
strlcpy(shader_name, "shader", sizeof(shader_name));
strlcat(shader_name, formatted_num, sizeof(shader_name));
if (!config_get_path(conf, shader_name, tmp_path, sizeof(tmp_path)))
{
2022-01-31 19:05:23 +02:00
RARCH_ERR("[Shaders]: Couldn't parse shader source \"%s\".\n", shader_name);
return false;
}
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(pass->source.path, conf->path, tmp_path);
replace_wildcards(pass->source.path, PATH_MAX_LENGTH, conf->path);
2014-09-09 05:56:12 +02:00
/* Smooth */
strlcpy(filter_name_buf, "filter_linear", sizeof(filter_name_buf));
strlcat(filter_name_buf, formatted_num, sizeof(filter_name_buf));
2016-05-24 22:48:15 +02:00
if (config_get_bool(conf, filter_name_buf, &tmp_bool))
{
bool smooth = tmp_bool;
pass->filter = smooth ? RARCH_FILTER_LINEAR : RARCH_FILTER_NEAREST;
2016-05-24 22:48:15 +02:00
}
else
pass->filter = RARCH_FILTER_UNSPEC;
2014-09-09 05:56:12 +02:00
/* Wrapping mode */
strlcpy(wrap_name_buf, "wrap_mode", sizeof(wrap_name_buf));
strlcat(wrap_name_buf, formatted_num, sizeof(wrap_name_buf));
if ((entry = config_get_entry(conf, wrap_name_buf))
&& !string_is_empty(entry->value))
pass->wrap = wrap_str_to_mode(entry->value);
entry = NULL;
2014-09-09 05:56:12 +02:00
/* Frame count mod */
strlcpy(frame_count_mod_buf, "frame_count_mod", sizeof(frame_count_mod_buf));
strlcat(frame_count_mod_buf, formatted_num, sizeof(frame_count_mod_buf));
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;
2014-09-09 05:56:12 +02:00
/* FBO types and mipmapping */
strlcpy(srgb_output_buf, "srgb_framebuffer", sizeof(srgb_output_buf));
strlcat(srgb_output_buf, formatted_num, sizeof(srgb_output_buf));
2016-05-24 22:48:15 +02:00
if (config_get_bool(conf, srgb_output_buf, &tmp_bool))
{
if (tmp_bool)
pass->fbo.flags |= FBO_SCALE_FLAG_SRGB_FBO;
else
pass->fbo.flags &= ~FBO_SCALE_FLAG_SRGB_FBO;
}
2014-05-11 19:35:54 +02:00
strlcpy(fp_fbo_buf, "float_framebuffer", sizeof(fp_fbo_buf));
strlcat(fp_fbo_buf, formatted_num, sizeof(fp_fbo_buf));
2016-05-24 22:48:15 +02:00
if (config_get_bool(conf, fp_fbo_buf, &tmp_bool))
{
if (tmp_bool)
pass->fbo.flags |= FBO_SCALE_FLAG_FP_FBO;
else
pass->fbo.flags &= ~FBO_SCALE_FLAG_FP_FBO;
}
2014-05-11 13:13:38 +02:00
strlcpy(mipmap_buf, "mipmap_input", sizeof(mipmap_buf));
strlcat(mipmap_buf, formatted_num, sizeof(mipmap_buf));
2016-05-24 22:48:15 +02:00
if (config_get_bool(conf, mipmap_buf, &tmp_bool))
pass->mipmap = tmp_bool;
2014-05-11 13:13:38 +02:00
strlcpy(alias_buf, "alias", sizeof(alias_buf));
strlcat(alias_buf, formatted_num, sizeof(alias_buf));
if (!config_get_array(conf, alias_buf, pass->alias, sizeof(pass->alias)))
*pass->alias = '\0';
2014-09-09 05:56:12 +02:00
/* Scale */
scale = &pass->fbo;
strlcpy(scale_name_buf, "scale_type", sizeof(scale_name_buf));
strlcat(scale_name_buf, formatted_num, sizeof(scale_name_buf));
config_get_array(conf, scale_name_buf, scale_type, sizeof(scale_type));
strlcpy(scale_name_buf, "scale_type_x", sizeof(scale_name_buf));
strlcat(scale_name_buf, formatted_num, sizeof(scale_name_buf));
config_get_array(conf, scale_name_buf, scale_type_x, sizeof(scale_type_x));
strlcpy(scale_name_buf, "scale_type_y", sizeof(scale_name_buf));
strlcat(scale_name_buf, formatted_num, sizeof(scale_name_buf));
config_get_array(conf, scale_name_buf, scale_type_y, sizeof(scale_type_y));
if (*scale_type)
{
strlcpy(scale_type_x, scale_type, sizeof(scale_type_x));
strlcpy(scale_type_y, scale_type, sizeof(scale_type_y));
}
else if (!*scale_type_x && !*scale_type_y)
return true;
scale->flags |= FBO_SCALE_FLAG_VALID;
2015-06-14 19:02:53 +02:00
scale->type_x = RARCH_SCALE_INPUT;
scale->type_y = RARCH_SCALE_INPUT;
scale->scale_x = 1.0;
scale->scale_y = 1.0;
if (*scale_type_x)
{
if (string_is_equal(scale_type_x, "source"))
2018-02-25 01:07:14 +01:00
scale->type_x = RARCH_SCALE_INPUT;
else if (string_is_equal(scale_type_x, "viewport"))
2018-02-25 01:07:14 +01:00
scale->type_x = RARCH_SCALE_VIEWPORT;
else if (string_is_equal(scale_type_x, "absolute"))
2018-02-25 01:07:14 +01:00
scale->type_x = RARCH_SCALE_ABSOLUTE;
else
{
2022-01-31 19:05:23 +02:00
RARCH_ERR("[Shaders]: Invalid attribute: \"%s\".\n", scale_type_x);
return false;
}
}
if (*scale_type_y)
{
if (string_is_equal(scale_type_y, "source"))
2018-02-25 01:07:14 +01:00
scale->type_y = RARCH_SCALE_INPUT;
else if (string_is_equal(scale_type_y, "viewport"))
2018-02-25 01:07:14 +01:00
scale->type_y = RARCH_SCALE_VIEWPORT;
else if (string_is_equal(scale_type_y, "absolute"))
2018-02-25 01:07:14 +01:00
scale->type_y = RARCH_SCALE_ABSOLUTE;
else
{
2022-01-31 19:05:23 +02:00
RARCH_ERR("[Shaders]: Invalid attribute: \"%s\".\n", scale_type_y);
return false;
}
}
strlcpy(attr_name_buf, "scale", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
2018-08-14 18:44:19 -04:00
if (scale->type_x == RARCH_SCALE_ABSOLUTE)
{
int iattr = 0;
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
else
{
2023-01-22 16:29:03 +01:00
strlcpy(attr_name_buf, "scale_x", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_x = iattr;
}
}
else
{
float fattr = 0.0f;
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
else
{
strlcpy(attr_name_buf, "scale_x", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_x = fattr;
}
}
strlcpy(attr_name_buf, "scale", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
2018-08-14 18:44:19 -04:00
if (scale->type_y == RARCH_SCALE_ABSOLUTE)
{
int iattr = 0;
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
else
{
strlcpy(attr_name_buf, "scale_y", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
if (config_get_int(conf, attr_name_buf, &iattr))
scale->abs_y = iattr;
}
}
else
{
float fattr = 0.0f;
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
else
{
strlcpy(attr_name_buf, "scale_y", sizeof(attr_name_buf));
strlcat(attr_name_buf, formatted_num, sizeof(attr_name_buf));
if (config_get_float(conf, attr_name_buf, &fattr))
scale->scale_y = fattr;
}
}
return true;
}
/**
* video_shader_parse_textures:
2022-07-15 01:12:04 +02:00
* @param conf
* Preset file to read from.
* @param shader
* Shader pass handle.
2015-01-11 19:59:59 +01:00
*
* Parses shader textures.
*
2022-07-15 01:12:04 +02:00
* @return true if successful, otherwise false.
2015-01-11 19:59:59 +01:00
**/
static bool video_shader_parse_textures(config_file_t *conf,
struct video_shader *shader)
{
size_t path_size = PATH_MAX_LENGTH;
2015-06-13 01:18:13 +02:00
const char *id = NULL;
char *save = NULL;
char *textures = (char*)malloc(1024 + path_size);
char texture_path[PATH_MAX_LENGTH];
if (!textures)
return false;
2016-10-21 06:10:58 +02:00
textures[0] = '\0';
texture_path[0] = '\0';
if (!config_get_array(conf, "textures", textures, 1024))
{
free(textures);
return true;
}
for (id = strtok_r(textures, ";", &save);
id && shader->luts < GFX_MAX_TEXTURES;
shader->luts++, id = strtok_r(NULL, ";", &save))
{
2016-10-21 06:10:58 +02:00
char id_filter[64];
char id_wrap[64];
char id_mipmap[64];
2015-06-13 01:18:13 +02:00
bool mipmap = false;
bool smooth = false;
struct config_entry_list
*entry = NULL;
2022-08-12 22:09:33 +02:00
id_filter[0] = id_wrap[0] = id_mipmap[0] = '\0';
if (!(entry = config_get_entry(conf, id)) ||
string_is_empty(entry->value))
{
2022-01-31 19:05:23 +02:00
RARCH_ERR("[Shaders]: Cannot find path to texture \"%s\"..\n",
id);
free(textures);
return false;
}
config_get_path(conf, id, texture_path, sizeof(texture_path));
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(shader->lut[shader->luts].path, conf->path, texture_path);
replace_wildcards(shader->lut[shader->luts].path, PATH_MAX_LENGTH, conf->path);
entry = NULL;
2014-09-08 17:57:18 +02:00
strlcpy(shader->lut[shader->luts].id, id,
sizeof(shader->lut[shader->luts].id));
2022-08-12 22:09:33 +02:00
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;
else
shader->lut[shader->luts].filter = RARCH_FILTER_UNSPEC;
strlcpy(id_wrap, id, sizeof(id_wrap));
2022-08-12 22:09:33 +02:00
strlcat(id_wrap, "_wrap_mode", sizeof(id_wrap));
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;
strlcpy(id_mipmap, id, sizeof(id_mipmap));
2022-08-12 22:09:33 +02:00
strlcat(id_mipmap, "_mipmap", sizeof(id_mipmap));
if (config_get_bool(conf, id_mipmap, &mipmap))
shader->lut[shader->luts].mipmap = mipmap;
else
shader->lut[shader->luts].mipmap = false;
}
free(textures);
return true;
}
/**
* video_shader_parse_find_parameter:
2022-07-15 01:12:04 +02:00
* @param params
* Shader parameter handle.
* @param num_params
* Number of shader params in @params.
* param id
* Identifier to search for.
2015-01-11 19:59:59 +01:00
*
* Finds a shader parameter with identifier @id in @params..
*
2022-07-15 01:12:04 +02:00
* @return Handle to shader parameter if successful, otherwise NULL.
2015-01-11 19:59:59 +01:00
**/
static struct video_shader_parameter *video_shader_parse_find_parameter(
struct video_shader_parameter *params,
unsigned num_params, const char *id)
2014-05-22 22:02:43 +02:00
{
2023-02-18 17:04:02 +01:00
size_t i;
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
for (i = 0; (unsigned)i < num_params; i++)
2014-05-22 22:02:43 +02:00
{
2016-01-20 04:07:24 +01:00
if (string_is_equal(params[i].id, id))
2014-05-22 22:02:43 +02:00
return &params[i];
}
2015-01-11 19:59:59 +01:00
2014-05-22 22:02:43 +02:00
return NULL;
}
/**
* video_shader_resolve_parameters:
2015-01-11 19:59:59 +01:00
* @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.
2020-11-14 21:23:18 -05:00
*
2015-01-11 19:59:59 +01:00
**/
void video_shader_resolve_parameters(struct video_shader *shader)
2014-05-22 21:24:52 +02:00
{
2023-02-18 17:04:02 +01:00
size_t i;
2016-08-01 15:43:34 +02:00
struct video_shader_parameter *param = &shader->parameters[0];
2014-05-22 21:24:52 +02:00
shader->num_parameters = 0;
2022-05-17 14:12:02 +02:00
#ifdef DEBUG
2014-09-08 17:57:18 +02:00
/* Find all parameters in our shaders. */
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Finding parameters in shader passes (#pragma parameter)..\n");
2022-05-17 14:12:02 +02:00
#endif
2014-05-22 21:24:52 +02:00
for (i = 0; i < shader->passes; i++)
{
const char *path = shader->pass[i].source.path;
uint8_t *buf = NULL;
int64_t buf_len = 0;
if (string_is_empty(path))
continue;
if (!path_is_valid(path))
continue;
2017-10-22 05:24:57 +02:00
/* First try to use the more robust slang implementation
* to support #includes. */
#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
/* FIXME: The check for slang can be removed
* 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 ( string_is_equal(path_get_extension(path), "slang")
&& slang_preprocess_parse_parameters(path, shader))
continue;
#endif
/* Read file contents */
if (filestream_read_file(path, (void**)&buf, &buf_len))
{
size_t line_index = 0;
struct string_list lines = {0};
bool lines_inited = false;
/* Split into lines */
if (buf_len > 0)
{
string_list_initialize(&lines);
lines_inited = string_split_noalloc(&lines, (const char*)buf, "\n");
}
/* Buffer is no longer required - clean up */
if ((void*)buf)
free((void*)buf);
if (!lines_inited)
continue;
2016-10-21 06:10:58 +02:00
/* Even though the pass is set in the loop too,
* not all passes have parameters */
2023-02-18 17:15:52 +01:00
param->pass = (int)i;
2018-08-18 00:33:52 -04:00
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")))
continue;
/* Parse line */
if ((ret = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f",
param->id, param->desc, &param->initial,
&param->minimum, &param->maximum, &param->step)) < 5)
continue;
2015-01-11 19:59:59 +01:00
param->id[63] = '\0';
param->desc[63] = '\0';
2014-05-22 22:02:43 +02:00
if (ret == 5)
param->step = 0.1f * (param->maximum - param->minimum);
2014-05-22 22:02:43 +02:00
2023-02-18 17:15:52 +01:00
param->pass = (int)i;
2022-05-17 14:12:02 +02:00
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_DBG("[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);
2022-05-17 14:12:02 +02:00
#endif
param->current = param->initial;
2014-05-22 21:24:52 +02:00
shader->num_parameters++;
param++;
}
2014-05-22 21:24:52 +02:00
string_list_deinitialize(&lines);
}
2014-05-22 21:24:52 +02:00
}
}
/**
* video_shader_load_current_parameter_values:
2022-07-15 01:12:04 +02:00
* @param conf
* Preset file to read from.
* @param 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.
*
2022-07-15 01:12:04 +02:00
* @return true (1) if successful, otherwise false (0).
**/
bool video_shader_load_current_parameter_values(
config_file_t *conf, struct video_shader *shader)
{
2023-02-18 17:04:02 +01:00
size_t i;
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++)
{
2022-05-17 14:12:02 +02:00
const struct config_entry_list *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*)
2022-05-17 14:12:02 +02:00
video_shader_parse_find_parameter(shader->parameters,
shader->num_parameters,
shader->parameters[i].id);
/* Log each parameter read */
if (config_get_float(conf, shader->parameters[i].id, &parameter->current))
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Load parameter value: \"%s\" = %f.\n", shader->parameters[i].id, parameter->current);
else
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Load parameter value: \"%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,
const char *formatted_num,
enum gfx_scale_type type,
float scale,
unsigned absolute)
{
char key[64];
char dim_str[64];
strlcpy(dim_str, dim, sizeof(dim_str));
strlcat(dim_str, formatted_num, sizeof(dim_str));
strlcpy(key, "scale_type_", sizeof(key));
strlcat(key, dim_str, sizeof(key));
config_set_string(conf, key, scale_type_to_str(type));
strlcpy(key, "scale_", sizeof(key));
strlcat(key, dim_str, sizeof(key));
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 char *formatted_num,
const struct gfx_fbo_scale *fbo)
{
char key[64];
strlcpy(key, "float_framebuffer", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key, (fbo->flags & FBO_SCALE_FLAG_FP_FBO) ? "true" : "false");
strlcpy(key, "srgb_framebuffer", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key, (fbo->flags & FBO_SCALE_FLAG_SRGB_FBO) ? "true" : "false");
if (!(fbo->flags & FBO_SCALE_FLAG_VALID))
return;
shader_write_scale_dim(conf, "x", formatted_num, fbo->type_x, fbo->scale_x, fbo->abs_x);
shader_write_scale_dim(conf, "y", formatted_num, fbo->type_y, fbo->scale_y, fbo->abs_y);
}
/**
* 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.
**/
static bool video_shader_write_root_preset(const struct video_shader *shader,
const char *path)
{
2023-02-18 17:04:02 +01:00
size_t i;
char key[64];
bool ret = true;
char *tmp = (char*)malloc(3 * PATH_MAX_LENGTH);
char *tmp_rel = tmp + PATH_MAX_LENGTH;
char *tmp_base = tmp + 2 * PATH_MAX_LENGTH;
config_file_t *conf = NULL;
if (!(conf = config_file_new_alloc()))
return false;
if (!tmp)
{
config_file_free(conf);
return false;
}
2020-11-22 19:10:08 -05:00
2022-01-31 19:05:23 +02:00
RARCH_DBG("[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, PATH_MAX_LENGTH);
/* ensure we use a clean base like the shader passes and texture paths do */
path_resolve_realpath(tmp_base, PATH_MAX_LENGTH, false);
path_basedir(tmp_base);
for (i = 0; i < shader->passes; i++)
{
char formatted_num[8];
const struct video_shader_pass *pass = &shader->pass[i];
formatted_num[0] = '\0';
2023-02-18 17:15:52 +01:00
snprintf(formatted_num, sizeof(formatted_num), "%u", (int)i);
strlcpy(key, "shader", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
strlcpy(tmp, pass->source.path, PATH_MAX_LENGTH);
path_relative_to(tmp_rel, tmp, tmp_base, PATH_MAX_LENGTH);
pathname_make_slashes_portable(tmp_rel);
config_set_path(conf, key, tmp_rel);
if (pass->filter != RARCH_FILTER_UNSPEC)
{
strlcpy(key, "filter_linear", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key,
(pass->filter == RARCH_FILTER_LINEAR)
? "true"
: "false");
}
strlcpy(key, "wrap_mode", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key, wrap_mode_to_str(pass->wrap));
if (pass->frame_count_mod)
{
strlcpy(key, "frame_count_mod", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_int(conf, key, pass->frame_count_mod);
}
strlcpy(key, "mipmap_input", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key, pass->mipmap ? "true" : "false");
strlcpy(key, "alias", sizeof(key));
strlcat(key, formatted_num, sizeof(key));
config_set_string(conf, key, pass->alias);
shader_write_fbo(conf, formatted_num, &pass->fbo);
}
/* 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];
2022-08-12 22:09:33 +02:00
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 k[128];
2022-08-12 22:09:33 +02:00
strlcpy(k, shader->lut[i].id, sizeof(k));
strlcat(k, "_linear", sizeof(k));
config_set_string(conf, k,
(shader->lut[i].filter == RARCH_FILTER_LINEAR)
? "true"
: "false");
}
/* Wrap Mode */
{
char k[128];
2022-08-12 22:09:33 +02:00
strlcpy(k, shader->lut[i].id, sizeof(k));
strlcat(k, "_wrap_mode", sizeof(k));
config_set_string(conf, k,
wrap_mode_to_str(shader->lut[i].wrap));
}
/* Mipmap On or Off */
{
char k[128];
2022-08-12 22:09:33 +02:00
strlcpy(k, shader->lut[i].id, sizeof(k));
strlcat(k, "_mipmap", sizeof(k));
config_set_string(conf, k, shader->lut[i].mipmap
? "true"
: "false");
}
}
}
/* Write the File! */
ret = config_file_write(conf, path, false);
config_file_free(conf);
free(tmp);
return ret;
}
static config_file_t *video_shader_get_root_preset_config(const char *path)
{
2021-01-16 17:17:16 +01:00
int reference_depth = 1;
char* nested_reference_path = NULL;
config_file_t *conf = config_file_new_from_path_to_string(path);
if (!conf)
2022-05-17 14:12:02 +02:00
return NULL;
nested_reference_path = (char*)malloc(PATH_MAX_LENGTH);
while (conf->references)
2021-01-16 17:17:16 +01:00
{
/* 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)
{
2022-01-31 19:05:23 +02:00
RARCH_ERR("[Shaders]: Get root preset - Exceeded maximum reference depth (%u) without finding a full preset. "
2021-01-16 17:17:16 +01:00
"This chain of referenced presets is likely cyclical.\n", SHADER_MAX_REFERENCE_DEPTH);
config_file_free(conf);
2021-01-16 17:17:16 +01:00
conf = NULL;
2022-05-17 14:12:02 +02:00
free(nested_reference_path);
return NULL;
2021-01-16 17:17:16 +01:00
}
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(nested_reference_path, conf->path, conf->references->path);
replace_wildcards(nested_reference_path, PATH_MAX_LENGTH, conf->path);
2021-01-16 17:17:16 +01:00
/* Create a new config from the referenced path */
config_file_free(conf);
/* If we can't read the reference preset */
if (!(conf = config_file_new_from_path_to_string(nested_reference_path)))
2021-01-16 17:17:16 +01:00
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Could not read shader preset in #reference line: \"%s\".\n", nested_reference_path);
2022-05-17 14:12:02 +02:00
free(nested_reference_path);
return NULL;
}
2021-01-16 17:17:16 +01:00
reference_depth += 1;
}
free(nested_reference_path);
return conf;
}
/**
* video_shader_check_reference_chain:
2022-07-15 01:12:04 +02:00
* @param path_to_save
* Path of the preset we want to validate is safe to save as
* a simple preset.
* @param reference_path
* Path of the reference which we would want to write into
* the new preset.
*
2022-07-15 01:12:04 +02:00
* Checks to see if we can save a valid simple preset
* (preset with a #reference in it) to this path.
*
2022-07-15 01:12:04 +02:00
* This takes into account reference links which can't be
* loaded and if saving this file would create a creating
* circular reference chain, because some link in
* the chain references the file path we want to save to.
*
* Checks each preset in the chain of presets with #reference
2022-07-15 01:12:04 +02:00
* Starts with reference_path. If it has no reference, then
* our check is valid.
* If it has a #reference, then check that the reference path
* is not the same as path_to_save.
* If it is not the same path, then go the the next nested reference
*
* Continues this until it finds a preset without #reference in it,
* or it hits the maximum recursion depth (at that point
* it is probably in a self referential cycle)
*
2022-07-15 01:12:04 +02:00
* @return true (1) if it was able to load all presets and
* found a full preset, otherwise false (0).
**/
static bool video_shader_check_reference_chain_for_save(
const char *path_to_save, const char *ref_path)
{
config_file_t *conf = config_file_new_from_path_to_string(ref_path);
bool ret = true;
if (!conf)
{
RARCH_ERR("[Shaders]: Could not read the #reference preset: \"%s\".\n", ref_path);
return false;
}
else
{
int ref_depth = 1;
char *path_to_save_conformed = (char*)malloc(PATH_MAX_LENGTH);
char *nested_ref_path = (char*)malloc(PATH_MAX_LENGTH);
strlcpy(path_to_save_conformed, path_to_save, PATH_MAX_LENGTH);
pathname_conform_slashes_to_os(path_to_save_conformed);
while (conf->references)
{
/* If we have reached the max depth of nested references stop attempting to read
* the next reference because we are likely in a self referential loop. */
if (ref_depth > SHADER_MAX_REFERENCE_DEPTH)
{
2022-01-31 19:05:23 +02:00
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);
ret = false;
break;
}
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(nested_ref_path, conf->path, conf->references->path);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
replace_wildcards(nested_ref_path, PATH_MAX_LENGTH, conf->path);
/* If one of the reference paths is the same as the file we want to save then this reference chain would be
* self-referential / cyclical and we can't save this as a simple preset*/
if (string_is_equal(nested_ref_path, path_to_save_conformed))
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving preset:\n"
" \"%s\"\n"
" With a #reference of:\n"
" \"%s\"\n"
" Would create a cyclical reference in preset:\n"
" \"%s\"\n"
" Which already references preset:\n"
" \"%s\"\n",
path_to_save_conformed, ref_path,
conf->path, nested_ref_path);
ret = false;
break;
}
/* Create a new config from the referenced path */
config_file_free(conf);
/* If we can't read the reference preset */
if (!(conf = config_file_new_from_path_to_string(nested_ref_path)))
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Could not read shader preset "
"in #reference line: \"%s\".\n", nested_ref_path);
ret = false;
break;
}
ref_depth += 1;
}
free(path_to_save_conformed);
free(nested_ref_path);
}
config_file_free(conf);
return ret;
}
/**
* video_shader_write_referenced_preset:
2022-07-15 01:12:04 +02:00
* @param path
* File to write to
* @param shader
* Shader preset to write
*
* Writes a referenced preset to disk
2022-07-15 01:12:04 +02:00
* 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
*
2022-07-15 01:12:04 +02:00
* @return false if a referenced preset cannot be saved
**/
static bool video_shader_write_referenced_preset(
const char *path_to_save,
const struct video_shader *shader)
{
2023-02-18 17:04:02 +01:00
size_t i;
config_file_t *conf = NULL;
config_file_t *ref_conf = NULL;
struct video_shader *ref_shader = (struct video_shader*)
calloc(1, sizeof(*ref_shader));
bool ret = false;
bool continue_saving_ref = true;
2020-12-27 20:32:43 -05:00
char *new_preset_basedir = strdup(path_to_save);
char *config_dir = (char*)malloc(PATH_MAX_LENGTH);
char *relative_tmp_ref_path = (char*)malloc(PATH_MAX_LENGTH);
char *abs_tmp_ref_path = (char*)malloc(PATH_MAX_LENGTH);
char *path_to_ref = (char*)malloc(PATH_MAX_LENGTH);
2020-12-27 20:32:43 -05:00
char* path_to_save_conformed = (char*)malloc(PATH_MAX_LENGTH);
strlcpy(path_to_save_conformed, path_to_save, PATH_MAX_LENGTH);
pathname_conform_slashes_to_os(path_to_save_conformed);
config_dir[0] = '\0';
relative_tmp_ref_path[0] = '\0';
abs_tmp_ref_path[0] = '\0';
2022-08-12 22:09:33 +02:00
path_to_ref[0] = '\0';
path_basedir(new_preset_basedir);
/* 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);
/* If there is no initial preset path loaded */
if (string_is_empty(shader->loaded_preset_path))
{
2022-01-31 19:05:23 +02:00
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/FIXME - remove once we don't write this preset anymore */
if (!strncmp(path_basename_nocompression(shader->loaded_preset_path),
"retroarch",
STRLEN_CONST("retroarch")))
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving full preset because "
"a reference to the "
"ever-changing retroarch preset can't be saved.\n");
goto end;
}
strlcpy(path_to_ref, shader->loaded_preset_path, PATH_MAX_LENGTH);
pathname_conform_slashes_to_os(path_to_ref);
/* Get a config from the file we want to make a reference to */
/* If the original preset can't be loaded, probably because
* it isn't there anymore */
if (!(ref_conf = config_file_new_from_path_to_string(path_to_ref)))
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving full preset because the initially "
"loaded preset can't be loaded. "
"It was likely renamed or deleted.\n");
goto end;
}
/* If we are trying to save on top the path referenced in the
* initially loaded preset.
*
* E.G. Preset_B references Preset_A, I load Preset_B do some
* parameter adjustments,
* then I save on top of Preset_A, we want to get a preset
* just like the original Preset_A with the new parameter
* adjustments.
*
* If there is a reference in the initially loaded preset,
* we should check it against the preset path we are currently
* trying to save */
if (ref_conf->references)
{
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(abs_tmp_ref_path, ref_conf->path, ref_conf->references->path);
replace_wildcards(abs_tmp_ref_path, PATH_MAX_LENGTH, ref_conf->path);
pathname_conform_slashes_to_os(abs_tmp_ref_path);
/* 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 */
if (string_is_equal(abs_tmp_ref_path, path_to_save_conformed))
{
strlcpy(path_to_ref, abs_tmp_ref_path, PATH_MAX_LENGTH);
config_file_free(ref_conf);
ref_conf = config_file_new_from_path_to_string(
path_to_ref);
}
}
/*
* If
* The new preset file we are trying to save is the
* same as the initially loaded preset
* or
* The initially loaded preset was located under the
* retroarch config folder
* this means that it was likely saved from inside the retroarch UI
* Then
* We should not save a preset with a reference to the initially loaded
* preset file itself, instead we need to save a new preset with
* the same reference as was in the initially loaded preset.
*/
/* If the reference path is the same as the path we want to save
* or the reference path is in the config (auto shader) folder */
if (string_is_equal(path_to_ref, path_to_save_conformed)
|| !strncmp(config_dir, path_to_ref, 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 (ref_conf->references)
{
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(path_to_ref, ref_conf->path, ref_conf->references->path);
replace_wildcards(path_to_ref, PATH_MAX_LENGTH, ref_conf->path);
/* If the reference path is also the same as what
* we are trying to save
This can easily happen
E.G.
- Save Preset As
- Save Game Preset
- Save Preset As (use same name as first time)
*/
if (string_is_equal(path_to_ref, path_to_save_conformed))
{
config_file_free(ref_conf);
ref_conf = config_file_new_from_path_to_string(path_to_ref);
/* If the reference also has a reference inside it */
/* Get the absolute path for the reference */
if (ref_conf->references)
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
{
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(path_to_ref, ref_conf->path, ref_conf->references->path);
replace_wildcards(path_to_ref, PATH_MAX_LENGTH, ref_conf->path);
}
else
{
/* If the config referenced is a full preset */
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving full preset because "
"a preset which "
"would reference itself can't be saved.\n");
goto end;
}
}
2020-11-22 19:10:08 -05:00
}
/* If there is no reference in the initial preset we need to
* save a full preset */
2020-11-22 19:10:08 -05:00
else
{
/* We can't save a reference to ourselves */
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving full preset because "
"a preset which "
"would reference itself can't be saved.\n");
2020-11-22 19:10:08 -05:00
goto end;
}
}
/* Check the reference chain that we would be saving to make sure it
* is valid */
if (!video_shader_check_reference_chain_for_save(
path_to_save_conformed, path_to_ref))
{
2022-01-31 19:05:23 +02:00
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;
}
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Reading preset to compare with "
"current values: \"%s\".\n", path_to_save_conformed);
/* Load the preset referenced in the preset into the shader */
if (!video_shader_load_preset_into_shader(path_to_ref, ref_shader))
{
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Saving full preset because "
"the preset could not be loaded from #reference line: \"%s\".\n",
path_to_ref);
goto end;
}
/* Create a new EMPTY config */
if (!(conf = config_file_new_alloc()))
goto end;
2020-12-27 20:32:43 -05:00
conf->path = strdup(path_to_save_conformed);
pathname_make_slashes_portable(relative_tmp_ref_path);
/* Add the reference path to the config */
config_file_add_reference(conf, path_to_ref);
/* 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 != ref_shader->passes)
{
2022-01-31 19:05:23 +02:00
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_ref = 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_ref)
{
/* Step through each pass comparing all the properties to
* make sure they match */
for (i = 0; (i < shader->passes && continue_saving_ref);
i++)
{
const struct video_shader_pass *pass = &shader->pass[i];
const struct video_shader_pass *root_pass = &ref_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))
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u path", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && pass->filter != root_pass->filter)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u filter", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && pass->wrap != root_pass->wrap)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u wrap", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && pass->frame_count_mod != root_pass->frame_count_mod)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u frame_count", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && pass->mipmap != root_pass->mipmap)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u mipmap", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && !string_is_equal(pass->alias, root_pass->alias))
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u alias", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && fbo->type_x != root_fbo->type_x)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u type_x", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && fbo->type_y != root_fbo->type_y)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u type_y", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && fbo->scale_x != root_fbo->scale_x)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u scale_x", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && fbo->scale_y != root_fbo->scale_y)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u scale_y", i);
#endif
continue_saving_ref = false;
}
if ( continue_saving_ref
&& (fbo->flags & FBO_SCALE_FLAG_FP_FBO) != (root_fbo->flags & FBO_SCALE_FLAG_FP_FBO))
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u fp_fbo", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref
&& (fbo->flags & FBO_SCALE_FLAG_SRGB_FBO) != (root_fbo->flags &
FBO_SCALE_FLAG_SRGB_FBO))
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u srgb_fbo", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref
&& ((fbo->flags & FBO_SCALE_FLAG_VALID) != (root_fbo->flags & FBO_SCALE_FLAG_VALID)))
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u valid", i);
#endif
continue_saving_ref = false;
}
if (continue_saving_ref && fbo->abs_x != root_fbo->abs_x)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u abs_x", i);
#endif
continue_saving_ref = false;
}
2020-11-02 21:07:20 -05:00
if (continue_saving_ref && fbo->abs_y != root_fbo->abs_y)
{
#ifdef DEBUG
RARCH_WARN("[Shaders]: Pass %u abs_y", i);
#endif
continue_saving_ref = false;
}
2020-11-02 21:07:20 -05:00
if (!continue_saving_ref)
{
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Current value doesn't match referenced value "
"- Full preset will be saved instead of simple preset.\n");
#endif
goto end;
}
}
}
2020-11-02 21:07:20 -05:00
/* 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
!= ref_shader->parameters[i].current)
config_set_float(conf, shader->parameters[i].id,
shader->parameters[i].current);
}
}
2020-11-02 21:07:20 -05:00
/* If the shader has textures */
if (shader->luts)
2020-11-02 21:07:20 -05:00
{
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(ref_shader->lut[i].path,
shader->lut[i].path))
{
char *path_for_save = (char*)malloc(PATH_MAX_LENGTH);
2020-11-02 21:07:20 -05:00
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);
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Texture override \"%s\" = \"%s\".\n",
shader->lut[i].id, path_for_save);
#endif
2020-11-02 21:07:20 -05:00
free(path_for_save);
}
}
2020-11-02 21:07:20 -05:00
}
/* Write the file, return will be true if successful */
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Saving simple preset to: \"%s\"\n",
path_to_save_conformed);
2020-12-27 20:32:43 -05:00
ret = config_file_write(conf, path_to_save_conformed, false);
end:
config_file_free(conf);
config_file_free(ref_conf);
free(ref_shader);
free(abs_tmp_ref_path);
free(relative_tmp_ref_path);
free(new_preset_basedir);
free(config_dir);
free(path_to_ref);
2020-12-27 20:32:43 -05:00
free(path_to_save_conformed);
return ret;
}
/**
* video_shader_load_root_config_into_shader:
2022-07-15 01:12:04 +02:00
* @param conf
* Preset file to read from.
* @param shader
* Shader handle.
2015-01-11 20:17:45 +01:00
*
2022-07-15 01:12:04 +02:00
* Loads preset file and all associated state
* (passes, textures, imports, etc).
2015-01-11 20:17:45 +01:00
*
2022-07-15 01:12:04 +02:00
* @return true (1) if successful, otherwise false (0).
2015-01-11 20:17:45 +01:00
**/
static bool video_shader_load_root_config_into_shader(
config_file_t *conf,
settings_t *settings,
struct video_shader *shader)
{
2023-02-18 17:04:02 +01:00
size_t i;
unsigned num_passes = 0;
bool watch_files = settings->bools.video_shader_watch_files;
/* This sets the shader to empty */
memset(shader, 0, sizeof(*shader));
if (!config_get_uint(conf, "shaders", &num_passes))
return false;
if (!num_passes)
return false;
if (!config_get_int(conf, "feedback_pass", &shader->feedback_pass))
shader->feedback_pass = -1;
shader->passes = MIN(num_passes, GFX_MAX_SHADERS);
2016-03-02 00:07:31 +01:00
/* 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, 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,
conf->path,
sizeof(shader->loaded_preset_path));
if (watch_files)
{
2020-08-26 18:54:14 +02:00
union string_list_elem_attr attr;
int flags =
PATH_CHANGE_TYPE_MODIFIED |
PATH_CHANGE_TYPE_WRITE_FILE_CLOSED |
PATH_CHANGE_TYPE_FILE_MOVED |
PATH_CHANGE_TYPE_FILE_DELETED;
struct string_list file_list = {0};
attr.i = 0;
if (file_change_data)
frontend_driver_watch_path_for_changes(NULL, 0, &file_change_data);
file_change_data = NULL;
2020-08-26 18:54:14 +02:00
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 */
2020-08-26 18:54:14 +02:00
for (i = 0; i < shader->passes; i++)
2018-01-26 00:14:59 -05:00
{
2023-02-18 17:15:52 +01:00
if (!video_shader_parse_pass(conf, &shader->pass[i], (unsigned)i))
2018-08-14 18:44:19 -04:00
{
2020-08-26 18:54:14 +02:00
string_list_deinitialize(&file_list);
return false;
2018-08-14 18:44:19 -04:00
}
string_list_append(&file_list, shader->pass[i].source.path, attr);
2020-08-26 18:54:14 +02:00
}
frontend_driver_watch_path_for_changes(&file_list, flags,
&file_change_data);
2020-08-26 18:54:14 +02:00
string_list_deinitialize(&file_list);
}
else
{
for (i = 0; i < shader->passes; i++)
{
2023-02-18 17:15:52 +01:00
if (!video_shader_parse_pass(conf, &shader->pass[i], (unsigned)i))
return false;
2020-08-26 18:54:14 +02:00
}
}
if (!video_shader_parse_textures(conf, shader))
return false;
/* Load the parameter values */
video_shader_resolve_parameters(shader);
/* Load the parameter values */
video_shader_load_current_parameter_values(conf, shader);
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Number of passes: %u\n", shader->passes);
RARCH_DBG("[Shaders]: Number of textures: %u\n", shader->luts);
/* Log Texture Names & Paths */
for (i = 0; i < shader->luts; i++)
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: \"%s\" = \"%s\".\n", shader->lut[i].id,
shader->lut[i].path);
#endif
return true;
}
/**
* override_shader_values:
2022-07-15 01:12:04 +02:00
* @param override_conf
* Config file who's values will be copied on top of conf
* @param shader
* Shader to be affected
*
* Takes values from override_config and overrides values of the shader
2015-01-11 20:17:45 +01:00
*
2022-07-15 01:12:04 +02:00
* @return 0 if nothing is overridden , 1 if something is overridden
2015-01-11 20:17:45 +01:00
**/
static bool override_shader_values(config_file_t *override_conf,
struct video_shader *shader)
{
2023-02-18 17:04:02 +01:00
size_t i;
bool return_val = false;
if (!shader || !override_conf)
2020-12-30 11:02:59 -05:00
return 0;
/* If the shader has parameters */
if (shader->num_parameters)
{
/* 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++)
{
/* If the parameter is in the reference config */
if (config_get_entry(override_conf, shader->parameters[i].id))
{
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,
&parameter->current);
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Parameter: \"%s\" = %f.\n",
shader->parameters[i].id,
shader->parameters[i].current);
#endif
2016-12-04 01:12:57 -05:00
return_val = true;
}
}
}
/* ---------------------------------------------------------------------------------
* ------------- Resolve Override texture paths to absolute paths-------------------
* --------------------------------------------------------------------------------- */
/* If the shader has textures */
if (shader->luts)
{
2020-12-30 11:02:59 -05:00
char *override_tex_path = (char*)malloc(PATH_MAX_LENGTH);
/* 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++)
{
/* If the texture is defined in the reference config */
if (config_get_entry(override_conf, shader->lut[i].id))
{
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
char *tex_path = (char*)malloc(PATH_MAX_LENGTH);
/* Texture path from the config */
config_get_path(override_conf, shader->lut[i].id, tex_path, PATH_MAX_LENGTH);
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(override_tex_path, override_conf->path, tex_path);
replace_wildcards(override_tex_path, PATH_MAX_LENGTH, override_conf->path);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
strlcpy(shader->lut[i].path, override_tex_path, PATH_MAX_LENGTH);
#ifdef DEBUG
2022-01-31 19:05:23 +02:00
RARCH_DBG("[Shaders]: Texture: \"%s\" = %s.\n",
shader->lut[i].id,
shader->lut[i].path);
#endif
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
free(tex_path);
return_val = true;
}
}
free(override_tex_path);
}
2014-05-11 13:13:38 +02:00
return return_val;
}
#if 0
/*
* Copies the content of the src_shader into the dst_shader
*/
static bool replace_shader_contents(struct video_shader *src_shader,
struct video_shader *dst_shader)
{
int i;
/* This sets the shader to empty */
memset(dst_shader, 0, sizeof(*dst_shader));
for (i = 0; i < src_shader->passes && i <= GFX_MAX_SHADERS; i++)
{
dst_shader->pass[i] = src_shader->pass[i];
dst_shader->passes += 1;
}
for (i = 0; i < src_shader->luts; i++)
{
strlcpy(dst_shader->lut[i].id,
src_shader->lut[i].id,
sizeof(dst_shader->lut[i].id));
strlcpy(dst_shader->lut[i].path,
src_shader->lut[i].path,
sizeof(dst_shader->lut[i].path));
dst_shader->luts += 1;
}
video_shader_resolve_parameters(dst_shader);
/* Step through the parameters in the shader and see if the parameter is in either of the shaders */
for (i = 0; i < dst_shader->num_parameters; i++)
{
/* Check the original shader */
if (video_shader_parse_find_parameter( src_shader->parameters,
src_shader->num_parameters,
dst_shader->parameters[i].id))
{
dst_shader->parameters[i].current = video_shader_parse_find_parameter( src_shader->parameters,
src_shader->num_parameters,
dst_shader->parameters[i].id)->current;
}
}
return true;
}
#endif
static bool combine_shaders(struct video_shader *combined_shader,
struct video_shader *first_shader,
struct video_shader *second_shader)
{
2023-02-18 17:04:02 +01:00
size_t i, j;
for (i = 0; i < first_shader->passes && i <= GFX_MAX_SHADERS; i++)
{
combined_shader->pass[i] = first_shader->pass[i];
combined_shader->passes += 1;
}
for (i = 0;
i < second_shader->passes && first_shader->passes + i <= GFX_MAX_SHADERS;
i++)
{
combined_shader->pass[first_shader->passes + i] = second_shader->pass[i];
combined_shader->passes += 1;
}
for (i = 0; i < first_shader->luts; i++)
{
strlcpy(combined_shader->lut[i].id,
first_shader->lut[i].id,
sizeof(combined_shader->lut[i].id));
strlcpy(combined_shader->lut[i].path,
first_shader->lut[i].path,
sizeof(combined_shader->lut[i].path));
combined_shader->luts += 1;
}
for (i = 0; i < second_shader->luts; i++)
{
bool b_name_in_list = false;
for (j = 0; j < combined_shader->luts; j++)
{
if (strncmp(second_shader->lut[i].id, combined_shader->lut[j].id, 64) == 0)
{
b_name_in_list = true;
break;
}
}
if (!b_name_in_list)
{
strlcpy(combined_shader->lut[combined_shader->luts].id,
second_shader->lut[i].id,
sizeof(combined_shader->lut[combined_shader->luts].id));
strlcpy(combined_shader->lut[combined_shader->luts].path,
second_shader->lut[i].path,
sizeof(combined_shader->lut[combined_shader->luts].path));
combined_shader->luts += 1;
}
}
video_shader_resolve_parameters(combined_shader);
/* Step through the parameters in the shader and see if the parameter is in either of the shaders */
for (i = 0; i < combined_shader->num_parameters; i++)
{
/* Check the original shader */
if (video_shader_parse_find_parameter( first_shader->parameters,
first_shader->num_parameters,
combined_shader->parameters[i].id))
{
combined_shader->parameters[i].current = video_shader_parse_find_parameter( first_shader->parameters,
first_shader->num_parameters,
combined_shader->parameters[i].id)->current;
}
/* Check the shader to append */
if (video_shader_parse_find_parameter( second_shader->parameters,
second_shader->num_parameters,
combined_shader->parameters[i].id))
{
combined_shader->parameters[i].current = video_shader_parse_find_parameter( second_shader->parameters,
second_shader->num_parameters,
combined_shader->parameters[i].id)->current;
}
}
return true;
}
/**
* video_shader_write_preset:
2022-07-15 01:12:04 +02:00
* @param path
* File to write to
* @param shader
* Shader to write
* @param 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 simple preset
* (With the #reference directive in it) or a full preset.
2022-07-15 01:12:04 +02:00
* @return true on success, otherwise false on failure
**/
bool video_shader_write_preset(const char *path,
const struct video_shader *shader,
bool reference)
{
if (!shader || string_is_empty(path))
return false;
/* If we should still save a referenced preset do it now */
if (reference)
{
if (video_shader_write_referenced_preset(path, shader))
return true;
2022-01-31 19:05:23 +02:00
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 */
if (path)
return video_shader_write_root_preset(shader, path);
return false;
}
/**
* video_shader_load_preset_into_shader:
2022-07-15 01:12:04 +02:00
* @param path
* Path to preset file, could be a
* Simple Preset (including a #reference) or Full Preset.
* @param shader
* Shader.
*
* Loads preset file to a shader including passes, textures
* and parameters
*
2022-07-15 01:12:04 +02:00
* @return true on success, otherwise false on failure.
**/
bool video_shader_load_preset_into_shader(const char *path,
struct video_shader *shader)
{
bool ret = true;
config_file_t *conf = NULL;
struct path_linked_list* override_paths_list = NULL;
struct path_linked_list* path_list_tmp = NULL;
config_file_t *root_conf = video_shader_get_root_preset_config(path);
if (!root_conf)
{
RARCH_LOG("\n");
2022-01-31 19:05:23 +02:00
RARCH_WARN("[Shaders]: Could not read root preset: \"%s\".\n", path);
ret = false;
goto end;
}
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Check if the root preset is a valid shader chain
If the config has a shaders entry then it is considered
a shader chain config, vs a config which may only have
parameter values and texture overrides
*/
if (!config_get_entry(root_conf, "shaders"))
{
RARCH_LOG("\n");
RARCH_WARN("[Shaders]: Root preset is not a valid shader chain because it has no shaders entry: \"%s\".\n", path);
ret = false;
goto end;
}
/* If the root_conf path matches the original path then
* there are no references so we just load it and go to the end */
if (string_is_equal(root_conf->path, path))
{
/* Load the config from the shader chain from the first reference into the shader */
video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader);
goto end;
}
/* Get the config from the initial preset file
* We don't need to check it's validity because it must
* have been valid to get the root preset */
conf = config_file_new_from_path_to_string(path);
2016-10-21 06:10:58 +02:00
#ifdef DEBUG
RARCH_DBG("\n[Shaders]: Crawl preset reference chain..\n");
#endif
/**
* Check references starting with the second to make sure
* they do not have a shader chains in them
**/
path_list_tmp = (struct path_linked_list*)conf->references->next;
while (path_list_tmp)
{
config_file_t *tmp_conf = NULL;
char *path_to_ref = (char*)malloc(PATH_MAX_LENGTH);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Get the absolute path and replace wildcards in the path */
fill_pathname_expanded_and_absolute(path_to_ref, conf->path, path_list_tmp->path);
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
replace_wildcards(path_to_ref, PATH_MAX_LENGTH, conf->path);
if ((tmp_conf = video_shader_get_root_preset_config(path_to_ref)))
{
Shader Preset - Wildcard Replacement in Paths on Load (#15023) When a simple preset loads, wildcards which are found in paths inside the presets will be replaced with values coming from the current RetroArch context. This will operate on both texture paths and reference paths. This would allow you to do things like have one preset which could be used with the entire list of images from the Bezel Project E.G. "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" would be replaced with "/shaders/MyBackground_glcore_YabaSanshiro.png" If no file found at that path, the path will revert to the original path, so operates as a fallback "/shaders/MyBackground_$VID-DRV$ _$CORE$.png" * Possible wildcards/tokens to be replaced: * * $CONTENT-DIR$ -> Content Directory of the game rom * * $CORE$ -> Core name * * $GAME$ -> Game ROM's name * * $VID-DRV$ -> Video Driver: Currently active driver, possible replacement values: * glcore * gl * vulkan * d3d11 * d3d9_hlsl * "N/A" * * $VID-DRV-SHADER-EXT$ -> Video Driver Shader File Extension: The extension of shaders type supported by the current video driver: * cg * glsl * slang * * $VID-DRV-PRESET-EXT$ -> Video Driver Preset File Extension: The extension of shaders type supported by the current video driver: * cgp * glslp * slangp * * $CORE-REQ-ROT$ -> Core Requested Rotation: Rotation the core is requesting, possible replacement values: * CORE-REQ-ROT-0 * CORE-REQ-ROT-90 * CORE-REQ-ROT-180 * CORE-REQ-ROT-270 * * $VID-ALLOW-CORE-ROT$ -> Video Allow Core Rotation: Reflects Retroarch's setting allowing the core requested rotation to affect the final rotation: * VID-ALLOW-CORE-ROT-OFF * VID-ALLOW-CORE-ROT-ON * * $VID-USER-ROT$ -> Video User Rotation: Rotation the core is requesting, possible replacement values, does not affect the UI: * VID-USER-ROT-0 * VID-USER-ROT-90 * VID-USER-ROT-180 * VID-USER-ROT-270 * * $VID-FINAL-ROT$ -> Video Final Rotation: Rotation which is the sum of the user rotation and the core rotation if it has been allowed, does not affect the UI: * VID-FINAL-ROT-0 * VID-FINAL-ROT-90 * VID-FINAL-ROT-180 * VID-FINAL-ROT-270 * * $SCREEN-ORIENT$ -> Screen Orientation: User adjusted screen orientation, will change windows from landscape to portrait, including the Retroarch UI: * SCREEN-ORIENT-0 * SCREEN-ORIENT-90 * SCREEN-ORIENT-180 * SCREEN-ORIENT-270 * * $VIEW-ASPECT-ORIENT$ -> Viewport Aspect Orientation: Orientation of the aspect ratio of the RetroArch viewport * VIEW-ASPECT-ORIENT-HORZ * VIEW-ASPECT-ORIENT-VERT * * $CORE-ASPECT-ORIENT$ -> Core Aspect Orientation: Orientation of the aspect ratio requested by the core * CORE-ASPECT-ORIENT-HORZ * CORE-ASPECT-ORIENT-VERT * * $PRESET_DIR$ -> Preset directory's name * * $PRESET$ -> Preset's name * * If no wildcards are found within the path, or the path * after replacing the wildcards does not exist on disk, * the path returned will be unaffected.
2023-02-26 13:06:57 -05:00
/* Check if the config is a valid shader chain config
If the config has a shaders entry then it is considered
a shader chain config, vs a config which may only have
parameter values and texture overrides
*/
if (config_get_entry(tmp_conf, "shaders"))
{
RARCH_WARN("\n[Shaders]: Additional #reference entries pointing at shader chain presets are not supported: \"%s\".\n", path_to_ref);
config_file_free(tmp_conf);
ret = false;
goto end;
}
config_file_free(tmp_conf);
}
else
{
RARCH_WARN("\n[Shaders]: Could not load root preset for #reference entry: \"%s\".\n", path_to_ref);
ret = false;
goto end;
}
path_list_tmp = path_list_tmp->next;
}
/* Load the config from the shader chain from the first reference into the shader */
video_shader_load_root_config_into_shader(root_conf, config_get_ptr(), shader);
/* Set Path for originally loaded preset because it is different than the root preset path */
strlcpy(shader->loaded_preset_path, path, sizeof(shader->loaded_preset_path));
#ifdef DEBUG
RARCH_DBG("\n[Shaders]: Start applying simple preset overrides..\n");
#endif
/* Gather all the paths of all of the presets in all reference chains */
override_paths_list = path_linked_list_new();
gather_reference_path_list(override_paths_list, conf->path, 0);
/*
* Step through the references and apply overrides for each one
* Start on the second item since the first is empty
*/
path_list_tmp = (struct path_linked_list*)override_paths_list;
while (path_list_tmp)
{
config_file_t *override_conf = config_file_new_from_path_to_string(path_list_tmp->path);
#ifdef DEBUG
RARCH_DBG("[Shaders]: Apply values from: \"%s\".\n", override_conf->path);
#endif
override_shader_values(override_conf, shader);
config_file_free(override_conf);
path_list_tmp = path_list_tmp->next;
}
#ifdef DEBUG
RARCH_DBG("[Shaders]: End apply overrides.\n\n");
#endif
end:
path_linked_list_free(override_paths_list);
config_file_free(conf);
config_file_free(root_conf);
return ret;
}
const char *video_shader_type_to_str(enum rarch_shader_type type)
{
switch (type)
{
case RARCH_SHADER_CG:
return "Cg";
case RARCH_SHADER_HLSL:
return "HLSL";
case RARCH_SHADER_GLSL:
return "GLSL";
case RARCH_SHADER_SLANG:
return "Slang";
case RARCH_SHADER_METAL:
return "Metal";
case RARCH_SHADER_NONE:
return "none";
default:
break;
}
return "???";
}
/**
* video_shader_is_supported:
* Tests if a shader type is supported.
* This is only accurate once the context driver was initialized.
2022-07-15 01:12:04 +02:00
* @return true on success, otherwise false on failure.
**/
2018-02-25 17:20:22 +01:00
bool video_shader_is_supported(enum rarch_shader_type type)
{
gfx_ctx_flags_t flags;
enum display_flags testflag = GFX_CTX_FLAGS_NONE;
flags.flags = 0;
2019-07-12 16:31:16 +02:00
2019-03-13 20:39:36 +01:00
switch (type)
{
case RARCH_SHADER_SLANG:
testflag = GFX_CTX_FLAGS_SHADERS_SLANG;
break;
2019-03-13 20:39:36 +01:00
case RARCH_SHADER_GLSL:
testflag = GFX_CTX_FLAGS_SHADERS_GLSL;
break;
2019-03-13 20:39:36 +01:00
case RARCH_SHADER_CG:
testflag = GFX_CTX_FLAGS_SHADERS_CG;
break;
2019-03-13 20:39:36 +01:00
case RARCH_SHADER_HLSL:
testflag = GFX_CTX_FLAGS_SHADERS_HLSL;
break;
2019-03-13 20:39:36 +01:00
case RARCH_SHADER_NONE:
default:
return false;
2019-03-13 20:39:36 +01:00
}
video_context_driver_get_flags(&flags);
return BIT32_GET(flags.flags, testflag);
}
const char *video_shader_get_preset_extension(enum rarch_shader_type type)
{
switch (type)
{
case RARCH_SHADER_GLSL:
2019-09-18 18:12:57 +02:00
return ".glslp";
case RARCH_SHADER_SLANG:
2019-09-18 18:12:57 +02:00
return ".slangp";
case RARCH_SHADER_HLSL:
case RARCH_SHADER_CG:
2019-09-18 18:12:57 +02:00
return ".cgp";
default:
break;
}
return NULL;
2018-02-25 17:20:22 +01:00
}
2018-02-25 23:03:39 +01:00
bool video_shader_any_supported(void)
{
gfx_ctx_flags_t flags;
flags.flags = 0;
video_context_driver_get_flags(&flags);
return
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG) ||
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL) ||
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG) ||
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_HLSL);
2018-02-25 23:03:39 +01:00
}
enum rarch_shader_type video_shader_get_type_from_ext(
const char *ext, bool *is_preset)
2018-02-25 17:20:22 +01:00
{
if (string_is_empty(ext))
return RARCH_SHADER_NONE;
if ((ext[0] != '\0') && (ext[0] == '.') && (ext[1] != '\0'))
ext++;
if (is_preset)
*is_preset =
string_is_equal_case_insensitive(ext, "cgp") ||
string_is_equal_case_insensitive(ext, "glslp") ||
string_is_equal_case_insensitive(ext, "slangp");
if (string_is_equal_case_insensitive(ext, "cgp") ||
string_is_equal_case_insensitive(ext, "cg")
)
return RARCH_SHADER_CG;
if (string_is_equal_case_insensitive(ext, "glslp") ||
string_is_equal_case_insensitive(ext, "glsl")
)
return RARCH_SHADER_GLSL;
if (string_is_equal_case_insensitive(ext, "slangp") ||
string_is_equal_case_insensitive(ext, "slang")
)
return RARCH_SHADER_SLANG;
2018-02-25 17:20:22 +01:00
return RARCH_SHADER_NONE;
}
bool video_shader_check_for_changes(void)
{
if (!file_change_data)
return false;
return frontend_driver_check_for_path_changes(file_change_data);
}
void video_shader_dir_free_shader(
struct rarch_dir_shader_list *dir_list,
bool shader_remember_last_dir)
{
if (dir_list->shader_list)
{
dir_list_free(dir_list->shader_list);
dir_list->shader_list = NULL;
}
if (dir_list->directory)
{
free(dir_list->directory);
dir_list->directory = NULL;
}
dir_list->selection = 0;
dir_list->shader_loaded = false;
dir_list->remember_last_preset_dir = shader_remember_last_dir;
}
static bool video_shader_dir_init_shader_internal(
2021-10-15 14:32:07 +02:00
bool shader_remember_last_dir,
struct rarch_dir_shader_list *dir_list,
const char *shader_dir,
const char *shader_file_name,
bool show_hidden_files)
{
size_t i;
struct string_list *new_list = dir_list_new_special(
shader_dir, DIR_LIST_SHADERS, NULL, show_hidden_files);
bool search_file_name = shader_remember_last_dir &&
!string_is_empty(shader_file_name);
if (!new_list)
return false;
if (new_list->size < 1)
{
dir_list_free(new_list);
return false;
}
dir_list_sort(new_list, false);
dir_list->shader_list = new_list;
dir_list->directory = strdup(shader_dir);
dir_list->selection = 0;
dir_list->shader_loaded = false;
dir_list->remember_last_preset_dir = shader_remember_last_dir;
if (search_file_name)
{
for (i = 0; i < new_list->size; i++)
{
const char *file_name = NULL;
const char *file_path = new_list->elems[i].data;
if (string_is_empty(file_path))
continue;
/* If a shader file name has been provided,
* search the list for a match and set 'selection'
* index if found */
file_name = path_basename(file_path);
if ( !string_is_empty(file_name) &&
2021-10-15 14:32:07 +02:00
string_is_equal(file_name, shader_file_name))
{
2021-12-04 15:21:12 +02:00
RARCH_LOG("[Shaders]: %s \"%s\".\n",
2021-10-15 14:32:07 +02:00
msg_hash_to_str(MSG_FOUND_SHADER),
file_path);
dir_list->selection = i;
break;
}
}
}
return true;
}
static void video_shader_dir_init_shader(
void *menu_driver_data_,
settings_t *settings,
struct rarch_dir_shader_list *dir_list)
{
bool show_hidden_files = settings->bools.show_hidden_files;
bool shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
const char *directory_video_shader = settings->paths.directory_video_shader;
const char *directory_menu_config = settings->paths.directory_menu_config;
bool video_shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
const char *last_shader_preset_dir = NULL;
const char *last_shader_preset_file_name = NULL;
#if defined(HAVE_MENU)
menu_handle_t *menu = (menu_handle_t*)menu_driver_data_;
enum rarch_shader_type last_shader_preset_type = menu ? menu->last_shader_selection.preset_type : RARCH_SHADER_NONE;
menu_driver_get_last_shader_preset_path(
&last_shader_preset_dir, &last_shader_preset_file_name);
#else
enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
#endif
/* Always free existing shader list */
video_shader_dir_free_shader(dir_list,
video_shader_remember_last_dir);
/* Try directory of last selected shader preset */
if (shader_remember_last_dir &&
(last_shader_preset_type != RARCH_SHADER_NONE) &&
!string_is_empty(last_shader_preset_dir) &&
video_shader_dir_init_shader_internal(
video_shader_remember_last_dir,
dir_list,
last_shader_preset_dir,
last_shader_preset_file_name,
show_hidden_files))
return;
/* Try video shaders directory */
if (!string_is_empty(directory_video_shader) &&
video_shader_dir_init_shader_internal(
video_shader_remember_last_dir,
dir_list,
directory_video_shader, NULL, show_hidden_files))
return;
/* Try config directory */
if (!string_is_empty(directory_menu_config) &&
video_shader_dir_init_shader_internal(
video_shader_remember_last_dir,
dir_list,
directory_menu_config, NULL, show_hidden_files))
return;
/* Try 'top level' directory containing main
* RetroArch config file */
if (!path_is_empty(RARCH_PATH_CONFIG))
{
char *rarch_config_directory = strdup(path_get(RARCH_PATH_CONFIG));
path_basedir(rarch_config_directory);
if (!string_is_empty(rarch_config_directory))
video_shader_dir_init_shader_internal(
video_shader_remember_last_dir,
dir_list,
rarch_config_directory, NULL, show_hidden_files);
free(rarch_config_directory);
}
}
void video_shader_dir_check_shader(
void *menu_driver_data_,
settings_t *settings,
struct rarch_dir_shader_list *dir_list,
bool pressed_next,
bool pressed_prev)
{
bool video_shader_remember_last_dir = settings->bools.video_shader_remember_last_dir;
const char *last_shader_preset_dir = NULL;
const char *last_shader_preset_file_name = NULL;
const char *set_shader_path = NULL;
bool dir_list_initialised = false;
#if defined(HAVE_MENU)
void *menu_ptr = menu_driver_data_;
menu_handle_t *menu = (menu_handle_t*)menu_ptr;
enum rarch_shader_type last_shader_preset_type = menu ? menu->last_shader_selection.preset_type : RARCH_SHADER_NONE;
menu_driver_get_last_shader_preset_path(
&last_shader_preset_dir, &last_shader_preset_file_name);
#else
void *menu_ptr = NULL;
enum rarch_shader_type last_shader_preset_type = RARCH_SHADER_NONE;
#endif
/* Check whether shader list needs to be
* (re)initialised */
if (!dir_list->shader_list ||
(dir_list->remember_last_preset_dir != video_shader_remember_last_dir) ||
(video_shader_remember_last_dir &&
(last_shader_preset_type != RARCH_SHADER_NONE) &&
!string_is_equal(dir_list->directory, last_shader_preset_dir)))
{
video_shader_dir_init_shader(menu_ptr, settings, dir_list);
dir_list_initialised = true;
}
if (!dir_list->shader_list ||
(dir_list->shader_list->size < 1))
return;
/* Check whether a 'last used' shader file
* name is provided
* > Note: We can end up calling
* string_is_equal(dir_list->directory, last_shader_preset_dir)
* twice. This is wasteful, but we cannot safely cache
* the first result since video_shader_dir_init_shader() is called
* in-between the two invocations... */
if (video_shader_remember_last_dir &&
(last_shader_preset_type != RARCH_SHADER_NONE) &&
string_is_equal(dir_list->directory, last_shader_preset_dir) &&
!string_is_empty(last_shader_preset_file_name))
{
/* Ensure that we start with a dir_list selection
* index matching the last used shader */
if (!dir_list_initialised)
{
const char *current_file_path = NULL;
const char *current_file_name = NULL;
if (dir_list->selection < dir_list->shader_list->size)
current_file_path = dir_list->shader_list->elems[dir_list->selection].data;
if (!string_is_empty(current_file_path))
current_file_name = path_basename(current_file_path);
if (!string_is_empty(current_file_name) &&
!string_is_equal(current_file_name, last_shader_preset_file_name))
{
size_t i;
for (i = 0; i < dir_list->shader_list->size; i++)
{
const char *file_path = dir_list->shader_list->elems[i].data;
const char *file_name = NULL;
if (string_is_empty(file_path))
continue;
file_name = path_basename(file_path);
if (string_is_empty(file_name))
continue;
if (string_is_equal(file_name, last_shader_preset_file_name))
{
dir_list->selection = i;
break;
}
}
}
}
2021-10-15 14:32:07 +02:00
#ifdef HAVE_MENU
/* Check whether the shader referenced by the
* current selection index is already loaded */
if (!dir_list->shader_loaded)
{
struct video_shader *shader = menu_shader_get();
if (shader && !string_is_empty(shader->loaded_preset_path))
{
char last_shader_path[PATH_MAX_LENGTH];
2022-08-12 22:09:33 +02:00
fill_pathname_join(last_shader_path,
last_shader_preset_dir, last_shader_preset_file_name,
sizeof(last_shader_path));
if (string_is_equal(last_shader_path, shader->loaded_preset_path))
dir_list->shader_loaded = true;
}
}
2021-10-15 14:32:07 +02:00
#endif
}
/* Select next shader in list */
if (pressed_next)
{
/* Only increment selection if a shader
* from this list has already been loaded
* (otherwise first entry in the list may
* be skipped) */
if (dir_list->shader_loaded)
{
if (dir_list->selection < dir_list->shader_list->size - 1)
dir_list->selection++;
else
dir_list->selection = 0;
}
}
/* Select previous shader in list */
else if (pressed_prev)
{
if (dir_list->selection > 0)
dir_list->selection--;
else
dir_list->selection = dir_list->shader_list->size - 1;
}
else
return;
set_shader_path = dir_list->shader_list->elems[dir_list->selection].data;
#if defined(HAVE_MENU)
menu_driver_set_last_shader_preset_path(set_shader_path);
#endif
command_set_shader(NULL, set_shader_path);
dir_list->shader_loaded = true;
}
2021-09-18 22:05:03 +02:00
static bool video_shader_load_shader_preset_internal(
2021-09-18 22:05:03 +02:00
char *s,
size_t len,
const char *shader_directory,
const char *core_name,
const char *special_name)
{
int i;
2021-09-18 22:05:03 +02:00
static enum rarch_shader_type types[] =
{
/* Shader preset priority, highest to lowest
* only important for video drivers with multiple shader backends */
RARCH_SHADER_GLSL, RARCH_SHADER_SLANG, RARCH_SHADER_CG, RARCH_SHADER_HLSL
};
for (i = 0; i < ARRAY_SIZE(types); i++)
{
if (!video_shader_is_supported(types[i]))
continue;
/* Concatenate strings into full paths */
if (!string_is_empty(core_name))
fill_pathname_join_special_ext(s,
shader_directory, core_name,
special_name,
video_shader_get_preset_extension(types[i]),
len);
else
{
if (string_is_empty(special_name))
break;
2022-08-12 22:09:33 +02:00
fill_pathname_join(s, shader_directory, special_name, len);
2021-09-18 22:05:03 +02:00
strlcat(s, video_shader_get_preset_extension(types[i]), len);
}
if (path_is_valid(s))
return true;
}
return false;
}
/**
* video_shader_load_auto_shader_preset:
*
* Tries to load a supported core-, game-, folder-specific or global
* shader preset from its respective location:
*
* global: $CONFIG_DIR/global.$PRESET_EXT
* core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.$PRESET_EXT
* folder-specific: $CONFIG_DIR/$CORE_NAME/$FOLDER_NAME.$PRESET_EXT
* game-specific: $CONFIG_DIR/$CORE_NAME/$GAME_NAME.$PRESET_EXT
*
* $CONFIG_DIR is expected to be Menu Config directory, or failing that, the
* directory where retroarch.cfg is stored.
*
* For compatibility purposes with versions 1.8.7 and older, the presets
* subdirectory on the Video Shader path is used as a fallback directory.
*
* Note: Uses video_shader_is_supported() which only works after
* context driver initialization.
*
* Returns: false if there was an error or no action was performed.
*/
static bool video_shader_load_auto_shader_preset(settings_t *settings, const char *core_name,
2021-09-18 22:05:03 +02:00
char *s, size_t len)
{
const char *video_shader_directory = settings->paths.directory_video_shader;
const char *menu_config_directory = settings->paths.directory_menu_config;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
bool has_content = !string_is_empty(rarch_path_basename);
2021-09-18 22:05:03 +02:00
const char *game_name = NULL;
2021-09-18 22:05:03 +02:00
const char *dirs[3] = {0};
size_t i = 0;
char shader_path[PATH_MAX_LENGTH];
char content_dir_name[PATH_MAX_LENGTH];
char config_file_directory[PATH_MAX_LENGTH];
char old_presets_directory[PATH_MAX_LENGTH];
shader_path[0] = '\0';
content_dir_name[0] = '\0';
2022-08-12 22:09:33 +02:00
config_file_directory[0] = '\0';
old_presets_directory[0] = '\0';
2021-09-18 22:05:03 +02:00
if (has_content)
{
2021-09-18 22:05:03 +02:00
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
game_name = path_basename(rarch_path_basename);
}
2021-09-18 22:05:03 +02:00
if (!path_is_empty(RARCH_PATH_CONFIG))
2022-08-12 22:09:33 +02:00
fill_pathname_basedir(config_file_directory,
2021-09-18 22:05:03 +02:00
path_get(RARCH_PATH_CONFIG), sizeof(config_file_directory));
if (!string_is_empty(video_shader_directory))
2022-08-12 22:09:33 +02:00
fill_pathname_join(old_presets_directory,
2021-09-18 22:05:03 +02:00
video_shader_directory, "presets", sizeof(old_presets_directory));
dirs[0] = menu_config_directory;
dirs[1] = config_file_directory;
dirs[2] = old_presets_directory;
for (i = 0; i < ARRAY_SIZE(dirs); i++)
{
if (string_is_empty(dirs[i]))
continue;
2022-08-12 22:09:33 +02:00
/* Game-specific shader preset found? */
if (has_content && video_shader_load_shader_preset_internal(
2022-08-12 22:09:33 +02:00
shader_path,
sizeof(shader_path),
dirs[i], core_name,
game_name))
goto success;
/* Folder-specific shader preset found? */
if (has_content && video_shader_load_shader_preset_internal(
2022-08-12 22:09:33 +02:00
shader_path,
sizeof(shader_path),
dirs[i], core_name,
content_dir_name))
goto success;
2021-09-18 22:05:03 +02:00
/* Core-specific shader preset found? */
if (video_shader_load_shader_preset_internal(
2021-09-18 22:05:03 +02:00
shader_path,
sizeof(shader_path),
dirs[i], core_name,
core_name))
goto success;
/* Global shader preset found? */
if (video_shader_load_shader_preset_internal(
2021-09-18 22:05:03 +02:00
shader_path,
sizeof(shader_path),
dirs[i], NULL,
"global"))
goto success;
}
return false;
success:
/* Shader preset exists, load it. */
strlcpy(s, shader_path, len);
return true;
}
2021-10-15 14:32:07 +02:00
bool video_shader_combine_preset_and_apply(
2021-10-29 14:13:16 +02:00
settings_t *settings,
enum rarch_shader_type type,
struct video_shader *menu_shader,
const char *preset_path,
const char *temp_dir,
bool prepend,
bool message)
{
bool ret = false;
char combined_preset_path[PATH_MAX_LENGTH];
char combined_preset_name[PATH_MAX_LENGTH];
const char *preset_ext = video_shader_get_preset_extension(type);
struct video_shader *shader_to_append = (struct video_shader*) calloc(1, sizeof(*shader_to_append));
struct video_shader *combined_shader = (struct video_shader*) calloc(1, sizeof(*combined_shader));
strlcpy(combined_preset_name, "retroarch", sizeof(combined_preset_name));
strlcat(combined_preset_name, preset_ext, sizeof(combined_preset_name));
fill_pathname_join(combined_preset_path, temp_dir, combined_preset_name, sizeof(combined_preset_path));
video_shader_load_preset_into_shader(preset_path, shader_to_append);
if (prepend)
combine_shaders(combined_shader, shader_to_append, menu_shader);
else
combine_shaders(combined_shader, menu_shader, shader_to_append);
/* We save to the always changing retroarch.slangp, retroarch.glsp...
then load it so that it is similar to Apply Preset */
video_shader_write_preset(combined_preset_path, combined_shader, false);
ret = menu_shader_manager_set_preset(menu_shader, type, combined_preset_path, true);
free(shader_to_append);
free(combined_shader);
return ret;
}
/* Sets and loads the preset in the video driver */
/* Applies the preset to the menu */
bool video_shader_apply_shader(
settings_t *settings,
enum rarch_shader_type type,
const char *preset_path,
bool message)
2021-10-29 14:13:16 +02:00
{
char msg[256];
video_driver_state_t *video_st = video_state_get_ptr();
2021-10-29 14:13:16 +02:00
runloop_state_t *runloop_st = runloop_state_get_ptr();
const char *core_name = runloop_st->system.info.library_name;
const char *preset_file = NULL;
#ifdef HAVE_MENU
struct video_shader *shader = menu_shader_get();
#endif
/* Disallow loading shaders when no core is loaded */
if (string_is_empty(core_name))
return false;
if (!string_is_empty(preset_path))
preset_file = path_basename_nocompression(preset_path);
/* TODO/FIXME - 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 (video_st->current_video->set_shader)
{
if ((video_st->current_video->set_shader(
video_st->data, type, preset_path)))
{
configuration_set_bool(settings, settings->bools.video_shader_enable, true);
if (!string_is_empty(preset_path))
{
strlcpy(runloop_st->runtime_shader_preset_path, preset_path,
sizeof(runloop_st->runtime_shader_preset_path));
#ifdef HAVE_MENU
/* reflect in shader manager */
if (menu_shader_manager_set_preset(
shader, type, preset_path, false))
shader->flags &= ~SHDR_FLAG_MODIFIED;
2021-10-29 14:13:16 +02:00
#endif
}
else
runloop_st->runtime_shader_preset_path[0] = '\0';
if (message)
{
/* Display message */
const char *msg_shader = msg_hash_to_str(MSG_SHADER);
size_t _len = strlcpy(msg, msg_shader, sizeof(msg));
msg[_len ] = ':';
msg[_len+1] = ' ';
msg[_len+2] = '\0';
2021-10-29 14:13:16 +02:00
if (preset_file)
{
msg[_len+2] = '"';
msg[_len+3] = '\0';
_len = strlcat(msg, preset_file, sizeof(msg));
msg[_len ] = '"';
msg[_len+1] = '\0';
}
2021-10-29 14:13:16 +02:00
else
strlcat(msg, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE), sizeof(msg));
2021-10-29 14:13:16 +02:00
#ifdef HAVE_GFX_WIDGETS
if (dispwidget_get_ptr()->active)
gfx_widget_set_generic_message(msg, 2000);
else
#endif
runloop_msg_queue_push(msg, 1, 120, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
2022-01-31 19:05:23 +02:00
RARCH_LOG("[Shaders]: %s: \"%s\".\n",
2021-10-29 14:13:16 +02:00
msg_hash_to_str(MSG_APPLYING_SHADER),
preset_path ? preset_path : "null");
return true;
}
}
#ifdef HAVE_MENU
/* reflect in shader manager */
menu_shader_manager_set_preset(shader, type, NULL, false);
#endif
/* Display error message */
fill_pathname_join_delim(msg,
msg_hash_to_str(MSG_FAILED_TO_APPLY_SHADER_PRESET),
preset_file ? preset_file : "null",
' ',
sizeof(msg));
runloop_msg_queue_push(
msg, 1, 180, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
return false;
}
/* get the name of the current shader preset */
const char *video_shader_get_current_shader_preset(void)
{
settings_t *settings = config_get_ptr();
runloop_state_t *runloop_st = runloop_state_get_ptr();
video_driver_state_t *video_st = video_state_get_ptr();
const char *core_name = runloop_st->system.info.library_name;
bool video_shader_enable = settings->bools.video_shader_enable;
unsigned video_shader_delay = settings->uints.video_shader_delay;
bool auto_shaders_enable = settings->bools.auto_shaders_enable;
bool cli_shader_disable = video_st->flags &
VIDEO_FLAG_CLI_SHADER_DISABLE;
if (!video_shader_enable)
return NULL;
if (video_shader_delay && !runloop_st->shader_delay_timer.timer_end)
return NULL;
/* Disallow loading auto-shaders when no core is loaded */
if (string_is_empty(core_name))
return NULL;
if (!string_is_empty(runloop_st->runtime_shader_preset_path))
return runloop_st->runtime_shader_preset_path;
/* load auto-shader once, --set-shader works like a global auto-shader */
if ( (video_st->flags & VIDEO_FLAG_SHADER_PRESETS_NEED_RELOAD)
&& !cli_shader_disable)
{
video_st->flags &= ~VIDEO_FLAG_SHADER_PRESETS_NEED_RELOAD;
if (video_shader_is_supported(
video_shader_parse_type(video_st->cli_shader_path)))
strlcpy(runloop_st->runtime_shader_preset_path,
video_st->cli_shader_path,
sizeof(runloop_st->runtime_shader_preset_path));
else
{
if (auto_shaders_enable) /* sets runtime_shader_preset_path */
{
if (video_shader_load_auto_shader_preset(
settings,
runloop_st->system.info.library_name,
runloop_st->runtime_shader_preset_path,
sizeof(runloop_st->runtime_shader_preset_path)))
{
2021-12-04 15:21:12 +02:00
RARCH_LOG("[Shaders]: Specific shader preset found at \"%s\".\n",
runloop_st->runtime_shader_preset_path);
}
}
}
return runloop_st->runtime_shader_preset_path;
}
return NULL;
}
void video_shader_toggle(settings_t *settings)
{
bool toggle = !settings->bools.video_shader_enable;
bool refresh = false;
struct video_shader *shader = menu_shader_get();
shader->flags |= SHDR_FLAG_MODIFIED;
if (toggle)
shader->flags &= ~SHDR_FLAG_DISABLED;
else
shader->flags |= SHDR_FLAG_DISABLED;
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
command_event(CMD_EVENT_SHADERS_APPLY_CHANGES, NULL);
/* TODO/FIXME: Due to general_write_handler being called twice,
* this has be done in this order in order to truly disable */
if (!toggle)
configuration_set_bool(settings, settings->bools.video_shader_enable, toggle);
}