From d048d1c644ba07f5253bcc2f0860be8c517da07c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 5 Jul 2024 19:21:33 +0200 Subject: [PATCH] drm: lease support --- include/aquamarine/backend/DRM.hpp | 35 ++++++- src/backend/drm/DRM.cpp | 146 +++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/include/aquamarine/backend/DRM.hpp b/include/aquamarine/backend/DRM.hpp index 85e31c3..6482003 100644 --- a/include/aquamarine/backend/DRM.hpp +++ b/include/aquamarine/backend/DRM.hpp @@ -11,6 +11,7 @@ namespace Aquamarine { class CDRMBackend; class CDRMFB; + class CDRMOutput; struct SDRMConnector; typedef std::function FIdleCallback; @@ -41,6 +42,31 @@ namespace Aquamarine { } }; + class CDRMLease { + public: + static Hyprutils::Memory::CSharedPointer create(std::vector> outputs); + ~CDRMLease(); + + void terminate(); + + int leaseFD = -1; + uint32_t lesseeID = 0; + Hyprutils::Memory::CWeakPointer backend; + std::vector> outputs; + bool active = true; + + struct { + Hyprutils::Signal::CSignal destroy; + } events; + + private: + CDRMLease() = default; + + void destroy(); + + friend class CDRMBackend; + }; + class CDRMFB { public: ~CDRMFB(); @@ -164,7 +190,10 @@ namespace Aquamarine { virtual Hyprutils::Math::Vector2D cursorPlaneSize(); virtual size_t getGammaSize(); + int getConnectorID(); + Hyprutils::Memory::CWeakPointer self; + Hyprutils::Memory::CWeakPointer lease; bool cursorVisible = true; Hyprutils::Math::Vector2D cursorPos; // without hotspot Hyprutils::Math::Vector2D cursorHotspot; @@ -181,6 +210,7 @@ namespace Aquamarine { bool lastCommitNoBuffer = true; friend struct SDRMConnector; + friend class CDRMLease; }; struct SDRMPageFlip { @@ -297,8 +327,10 @@ namespace Aquamarine { void log(eBackendLogLevel, const std::string&); bool sessionActive(); + int getNonMasterFD(); std::vector idleCallbacks; + std::string gpuName; private: CDRMBackend(Hyprutils::Memory::CSharedPointer backend); @@ -309,12 +341,12 @@ namespace Aquamarine { bool initResources(); bool grabFormats(); void scanConnectors(); + void scanLeases(); void restoreAfterVT(); Hyprutils::Memory::CSharedPointer gpu; Hyprutils::Memory::CSharedPointer impl; Hyprutils::Memory::CWeakPointer primary; - std::string gpuName; Hyprutils::Memory::CWeakPointer backend; @@ -348,5 +380,6 @@ namespace Aquamarine { friend class CDRMLegacyImpl; friend class CDRMAtomicImpl; friend class CDRMAtomicRequest; + friend class CDRMLease; }; }; diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp index 1583a40..2bd8236 100644 --- a/src/backend/drm/DRM.cpp +++ b/src/backend/drm/DRM.cpp @@ -7,6 +7,7 @@ #include #include #include +#include extern "C" { #include @@ -470,6 +471,9 @@ bool Aquamarine::CDRMBackend::registerGPU(SP gpu_, SPlog(AQ_LOG_DEBUG, std::format("drm: Got a hotplug event for {}", gpuName)); scanConnectors(); + } else if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_LEASE) { + backend->log(AQ_LOG_DEBUG, std::format("drm: Got a lease event for {}", gpuName)); + scanLeases(); } }); @@ -543,6 +547,48 @@ void Aquamarine::CDRMBackend::scanConnectors() { drmModeFreeResources(resources); } +void Aquamarine::CDRMBackend::scanLeases() { + auto lessees = drmModeListLessees(gpu->fd); + if (!lessees) { + backend->log(AQ_LOG_ERROR, "drmModeListLessees failed"); + return; + } + + for (auto& c : connectors) { + if (!c->output || !c->output->lease) + continue; + + bool has = false; + for (size_t i = 0; i < lessees->count; ++i) { + if (lessees->lessees[i] == c->output->lease->lesseeID) { + has = true; + break; + } + } + + if (has) + continue; + + backend->log(AQ_LOG_DEBUG, std::format("lessee {} gone, removing", c->output->lease->lesseeID)); + + // don't terminate + c->output->lease->active = false; + + auto l = c->output->lease; + + for (auto& c2 : connectors) { + if (!c2->output || c2->output->lease != c->output->lease) + continue; + + c2->output->lease.reset(); + } + + l->destroy(); + } + + drmFree(lessees); +} + bool Aquamarine::CDRMBackend::start() { impl->reset(); return true; @@ -682,6 +728,22 @@ bool Aquamarine::CDRMBackend::createOutput(const std::string&) { return false; } +int Aquamarine::CDRMBackend::getNonMasterFD() { + int fd = open(gpuName.c_str(), O_RDWR | O_CLOEXEC); + + if (fd < 0) { + backend->log(AQ_LOG_ERROR, "drm: couldn't dupe fd for non master"); + return -1; + } + + if (drmIsMaster(fd) && drmDropMaster(fd) < 0) { + backend->log(AQ_LOG_ERROR, "drm: couldn't drop master from duped fd"); + return -1; + } + + return fd; +} + bool Aquamarine::SDRMPlane::init(drmModePlane* plane) { id = plane->plane_id; @@ -1269,6 +1331,10 @@ size_t Aquamarine::CDRMOutput::getGammaSize() { return size; } +int Aquamarine::CDRMOutput::getConnectorID() { + return connector->id; +} + Aquamarine::CDRMOutput::CDRMOutput(const std::string& name_, Hyprutils::Memory::CWeakPointer backend_, SP connector_) : backend(backend_), connector(connector_) { name = name_; @@ -1488,3 +1554,83 @@ void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CShar Aquamarine::CDRMBufferAttachment::CDRMBufferAttachment(SP fb_) : fb(fb_) { ; } + +SP Aquamarine::CDRMLease::create(std::vector> outputs) { + if (outputs.empty()) + return nullptr; + + if (outputs.at(0)->getBackend()->type() != AQ_BACKEND_DRM) + return nullptr; + + auto backend = ((CDRMBackend*)outputs.at(0)->getBackend().get())->self.lock(); + + for (auto& o : outputs) { + if (o->getBackend() != backend) { + backend->log(AQ_LOG_ERROR, "drm lease: Mismatched backends"); + return nullptr; + } + } + + std::vector objects; + + auto lease = SP(new CDRMLease); + + for (auto& o : outputs) { + auto drmo = ((CDRMOutput*)o.get())->self.lock(); + backend->log(AQ_LOG_DEBUG, std::format("drm lease: output {}, connector {}", drmo->name, drmo->connector->id)); + + // FIXME: do we have to alloc a crtc here? + if (!drmo->connector->crtc) { + backend->log(AQ_LOG_ERROR, std::format("drm lease: output {} has no crtc", drmo->name)); + return nullptr; + } + + backend->log(AQ_LOG_DEBUG, std::format("drm lease: crtc {}, primary {}", drmo->connector->crtc->id, drmo->connector->crtc->primary->id)); + + objects.push_back(drmo->connector->id); + objects.push_back(drmo->connector->crtc->id); + objects.push_back(drmo->connector->crtc->primary->id); + if (drmo->connector->crtc->cursor) + objects.push_back(drmo->connector->crtc->cursor->id); + + lease->outputs.emplace_back(drmo); + } + + backend->log(AQ_LOG_DEBUG, "drm lease: issuing a lease"); + + int leaseFD = drmModeCreateLease(backend->gpu->fd, objects.data(), objects.size(), O_CLOEXEC, &lease->lesseeID); + if (leaseFD < 0) { + backend->log(AQ_LOG_ERROR, "drm lease: drm rejected a lease"); + return nullptr; + } + + for (auto& o : lease->outputs) { + o->lease = lease; + } + + lease->leaseFD = leaseFD; + + backend->log(AQ_LOG_DEBUG, std::format("drm lease: lease granted with lessee id {}", lease->lesseeID)); + + return lease; +} + +Aquamarine::CDRMLease::~CDRMLease() { + if (active) + terminate(); + else + destroy(); +} + +void Aquamarine::CDRMLease::terminate() { + active = false; + + if (drmModeRevokeLease(backend->gpu->fd, lesseeID) < 0) + backend->log(AQ_LOG_ERROR, "drm lease: Failed to revoke lease"); + + destroy(); +} + +void Aquamarine::CDRMLease::destroy() { + events.destroy.emit(); +}