Skip to content

Commit

Permalink
Improve frametiming for linux capture (#2333)
Browse files Browse the repository at this point in the history
  • Loading branch information
gschintgen authored Apr 12, 2024
1 parent 5c1bad7 commit fcd4c07
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 44 deletions.
20 changes: 20 additions & 0 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include <mutex>
#include <string>

#include "src/config.h"
#include "src/logging.h"
#include "src/stat_trackers.h"
#include "src/thread_safe.h"
#include "src/utility.h"
#include "src/video_colorspace.h"
Expand All @@ -19,6 +21,8 @@ extern "C" {
#include <moonlight-common-c/src/Limelight.h>
}

using namespace std::literals;

struct sockaddr;
struct AVFrame;
struct AVBufferRef;
Expand Down Expand Up @@ -499,6 +503,22 @@ namespace platf {
int env_width, env_height;

int width, height;

protected:
// collect capture timing data (at loglevel debug)
stat_trackers::min_max_avg_tracker<double> sleep_overshoot_tracker;
void
log_sleep_overshoot(std::chrono::nanoseconds overshoot_ns) {
if (config::sunshine.min_log_level <= 1) {
// Print sleep overshoot stats to debug log every 20 seconds
auto print_info = [&](double min_overshoot, double max_overshoot, double avg_overshoot) {
auto f = stat_trackers::one_digit_after_decimal();
BOOST_LOG(debug) << "Sleep overshoot (min/max/avg): " << f % min_overshoot << "ms/" << f % max_overshoot << "ms/" << f % avg_overshoot << "ms";
};
// std::chrono::nanoseconds overshoot_ns = std::chrono::steady_clock::now() - next_frame;
sleep_overshoot_tracker.collect_and_callback_on_interval(overshoot_ns.count() / 1000000., print_info, 20s);
}
}
};

class mic_t {
Expand Down
15 changes: 10 additions & 5 deletions src/platform/linux/cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,16 +800,21 @@ namespace cuda {
handle.reset();
});

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();
if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
std::this_thread::sleep_for(1ns);
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 150ms, *cursor);
Expand Down
30 changes: 20 additions & 10 deletions src/platform/linux/kmsgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,17 +1193,22 @@ namespace platf {
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
auto next_frame = std::chrono::steady_clock::now();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
std::this_thread::sleep_for(1ns);
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down Expand Up @@ -1412,17 +1417,22 @@ namespace platf {
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();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
std::this_thread::sleep_for(1ns);
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down
28 changes: 20 additions & 8 deletions src/platform/linux/wlgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,22 @@ namespace wl {
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
auto next_frame = std::chrono::steady_clock::now();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down Expand Up @@ -259,16 +265,22 @@ namespace wl {
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
auto next_frame = std::chrono::steady_clock::now();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down
30 changes: 20 additions & 10 deletions src/platform/linux/x11grab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,17 +481,22 @@ namespace platf {
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
auto next_frame = std::chrono::steady_clock::now();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
std::this_thread::sleep_for(1ns);
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down Expand Up @@ -622,17 +627,22 @@ namespace platf {
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
auto next_frame = std::chrono::steady_clock::now();

sleep_overshoot_tracker.reset();

while (true) {
auto now = std::chrono::steady_clock::now();

if (next_frame > now) {
std::this_thread::sleep_for((next_frame - now) / 3 * 2);
std::this_thread::sleep_for(next_frame - now);
}
while (next_frame > now) {
std::this_thread::sleep_for(1ns);
now = std::chrono::steady_clock::now();
now = std::chrono::steady_clock::now();
std::chrono::nanoseconds overshoot_ns = now - next_frame;
log_sleep_overshoot(overshoot_ns);

next_frame += delay;
if (next_frame < now) { // some major slowdown happened; we couldn't keep up
next_frame = now + delay;
}
next_frame = now + delay;

std::shared_ptr<platf::img_t> img_out;
auto status = snapshot(pull_free_image_cb, img_out, 1000ms, *cursor);
Expand Down
14 changes: 3 additions & 11 deletions src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ namespace platf::dxgi {
SetThreadExecutionState(ES_CONTINUOUS);
});

stat_trackers::min_max_avg_tracker<double> sleep_overshoot_tracker;
sleep_overshoot_tracker.reset();

while (true) {
// This will return false if the HDR state changes or for any number of other
Expand Down Expand Up @@ -184,16 +184,8 @@ namespace platf::dxgi {
}
else {
high_precision_sleep(sleep_period);

if (config::sunshine.min_log_level <= 1) {
// Print sleep overshoot stats to debug log every 20 seconds
auto print_info = [&](double min_overshoot, double max_overshoot, double avg_overshoot) {
auto f = stat_trackers::one_digit_after_decimal();
BOOST_LOG(debug) << "Sleep overshoot (min/max/avg): " << f % min_overshoot << "ms/" << f % max_overshoot << "ms/" << f % avg_overshoot << "ms";
};
std::chrono::nanoseconds overshoot_ns = std::chrono::steady_clock::now() - sleep_target;
sleep_overshoot_tracker.collect_and_callback_on_interval(overshoot_ns.count() / 1000000., print_info, 20s);
}
std::chrono::nanoseconds overshoot_ns = std::chrono::steady_clock::now() - sleep_target;
log_sleep_overshoot(overshoot_ns);

status = snapshot(pull_free_image_cb, img_out, 0ms, *cursor);

Expand Down

0 comments on commit fcd4c07

Please sign in to comment.