From 2d969c2cccc61a3fdc718b7aaa0b13410cd850f0 Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Fri, 20 May 2022 16:25:09 +0100 Subject: [PATCH] platform/windows: change dwmflush default, add autodetection On each re/init, query the active monitor refresh rate via DwmGetCompositionTimingInfo. If the client requested framerate exceeds the host monitor refresh, automatically disable DwmFlush. This avoids the problem by which DwmFlush would constrain the client FPS if the host monitor runs at a lower refresh rate, thus allowing the feature to be enabled by default. If there are other issues caused by DwmFlush for certain systems, it can still be disabled via configuration. --- docs/source/about/advanced_usage.rst | 7 ++++--- src_assets/common/assets/web/config.html | 6 +++--- sunshine/config.cpp | 8 ++++---- sunshine/platform/windows/display.h | 1 + sunshine/platform/windows/display_base.cpp | 18 +++++++++++++++++- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/docs/source/about/advanced_usage.rst b/docs/source/about/advanced_usage.rst index e071ada5..e0903223 100644 --- a/docs/source/about/advanced_usage.rst +++ b/docs/source/about/advanced_usage.rst @@ -339,11 +339,12 @@ dwmflush Description Invoke DwmFlush() to sync screen capture to the Windows presentation interval. - .. Caution:: Applies to Windows only. Alleviates visual stuttering during mouse movement, but causes the capture - rate to be limited to the host monitor's currently active refresh rate. + .. Caution:: Applies to Windows only. Alleviates visual stuttering during mouse movement. + If enabled, this feature will automatically deactivate if the client framerate exceeds + the host monitor's current refresh rate. Default - ``disabled`` + ``enabled`` Examples diff --git a/src_assets/common/assets/web/config.html b/src_assets/common/assets/web/config.html index 1d34512c..01954e76 100644 --- a/src_assets/common/assets/web/config.html +++ b/src_assets/common/assets/web/config.html @@ -410,8 +410,8 @@
- Improves capture latency during mouse movement.
- Enabling this may prevent the client's FPS from exceeding the host monitor's active refresh rate. + Improves capture latency/smoothness during mouse movement.
+ Disable if you encounter any VSync-related issues.
@@ -843,7 +843,7 @@ this.config.key_rightalt_to_key_win || "disabled"; this.config.gamepad = this.config.gamepad || "x360"; this.config.upnp = this.config.upnp || "disabled"; - this.config.dwmflush = this.config.dwmflush || "disabled"; + this.config.dwmflush = this.config.dwmflush || "enabled"; this.config.min_log_level = this.config.min_log_level || 2; this.config.origin_pin_allowed = this.config.origin_pin_allowed || "pc"; diff --git a/sunshine/config.cpp b/sunshine/config.cpp index ac1d9ccf..21c27e2d 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -226,10 +226,10 @@ video_t video { 1, -1 }, // vt - {}, // encoder - {}, // adapter_name - {}, // output_name - false // dwmflush + {}, // encoder + {}, // adapter_name + {}, // output_name + true // dwmflush }; audio_t audio {}; diff --git a/sunshine/platform/windows/display.h b/sunshine/platform/windows/display.h index 60539efc..6a150135 100644 --- a/sunshine/platform/windows/display.h +++ b/sunshine/platform/windows/display.h @@ -96,6 +96,7 @@ class duplication_t { public: dup_t dup; bool has_frame {}; + bool use_dwmflush {}; capture_e next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::chrono::milliseconds timeout, resource_t::pointer *res_p); capture_e reset(dup_t::pointer dup_p = dup_t::pointer()); diff --git a/sunshine/platform/windows/display_base.cpp b/sunshine/platform/windows/display_base.cpp index 12f8cad0..9ee9ad97 100644 --- a/sunshine/platform/windows/display_base.cpp +++ b/sunshine/platform/windows/display_base.cpp @@ -2,6 +2,7 @@ // Created by loki on 1/12/20. // +#include #include #include "display.h" @@ -20,7 +21,7 @@ capture_e duplication_t::next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::ch return capture_status; } - if(config::video.dwmflush) { + if(use_dwmflush) { DwmFlush(); } @@ -217,6 +218,21 @@ int display_base_t::init(int framerate, const std::string &display_name) { << "Offset : "sv << offset_x << 'x' << offset_y << std::endl << "Virtual Desktop : "sv << env_width << 'x' << env_height; + // Enable DwmFlush() only if the current refresh rate can match the client framerate. + auto refresh_rate = framerate; + DWM_TIMING_INFO timing_info; + timing_info.cbSize = sizeof(timing_info); + + status = DwmGetCompositionTimingInfo(NULL, &timing_info); + if(FAILED(status)) { + BOOST_LOG(warning) << "Failed to detect active refresh rate."; + } + else { + refresh_rate = std::round((double)timing_info.rateRefresh.uiNumerator / (double)timing_info.rateRefresh.uiDenominator); + } + + dup.use_dwmflush = config::video.dwmflush && !(framerate > refresh_rate) ? true : false; + // Bump up thread priority { const DWORD flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY;