Automatic Frame Delay improvements (#14754)

This commit is contained in:
sonninnos 2022-12-22 19:58:26 +02:00 committed by GitHub
parent 1334bd0408
commit 05c3c0a552
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 221 additions and 174 deletions

View File

@ -949,10 +949,8 @@ void recording_dump_frame(
unsigned height, size_t pitch, bool is_idle)
{
struct record_video_data ffemu_data;
video_driver_state_t
*video_st = &video_driver_st;
recording_state_t
*record_st = recording_state_get_ptr();
video_driver_state_t *video_st = &video_driver_st;
recording_state_t *record_st = recording_state_get_ptr();
ffemu_data.data = data;
ffemu_data.width = width;
@ -1290,7 +1288,6 @@ bool video_display_server_get_flags(gfx_ctx_flags_t *flags)
return true;
}
bool video_driver_is_threaded(void)
{
#ifdef HAVE_THREADS
@ -2412,7 +2409,7 @@ bool video_driver_find_driver(
RARCH_LOG_OUTPUT("Available %ss are:\n", prefix);
for (d = 0; video_drivers[d]; d++)
RARCH_LOG_OUTPUT("\t%s\n", video_drivers[d]->ident);
RARCH_WARN("Going to default to first %s...\n", prefix);
RARCH_WARN("Going to default to first %s..\n", prefix);
}
if (!(video_st->current_video = (video_driver_t*)video_drivers[0]))
@ -2687,7 +2684,7 @@ size_t video_driver_get_window_title(char *buf, unsigned len)
void video_driver_build_info(video_frame_info_t *video_info)
{
video_viewport_t *custom_vp = NULL;
runloop_state_t *runloop_st = runloop_state_get_ptr();
runloop_state_t *runloop_st = runloop_state_get_ptr();
settings_t *settings = config_get_ptr();
video_driver_state_t *video_st = &video_driver_st;
input_driver_state_t *input_st = input_state_get_ptr();
@ -2699,7 +2696,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
#endif
#ifdef HAVE_THREADS
bool is_threaded =
VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
VIDEO_DRIVER_THREADED_LOCK(video_st, is_threaded);
#endif
@ -2710,9 +2707,8 @@ void video_driver_build_info(video_frame_info_t *video_info)
video_info->widgets_active = false;
#endif
#ifdef HAVE_MENU
video_info->notifications_hidden =
settings->bools.notification_show_when_menu_is_alive && !(menu_st->flags &
MENU_ST_FLAG_ALIVE);
video_info->notifications_hidden = settings->bools.notification_show_when_menu_is_alive
&& !(menu_st->flags & MENU_ST_FLAG_ALIVE);
#endif
video_info->refresh_rate = settings->floats.video_refresh_rate;
video_info->crt_switch_resolution = settings->uints.crt_switch_resolution;
@ -2730,11 +2726,12 @@ void video_driver_build_info(video_frame_info_t *video_info)
video_info->core_status_msg_show = runloop_st->core_status_msg.set;
video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
video_info->post_filter_record = settings->bools.video_post_filter_record;
video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons;
video_info->input_menu_swap_ok_cancel_buttons
= settings->bools.input_menu_swap_ok_cancel_buttons;
video_info->max_swapchain_images = settings->uints.video_max_swapchain_images;
video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen;
video_info->fullscreen = settings->bools.video_fullscreen
|| (video_st->flags & VIDEO_FLAG_FORCE_FULLSCREEN);
|| (video_st->flags & VIDEO_FLAG_FORCE_FULLSCREEN);
video_info->menu_mouse_enable = settings->bools.menu_mouse_enable;
video_info->monitor_index = settings->uints.video_monitor_index;
@ -2753,12 +2750,9 @@ void video_driver_build_info(video_frame_info_t *video_info)
#if defined(HAVE_GFX_WIDGETS)
video_info->widgets_userdata = p_dispwidget;
video_info->widgets_is_paused = video_st->flags &
VIDEO_FLAG_WIDGETS_PAUSED;
video_info->widgets_is_fast_forwarding = video_st->flags &
VIDEO_FLAG_WIDGETS_FAST_FORWARD;
video_info->widgets_is_rewinding = video_st->flags &
VIDEO_FLAG_WIDGETS_REWINDING;
video_info->widgets_is_paused = video_st->flags & VIDEO_FLAG_WIDGETS_PAUSED;
video_info->widgets_is_fast_forwarding = video_st->flags & VIDEO_FLAG_WIDGETS_FAST_FORWARD;
video_info->widgets_is_rewinding = video_st->flags & VIDEO_FLAG_WIDGETS_REWINDING;
#else
video_info->widgets_userdata = NULL;
video_info->widgets_is_paused = false;
@ -2769,21 +2763,18 @@ VIDEO_FLAG_WIDGETS_FAST_FORWARD;
video_info->width = video_st->width;
video_info->height = video_st->height;
video_info->use_rgba = video_st->flags &
VIDEO_FLAG_USE_RGBA;
video_info->use_rgba = video_st->flags & VIDEO_FLAG_USE_RGBA;
video_info->hdr_enable = settings->bools.video_hdr_enable;
video_info->libretro_running = false;
video_info->msg_bgcolor_enable =
settings->bools.video_msg_bgcolor_enable;
video_info->msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable;
video_info->fps_update_interval = settings->uints.fps_update_interval;
video_info->memory_update_interval = settings->uints.memory_update_interval;
#ifdef HAVE_MENU
video_info->menu_is_alive = menu_st->flags & MENU_ST_FLAG_ALIVE;
video_info->menu_screensaver_active = menu_st->flags &
MENU_ST_FLAG_SCREENSAVER_ACTIVE;
video_info->menu_screensaver_active = menu_st->flags & MENU_ST_FLAG_SCREENSAVER_ACTIVE;
video_info->menu_footer_opacity = settings->floats.menu_footer_opacity;
video_info->menu_header_opacity = settings->floats.menu_header_opacity;
video_info->materialui_color_theme = settings->uints.menu_materialui_color_theme;
@ -2793,18 +2784,12 @@ VIDEO_FLAG_WIDGETS_FAST_FORWARD;
video_info->xmb_color_theme = settings->uints.menu_xmb_color_theme;
video_info->timedate_enable = settings->bools.menu_timedate_enable;
video_info->battery_level_enable = settings->bools.menu_battery_level_enable;
video_info->xmb_shadows_enable =
settings->bools.menu_xmb_shadows_enable;
video_info->xmb_alpha_factor =
settings->uints.menu_xmb_alpha_factor;
video_info->menu_wallpaper_opacity =
settings->floats.menu_wallpaper_opacity;
video_info->menu_framebuffer_opacity =
settings->floats.menu_framebuffer_opacity;
video_info->xmb_shadows_enable = settings->bools.menu_xmb_shadows_enable;
video_info->xmb_alpha_factor = settings->uints.menu_xmb_alpha_factor;
video_info->menu_wallpaper_opacity = settings->floats.menu_wallpaper_opacity;
video_info->menu_framebuffer_opacity = settings->floats.menu_framebuffer_opacity;
video_info->overlay_behind_menu = settings->bools.input_overlay_behind_menu;
video_info->libretro_running = runloop_st->current_core.flags &
RETRO_CORE_FLAG_GAME_LOADED;
video_info->libretro_running = runloop_st->current_core.flags & RETRO_CORE_FLAG_GAME_LOADED;
#else
video_info->menu_is_alive = false;
video_info->menu_screensaver_active = false;
@ -2828,14 +2813,12 @@ RETRO_CORE_FLAG_GAME_LOADED;
video_info->runloop_is_slowmotion = runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION;
video_info->fastforward_frameskip = settings->bools.fastforward_frameskip;
video_info->input_driver_nonblock_state = input_st ?
(input_st->flags & INP_FLAG_NONBLOCKING) : false;
video_info->input_driver_grab_mouse_state = (input_st->flags &
INP_FLAG_GRAB_MOUSE_STATE);
video_info->input_driver_nonblock_state = input_st
? (input_st->flags & INP_FLAG_NONBLOCKING) : false;
video_info->input_driver_grab_mouse_state = (input_st->flags & INP_FLAG_GRAB_MOUSE_STATE);
video_info->disp_userdata = disp_get_ptr();
video_info->userdata =
VIDEO_DRIVER_GET_PTR_INTERNAL(video_st);
video_info->userdata = VIDEO_DRIVER_GET_PTR_INTERNAL(video_st);
#ifdef HAVE_THREADS
VIDEO_DRIVER_THREADED_UNLOCK(video_st, is_threaded);
@ -3139,7 +3122,7 @@ bool video_context_driver_set_flags(gfx_ctx_flags_t *flags)
}
video_st->current_video_context.set_flags(
video_st->context_data, flags->flags);
video_st->context_data, flags->flags);
return true;
}
@ -3461,10 +3444,10 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
video.width = width;
video.height = height;
video.fullscreen = settings->bools.video_fullscreen ||
(video_st->flags & VIDEO_FLAG_FORCE_FULLSCREEN);
video.vsync = settings->bools.video_vsync &&
(!(runloop_st->flags & RUNLOOP_FLAG_FORCE_NONBLOCK));
video.fullscreen = settings->bools.video_fullscreen
|| (video_st->flags & VIDEO_FLAG_FORCE_FULLSCREEN);
video.vsync = settings->bools.video_vsync
&& (!(runloop_st->flags & RUNLOOP_FLAG_FORCE_NONBLOCK));
video.force_aspect = settings->bools.video_force_aspect;
video.font_enable = settings->bools.video_font_enable;
video.swap_interval = runloop_get_video_swap_interval(
@ -3480,13 +3463,12 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
video.font_size = settings->floats.video_font_size;
video.path_font = settings->paths.path_font;
#ifdef HAVE_VIDEO_FILTER
video.rgb32 =
video_st->state_filter
? (video_st->flags & VIDEO_FLAG_STATE_OUT_RGB32)
: (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
video.rgb32 = video_st->state_filter
? (video_st->flags & VIDEO_FLAG_STATE_OUT_RGB32)
: (video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
#else
video.rgb32 =
(video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
(video_driver_pix_fmt == RETRO_PIXEL_FORMAT_XRGB8888);
#endif
video.parent = 0;
@ -3499,19 +3481,17 @@ bool video_driver_init_internal(bool *video_is_threaded, bool verbosity_enabled)
tmp = input_state_get_ptr()->current_driver;
/* Need to grab the "real" video driver interface on a reinit. */
video_driver_find_driver(settings,
"video driver", verbosity_enabled);
video_driver_find_driver(settings, "video driver", verbosity_enabled);
#ifdef HAVE_THREADS
video.is_threaded =
VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
video.is_threaded = VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
*video_is_threaded = video.is_threaded;
if (video.is_threaded)
{
bool ret;
/* Can't do hardware rendering with threaded driver currently. */
RARCH_LOG("[Video]: Starting threaded video driver ...\n");
RARCH_LOG("[Video]: Starting threaded video driver..\n");
ret = video_init_thread(
(const video_driver_t**)&video_st->current_video,
@ -3522,7 +3502,7 @@ VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
video);
if (!ret)
{
RARCH_ERR("[Video]: Cannot open threaded video driver ... Exiting ...\n");
RARCH_ERR("[Video]: Cannot open threaded video driver.. Exiting..\n");
return false;
}
}
@ -3535,7 +3515,7 @@ VIDEO_DRIVER_IS_THREADED_INTERNAL(video_st);
if (!video_st->data)
{
RARCH_ERR("[Video]: Cannot open video driver ... Exiting ...\n");
RARCH_ERR("[Video]: Cannot open video driver.. Exiting..\n");
return false;
}
@ -3784,15 +3764,15 @@ void video_driver_frame(const void *data, unsigned width,
status_text[buf_pos+3] = ' ';
status_text[buf_pos+4] = '\0';
}
buf_pos = strlcat(status_text, msg_hash_to_str(MSG_FRAMES),
sizeof(status_text));
buf_pos = strlcat(status_text,
msg_hash_to_str(MSG_FRAMES),
sizeof(status_text));
status_text[buf_pos ] = ':';
status_text[++buf_pos] = ' ';
status_text[++buf_pos] = '\0';
buf_pos += snprintf(
status_text + buf_pos,
sizeof(status_text) - buf_pos,
"%" PRIu64, (uint64_t)video_st->frame_count);
buf_pos += snprintf(status_text + buf_pos,
sizeof(status_text) - buf_pos,
"%" PRIu64, (uint64_t)video_st->frame_count);
}
if (video_info.memory_show)
@ -4189,43 +4169,52 @@ void video_driver_reinit(int flags)
settings_t *settings = config_get_ptr();
video_driver_state_t *video_st = &video_driver_st;
struct retro_hw_render_callback *hwr =
VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(video_st);
VIDEO_DRIVER_GET_HW_CONTEXT_INTERNAL(video_st);
if (hwr->cache_context != false)
video_st->flags |= VIDEO_FLAG_CACHE_CONTEXT;
video_st->flags |= VIDEO_FLAG_CACHE_CONTEXT;
else
video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT;
video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT;
video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT_ACK;
video_driver_reinit_context(settings, flags);
video_st->flags &= ~VIDEO_FLAG_CACHE_CONTEXT;
}
uint32_t video_driver_get_st_flags(void)
{
video_driver_state_t *video_st = &video_driver_st;
return video_st->flags;
}
#define FRAME_DELAY_AUTO_DEBUG 0
void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_auto_t *vfda)
{
unsigned i = 0;
unsigned frame_time = 0;
unsigned frame_time_frames = vfda->frame_time_interval;
unsigned frame_time_target = 1000000.0f / vfda->refresh_rate;
unsigned frame_time_limit_min = frame_time_target * 1.30f;
unsigned frame_time_limit_med = frame_time_target * 1.50f;
unsigned frame_time_limit_max = frame_time_target * 1.90f;
unsigned frame_time_limit_cap = frame_time_target * 3.00f;
unsigned frame_time_limit_ign = frame_time_target * 3.50f;
retro_time_t frame_time_min = frame_time_target;
retro_time_t frame_time_max = frame_time_target;
unsigned frame_time_count_pos = 0;
unsigned frame_time_count_min = 0;
unsigned frame_time_count_med = 0;
unsigned frame_time_count_max = 0;
unsigned frame_time_count_ign = 0;
unsigned frame_time_index =
(video_st->frame_time_count &
(MEASURE_FRAME_TIME_SAMPLES_COUNT - 1));
uint32_t frame_time_average = 0;
uint32_t frame_time_delta = 0;
uint32_t frame_time_min = 0;
uint32_t frame_time_max = 0;
uint16_t frame_time_index = (video_st->frame_time_count & (MEASURE_FRAME_TIME_SAMPLES_COUNT - 1));
uint16_t frame_time_target = 1000000.0f / vfda->refresh_rate;
uint16_t frame_time_limit_mar = frame_time_target * 1.15f;
uint16_t frame_time_limit_min = frame_time_target * 1.30f;
uint16_t frame_time_limit_med = frame_time_target * 1.50f;
uint16_t frame_time_limit_max = frame_time_target * 1.85f;
uint16_t frame_time_limit_cap = frame_time_target * 3.00f;
uint16_t frame_time_limit_ign = frame_time_target * 3.25f;
uint8_t frame_time_frames = vfda->frame_time_interval;
uint8_t frame_time_count_pos = 0;
uint8_t frame_time_count_min = 0;
uint8_t frame_time_count_med = 0;
uint8_t frame_time_count_max = 0;
uint8_t frame_time_count_ign = 0;
uint8_t i = 0;
/* Initialize min & max to target */
frame_time_min = frame_time_max = frame_time_target;
/* Calculate average frame time */
for (i = 1; i < frame_time_frames + 1; i++)
{
retro_time_t frame_time_i = 0;
uint32_t frame_time_i = 0;
if (i > frame_time_index)
continue;
@ -4255,25 +4244,26 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au
frame_time_i = frame_time_limit_cap;
}
frame_time += frame_time_i;
frame_time_average += frame_time_i;
}
frame_time /= frame_time_frames;
frame_time_average /= frame_time_frames;
frame_time_delta = frame_time_max - frame_time_min;
/* Ignore values when core is doing internal frame skipping */
if (frame_time_count_ign > 0)
frame_time = 0;
frame_time_average = frame_time_target;
/* Special handlings for different video driver frame timings */
if (frame_time < frame_time_limit_med && frame_time > frame_time_target)
if ( ( frame_time_average > frame_time_target
&& frame_time_average < frame_time_limit_med)
|| (frame_time_delta > frame_time_limit_max))
{
retro_time_t frame_time_frames_half = frame_time_frames / 2;
retro_time_t frame_time_delta = frame_time_max - frame_time_min;
uint8_t frame_time_frames_half = frame_time_frames / 2;
/* Ensure outcome on certain conditions */
int mode = 0;
int8_t mode = 0;
/* All frames are above the target */
/* All interval frames are above the target */
if (frame_time_count_pos == frame_time_frames)
mode = 1;
/* At least half of interval frames are above minimum level */
@ -4281,27 +4271,30 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au
mode = 2;
/* D3Dx stripe equalizer */
else if (
frame_time_count_pos == frame_time_frames_half
&& ((
( frame_time_count_min > 1
|| frame_time_count_med > 0)
&& frame_time_delta > (frame_time_target / 3)
&& frame_time_delta < (frame_time_target / 2)
)
|| (frame_time_count_min > 2)
)
&& frame_time > frame_time_target
(frame_time_count_pos == frame_time_frames_half)
&& ( frame_time_count_min > 0
|| frame_time_count_med > 0)
&& (frame_time_delta > frame_time_target / 2.50f)
)
mode = 3;
/* Boost med/max spikes */
else if (
( frame_time_count_pos >= frame_time_frames_half)
&& ( frame_time_count_max > 0
|| frame_time_count_med > 1)
&& ( frame_time_count_max == frame_time_count_med)
&& ( frame_time_delta < frame_time_target)
(frame_time_count_pos > frame_time_frames_half)
&& ( frame_time_count_med > 1
|| frame_time_count_max > 0)
&& (frame_time_average > frame_time_limit_mar)
&& (frame_time_delta < frame_time_limit_min)
)
mode = 4;
/* Boost min/med spikes */
else if (
(frame_time_count_pos >= frame_time_frames_half)
&& ( frame_time_count_min > 1
|| frame_time_count_med > 0)
&& (frame_time_count_max == 0)
&& (frame_time_average > frame_time_limit_mar)
)
mode = 5;
/* Ignore */
else if (
(frame_time_delta > frame_time_target)
@ -4309,49 +4302,52 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au
)
mode = -1;
if (mode > 0)
if (mode > 0 && frame_time_average < frame_time_limit_med)
{
#if FRAME_DELAY_AUTO_DEBUG
RARCH_LOG("[Video]: Frame delay nudge %d by mode %d.\n", frame_time, mode);
RARCH_LOG("[Video]: Frame delay nudge %d by mode %d.\n", frame_time_average, mode);
#endif
frame_time = frame_time_limit_med;
frame_time_average = frame_time_limit_med;
}
else if (mode < 0)
{
#if FRAME_DELAY_AUTO_DEBUG
RARCH_LOG("[Video]: Frame delay ignore %d.\n", frame_time);
RARCH_LOG("[Video]: Frame delay ignore %d.\n", frame_time_average);
#endif
frame_time = 0;
frame_time_average = frame_time_target;
}
}
/* Final output decision */
if (frame_time > frame_time_limit_min)
if (frame_time_average > frame_time_limit_min)
{
unsigned delay_decrease = 1;
uint8_t delay_decrease = 1;
/* Increase decrease the more frame time is off target */
if (frame_time > frame_time_limit_med && video_st->frame_delay_effective > delay_decrease)
if ( frame_time_average > frame_time_limit_med
&& video_st->frame_delay_effective > delay_decrease)
{
delay_decrease++;
if (frame_time > frame_time_limit_max && video_st->frame_delay_effective > delay_decrease)
if ( frame_time_average > frame_time_limit_max
&& video_st->frame_delay_effective > delay_decrease)
delay_decrease++;
}
vfda->decrease = delay_decrease;
vfda->delay_decrease = delay_decrease;
}
vfda->time = frame_time;
vfda->target = frame_time_target;
vfda->frame_time_average = frame_time_average;
vfda->frame_time_target = frame_time_target;
#if FRAME_DELAY_AUTO_DEBUG
if (frame_time_index > frame_time_frames)
RARCH_LOG("[Video]: %5d / pos:%d min:%d med:%d max:%d / delta:%5d = %5d %5d %5d %5d %5d %5d %5d %5d\n",
frame_time,
RARCH_LOG("[Video]: %5d / pos:%d min:%d med:%d max:%d ign:%d / delta:%5d = %5d %5d %5d %5d %5d %5d %5d %5d\n",
frame_time_average,
frame_time_count_pos,
frame_time_count_min,
frame_time_count_med,
frame_time_count_max,
frame_time_count_ign,
frame_time_max - frame_time_min,
video_st->frame_time_samples[frame_time_index - 1],
video_st->frame_time_samples[frame_time_index - 2],
@ -4364,9 +4360,3 @@ void video_frame_delay_auto(video_driver_state_t *video_st, video_frame_delay_au
);
#endif
}
uint32_t video_driver_get_st_flags(void)
{
video_driver_state_t *video_st = &video_driver_st;
return video_st->flags;
}

View File

@ -912,8 +912,6 @@ typedef struct
unsigned state_scale;
unsigned state_out_bpp;
#endif
unsigned frame_delay_target;
unsigned frame_delay_effective;
unsigned frame_cache_width;
unsigned frame_cache_height;
unsigned width;
@ -946,15 +944,19 @@ typedef struct
char title_buf[64];
char cached_driver_id[32];
uint8_t frame_delay_target;
uint8_t frame_delay_effective;
bool frame_delay_pause;
bool threaded;
} video_driver_state_t;
typedef struct video_frame_delay_auto {
float refresh_rate;
unsigned frame_time_interval;
unsigned decrease;
unsigned target;
unsigned time;
uint16_t frame_time_target;
uint16_t frame_time_average;
uint8_t frame_time_interval;
uint8_t delay_decrease;
} video_frame_delay_auto_t;
extern struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END];

View File

@ -6969,6 +6969,10 @@ void retroarch_menu_running_finished(bool quit)
if (settings && settings->bools.input_overlay_hide_in_menu)
input_overlay_init();
#endif
/* Ignore frame delay target temporarily */
if (settings->bools.video_frame_delay_auto)
video_st->frame_delay_pause = true;
}
bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data)

View File

@ -6371,23 +6371,42 @@ static void setting_get_string_representation_video_frame_delay(rarch_setting_t
char *s, size_t len)
{
settings_t *settings = config_get_ptr();
video_driver_state_t *video_st = video_state_get_ptr();
if (!setting)
return;
if (settings && settings->bools.video_frame_delay_auto)
{
video_driver_state_t *video_st = video_state_get_ptr();
struct menu_state *menu_st = menu_state_get_ptr();
file_list_t *menu_stack = MENU_LIST_GET(menu_st->entries.list, 0);
const char *label = NULL;
if (menu_stack && menu_stack->size)
label = menu_stack->list[menu_stack->size - 1].label;
if (*setting->value.target.unsigned_integer == 0)
snprintf(s, len, "%s (%u %s)",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTOMATIC),
video_st->frame_delay_effective,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_EFFECTIVE));
{
if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST)))
snprintf(s, len, "%s",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTOMATIC));
else
snprintf(s, len, "%s (%u %s)",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_AUTOMATIC),
video_st->frame_delay_effective,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_EFFECTIVE));
}
else
snprintf(s, len, "%u (%u %s)",
*setting->value.target.unsigned_integer,
video_st->frame_delay_effective,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_EFFECTIVE));
{
if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST)))
snprintf(s, len, "%u",
*setting->value.target.unsigned_integer);
else
snprintf(s, len, "%u (%u %s)",
*setting->value.target.unsigned_integer,
video_st->frame_delay_effective,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY_EFFECTIVE));
}
}
else
snprintf(s, len, "%u", *setting->value.target.unsigned_integer);

