mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-01-29 09:32:39 +00:00
Replace frame capture busy loop with waitable timer (#778)
This commit is contained in:
parent
4ef97c755a
commit
7f6383833c
@ -116,6 +116,7 @@ public:
|
|||||||
class display_base_t : public display_t {
|
class display_base_t : public display_t {
|
||||||
public:
|
public:
|
||||||
int init(int framerate, const std::string &display_name);
|
int init(int framerate, const std::string &display_name);
|
||||||
|
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
||||||
|
|
||||||
std::chrono::nanoseconds delay;
|
std::chrono::nanoseconds delay;
|
||||||
|
|
||||||
@ -147,15 +148,14 @@ protected:
|
|||||||
|
|
||||||
const char *dxgi_format_to_string(DXGI_FORMAT format);
|
const char *dxgi_format_to_string(DXGI_FORMAT format);
|
||||||
|
|
||||||
virtual int complete_img(img_t *img, bool dummy) = 0;
|
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) = 0;
|
||||||
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
|
virtual int complete_img(img_t *img, bool dummy) = 0;
|
||||||
|
virtual std::vector<DXGI_FORMAT> get_supported_sdr_capture_formats() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_ram_t : public display_base_t {
|
class display_ram_t : public display_base_t {
|
||||||
public:
|
public:
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||||
capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible);
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override;
|
std::shared_ptr<img_t> alloc_img() override;
|
||||||
int dummy_img(img_t *img) override;
|
int dummy_img(img_t *img) override;
|
||||||
@ -171,8 +171,7 @@ public:
|
|||||||
|
|
||||||
class display_vram_t : public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
class display_vram_t : public display_base_t, public std::enable_shared_from_this<display_vram_t> {
|
||||||
public:
|
public:
|
||||||
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) override;
|
virtual capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible) override;
|
||||||
capture_e snapshot(img_t *img, std::chrono::milliseconds timeout, bool cursor_visible);
|
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override;
|
std::shared_ptr<img_t> alloc_img() override;
|
||||||
int dummy_img(img_t *img_base) override;
|
int dummy_img(img_t *img_base) override;
|
||||||
|
@ -79,6 +79,63 @@ duplication_t::~duplication_t() {
|
|||||||
release_frame();
|
release_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
capture_e display_base_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<::platf::img_t> img, 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
while(img) {
|
||||||
|
auto wait_time_us = std::chrono::duration_cast<std::chrono::microseconds>(next_frame - std::chrono::steady_clock::now()).count();
|
||||||
|
|
||||||
|
// If the wait time is between 1 us and 1 second, wait the specified time
|
||||||
|
// and offset the next frame time from the exact current frame time target.
|
||||||
|
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);
|
||||||
|
next_frame += delay;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// If the wait time is negative (meaning the frame is past due) or the
|
||||||
|
// computed wait time is beyond a second (meaning possible clock issues),
|
||||||
|
// just capture the frame now and resynchronize the frame interval with
|
||||||
|
// the current time.
|
||||||
|
next_frame = std::chrono::steady_clock::now() + delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto status = snapshot(img.get(), 1000ms, *cursor);
|
||||||
|
switch(status) {
|
||||||
|
case platf::capture_e::reinit:
|
||||||
|
case platf::capture_e::error:
|
||||||
|
return status;
|
||||||
|
case platf::capture_e::timeout:
|
||||||
|
img = snapshot_cb(img, false);
|
||||||
|
break;
|
||||||
|
case platf::capture_e::ok:
|
||||||
|
img = snapshot_cb(img, true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int)status << ']';
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return capture_e::ok;
|
||||||
|
}
|
||||||
|
|
||||||
int display_base_t::init(int framerate, const std::string &display_name) {
|
int display_base_t::init(int framerate, const std::string &display_name) {
|
||||||
std::once_flag windows_cpp_once_flag;
|
std::once_flag windows_cpp_once_flag;
|
||||||
|
|
||||||
|
@ -165,37 +165,6 @@ void blend_cursor(const cursor_t &cursor, img_t &img) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
capture_e display_ram_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<::platf::img_t> img, bool *cursor) {
|
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
while(img) {
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
|
||||||
while(next_frame > now) {
|
|
||||||
now = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
next_frame = now + delay;
|
|
||||||
|
|
||||||
auto status = snapshot(img.get(), 1000ms, *cursor);
|
|
||||||
switch(status) {
|
|
||||||
case platf::capture_e::reinit:
|
|
||||||
case platf::capture_e::error:
|
|
||||||
return status;
|
|
||||||
case platf::capture_e::timeout:
|
|
||||||
img = snapshot_cb(img, false);
|
|
||||||
std::this_thread::sleep_for(1ms);
|
|
||||||
break;
|
|
||||||
case platf::capture_e::ok:
|
|
||||||
img = snapshot_cb(img, true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int)status << ']';
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return capture_e::ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
capture_e display_ram_t::snapshot(::platf::img_t *img_base, std::chrono::milliseconds timeout, bool cursor_visible) {
|
||||||
auto img = (img_t *)img_base;
|
auto img = (img_t *)img_base;
|
||||||
|
|
||||||
|
@ -698,37 +698,6 @@ public:
|
|||||||
device_ctx_t device_ctx;
|
device_ctx_t device_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
capture_e display_vram_t::capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<::platf::img_t> img, bool *cursor) {
|
|
||||||
auto next_frame = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
while(img) {
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
|
||||||
while(next_frame > now) {
|
|
||||||
now = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
next_frame = now + delay;
|
|
||||||
|
|
||||||
auto status = snapshot(img.get(), 1000ms, *cursor);
|
|
||||||
switch(status) {
|
|
||||||
case platf::capture_e::reinit:
|
|
||||||
case platf::capture_e::error:
|
|
||||||
return status;
|
|
||||||
case platf::capture_e::timeout:
|
|
||||||
img = snapshot_cb(img, false);
|
|
||||||
std::this_thread::sleep_for(1ms);
|
|
||||||
break;
|
|
||||||
case platf::capture_e::ok:
|
|
||||||
img = snapshot_cb(img, true);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BOOST_LOG(error) << "Unrecognized capture status ["sv << (int)status << ']';
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return capture_e::ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::buffer_t<std::uint8_t> &&cursor_img, DXGI_OUTDUPL_POINTER_SHAPE_INFO &shape_info) {
|
bool set_cursor_texture(device_t::pointer device, gpu_cursor_t &cursor, util::buffer_t<std::uint8_t> &&cursor_img, DXGI_OUTDUPL_POINTER_SHAPE_INFO &shape_info) {
|
||||||
// This cursor image may not be used
|
// This cursor image may not be used
|
||||||
if(cursor_img.size() == 0) {
|
if(cursor_img.size() == 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user