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 */
|
/* 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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue