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

Implement basic network flow control #2803

Merged
merged 3 commits into from
Jul 11, 2024
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 cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ list(PREPEND PLATFORM_LIBRARIES
libstdc++.a
libwinpthread.a
libssp.a
ntdll
ksuser
wsock32
ws2_32
Expand Down
28 changes: 28 additions & 0 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <mutex>
#include <string>

#include <boost/core/noncopyable.hpp>

#include "src/config.h"
#include "src/logging.h"
#include "src/stat_trackers.h"
Expand Down Expand Up @@ -799,4 +801,30 @@ namespace platf {
*/
std::vector<supported_gamepad_t> &
supported_gamepads(input_t *input);

struct high_precision_timer: private boost::noncopyable {
virtual ~high_precision_timer() = default;

/**
* @brief Sleep for the duration
* @param duration Sleep duration
*/
virtual void
sleep_for(const std::chrono::nanoseconds &duration) = 0;

/**
* @brief Check if platform-specific timer backend has been initialized successfully
* @return `true` on success, `false` on error
*/
virtual
operator bool() = 0;
};

/**
* @brief Create platform-specific timer capable of high-precision sleep
* @return A unique pointer to timer
*/
std::unique_ptr<high_precision_timer>
create_high_precision_timer();

} // namespace platf
17 changes: 17 additions & 0 deletions src/platform/linux/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,4 +933,21 @@

return std::make_unique<deinit_t>();
}

class linux_high_precision_timer: public high_precision_timer {

Check warning on line 937 in src/platform/linux/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/misc.cpp#L937

Added line #L937 was not covered by tests
public:
void
sleep_for(const std::chrono::nanoseconds &duration) override {
std::this_thread::sleep_for(duration);

Check warning on line 941 in src/platform/linux/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/misc.cpp#L940-L941

Added lines #L940 - L941 were not covered by tests
}

operator bool() override {
return true;

Check warning on line 945 in src/platform/linux/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/misc.cpp#L944-L945

Added lines #L944 - L945 were not covered by tests
}
};

std::unique_ptr<high_precision_timer>
create_high_precision_timer() {
return std::make_unique<linux_high_precision_timer>();

Check warning on line 951 in src/platform/linux/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/linux/misc.cpp#L950-L951

Added lines #L950 - L951 were not covered by tests
}
} // namespace platf
16 changes: 16 additions & 0 deletions src/platform/macos/misc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,22 @@
return std::make_unique<qos_t>(sockfd, reset_options);
}

class macos_high_precision_timer: public high_precision_timer {
public:
void
sleep_for(const std::chrono::nanoseconds &duration) override {
std::this_thread::sleep_for(duration);

Check warning on line 514 in src/platform/macos/misc.mm

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/misc.mm#L513-L514

Added lines #L513 - L514 were not covered by tests
}

operator bool() override {
return true;

Check warning on line 518 in src/platform/macos/misc.mm

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/misc.mm#L517-L518

Added lines #L517 - L518 were not covered by tests
}
};

std::unique_ptr<high_precision_timer>
create_high_precision_timer() {
return std::make_unique<macos_high_precision_timer>();

Check warning on line 524 in src/platform/macos/misc.mm

View check run for this annotation

Codecov / codecov/patch

src/platform/macos/misc.mm#L523-L524

Added lines #L523 - L524 were not covered by tests
}
} // namespace platf

namespace dyn {
Expand Down
5 changes: 1 addition & 4 deletions src/platform/windows/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,6 @@ 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;

Expand All @@ -184,7 +181,7 @@ namespace platf::dxgi {
DXGI_FORMAT capture_format;
D3D_FEATURE_LEVEL feature_level;

util::safe_ptr_v2<std::remove_pointer_t<HANDLE>, BOOL, CloseHandle> timer;
std::unique_ptr<high_precision_timer> timer = create_high_precision_timer();

typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE, ///< Idle priority class
Expand Down
35 changes: 4 additions & 31 deletions src/platform/windows/display_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,27 +182,6 @@
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 adjust_client_frame_rate = [&]() -> DXGI_RATIONAL {
Expand Down Expand Up @@ -268,7 +247,7 @@
status = capture_e::timeout;
}
else {
high_precision_sleep(sleep_period);
timer->sleep_for(sleep_period);
std::chrono::nanoseconds overshoot_ns = std::chrono::steady_clock::now() - sleep_target;
log_sleep_overshoot(overshoot_ns);

Expand Down Expand Up @@ -799,15 +778,9 @@
<< "Max Full Luminance : "sv << desc1.MaxFullFrameLuminance << " nits"sv;
}

// 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;
}
if (!timer || !*timer) {
BOOST_LOG(error) << "Uninitialized high precision timer";
return -1;

Check warning on line 783 in src/platform/windows/display_base.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/display_base.cpp#L783

Added line #L783 was not covered by tests
}

return 0;
Expand Down
106 changes: 102 additions & 4 deletions src/platform/windows/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@
#define WLAN_API_MAKE_VERSION(_major, _minor) (((DWORD) (_minor)) << 16 | (_major))
#endif

#include <winternl.h>
extern "C" {
NTSTATUS NTAPI
NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);
}

