Implement basic network flow control (#2803)

Co-authored-by: Cameron Gutman <aicommander@gmail.com>
This commit is contained in:
ns6089
2024-07-11 03:03:16 +03:00
committed by GitHub
parent 6607a28a68
commit 037c61dc99
9 changed files with 352 additions and 101 deletions

View File

@@ -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;
@@ -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

View File

@@ -182,27 +182,6 @@ 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 adjust_client_frame_rate = [&]() -> DXGI_RATIONAL {
@@ -268,7 +247,7 @@ namespace platf::dxgi {
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);
@@ -799,15 +778,9 @@ namespace platf::dxgi {
<< "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;
}
return 0;

View File

@@ -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;
if (!NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, &current)) ||
!NT_SUCCESS(NtSetTimerResolution(maximum, TRUE, &current))) {
return false;
}
return true;
}
bool
nt_set_timer_resolution_min() {
ULONG minimum, maximum, current;
if (!NT_SUCCESS(NtQueryTimerResolution(&minimum, &maximum, &current)) ||
!NT_SUCCESS(NtSetTimerResolution(minimum, TRUE, &current))) {
return false;
}
return true;
}
} // namespace
namespace bp = boost::process;
using namespace std::literals;
@@ -1115,8 +1147,15 @@ namespace platf {
// 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;
}
else {
BOOST_LOG(error) << "NtSetTimerResolution() failed, falling back to timeBeginPeriod()";
timeBeginPeriod(1);
used_nt_set_timer_resolution = false;
}
// Promote ourselves to high priority class
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
@@ -1199,8 +1238,16 @@ namespace platf {
// 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;
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);
}
// Disable MMCSS scheduling for DWM
DwmEnableMMCSS(false);
@@ -1756,4 +1803,55 @@ namespace platf {
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);
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 {
if (!timer) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with uninitialized timer";
return;
}
if (duration < 0s) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with negative duration";
return;
}
if (duration > 5s) {
BOOST_LOG(error) << "Attempting high_precision_timer::sleep_for() with unexpectedly large duration (>5s)";
return;
}
LARGE_INTEGER due_time;
due_time.QuadPart = duration.count() / -100;
SetWaitableTimer(timer, &due_time, 0, nullptr, nullptr, false);
WaitForSingleObject(timer, INFINITE);
}
operator bool() override {
return timer != NULL;
}
private:
HANDLE timer = NULL;
};
std::unique_ptr<high_precision_timer>
create_high_precision_timer() {
return std::make_unique<win32_high_precision_timer>();
}
} // namespace platf