View File

@ -2000,6 +2000,11 @@ bool command_event(enum event_command cmd, void *data)
case CMD_EVENT_REINIT:
command_event_reinit(
data ? *(const int*)data : DRIVERS_CMD_ALL);
/* Recalibrate frame delay target */
if (settings->bools.video_frame_delay_auto)
video_st->frame_delay_target = 0;
break;
case CMD_EVENT_CHEATS_APPLY:
#ifdef HAVE_CHEATS

View File

@ -2665,9 +2665,15 @@ bool runloop_environment_cb(unsigned cmd, void *data)
if (video_fullscreen)
video_driver_hide_mouse();
/* Recalibrate frame delay target */
/* Recalibrate frame delay target when video reinits
* and pause frame delay when video does not reinit */
if (settings->bools.video_frame_delay_auto)
video_st->frame_delay_target = 0;
{
if (no_video_reinit)
video_st->frame_delay_pause = true;
else
video_st->frame_delay_target = 0;
}
return true;
}
@ -2874,6 +2880,10 @@ bool runloop_environment_cb(unsigned cmd, void *data)
* using core-dependent aspect ratios. */
video_driver_set_aspect_ratio();
/* Ignore frame delay target temporarily */
if (settings->bools.video_frame_delay_auto)
video_st->frame_delay_pause = true;
/* TODO: Figure out what to do, if anything, with
recording. */
}
@ -7891,50 +7901,66 @@ int runloop_iterate(void)
}
}
if (!(input_st->flags & INP_FLAG_NONBLOCKING))
/* Frame delay */
if ( !(input_st->flags & INP_FLAG_NONBLOCKING)
|| (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION))
{
bool skip_delay = core_paused
|| (runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION)
|| (runloop_st->flags & RUNLOOP_FLAG_FASTMOTION);
if (settings->bools.video_frame_delay_auto)
{
static bool slowmotion_prev = false;
static unsigned skip_frames = 0;
float refresh_rate = settings->floats.video_refresh_rate;
unsigned video_swap_interval = runloop_get_video_swap_interval(
float refresh_rate = settings->floats.video_refresh_rate;
uint8_t video_swap_interval = runloop_get_video_swap_interval(
settings->uints.video_swap_interval);
unsigned video_bfi = settings->uints.video_black_frame_insertion;
unsigned frame_time_interval = 8;
bool frame_time_update =
/* Skip some starting frames for stabilization */
uint8_t video_bfi = settings->uints.video_black_frame_insertion;
uint8_t frame_time_interval = 8;
static uint8_t skip_update = 0;
static bool skip_delay_prev = false;
bool frame_time_update =
/* Skip some initial frames for stabilization */
video_st->frame_count > frame_time_interval &&
/* Only update when there are enough frames for averaging */
video_st->frame_count % frame_time_interval == 0;
/* A few frames need to get ignored after slowmotion is disabled */
if (!(runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION) && slowmotion_prev)
skip_frames = frame_time_interval * 2;
/* A few frames must be ignored after slow+fastmotion/pause
* is disabled or geometry change is triggered */
if ( (!skip_delay && skip_delay_prev)
|| video_st->frame_delay_pause)
{
skip_update = frame_time_interval * 4;
video_st->frame_delay_pause = false;
}
if (skip_frames)
skip_frames--;
if (skip_update)
skip_update--;
slowmotion_prev = runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION;
/* Always skip when slowmotion is active */
if (slowmotion_prev)
skip_frames = 1;
skip_delay_prev = skip_delay;
if (skip_frames)
/* Always skip when slow+fastmotion/pause is active */
if (skip_delay_prev)
skip_update = 1;
if (skip_update)
frame_time_update = false;
/* Black frame insertion + swap interval multiplier */
refresh_rate = (refresh_rate / (video_bfi + 1.0f) / video_swap_interval);
/* Set target moderately as half frame time with 0 delay */
/* Set target moderately as half frame time with 0 (Auto) delay */
if (video_frame_delay == 0)
video_frame_delay = 1 / refresh_rate * 1000 / 2;
/* Reset new desired delay target */
if (video_st->frame_delay_target != video_frame_delay)
{
frame_time_update = false;
video_st->frame_delay_target = video_frame_delay_effective = video_frame_delay;
RARCH_LOG("[Video]: Frame delay reset to %d ms.\n", video_frame_delay);
}
/* Decide what should happen to effective delay */
if (video_frame_delay_effective > 0 && frame_time_update)
{
video_frame_delay_auto_t vfda = {0};
@ -7942,11 +7968,11 @@ int runloop_iterate(void)
vfda.refresh_rate = refresh_rate;
video_frame_delay_auto(video_st, &vfda);
if (vfda.decrease > 0)
if (vfda.delay_decrease > 0)
{
video_frame_delay_effective -= vfda.decrease;
RARCH_LOG("[Video]: Frame delay decrease by %d ms to %d ms due to frame time: %d > %d.\n",
vfda.decrease, video_frame_delay_effective, vfda.time, vfda.target);
video_frame_delay_effective -= vfda.delay_decrease;
RARCH_LOG("[Video]: Frame delay decrease by %d ms to %d ms due to frame time average: %d > %d.\n",
vfda.delay_decrease, video_frame_delay_effective, vfda.frame_time_average, vfda.frame_time_target);
}
}
}
@ -7955,7 +7981,8 @@ int runloop_iterate(void)
video_st->frame_delay_effective = video_frame_delay_effective;
if (video_frame_delay_effective > 0)
/* Never apply frame delay when slow+fastmotion/pause is active */
if (video_frame_delay_effective > 0 && !skip_delay)
retro_sleep(video_frame_delay_effective);
}