diff --git a/config.def.h b/config.def.h index 7899d159b9..251977a4fc 100644 --- a/config.def.h +++ b/config.def.h @@ -278,6 +278,8 @@ #define DEFAULT_SHADER_ENABLE false #endif +#define DEFAULT_SHADER_DELAY 0 + /* Only scale in integer steps. * The base size depends on system-reported geometry and aspect ratio. * If video_force_aspect is not set, X/Y will be integer scaled independently. diff --git a/configuration.c b/configuration.c index f0dfc66e4e..95786ac6c7 100644 --- a/configuration.c +++ b/configuration.c @@ -1747,6 +1747,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #ifdef HAVE_VIDEO_LAYOUT SETTING_UINT("video_layout_selected_view", &settings->uints.video_layout_selected_view, true, 0, false); #endif + SETTING_UINT("video_shader_delay", &settings->uints.video_shader_delay, true, DEFAULT_SHADER_DELAY, false); #ifdef HAVE_COMMAND SETTING_UINT("network_cmd_port", &settings->uints.network_cmd_port, true, network_cmd_port, false); #endif diff --git a/configuration.h b/configuration.h index 44a1a6de64..78436daf09 100644 --- a/configuration.h +++ b/configuration.h @@ -504,6 +504,7 @@ typedef struct settings unsigned video_overscan_correction_top; unsigned video_overscan_correction_bottom; #endif + unsigned video_shader_delay; unsigned menu_timedate_style; unsigned menu_thumbnails; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 74095a08ab..26ca9277ec 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1351,6 +1351,8 @@ MSG_HASH(MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE, "video_force_srgb_disable") MSG_HASH(MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, "video_frame_delay") +MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, + "video_shader_delay") MSG_HASH(MENU_ENUM_LABEL_VIDEO_FULLSCREEN, "video_fullscreen") MSG_HASH(MENU_ENUM_LABEL_VIDEO_GAMMA, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index d4f9180fff..8b6d204c25 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1475,6 +1475,14 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) " \n" "Maximum is 15."); break; + case MENU_ENUM_LABEL_VIDEO_SHADER_DELAY: + snprintf(s, len, + "Sets by how many milliseconds auto-loading shaders\n" + "are delayed.\n" + "\n" + "Can work around graphical glitches due to using\n" + "'screen grabbing' software like streaming software."); + break; case MENU_ENUM_LABEL_VIDEO_HARD_SYNC_FRAMES: snprintf(s, len, "Sets how many frames CPU can \n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 14ef4ea7ba..73ecccf041 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -3780,6 +3780,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, "Frame Delay" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DELAY, + "Auto-Shader Delay" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, "Start in Fullscreen Mode" @@ -4419,6 +4423,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, "Reduces latency at the cost of a higher risk of video stuttering. Adds a delay after V-Sync (in ms)." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_DELAY, + "Delays auto-loading shaders (in ms). Can work around graphical glitches when using 'screen grabbing' software." + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, "Sets how many frames the CPU can run ahead of the GPU when using 'Hard GPU Sync'." diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 62952c3986..be65741381 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -194,6 +194,7 @@ default_sublabel_macro(action_bind_sublabel_input_hotkey_settings, MENU_ default_sublabel_macro(action_bind_sublabel_materialui_icons_enable, MENU_ENUM_SUBLABEL_MATERIALUI_ICONS_ENABLE) default_sublabel_macro(action_bind_sublabel_add_content_list, MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST) default_sublabel_macro(action_bind_sublabel_video_frame_delay, MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY) +default_sublabel_macro(action_bind_sublabel_video_shader_delay, MENU_ENUM_SUBLABEL_VIDEO_SHADER_DELAY) default_sublabel_macro(action_bind_sublabel_video_black_frame_insertion, MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION) default_sublabel_macro(action_bind_sublabel_systeminfo_cpu_cores, MENU_ENUM_SUBLABEL_CPU_CORES) default_sublabel_macro(action_bind_sublabel_toggle_gamepad_combo, MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO) @@ -2543,6 +2544,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_frame_delay); break; + case MENU_ENUM_LABEL_VIDEO_SHADER_DELAY: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_shader_delay); + break; case MENU_ENUM_LABEL_ADD_CONTENT_LIST: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_add_content_list); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 0be1cce8f1..867ab61407 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -7488,6 +7488,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist_parse_settings_enum(info->list, MENU_ENUM_LABEL_VIDEO_SMOOTH, PARSE_ONLY_BOOL, false); + if (menu_displaylist_parse_settings_enum(info->list, + MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, + PARSE_ONLY_UINT, false) == 0) + count++; menu_displaylist_parse_settings_enum(info->list, MENU_ENUM_LABEL_VIDEO_FILTER, PARSE_ONLY_PATH, false); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d4c25a6591..cde4642e0e 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -9531,6 +9531,21 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, 15, 1, true, true); SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED); + CONFIG_UINT( + list, list_info, + &settings->uints.video_shader_delay, + MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, + MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DELAY, + DEFAULT_SHADER_DELAY, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + menu_settings_list_current_add_range(list, list_info, 0, 0, 1, true, false); + SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_ADVANCED); + #if !defined(RARCH_MOBILE) if (video_driver_test_all_flags(GFX_CTX_FLAGS_BLACK_FRAME_INSERTION)) { diff --git a/menu/menu_shader.c b/menu/menu_shader.c index 8756dd6f17..474472012e 100644 --- a/menu/menu_shader.c +++ b/menu/menu_shader.c @@ -168,7 +168,7 @@ bool menu_shader_manager_set_preset(struct video_shader *shader, bool refresh = false; bool ret = false; - if (apply && !retroarch_apply_shader(type, preset_path)) + if (apply && !retroarch_apply_shader(type, preset_path, true)) { /* We don't want to disable shaders entirely here, * just reset number of passes diff --git a/msg_hash.h b/msg_hash.h index 3ae7fdcff0..238bb8973c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -821,6 +821,7 @@ enum msg_hash_enums MENU_LABEL(VIDEO_GPU_SCREENSHOT), MENU_LABEL(VIDEO_BLACK_FRAME_INSERTION), MENU_LABEL(VIDEO_FRAME_DELAY), + MENU_LABEL(VIDEO_SHADER_DELAY), MENU_LABEL(VIDEO_VSYNC), MENU_LABEL(VIDEO_ADAPTIVE_VSYNC), MENU_LABEL(VIDEO_HARD_SYNC), diff --git a/performance_counters.c b/performance_counters.c index f453e67afe..774a72023e 100644 --- a/performance_counters.c +++ b/performance_counters.c @@ -133,7 +133,7 @@ int rarch_timer_get_timeout(rarch_timer_t *timer) { if (!timer) return 0; - return (int)timer->timeout_us / 1000000; + return (int)(timer->timeout_us / 1000000); } bool rarch_timer_is_running(rarch_timer_t *timer) @@ -185,3 +185,13 @@ void rarch_timer_begin(rarch_timer_t *timer, uint64_t sec) timer->timer_begin = true; timer->timer_end = false; } + +void rarch_timer_begin_us(rarch_timer_t *timer, uint64_t usec) +{ + if (!timer) + return; + rarch_timer_begin_new_time_us(timer, usec); + timer->timer_begin = true; + timer->timer_end = false; +} + diff --git a/performance_counters.h b/performance_counters.h index 9aedbbd5e7..e36e4ffe0c 100644 --- a/performance_counters.h +++ b/performance_counters.h @@ -95,7 +95,9 @@ bool rarch_timer_is_running(rarch_timer_t *timer); bool rarch_timer_has_expired(rarch_timer_t *timer); -void rarch_timer_begin(rarch_timer_t *timer, uint64_t ms); +void rarch_timer_begin(rarch_timer_t *timer, uint64_t sec); + +void rarch_timer_begin_us(rarch_timer_t *timer, uint64_t usec); void rarch_timer_begin_new_time(rarch_timer_t *timer, uint64_t sec); diff --git a/retroarch.c b/retroarch.c index 429042908f..25dbc3357b 100644 --- a/retroarch.c +++ b/retroarch.c @@ -921,6 +921,7 @@ static bool shader_presets_need_reload = true; static char cli_shader[PATH_MAX_LENGTH] = {0}; static bool cli_shader_disable = false; static char runtime_shader_preset[PATH_MAX_LENGTH] = {0}; +static rarch_timer_t shader_delay_timer = {0}; #endif static char runloop_max_frames_screenshot_path[PATH_MAX_LENGTH] = {0}; static char runtime_content_path[PATH_MAX_LENGTH] = {0}; @@ -2217,7 +2218,7 @@ static const struct cmd_map map[] = { }; #endif -bool retroarch_apply_shader(enum rarch_shader_type type, const char *preset_path) +bool retroarch_apply_shader(enum rarch_shader_type type, const char *preset_path, bool message) { #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) settings_t *settings = configuration_settings; @@ -2242,17 +2243,21 @@ bool retroarch_apply_shader(enum rarch_shader_type type, const char *preset_path menu_shader_set_modified(false); #endif - /* Display message */ - snprintf(msg, sizeof(msg), - preset_file ? "Shader: \"%s\"" : "Shader: %s", - preset_file ? preset_file : "None"); + if (message) + { + /* Display message */ + snprintf(msg, sizeof(msg), + preset_file ? "Shader: \"%s\"" : "Shader: %s", + preset_file ? preset_file : "None"); #ifdef HAVE_MENU_WIDGETS - if (menu_widgets_inited) - menu_widgets_set_message(msg); - else + if (menu_widgets_inited) + menu_widgets_set_message(msg); + else #endif - runloop_msg_queue_push(msg, 1, 120, true, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + runloop_msg_queue_push(msg, 1, 120, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } + RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_APPLYING_SHADER), preset_path ? preset_path : "null"); @@ -2301,7 +2306,7 @@ bool command_set_shader(const char *arg) } } - return retroarch_apply_shader(type, arg); + return retroarch_apply_shader(type, arg, true); #else return false; #endif @@ -4060,6 +4065,8 @@ static bool command_event_init_core(enum rarch_core_type type) /* Load auto-shaders on the next occasion */ #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) shader_presets_need_reload = true; + shader_delay_timer.timer_begin = false; /* not initialized */ + shader_delay_timer.timer_end = false; /* not expired */ #endif /* reset video format to libretro's default */ @@ -21589,8 +21596,8 @@ static void retroarch_print_help(const char *arg0) puts(" -s, --save=PATH Path for save files (*.srm)."); puts(" -S, --savestate=PATH Path for the save state files (*.state)."); puts(" --set-shader PATH Path to a shader (preset) that will be loaded each time content is loaded.\n" - " Effectively overrides core shader presets.\n" - " An empty argument \"\" will disable shader core presets."); + " Effectively overrides automatic shader presets.\n" + " An empty argument \"\" will disable automatic shader presets."); puts(" -f, --fullscreen Start the program in fullscreen regardless " "of config settings."); puts(" -c, --config=FILE Path for config file." @@ -23545,6 +23552,9 @@ const char* retroarch_get_shader_preset(void) if (!settings->bools.video_shader_enable) return NULL; + if (settings->uints.video_shader_delay && !shader_delay_timer.timer_end) + return NULL; + if (!string_is_empty(runtime_shader_preset)) return runtime_shader_preset; @@ -24820,14 +24830,7 @@ static enum runloop_state runloop_check_state(void) need_to_apply = true; if (!rarch_timer_is_running(&timer)) - { - /* rarch_timer_t convenience functions only support whole seconds. */ - - /* rarch_timer_begin */ - timer.timeout_end = cpu_features_get_time_usec() + SHADER_FILE_WATCH_DELAY_MSEC * 1000; - timer.timer_begin = true; - timer.timer_end = false; - } + rarch_timer_begin_us(&timer, SHADER_FILE_WATCH_DELAY_MSEC * 1000); } /* If a file is modified atomically (moved/renamed from a different file), @@ -24840,9 +24843,7 @@ static enum runloop_state runloop_check_state(void) */ if (need_to_apply) { - /* rarch_timer_tick */ - timer.current = cpu_features_get_time_usec(); - timer.timeout_us = (timer.timeout_end - timer.current); + rarch_timer_tick(&timer); if (!timer.timer_end && rarch_timer_has_expired(&timer)) { @@ -24852,6 +24853,27 @@ static enum runloop_state runloop_check_state(void) } } } + + if (settings->uints.video_shader_delay && !shader_delay_timer.timer_end) + { + if (!rarch_timer_is_running(&shader_delay_timer)) + rarch_timer_begin_us(&shader_delay_timer, settings->uints.video_shader_delay * 1000); + else + { + rarch_timer_tick(&shader_delay_timer); + + if (rarch_timer_has_expired(&shader_delay_timer)) + { + rarch_timer_end(&shader_delay_timer); + + { + const char *preset = retroarch_get_shader_preset(); + enum rarch_shader_type type = video_shader_parse_type(preset); + retroarch_apply_shader(type, preset, false); + } + } + } + } #endif return RUNLOOP_STATE_ITERATE; diff --git a/retroarch.h b/retroarch.h index 39b42f5db8..3db197d99b 100644 --- a/retroarch.h +++ b/retroarch.h @@ -323,7 +323,8 @@ bool retroarch_is_forced_fullscreen(void); void retroarch_set_current_core_type( enum rarch_core_type type, bool explicitly_set); -bool retroarch_apply_shader(enum rarch_shader_type type, const char *preset_path); +bool retroarch_apply_shader(enum rarch_shader_type type, const char *preset_path, + bool message); const char* retroarch_get_shader_preset(void); diff --git a/ui/drivers/qt/options/video.cpp b/ui/drivers/qt/options/video.cpp index a23436cff0..2b85c12c50 100644 --- a/ui/drivers/qt/options/video.cpp +++ b/ui/drivers/qt/options/video.cpp @@ -144,6 +144,7 @@ QWidget *VideoPage::widget() miscGroup->add(MENU_ENUM_LABEL_VIDEO_GPU_SCREENSHOT); miscGroup->add(MENU_ENUM_LABEL_VIDEO_CROP_OVERSCAN); miscGroup->add(MENU_ENUM_LABEL_VIDEO_SMOOTH); + miscGroup->add(MENU_ENUM_LABEL_VIDEO_SHADER_DELAY); syncMiscLayout->addWidget(syncGroup); syncMiscLayout->addWidget(miscGroup);