Commit 0cd45369 authored by Xaver Hugl's avatar Xaver Hugl
Browse files

backends/drm: split out layers for lease outputs and remove DrmDisplayDevice

parent aac7f50d
......@@ -13,7 +13,6 @@ set(DRM_SOURCES
drm_gpu.cpp
dumb_swapchain.cpp
shadowbuffer.cpp
drm_display_device.cpp
drm_layer.cpp
drm_pipeline.cpp
drm_pipeline_legacy.cpp
......@@ -28,6 +27,7 @@ set(DRM_SOURCES
gbm_dmabuf.cpp
placeholderinputeventfilter.cpp
virtual_egl_gbm_layer.cpp
drm_lease_egl_gbm_layer.cpp
)
add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES})
......
......@@ -16,8 +16,8 @@ namespace KWin
DrmAbstractOutput::DrmAbstractOutput(DrmGpu *gpu)
: AbstractWaylandOutput(gpu->platform())
, DrmDisplayDevice(gpu)
, m_renderLoop(new RenderLoop(this))
, m_gpu(gpu)
{
}
......@@ -26,11 +26,6 @@ RenderLoop *DrmAbstractOutput::renderLoop() const
return m_renderLoop;
}
QRect DrmAbstractOutput::renderGeometry() const
{
return geometry();
}
void DrmAbstractOutput::frameFailed() const
{
RenderLoopPrivate::get(m_renderLoop)->notifyFrameFailed();
......@@ -57,4 +52,9 @@ QVector<int32_t> DrmAbstractOutput::regionToRects(const QRegion &region) const
return rects;
}
DrmGpu *DrmAbstractOutput::gpu() const
{
return m_gpu;
}
}
......@@ -9,29 +9,34 @@
#pragma once
#include "abstract_wayland_output.h"
#include "drm_display_device.h"
namespace KWin
{
class DrmBackend;
class DrmGpu;
class DrmOutputLayer;
class DrmAbstractOutput : public AbstractWaylandOutput, public DrmDisplayDevice
class DrmAbstractOutput : public AbstractWaylandOutput
{
Q_OBJECT
public:
DrmAbstractOutput(DrmGpu *gpu);
RenderLoop *renderLoop() const override;
QRect renderGeometry() const override;
void frameFailed() const override;
void pageFlipped(std::chrono::nanoseconds timestamp) const override;
QVector<int32_t> regionToRects(const QRegion &region) const override;
void frameFailed() const;
void pageFlipped(std::chrono::nanoseconds timestamp) const;
QVector<int32_t> regionToRects(const QRegion &region) const;
DrmGpu *gpu() const;
virtual bool present() = 0;
virtual DrmOutputLayer *outputLayer() const = 0;
protected:
friend class DrmGpu;
RenderLoop *m_renderLoop;
DrmGpu *const m_gpu;
};
}
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QRegion>
#include "drm_object_plane.h"
namespace KWin
{
class DrmBuffer;
class DrmGpu;
class DrmOutputLayer;
class DrmDisplayDevice
{
public:
DrmDisplayDevice(DrmGpu *gpu);
virtual ~DrmDisplayDevice() = default;
DrmGpu *gpu() const;
virtual bool present() = 0;
virtual void frameFailed() const = 0;
virtual void pageFlipped(std::chrono::nanoseconds timestamp) const = 0;
virtual QRect renderGeometry() const = 0;
virtual DrmOutputLayer *outputLayer() const = 0;
virtual QVector<int32_t> regionToRects(const QRegion &region) const = 0;
protected:
DrmGpu *const m_gpu;
};
}
......@@ -309,9 +309,9 @@ bool DrmGpu::updateOutputs()
if (testPendingConfiguration()) {
for (const auto &pipeline : qAsConst(m_pipelines)) {
pipeline->applyPendingChanges();
if (const auto drmOutput = dynamic_cast<DrmAbstractOutput*>(pipeline->displayDevice()); drmOutput && !pipeline->pending.crtc) {
if (pipeline->output() && !pipeline->pending.crtc) {
pipeline->pending.enabled = false;
drmOutput->setEnabled(false);
pipeline->output()->setEnabled(false);
}
}
} else {
......@@ -740,7 +740,7 @@ bool DrmGpu::maybeModeset()
if (pipeline->modesetPresentPending()) {
pipeline->resetModesetPresentPending();
if (!ok) {
pipeline->displayDevice()->frameFailed();
pipeline->output()->frameFailed();
}
}
}
......
......@@ -8,7 +8,6 @@
*/
#include "drm_layer.h"
#include "drm_pipeline.h"
#include "drm_display_device.h"
#include <QMatrix4x4>
......@@ -22,11 +21,43 @@ void DrmOutputLayer::aboutToStartPainting(const QRegion &damagedRegion)
Q_UNUSED(damagedRegion)
}
bool DrmOutputLayer::scanout(SurfaceItem *surfaceItem)
{
Q_UNUSED(surfaceItem)
return false;
}
std::optional<QRegion> DrmOutputLayer::startRendering()
{
return {};
}
bool DrmOutputLayer::endRendering(const QRegion &damagedRegion)
{
Q_UNUSED(damagedRegion)
return false;
}
QRegion DrmOutputLayer::currentDamage() const
{
return {};
}
QSharedPointer<GLTexture> DrmOutputLayer::texture() const
{
return nullptr;
}
DrmPipelineLayer::DrmPipelineLayer(DrmPipeline *pipeline)
: m_pipeline(pipeline)
{
}
bool DrmPipelineLayer::hasDirectScanoutBuffer() const
{
return false;
}
}
#include "drm_layer.moc"
......@@ -28,19 +28,19 @@ public:
virtual ~DrmOutputLayer();
virtual void aboutToStartPainting(const QRegion &damagedRegion);
virtual std::optional<QRegion> startRendering() = 0;
virtual bool endRendering(const QRegion &damagedRegion) = 0;
virtual std::optional<QRegion> startRendering();
virtual bool endRendering(const QRegion &damagedRegion);
/**
* attempts to directly scan out the current buffer of the surfaceItem
* @returns true if scanout was successful
* false if rendering is required
*/
virtual bool scanout(SurfaceItem *surfaceItem) = 0;
virtual bool scanout(SurfaceItem *surfaceItem);
virtual QSharedPointer<GLTexture> texture() const = 0;
virtual QSharedPointer<GLTexture> texture() const;
virtual QRegion currentDamage() const = 0;
virtual QRegion currentDamage() const;
};
class DrmPipelineLayer : public DrmOutputLayer
......@@ -55,7 +55,7 @@ public:
virtual QSharedPointer<DrmBuffer> testBuffer() = 0;
virtual QSharedPointer<DrmBuffer> currentBuffer() const = 0;
virtual bool hasDirectScanoutBuffer() const = 0;
virtual bool hasDirectScanoutBuffer() const;
protected:
DrmPipeline *const m_pipeline;
......
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "drm_lease_egl_gbm_layer.h"
#include "drm_buffer_gbm.h"
#include "egl_gbm_backend.h"
#include "drm_pipeline.h"
#include "drm_gpu.h"
#include "logging.h"
#include <drm_fourcc.h>
#include <gbm.h>
namespace KWin
{
DrmLeaseEglGbmLayer::DrmLeaseEglGbmLayer(EglGbmBackend *backend, DrmPipeline *pipeline)
: DrmPipelineLayer(pipeline)
{
connect(backend, &EglGbmBackend::aboutToBeDestroyed, this, [this]() {
m_buffer.reset();
});
}
QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::testBuffer()
{
const auto mods = m_pipeline->supportedModifiers(DRM_FORMAT_XRGB8888);
const auto size = m_pipeline->sourceSize();
if (!m_buffer || m_buffer->size() != size || !(mods.isEmpty() || mods.contains(m_buffer->modifier()))) {
gbm_bo *newBo;
if (mods.isEmpty()) {
newBo = gbm_bo_create(m_pipeline->gpu()->gbmDevice(), size.width(), size.height(), DRM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT);
} else {
QVector<uint64_t> modifiers;
modifiers.reserve(mods.count());
for (const auto &mod : mods) {
modifiers << mod;
}
newBo = gbm_bo_create_with_modifiers(m_pipeline->gpu()->gbmDevice(), size.width(), size.height(), DRM_FORMAT_XRGB8888, modifiers.constData(), mods.count());
}
if (newBo) {
m_buffer = QSharedPointer<DrmGbmBuffer>::create(m_pipeline->gpu(), nullptr, newBo);
} else {
qCWarning(KWIN_DRM) << "Failed to create gbm_bo for lease output";
}
}
return m_buffer;
}
QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::currentBuffer() const
{
return m_buffer;
}
}
......@@ -6,19 +6,26 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "drm_display_device.h"
#pragma once
#include "drm_layer.h"
#include <QSharedPointer>
namespace KWin
{
DrmDisplayDevice::DrmDisplayDevice(DrmGpu *gpu)
: m_gpu(gpu)
{
}
class EglGbmBackend;
DrmGpu *DrmDisplayDevice::gpu() const
class DrmLeaseEglGbmLayer : public DrmPipelineLayer
{
return m_gpu;
}
public:
DrmLeaseEglGbmLayer(EglGbmBackend *backend, DrmPipeline *pipeline);
QSharedPointer<DrmBuffer> testBuffer() override;
QSharedPointer<DrmBuffer> currentBuffer() const override;
private:
QSharedPointer<DrmBuffer> m_buffer;
};
}
......@@ -30,16 +30,13 @@ DrmLeaseOutput::DrmLeaseOutput(DrmPipeline *pipeline, KWaylandServer::DrmLeaseDe
pipeline->connector()->modelName(),
QStringLiteral("%1 %2").arg(pipeline->connector()->edid()->manufacturerString(), pipeline->connector()->modelName())
)
, DrmDisplayDevice(pipeline->gpu())
, m_pipeline(pipeline)
{
m_pipeline->setDisplayDevice(this);
qCDebug(KWIN_DRM) << "offering connector" << m_pipeline->connector()->id() << "for lease";
}
DrmLeaseOutput::~DrmLeaseOutput()
{
m_pipeline->setDisplayDevice(nullptr);
qCDebug(KWIN_DRM) << "revoking lease offer for connector" << m_pipeline->connector()->id();
}
......@@ -79,34 +76,4 @@ DrmPipeline *DrmLeaseOutput::pipeline() const
return m_pipeline;
}
bool DrmLeaseOutput::present()
{
return false;
}
QRect DrmLeaseOutput::renderGeometry() const
{
return QRect(QPoint(), m_pipeline->sourceSize());
}
DrmOutputLayer *DrmLeaseOutput::outputLayer() const
{
return m_pipeline->pending.layer.data();
}
void DrmLeaseOutput::frameFailed() const
{
}
void DrmLeaseOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
{
Q_UNUSED(timestamp)
}
QVector<int32_t> DrmLeaseOutput::regionToRects(const QRegion &region) const
{
Q_UNUSED(region)
return {};
}
}
......@@ -13,8 +13,6 @@
#include <QVector>
#include <KWaylandServer/drmleasedevice_v1_interface.h>
#include "drm_display_device.h"
namespace KWin
{
......@@ -26,7 +24,7 @@ class DrmPipeline;
* that is not used directly by the compositor but is instead leased out to
* applications (usually VR compositors) that drive the output themselves
*/
class DrmLeaseOutput : public KWaylandServer::DrmLeaseConnectorV1Interface, public DrmDisplayDevice
class DrmLeaseOutput : public KWaylandServer::DrmLeaseConnectorV1Interface
{
Q_OBJECT
public:
......@@ -40,13 +38,6 @@ public:
KWaylandServer::DrmLeaseV1Interface *lease() const;
DrmPipeline *pipeline() const;
bool present() override;
QRect renderGeometry() const override;
DrmOutputLayer *outputLayer() const override;
void frameFailed() const override;
void pageFlipped(std::chrono::nanoseconds timestamp) const override;
QVector<int32_t> regionToRects(const QRegion &region) const override;
private:
DrmPipeline *m_pipeline;
KWaylandServer::DrmLeaseV1Interface *m_lease = nullptr;
......
......@@ -377,8 +377,8 @@ bool DrmConnector::updateProperties()
if (!m_pipeline->pending.mode) {
m_pipeline->pending.mode = m_modes.constFirst();
}
if (const auto output = dynamic_cast<DrmOutput*>(m_pipeline->displayDevice())) {
output->updateModes();
if (m_pipeline->output()) {
m_pipeline->output()->updateModes();
}
}
}
......
......@@ -46,7 +46,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
, m_pipeline(pipeline)
, m_connector(pipeline->connector())
{
m_pipeline->setDisplayDevice(this);
m_pipeline->setOutput(this);
const auto conn = m_pipeline->connector();
m_renderLoop->setRefreshRate(m_pipeline->pending.mode->refreshRate());
setSubPixelInternal(conn->subpixel());
......@@ -79,7 +79,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
DrmOutput::~DrmOutput()
{
m_pipeline->setDisplayDevice(nullptr);
m_pipeline->setOutput(nullptr);
}
static bool isCursorSpriteCompatible(const QImage *buffer, const QImage *sprite)
......
......@@ -32,8 +32,7 @@ namespace KWin
{
DrmPipeline::DrmPipeline(DrmConnector *conn)
: m_displayDevice(nullptr)
, m_connector(conn)
: m_connector(conn)
{
}
......@@ -309,8 +308,8 @@ bool DrmPipeline::setCursor(const QSharedPointer<DrmDumbBuffer> &buffer, const Q
}
if (result) {
m_next = pending;
if (const auto drmOutput = dynamic_cast<DrmOutput*>(m_displayDevice); drmOutput && (visibleBefore || isCursorVisible())) {
drmOutput->renderLoop()->scheduleRepaint();
if (m_output && (visibleBefore || isCursorVisible())) {
m_output->renderLoop()->scheduleRepaint();
}
} else {
pending = m_next;
......@@ -334,8 +333,8 @@ bool DrmPipeline::moveCursor(QPoint pos)
}
if (result) {
m_next = pending;
if (const auto drmOutput = dynamic_cast<DrmOutput*>(m_displayDevice); drmOutput && (visibleBefore || isCursorVisible())) {
drmOutput->renderLoop()->scheduleRepaint();
if (m_output && (visibleBefore || isCursorVisible())) {
m_output->renderLoop()->scheduleRepaint();
}
} else {
pending = m_next;
......@@ -395,12 +394,19 @@ void DrmPipeline::pageFlipped(std::chrono::nanoseconds timestamp)
m_current.crtc->cursorPlane()->flipBuffer();
}
m_pageflipPending = false;
m_displayDevice->pageFlipped(timestamp);
if (m_output) {
m_output->pageFlipped(timestamp);
}
}
void DrmPipeline::setOutput(DrmOutput *output)
{
m_output = output;
}
void DrmPipeline::setDisplayDevice(DrmDisplayDevice *device)
DrmOutput *DrmPipeline::output() const
{
m_displayDevice = device;
return m_output;
}
static const QMap<uint32_t, QVector<uint64_t>> legacyFormats = {
......@@ -483,11 +489,6 @@ DrmCrtc *DrmPipeline::currentCrtc() const
return m_current.crtc;
}
DrmDisplayDevice *DrmPipeline::displayDevice() const
{
return m_displayDevice;
}
DrmGammaRamp::DrmGammaRamp(DrmGpu *gpu, const GammaRamp &lut)
: m_gpu(gpu)
, m_lut(lut)
......
......@@ -32,7 +32,6 @@ class DrmDumbBuffer;
class GammaRamp;
class DrmConnectorMode;
class DrmPipelineLayer;
class DrmDisplayDevice;
class DrmGammaRamp
{
......@@ -94,8 +93,8 @@ public:
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const;
QMap<uint32_t, QVector<uint64_t>> supportedFormats() const;
void setDisplayDevice(DrmDisplayDevice *device);
DrmDisplayDevice *displayDevice() const;
void setOutput(DrmOutput *output);
DrmOutput *output() const;
struct State {
DrmCrtc *crtc = nullptr;
......@@ -154,7 +153,7 @@ private:
static void printFlags(uint32_t flags);
static void printProps(DrmObject *object, PrintMode mode);
DrmDisplayDevice *m_displayDevice = nullptr;
DrmOutput *m_output = nullptr;
DrmConnector *m_connector = nullptr;
bool m_pageflipPending = false;
......
......@@ -15,16 +15,17 @@
#include "drm_backend.h"
#include "drm_pipeline.h"
#include "drm_virtual_output.h"
#include "drm_output.h"
#include <drm_fourcc.h>
namespace KWin
{
DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline)
DrmQPainterLayer::DrmQPainterLayer(DrmQPainterBackend *backend, DrmPipeline *pipeline)
: DrmPipelineLayer(pipeline)
{
connect(static_cast<DrmQPainterBackend*>(pipeline->gpu()->platform()->renderBackend()), &DrmQPainterBackend::aboutToBeDestroyed, this, [this]() {
connect(backend, &DrmQPainterBackend::aboutToBeDestroyed, this, [this]() {
m_swapchain.reset();
});
}
......@@ -35,7 +36,7 @@ std::optional<QRegion> DrmQPainterLayer::startRendering()
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->sourceSize(), DRM_FORMAT_XRGB8888);
}
QRegion needsRepaint;
if (!m_swapchain->acquireBuffer(m_pipeline->displayDevice()->renderGeometry(), &needsRepaint)) {
if (!m_swapchain->acquireBuffer(m_pipeline->output()->geometry(), &needsRepaint)) {
return std::optional<QRegion>();
}
return needsRepaint;
......@@ -48,12 +49,6 @@ bool DrmQPainterLayer::endRendering(const QRegion &damagedRegion)
return true;
}
bool DrmQPainterLayer::scanout(SurfaceItem *surfaceItem)
{
Q_UNUSED(surfaceItem);
return false;
}
QSharedPointer<DrmBuffer> DrmQPainterLayer::testBuffer()
{
if (!doesSwapchainFit()) {
......@@ -77,16 +72,6 @@ QRegion DrmQPainterLayer::currentDamage() const
return m_currentDamage;
}
bool DrmQPainterLayer::hasDirectScanoutBuffer() const
{
return false;
}
QSharedPointer<GLTexture> DrmQPainterLayer::texture() const
{
return nullptr;
}
QImage *DrmQPainterLayer::image()
{
return m_swapchain ? m_swapchain->currentBuffer()->image() : nullptr;
......@@ -112,25 +97,37 @@ bool DrmVirtualQPainterLayer::endRendering(const QRegion &damagedRegion)
return true;
}
bool DrmVirtualQPainterLayer::scanout(SurfaceItem *surfaceItem)
QRegion DrmVirtualQPainterLayer::currentDamage() const
{
return m_currentDamage;
}