Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

platform/windows: add DwmFlush() call to improve Windows capture #164

Merged
merged 5 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ if(WIN32)
ws2_32
d3d11 dxgi D3DCompiler
setupapi
dwmapi
)

set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp PROPERTIES COMPILE_DEFINITIONS "UNICODE=1;ERROR_INVALID_DEVICE_OBJECT_PARAMETER=650")
Expand Down
20 changes: 20 additions & 0 deletions docs/source/about/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,26 @@ Example
3840x1600,
]

dwmflush
^^^^^^^^

Description
Invoke DwmFlush() to sync screen capture to the Windows presentation interval.

.. 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
``enabled``

Examples

Windows
.. code-block:: text

dwmflush = enabled

Audio
-----

Expand Down
33 changes: 23 additions & 10 deletions src_assets/common/assets/web/config.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ <h1 class="my-4">Configuration</h1>
class="form-select"
v-model="config.min_log_level"
>
<option :value="0">Verbose</option>
<option :value="1">Debug</option>
<option :value="2">Info</option>
<option :value="3">Warning</option>
<option :value="4">Error</option>
<option :value="5">Fatal</option>
<option :value="6">None</option>
<option value="0">Verbose</option>
<option value="1">Debug</option>
<option value="2">Info</option>
<option value="3">Warning</option>
<option value="4">Error</option>
<option value="5">Fatal</option>
<option value="6">None</option>
</select>
<div class="form-text">
The minimum log level printed to standard out
Expand Down Expand Up @@ -400,7 +400,18 @@ <h1 class="my-4">Configuration</h1>
You can select the video card you want to stream:<br />
The appropriate values can be found using the following command:<br />
tools\dxgi-info.exe<br />
<br />
</div>
</div>
<!--DwmFlush-->
<div class="mb-3" v-if="platform === 'windows'">
<label for="dwmflush" class="form-label">DwmFlush</label>
<select id="dwmflush" class="form-select" v-model="config.dwmflush">
<option value="disabled">Disabled</option>
<option value="enabled">Enabled</option>
</select>
<div class="form-text">
Improves capture latency/smoothness during mouse movement.<br />
Disable if you encounter any VSync-related issues.
</div>
</div>
<div class="mb-3" class="config-page" v-if="platform === 'linux'">
Expand Down Expand Up @@ -497,7 +508,7 @@ <h1 class="my-4">Configuration</h1>
<div class="mb-3">
<label for="encoder" class="form-label">Force a Specific Encoder</label>
<select id="encoder" class="form-select" v-model="config.encoder">
<option :value="''">Autodetect</option>
<option value>Autodetect</option>
<option value="nvenc">nVidia NVENC</option>
<option value="amdvce">AMD AMF/VCE</option>
<option value="vaapi">VA-API</option>
Expand Down Expand Up @@ -696,7 +707,7 @@ <h1 class="my-4">Configuration</h1>
</select>
</div>
<div class="mb-3">
<label for="amd_coder" class="form-label">AMD AMF Rate Control</label>
<label for="amd_coder" class="form-label">AMD AMF Coder</label>
<select id="amd_coder" class="form-select" v-model="config.amd_coder">
<option value="auto">auto</option>
<option value="cabac">cabac</option>
Expand Down Expand Up @@ -832,6 +843,7 @@ <h1 class="my-4">Configuration</h1>
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 || "enabled";
this.config.min_log_level = this.config.min_log_level || 2;
this.config.origin_pin_allowed =
this.config.origin_pin_allowed || "pc";
Expand All @@ -842,6 +854,7 @@ <h1 class="my-4">Configuration</h1>
this.config.nv_preset = this.config.nv_preset || "default";
this.config.nv_rc = this.config.nv_rc || "auto";
this.config.nv_coder = this.config.nv_coder || "auto";
this.config.amd_coder = this.config.amd_coder || "auto"
this.config.amd_quality = this.config.amd_quality || "default";
this.config.amd_rc = this.config.amd_rc || "auto";
this.config.vt_coder = this.config.vt_coder || "auto";
Expand Down
17 changes: 11 additions & 6 deletions sunshine/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,16 @@ video_t video {
std::nullopt,
-1 }, // amd

{}, // encoder
{}, // adapter_name
{}, // output_name
{
0,
0,
1,
-1 }, // vt

{}, // encoder
{}, // adapter_name
{}, // output_name
true // dwmflush
};

audio_t audio {};
Expand Down Expand Up @@ -722,16 +729,14 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
}

int_f(vars, "vt_coder", video.vt.coder, vt::coder_from_view);
video.vt.allow_sw = 0;
int_f(vars, "vt_software", video.vt.allow_sw, vt::allow_software_from_view);
video.vt.require_sw = 0;
int_f(vars, "vt_software", video.vt.require_sw, vt::force_software_from_view);
video.vt.realtime = 1;
int_f(vars, "vt_realtime", video.vt.realtime, vt::rt_from_view);

string_f(vars, "encoder", video.encoder);
string_f(vars, "adapter_name", video.adapter_name);
string_f(vars, "output_name", video.output_name);
bool_f(vars, "dwmflush", video.dwmflush);

path_f(vars, "pkey", nvhttp.pkey);
path_f(vars, "cert", nvhttp.cert);
Expand Down
1 change: 1 addition & 0 deletions sunshine/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct video_t {
std::string encoder;
std::string adapter_name;
std::string output_name;
bool dwmflush;
};

struct audio_t {
Expand Down
4 changes: 3 additions & 1 deletion sunshine/platform/windows/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <d3d11.h>
#include <d3d11_4.h>
#include <d3dcommon.h>
#include <dwmapi.h>
#include <dxgi.h>
#include <dxgi1_2.h>

Expand Down Expand Up @@ -95,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());
Expand Down Expand Up @@ -172,4 +174,4 @@ class display_vram_t : public display_base_t, public std::enable_shared_from_thi
};
} // namespace platf::dxgi

#endif
#endif
20 changes: 20 additions & 0 deletions sunshine/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Created by loki on 1/12/20.
//

#include <cmath>
#include <codecvt>

#include "display.h"
Expand All @@ -20,6 +21,10 @@ capture_e duplication_t::next_frame(DXGI_OUTDUPL_FRAME_INFO &frame_info, std::ch
return capture_status;
}

if(use_dwmflush) {
DwmFlush();
}

auto status = dup->AcquireNextFrame(timeout.count(), &frame_info, res_p);

switch(status) {
Expand Down Expand Up @@ -213,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;
Expand Down