drm/backend: idle improvements and drm fixes

This commit is contained in:
Vaxry 2024-06-30 19:04:14 +02:00
parent a313f6f0e4
commit c19bf35c02
5 changed files with 102 additions and 35 deletions

View file

@ -104,6 +104,12 @@ namespace Aquamarine {
/* get a vector of the backend implementations available */ /* get a vector of the backend implementations available */
const std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>>& getImplementations(); const std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>>& getImplementations();
/* push an idle event to the queue */
void addIdleEvent(Hyprutils::Memory::CSharedPointer<std::function<void(void)>> fn);
/* remove an idle event from the queue */
void removeIdleEvent(Hyprutils::Memory::CSharedPointer<std::function<void(void)>> pfn);
struct { struct {
Hyprutils::Signal::CSignal newOutput; Hyprutils::Signal::CSignal newOutput;
Hyprutils::Signal::CSignal newPointer; Hyprutils::Signal::CSignal newPointer;
@ -130,6 +136,13 @@ namespace Aquamarine {
Hyprutils::Memory::CWeakPointer<CBackend> self; Hyprutils::Memory::CWeakPointer<CBackend> self;
std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> sessionFDs; std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> sessionFDs;
struct {
int fd = -1;
std::vector<Hyprutils::Memory::CSharedPointer<std::function<void(void)>>> pending;
} idle;
void dispatchIdle();
// //
struct { struct {
std::condition_variable loopSignal; std::condition_variable loopSignal;

View file

@ -45,7 +45,8 @@ namespace Aquamarine {
public: public:
~CDRMFB(); ~CDRMFB();
static Hyprutils::Memory::CSharedPointer<CDRMFB> create(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, bool* isNew = nullptr); static Hyprutils::Memory::CSharedPointer<CDRMFB> create(Hyprutils::Memory::CSharedPointer<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_,
bool* isNew = nullptr);
void closeHandles(); void closeHandles();
// drops the buffer from KMS // drops the buffer from KMS
@ -170,10 +171,13 @@ namespace Aquamarine {
private: private:
CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_); CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, Hyprutils::Memory::CSharedPointer<SDRMConnector> connector_);
bool commitState(bool onlyTest = false); bool commitState(bool onlyTest = false);
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend; Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
Hyprutils::Memory::CSharedPointer<SDRMConnector> connector; Hyprutils::Memory::CSharedPointer<SDRMConnector> connector;
Hyprutils::Memory::CSharedPointer<std::function<void(void)>> frameIdle;
bool lastCommitNoBuffer = true;
friend struct SDRMConnector; friend struct SDRMConnector;
}; };
@ -194,6 +198,7 @@ namespace Aquamarine {
uint32_t gammaLut = 0; uint32_t gammaLut = 0;
uint32_t fbDamage = 0; uint32_t fbDamage = 0;
uint32_t modeBlob = 0; uint32_t modeBlob = 0;
bool blobbed = false;
} atomic; } atomic;
void calculateMode(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector); void calculateMode(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);

View file

@ -5,11 +5,29 @@
#include <sys/poll.h> #include <sys/poll.h>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <sys/timerfd.h>
#include <time.h>
#include <string.h>
using namespace Hyprutils::Memory; using namespace Hyprutils::Memory;
using namespace Aquamarine; using namespace Aquamarine;
#define SP CSharedPointer #define SP CSharedPointer
#define TIMESPEC_NSEC_PER_SEC 1000000000L
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;
}
}
static const char* backendTypeToName(eBackendType type) { static const char* backendTypeToName(eBackendType type) {
switch (type) { switch (type) {
case AQ_BACKEND_DRM: return "drm"; case AQ_BACKEND_DRM: return "drm";
@ -67,6 +85,9 @@ Hyprutils::Memory::CSharedPointer<CBackend> Aquamarine::CBackend::create(const s
} }
} }
// create a timerfd for idle events
backend->idle.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
return backend; return backend;
} }
@ -80,7 +101,7 @@ bool Aquamarine::CBackend::start() {
bool fallback = false; bool fallback = false;
int started = 0; int started = 0;
auto optionsForType = [this] (eBackendType type) -> SBackendImplementationOptions { auto optionsForType = [this](eBackendType type) -> SBackendImplementationOptions {
for (auto& o : implementationOptions) { for (auto& o : implementationOptions) {
if (o.backendType == type) if (o.backendType == type)
return o; return o;
@ -95,8 +116,7 @@ bool Aquamarine::CBackend::start() {
log(AQ_LOG_ERROR, std::format("Requested backend ({}) could not start, enabling fallbacks", backendTypeToName(implementations.at(i)->type()))); log(AQ_LOG_ERROR, std::format("Requested backend ({}) could not start, enabling fallbacks", backendTypeToName(implementations.at(i)->type())));
fallback = true; fallback = true;
if (optionsForType(implementations.at(i)->type()).backendRequestMode == AQ_BACKEND_REQUEST_MANDATORY) { if (optionsForType(implementations.at(i)->type()).backendRequestMode == AQ_BACKEND_REQUEST_MANDATORY) {
log(AQ_LOG_CRITICAL, log(AQ_LOG_CRITICAL, std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementations.at(i)->type())));
std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementations.at(i)->type())));
implementations.clear(); implementations.clear();
return false; return false;
} }
@ -158,6 +178,8 @@ std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::ge
result.emplace_back(sfd); result.emplace_back(sfd);
} }
result.emplace_back(makeShared<SPollFD>(idle.fd, [this]() { dispatchIdle(); }));
return result; return result;
} }
@ -191,6 +213,33 @@ std::vector<SDRMFormat> Aquamarine::CBackend::getPrimaryRenderFormats() {
return {}; return {};
} }
const std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>>& Aquamarine::CBackend::getImplementations() { const std::vector<SP<IBackendImplementation>>& Aquamarine::CBackend::getImplementations() {
return implementations; return implementations;
} }
void Aquamarine::CBackend::addIdleEvent(SP<std::function<void(void)>> fn) {
auto r = idle.pending.emplace_back(fn);
// update timerfd
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
itimerspec ts = {.it_value = now};
if (timerfd_settime(idle.fd, TFD_TIMER_ABSTIME, &ts, nullptr))
log(AQ_LOG_ERROR, std::format("backend: failed to arm timerfd: {}", strerror(errno)));
}
void Aquamarine::CBackend::removeIdleEvent(SP<std::function<void(void)>> pfn) {
std::erase(idle.pending, pfn);
}
void Aquamarine::CBackend::dispatchIdle() {
auto cpy = idle.pending;
idle.pending.clear();
for (auto& i : cpy) {
if (i && *i)
(*i)();
}
}

View file

@ -576,19 +576,8 @@ bool Aquamarine::CDRMBackend::dispatchEvents() {
.page_flip_handler2 = ::handlePF, .page_flip_handler2 = ::handlePF,
}; };
// we will call this asynchronously and not only when drm fd polls, so we
// ignore the errors (from e.g. a partial read)
// TODO: is this ok?
if (drmHandleEvent(gpu->fd, &event) != 0) if (drmHandleEvent(gpu->fd, &event) != 0)
; // backend->log(AQ_LOG_ERROR, std::format("drm: Failed to handle event on fd {}", gpu->fd)); backend->log(AQ_LOG_ERROR, std::format("drm: Failed to handle event on fd {}", gpu->fd));
if (!idleCallbacks.empty()) {
for (auto& c : idleCallbacks) {
if (c)
c();
}
idleCallbacks.clear();
}
return true; return true;
} }
@ -1015,7 +1004,9 @@ void Aquamarine::SDRMConnector::onPresent() {
} }
Aquamarine::CDRMOutput::~CDRMOutput() { Aquamarine::CDRMOutput::~CDRMOutput() {
; backend->backend->removeIdleEvent(frameIdle);
connector->isPageFlipPending = false;
connector->frameEventScheduled = false;
} }
bool Aquamarine::CDRMOutput::commit() { bool Aquamarine::CDRMOutput::commit() {
@ -1146,7 +1137,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
} }
data.blocking = BLOCKING; data.blocking = BLOCKING;
data.modeset = NEEDS_RECONFIG; data.modeset = NEEDS_RECONFIG || lastCommitNoBuffer;
data.flags = flags; data.flags = flags;
data.test = onlyTest; data.test = onlyTest;
if (MODE->modeInfo.has_value()) if (MODE->modeInfo.has_value())
@ -1156,10 +1147,14 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
bool ok = connector->commitState(data); bool ok = connector->commitState(data);
events.commit.emit(); if (onlyTest)
return ok;
events.commit.emit();
state->onCommit(); state->onCommit();
lastCommitNoBuffer = !data.mainFB;
return ok; return ok;
} }
@ -1202,12 +1197,7 @@ void Aquamarine::CDRMOutput::scheduleFrame() {
connector->frameEventScheduled = true; connector->frameEventScheduled = true;
backend->idleCallbacks.emplace_back([this]() { backend->backend->addIdleEvent(frameIdle);
connector->frameEventScheduled = false;
if (connector->isPageFlipPending)
return;
events.frame.emit();
});
} }
Vector2D Aquamarine::CDRMOutput::cursorPlaneSize() { Vector2D Aquamarine::CDRMOutput::cursorPlaneSize() {
@ -1217,6 +1207,13 @@ Vector2D Aquamarine::CDRMOutput::cursorPlaneSize() {
Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, SP<SDRMConnector> connector_) : Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, SP<SDRMConnector> connector_) :
backend(backend_), connector(connector_) { backend(backend_), connector(connector_) {
name = name_; name = name_;
frameIdle = makeShared<std::function<void(void)>>([this]() {
connector->frameEventScheduled = false;
if (connector->isPageFlipPending)
return;
events.frame.emit();
});
} }
SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, bool* isNew) { SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CWeakPointer<CDRMBackend> backend_, bool* isNew) {

View file

@ -47,7 +47,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
// Disable the plane // Disable the plane
backend->log(AQ_LOG_TRACE, std::format("atomic planeProps: disabling plane {}", plane->id)); backend->log(AQ_LOG_TRACE, std::format("atomic planeProps: disabling plane {}", plane->id));
add(plane->id, plane->props.fb_id, 0); add(plane->id, plane->props.fb_id, 0);
add(plane->id, plane->props.crtc_id, crtc); add(plane->id, plane->props.crtc_id, 0);
add(plane->id, plane->props.crtc_x, (uint64_t)pos.x); add(plane->id, plane->props.crtc_x, (uint64_t)pos.x);
add(plane->id, plane->props.crtc_y, (uint64_t)pos.y); add(plane->id, plane->props.crtc_y, (uint64_t)pos.y);
return; return;
@ -73,7 +73,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) { void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
const auto& STATE = connector->output->state->state(); const auto& STATE = connector->output->state->state();
const bool enable = STATE.enabled; const bool enable = STATE.enabled && data.mainFB;
backend->log(AQ_LOG_TRACE, backend->log(AQ_LOG_TRACE,
std::format("atomic addConnector blobs: mode_id {}, active {}, crtc_id {}, link_status {}, content_type {}", connector->crtc->props.mode_id, std::format("atomic addConnector blobs: mode_id {}, active {}, crtc_id {}, link_status {}, content_type {}", connector->crtc->props.mode_id,
@ -82,8 +82,8 @@ void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPoint
add(connector->id, connector->props.crtc_id, enable ? connector->crtc->id : 0); add(connector->id, connector->props.crtc_id, enable ? connector->crtc->id : 0);
if (data.modeset && enable) { if (data.modeset && enable) {
backend->log(AQ_LOG_TRACE, std::format("atomic: mode blob {}", data.atomic.modeBlob));
add(connector->crtc->id, connector->crtc->props.mode_id, data.atomic.modeBlob); add(connector->crtc->id, connector->crtc->props.mode_id, data.atomic.modeBlob);
data.atomic.blobbed = true;
} }
if (data.modeset && enable && connector->props.link_status) if (data.modeset && enable && connector->props.link_status)
@ -182,7 +182,8 @@ void Aquamarine::CDRMAtomicRequest::rollback(SDRMConnectorCommitData& data) {
return; return;
conn->crtc->atomic.ownModeID = true; conn->crtc->atomic.ownModeID = true;
rollbackBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob); if (data.atomic.blobbed)
rollbackBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob);
// TODO: gamma // TODO: gamma
//rollbackBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut); //rollbackBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut);
destroyBlob(data.atomic.fbDamage); destroyBlob(data.atomic.fbDamage);
@ -196,7 +197,8 @@ void Aquamarine::CDRMAtomicRequest::apply(SDRMConnectorCommitData& data) {
conn->crtc->atomic.modeID = 0; conn->crtc->atomic.modeID = 0;
conn->crtc->atomic.ownModeID = true; conn->crtc->atomic.ownModeID = true;
commitBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob); if (data.atomic.blobbed)
commitBlob(&conn->crtc->atomic.modeID, data.atomic.modeBlob);
// TODO: gamma // TODO: gamma
//commitBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut); //commitBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut);
destroyBlob(data.atomic.fbDamage); destroyBlob(data.atomic.fbDamage);
@ -262,7 +264,8 @@ bool Aquamarine::CDRMAtomicImpl::commit(Hyprutils::Memory::CSharedPointer<SDRMCo
if (ok) { if (ok) {
request.apply(data); request.apply(data);
connector->isPageFlipPending = true; if (!data.test && data.mainFB && connector->output->state->state().enabled && (flags & DRM_MODE_PAGE_FLIP_EVENT))
connector->isPageFlipPending = true;
} else } else
request.rollback(data); request.rollback(data);