mirror of
https://github.com/hyprwm/aquamarine.git
synced 2024-11-17 04:56:00 +01:00
drm: lease support
This commit is contained in:
parent
2a3ff6a61d
commit
d048d1c644
2 changed files with 180 additions and 1 deletions
|
@ -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;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue