Skip to content

Commit ea2b9a6

Browse files
committed
Add static pacing to video network packets
1 parent b650400 commit ea2b9a6

File tree

8 files changed

+255
-62
lines changed

8 files changed

+255
-62
lines changed

src/platform/common.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <mutex>
1111
#include <string>
1212

13+
#include <boost/core/noncopyable.hpp>
14+
1315
#include "src/config.h"
1416
#include "src/logging.h"
1517
#include "src/stat_trackers.h"
@@ -790,4 +792,30 @@ namespace platf {
790792
*/
791793
std::vector<supported_gamepad_t> &
792794
supported_gamepads(input_t *input);
795+
796+
struct high_precision_timer: private boost::noncopyable {
797+
virtual ~high_precision_timer() = default;
798+
799+
/**
800+
* @brief Sleep for the duration
801+
* @param duration Sleep duration
802+
*/
803+
virtual void
804+
sleep_for(const std::chrono::nanoseconds &duration) = 0;
805+
806+
/**
807+
* @brief Check if platform-specific timer backend has been initialized successfully
808+
* @return `true` on success, `false` on error
809+
*/
810+
virtual
811+
operator bool() = 0;
812+
};
813+
814+
/**
815+
* @brief Create platform-specific timer capable of high-precision sleep
816+
* @return A unique pointer to timer
817+
*/
818+
std::unique_ptr<high_precision_timer>
819+
create_high_precision_timer();
820+
793821
} // namespace platf

src/platform/linux/misc.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,4 +933,21 @@ namespace platf {
933933

934934
return std::make_unique<deinit_t>();
935935
}
936+
937+
class linux_high_precision_timer: public high_precision_timer {
938+
public:
939+
void
940+
sleep_for(const std::chrono::nanoseconds &duration) override {
941+
std::this_thread::sleep_for(duration);
942+
}
943+
944+
operator bool() override {
945+
true;
946+
}
947+
};
948+
949+
std::unique_ptr<high_precision_timer>
950+
create_high_precision_timer() {
951+
return std::make_unique<linux_high_precision_timer>();
952+
}
936953
} // namespace platf

src/platform/macos/misc.mm

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,22 @@
507507
return std::make_unique<qos_t>(sockfd, reset_options);
508508
}
509509

510+
class macos_high_precision_timer: public high_precision_timer {
511+
public:
512+
void
513+
sleep_for(const std::chrono::nanoseconds &duration) override {
514+
std::this_thread::sleep_for(duration);
515+
}
516+
517+
operator bool() override {
518+
true;
519+
}
520+
};
521+
522+
std::unique_ptr<high_precision_timer>
523+
create_high_precision_timer() {
524+
return std::make_unique<macos_high_precision_timer>();
525+
}
510526
} // namespace platf
511527

512528
namespace dyn {

src/platform/windows/display.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,6 @@ namespace platf::dxgi {
161161
int
162162
init(const ::video::config_t &config, const std::string &display_name);
163163

164-
void
165-
high_precision_sleep(std::chrono::nanoseconds duration);
166-
167164
capture_e
168165
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override;
169166

@@ -184,7 +181,7 @@ namespace platf::dxgi {
184181
DXGI_FORMAT capture_format;
185182
D3D_FEATURE_LEVEL feature_level;
186183

187-
util::safe_ptr_v2<std::remove_pointer_t<HANDLE>, BOOL, CloseHandle> timer;
184+
std::unique_ptr<high_precision_timer> timer = create_high_precision_timer();
188185

189186
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
190187
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE, ///< Idle priority class

src/platform/windows/display_base.cpp

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -182,27 +182,6 @@ namespace platf::dxgi {
182182
release_frame();
183183
}
184184

185-
void
186-
display_base_t::high_precision_sleep(std::chrono::nanoseconds duration) {
187-
if (!timer) {
188-
BOOST_LOG(error) << "Attempting high_precision_sleep() with uninitialized timer";
189-
return;
190-
}
191-
if (duration < 0s) {
192-
BOOST_LOG(error) << "Attempting high_precision_sleep() with negative duration";
193-
return;
194-
}
195-
if (duration > 5s) {
196-
BOOST_LOG(error) << "Attempting high_precision_sleep() with unexpectedly large duration (>5s)";
197-
return;
198-
}
199-
200-
LARGE_INTEGER due_time;
201-
due_time.QuadPart = duration.count() / -100;
202-
SetWaitableTimer(timer.get(), &due_time, 0, nullptr, nullptr, false);
203-
WaitForSingleObject(timer.get(), INFINITE);
204-
}
205-
206185
capture_e
207186
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) {
208187
auto adjust_client_frame_rate = [&]() -> DXGI_RATIONAL {
@@ -268,7 +247,7 @@ namespace platf::dxgi {
268247
status = capture_e::timeout;
269248
}
270249
else {
271-
high_precision_sleep(sleep_period);
250+
timer->sleep_for(sleep_period);
272251
std::chrono::nanoseconds overshoot_ns = std::chrono::steady_clock::now() - sleep_target;
273252
log_sleep_overshoot(overshoot_ns);
274253

@@ -799,15 +778,9 @@ namespace platf::dxgi {
799778
<< "Max Full Luminance : "sv << desc1.MaxFullFrameLuminance << " nits"sv;
800779
}
801780

802-
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
803-
timer.reset(CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS));
804-
if (!timer) {
805-
timer.reset(CreateWaitableTimerEx(nullptr, nullptr, 0, TIMER_ALL_ACCESS));
806-
if (!timer) {
807-
auto winerr = GetLastError();
808-
BOOST_LOG(error) << "Failed to create timer: "sv << winerr;
809-
return -1;
810-
}
781+
if (!timer || !*timer) {
782+
BOOST_LOG(error) << "Uninitialized high precision timer";
783+
return -1;
811784
}
812785

813786
return 0;

src/platform/windows/misc.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,4 +1803,55 @@ namespace platf {
18031803

18041804
return output;
18051805
}
1806+
1807+
class win32_high_precision_timer: public high_precision_timer {
1808+
public:
1809+
win32_high_precision_timer() {
1810+
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
1811+
timer = CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
1812+
if (!timer) {
1813+
timer = CreateWaitableTimerEx(nullptr, nullptr, 0, TIMER_ALL_ACCESS);
1814+
if (!timer) {
1815+
BOOST_LOG(error) << "Unable to create high_precision_timer, CreateWaitableTimerEx() failed: " << GetLastError();
1816+
}
1817+
}
1818+
}
1819+
1820+
~win32_high_precision_timer() {
1821+
if (timer) CloseHandle(timer);
1822+
}
1823+
1824+
void
1825+
sleep_for(const std::chrono::nanoseconds &duration) override {
1826+
if (!timer) {
1827+
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with uninitialized timer";
1828+
return;
1829+
}
1830+
if (duration < 0s) {
1831+
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with negative duration";
1832+
return;
1833+
}
1834+
if (duration > 5s) {
1835+
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with unexpectedly large duration (>5s)";
1836+
return;
1837+
}
1838+
1839+
LARGE_INTEGER due_time;
1840+
due_time.QuadPart = duration.count() / -100;
1841+
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
1842+
WaitForSingleObject(timer, INFINITE);
1843+
}
1844+
1845+
operator bool() override {
1846+
return timer != NULL;
1847+
}
1848+
1849+
private:
1850+
HANDLE timer = NULL;
1851+
};
1852+
1853+
std::unique_ptr<high_precision_timer>
1854+
create_high_precision_timer() {
1855+
return std::make_unique<win32_high_precision_timer>();
1856+
}
18061857
} // namespace platf

0 commit comments

Comments
 (0)