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 */
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 {
Hyprutils::Signal::CSignal newOutput;
Hyprutils::Signal::CSignal newPointer;
@ -130,6 +136,13 @@ namespace Aquamarine {
Hyprutils::Memory::CWeakPointer<CBackend> self;
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 {
std::condition_variable loopSignal;

View file

@ -45,7 +45,8 @@ namespace Aquamarine {
public:
~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();
// drops the buffer from KMS
@ -170,10 +171,13 @@ namespace Aquamarine {
private:
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::CSharedPointer<SDRMConnector> connector;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
Hyprutils::Memory::CSharedPointer<SDRMConnector> connector;
Hyprutils::Memory::CSharedPointer<std::function<void(void)>> frameIdle;
bool lastCommitNoBuffer = true;
friend struct SDRMConnector;
};
@ -194,6 +198,7 @@ namespace Aquamarine {
uint32_t gammaLut = 0;
uint32_t fbDamage = 0;
uint32_t modeBlob = 0;
bool blobbed = false;
} atomic;
void calculateMode(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector);

View file

@ -5,11 +5,29 @@
#include <sys/poll.h>
#include <thread>
#include <chrono>
#include <sys/timerfd.h>
#include <time.h>
#include <string.h>
using namespace Hyprutils::Memory;
using namespace Aquamarine;
#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) {
switch (type) {
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;
}
@ -80,7 +101,7 @@ bool Aquamarine::CBackend::start() {
bool fallback = false;
int started = 0;
auto optionsForType = [this] (eBackendType type) -> SBackendImplementationOptions {
auto optionsForType = [this](eBackendType type) -> SBackendImplementationOptions {
for (auto& o : implementationOptions) {
if (o.backendType == type)
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())));
fallback = true;
if (optionsForType(implementations.at(i)->type()).backendRequestMode == AQ_BACKEND_REQUEST_MANDATORY) {
log(AQ_LOG_CRITICAL,
std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementations.at(i)->type())));
log(AQ_LOG_CRITICAL, std::format("Requested backend ({}) could not start and it's mandatory, cannot continue!", backendTypeToName(implementations.at(i)->type())));
implementations.clear();
return false;
}
@ -158,6 +178,8 @@ std::vector<Hyprutils::Memory::CSharedPointer<SPollFD>> Aquamarine::CBackend::ge
result.emplace_back(sfd);
}
result.emplace_back(makeShared<SPollFD>(idle.fd, [this]() { dispatchIdle(); }));
return result;
}
@ -191,6 +213,33 @@ std::vector<SDRMFormat> Aquamarine::CBackend::getPrimaryRenderFormats() {
return {};
}
const std::vector<Hyprutils::Memory::CSharedPointer<IBackendImplementation>>& Aquamarine::CBackend::getImplementations() {
const std::vector<SP<IBackendImplementation>>& Aquamarine::CBackend::getImplementations() {
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,
};
// 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)
; // 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();
}
backend->log(AQ_LOG_ERROR, std::format("drm: Failed to handle event on fd {}", gpu->fd));
return true;
}
@ -1015,7 +1004,9 @@ void Aquamarine::SDRMConnector::onPresent() {
}
Aquamarine::CDRMOutput::~CDRMOutput() {
;
backend->backend->removeIdleEvent(frameIdle);
connector->isPageFlipPending = false;
connector->frameEventScheduled = false;
}
bool Aquamarine::CDRMOutput::commit() {
@ -1146,7 +1137,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
}
data.blocking = BLOCKING;
data.modeset = NEEDS_RECONFIG;
data.modeset = NEEDS_RECONFIG || lastCommitNoBuffer;
data.flags = flags;
data.test = onlyTest;
if (MODE->modeInfo.has_value())
@ -1156,10 +1147,14 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
bool ok = connector->commitState(data);
events.commit.emit();
if (onlyTest)
return ok;
events.commit.emit();
state->onCommit();
lastCommitNoBuffer = !data.mainFB;
return ok;
}
@ -1202,12 +1197,7 @@ void Aquamarine::CDRMOutput::scheduleFrame() {
connector->frameEventScheduled = true;
backend->idleCallbacks.emplace_back([this]() {
connector->frameEventScheduled = false;
if (connector->isPageFlipPending)
return;
events.frame.emit();
});
backend->backend->addIdleEvent(frameIdle);
}
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_) :
backend(backend_), connector(connector_) {
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) {

View file

@ -47,7 +47,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
// Disable the plane
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.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_y, (uint64_t)pos.y);
return;
@ -73,7 +73,7 @@ void Aquamarine::CDRMAtomicRequest::planeProps(Hyprutils::Memory::CSharedPointer
void Aquamarine::CDRMAtomicRequest::addConnector(Hyprutils::Memory::CSharedPointer<SDRMConnector> connector, SDRMConnectorCommitData& data) {
const auto& STATE = connector->output->state->state();
const bool enable = STATE.enabled;
const bool enable = STATE.enabled && data.mainFB;
backend->log(AQ_LOG_TRACE,
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);
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);
data.atomic.blobbed = true;
}
if (data.modeset && enable && connector->props.link_status)
@ -182,7 +182,8 @@ void Aquamarine::CDRMAtomicRequest::rollback(SDRMConnectorCommitData& data) {
return;
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
//rollbackBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut);
destroyBlob(data.atomic.fbDamage);
@ -196,7 +197,8 @@ void Aquamarine::CDRMAtomicRequest::apply(SDRMConnectorCommitData& data) {
conn->crtc->atomic.modeID = 0;
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
//commitBlob(&conn->crtc->atomic.gammaLut, conn->atomic.gammaLut);
destroyBlob(data.atomic.fbDamage);
@ -262,7 +264,8 @@ bool Aquamarine::CDRMAtomicImpl::commit(Hyprutils::Memory::CSharedPointer<SDRMCo
if (ok) {
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
request.rollback(data);