backends/drm: remove Wayland bits for drm leasing

This commit is contained in:
Xaver Hugl 2022-10-11 18:42:19 +02:00
parent fcaf0cad9e
commit 49ad013295
15 changed files with 734 additions and 751 deletions

View file

@ -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<DrmGpu> 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<std::unique_ptr<DrmGpu>> &DrmBackend::gpus() const
{
return m_gpus;
}
}

View file

@ -75,12 +75,16 @@ public:
void releaseBuffers();
void updateOutputs();
const std::vector<std::unique_ptr<DrmGpu>> &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;

View file

@ -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 <algorithm>
#include <errno.h>
@ -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<KWaylandServer::DrmLeaseDeviceV1Interface>(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<DrmLease> DrmGpu::leaseOutputs(const QVector<DrmOutput *> &outputs)
{
QVector<uint32_t> objects;
QVector<DrmOutput *> 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<DrmLease>(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<DrmVirtualOutput *> DrmGpu::virtualOutputs() const
{
return m_virtualOutputs;
@ -817,4 +778,33 @@ void DrmGpu::recreateSurfaces()
}
}
DrmLease::DrmLease(DrmGpu *gpu, FileDescriptor &&fd, uint32_t lesseeId, const QVector<DrmOutput *> &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;
}
}

View file

@ -9,6 +9,7 @@
#pragma once
#include "drm_pipeline.h"
#include "utils/filedescriptor.h"
#include <QPointer>
#include <QSize>
@ -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<DrmOutput *> &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<DrmOutput *> m_outputs;
};
class DrmGpu : public QObject
{
Q_OBJECT
@ -87,6 +102,9 @@ public:
void releaseBuffers();
void recreateSurfaces();
FileDescriptor createNonMasterFd() const;
std::unique_ptr<DrmLease> leaseOutputs(const QVector<DrmOutput *> &outputs);
Q_SIGNALS:
void outputAdded(DrmAbstractOutput *output);
void outputRemoved(DrmAbstractOutput *output);
@ -102,9 +120,6 @@ private:
DrmPipeline::Error testPipelines();
QVector<DrmObject *> 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<DrmOutput *> m_drmOutputs;
QVector<DrmVirtualOutput *> m_virtualOutputs;
std::unique_ptr<KWaylandServer::DrmLeaseDeviceV1Interface> m_leaseDevice;
std::unique_ptr<QSocketNotifier> m_socketNotifier;
QSize m_cursorSize;

View file

@ -25,7 +25,6 @@
#include "drm_layer.h"
#include "drm_logging.h"
#include "kwinglutils.h"
#include "wayland/drmleasedevice_v1_interface.h"
// Qt
#include <QCryptographicHash>
#include <QMatrix4x4>
@ -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<KWaylandServer::DrmLeaseConnectorV1Interface>(
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<uint32_t> &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<uint32_t> &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;
}

View file

@ -20,13 +20,6 @@
#include <chrono>
#include <xf86drmMode.h>
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<uint32_t> &objectList);
void leased(KWaylandServer::DrmLeaseV1Interface *lease);
void leased(DrmLease *lease);
void leaseEnded();
void setColorTransformation(const std::shared_ptr<ColorTransformation> &transformation) override;
@ -84,8 +78,7 @@ private:
bool m_cursorTextureDirty = true;
std::unique_ptr<GLTexture> m_cursorTexture;
QTimer m_turnOffTimer;
std::unique_ptr<KWaylandServer::DrmLeaseConnectorV1Interface> m_offer;
KWaylandServer::DrmLeaseV1Interface *m_lease = nullptr;
DrmLease *m_lease = nullptr;
};
}

View file

@ -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

View file

