diff --git a/src/backends/drm/drm_backend.cpp b/src/backends/drm/drm_backend.cpp index 6b6806fb3c..f0a3523210 100644 --- a/src/backends/drm/drm_backend.cpp +++ b/src/backends/drm/drm_backend.cpp @@ -300,6 +300,7 @@ DrmGpu *DrmBackend::addGpu(const QString &fileName) m_active = true; connect(gpu, &DrmGpu::outputAdded, this, &DrmBackend::addOutput); connect(gpu, &DrmGpu::outputRemoved, this, &DrmBackend::removeOutput); + Q_EMIT gpuAdded(gpu); return gpu; } @@ -333,7 +334,9 @@ void DrmBackend::updateOutputs() DrmGpu *gpu = it->get(); if (gpu->isRemoved() || (gpu != primaryGpu() && gpu->drmOutputs().isEmpty())) { qCDebug(KWIN_DRM) << "Removing GPU" << (*it)->devNode(); + const std::unique_ptr keepAlive = std::move(*it); it = m_gpus.erase(it); + Q_EMIT gpuRemoved(keepAlive.get()); } else { it++; } @@ -526,4 +529,9 @@ void DrmBackend::releaseBuffers() gpu->releaseBuffers(); } } + +const std::vector> &DrmBackend::gpus() const +{ + return m_gpus; +} } diff --git a/src/backends/drm/drm_backend.h b/src/backends/drm/drm_backend.h index 1143b354d5..2c0919da85 100644 --- a/src/backends/drm/drm_backend.h +++ b/src/backends/drm/drm_backend.h @@ -75,12 +75,16 @@ public: void releaseBuffers(); void updateOutputs(); + const std::vector> &gpus() const; + public Q_SLOTS: void turnOutputsOn(); void sceneInitialized() override; Q_SIGNALS: void activeChanged(); + void gpuAdded(DrmGpu *gpu); + void gpuRemoved(DrmGpu *gpu); protected: bool applyOutputChanges(const OutputConfiguration &config) override; diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 24b02e1741..82ab6178ce 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -24,8 +24,6 @@ #include "drm_plane.h" #include "drm_virtual_output.h" #include "gbm_dmabuf.h" -#include "wayland/drmleasedevice_v1_interface.h" -#include "wayland_server.h" // system #include #include @@ -85,30 +83,6 @@ DrmGpu::DrmGpu(DrmBackend *backend, const QString &devNode, int fd, dev_t device connect(m_socketNotifier.get(), &QSocketNotifier::activated, this, &DrmGpu::dispatchEvents); initDrmResources(); - - m_leaseDevice = std::make_unique(waylandServer()->display(), [this] { - char *path = drmGetDeviceNameFromFd2(m_fd); - FileDescriptor fd{open(path, O_RDWR | O_CLOEXEC)}; - if (!fd.isValid()) { - qCWarning(KWIN_DRM) << "Could not open DRM fd for leasing!" << strerror(errno); - } else { - if (drmIsMaster(fd.get())) { - if (drmDropMaster(fd.get()) != 0) { - qCWarning(KWIN_DRM) << "Could not create a non-master DRM fd for leasing!" << strerror(errno); - return FileDescriptor{}; - } - } - } - return fd; - }); - connect(m_leaseDevice.get(), &KWaylandServer::DrmLeaseDeviceV1Interface::leaseRequested, this, &DrmGpu::handleLeaseRequest); - connect(m_leaseDevice.get(), &KWaylandServer::DrmLeaseDeviceV1Interface::leaseRevoked, this, &DrmGpu::handleLeaseRevoked); - connect(m_platform, &DrmBackend::activeChanged, m_leaseDevice.get(), [this]() { - if (!m_platform->isActive()) { - // when we gain drm master we want to update outputs first and only then notify the lease device - m_leaseDevice->setDrmMaster(false); - } - }); } DrmGpu::~DrmGpu() @@ -120,7 +94,6 @@ DrmGpu::~DrmGpu() m_crtcs.clear(); m_connectors.clear(); m_planes.clear(); - m_leaseDevice.reset(); m_socketNotifier.reset(); if (m_gbmDevice) { gbm_device_destroy(m_gbmDevice); @@ -128,6 +101,23 @@ DrmGpu::~DrmGpu() m_platform->session()->closeRestricted(m_fd); } +FileDescriptor DrmGpu::createNonMasterFd() const +{ + char *path = drmGetDeviceNameFromFd2(m_fd); + FileDescriptor fd{open(path, O_RDWR | O_CLOEXEC)}; + if (!fd.isValid()) { + qCWarning(KWIN_DRM) << "Could not open DRM fd for leasing!" << strerror(errno); + } else { + if (drmIsMaster(fd.get())) { + if (drmDropMaster(fd.get()) != 0) { + qCWarning(KWIN_DRM) << "Could not create a non-master DRM fd for leasing!" << strerror(errno); + return FileDescriptor{}; + } + } + } + return fd; +} + clockid_t DrmGpu::presentationClock() const { return m_presentationClock; @@ -227,7 +217,7 @@ bool DrmGpu::updateOutputs() } } if (!leaseActive) { - output->lease()->revoke(); + Q_EMIT output->lease()->revokeRequested(); } } } @@ -266,7 +256,7 @@ bool DrmGpu::updateOutputs() qCDebug(KWIN_DRM, "New %soutput on GPU %s: %s", conn->isNonDesktop() ? "non-desktop " : "", qPrintable(m_devNode), qPrintable(conn->modelName())); const auto pipeline = conn->pipeline(); m_pipelines << pipeline; - auto output = new DrmOutput(pipeline, m_leaseDevice.get()); + auto output = new DrmOutput(pipeline); m_drmOutputs << output; addedOutputs << output; Q_EMIT outputAdded(output); @@ -324,10 +314,6 @@ bool DrmGpu::updateOutputs() output->pipeline()->applyPendingChanges(); } } - m_leaseDevice->setDrmMaster(true); - // after (potential) lease offer changes, a done event needs to be sent - // to signal clients to handle the changes - m_leaseDevice->done(); return true; } @@ -604,22 +590,12 @@ void DrmGpu::removeVirtualOutput(DrmVirtualOutput *output) } } -void DrmGpu::handleLeaseRequest(KWaylandServer::DrmLeaseV1Interface *leaseRequest) +std::unique_ptr DrmGpu::leaseOutputs(const QVector &outputs) { QVector objects; - QVector outputs; - - const auto connectors = leaseRequest->connectors(); - for (KWaylandServer::DrmLeaseConnectorV1Interface *connector : connectors) { - if (DrmOutput *output = findOutput(connector->id())) { - if (output->lease()) { - continue; // already leased - } - if (!output->addLeaseObjects(objects)) { - leaseRequest->deny(); - return; - } - outputs << output; + for (DrmOutput *output : outputs) { + if (output->lease() || !output->addLeaseObjects(objects)) { + return nullptr; } } @@ -631,31 +607,16 @@ void DrmGpu::handleLeaseRequest(KWaylandServer::DrmLeaseV1Interface *leaseReques for (const auto &res : qAsConst(objects)) { qCWarning(KWIN_DRM) << res; } - leaseRequest->deny(); + return nullptr; } else { qCDebug(KWIN_DRM, "Created lease for %d resources:", objects.count()); for (const auto &res : qAsConst(objects)) { qCDebug(KWIN_DRM) << res; } - leaseRequest->grant(std::move(fd), lesseeId); - for (const auto &output : qAsConst(outputs)) { - output->leased(leaseRequest); - } + return std::make_unique(this, std::move(fd), lesseeId, outputs); } } -void DrmGpu::handleLeaseRevoked(KWaylandServer::DrmLeaseV1Interface *lease) -{ - const auto connectors = lease->connectors(); - for (KWaylandServer::DrmLeaseConnectorV1Interface *connector : connectors) { - if (DrmOutput *output = findOutput(connector->id())) { - output->leaseEnded(); - } - } - qCDebug(KWIN_DRM, "Revoking lease with leaseID %d", lease->lesseeId()); - drmModeRevokeLease(m_fd, lease->lesseeId()); -} - QVector DrmGpu::virtualOutputs() const { return m_virtualOutputs; @@ -817,4 +778,33 @@ void DrmGpu::recreateSurfaces() } } +DrmLease::DrmLease(DrmGpu *gpu, FileDescriptor &&fd, uint32_t lesseeId, const QVector &outputs) + : m_gpu(gpu) + , m_fd(std::move(fd)) + , m_lesseeId(lesseeId) + , m_outputs(outputs) +{ + for (const auto output : m_outputs) { + output->leased(this); + } +} + +DrmLease::~DrmLease() +{ + qCDebug(KWIN_DRM, "Revoking lease with leaseID %d", m_lesseeId); + drmModeRevokeLease(m_gpu->fd(), m_lesseeId); + for (const auto &output : m_outputs) { + output->leaseEnded(); + } +} + +FileDescriptor &DrmLease::fd() +{ + return m_fd; +} + +uint32_t DrmLease::lesseeId() const +{ + return m_lesseeId; +} } diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h index 0fd7fbef7e..6111e96a4c 100644 --- a/src/backends/drm/drm_gpu.h +++ b/src/backends/drm/drm_gpu.h @@ -9,6 +9,7 @@ #pragma once #include "drm_pipeline.h" +#include "utils/filedescriptor.h" #include #include @@ -21,12 +22,6 @@ struct gbm_device; -namespace KWaylandServer -{ -class DrmLeaseDeviceV1Interface; -class DrmLeaseV1Interface; -} - namespace KWin { @@ -41,6 +36,26 @@ class DrmAbstractOutput; class DrmRenderBackend; class DrmVirtualOutput; +class DrmLease : public QObject +{ + Q_OBJECT +public: + DrmLease(DrmGpu *gpu, FileDescriptor &&fd, uint32_t lesseeId, const QVector &outputs); + ~DrmLease(); + + FileDescriptor &fd(); + uint32_t lesseeId() const; + +Q_SIGNALS: + void revokeRequested(); + +private: + DrmGpu *const m_gpu; + FileDescriptor m_fd; + const uint32_t m_lesseeId; + const QVector m_outputs; +}; + class DrmGpu : public QObject { Q_OBJECT @@ -87,6 +102,9 @@ public: void releaseBuffers(); void recreateSurfaces(); + FileDescriptor createNonMasterFd() const; + std::unique_ptr leaseOutputs(const QVector &outputs); + Q_SIGNALS: void outputAdded(DrmAbstractOutput *output); void outputRemoved(DrmAbstractOutput *output); @@ -102,9 +120,6 @@ private: DrmPipeline::Error testPipelines(); QVector unusedObjects() const; - void handleLeaseRequest(KWaylandServer::DrmLeaseV1Interface *leaseRequest); - void handleLeaseRevoked(KWaylandServer::DrmLeaseV1Interface *lease); - static void pageFlipHandler(int fd, unsigned int sequence, unsigned int sec, unsigned int usec, unsigned int crtc_id, void *user_data); const int m_fd; @@ -128,7 +143,6 @@ private: QVector m_drmOutputs; QVector m_virtualOutputs; - std::unique_ptr m_leaseDevice; std::unique_ptr m_socketNotifier; QSize m_cursorSize; diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 2ba96678f4..5cabeb64f3 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -25,7 +25,6 @@ #include "drm_layer.h" #include "drm_logging.h" #include "kwinglutils.h" -#include "wayland/drmleasedevice_v1_interface.h" // Qt #include #include @@ -40,7 +39,7 @@ namespace KWin { -DrmOutput::DrmOutput(DrmPipeline *pipeline, KWaylandServer::DrmLeaseDeviceV1Interface *leaseDevice) +DrmOutput::DrmOutput(DrmPipeline *pipeline) : DrmAbstractOutput(pipeline->connector()->gpu()) , m_pipeline(pipeline) , m_connector(pipeline->connector()) @@ -95,13 +94,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline, KWaylandServer::DrmLeaseDeviceV1Inte setDrmDpmsMode(DpmsMode::Off); }); - if (conn->isNonDesktop()) { - m_offer = std::make_unique( - leaseDevice, - conn->id(), - conn->modelName(), - QStringLiteral("%1 %2").arg(conn->edid()->manufacturerString(), conn->modelName())); - } else { + if (!conn->isNonDesktop()) { connect(Cursors::self(), &Cursors::currentCursorChanged, this, &DrmOutput::updateCursor); connect(Cursors::self(), &Cursors::hiddenChanged, this, &DrmOutput::updateCursor); connect(Cursors::self(), &Cursors::positionChanged, this, &DrmOutput::moveCursor); @@ -115,7 +108,6 @@ DrmOutput::~DrmOutput() bool DrmOutput::addLeaseObjects(QVector &objectList) { - Q_ASSERT(m_offer); if (!m_pipeline->crtc()) { qCWarning(KWIN_DRM) << "Can't lease connector: No suitable crtc available"; return false; @@ -129,20 +121,18 @@ bool DrmOutput::addLeaseObjects(QVector &objectList) return true; } -void DrmOutput::leased(KWaylandServer::DrmLeaseV1Interface *lease) +void DrmOutput::leased(DrmLease *lease) { - Q_ASSERT(m_offer); m_lease = lease; } void DrmOutput::leaseEnded() { - Q_ASSERT(m_offer); qCDebug(KWIN_DRM) << "ended lease for connector" << m_pipeline->connector()->id(); m_lease = nullptr; } -KWaylandServer::DrmLeaseV1Interface *DrmOutput::lease() const +DrmLease *DrmOutput::lease() const { return m_lease; } diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index bd67ecd1d4..174358a40a 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -20,13 +20,6 @@ #include #include -namespace KWaylandServer -{ -class DrmLeaseConnectorV1Interface; -class DrmLeaseDeviceV1Interface; -class DrmLeaseV1Interface; -} - namespace KWin { @@ -36,12 +29,13 @@ class DrmPipeline; class DumbSwapchain; class GLTexture; class RenderTarget; +class DrmLease; class KWIN_EXPORT DrmOutput : public DrmAbstractOutput { Q_OBJECT public: - DrmOutput(DrmPipeline *pipeline, KWaylandServer::DrmLeaseDeviceV1Interface *leaseDevice); + DrmOutput(DrmPipeline *pipeline); ~DrmOutput() override; DrmConnector *connector() const; @@ -60,9 +54,9 @@ public: void updateCursor(); void moveCursor(); - KWaylandServer::DrmLeaseV1Interface *lease() const; + DrmLease *lease() const; bool addLeaseObjects(QVector &objectList); - void leased(KWaylandServer::DrmLeaseV1Interface *lease); + void leased(DrmLease *lease); void leaseEnded(); void setColorTransformation(const std::shared_ptr &transformation) override; @@ -84,8 +78,7 @@ private: bool m_cursorTextureDirty = true; std::unique_ptr m_cursorTexture; QTimer m_turnOffTimer; - std::unique_ptr m_offer; - KWaylandServer::DrmLeaseV1Interface *m_lease = nullptr; + DrmLease *m_lease = nullptr; }; } diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 6299a6c4b8..d590696d00 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -216,7 +216,7 @@ target_sources(kwin PRIVATE display.cpp dpms_interface.cpp drmclientbuffer.cpp - drmleasedevice_v1_interface.cpp + drmlease_v1_interface.cpp fakeinput_interface.cpp filtered_display.cpp idle_interface.cpp diff --git a/src/wayland/drmlease_v1_interface.cpp b/src/wayland/drmlease_v1_interface.cpp new file mode 100644 index 0000000000..4645a2049f --- /dev/null +++ b/src/wayland/drmlease_v1_interface.cpp @@ -0,0 +1,456 @@ +/* + SPDX-FileCopyrightText: 2021-2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#include "drmlease_v1_interface.h" +#include "display.h" +#include "drmlease_v1_interface_p.h" +#include "utils.h" +#include "utils/common.h" + +#include +#include + +namespace KWaylandServer +{ + +static const quint32 s_version = 1; + +DrmLeaseManagerV1::DrmLeaseManagerV1(KWin::DrmBackend *backend, Display *display, QObject *parent) + : QObject(parent) + , m_backend(backend) + , m_display(display) +{ + const auto &gpus = m_backend->gpus(); + for (const auto &gpu : gpus) { + addGpu(gpu.get()); + } + connect(m_backend, &KWin::DrmBackend::gpuAdded, this, &DrmLeaseManagerV1::addGpu); + connect(m_backend, &KWin::DrmBackend::gpuRemoved, this, &DrmLeaseManagerV1::removeGpu); + connect(m_backend, &KWin::DrmBackend::outputsQueried, this, &DrmLeaseManagerV1::handleOutputsQueried); + connect(m_backend, &KWin::DrmBackend::activeChanged, this, [this]() { + if (!m_backend->isActive()) { + for (const auto device : m_leaseDevices) { + device->setDrmMaster(false); + } + } + }); +} + +DrmLeaseManagerV1::~DrmLeaseManagerV1() +{ + for (const auto device : m_leaseDevices) { + device->remove(); + } +} + +void DrmLeaseManagerV1::addGpu(KWin::DrmGpu *gpu) +{ + m_leaseDevices[gpu] = new DrmLeaseDeviceV1Interface(m_display, gpu); +} + +void DrmLeaseManagerV1::removeGpu(KWin::DrmGpu *gpu) +{ + if (auto device = m_leaseDevices.take(gpu)) { + device->remove(); + } +} + +void DrmLeaseManagerV1::handleOutputsQueried() +{ + for (const auto device : m_leaseDevices) { + device->done(); + device->setDrmMaster(m_backend->isActive()); + } +} + +DrmLeaseDeviceV1Interface::DrmLeaseDeviceV1Interface(Display *display, KWin::DrmGpu *gpu) + : QtWaylandServer::wp_drm_lease_device_v1(*display, s_version) + , m_gpu(gpu) +{ + const auto outputs = gpu->drmOutputs(); + for (const auto output : outputs) { + addOutput(output); + } + connect(gpu, &KWin::DrmGpu::outputAdded, this, &DrmLeaseDeviceV1Interface::addOutput); + connect(gpu, &KWin::DrmGpu::outputRemoved, this, &DrmLeaseDeviceV1Interface::removeOutput); +} + +DrmLeaseDeviceV1Interface::~DrmLeaseDeviceV1Interface() +{ + for (auto it = m_connectors.begin(); it != m_connectors.end(); it++) { + removeOutput(it.key()); + } +} + +void DrmLeaseDeviceV1Interface::addOutput(KWin::DrmAbstractOutput *output) +{ + KWin::DrmOutput *drmOutput = qobject_cast(output); + if (!drmOutput || !drmOutput->isNonDesktop()) { + return; + } + auto connector = new DrmLeaseConnectorV1Interface(this, drmOutput); + m_connectors[drmOutput] = connector; + + if (m_hasDrmMaster) { + offerConnector(connector); + } +} + +void DrmLeaseDeviceV1Interface::removeOutput(KWin::DrmAbstractOutput *output) +{ + const auto it = m_connectors.find(output); + if (it != m_connectors.end()) { + DrmLeaseConnectorV1Interface *connector = *it; + connector->withdraw(); + for (const auto &lease : qAsConst(m_leases)) { + if (lease->connectors().contains(connector)) { + lease->connectors().removeOne(connector); + lease->revoke(); + } + } + for (const auto &leaseRequest : qAsConst(m_leaseRequests)) { + if (leaseRequest->connectors().contains(connector)) { + leaseRequest->invalidate(); + } + } + m_connectors.erase(it); + } +} + +void DrmLeaseDeviceV1Interface::setDrmMaster(bool hasDrmMaster) +{ + if (hasDrmMaster == m_hasDrmMaster) { + return; + } + if (hasDrmMaster) { + // send pending drm fds + while (!m_pendingFds.isEmpty()) { + KWin::FileDescriptor fd = m_gpu->createNonMasterFd(); + send_drm_fd(m_pendingFds.dequeue(), fd.get()); + } + // offer all connectors again + for (const auto connector : qAsConst(m_connectors)) { + offerConnector(connector); + } + } else { + // withdraw all connectors + for (const auto connector : qAsConst(m_connectors)) { + connector->withdraw(); + } + // and revoke all leases + for (const auto &lease : qAsConst(m_leases)) { + lease->revoke(); + } + } + m_hasDrmMaster = hasDrmMaster; + done(); +} + +void DrmLeaseDeviceV1Interface::done() +{ + const auto resources = resourceMap(); + for (const auto resource : resources) { + send_done(resource->handle); + } +} + +void DrmLeaseDeviceV1Interface::remove() +{ + for (const auto &lease : qAsConst(m_leases)) { + lease->deny(); + } + for (const auto connector : qAsConst(m_connectors)) { + connector->withdraw(); + } + for (const auto &request : qAsConst(m_leaseRequests)) { + request->invalidate(); + } + done(); + globalRemove(); +} + +void DrmLeaseDeviceV1Interface::addLeaseRequest(DrmLeaseRequestV1Interface *leaseRequest) +{ + m_leaseRequests.push_back(leaseRequest); +} + +void DrmLeaseDeviceV1Interface::removeLeaseRequest(DrmLeaseRequestV1Interface *leaseRequest) +{ + m_leaseRequests.removeOne(leaseRequest); +} + +void DrmLeaseDeviceV1Interface::addLease(DrmLeaseV1Interface *lease) +{ + m_leases.push_back(lease); +} + +void DrmLeaseDeviceV1Interface::removeLease(DrmLeaseV1Interface *lease) +{ + m_leases.removeOne(lease); +} + +bool DrmLeaseDeviceV1Interface::hasDrmMaster() const +{ + return m_hasDrmMaster; +} + +KWin::DrmGpu *DrmLeaseDeviceV1Interface::gpu() const +{ + return m_gpu; +} + +void DrmLeaseDeviceV1Interface::offerConnector(DrmLeaseConnectorV1Interface *connector) +{ + for (const auto &resource : resourceMap()) { + auto connectorResource = connector->add(resource->client(), 0, resource->version()); + send_connector(resource->handle, connectorResource->handle); + connector->send(connectorResource->handle); + } +} + +void DrmLeaseDeviceV1Interface::wp_drm_lease_device_v1_create_lease_request(Resource *resource, uint32_t id) +{ + wl_resource *requestResource = wl_resource_create(resource->client(), &wp_drm_lease_request_v1_interface, + resource->version(), id); + if (!requestResource) { + wl_resource_post_no_memory(resource->handle); + return; + } + m_leaseRequests << new DrmLeaseRequestV1Interface(this, requestResource); +} + +void DrmLeaseDeviceV1Interface::wp_drm_lease_device_v1_release(Resource *resource) +{ + send_released(resource->handle); + wl_resource_destroy(resource->handle); +} + +void DrmLeaseDeviceV1Interface::wp_drm_lease_device_v1_bind_resource(Resource *resource) +{ + if (isGlobalRemoved()) { + return; + } + if (!m_hasDrmMaster) { + m_pendingFds << resource->handle; + return; + } + KWin::FileDescriptor fd = m_gpu->createNonMasterFd(); + send_drm_fd(resource->handle, fd.get()); + for (const auto connector : qAsConst(m_connectors)) { + if (!connector->withdrawn()) { + auto connectorResource = connector->add(resource->client(), 0, s_version); + send_connector(resource->handle, connectorResource->handle); + connector->send(connectorResource->handle); + } + } + send_done(resource->handle); +} + +void DrmLeaseDeviceV1Interface::wp_drm_lease_device_v1_destroy_global() +{ + delete this; +} + +DrmLeaseConnectorV1Interface::DrmLeaseConnectorV1Interface(DrmLeaseDeviceV1Interface *leaseDevice, KWin::DrmOutput *output) + : wp_drm_lease_connector_v1() + , m_device(leaseDevice) + , m_output(output) +{ +} + +uint32_t DrmLeaseConnectorV1Interface::id() const +{ + return m_output->connector()->id(); +} + +DrmLeaseDeviceV1Interface *DrmLeaseConnectorV1Interface::device() const +{ + return m_device; +} + +KWin::DrmOutput *DrmLeaseConnectorV1Interface::output() const +{ + return m_output; +} + +bool DrmLeaseConnectorV1Interface::withdrawn() const +{ + return m_withdrawn; +} + +void DrmLeaseConnectorV1Interface::send(wl_resource *resource) +{ + m_withdrawn = false; + send_connector_id(resource, m_output->connector()->id()); + send_name(resource, m_output->name()); + send_description(resource, m_output->description()); + send_done(resource); +} + +void DrmLeaseConnectorV1Interface::withdraw() +{ + if (!m_withdrawn) { + m_withdrawn = true; + for (const auto &resource : resourceMap()) { + send_withdrawn(resource->handle); + } + } +} + +void DrmLeaseConnectorV1Interface::wp_drm_lease_connector_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +DrmLeaseRequestV1Interface::DrmLeaseRequestV1Interface(DrmLeaseDeviceV1Interface *device, wl_resource *resource) + : wp_drm_lease_request_v1(resource) + , m_device(device) +{ +} + +DrmLeaseRequestV1Interface::~DrmLeaseRequestV1Interface() +{ + m_device->removeLeaseRequest(this); +} + +QVector DrmLeaseRequestV1Interface::connectors() const +{ + return m_connectors; +} + +void DrmLeaseRequestV1Interface::invalidate() +{ + m_connectors.clear(); + m_invalid = true; +} + +void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_request_connector(Resource *resource, struct ::wl_resource *connector_handle) +{ + Q_UNUSED(resource); + if (auto connector = resource_cast(connector_handle)) { + if (connector->device() != m_device) { + wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE, "Requested connector from invalid lease device"); + } else if (connector->withdrawn()) { + qCWarning(KWIN_CORE) << "DrmLease: withdrawn connector requested"; + } else if (m_connectors.contains(connector)) { + wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Requested connector twice"); + } else { + m_connectors << connector; + } + } else { + qCWarning(KWIN_CORE, "DrmLease: Invalid connector requested"); + } +} + +void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_submit(Resource *resource, uint32_t id) +{ + wl_resource *leaseResource = wl_resource_create(resource->client(), &wp_drm_lease_v1_interface, s_version, id); + if (!leaseResource) { + wl_resource_post_no_memory(resource->handle); + return; + } + DrmLeaseV1Interface *lease = new DrmLeaseV1Interface(m_device, m_connectors, leaseResource); + m_device->addLease(lease); + if (!m_device->hasDrmMaster()) { + qCWarning(KWIN_CORE) << "DrmLease: rejecting lease request without drm master"; + lease->deny(); + } else if (m_invalid) { + qCWarning(KWIN_CORE) << "DrmLease: rejecting lease request with a withdrawn connector"; + lease->deny(); + } else if (m_connectors.isEmpty()) { + wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "Requested lease without connectors"); + } else { + QVector outputs; + for (const auto &connector : m_connectors) { + outputs.push_back(connector->output()); + } + auto drmLease = m_device->gpu()->leaseOutputs(outputs); + if (drmLease) { + lease->grant(std::move(drmLease)); + } else { + lease->deny(); + } + } + wl_resource_destroy(resource->handle); +} + +void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +DrmLeaseV1Interface::DrmLeaseV1Interface(DrmLeaseDeviceV1Interface *device, const QVector &connectors, wl_resource *resource) + : wp_drm_lease_v1(resource) + , m_device(device) + , m_connectors(connectors) +{ +} + +DrmLeaseV1Interface::~DrmLeaseV1Interface() +{ + if (m_lease) { + revoke(); + } else { + deny(); + } + m_device->removeLease(this); +} + +void DrmLeaseV1Interface::grant(std::unique_ptr &&lease) +{ + KWin::FileDescriptor tmp = std::move(lease->fd()); + send_lease_fd(tmp.get()); + m_lease = std::move(lease); + connect(lease.get(), &KWin::DrmLease::revokeRequested, this, &DrmLeaseV1Interface::revoke); + for (const auto &connector : qAsConst(m_connectors)) { + connector->withdraw(); + } + m_device->done(); +} + +void DrmLeaseV1Interface::deny() +{ + Q_ASSERT(!m_lease); + if (!m_finished) { + m_finished = true; + send_finished(); + } +} + +void DrmLeaseV1Interface::revoke() +{ + Q_ASSERT(m_lease); + if (!m_finished) { + m_finished = true; + send_finished(); + } + m_lease.reset(); + // check if we should offer connectors again + if (m_device->hasDrmMaster()) { + for (const auto &connector : qAsConst(m_connectors)) { + m_device->offerConnector(connector); + } + m_device->done(); + } +} + +void DrmLeaseV1Interface::wp_drm_lease_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void DrmLeaseV1Interface::wp_drm_lease_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete this; +} + +QVector DrmLeaseV1Interface::connectors() const +{ + return m_connectors; +} + +} diff --git a/src/wayland/drmlease_v1_interface.h b/src/wayland/drmlease_v1_interface.h new file mode 100644 index 0000000000..82560d15e7 --- /dev/null +++ b/src/wayland/drmlease_v1_interface.h @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2021-2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL + */ +#pragma once + +#include +#include +#include +#include + +namespace KWin +{ +class DrmBackend; +class DrmGpu; +} + +namespace KWaylandServer +{ + +class DrmLeaseDeviceV1Interface; +class DrmLeaseConnectorV1Interface; +class Display; + +class DrmLeaseManagerV1 : public QObject +{ + Q_OBJECT +public: + DrmLeaseManagerV1(KWin::DrmBackend *backend, Display *display, QObject *parent = nullptr); + ~DrmLeaseManagerV1(); + +private: + void addGpu(KWin::DrmGpu *gpu); + void removeGpu(KWin::DrmGpu *gpu); + void handleOutputsQueried(); + + KWin::DrmBackend *const m_backend; + Display *const m_display; + QHash m_leaseDevices; +}; +} diff --git a/src/wayland/drmlease_v1_interface_p.h b/src/wayland/drmlease_v1_interface_p.h new file mode 100644 index 0000000000..343eb0652c --- /dev/null +++ b/src/wayland/drmlease_v1_interface_p.h @@ -0,0 +1,127 @@ +/* + SPDX-FileCopyrightText: 2021-2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#pragma once + +#include + +#include "backends/drm/drm_backend.h" +#include "backends/drm/drm_connector.h" +#include "backends/drm/drm_gpu.h" +#include "backends/drm/drm_output.h" +#include "utils/filedescriptor.h" + +#include +#include +#include + +namespace KWaylandServer +{ + +class Display; +class DrmLeaseConnectorV1Interface; +class DrmLeaseRequestV1Interface; +class DrmLeaseV1Interface; +class DrmLeaseConnectorV1InterfacePrivate; + +class DrmLeaseDeviceV1Interface : public QObject, public QtWaylandServer::wp_drm_lease_device_v1 +{ +public: + explicit DrmLeaseDeviceV1Interface(Display *display, KWin::DrmGpu *gpu); + ~DrmLeaseDeviceV1Interface(); + + void addOutput(KWin::DrmAbstractOutput *output); + void removeOutput(KWin::DrmAbstractOutput *output); + void setDrmMaster(bool hasDrmMaster); + void done(); + void remove(); + void addLeaseRequest(DrmLeaseRequestV1Interface *leaseRequest); + void removeLeaseRequest(DrmLeaseRequestV1Interface *leaseRequest); + void addLease(DrmLeaseV1Interface *lease); + void removeLease(DrmLeaseV1Interface *lease); + void offerConnector(DrmLeaseConnectorV1Interface *connector); + + bool hasDrmMaster() const; + KWin::DrmGpu *gpu() const; + +private: + void wp_drm_lease_device_v1_create_lease_request(Resource *resource, uint32_t id) override; + void wp_drm_lease_device_v1_release(Resource *resource) override; + void wp_drm_lease_device_v1_bind_resource(Resource *resource) override; + void wp_drm_lease_device_v1_destroy_global() override; + + KWin::DrmGpu *const m_gpu; + bool m_hasDrmMaster = true; + QHash m_connectors; + QQueue m_pendingFds; + QVector m_leaseRequests; + QVector m_leases; +}; + +class DrmLeaseConnectorV1Interface : public QObject, public QtWaylandServer::wp_drm_lease_connector_v1 +{ + Q_OBJECT +public: + explicit DrmLeaseConnectorV1Interface(DrmLeaseDeviceV1Interface *leaseDevice, KWin::DrmOutput *output); + + uint32_t id() const; + void send(wl_resource *resource); + void withdraw(); + + DrmLeaseDeviceV1Interface *device() const; + KWin::DrmOutput *output() const; + bool withdrawn() const; + +private: + void wp_drm_lease_connector_v1_destroy(Resource *resource) override; + + QPointer m_device; + bool m_withdrawn = false; + KWin::DrmOutput *const m_output; +}; + +class DrmLeaseRequestV1Interface : public QtWaylandServer::wp_drm_lease_request_v1 +{ +public: + DrmLeaseRequestV1Interface(DrmLeaseDeviceV1Interface *device, wl_resource *resource); + ~DrmLeaseRequestV1Interface(); + + QVector connectors() const; + void invalidate(); + +protected: + void wp_drm_lease_request_v1_request_connector(Resource *resource, struct ::wl_resource *connector) override; + void wp_drm_lease_request_v1_submit(Resource *resource, uint32_t id) override; + void wp_drm_lease_request_v1_destroy_resource(Resource *resource) override; + + DrmLeaseDeviceV1Interface *const m_device; + QVector m_connectors; + bool m_invalid = false; +}; + +class DrmLeaseV1Interface : public QObject, private QtWaylandServer::wp_drm_lease_v1 +{ + Q_OBJECT +public: + DrmLeaseV1Interface(DrmLeaseDeviceV1Interface *device, const QVector &connectors, wl_resource *resource); + ~DrmLeaseV1Interface(); + + void grant(std::unique_ptr &&lease); + void deny(); + void revoke(); + + QVector connectors() const; + +private: + DrmLeaseDeviceV1Interface *m_device; + QVector m_connectors; + std::unique_ptr m_lease; + bool m_finished = false; + + void wp_drm_lease_v1_destroy(Resource *resource) override; + void wp_drm_lease_v1_destroy_resource(Resource *resource) override; +}; + +} diff --git a/src/wayland/drmleasedevice_v1_interface.cpp b/src/wayland/drmleasedevice_v1_interface.cpp deleted file mode 100644 index 85682f4c32..0000000000 --- a/src/wayland/drmleasedevice_v1_interface.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Xaver Hugl - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ - -#include "drmleasedevice_v1_interface.h" -#include "display.h" -#include "drmleasedevice_v1_interface_p.h" -#include "utils.h" -#include "utils/common.h" - -#include -#include - -namespace KWaylandServer -{ - -static const quint32 s_version = 1; - -DrmLeaseDeviceV1Interface::DrmLeaseDeviceV1Interface(Display *display, std::function createNonMasterFd) - : d(new DrmLeaseDeviceV1InterfacePrivate(display, this, createNonMasterFd)) -{ -} - -DrmLeaseDeviceV1Interface::~DrmLeaseDeviceV1Interface() -{ - d->remove(); -} - -void DrmLeaseDeviceV1Interface::setDrmMaster(bool hasDrmMaster) -{ - if (hasDrmMaster == d->hasDrmMaster) { - return; - } - if (hasDrmMaster) { - // send pending drm fds - while (!d->pendingFds.isEmpty()) { - KWin::FileDescriptor fd = d->createNonMasterFd(); - d->send_drm_fd(d->pendingFds.dequeue(), fd.get()); - } - // offer all connectors again - for (const auto &connector : qAsConst(d->connectors)) { - auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector); - connectorPrivate->withdrawn = false; - for (const auto &resource : d->resourceMap()) { - auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version); - d->send_connector(resource->handle, connectorResource->handle); - connectorPrivate->send(connectorResource->handle); - } - } - } else { - // withdraw all connectors - for (const auto &connector : qAsConst(d->connectors)) { - DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw(); - } - // and revoke all leases - for (const auto &lease : qAsConst(d->leases)) { - lease->deny(); - } - } - d->hasDrmMaster = hasDrmMaster; - done(); -} - -void DrmLeaseDeviceV1Interface::done() -{ - const auto resources = d->resourceMap(); - for (const auto resource : resources) { - d->send_done(resource->handle); - } -} - -DrmLeaseDeviceV1InterfacePrivate::DrmLeaseDeviceV1InterfacePrivate(Display *display, DrmLeaseDeviceV1Interface *device, std::function createNonMasterFd) - : QtWaylandServer::wp_drm_lease_device_v1(*display, s_version) - , q(device) - , createNonMasterFd(createNonMasterFd) -{ -} - -DrmLeaseDeviceV1InterfacePrivate::~DrmLeaseDeviceV1InterfacePrivate() -{ -} - -void DrmLeaseDeviceV1InterfacePrivate::remove() -{ - for (const auto &lease : qAsConst(leases)) { - lease->deny(); - } - for (const auto &connector : qAsConst(connectors)) { - DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw(); - } - for (const auto &request : qAsConst(leaseRequests)) { - request->connectors.clear(); - } - q->done(); - globalRemove(); -} - -void DrmLeaseDeviceV1InterfacePrivate::registerConnector(DrmLeaseConnectorV1Interface *connector) -{ - connectors << connector; - if (!hasDrmMaster) { - return; - } - for (const auto &resource : resourceMap()) { - auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector); - auto connectorResource = connectorPrivate->add(resource->client(), 0, resource->version()); - send_connector(resource->handle, connectorResource->handle); - connectorPrivate->send(connectorResource->handle); - } -} - -void DrmLeaseDeviceV1InterfacePrivate::unregisterConnector(DrmLeaseConnectorV1Interface *connector) -{ - connectors.removeOne(connector); - for (const auto &lease : qAsConst(leases)) { - if (lease->d->connectors.contains(connector)) { - lease->d->connectors.removeOne(connector); - lease->deny(); - } - } - for (const auto &leaseRequest : qAsConst(leaseRequests)) { - if (leaseRequest->connectors.removeOne(connector)) { - leaseRequest->invalid = true; - } - } -} - -DrmLeaseDeviceV1InterfacePrivate *DrmLeaseDeviceV1InterfacePrivate::get(DrmLeaseDeviceV1Interface *device) -{ - return device->d; -} - -void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_create_lease_request(Resource *resource, uint32_t id) -{ - wl_resource *requestResource = wl_resource_create(resource->client(), &wp_drm_lease_request_v1_interface, - resource->version(), id); - if (!requestResource) { - wl_resource_post_no_memory(resource->handle); - return; - } - leaseRequests << new DrmLeaseRequestV1Interface(this, requestResource); -} - -void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_release(Resource *resource) -{ - send_released(resource->handle); - wl_resource_destroy(resource->handle); -} - -void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_bind_resource(Resource *resource) -{ - if (isGlobalRemoved()) { - return; - } - if (!hasDrmMaster) { - pendingFds << resource->handle; - return; - } - KWin::FileDescriptor fd = createNonMasterFd(); - send_drm_fd(resource->handle, fd.get()); - for (const auto &connector : qAsConst(connectors)) { - auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector); - if (!connectorPrivate->withdrawn) { - auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version); - send_connector(resource->handle, connectorResource->handle); - connectorPrivate->send(connectorResource->handle); - } - } - send_done(resource->handle); -} - -void DrmLeaseDeviceV1InterfacePrivate::wp_drm_lease_device_v1_destroy_global() -{ - delete this; -} - -DrmLeaseConnectorV1Interface::DrmLeaseConnectorV1Interface(DrmLeaseDeviceV1Interface *leaseDevice, - uint32_t id, - const QString &name, - const QString &description) - : d(new DrmLeaseConnectorV1InterfacePrivate(leaseDevice, this, id, name, description)) -{ - DrmLeaseDeviceV1InterfacePrivate::get(leaseDevice)->registerConnector(this); -} - -DrmLeaseConnectorV1Interface::~DrmLeaseConnectorV1Interface() -{ - d->withdraw(); - if (d->device) { - auto devicePrivate = DrmLeaseDeviceV1InterfacePrivate::get(d->device); - devicePrivate->unregisterConnector(this); - } -} - -uint32_t DrmLeaseConnectorV1Interface::id() const -{ - return d->connectorId; -} - -DrmLeaseConnectorV1Interface *DrmLeaseConnectorV1Interface::get(wl_resource *resource) -{ - if (auto connectorPrivate = resource_cast(resource)) { - return connectorPrivate->q; - } - return nullptr; -} - -DrmLeaseConnectorV1InterfacePrivate::DrmLeaseConnectorV1InterfacePrivate(DrmLeaseDeviceV1Interface *device, - DrmLeaseConnectorV1Interface *connector, - uint32_t connectorId, - const QString &name, - const QString &description) - : wp_drm_lease_connector_v1() - , q(connector) - , device(device) - , connectorId(connectorId) - , name(name) - , description(description) -{ -} - -DrmLeaseConnectorV1InterfacePrivate::~DrmLeaseConnectorV1InterfacePrivate() -{ -} - -void DrmLeaseConnectorV1InterfacePrivate::send(wl_resource *resource) -{ - send_connector_id(resource, connectorId); - send_name(resource, name); - send_description(resource, description); - send_done(resource); -} - -void DrmLeaseConnectorV1InterfacePrivate::withdraw() -{ - if (!withdrawn) { - withdrawn = true; - for (const auto &resource : resourceMap()) { - send_withdrawn(resource->handle); - } - } -} - -DrmLeaseConnectorV1InterfacePrivate *DrmLeaseConnectorV1InterfacePrivate::get(DrmLeaseConnectorV1Interface *connector) -{ - return connector->d.get(); -} - -void DrmLeaseConnectorV1InterfacePrivate::wp_drm_lease_connector_v1_destroy(Resource *resource) -{ - wl_resource_destroy(resource->handle); -} - -DrmLeaseRequestV1Interface::DrmLeaseRequestV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource) - : wp_drm_lease_request_v1(resource) - , device(device) -{ -} - -DrmLeaseRequestV1Interface::~DrmLeaseRequestV1Interface() -{ - device->leaseRequests.removeOne(this); -} - -void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_request_connector(Resource *resource, struct ::wl_resource *connector_handle) -{ - Q_UNUSED(resource); - if (auto connector = DrmLeaseConnectorV1Interface::get(connector_handle)) { - auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector); - if (connectorPrivate->device != device->q) { - wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE, "Requested connector from invalid lease device"); - } else if (connectorPrivate->withdrawn) { - qCWarning(KWIN_CORE) << "DrmLease: withdrawn connector requested"; - } else if (connectors.contains(connector)) { - wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Requested connector twice"); - } else { - connectors << connector; - } - } else { - qCWarning(KWIN_CORE, "DrmLease: Invalid connector requested"); - } -} - -void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_submit(Resource *resource, uint32_t id) -{ - wl_resource *leaseResource = wl_resource_create(resource->client(), &wp_drm_lease_v1_interface, s_version, id); - if (!leaseResource) { - wl_resource_post_no_memory(resource->handle); - return; - } - DrmLeaseV1Interface *lease = new DrmLeaseV1Interface(device, leaseResource); - device->leases << lease; - if (!device->hasDrmMaster) { - qCWarning(KWIN_CORE) << "DrmLease: rejecting lease request without drm master"; - lease->deny(); - } else if (invalid) { - qCWarning(KWIN_CORE) << "DrmLease: rejecting lease request with a withdrawn connector"; - lease->deny(); - } else if (connectors.isEmpty()) { - wl_resource_post_error(resource->handle, WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "Requested lease without connectors"); - } else { - lease->d->connectors = connectors; - Q_EMIT device->q->leaseRequested(lease); - } - wl_resource_destroy(resource->handle); -} - -void DrmLeaseRequestV1Interface::wp_drm_lease_request_v1_destroy_resource(Resource *resource) -{ - Q_UNUSED(resource) - delete this; -} - -DrmLeaseV1Interface::DrmLeaseV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource) - : d(new DrmLeaseV1InterfacePrivate(device, this, resource)) -{ -} - -DrmLeaseV1Interface::~DrmLeaseV1Interface() -{ - if (d->lesseeId) { - revoke(); - } else { - deny(); - } - - d->device->leases.removeOne(this); -} - -void DrmLeaseV1Interface::grant(KWin::FileDescriptor &&leaseFd, uint32_t lesseeId) -{ - KWin::FileDescriptor tmp = std::move(leaseFd); - d->send_lease_fd(tmp.get()); - d->lesseeId = lesseeId; - for (const auto &connector : qAsConst(d->connectors)) { - DrmLeaseConnectorV1InterfacePrivate::get(connector)->withdraw(); - } - d->device->q->done(); -} - -void DrmLeaseV1Interface::deny() -{ - if (!d->finished) { - d->finished = true; - d->send_finished(); - } -} - -void DrmLeaseV1Interface::revoke() -{ - Q_ASSERT(d->lesseeId != 0); - if (!d->finished) { - d->finished = true; - d->send_finished(); - } - Q_EMIT d->device->q->leaseRevoked(this); - // check if we should offer connectors again - if (d->device->hasDrmMaster) { - bool sent = false; - for (const auto &connector : qAsConst(d->connectors)) { - auto connectorPrivate = DrmLeaseConnectorV1InterfacePrivate::get(connector); - connectorPrivate->withdrawn = false; - for (const auto &resource : d->device->resourceMap()) { - auto connectorResource = connectorPrivate->add(resource->client(), 0, s_version); - d->device->send_connector(resource->handle, connectorResource->handle); - connectorPrivate->send(connectorResource->handle); - sent = true; - } - } - if (sent) { - d->device->q->done(); - } - } - d->lesseeId = 0; -} - -uint32_t DrmLeaseV1Interface::lesseeId() const -{ - return d->lesseeId; -} - -QVector DrmLeaseV1Interface::connectors() const -{ - return d->connectors; -} - -DrmLeaseV1InterfacePrivate::DrmLeaseV1InterfacePrivate(DrmLeaseDeviceV1InterfacePrivate *device, DrmLeaseV1Interface *q, wl_resource *resource) - : wp_drm_lease_v1(resource) - , device(device) - , q(q) -{ -} - -void DrmLeaseV1InterfacePrivate::wp_drm_lease_v1_destroy(Resource *resource) -{ - wl_resource_destroy(resource->handle); -} - -void DrmLeaseV1InterfacePrivate::wp_drm_lease_v1_destroy_resource(Resource *resource) -{ - Q_UNUSED(resource) - delete q; -} - -} diff --git a/src/wayland/drmleasedevice_v1_interface.h b/src/wayland/drmleasedevice_v1_interface.h deleted file mode 100644 index ae2f1db8df..0000000000 --- a/src/wayland/drmleasedevice_v1_interface.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Xaver Hugl - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ - -#pragma once - -#include "kwin_export.h" -#include "utils/filedescriptor.h" - -#include -#include - -struct wl_resource; - -namespace KWaylandServer -{ - -class Display; -class DrmLeaseDeviceV1InterfacePrivate; -class DrmLeaseV1Interface; -class DrmLeaseV1InterfacePrivate; -class DrmLeaseRequestV1Interface; -class DrmLeaseConnectorV1InterfacePrivate; - -/** - * The DrmLeaseV1DeviceInterface allows the wayland compositor to offer unused - * drm connectors for lease by clients. The main use for this is VR headsets - */ -class KWIN_EXPORT DrmLeaseDeviceV1Interface : public QObject -{ - Q_OBJECT -public: - /** - * @param createNonMasterFd a function that creates non-master drm file descriptors for - * this device that clients can use to enumerate connectors and their properties - */ - explicit DrmLeaseDeviceV1Interface(Display *display, std::function createNonMasterFd); - ~DrmLeaseDeviceV1Interface() override; - - /** - * Must be called by the compositor when it loses or gains drm master - */ - void setDrmMaster(bool hasDrmMaster); - - /** - * Must be called after connectors have been added or removed - */ - void done(); - -Q_SIGNALS: - /** - * Emitted when a lease is requested. The compositor needs to either - * grant or deny the lease when receiving this signal - */ - void leaseRequested(DrmLeaseV1Interface *leaseRequest); - - /** - * Emitted when a granted lease gets revoked - */ - void leaseRevoked(DrmLeaseV1Interface *lease); - -private: - friend class DrmLeaseDeviceV1InterfacePrivate; - DrmLeaseDeviceV1InterfacePrivate *d; -}; - -/** - * Represents a lease offer from the compositor. Creating the DrmLeaseConnectorV1Interface - * will allow clients to requests a lease for the connector, deleting it will result in the - * offer and possibly an active lease being revoked - */ -class KWIN_EXPORT DrmLeaseConnectorV1Interface : public QObject -{ - Q_OBJECT -public: - explicit DrmLeaseConnectorV1Interface(DrmLeaseDeviceV1Interface *leaseDevice, uint32_t id, const QString &name, const QString &description); - ~DrmLeaseConnectorV1Interface() override; - - uint32_t id() const; - - static DrmLeaseConnectorV1Interface *get(wl_resource *resource); - -private: - friend class DrmLeaseConnectorV1InterfacePrivate; - std::unique_ptr d; -}; - -/** - * Represents a lease request or active lease - */ -class KWIN_EXPORT DrmLeaseV1Interface : public QObject -{ - Q_OBJECT -public: - /** - * Grant the client requesting the lease access to DRM resources needed to - * drive the outputs corresponding to the requested connectors. - * Must only be called once in response to DrmLeaseDeviceV1Interface::leaseRequested - */ - void grant(KWin::FileDescriptor &&leaseFd, uint32_t lesseeId); - - /** - * Deny the lease request. The compositor may call this in response to - * DrmLeaseDeviceV1Interface::leaseRequested - */ - void deny(); - - /** - * revoke a granted lease request and offer the leased connectors again - */ - void revoke(); - - /** - * The connectors this lease (request) encompasses - */ - QVector connectors() const; - - /** - * The lesseeId passed to DrmLeaseV1Interface::grant, or 0 if this lease was not granted - */ - uint32_t lesseeId() const; - -private: - DrmLeaseV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource); - ~DrmLeaseV1Interface(); - - friend class DrmLeaseDeviceV1InterfacePrivate; - friend class DrmLeaseRequestV1Interface; - friend class DrmLeaseV1InterfacePrivate; - std::unique_ptr d; -}; - -} diff --git a/src/wayland/drmleasedevice_v1_interface_p.h b/src/wayland/drmleasedevice_v1_interface_p.h deleted file mode 100644 index 1b28e37217..0000000000 --- a/src/wayland/drmleasedevice_v1_interface_p.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - SPDX-FileCopyrightText: 2021 Xaver Hugl - - SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL -*/ - -#pragma once - -#include "utils/filedescriptor.h" -#include - -#include -#include -#include - -namespace KWaylandServer -{ - -class Display; -class DrmLeaseConnectorV1Interface; -class DrmLeaseRequestV1Interface; -class DrmLeaseV1Interface; - -class DrmLeaseDeviceV1InterfacePrivate : public QtWaylandServer::wp_drm_lease_device_v1 -{ -public: - DrmLeaseDeviceV1InterfacePrivate(Display *display, DrmLeaseDeviceV1Interface *device, std::function createNonMasterFd); - ~DrmLeaseDeviceV1InterfacePrivate(); - void remove(); - - void registerConnector(DrmLeaseConnectorV1Interface *connector); - void unregisterConnector(DrmLeaseConnectorV1Interface *connector); - - static DrmLeaseDeviceV1InterfacePrivate *get(DrmLeaseDeviceV1Interface *device); - - DrmLeaseDeviceV1Interface *q; - QVector connectors; - QVector leaseRequests; - QVector leases; - QQueue pendingFds; - std::function createNonMasterFd; - bool hasDrmMaster = true; - bool removed = false; - -protected: - void wp_drm_lease_device_v1_create_lease_request(Resource *resource, uint32_t id) override; - void wp_drm_lease_device_v1_release(Resource *resource) override; - void wp_drm_lease_device_v1_bind_resource(Resource *resource) override; - void wp_drm_lease_device_v1_destroy_global() override; -}; - -class DrmLeaseConnectorV1InterfacePrivate : public QObject, public QtWaylandServer::wp_drm_lease_connector_v1 -{ - Q_OBJECT -public: - DrmLeaseConnectorV1InterfacePrivate(DrmLeaseDeviceV1Interface *device, DrmLeaseConnectorV1Interface *connector, - uint32_t connectorId, const QString &name, const QString &description); - ~DrmLeaseConnectorV1InterfacePrivate(); - - void send(wl_resource *resource); - void withdraw(); - - static DrmLeaseConnectorV1InterfacePrivate *get(DrmLeaseConnectorV1Interface *connector); - - DrmLeaseConnectorV1Interface *q; - QPointer device; - uint32_t connectorId; - QString name; - QString description; - bool withdrawn = false; - -protected: - void wp_drm_lease_connector_v1_destroy(Resource *resource) override; -}; - -class DrmLeaseRequestV1Interface : public QtWaylandServer::wp_drm_lease_request_v1 -{ -public: - DrmLeaseRequestV1Interface(DrmLeaseDeviceV1InterfacePrivate *device, wl_resource *resource); - ~DrmLeaseRequestV1Interface(); - - DrmLeaseDeviceV1InterfacePrivate *device; - QVector connectors; - bool invalid = false; - -protected: - void wp_drm_lease_request_v1_request_connector(Resource *resource, struct ::wl_resource *connector) override; - void wp_drm_lease_request_v1_submit(Resource *resource, uint32_t id) override; - void wp_drm_lease_request_v1_destroy_resource(Resource *resource) override; -}; - -class DrmLeaseV1InterfacePrivate : public QtWaylandServer::wp_drm_lease_v1 -{ -public: - DrmLeaseV1InterfacePrivate(DrmLeaseDeviceV1InterfacePrivate *device, DrmLeaseV1Interface *q, wl_resource *resource); - - DrmLeaseDeviceV1InterfacePrivate *device; - DrmLeaseV1Interface *q; - QVector connectors; - uint32_t lesseeId = 0; - bool finished = false; - -protected: - void wp_drm_lease_v1_destroy(Resource *resource) override; - void wp_drm_lease_v1_destroy_resource(Resource *resource) override; -}; - -} diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index e741b0887f..3f65b37ecc 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -10,6 +10,7 @@ #include +#include "backends/drm/drm_backend.h" #include "composite.h" #include "core/output.h" #include "core/platform.h" @@ -31,6 +32,7 @@ #include "wayland/datasource_interface.h" #include "wayland/display.h" #include "wayland/dpms_interface.h" +#include "wayland/drmlease_v1_interface.h" #include "wayland/filtered_display.h" #include "wayland/idle_interface.h" #include "wayland/idleinhibit_v1_interface.h" @@ -563,6 +565,11 @@ void WaylandServer::initWorkspace() if (hasScreenLockerIntegration()) { initScreenLocker(); } + + if (auto backend = qobject_cast(kwinApp()->platform())) { + m_leaseManager = new KWaylandServer::DrmLeaseManagerV1(backend, m_display, m_display); + } + Q_EMIT initialized(); } diff --git a/src/wayland_server.h b/src/wayland_server.h index 6bd3957e64..c838cc67cf 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -50,6 +50,7 @@ class KeyboardShortcutsInhibitManagerV1Interface; class XdgDecorationManagerV1Interface; class XWaylandKeyboardGrabManagerV1Interface; class ContentTypeManagerV1Interface; +class DrmLeaseManagerV1; } namespace KWin @@ -293,6 +294,7 @@ private: InitializationFlags m_initFlags; QHash m_waylandOutputs; QHash m_waylandOutputDevices; + KWaylandServer::DrmLeaseManagerV1 *m_leaseManager = nullptr; KWIN_SINGLETON(WaylandServer) };