Skip to content
44 changes: 10 additions & 34 deletions src/backend/Headless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,6 @@ using namespace Hyprutils::Math;

#define TIMESPEC_NSEC_PER_SEC 1000000000LL

static void timespecAddNs(timespec* pTimespec, int64_t delta) {
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;

pTimespec->tv_sec += delta_s_high;

pTimespec->tv_nsec += (long)delta_ns_low;
if (pTimespec->tv_nsec >= TIMESPEC_NSEC_PER_SEC) {
pTimespec->tv_nsec -= TIMESPEC_NSEC_PER_SEC;
++pTimespec->tv_sec;
}
}

Aquamarine::CHeadlessOutput::CHeadlessOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CHeadlessBackend> backend_) : backend(backend_) {
name = name_;

Expand Down Expand Up @@ -86,18 +73,15 @@ void Aquamarine::CHeadlessOutput::scheduleFrame(const scheduleFrameReason reason
else if (currentState.customMode)
refreshRatemHz = currentState.customMode->refreshRate;

int64_t frameIntervalNs = (TIMESPEC_NSEC_PER_SEC * 1000LL) / refreshRatemHz;
const auto frameInterval = std::chrono::nanoseconds(1'000'000'000'000LL / refreshRatemHz);
const auto NEXT_FRAME_TIME = lastFrame + frameInterval;

const auto NOW = std::chrono::steady_clock::now();
const int64_t TIME_SINCE_FRAME = std::chrono::duration_cast<std::chrono::nanoseconds>(NOW - lastFrame).count();
const int64_t TIME_UNTIL_FRAME = frameIntervalNs - TIME_SINCE_FRAME;

if (TIME_UNTIL_FRAME <= 0) {
if (std::chrono::steady_clock::now() >= NEXT_FRAME_TIME) {
backend->backend->addIdleEvent(framecb);
return;
}

backend->addTimer(NOW + std::chrono::nanoseconds(TIME_UNTIL_FRAME), [this]() {
backend->addTimer(NEXT_FRAME_TIME, [this]() {
if (framecb)
(*framecb)();
});
Expand Down Expand Up @@ -220,24 +204,16 @@ void Aquamarine::CHeadlessBackend::dispatchTimers() {
}

void Aquamarine::CHeadlessBackend::updateTimerFD() {
long long lowestNs = TIMESPEC_NSEC_PER_SEC * 240 /* 240s, 4 mins */;
const auto clocknow = std::chrono::steady_clock::now();
auto soonestTimer = std::chrono::steady_clock::now() + std::chrono::minutes(4);

for (auto const& t : timers.timers) {
auto delta = std::chrono::duration_cast<std::chrono::microseconds>(t.when - clocknow).count() * 1000 /* µs -> ns */;

if (delta < lowestNs)
lowestNs = delta;
if (t.when < soonestTimer)
soonestTimer = t.when;
}

if (lowestNs < 0)
lowestNs = 0;

timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
timespecAddNs(&now, lowestNs);

itimerspec ts = {.it_value = now};
auto secs = std::chrono::time_point_cast<std::chrono::seconds>(soonestTimer);
auto ns = std::chrono::time_point_cast<std::chrono::nanoseconds>(soonestTimer) - std::chrono::time_point_cast<std::chrono::nanoseconds>(secs);
itimerspec ts = {.it_value = {secs.time_since_epoch().count(), ns.count()}};

if (timerfd_settime(timers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr))
backend->log(AQ_LOG_ERROR, std::format("headless: failed to arm timerfd: {}", strerror(errno)));
Expand Down