@ -0,0 +1,456 @@
/*
SPDX-FileCopyrightText: 2021-2022 Xaver Hugl <xaver.hugl@gmail.com>
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 <fcntl.h>
#include <unistd.h>
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<KWin::DrmOutput *>(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<DrmLeaseConnectorV1Interface *> 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<DrmLeaseConnectorV1Interface *>(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<KWin::DrmOutput *> 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<DrmLeaseConnectorV1Interface *> &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<KWin::DrmLease> &&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<DrmLeaseConnectorV1Interface *> DrmLeaseV1Interface::connectors() const
{
return m_connectors;
}
}

View file

@ -0,0 +1,42 @@
/*
SPDX-FileCopyrightText: 2021-2022 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <QHash>
#include <QObject>
#include <map>
#include <memory>
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<KWin::DrmGpu *, DrmLeaseDeviceV1Interface *> m_leaseDevices;
};
}

View file

@ -0,0 +1,127 @@
/*
SPDX-FileCopyrightText: 2021-2022 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <qwayland-server-drm-lease-v1.h>
#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 <QObject>
#include <QPointer>
#include <QQueue>
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<KWin::DrmAbstractOutput *, DrmLeaseConnectorV1Interface *> m_connectors;
QQueue<wl_resource *> m_pendingFds;
QVector<DrmLeaseRequestV1Interface *> m_leaseRequests;
QVector<DrmLeaseV1Interface *> 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<DrmLeaseDeviceV1Interface> 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<DrmLeaseConnectorV1Interface *> 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<DrmLeaseConnectorV1Interface *> m_connectors;
bool m_invalid = false;
};
class DrmLeaseV1Interface : public QObject, private QtWaylandServer::wp_drm_lease_v1
{
Q_OBJECT
public:
DrmLeaseV1Interface(DrmLeaseDeviceV1Interface *device, const QVector<DrmLeaseConnectorV1Interface *> &connectors, wl_resource *resource);
~DrmLeaseV1Interface();
void grant(std::unique_ptr<KWin::DrmLease> &&lease);
void deny();
void revoke();
QVector<DrmLeaseConnectorV1Interface *> connectors() const;
private:
DrmLeaseDeviceV1Interface *m_device;
QVector<DrmLeaseConnectorV1Interface *> m_connectors;
std::unique_ptr<KWin::DrmLease> 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;
};
}

View file

@ -1,407 +0,0 @@
/*
SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
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 <fcntl.h>
#include <unistd.h>
namespace KWaylandServer
{
static const quint32 s_version = 1;
DrmLeaseDeviceV1Interface::DrmLeaseDeviceV1Interface(Display *display, std::function<KWin::FileDescriptor()> 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<KWin::FileDescriptor()> 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<DrmLeaseConnectorV1InterfacePrivate *>(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<DrmLeaseConnectorV1Interface *> 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;
}
}

View file

@ -1,135 +0,0 @@
/*
SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
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 <QObject>
#include <QPointer>
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<KWin::FileDescriptor()> 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<DrmLeaseConnectorV1InterfacePrivate> 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<DrmLeaseConnectorV1Interface *> 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<DrmLeaseV1InterfacePrivate> d;
};
}

View file

@ -1,108 +0,0 @@
/*
SPDX-FileCopyrightText: 2021 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include "utils/filedescriptor.h"
#include <qwayland-server-drm-lease-v1.h>
#include <QObject>
#include <QPointer>
#include <QQueue>
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<KWin::FileDescriptor()> createNonMasterFd);
~DrmLeaseDeviceV1InterfacePrivate();
void remove();
void registerConnector(DrmLeaseConnectorV1Interface *connector);
void unregisterConnector(DrmLeaseConnectorV1Interface *connector);
static DrmLeaseDeviceV1InterfacePrivate *get(DrmLeaseDeviceV1Interface *device);
DrmLeaseDeviceV1Interface *q;
QVector<DrmLeaseConnectorV1Interface *> connectors;
QVector<DrmLeaseRequestV1Interface *> leaseRequests;
QVector<DrmLeaseV1Interface *> leases;
QQueue<wl_resource *> pendingFds;
std::function<KWin::FileDescriptor()> 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<DrmLeaseDeviceV1Interface> 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<DrmLeaseConnectorV1Interface *> 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<DrmLeaseConnectorV1Interface *> 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;
};
}

View file

@ -10,6 +10,7 @@
#include <config-kwin.h>
#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<DrmBackend *>(kwinApp()->platform())) {
m_leaseManager = new KWaylandServer::DrmLeaseManagerV1(backend, m_display, m_display);
}
Q_EMIT initialized();
}

View file

@ -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<Output *, KWaylandServer::OutputInterface *> m_waylandOutputs;
QHash<Output *, KWaylandServer::OutputDeviceV2Interface *> m_waylandOutputDevices;
KWaylandServer::DrmLeaseManagerV1 *m_leaseManager = nullptr;
KWIN_SINGLETON(WaylandServer)
};