From 6713e3b7f70a66c22a418f54371086ac2caa1921 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:23:02 +0300 Subject: [PATCH] (Vulkan) Prefer IMMEDIATE mode without vsync (#17009) * (Vulkan) Prefer IMMEDIATE mode without vsync * Clamp max_swapchain_images and hard_sync_frames * (Vulkan) Improve fastforward frameskip option hack --- config.def.h | 4 ++ configuration.c | 9 ++++- gfx/common/vulkan_common.c | 81 ++++++++++++++++++++++++++------------ gfx/video_driver.c | 15 +++---- gfx/video_driver.h | 2 + menu/menu_setting.c | 6 +-- 6 files changed, 79 insertions(+), 38 deletions(-) diff --git a/config.def.h b/config.def.h index 9c3f1061361..8b48705c972 100644 --- a/config.def.h +++ b/config.def.h @@ -368,6 +368,8 @@ /* Vulkan specific */ #define DEFAULT_MAX_SWAPCHAIN_IMAGES 3 +#define MINIMUM_MAX_SWAPCHAIN_IMAGES 2 +#define MAXIMUM_MAX_SWAPCHAIN_IMAGES 4 /* D3D1x specific */ #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP @@ -391,6 +393,8 @@ * 2: Etc ... */ #define DEFAULT_HARD_SYNC_FRAMES 0 +#define MINIMUM_HARD_SYNC_FRAMES 0 +#define MAXIMUM_HARD_SYNC_FRAMES 3 /* Sets how many milliseconds to delay after VSync before running the core. * Can reduce latency at cost of higher risk of stuttering. diff --git a/configuration.c b/configuration.c index 343a6bf5ce0..5808a3f21c5 100644 --- a/configuration.c +++ b/configuration.c @@ -3870,8 +3870,13 @@ static bool config_load_file(global_t *global, free(override_username); } - if (settings->uints.video_hard_sync_frames > 3) - settings->uints.video_hard_sync_frames = 3; + if (settings->uints.video_hard_sync_frames > MAXIMUM_HARD_SYNC_FRAMES) + settings->uints.video_hard_sync_frames = MAXIMUM_HARD_SYNC_FRAMES; + + if (settings->uints.video_max_swapchain_images < MINIMUM_MAX_SWAPCHAIN_IMAGES) + settings->uints.video_max_swapchain_images = MINIMUM_MAX_SWAPCHAIN_IMAGES; + if (settings->uints.video_max_swapchain_images > MAXIMUM_MAX_SWAPCHAIN_IMAGES) + settings->uints.video_max_swapchain_images = MAXIMUM_MAX_SWAPCHAIN_IMAGES; if (settings->uints.video_frame_delay > MAXIMUM_FRAME_DELAY) settings->uints.video_frame_delay = MAXIMUM_FRAME_DELAY; diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 93fd92c48d1..7033e68668e 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1966,7 +1966,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, { /* Do not bother creating a swapchain redundantly. */ #ifdef VULKAN_DEBUG - RARCH_LOG("[Vulkan]: Do not need to re-create swapchain.\n"); + RARCH_DBG("[Vulkan]: Do not need to re-create swapchain.\n"); #endif vulkan_create_wait_fences(vk); @@ -2025,43 +2025,77 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, vk->context.gpu, vk->vk_surface, &present_mode_count, present_modes); -#ifdef VULKAN_DEBUG + vk->context.swap_interval = swap_interval; + + /* Prefer IMMEDIATE without vsync */ for (i = 0; i < present_mode_count; i++) { - RARCH_LOG("[Vulkan]: Swapchain supports present mode: %u.\n", - present_modes[i]); + if ( !swap_interval + && !vsync + && present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + swapchain_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; + break; + } } -#endif - vk->context.swap_interval = swap_interval; + /* If still in FIFO with no swap interval, try MAILBOX */ for (i = 0; i < present_mode_count; i++) { if ( !swap_interval - && (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)) + && swapchain_present_mode == VK_PRESENT_MODE_FIFO_KHR + && present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { swapchain_present_mode = VK_PRESENT_MODE_MAILBOX_KHR; break; } - else if (!swap_interval - && (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) + } + + /* Present mode logging */ + if (vk->swapchain == VK_NULL_HANDLE) + { + for (i = 0; i < present_mode_count; i++) { - swapchain_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR; - break; + switch (present_modes[i]) + { + case VK_PRESENT_MODE_IMMEDIATE_KHR: + RARCH_DBG("[Vulkan]: Swapchain supports present mode: IMMEDIATE.\n"); + break; + case VK_PRESENT_MODE_MAILBOX_KHR: + RARCH_DBG("[Vulkan]: Swapchain supports present mode: MAILBOX.\n"); + break; + case VK_PRESENT_MODE_FIFO_KHR: + RARCH_DBG("[Vulkan]: Swapchain supports present mode: FIFO.\n"); + break; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + RARCH_DBG("[Vulkan]: Swapchain supports present mode: FIFO_RELAXED.\n"); + break; + default: + break; + } } - else if ( swap_interval - && (present_modes[i] == VK_PRESENT_MODE_FIFO_KHR)) + } + else + { + switch (swapchain_present_mode) { - /* Kind of tautological since FIFO must always be present. */ - swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR; - break; + case VK_PRESENT_MODE_IMMEDIATE_KHR: + RARCH_DBG("[Vulkan]: Creating swapchain with present mode: IMMEDIATE.\n"); + break; + case VK_PRESENT_MODE_MAILBOX_KHR: + RARCH_DBG("[Vulkan]: Creating swapchain with present mode: MAILBOX.\n"); + break; + case VK_PRESENT_MODE_FIFO_KHR: + RARCH_DBG("[Vulkan]: Creating swapchain with present mode: FIFO.\n"); + break; + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + RARCH_DBG("[Vulkan]: Creating swapchain with present mode: FIFO_RELAXED.\n"); + break; + default: + break; } } -#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); vkGetPhysicalDeviceSurfaceFormatsKHR(vk->context.gpu, @@ -2175,11 +2209,6 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, return true; } -#ifdef VULKAN_DEBUG - RARCH_LOG("[Vulkan]: Using swapchain size %ux%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, * we would be unable to overlap CPU and GPU, which can get very slow diff --git a/gfx/video_driver.c b/gfx/video_driver.c index c4902a26faa..4112bc42019 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -2709,17 +2709,18 @@ void video_driver_build_info(video_frame_info_t *video_info) video_info->runloop_is_paused = (runloop_st->flags & RUNLOOP_FLAG_PAUSED) ? true : false; video_info->runloop_is_slowmotion = (runloop_st->flags & RUNLOOP_FLAG_SLOWMOTION) ? true : false; video_info->fastforward_frameskip = settings->bools.fastforward_frameskip; + video_info->frame_time_target = 1000000.0f / video_info->refresh_rate; #ifdef _WIN32 #ifdef HAVE_VULKAN /* Vulkan in Windows does mailbox emulation * in fullscreen with vsync, effectively - * discarding frames that can't be shown, - * therefore do not do it twice. */ + * already discarding frames, therefore compensate + * frameskip target to make it smoother and faster. */ if ( video_info->fullscreen && settings->bools.video_vsync && string_is_equal(video_driver_get_ident(), "vulkan")) - video_info->fastforward_frameskip = false; + video_info->frame_time_target /= 2.0f; #endif #endif @@ -3409,9 +3410,9 @@ void video_driver_frame(const void *data, unsigned width, static retro_time_t last_time; static retro_time_t curr_time; static retro_time_t fps_time; - static retro_time_t frame_time_accumulator; static float last_fps, frame_time; static uint64_t last_used_memory, last_total_memory; + static uint16_t frame_time_accumulator; /* Mark the start of nonblock state for * ignoring initial previous frame time */ static int8_t nonblock_active; @@ -3494,9 +3495,9 @@ void video_driver_frame(const void *data, unsigned width, && video_info.fastforward_frameskip) #endif { - retro_time_t frame_time_accumulator_prev = frame_time_accumulator; - retro_time_t frame_time_delta = new_time - last_time; - retro_time_t frame_time_target = 1000000.0f / video_info.refresh_rate; + uint16_t frame_time_accumulator_prev = frame_time_accumulator; + uint16_t frame_time_delta = new_time - last_time; + uint16_t frame_time_target = video_info.frame_time_target; /* Ignore initial previous frame time * to prevent rubber band startup */ diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 718d1dcbeaf..13903f7d9e7 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -456,6 +456,8 @@ typedef struct video_frame_info uint32_t video_st_flags; uint16_t menu_st_flags; + uint16_t frame_time_target; + char stat_text[1024]; bool widgets_active; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 88018fc4202..19929bcced1 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -14017,8 +14017,8 @@ static bool setting_append_list( general_write_handler, general_read_handler); (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; - (*list)[list_info->index - 1].offset_by = 2; - menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 4, 1, true, true); + (*list)[list_info->index - 1].offset_by = MINIMUM_MAX_SWAPCHAIN_IMAGES; + menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, MAXIMUM_MAX_SWAPCHAIN_IMAGES, 1, true, true); SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_CMD_APPLY_AUTO); MENU_SETTINGS_LIST_CURRENT_ADD_CMD(list, list_info, CMD_EVENT_REINIT); @@ -14089,7 +14089,7 @@ static bool setting_append_list( 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, 3, 1, true, true); + menu_settings_list_current_add_range(list, list_info, MINIMUM_HARD_SYNC_FRAMES, MAXIMUM_HARD_SYNC_FRAMES, 1, true, true); if (video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC)) {