diff --git a/gfx/common/egl_common.c b/gfx/common/egl_common.c index cf20ada661..2c24b072cb 100644 --- a/gfx/common/egl_common.c +++ b/gfx/common/egl_common.c @@ -349,10 +349,9 @@ void egl_set_swap_interval(egl_ctx_data_t *egl, int interval) if (!_egl_get_current_context()) return; - RARCH_LOG("[EGL]: eglSwapInterval(%u)\n", interval); if (!_egl_swap_interval(egl->dpy, interval)) { - RARCH_ERR("[EGL]: eglSwapInterval() failed.\n"); + RARCH_ERR("[EGL]: eglSwapInterval(%i) failed.\n", interval); egl_report_error(); } } diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index eb9927ba3d..ff25383dee 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -3002,11 +3002,13 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, vk->context.gpu, vk->vk_surface, &present_mode_count, present_modes); +#ifdef VULKAN_DEBUG for (i = 0; i < present_mode_count; i++) { - RARCH_DBG("[Vulkan]: Swapchain supports present mode: %u.\n", + RARCH_LOG("[Vulkan]: Swapchain supports present mode: %u.\n", present_modes[i]); } +#endif vk->context.swap_interval = swap_interval; for (i = 0; i < present_mode_count; i++) @@ -3030,8 +3032,10 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, } } +#ifdef VULKAN_DEBUG RARCH_LOG("[Vulkan]: Creating swapchain with present mode: %u\n", (unsigned)swapchain_present_mode); +#endif vkGetPhysicalDeviceSurfaceFormatsKHR(vk->context.gpu, vk->vk_surface, &format_count, NULL); @@ -3108,8 +3112,10 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, return true; } +#ifdef VULKAN_DEBUG RARCH_LOG("[Vulkan]: Using swapchain size %u x %u.\n", swapchain_size.width, swapchain_size.height); +#endif /* Unless we have other reasons to clamp, we should prefer 3 images. * We hard sync against the swapchain, so if we have 2 images, @@ -3214,8 +3220,10 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, vkGetSwapchainImagesKHR(vk->context.device, vk->swapchain, &vk->context.num_swapchain_images, vk->context.swapchain_images); +#ifdef VULKAN_DEBUG RARCH_LOG("[Vulkan]: Got %u swapchain images.\n", vk->context.num_swapchain_images); +#endif /* Force driver to reset swapchain image handles. */ vk->context.invalid_swapchain = true; diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 4688e203b7..ba16cac452 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -3252,8 +3252,6 @@ static void gl2_set_nonblock_state( if (!gl) return; - RARCH_LOG("[GL]: VSync => %s\n", state ? "OFF" : "ON"); - gl2_context_bind_hw_render(gl, false); if (!state) diff --git a/gfx/drivers/gl1.c b/gfx/drivers/gl1.c index cca7df6617..2162bb30e9 100644 --- a/gfx/drivers/gl1.c +++ b/gfx/drivers/gl1.c @@ -974,8 +974,6 @@ static void gl1_gfx_set_nonblock_state(void *data, bool state, if (!gl1) return; - RARCH_LOG("[GL1]: VSync => %s\n", state ? "OFF" : "ON"); - gl1_context_bind_hw_render(gl1, false); if (!state) diff --git a/gfx/drivers/gl_core.c b/gfx/drivers/gl_core.c index e61cc046dc..2d2e782212 100644 --- a/gfx/drivers/gl_core.c +++ b/gfx/drivers/gl_core.c @@ -1590,8 +1590,6 @@ static void gl_core_set_nonblock_state(void *data, bool state, if (!gl) return; - RARCH_LOG("[GLCore]: VSync => %s\n", state ? "OFF" : "ON"); - gl_core_context_bind_hw_render(gl, false); if (!state) interval = swap_interval; diff --git a/gfx/drivers/vulkan.c b/gfx/drivers/vulkan.c index 4f9b5720c2..5ed58d3cd1 100644 --- a/gfx/drivers/vulkan.c +++ b/gfx/drivers/vulkan.c @@ -1345,8 +1345,6 @@ static void vulkan_set_nonblock_state(void *data, bool state, if (!vk) return; - RARCH_LOG("[Vulkan]: VSync => %s\n", state ? "OFF" : "ON"); - if (!state) interval = swap_interval; diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c index 0d077503dc..3f551cbca7 100644 --- a/gfx/drivers_context/wgl_ctx.c +++ b/gfx/drivers_context/wgl_ctx.c @@ -451,9 +451,8 @@ static void gfx_ctx_wgl_swap_interval(void *data, int interval) if (!win32_hrc || !p_swap_interval) return; - RARCH_LOG("[WGL]: wglSwapInterval(%i)\n", win32_interval); if (!p_swap_interval(win32_interval)) - RARCH_WARN("[WGL]: wglSwapInterval() failed.\n"); + RARCH_WARN("[WGL]: wglSwapInterval(%i) failed.\n", win32_interval); #endif break; diff --git a/gfx/drivers_context/x_ctx.c b/gfx/drivers_context/x_ctx.c index 365a0d9743..c9b263374b 100644 --- a/gfx/drivers_context/x_ctx.c +++ b/gfx/drivers_context/x_ctx.c @@ -258,40 +258,30 @@ static void gfx_ctx_x_swap_interval(void *data, int interval) { if (g_pglSwapInterval) { - RARCH_LOG("[GLX]: glXSwapInterval(%i)\n", x->interval); if (g_pglSwapInterval(x->interval) != 0) - RARCH_WARN("[GLX]: glXSwapInterval() failed.\n"); + RARCH_WARN("[GLX]: glXSwapInterval(%i) failed.\n", x->interval); } else if (g_pglSwapIntervalEXT) - { - RARCH_LOG("[GLX]: glXSwapIntervalEXT(%i)\n", x->interval); g_pglSwapIntervalEXT(g_x11_dpy, x->glx_win, x->interval); - } else if (g_pglSwapIntervalSGI) { - RARCH_LOG("[GLX]: glXSwapIntervalSGI(%i)\n", x->interval); if (g_pglSwapIntervalSGI(x->interval) != 0) - RARCH_WARN("[GLX]: glXSwapIntervalSGI() failed.\n"); + RARCH_WARN("[GLX]: glXSwapIntervalSGI(%i) failed.\n", x->interval); } } else { if (g_pglSwapIntervalEXT) - { - RARCH_LOG("[GLX]: glXSwapIntervalEXT(%i)\n", x->interval); g_pglSwapIntervalEXT(g_x11_dpy, x->glx_win, x->interval); - } else if (g_pglSwapInterval) { - RARCH_LOG("[GLX]: glXSwapInterval(%i)\n", x->interval); if (g_pglSwapInterval(x->interval) != 0) - RARCH_WARN("[GLX]: glXSwapInterval() failed.\n"); + RARCH_WARN("[GLX]: glXSwapInterval(%i) failed.\n", x->interval); } else if (g_pglSwapIntervalSGI) { - RARCH_LOG("[GLX]: glXSwapIntervalSGI(%i)\n", x->interval); if (g_pglSwapIntervalSGI(x->interval) != 0) - RARCH_WARN("[GLX]: glXSwapIntervalSGI() failed.\n"); + RARCH_WARN("[GLX]: glXSwapIntervalSGI(%i) failed.\n", x->interval); } } #endif diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 8a5da8648b..bda0b77ed7 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -1378,6 +1378,16 @@ enum retro_mod * call will target the newly initialized driver. */ +#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64 + /* const struct retro_fastforwarding_override * -- + * Used by a libretro core to override the current + * fastforwarding mode of the frontend. + * If NULL is passed to this function, the frontend + * will return true if fastforwarding override + * functionality is supported (no change in + * fastforwarding state will occur in this case). + */ + /* VFS functionality */ /* File paths: @@ -2938,6 +2948,47 @@ struct retro_framebuffer Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */ }; +/* Used by a libretro core to override the current + * fastforwarding mode of the frontend */ +struct retro_fastforwarding_override +{ + /* Specifies the runtime speed multiplier that + * will be applied when 'fastforward' is true. + * For example, a value of 5.0 when running 60 FPS + * content will cap the fast-forward rate at 300 FPS. + * Note that the target multiplier may not be achieved + * if the host hardware has insufficient processing + * power. + * Setting a value of 0.0 (or greater than 0.0 but + * less than 1.0) will result in an uncapped + * fast-forward rate (limited only by hardware + * capacity). + * If the value is negative, it will be ignored + * (i.e. the frontend will use a runtime speed + * multiplier of its own choosing) */ + float ratio; + + /* If true, fastforwarding mode will be enabled. + * If false, fastforwarding mode will be disabled. */ + bool fastforward; + + /* If true, and if supported by the frontend, an + * on-screen notification will be displayed while + * 'fastforward' is true. + * If false, and if supported by the frontend, any + * on-screen fast-forward notifications will be + * suppressed */ + bool notification; + + /* If true, the core will have sole control over + * when fastforwarding mode is enabled/disabled; + * the frontend will not be able to change the + * state set by 'fastforward' until either + * 'inhibit_toggle' is set to false, or the core + * is unloaded */ + bool inhibit_toggle; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing diff --git a/retroarch.c b/retroarch.c index b67d8a10dc..276192d811 100644 --- a/retroarch.c +++ b/retroarch.c @@ -12649,14 +12649,25 @@ static void command_event_runtime_log_init(struct rarch_state *p_rarch) sizeof(p_rarch->runtime_core_path)); } -static void retroarch_set_frame_limit( +static INLINE void retroarch_set_frame_limit( struct rarch_state *p_rarch, float fastforward_ratio) { const struct retro_system_av_info* av_info = &p_rarch->video_driver_av_info; p_rarch->frame_limit_minimum_time = (fastforward_ratio < 1.0f) ? 0.0f : - (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); + (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); +} + +static INLINE float retroarch_get_runloop_fastforward_ratio( + settings_t *settings, + runloop_state_t *p_runloop) +{ + struct retro_fastforwarding_override *fastmotion_override = + &p_runloop->fastmotion_override; + + return (fastmotion_override->fastforward && (fastmotion_override->ratio >= 0.0f)) ? + fastmotion_override->ratio : settings->floats.fastforward_ratio; } static bool command_event_init_core( @@ -12666,12 +12677,12 @@ static bool command_event_init_core( { #ifdef HAVE_CONFIGFILE bool auto_overrides_enable = settings->bools.auto_overrides_enable; - bool auto_remaps_enable = settings->bools.auto_remaps_enable; - const char *dir_input_remapping = settings->paths.directory_input_remapping; + bool auto_remaps_enable = false; + const char *dir_input_remapping = NULL; #endif - bool show_set_initial_disk_msg = settings->bools.notification_show_set_initial_disk; - unsigned poll_type_behavior = settings->uints.input_poll_type_behavior; - float fastforward_ratio = settings->floats.fastforward_ratio; + bool show_set_initial_disk_msg = false; + unsigned poll_type_behavior = 0; + float fastforward_ratio = 0.0f; rarch_system_info_t *sys_info = &runloop_state.system; if (!init_libretro_symbols(p_rarch, @@ -12711,6 +12722,17 @@ static bool command_event_init_core( config_load_override(&runloop_state.system); #endif + /* Cannot access these settings-related parameters + * until *after* config overrides have been loaded */ +#ifdef HAVE_CONFIGFILE + auto_remaps_enable = settings->bools.auto_remaps_enable; + dir_input_remapping = settings->paths.directory_input_remapping; +#endif + show_set_initial_disk_msg = settings->bools.notification_show_set_initial_disk; + poll_type_behavior = settings->uints.input_poll_type_behavior; + fastforward_ratio = retroarch_get_runloop_fastforward_ratio( + settings, &runloop_state); + #ifdef HAVE_CHEEVOS /* assume the core supports achievements unless it tells us otherwise */ rcheevos_set_support_cheevos(true); @@ -13314,6 +13336,24 @@ static void retroarch_game_focus_free(struct rarch_state *p_rarch) p_rarch->game_focus_state.core_requested = false; } +static void retroarch_fastmotion_override_free(struct rarch_state *p_rarch, + runloop_state_t *p_runloop) +{ + settings_t *settings = p_rarch->configuration_settings; + float fastforward_ratio = settings->floats.fastforward_ratio; + bool reset_frame_limit = p_runloop->fastmotion_override.fastforward && + (p_runloop->fastmotion_override.ratio >= 0.0f) && + (p_runloop->fastmotion_override.ratio != fastforward_ratio); + + p_runloop->fastmotion_override.ratio = 0.0f; + p_runloop->fastmotion_override.fastforward = false; + p_runloop->fastmotion_override.notification = false; + p_runloop->fastmotion_override.inhibit_toggle = false; + + if (reset_frame_limit) + retroarch_set_frame_limit(p_rarch, fastforward_ratio); +} + static void retroarch_system_info_free(struct rarch_state *p_rarch) { rarch_system_info_t *sys_info = &runloop_state.system; @@ -14971,7 +15011,8 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_SET_FRAME_LIMIT: retroarch_set_frame_limit(p_rarch, - settings->floats.fastforward_ratio); + retroarch_get_runloop_fastforward_ratio( + settings, &runloop_state)); break; case CMD_EVENT_DISCORD_INIT: #ifdef HAVE_DISCORD @@ -18335,6 +18376,74 @@ static bool rarch_environment_cb(unsigned cmd, void *data) *(bool *)data = runloop_state.fastmotion; break; + case RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE: + { + struct retro_fastforwarding_override *fastforwarding_override = + (struct retro_fastforwarding_override *)data; + + if (fastforwarding_override) + { + runloop_state_t *p_runloop = &runloop_state; + bool frame_time_counter_reset_after_fastforwarding = settings ? + settings->bools.frame_time_counter_reset_after_fastforwarding : false; + float fastforward_ratio_default = settings ? + settings->floats.fastforward_ratio : 0.0f; + float fastforward_ratio_last = + (p_runloop->fastmotion_override.fastforward && + (p_runloop->fastmotion_override.ratio >= 0.0f)) ? + p_runloop->fastmotion_override.ratio : + fastforward_ratio_default; + float fastforward_ratio_current; + + memcpy(&p_runloop->fastmotion_override, + fastforwarding_override, + sizeof(p_runloop->fastmotion_override)); + + /* Check if 'fastmotion' state has changed */ + if (p_runloop->fastmotion != + p_runloop->fastmotion_override.fastforward) + { + p_runloop->fastmotion = + p_runloop->fastmotion_override.fastforward; + + if (p_runloop->fastmotion) + p_rarch->input_driver_nonblock_state = true; + else + { + p_rarch->input_driver_nonblock_state = false; + p_rarch->fastforward_after_frames = 1; + } + driver_set_nonblock_state(); + + /* Reset frame time counter when toggling + * fast-forward off, if required */ + if (!p_runloop->fastmotion && + frame_time_counter_reset_after_fastforwarding) + p_rarch->video_driver_frame_time_count = 0; + + /* Ensure fast forward widget is disabled when + * toggling fast-forward off + * (required if RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE + * is called during core de-initialisation) */ +#if defined(HAVE_GFX_WIDGETS) + if (p_rarch->widgets_active && !p_runloop->fastmotion) + p_rarch->gfx_widgets_fast_forward = false; +#endif + } + + /* Update frame limit, if required */ + fastforward_ratio_current = (p_runloop->fastmotion_override.fastforward && + (p_runloop->fastmotion_override.ratio >= 0.0f)) ? + p_runloop->fastmotion_override.ratio : + fastforward_ratio_default; + + if (fastforward_ratio_current != fastforward_ratio_last) + retroarch_set_frame_limit(p_rarch, fastforward_ratio_current); + } + + break; + } + case RETRO_ENVIRONMENT_GET_INPUT_BITMASKS: /* Just falldown, the function will return true */ break; @@ -18786,6 +18895,7 @@ static void uninit_libretro_symbols( retroarch_frame_time_free(p_rarch); retroarch_audio_buffer_status_free(p_rarch); retroarch_game_focus_free(p_rarch); + retroarch_fastmotion_override_free(p_rarch, &runloop_state); p_rarch->camera_driver_active = false; p_rarch->location_driver_active = false; @@ -36275,6 +36385,7 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) retroarch_frame_time_free(p_rarch); retroarch_audio_buffer_status_free(p_rarch); retroarch_game_focus_free(p_rarch); + retroarch_fastmotion_override_free(p_rarch, &runloop_state); break; case RARCH_CTL_IS_IDLE: return runloop_state.idle; @@ -37125,7 +37236,6 @@ static enum runloop_state runloop_check_state( bool focused = true; bool rarch_is_initialized = p_rarch->rarch_is_inited; bool runloop_paused = runloop_state.paused; - float fastforward_ratio = settings->floats.fastforward_ratio; bool pause_nonactive = settings->bools.pause_nonactive; #ifdef HAVE_MENU menu_handle_t *menu = p_rarch->menu_driver_data; @@ -37839,6 +37949,9 @@ static enum runloop_state runloop_check_state( if (p_rarch->menu_driver_alive) { + float fastforward_ratio = retroarch_get_runloop_fastforward_ratio( + settings, &runloop_state); + if (!settings->bools.menu_throttle_framerate && !fastforward_ratio) return RUNLOOP_STATE_MENU_ITERATE; @@ -37990,8 +38103,9 @@ static enum runloop_state runloop_check_state( /* Check if we have pressed the fast forward button */ /* To avoid continuous switching if we hold the button down, we require * that the button must go from pressed to unpressed back to pressed - * to be able to toggle between then. + * to be able to toggle between them. */ + if (!runloop_state.fastmotion_override.inhibit_toggle) { static bool old_button_state = false; static bool old_hold_button_state = false; @@ -38008,7 +38122,7 @@ static enum runloop_state runloop_check_state( { bool check1 = p_rarch->input_driver_nonblock_state; p_rarch->input_driver_nonblock_state = !check1; - runloop_state.fastmotion = !check1; + runloop_state.fastmotion = !check1; if (check1) p_rarch->fastforward_after_frames = 1; driver_set_nonblock_state(); @@ -38022,9 +38136,14 @@ static enum runloop_state runloop_check_state( old_button_state = new_button_state; old_hold_button_state = new_hold_button_state; + } - /* Display fast-forward notification - * > Use widgets, if enabled */ + /* Display fast-forward notification, unless + * disabled via override */ + if (!runloop_state.fastmotion_override.fastforward || + runloop_state.fastmotion_override.notification) + { + /* > Use widgets, if enabled */ #if defined(HAVE_GFX_WIDGETS) if (widgets_active) p_rarch->gfx_widgets_fast_forward = @@ -38041,6 +38160,10 @@ static enum runloop_state runloop_check_state( msg_hash_to_str(MSG_FAST_FORWARD), 1, 1, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } } +#if defined(HAVE_GFX_WIDGETS) + else + p_rarch->gfx_widgets_fast_forward = false; +#endif /* Check if we have pressed any of the state slot buttons */ { @@ -38568,8 +38691,6 @@ int runloop_iterate(void) end: if (vrr_runloop_enable) { - const retro_time_t fastforward_ratio = settings->floats.fastforward_ratio; - /* Sync on video only, block audio later. */ if (p_rarch->fastforward_after_frames && audio_sync) { @@ -38601,7 +38722,12 @@ end: } } - retroarch_set_frame_limit(p_rarch, runloop_state.fastmotion ? fastforward_ratio : 1.0f); + if (runloop_state.fastmotion) + retroarch_set_frame_limit(p_rarch, + retroarch_get_runloop_fastforward_ratio( + settings, &runloop_state)); + else + retroarch_set_frame_limit(p_rarch, 1.0f); } /* if there's a fast forward limit, inject sleeps to keep from going too fast. */ diff --git a/retroarch_data.h b/retroarch_data.h index 04f2bd4501..673fccf62d 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -1682,6 +1682,8 @@ struct runloop unsigned max_frames; unsigned audio_latency; + struct retro_fastforwarding_override fastmotion_override; /* float alignment */ + bool missing_bios; bool force_nonblock; bool paused;