mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-01-06 00:56:13 +00:00
Add high_precision_sleep() method
This commit is contained in:
parent
8dc51a21df
commit
d81e2cecaa
@ -126,6 +126,9 @@ namespace platf::dxgi {
|
||||
int
|
||||
init(const ::video::config_t &config, const std::string &display_name);
|
||||
|
||||
void
|
||||
high_precision_sleep(std::chrono::nanoseconds duration);
|
||||
|
||||
capture_e
|
||||
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override;
|
||||
|
||||
@ -141,6 +144,8 @@ namespace platf::dxgi {
|
||||
DXGI_FORMAT capture_format;
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
|
||||
util::safe_ptr_v2<std::remove_pointer_t<HANDLE>, BOOL, CloseHandle> timer;
|
||||
|
||||
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
|
||||
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
|
||||
|
@ -95,25 +95,31 @@ namespace platf::dxgi {
|
||||
release_frame();
|
||||
}
|
||||
|
||||
void
|
||||
display_base_t::high_precision_sleep(std::chrono::nanoseconds duration) {
|
||||
if (!timer) {
|
||||
BOOST_LOG(error) << "Attempting high_precision_sleep() with uninitialized timer";
|
||||
return;
|
||||
}
|
||||
if (duration < 0s) {
|
||||
BOOST_LOG(error) << "Attempting high_precision_sleep() with negative duration";
|
||||
return;
|
||||
}
|
||||
if (duration > 5s) {
|
||||
BOOST_LOG(error) << "Attempting high_precision_sleep() with unexpectedly large duration (>5s)";
|
||||
return;
|
||||
}
|
||||
|
||||
LARGE_INTEGER due_time;
|
||||
due_time.QuadPart = duration.count() / -100;
|
||||
SetWaitableTimer(timer.get(), &due_time, 0, nullptr, nullptr, false);
|
||||
WaitForSingleObject(timer.get(), INFINITE);
|
||||
}
|
||||
|
||||
capture_e
|
||||
display_base_t::capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) {
|
||||
auto next_frame = std::chrono::steady_clock::now();
|
||||
|
||||
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
|
||||
HANDLE timer = CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
||||
if (!timer) {
|
||||
timer = CreateWaitableTimerEx(nullptr, nullptr, 0, TIMER_ALL_ACCESS);
|
||||
if (!timer) {
|
||||
auto winerr = GetLastError();
|
||||
BOOST_LOG(error) << "Failed to create timer: "sv << winerr;
|
||||
return capture_e::error;
|
||||
}
|
||||
}
|
||||
|
||||
auto close_timer = util::fail_guard([timer]() {
|
||||
CloseHandle(timer);
|
||||
});
|
||||
|
||||
// Keep the display awake during capture. If the display goes to sleep during
|
||||
// capture, best case is that capture stops until it powers back on. However,
|
||||
// worst case it will trigger us to reinit DD, waking the display back up in
|
||||
@ -131,13 +137,11 @@ namespace platf::dxgi {
|
||||
return platf::capture_e::reinit;
|
||||
}
|
||||
|
||||
// If the wait time is between 1 us and 1 second, wait the specified time
|
||||
// If the wait time is positive and below 1 second, wait the specified time
|
||||
// and offset the next frame time from the exact current frame time target.
|
||||
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count();
|
||||
if (wait_time_us > 0 && wait_time_us < 1000000) {
|
||||
LARGE_INTEGER due_time { .QuadPart = -10LL * wait_time_us };
|
||||
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
|
||||
WaitForSingleObject(timer, INFINITE);
|
||||
auto wait_time = next_frame - std::chrono::steady_clock::now();
|
||||
if (wait_time > 0s && wait_time < 1s) {
|
||||
high_precision_sleep(wait_time);
|
||||
next_frame += delay;
|
||||
}
|
||||
else {
|
||||
@ -613,6 +617,17 @@ namespace platf::dxgi {
|
||||
// Capture format will be determined from the first call to AcquireNextFrame()
|
||||
capture_format = DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
|
||||
timer.reset(CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS));
|
||||
if (!timer) {
|
||||
timer.reset(CreateWaitableTimerEx(nullptr, nullptr, 0, TIMER_ALL_ACCESS));
|
||||
if (!timer) {
|
||||
auto winerr = GetLastError();
|
||||
BOOST_LOG(error) << "Failed to create timer: "sv << winerr;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user