drm: lease support

This commit is contained in:
Vaxry 2024-07-05 19:21:33 +02:00
parent 2a3ff6a61d
commit d048d1c644
2 changed files with 180 additions and 1 deletions

View file

@ -11,6 +11,7 @@
namespace Aquamarine { namespace Aquamarine {
class CDRMBackend; class CDRMBackend;
class CDRMFB; class CDRMFB;
class CDRMOutput;
struct SDRMConnector; struct SDRMConnector;
typedef std::function<void(void)> FIdleCallback; typedef std::function<void(void)> FIdleCallback;
@ -41,6 +42,31 @@ namespace Aquamarine {
} }
}; };
class CDRMLease {
public:
static Hyprutils::Memory::CSharedPointer<CDRMLease> create(std::vector<Hyprutils::Memory::CSharedPointer<IOutput>> outputs);
~CDRMLease();
void terminate();
int leaseFD = -1;
uint32_t lesseeID = 0;
Hyprutils::Memory::CWeakPointer<CDRMBackend> backend;
std::vector<Hyprutils::Memory::CWeakPointer<CDRMOutput>> outputs;
bool active = true;
struct {
Hyprutils::Signal::CSignal destroy;
} events;
private:
CDRMLease() = default;
void destroy();
friend class CDRMBackend;
};
class CDRMFB { class CDRMFB {
public: public:
~CDRMFB(); ~CDRMFB();
@ -164,7 +190,10 @@ namespace Aquamarine {
virtual Hyprutils::Math::Vector2D cursorPlaneSize(); virtual Hyprutils::Math::Vector2D cursorPlaneSize();
virtual size_t getGammaSize(); virtual size_t getGammaSize();
int getConnectorID();
Hyprutils::Memory::CWeakPointer<CDRMOutput> self; Hyprutils::Memory::CWeakPointer<CDRMOutput> self;
Hyprutils::Memory::CWeakPointer<CDRMLease> lease;
bool cursorVisible = true; bool cursorVisible = true;
Hyprutils::Math::Vector2D cursorPos; // without hotspot Hyprutils::Math::Vector2D cursorPos; // without hotspot
Hyprutils::Math::Vector2D cursorHotspot; Hyprutils::Math::Vector2D cursorHotspot;
@ -181,6 +210,7 @@ namespace Aquamarine {
bool lastCommitNoBuffer = true; bool lastCommitNoBuffer = true;
friend struct SDRMConnector; friend struct SDRMConnector;
friend class CDRMLease;
}; };
struct SDRMPageFlip { struct SDRMPageFlip {
@ -297,8 +327,10 @@ namespace Aquamarine {
void log(eBackendLogLevel, const std::string&); void log(eBackendLogLevel, const std::string&);
bool sessionActive(); bool sessionActive();
int getNonMasterFD();
std::vector<FIdleCallback> idleCallbacks; std::vector<FIdleCallback> idleCallbacks;
std::string gpuName;
private: private:
CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend); CDRMBackend(Hyprutils::Memory::CSharedPointer<CBackend> backend);
@ -309,12 +341,12 @@ namespace Aquamarine {
bool initResources(); bool initResources();
bool grabFormats(); bool grabFormats();
void scanConnectors(); void scanConnectors();
void scanLeases();
void restoreAfterVT(); void restoreAfterVT();
Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu; Hyprutils::Memory::CSharedPointer<CSessionDevice> gpu;
Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl; Hyprutils::Memory::CSharedPointer<IDRMImplementation> impl;
Hyprutils::Memory::CWeakPointer<CDRMBackend> primary; Hyprutils::Memory::CWeakPointer<CDRMBackend> primary;
std::string gpuName;
Hyprutils::Memory::CWeakPointer<CBackend> backend; Hyprutils::Memory::CWeakPointer<CBackend> backend;
@ -348,5 +380,6 @@ namespace Aquamarine {
friend class CDRMLegacyImpl; friend class CDRMLegacyImpl;
friend class CDRMAtomicImpl; friend class CDRMAtomicImpl;
friend class CDRMAtomicRequest; friend class CDRMAtomicRequest;
friend class CDRMLease;
}; };
}; };

View file

@ -7,6 +7,7 @@
#include <deque> #include <deque>
#include <cstring> #include <cstring>
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h>
extern "C" { extern "C" {
#include <libseat.h> #include <libseat.h>
@ -470,6 +471,9 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG) { if (E.type == CSessionDevice::AQ_SESSION_EVENT_CHANGE_HOTPLUG) {
backend->log(AQ_LOG_DEBUG, std::format("drm: Got a hotplug event for {}", gpuName)); backend->log(AQ_LOG_DEBUG, std::format("drm: Got a hotplug event for {}", gpuName));
scanConnectors(); 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); 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() { bool Aquamarine::CDRMBackend::start() {
impl->reset(); impl->reset();
return true; return true;
@ -682,6 +728,22 @@ bool Aquamarine::CDRMBackend::createOutput(const std::string&) {
return false; 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) { bool Aquamarine::SDRMPlane::init(drmModePlane* plane) {
id = plane->plane_id; id = plane->plane_id;
@ -1269,6 +1331,10 @@ size_t Aquamarine::CDRMOutput::getGammaSize() {
return size; return size;
} }
int Aquamarine::CDRMOutput::getConnectorID() {
return connector->id;
}
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_;
@ -1488,3 +1554,83 @@ void Aquamarine::SDRMConnectorCommitData::calculateMode(Hyprutils::Memory::CShar
Aquamarine::CDRMBufferAttachment::CDRMBufferAttachment(SP<CDRMFB> fb_) : fb(fb_) { Aquamarine::CDRMBufferAttachment::CDRMBufferAttachment(SP<CDRMFB> fb_) : fb(fb_) {
; ;
} }
SP<CDRMLease> Aquamarine::CDRMLease::create(std::vector<SP<IOutput>> 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<uint32_t> objects;
auto lease = SP<CDRMLease>(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();
}