diff --git a/config.def.h b/config.def.h index d819d3a8f4..a8455175e9 100644 --- a/config.def.h +++ b/config.def.h @@ -339,7 +339,13 @@ #define DEFAULT_MAX_SWAPCHAIN_IMAGES 3 /* D3D1x specific */ +#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +#define DEFAULT_WAITABLE_SWAPCHAINS false +#else +#define DEFAULT_WAITABLE_SWAPCHAINS true +#endif #define DEFAULT_MAX_FRAME_LATENCY 1 +#define MAXIMUM_MAX_FRAME_LATENCY 4 /* GL specific */ #define DEFAULT_ADAPTIVE_VSYNC false diff --git a/configuration.c b/configuration.c index a979f4a3fa..62a856afe1 100644 --- a/configuration.c +++ b/configuration.c @@ -1698,6 +1698,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("video_vsync", &settings->bools.video_vsync, true, DEFAULT_VSYNC, false); SETTING_BOOL("video_adaptive_vsync", &settings->bools.video_adaptive_vsync, true, DEFAULT_ADAPTIVE_VSYNC, false); SETTING_BOOL("video_hard_sync", &settings->bools.video_hard_sync, true, DEFAULT_HARD_SYNC, false); + SETTING_BOOL("video_waitable_swapchains", &settings->bools.video_waitable_swapchains, true, DEFAULT_WAITABLE_SWAPCHAINS, false); SETTING_BOOL("video_disable_composition", &settings->bools.video_disable_composition, true, DEFAULT_DISABLE_COMPOSITION, false); SETTING_BOOL("pause_nonactive", &settings->bools.pause_nonactive, true, DEFAULT_PAUSE_NONACTIVE, false); SETTING_BOOL("video_gpu_screenshot", &settings->bools.video_gpu_screenshot, true, DEFAULT_GPU_SCREENSHOT, false); diff --git a/configuration.h b/configuration.h index b36b91867c..22d52f0a96 100644 --- a/configuration.h +++ b/configuration.h @@ -521,6 +521,7 @@ typedef struct settings bool video_vsync; bool video_adaptive_vsync; bool video_hard_sync; + bool video_waitable_swapchains; bool video_vfilter; bool video_smooth; bool video_ctx_scaling; diff --git a/gfx/common/d3d11_common.h b/gfx/common/d3d11_common.h index 41aea89345..e752612915 100644 --- a/gfx/common/d3d11_common.h +++ b/gfx/common/d3d11_common.h @@ -197,6 +197,7 @@ typedef struct float clearcolor[4]; unsigned swap_interval; bool vsync; + bool waitable_swapchains; bool wait_for_vblank; bool resize_chain; bool keep_aspect; diff --git a/gfx/common/d3d12_common.h b/gfx/common/d3d12_common.h index c2b2de7e66..851f35d320 100644 --- a/gfx/common/d3d12_common.h +++ b/gfx/common/d3d12_common.h @@ -183,6 +183,7 @@ typedef struct float clearcolor[4]; int frame_index; bool vsync; + bool waitable_swapchains; bool wait_for_vblank; unsigned swap_interval; #ifdef HAVE_DXGI_HDR diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 516c48f621..e9d5789f27 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -988,7 +988,8 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11, d3d11->has_flip_model = true; d3d11->has_allow_tearing = true; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + if (d3d11->waitable_swapchains) + desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; #endif @@ -999,7 +1000,8 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11, &desc, NULL, (IDXGISwapChain1**)&d3d11->swapChain))) return false; #else - desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + if (d3d11->waitable_swapchains) + desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; adapter->lpVtbl->GetParent( @@ -1064,7 +1066,8 @@ static bool d3d11_init_swapchain(d3d11_video_t* d3d11, #endif /* __WINRT__ */ - if ((d3d11->frameLatencyWaitableObject = DXGIGetFrameLatencyWaitableObject(d3d11->swapChain))) + if (d3d11->waitable_swapchains && + (d3d11->frameLatencyWaitableObject = DXGIGetFrameLatencyWaitableObject(d3d11->swapChain))) { settings_t* settings = config_get_ptr(); UINT max_latency = settings->uints.video_max_frame_latency; @@ -1190,6 +1193,8 @@ static void *d3d11_gfx_init(const video_info_t* video, d3d11->hdr.max_fall = 0.0f; #endif + d3d11->waitable_swapchains = settings->bools.video_waitable_swapchains; + #ifdef __WINRT__ if (!d3d11_init_swapchain(d3d11, d3d11->vp.full_width, @@ -1849,7 +1854,8 @@ static bool d3d11_gfx_frame( { UINT swapchain_flags = d3d11->has_allow_tearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; - swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + if (d3d11->waitable_swapchains) + swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; #ifdef HAVE_DXGI_HDR d3d11->hdr.enable = video_hdr_enable; @@ -1925,7 +1931,7 @@ static bool d3d11_gfx_frame( d3d11->hdr.max_fall); #endif } - else + else if (d3d11->waitable_swapchains) { WaitForSingleObjectEx( d3d11->frameLatencyWaitableObject, diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index da678818cf..043239fa84 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -1259,7 +1259,8 @@ static bool d3d12_init_swapchain(d3d12_video_t* d3d12, #endif desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + if (d3d12->chain.waitable_swapchains) + desc.Flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; #ifdef __WINRT__ hr = DXGICreateSwapChainForCoreWindow(d3d12->factory, d3d12->queue.handle, corewindow, &desc, NULL, &d3d12->chain.handle); @@ -1272,7 +1273,8 @@ static bool d3d12_init_swapchain(d3d12_video_t* d3d12, return false; } - if ((d3d12->chain.frameLatencyWaitableObject = DXGIGetFrameLatencyWaitableObject(d3d12->chain.handle))) + if (d3d12->chain.waitable_swapchains && + (d3d12->chain.frameLatencyWaitableObject = DXGIGetFrameLatencyWaitableObject(d3d12->chain.handle))) { settings_t* settings = config_get_ptr(); UINT max_latency = settings->uints.video_max_frame_latency; @@ -1778,6 +1780,8 @@ static void *d3d12_gfx_init(const video_info_t* video, d3d12->hdr.max_fall = 0.0f; #endif + d3d12->chain.waitable_swapchains = settings->bools.video_waitable_swapchains; + d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data); d3d12_init_base(d3d12); @@ -2163,7 +2167,7 @@ static bool d3d12_gfx_frame( d3d12->hdr.max_fall); #endif } - else + else if (d3d12->chain.waitable_swapchains) { WaitForSingleObjectEx( d3d12->chain.frameLatencyWaitableObject, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 26fbfbbe45..7e66b18576 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -10907,6 +10907,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Tells the video driver to explicitly use a specified buffering mode." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_WAITABLE_SWAPCHAINS, + "Waitable Swapchains" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS, + "Hard-synchronize the CPU and GPU. Reduces latency at the cost of performance." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_MAX_FRAME_LATENCY, "Max Frame Latency" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index feef5154fb..cc336630c4 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -354,6 +354,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_timezone, MENU_ #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_user_language, MENU_ENUM_SUBLABEL_USER_LANGUAGE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_max_swapchain_images, MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_waitable_swapchains, MENU_ENUM_SUBLABEL_VIDEO_WAITABLE_SWAPCHAINS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_max_frame_latency, MENU_ENUM_SUBLABEL_VIDEO_MAX_FRAME_LATENCY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_online_updater, MENU_ENUM_SUBLABEL_ONLINE_UPDATER) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_fps_show, MENU_ENUM_SUBLABEL_FPS_SHOW) @@ -4184,6 +4185,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_max_swapchain_images); break; + case MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_waitable_swapchains); + break; case MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_max_frame_latency); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 0c65f772d8..ec1b6f4695 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -8568,6 +8568,7 @@ unsigned menu_displaylist_build_list( { bool video_vsync = settings->bools.video_vsync; bool video_hard_sync = settings->bools.video_hard_sync; + bool video_wait_swap = settings->bools.video_waitable_swapchains; if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_VIDEO_VSYNC, @@ -8622,9 +8623,14 @@ unsigned menu_displaylist_build_list( if (video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY)) { if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, - MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY, - PARSE_ONLY_UINT, false) == 0) + MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS, + PARSE_ONLY_BOOL, false) == 0) count++; + if (video_wait_swap) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY, + PARSE_ONLY_UINT, false) == 0) + count++; } if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, @@ -9039,6 +9045,7 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_LATENCY_SETTINGS_LIST: { bool video_hard_sync = settings->bools.video_hard_sync; + bool video_wait_swap = settings->bools.video_waitable_swapchains; #ifdef HAVE_RUNAHEAD bool runahead_supported = true; bool runahead_enabled = settings->bools.run_ahead_enabled; @@ -9068,9 +9075,16 @@ unsigned menu_displaylist_build_list( if (video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY)) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, - MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY, - PARSE_ONLY_UINT, false); + MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS, + PARSE_ONLY_BOOL, false); count++; + if (video_wait_swap) + { + MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY, + PARSE_ONLY_UINT, false); + count++; + } } if (video_driver_test_all_flags(GFX_CTX_FLAGS_HARD_SYNC)) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index f9de71c059..76622486f2 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -12533,6 +12533,26 @@ static bool setting_append_list( 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); + CONFIG_BOOL( + list, list_info, + &settings->bools.video_waitable_swapchains, + MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS, + MENU_ENUM_LABEL_VALUE_VIDEO_WAITABLE_SWAPCHAINS, + DEFAULT_WAITABLE_SWAPCHAINS, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + (*list)[list_info->index - 1].action_ok = setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh; + 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); + CONFIG_UINT( list, list_info, &settings->uints.video_max_frame_latency, @@ -12546,7 +12566,7 @@ static bool setting_append_list( general_read_handler); (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; (*list)[list_info->index - 1].offset_by = 0; - menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, 3, 1, true, true); + menu_settings_list_current_add_range(list, list_info, (*list)[list_info->index - 1].offset_by, MAXIMUM_MAX_FRAME_LATENCY, 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); diff --git a/msg_hash.h b/msg_hash.h index d58e6efeec..493c823d1c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1097,6 +1097,7 @@ enum msg_hash_enums MENU_LABEL(VIDEO_FILTER_FLICKER), MENU_LABEL(VIDEO_SOFT_FILTER), MENU_LABEL(VIDEO_MAX_SWAPCHAIN_IMAGES), + MENU_LABEL(VIDEO_WAITABLE_SWAPCHAINS), MENU_LABEL(VIDEO_MAX_FRAME_LATENCY), MENU_LABEL(VIDEO_GPU_SCREENSHOT), MENU_LABEL(VIDEO_BLACK_FRAME_INSERTION), diff --git a/ui/drivers/qt/qt_options.cpp b/ui/drivers/qt/qt_options.cpp index c19c1240cb..68651bf015 100644 --- a/ui/drivers/qt/qt_options.cpp +++ b/ui/drivers/qt/qt_options.cpp @@ -354,6 +354,7 @@ QWidget *LatencyPage::widget() } layout->add(MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES); + layout->add(MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS); layout->add(MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY); layout->add(MENU_ENUM_LABEL_VIDEO_FRAME_DELAY); @@ -1341,6 +1342,7 @@ QWidget *VideoPage::widget() } syncGroup->add(MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES); + syncGroup->add(MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS); syncGroup->add(MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY); syncGroup->add(MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE);