Skip to content

Commit

Permalink
videoout: Make present thread realtime on macOS. (shadps4-emu#990)
Browse files Browse the repository at this point in the history
  • Loading branch information
squidbus authored Sep 19, 2024
1 parent 60f315a commit 048b8ae
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
43 changes: 43 additions & 0 deletions src/common/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "common/thread.h"
#ifdef __APPLE__
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <pthread.h>
#elif defined(_WIN32)
#include <windows.h>
Expand All @@ -31,6 +32,48 @@

namespace Common {

#ifdef __APPLE__

void SetCurrentThreadRealtime(const std::chrono::nanoseconds period_ns) {
// CPU time to grant.
const std::chrono::nanoseconds computation_ns = period_ns / 2;

// Determine the timebase for converting time to ticks.
struct mach_timebase_info timebase {};
mach_timebase_info(&timebase);
const auto ticks_per_ns =
static_cast<double>(timebase.denom) / static_cast<double>(timebase.numer);

const auto period_ticks =
static_cast<u32>(static_cast<double>(period_ns.count()) * ticks_per_ns);
const auto computation_ticks =
static_cast<u32>(static_cast<double>(computation_ns.count()) * ticks_per_ns);

thread_time_constraint_policy policy = {
.period = period_ticks,
.computation = computation_ticks,
// Should not matter since preemptible is false, but needs to be >= computation regardless.
.constraint = computation_ticks,
.preemptible = false,
};

int ret = thread_policy_set(
pthread_mach_thread_np(pthread_self()), THREAD_TIME_CONSTRAINT_POLICY,
reinterpret_cast<thread_policy_t>(&policy), THREAD_TIME_CONSTRAINT_POLICY_COUNT);
if (ret != KERN_SUCCESS) {
LOG_ERROR(Common, "Could not set thread to real-time with period {} ns: {}",
period_ns.count(), ret);
}
}

#else

void SetCurrentThreadRealtime(const std::chrono::nanoseconds period_ns) {
// Not implemented
}

#endif

#ifdef _WIN32

void SetCurrentThreadPriority(ThreadPriority new_priority) {
Expand Down
3 changes: 3 additions & 0 deletions src/common/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include <chrono>
#include "common/types.h"

namespace Common {
Expand All @@ -16,6 +17,8 @@ enum class ThreadPriority : u32 {
Critical = 4,
};

void SetCurrentThreadRealtime(std::chrono::nanoseconds period_ns);

void SetCurrentThreadPriority(ThreadPriority new_priority);

void SetCurrentThreadName(const char* name);
Expand Down
6 changes: 4 additions & 2 deletions src/core/libraries/videoout/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,11 @@ void VideoOutDriver::SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_
}

void VideoOutDriver::PresentThread(std::stop_token token) {
static constexpr std::chrono::milliseconds VblankPeriod{16};
static constexpr std::chrono::nanoseconds VblankPeriod{16666667};
const auto vblank_period = VblankPeriod / Config::vblankDiv();

Common::SetCurrentThreadName("PresentThread");
Common::SetCurrentThreadRealtime(vblank_period);

const auto receive_request = [this] -> Request {
std::scoped_lock lk{mutex};
Expand All @@ -274,7 +277,6 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
return {};
};

auto vblank_period = VblankPeriod / Config::vblankDiv();
auto delay = std::chrono::microseconds{0};
while (!token.stop_requested()) {
// Sleep for most of the vblank duration.
Expand Down

0 comments on commit 048b8ae

Please sign in to comment.