namespace {

std::atomic<bool> used_nt_set_timer_resolution = false;

bool
nt_set_timer_resolution_max() {
ULONG minimum, maximum, current;

Check warning on line 76 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L75-L76

Added lines #L75 - L76 were not covered by tests
if (!NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, &current)) ||
!NT_SUCCESS(NtSetTimerResolution(maximum, TRUE, &current))) {
return false;

Check warning on line 79 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L78-L79

Added lines #L78 - L79 were not covered by tests
}
return true;
}

bool
nt_set_timer_resolution_min() {
ULONG minimum, maximum, current;

Check warning on line 86 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L85-L86

Added lines #L85 - L86 were not covered by tests
if (!NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, &current)) ||
!NT_SUCCESS(NtSetTimerResolution(minimum, TRUE, &current))) {
return false;

Check warning on line 89 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L88-L89

Added lines #L88 - L89 were not covered by tests
}
return true;
}

} // namespace

namespace bp = boost::process;

using namespace std::literals;
Expand Down Expand Up @@ -1115,8 +1147,15 @@
// Enable MMCSS scheduling for DWM
DwmEnableMMCSS(true);

// Reduce timer period to 1ms
timeBeginPeriod(1);
// Reduce timer period to 0.5ms
if (nt_set_timer_resolution_max()) {
used_nt_set_timer_resolution = true;

Check warning on line 1152 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1152

Added line #L1152 was not covered by tests
}
else {
BOOST_LOG(error) << "NtSetTimerResolution() failed, falling back to timeBeginPeriod()";
timeBeginPeriod(1);
used_nt_set_timer_resolution = false;

Check warning on line 1157 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1156-L1157

Added lines #L1156 - L1157 were not covered by tests
}

// Promote ourselves to high priority class
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
Expand Down Expand Up @@ -1199,8 +1238,16 @@
// Demote ourselves back to normal priority class
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);

// End our 1ms timer request
timeEndPeriod(1);
// End our 0.5ms timer request
if (used_nt_set_timer_resolution) {
used_nt_set_timer_resolution = false;

Check warning on line 1243 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1243

Added line #L1243 was not covered by tests
if (!nt_set_timer_resolution_min()) {
BOOST_LOG(error) << "nt_set_timer_resolution_min() failed even though nt_set_timer_resolution_max() succeeded";
}
}
else {
timeEndPeriod(1);

Check warning on line 1249 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1249

Added line #L1249 was not covered by tests
}

// Disable MMCSS scheduling for DWM
DwmEnableMMCSS(false);
Expand Down Expand Up @@ -1756,4 +1803,55 @@

return output;
}

class win32_high_precision_timer: public high_precision_timer {
public:
win32_high_precision_timer() {
// Use CREATE_WAITABLE_TIMER_HIGH_RESOLUTION if supported (Windows 10 1809+)
timer = CreateWaitableTimerEx(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (!timer) {
timer = CreateWaitableTimerEx(nullptr, nullptr, 0, TIMER_ALL_ACCESS);

Check warning on line 1813 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1813

Added line #L1813 was not covered by tests
if (!timer) {
BOOST_LOG(error) << "Unable to create high_precision_timer, CreateWaitableTimerEx() failed: " << GetLastError();
}
}
}

~win32_high_precision_timer() {
if (timer) CloseHandle(timer);
}

void
sleep_for(const std::chrono::nanoseconds &duration) override {

Check warning on line 1825 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1825

Added line #L1825 was not covered by tests
if (!timer) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with uninitialized timer";
return;

Check warning on line 1828 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1828

Added line #L1828 was not covered by tests
}
if (duration < 0s) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with negative duration";
return;

Check warning on line 1832 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1832

Added line #L1832 was not covered by tests
}
if (duration > 5s) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with unexpectedly large duration (>5s)";
return;

Check warning on line 1836 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1836

Added line #L1836 was not covered by tests
}

LARGE_INTEGER due_time;
due_time.QuadPart = duration.count() / -100;
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
WaitForSingleObject(timer, INFINITE);

Check warning on line 1842 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1839-L1842

Added lines #L1839 - L1842 were not covered by tests
}

operator bool() override {
return timer != NULL;

Check warning on line 1846 in src/platform/windows/misc.cpp

View check run for this annotation

Codecov / codecov/patch

src/platform/windows/misc.cpp#L1845-L1846

Added lines #L1845 - L1846 were not covered by tests
}

private:
HANDLE timer = NULL;
};

std::unique_ptr<high_precision_timer>
create_high_precision_timer() {
return std::make_unique<win32_high_precision_timer>();
}
} // namespace platf
Loading
Loading