mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-12-22 22:59:47 +01:00
drm/backend: idle improvements and drm fixes
This commit is contained in:
parent
a313f6f0e4
commit
c19bf35c02
5 changed files with 102 additions and 35 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue