Skip to content

drm-lease: Add Multi-GPU Support #10099

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ void CMonitor::onConnect(bool noRule) {

if (output->nonDesktop) {
Debug::log(LOG, "Not configuring non-desktop output");
if (PROTO::lease)
PROTO::lease->offer(self.lock());

for (auto& lease : PROTO::lease) {
if (lease.second && output->getBackend() == lease.second->getBackend()) {
lease.second->offer(self.lock());
}
}

return;
}
Expand Down
12 changes: 8 additions & 4 deletions src/managers/ProtocolManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,12 @@ CProtocolManager::CProtocolManager() {
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
continue;

PROTO::lease = makeUnique<CDRMLeaseProtocol>(&wp_drm_lease_device_v1_interface, 1, "DRMLease");
if (*PENABLEEXPLICIT)
auto lease = makeShared<CDRMLeaseProtocol>(&wp_drm_lease_device_v1_interface, 1, "DRMLease", b);
if (lease->good())
PROTO::lease.emplace(lease->getDeviceName(), lease);

if (*PENABLEEXPLICIT && !PROTO::sync)
PROTO::sync = makeUnique<CDRMSyncobjProtocol>(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj");
break;
}

if (g_pHyprOpenGL->getDRMFormats().size() > 0) {
Expand Down Expand Up @@ -272,7 +274,9 @@ CProtocolManager::~CProtocolManager() {
PROTO::xxColorManagement.reset();
PROTO::frogColorManagement.reset();

PROTO::lease.reset();
for (auto& lease : PROTO::lease) {
lease.second.reset();
}
PROTO::sync.reset();
PROTO::mesaDRM.reset();
PROTO::linuxDma.reset();
Expand Down
105 changes: 67 additions & 38 deletions src/protocols/DRMLease.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "DRMLease.hpp"
#include "../Compositor.hpp"
#include "../helpers/Monitor.hpp"
#include "drm-lease-v1.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include "protocols/WaylandProtocol.hpp"
#include <aquamarine/backend/DRM.hpp>
#include <fcntl.h>
using namespace Hyprutils::OS;
Expand All @@ -10,12 +12,18 @@ CDRMLeaseResource::CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRe
if UNLIKELY (!good())
return;

resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); });
resource->setDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); });

parent = request->parent;
requested = request->requested;

resource->setOnDestroy([this](CWpDrmLeaseV1* r) {
if (parent && PROTO::lease.contains(parent->deviceName))
PROTO::lease[parent->deviceName]->destroyResource(this);
});
resource->setDestroy([this](CWpDrmLeaseV1* r) {
if (parent && PROTO::lease.contains(parent->deviceName))
PROTO::lease[parent->deviceName]->destroyResource(this);
});

for (auto const& m : requested) {
if (!m->monitor || m->monitor->isBeingLeased) {
LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null"));
Expand Down Expand Up @@ -82,11 +90,14 @@ CDRMLeaseResource::~CDRMLeaseResource() {
listeners.destroyLease.reset();
}

CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> resource_) : resource(resource_) {
CDRMLeaseRequestResource::CDRMLeaseRequestResource(WP<CDRMLeaseDeviceResource> parent_, SP<CWpDrmLeaseRequestV1> resource_) : parent(parent_), resource(resource_) {
if UNLIKELY (!good())
return;

resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); });
resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) {
if (parent && PROTO::lease.contains(parent->deviceName))
PROTO::lease[parent->deviceName]->destroyResource(this);
});

resource->setRequestConnector([this](CWpDrmLeaseRequestV1* r, wl_resource* conn) {
if (!conn) {
Expand All @@ -101,7 +112,12 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> reso
return;
}

// TODO: when (if) we add multi, make sure this is from the correct device.
auto& lease = PROTO::lease[parent->deviceName];

if (std::find(lease->m_vConnectors.begin(), lease->m_vConnectors.end(), CONNECTOR) == lease->m_vConnectors.end()) {
resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE, "Connector requested for wrong device");
return;
}

requested.emplace_back(CONNECTOR);
});
Expand All @@ -118,10 +134,10 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> reso
return;
}

PROTO::lease->m_vLeases.emplace_back(RESOURCE);
PROTO::lease[parent->deviceName]->m_vLeases.emplace_back(RESOURCE);

// per protcol, after submit, this is dead.
PROTO::lease->destroyResource(this);
PROTO::lease[parent->deviceName]->destroyResource(this);
});
}

Expand All @@ -134,12 +150,19 @@ SP<CDRMLeaseConnectorResource> CDRMLeaseConnectorResource::fromResource(wl_resou
return data ? data->self.lock() : nullptr;
}

CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP<CWpDrmLeaseConnectorV1> resource_, PHLMONITOR monitor_) : monitor(monitor_), resource(resource_) {
CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(WP<CDRMLeaseDeviceResource> parent_, SP<CWpDrmLeaseConnectorV1> resource_, PHLMONITOR monitor_) :
parent(parent_), monitor(monitor_), resource(resource_) {
if UNLIKELY (!good())
return;

resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); });
resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); });
resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) {
if (parent && PROTO::lease.contains(parent->deviceName))
PROTO::lease[parent->deviceName]->destroyResource(this);
});
resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) {
if (parent && PROTO::lease.contains(parent->deviceName))
PROTO::lease[parent->deviceName]->destroyResource(this);
});

resource->setData(this);

Expand All @@ -163,30 +186,37 @@ void CDRMLeaseConnectorResource::sendData() {
resource->sendDone();
}

CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resource_) : resource(resource_) {
CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(std::string deviceName_, SP<CWpDrmLeaseDeviceV1> resource_) : deviceName(deviceName_), resource(resource_) {
if UNLIKELY (!good())
return;

resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); });
resource->setRelease([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); });
resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) {
if (PROTO::lease.contains(deviceName))
PROTO::lease[deviceName]->destroyResource(this);
});
resource->setRelease([this](CWpDrmLeaseDeviceV1* r) {
if (PROTO::lease.contains(deviceName))
PROTO::lease[deviceName]->destroyResource(this);
});

resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) {
auto RESOURCE = makeShared<CDRMLeaseRequestResource>(makeShared<CWpDrmLeaseRequestV1>(resource->client(), resource->version(), id));
auto RESOURCE = makeShared<CDRMLeaseRequestResource>(self, makeShared<CWpDrmLeaseRequestV1>(resource->client(), resource->version(), id));
if UNLIKELY (!RESOURCE) {
resource->noMemory();
return;
}

RESOURCE->self = RESOURCE;

PROTO::lease->m_vRequests.emplace_back(RESOURCE);
PROTO::lease[deviceName]->m_vRequests.emplace_back(RESOURCE);

LOGM(LOG, "New lease request {}", id);

RESOURCE->parent = self;
});

CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()};
auto& primaryDevice = PROTO::lease[deviceName]->primaryDevice;
CFileDescriptor fd{((Aquamarine::CDRMBackend*)primaryDevice->backend.get())->getNonMasterFD()};
if (!fd.isValid()) {
LOGM(ERR, "Failed to dup fd in lease");
return;
Expand All @@ -195,7 +225,7 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resourc
LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get());
resource->sendDrmFd(fd.get());

for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) {
for (auto const& m : primaryDevice->offeredOutputs) {
if (m)
sendConnector(m.lock());
}
Expand All @@ -211,7 +241,7 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) {
if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e && !e->dead && e->monitor == monitor; }) != connectorsSent.end())
return;

auto RESOURCE = makeShared<CDRMLeaseConnectorResource>(makeShared<CWpDrmLeaseConnectorV1>(resource->client(), resource->version(), 0), monitor);
auto RESOURCE = makeShared<CDRMLeaseConnectorResource>(self, makeShared<CWpDrmLeaseConnectorV1>(resource->client(), resource->version(), 0), monitor);
if UNLIKELY (!RESOURCE) {
resource->noMemory();
return;
Expand All @@ -223,7 +253,7 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) {
LOGM(LOG, "Sending new connector {}", monitor->szName);

connectorsSent.emplace_back(RESOURCE);
PROTO::lease->m_vConnectors.emplace_back(RESOURCE);
PROTO::lease[deviceName]->m_vConnectors.emplace_back(RESOURCE);

resource->sendConnector(RESOURCE->resource.get());

Expand All @@ -244,25 +274,14 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend) : backe
name = drm->gpuName;
}

CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
continue;

auto drm = ((Aquamarine::CDRMBackend*)b.get())->self.lock();

primaryDevice = makeShared<CDRMLeaseDevice>(drm);

if (primaryDevice->success)
break;
}

if (!primaryDevice || !primaryDevice->success)
g_pEventLoopManager->doLater([]() { PROTO::lease.reset(); });
CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<Aquamarine::IBackendImplementation> backend) :
IWaylandProtocol(iface, ver, name) {
auto drm = ((Aquamarine::CDRMBackend*)backend.get())->self.lock();
primaryDevice = makeShared<CDRMLeaseDevice>(drm);
}

void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CDRMLeaseDeviceResource>(makeShared<CWpDrmLeaseDeviceV1>(client, ver, id)));
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CDRMLeaseDeviceResource>(primaryDevice->name, makeShared<CWpDrmLeaseDeviceV1>(client, ver, id)));

if UNLIKELY (!RESOURCE->good()) {
wl_client_post_no_memory(client);
Expand Down Expand Up @@ -296,10 +315,8 @@ void CDRMLeaseProtocol::offer(PHLMONITOR monitor) {
std::erase_if(primaryDevice->offeredOutputs, [](const auto& e) { return e.expired(); });
if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end())
return;

if (monitor->output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
return;

if (monitor->output->getBackend() != primaryDevice->backend) {
LOGM(ERR, "Monitor {} cannot be leased: primaryDevice lease is for a different device", monitor->szName);
return;
Expand All @@ -312,3 +329,15 @@ void CDRMLeaseProtocol::offer(PHLMONITOR monitor) {
m->resource->sendDone();
}
}

std::string CDRMLeaseProtocol::getDeviceName() {
return primaryDevice->name;
}

SP<Aquamarine::IBackendImplementation> CDRMLeaseProtocol::getBackend() {
return primaryDevice->backend;
}

bool CDRMLeaseProtocol::good() {
return primaryDevice && primaryDevice->success;
}
17 changes: 12 additions & 5 deletions src/protocols/DRMLease.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <aquamarine/backend/Backend.hpp>
#include <vector>
#include <unordered_map>
#include "WaylandProtocol.hpp"
Expand Down Expand Up @@ -42,7 +43,7 @@ class CDRMLeaseResource {

class CDRMLeaseRequestResource {
public:
CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> resource_);
CDRMLeaseRequestResource(WP<CDRMLeaseDeviceResource> parent_, SP<CWpDrmLeaseRequestV1> resource_);

bool good();

Expand All @@ -56,7 +57,7 @@ class CDRMLeaseRequestResource {

class CDRMLeaseConnectorResource {
public:
CDRMLeaseConnectorResource(SP<CWpDrmLeaseConnectorV1> resource_, PHLMONITOR monitor_);
CDRMLeaseConnectorResource(WP<CDRMLeaseDeviceResource> parent_, SP<CWpDrmLeaseConnectorV1> resource_, PHLMONITOR monitor_);
static SP<CDRMLeaseConnectorResource> fromResource(wl_resource*);

bool good();
Expand All @@ -79,14 +80,15 @@ class CDRMLeaseConnectorResource {

class CDRMLeaseDeviceResource {
public:
CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resource_);
CDRMLeaseDeviceResource(std::string deviceName, SP<CWpDrmLeaseDeviceV1> resource_);

bool good();
void sendConnector(PHLMONITOR monitor);

std::vector<WP<CDRMLeaseConnectorResource>> connectorsSent;

WP<CDRMLeaseDeviceResource> self;
std::string deviceName;

private:
SP<CWpDrmLeaseDeviceV1> resource;
Expand All @@ -107,12 +109,16 @@ class CDRMLeaseDevice {

class CDRMLeaseProtocol : public IWaylandProtocol {
public:
CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name);
CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP<Aquamarine::IBackendImplementation> drm);

virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);

void offer(PHLMONITOR monitor);

SP<Aquamarine::IBackendImplementation> getBackend();
std::string getDeviceName();
bool good();

private:
void destroyResource(CDRMLeaseDeviceResource* resource);
void destroyResource(CDRMLeaseConnectorResource* resource);
Expand All @@ -126,6 +132,7 @@ class CDRMLeaseProtocol : public IWaylandProtocol {
std::vector<SP<CDRMLeaseResource>> m_vLeases;

SP<CDRMLeaseDevice> primaryDevice;
WP<CDRMLeaseProtocol> self;

friend class CDRMLeaseDeviceResource;
friend class CDRMLeaseConnectorResource;
Expand All @@ -134,5 +141,5 @@ class CDRMLeaseProtocol : public IWaylandProtocol {
};

namespace PROTO {
inline UP<CDRMLeaseProtocol> lease;
inline std::unordered_map<std::string, SP<CDRMLeaseProtocol>> lease;
};