backends/drm: remove some unnecessary redirection
This commit is contained in:
parent
0ba5916fe6
commit
aac7f50d8b
29 changed files with 572 additions and 362 deletions
|
@ -27,6 +27,7 @@ set(DRM_SOURCES
|
|||
gbm_surface.cpp
|
||||
gbm_dmabuf.cpp
|
||||
placeholderinputeventfilter.cpp
|
||||
virtual_egl_gbm_layer.cpp
|
||||
)
|
||||
|
||||
add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES})
|
||||
|
|
|
@ -41,4 +41,20 @@ void DrmAbstractOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
|
|||
RenderLoopPrivate::get(m_renderLoop)->notifyFrameCompleted(timestamp);
|
||||
}
|
||||
|
||||
QVector<int32_t> DrmAbstractOutput::regionToRects(const QRegion ®ion) const
|
||||
{
|
||||
const int height = pixelSize().height();
|
||||
const QMatrix4x4 matrix = AbstractWaylandOutput::logicalToNativeMatrix(geometry(), scale(), transform());
|
||||
QVector<EGLint> rects;
|
||||
rects.reserve(region.rectCount() * 4);
|
||||
for (const QRect &_rect : region) {
|
||||
const QRect rect = matrix.mapRect(_rect);
|
||||
rects << rect.left();
|
||||
rects << height - (rect.y() + rect.height());
|
||||
rects << rect.width();
|
||||
rects << rect.height();
|
||||
}
|
||||
return rects;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
QRect renderGeometry() const override;
|
||||
void frameFailed() const override;
|
||||
void pageFlipped(std::chrono::nanoseconds timestamp) const override;
|
||||
QVector<int32_t> regionToRects(const QRegion ®ion) const override;
|
||||
|
||||
protected:
|
||||
friend class DrmGpu;
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <gbm.h>
|
||||
#include <drm_fourcc.h>
|
||||
// KWaylandServer
|
||||
#include "KWaylandServer/clientbuffer.h"
|
||||
#include <drm_fourcc.h>
|
||||
#include "KWaylandServer/linuxdmabufv1clientbuffer.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -31,17 +32,42 @@ namespace KWin
|
|||
GbmBuffer::GbmBuffer(GbmSurface *surface, gbm_bo *bo)
|
||||
: m_surface(surface)
|
||||
, m_bo(bo)
|
||||
{
|
||||
m_stride = gbm_bo_get_stride(m_bo);
|
||||
}
|
||||
|
||||
GbmBuffer::GbmBuffer(gbm_bo *buffer, KWaylandServer::ClientBuffer *clientBuffer)
|
||||
: m_bo(buffer)
|
||||
, m_clientBuffer(clientBuffer)
|
||||
, m_stride(gbm_bo_get_stride(m_bo))
|
||||
{
|
||||
if (m_clientBuffer) {
|
||||
m_clientBuffer->ref();
|
||||
}
|
||||
|
||||
GbmBuffer::GbmBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer)
|
||||
: m_clientBuffer(clientBuffer)
|
||||
{
|
||||
clientBuffer->ref();
|
||||
const auto planes = clientBuffer->planes();
|
||||
if (planes.first().modifier != DRM_FORMAT_MOD_INVALID || planes.first().offset > 0 || planes.count() > 1) {
|
||||
gbm_import_fd_modifier_data data = {};
|
||||
data.format = clientBuffer->format();
|
||||
data.width = (uint32_t) clientBuffer->size().width();
|
||||
data.height = (uint32_t) clientBuffer->size().height();
|
||||
data.num_fds = planes.count();
|
||||
data.modifier = planes.first().modifier;
|
||||
for (int i = 0; i < planes.count(); i++) {
|
||||
data.fds[i] = planes[i].fd;
|
||||
data.offsets[i] = planes[i].offset;
|
||||
data.strides[i] = planes[i].stride;
|
||||
}
|
||||
m_bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
} else {
|
||||
const auto &plane = planes.first();
|
||||
gbm_import_fd_data data = {};
|
||||
data.fd = plane.fd;
|
||||
data.width = (uint32_t) clientBuffer->size().width();
|
||||
data.height = (uint32_t) clientBuffer->size().height();
|
||||
data.stride = plane.stride;
|
||||
data.format = clientBuffer->format();
|
||||
m_bo = gbm_bo_import(gpu->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT);
|
||||
}
|
||||
if (m_bo) {
|
||||
m_stride = gbm_bo_get_stride(m_bo);
|
||||
} else if (errno != EINVAL) {
|
||||
qCWarning(KWIN_DRM) << "Importing buffer for direct scanout failed:" << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,13 +131,15 @@ uint32_t GbmBuffer::stride() const
|
|||
|
||||
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, GbmSurface *surface, gbm_bo *bo)
|
||||
: DrmBuffer(gpu, gbm_bo_get_format(bo), gbm_bo_get_modifier(bo)), GbmBuffer(surface, bo)
|
||||
: DrmBuffer(gpu, gbm_bo_get_format(bo), gbm_bo_get_modifier(bo))
|
||||
, GbmBuffer(surface, bo)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::ClientBuffer *clientBuffer)
|
||||
: DrmBuffer(gpu, gbm_bo_get_format(buffer), gbm_bo_get_modifier(buffer)), GbmBuffer(buffer, clientBuffer)
|
||||
DrmGbmBuffer::DrmGbmBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer)
|
||||
: DrmBuffer(gpu, clientBuffer->format(), clientBuffer->planes().constFirst().modifier)
|
||||
, GbmBuffer(gpu, clientBuffer)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
@ -127,6 +155,9 @@ DrmGbmBuffer::~DrmGbmBuffer()
|
|||
|
||||
void DrmGbmBuffer::initialize()
|
||||
{
|
||||
if (!m_bo) {
|
||||
return;
|
||||
}
|
||||
m_size = QSize(gbm_bo_get_width(m_bo), gbm_bo_get_height(m_bo));
|
||||
uint32_t handles[4] = { };
|
||||
uint32_t strides[4] = { };
|
||||
|
|
|
@ -19,6 +19,7 @@ struct gbm_bo;
|
|||
namespace KWaylandServer
|
||||
{
|
||||
class ClientBuffer;
|
||||
class LinuxDmaBufV1ClientBuffer;
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
|
@ -31,7 +32,7 @@ class GbmBuffer : public QObject
|
|||
Q_OBJECT
|
||||
public:
|
||||
GbmBuffer(GbmSurface *surface, gbm_bo *bo);
|
||||
GbmBuffer(gbm_bo *buffer, KWaylandServer::ClientBuffer *clientBuffer);
|
||||
GbmBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer);
|
||||
virtual ~GbmBuffer();
|
||||
|
||||
void releaseBuffer();
|
||||
|
@ -56,7 +57,7 @@ class DrmGbmBuffer : public DrmBuffer, public GbmBuffer
|
|||
{
|
||||
public:
|
||||
DrmGbmBuffer(DrmGpu *gpu, GbmSurface *surface, gbm_bo *bo);
|
||||
DrmGbmBuffer(DrmGpu *gpu, gbm_bo *buffer, KWaylandServer::ClientBuffer *clientBuffer);
|
||||
DrmGbmBuffer(DrmGpu *gpu, KWaylandServer::LinuxDmaBufV1ClientBuffer *clientBuffer);
|
||||
~DrmGbmBuffer() override;
|
||||
|
||||
bool needsModeChange(DrmBuffer *b) const override;
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace KWin
|
|||
|
||||
class DrmBuffer;
|
||||
class DrmGpu;
|
||||
class DrmLayer;
|
||||
class DrmOutputLayer;
|
||||
|
||||
class DrmDisplayDevice
|
||||
{
|
||||
|
@ -28,18 +28,11 @@ public:
|
|||
DrmGpu *gpu() const;
|
||||
|
||||
virtual bool present() = 0;
|
||||
virtual bool testScanout() = 0;
|
||||
virtual void frameFailed() const = 0;
|
||||
virtual void pageFlipped(std::chrono::nanoseconds timestamp) const = 0;
|
||||
|
||||
virtual DrmPlane::Transformations softwareTransforms() const = 0;
|
||||
virtual QSize bufferSize() const = 0;
|
||||
virtual QSize sourceSize() const = 0;
|
||||
virtual bool isFormatSupported(uint32_t drmFormat) const = 0;
|
||||
virtual QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const = 0;
|
||||
virtual int maxBpc() const = 0;
|
||||
virtual QRect renderGeometry() const = 0;
|
||||
virtual DrmLayer *outputLayer() const = 0;
|
||||
virtual DrmOutputLayer *outputLayer() const = 0;
|
||||
virtual QVector<int32_t> regionToRects(const QRegion ®ion) const = 0;
|
||||
|
||||
protected:
|
||||
DrmGpu *const m_gpu;
|
||||
|
|
|
@ -422,7 +422,7 @@ bool DrmGpu::testPipelines()
|
|||
QVector<DrmPipeline*> inactivePipelines;
|
||||
for (const auto &pipeline : qAsConst(m_pipelines)) {
|
||||
if (!pipeline->pending.layer) {
|
||||
pipeline->pending.layer = m_platform->renderBackend()->createLayer(pipeline->displayDevice());
|
||||
pipeline->pending.layer = m_platform->renderBackend()->createDrmPipelineLayer(pipeline);
|
||||
}
|
||||
if (!pipeline->pending.active) {
|
||||
pipeline->pending.active = true;
|
||||
|
@ -772,7 +772,7 @@ QSize DrmGpu::cursorSize() const
|
|||
void DrmGpu::recreateSurfaces()
|
||||
{
|
||||
for (const auto &pipeline : qAsConst(m_pipelines)) {
|
||||
pipeline->pending.layer = m_platform->renderBackend()->createLayer(pipeline->displayDevice());
|
||||
pipeline->pending.layer = m_platform->renderBackend()->createDrmPipelineLayer(pipeline);
|
||||
}
|
||||
for (const auto &output : qAsConst(m_outputs)) {
|
||||
if (const auto virtualOutput = qobject_cast<DrmVirtualOutput*>(output)) {
|
||||
|
|
|
@ -7,20 +7,24 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#include "drm_layer.h"
|
||||
#include "drm_pipeline.h"
|
||||
#include "drm_display_device.h"
|
||||
|
||||
#include <QMatrix4x4>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
DrmLayer::DrmLayer(KWin::DrmDisplayDevice* device)
|
||||
: m_displayDevice(device)
|
||||
DrmOutputLayer::~DrmOutputLayer() = default;
|
||||
|
||||
void DrmOutputLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
DrmLayer::~DrmLayer() = default;
|
||||
|
||||
DrmDisplayDevice *DrmLayer::displayDevice() const
|
||||
DrmPipelineLayer::DrmPipelineLayer(DrmPipeline *pipeline)
|
||||
: m_pipeline(pipeline)
|
||||
{
|
||||
return m_displayDevice;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,15 +18,16 @@ namespace KWin
|
|||
|
||||
class SurfaceItem;
|
||||
class DrmBuffer;
|
||||
class DrmDisplayDevice;
|
||||
class GLTexture;
|
||||
class DrmPipeline;
|
||||
|
||||
class DrmLayer : public QObject
|
||||
class DrmOutputLayer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DrmLayer(DrmDisplayDevice *device);
|
||||
virtual ~DrmLayer();
|
||||
virtual ~DrmOutputLayer();
|
||||
|
||||
virtual void aboutToStartPainting(const QRegion &damagedRegion);
|
||||
virtual std::optional<QRegion> startRendering() = 0;
|
||||
virtual bool endRendering(const QRegion &damagedRegion) = 0;
|
||||
|
||||
|
@ -37,6 +38,16 @@ public:
|
|||
*/
|
||||
virtual bool scanout(SurfaceItem *surfaceItem) = 0;
|
||||
|
||||
virtual QSharedPointer<GLTexture> texture() const = 0;
|
||||
|
||||
virtual QRegion currentDamage() const = 0;
|
||||
};
|
||||
|
||||
class DrmPipelineLayer : public DrmOutputLayer
|
||||
{
|
||||
public:
|
||||
DrmPipelineLayer(DrmPipeline *pipeline);
|
||||
|
||||
/**
|
||||
* @returns a buffer for atomic test commits
|
||||
* If no fitting buffer is available, a new current buffer is created
|
||||
|
@ -44,13 +55,10 @@ public:
|
|||
virtual QSharedPointer<DrmBuffer> testBuffer() = 0;
|
||||
|
||||
virtual QSharedPointer<DrmBuffer> currentBuffer() const = 0;
|
||||
virtual QRegion currentDamage() const = 0;
|
||||
virtual bool hasDirectScanoutBuffer() const = 0;
|
||||
|
||||
DrmDisplayDevice *displayDevice() const;
|
||||
|
||||
protected:
|
||||
DrmDisplayDevice *const m_displayDevice;
|
||||
DrmPipeline *const m_pipeline;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "drm_object_crtc.h"
|
||||
#include "drm_object_plane.h"
|
||||
#include "drm_pipeline.h"
|
||||
#include "drm_layer.h"
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
|
@ -83,51 +84,12 @@ bool DrmLeaseOutput::present()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DrmLeaseOutput::testScanout()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DrmPlane::Transformations DrmLeaseOutput::softwareTransforms() const
|
||||
{
|
||||
return DrmPlane::Transformation::Rotate0;
|
||||
}
|
||||
|
||||
QSize DrmLeaseOutput::bufferSize() const
|
||||
{
|
||||
return m_pipeline->bufferSize();
|
||||
}
|
||||
|
||||
QSize DrmLeaseOutput::sourceSize() const
|
||||
{
|
||||
return m_pipeline->sourceSize();
|
||||
}
|
||||
|
||||
bool DrmLeaseOutput::isFormatSupported(uint32_t drmFormat) const
|
||||
{
|
||||
return m_pipeline->isFormatSupported(drmFormat);
|
||||
}
|
||||
|
||||
QVector<uint64_t> DrmLeaseOutput::supportedModifiers(uint32_t drmFormat) const
|
||||
{
|
||||
return m_pipeline->supportedModifiers(drmFormat);
|
||||
}
|
||||
|
||||
int DrmLeaseOutput::maxBpc() const
|
||||
{
|
||||
if (const auto prop = m_pipeline->connector()->getProp(DrmConnector::PropertyIndex::MaxBpc)) {
|
||||
return prop->maxValue();
|
||||
} else {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
QRect DrmLeaseOutput::renderGeometry() const
|
||||
{
|
||||
return QRect(QPoint(), m_pipeline->sourceSize());
|
||||
}
|
||||
|
||||
DrmLayer *DrmLeaseOutput::outputLayer() const
|
||||
DrmOutputLayer *DrmLeaseOutput::outputLayer() const
|
||||
{
|
||||
return m_pipeline->pending.layer.data();
|
||||
}
|
||||
|
@ -141,4 +103,10 @@ void DrmLeaseOutput::pageFlipped(std::chrono::nanoseconds timestamp) const
|
|||
Q_UNUSED(timestamp)
|
||||
}
|
||||
|
||||
QVector<int32_t> DrmLeaseOutput::regionToRects(const QRegion ®ion) const
|
||||
{
|
||||
Q_UNUSED(region)
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,17 +41,11 @@ public:
|
|||
DrmPipeline *pipeline() const;
|
||||
|
||||
bool present() override;
|
||||
DrmPlane::Transformations softwareTransforms() const override;
|
||||
QSize bufferSize() const override;
|
||||
QSize sourceSize() const override;
|
||||
bool isFormatSupported(uint32_t drmFormat) const override;
|
||||
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const override;
|
||||
int maxBpc() const override;
|
||||
QRect renderGeometry() const override;
|
||||
DrmLayer *outputLayer() const override;
|
||||
bool testScanout() override;
|
||||
DrmOutputLayer *outputLayer() const override;
|
||||
void frameFailed() const override;
|
||||
void pageFlipped(std::chrono::nanoseconds timestamp) const override;
|
||||
QVector<int32_t> regionToRects(const QRegion ®ion) const override;
|
||||
|
||||
private:
|
||||
DrmPipeline *m_pipeline;
|
||||
|
|
|
@ -340,11 +340,6 @@ bool DrmOutput::present()
|
|||
}
|
||||
}
|
||||
|
||||
bool DrmOutput::testScanout()
|
||||
{
|
||||
return m_pipeline->testScanout();
|
||||
}
|
||||
|
||||
int DrmOutput::gammaRampSize() const
|
||||
{
|
||||
return m_pipeline->pending.crtc ? m_pipeline->pending.crtc->gammaRampSize() : 256;
|
||||
|
@ -373,26 +368,6 @@ DrmPipeline *DrmOutput::pipeline() const
|
|||
return m_pipeline;
|
||||
}
|
||||
|
||||
QSize DrmOutput::bufferSize() const
|
||||
{
|
||||
return m_pipeline->bufferSize();
|
||||
}
|
||||
|
||||
QSize DrmOutput::sourceSize() const
|
||||
{
|
||||
return m_pipeline->sourceSize();
|
||||
}
|
||||
|
||||
bool DrmOutput::isFormatSupported(uint32_t drmFormat) const
|
||||
{
|
||||
return m_pipeline->isFormatSupported(drmFormat);
|
||||
}
|
||||
|
||||
QVector<uint64_t> DrmOutput::supportedModifiers(uint32_t drmFormat) const
|
||||
{
|
||||
return m_pipeline->supportedModifiers(drmFormat);
|
||||
}
|
||||
|
||||
bool DrmOutput::queueChanges(const WaylandOutputConfig &config)
|
||||
{
|
||||
static bool valid;
|
||||
|
@ -449,28 +424,12 @@ void DrmOutput::revertQueuedChanges()
|
|||
m_pipeline->revertPendingChanges();
|
||||
}
|
||||
|
||||
int DrmOutput::maxBpc() const
|
||||
{
|
||||
auto prop = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc);
|
||||
return prop ? prop->maxValue() : 8;
|
||||
}
|
||||
|
||||
bool DrmOutput::usesSoftwareCursor() const
|
||||
{
|
||||
return !m_setCursorSuccessful || !m_moveCursorSuccessful;
|
||||
}
|
||||
|
||||
DrmPlane::Transformations DrmOutput::softwareTransforms() const
|
||||
{
|
||||
if (m_pipeline->pending.bufferTransformation == m_pipeline->pending.sourceTransformation) {
|
||||
return DrmPlane::Transformation::Rotate0;
|
||||
} else {
|
||||
// TODO handle sourceTransformation != Rotate0
|
||||
return m_pipeline->pending.sourceTransformation;
|
||||
}
|
||||
}
|
||||
|
||||
DrmLayer *DrmOutput::outputLayer() const
|
||||
DrmOutputLayer *DrmOutput::outputLayer() const
|
||||
{
|
||||
return m_pipeline->pending.layer.data();
|
||||
}
|
||||
|
|
|
@ -47,14 +47,7 @@ public:
|
|||
DrmPipeline *pipeline() const;
|
||||
|
||||
bool present() override;
|
||||
bool testScanout() override;
|
||||
QSize bufferSize() const override;
|
||||
QSize sourceSize() const override;
|
||||
bool isFormatSupported(uint32_t drmFormat) const override;
|
||||
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const override;
|
||||
DrmPlane::Transformations softwareTransforms() const override;
|
||||
int maxBpc() const override;
|
||||
DrmLayer *outputLayer() const override;
|
||||
DrmOutputLayer *outputLayer() const override;
|
||||
|
||||
bool queueChanges(const WaylandOutputConfig &config);
|
||||
void applyQueuedChanges(const WaylandOutputConfig &config);
|
||||
|
|
|
@ -31,7 +31,7 @@ class DrmBuffer;
|
|||
class DrmDumbBuffer;
|
||||
class GammaRamp;
|
||||
class DrmConnectorMode;
|
||||
class DrmLayer;
|
||||
class DrmPipelineLayer;
|
||||
class DrmDisplayDevice;
|
||||
|
||||
class DrmGammaRamp
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
RenderLoopPrivate::SyncMode syncMode = RenderLoopPrivate::SyncMode::Fixed;
|
||||
QSharedPointer<DrmGammaRamp> gamma;
|
||||
|
||||
QSharedPointer<DrmLayer> layer;
|
||||
QSharedPointer<DrmPipelineLayer> layer;
|
||||
|
||||
QPoint cursorPos;
|
||||
QPoint cursorHotspot;
|
||||
|
|
|
@ -13,16 +13,18 @@
|
|||
#include "scene_qpainter_drm_backend.h"
|
||||
#include "drm_gpu.h"
|
||||
#include "drm_backend.h"
|
||||
#include "drm_pipeline.h"
|
||||
#include "drm_virtual_output.h"
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
DrmQPainterLayer::DrmQPainterLayer(DrmDisplayDevice *displayDevice)
|
||||
: DrmLayer(displayDevice)
|
||||
DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline)
|
||||
: DrmPipelineLayer(pipeline)
|
||||
{
|
||||
connect(static_cast<DrmQPainterBackend*>(displayDevice->gpu()->platform()->renderBackend()), &DrmQPainterBackend::aboutToBeDestroyed, this, [this]() {
|
||||
connect(static_cast<DrmQPainterBackend*>(pipeline->gpu()->platform()->renderBackend()), &DrmQPainterBackend::aboutToBeDestroyed, this, [this]() {
|
||||
m_swapchain.reset();
|
||||
});
|
||||
}
|
||||
|
@ -30,10 +32,10 @@ DrmQPainterLayer::DrmQPainterLayer(DrmDisplayDevice *displayDevice)
|
|||
std::optional<QRegion> DrmQPainterLayer::startRendering()
|
||||
{
|
||||
if (!doesSwapchainFit()) {
|
||||
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_displayDevice->gpu(), m_displayDevice->sourceSize(), DRM_FORMAT_XRGB8888);
|
||||
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->sourceSize(), DRM_FORMAT_XRGB8888);
|
||||
}
|
||||
QRegion needsRepaint;
|
||||
if (!m_swapchain->acquireBuffer(m_displayDevice->renderGeometry(), &needsRepaint)) {
|
||||
if (!m_swapchain->acquireBuffer(m_pipeline->displayDevice()->renderGeometry(), &needsRepaint)) {
|
||||
return std::optional<QRegion>();
|
||||
}
|
||||
return needsRepaint;
|
||||
|
@ -55,14 +57,14 @@ bool DrmQPainterLayer::scanout(SurfaceItem *surfaceItem)
|
|||
QSharedPointer<DrmBuffer> DrmQPainterLayer::testBuffer()
|
||||
{
|
||||
if (!doesSwapchainFit()) {
|
||||
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_displayDevice->gpu(), m_displayDevice->sourceSize(), DRM_FORMAT_XRGB8888);
|
||||
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->sourceSize(), DRM_FORMAT_XRGB8888);
|
||||
}
|
||||
return m_swapchain->currentBuffer();
|
||||
}
|
||||
|
||||
bool DrmQPainterLayer::doesSwapchainFit() const
|
||||
{
|
||||
return m_swapchain && m_swapchain->size() == m_displayDevice->sourceSize();
|
||||
return m_swapchain && m_swapchain->size() == m_pipeline->sourceSize();
|
||||
}
|
||||
|
||||
QSharedPointer<DrmBuffer> DrmQPainterLayer::currentBuffer() const
|
||||
|
@ -80,4 +82,55 @@ bool DrmQPainterLayer::hasDirectScanoutBuffer() const
|
|||
return false;
|
||||
}
|
||||
|
||||
QSharedPointer<GLTexture> DrmQPainterLayer::texture() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QImage *DrmQPainterLayer::image()
|
||||
{
|
||||
return m_swapchain ? m_swapchain->currentBuffer()->image() : nullptr;
|
||||
}
|
||||
|
||||
|
||||
DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output)
|
||||
: m_output(output)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<QRegion> DrmVirtualQPainterLayer::startRendering()
|
||||
{
|
||||
if (m_image.isNull() || m_image.size() != m_output->pixelSize()) {
|
||||
m_image = QImage(m_output->pixelSize(), QImage::Format_RGB32);
|
||||
}
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
bool DrmVirtualQPainterLayer::endRendering(const QRegion &damagedRegion)
|
||||
{
|
||||
m_currentDamage = damagedRegion;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrmVirtualQPainterLayer::scanout(SurfaceItem *surfaceItem)
|
||||
{
|
||||
Q_UNUSED(surfaceItem);
|
||||
return false;
|
||||
}
|
||||
|
||||
QSharedPointer<GLTexture> DrmVirtualQPainterLayer::texture() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QRegion DrmVirtualQPainterLayer::currentDamage() const
|
||||
{
|
||||
return m_currentDamage;
|
||||
}
|
||||
|
||||
QImage *DrmVirtualQPainterLayer::image()
|
||||
{
|
||||
return &m_image;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,23 +9,37 @@
|
|||
#pragma once
|
||||
#include "drm_layer.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class DumbSwapchain;
|
||||
class DrmPipeline;
|
||||
class DrmVirtualOutput;
|
||||
|
||||
class DrmQPainterLayer : public DrmLayer
|
||||
class QPainterLayer
|
||||
{
|
||||
public:
|
||||
DrmQPainterLayer(DrmDisplayDevice *displayDevice);
|
||||
virtual ~QPainterLayer() = default;
|
||||
|
||||
virtual QImage *image() = 0;
|
||||
};
|
||||
|
||||
class DrmQPainterLayer : public DrmPipelineLayer, QPainterLayer
|
||||
{
|
||||
public:
|
||||
DrmQPainterLayer(DrmPipeline *pipeline);
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<GLTexture> texture() const override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
QRegion currentDamage() const override;
|
||||
bool hasDirectScanoutBuffer() const override;
|
||||
QImage *image() override;
|
||||
|
||||
private:
|
||||
bool doesSwapchainFit() const;
|
||||
|
@ -34,4 +48,23 @@ private:
|
|||
QRegion m_currentDamage;
|
||||
};
|
||||
|
||||
class DrmVirtualQPainterLayer : public DrmOutputLayer, QPainterLayer
|
||||
{
|
||||
public:
|
||||
DrmVirtualQPainterLayer(DrmVirtualOutput *output);
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
|
||||
QSharedPointer<GLTexture> texture() const override;
|
||||
QRegion currentDamage() const override;
|
||||
QImage *image() override;
|
||||
|
||||
private:
|
||||
QImage m_image;
|
||||
QRegion m_currentDamage;
|
||||
DrmVirtualOutput *const m_output;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -13,15 +13,19 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class DrmLayer;
|
||||
class DrmPipelineLayer;
|
||||
class DrmDisplayDevice;
|
||||
class DrmVirtualOutput;
|
||||
class DrmPipeline;
|
||||
class DrmOutputLayer;
|
||||
|
||||
class DrmRenderBackend
|
||||
{
|
||||
public:
|
||||
virtual ~DrmRenderBackend() = default;
|
||||
|
||||
virtual QSharedPointer<DrmLayer> createLayer(DrmDisplayDevice *displayDevice) = 0;
|
||||
virtual QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) = 0;
|
||||
virtual QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -77,29 +77,6 @@ void DrmVirtualOutput::updateEnablement(bool enable)
|
|||
gpu()->platform()->enableOutput(this, enable);
|
||||
}
|
||||
|
||||
QSize DrmVirtualOutput::bufferSize() const
|
||||
{
|
||||
return pixelSize();
|
||||
}
|
||||
|
||||
QSize DrmVirtualOutput::sourceSize() const
|
||||
{
|
||||
return pixelSize();
|
||||
}
|
||||
|
||||
bool DrmVirtualOutput::isFormatSupported(uint32_t drmFormat) const
|
||||
{
|
||||
Q_UNUSED(drmFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<uint64_t> DrmVirtualOutput::supportedModifiers(uint32_t drmFormat) const
|
||||
{
|
||||
Q_UNUSED(drmFormat);
|
||||
// empty list -> implicit modifiers are used / modifier is freely chosen by gbm
|
||||
return {};
|
||||
}
|
||||
|
||||
int DrmVirtualOutput::gammaRampSize() const
|
||||
{
|
||||
return 200;
|
||||
|
@ -111,26 +88,11 @@ bool DrmVirtualOutput::setGammaRamp(const GammaRamp &gamma)
|
|||
return true;
|
||||
}
|
||||
|
||||
int DrmVirtualOutput::maxBpc() const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
DrmPlane::Transformations DrmVirtualOutput::softwareTransforms() const
|
||||
{
|
||||
return DrmPlane::Transformation::Rotate0;
|
||||
}
|
||||
|
||||
DrmLayer *DrmVirtualOutput::outputLayer() const
|
||||
DrmOutputLayer *DrmVirtualOutput::outputLayer() const
|
||||
{
|
||||
return m_layer.data();
|
||||
}
|
||||
|
||||
bool DrmVirtualOutput::testScanout()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrmVirtualOutput::recreateSurface()
|
||||
{
|
||||
m_layer = m_gpu->platform()->renderBackend()->createLayer(this);
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace KWin
|
|||
|
||||
class SoftwareVsyncMonitor;
|
||||
class VirtualBackend;
|
||||
class DrmLayer;
|
||||
class DrmPipelineLayer;
|
||||
|
||||
class DrmVirtualOutput : public DrmAbstractOutput
|
||||
{
|
||||
|
@ -30,19 +30,9 @@ public:
|
|||
~DrmVirtualOutput() override;
|
||||
|
||||
bool present() override;
|
||||
QSize bufferSize() const override;
|
||||
QSize sourceSize() const override;
|
||||
|
||||
bool isFormatSupported(uint32_t drmFormat) const override;
|
||||
QVector<uint64_t> supportedModifiers(uint32_t drmFormat) const override;
|
||||
int maxBpc() const override;
|
||||
|
||||
int gammaRampSize() const override;
|
||||
bool setGammaRamp(const GammaRamp &gamma) override;
|
||||
DrmPlane::Transformations softwareTransforms() const override;
|
||||
DrmLayer *outputLayer() const override;
|
||||
bool testScanout() override;
|
||||
|
||||
DrmOutputLayer *outputLayer() const override;
|
||||
void recreateSurface();
|
||||
|
||||
private:
|
||||
|
@ -50,7 +40,7 @@ private:
|
|||
void setDpmsMode(DpmsMode mode) override;
|
||||
void updateEnablement(bool enable) override;
|
||||
|
||||
QSharedPointer<DrmLayer> m_layer;
|
||||
QSharedPointer<DrmOutputLayer> m_layer;
|
||||
bool m_pageFlipPending = true;
|
||||
int m_modeIndex = 0;
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "drm_abstract_output.h"
|
||||
#include "egl_dmabuf.h"
|
||||
#include "egl_gbm_layer.h"
|
||||
#include "virtual_egl_gbm_layer.h"
|
||||
// kwin libs
|
||||
#include <kwinglplatform.h>
|
||||
#include <kwineglimagetexture.h>
|
||||
|
@ -208,38 +209,9 @@ bool EglGbmBackend::initBufferConfigs()
|
|||
return false;
|
||||
}
|
||||
|
||||
static QVector<EGLint> regionToRects(const QRegion ®ion, DrmAbstractOutput *output)
|
||||
{
|
||||
const int height = output->sourceSize().height();
|
||||
|
||||
const QMatrix4x4 matrix = DrmOutput::logicalToNativeMatrix(output->geometry(),
|
||||
output->scale(),
|
||||
output->transform());
|
||||
|
||||
QVector<EGLint> rects;
|
||||
rects.reserve(region.rectCount() * 4);
|
||||
for (const QRect &_rect : region) {
|
||||
const QRect rect = matrix.mapRect(_rect);
|
||||
|
||||
rects << rect.left();
|
||||
rects << height - (rect.y() + rect.height());
|
||||
rects << rect.width();
|
||||
rects << rect.height();
|
||||
}
|
||||
return rects;
|
||||
}
|
||||
|
||||
void EglGbmBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion)
|
||||
{
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput*>(output);
|
||||
const auto &surface = static_cast<EglGbmLayer*>(drmOutput->outputLayer());
|
||||
if (surface->bufferAge() > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
||||
QVector<EGLint> rects = regionToRects(damagedRegion, static_cast<DrmAbstractOutput*>(output));
|
||||
const bool correct = eglSetDamageRegionKHR(eglDisplay(), surface->eglSurface(), rects.data(), rects.count()/4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_DRM) << "eglSetDamageRegionKHR failed:" << getEglErrorString();
|
||||
}
|
||||
}
|
||||
static_cast<DrmAbstractOutput*>(output)->outputLayer()->aboutToStartPainting(damagedRegion);
|
||||
}
|
||||
|
||||
SurfaceTexture *EglGbmBackend::createSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
|
||||
|
@ -303,23 +275,6 @@ GbmFormat EglGbmBackend::gbmFormatForDrmFormat(uint32_t format) const
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<uint32_t> EglGbmBackend::chooseFormat(DrmDisplayDevice *device) const
|
||||
{
|
||||
// formats are already sorted by order of preference
|
||||
std::optional<uint32_t> fallback;
|
||||
for (const auto &format : qAsConst(m_formats)) {
|
||||
if (device->isFormatSupported(format.drmFormat)) {
|
||||
int bpc = std::max(format.redSize, std::max(format.greenSize, format.blueSize));
|
||||
if (bpc <= device->maxBpc() && !fallback.has_value()) {
|
||||
fallback = format.drmFormat;
|
||||
} else {
|
||||
return format.drmFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
bool EglGbmBackend::prefer10bpc() const
|
||||
{
|
||||
static bool ok = false;
|
||||
|
@ -332,9 +287,14 @@ EGLConfig EglGbmBackend::config(uint32_t format) const
|
|||
return m_configs[format];
|
||||
}
|
||||
|
||||
QSharedPointer<DrmLayer> EglGbmBackend::createLayer(DrmDisplayDevice *displayDevice)
|
||||
QSharedPointer<DrmPipelineLayer> EglGbmBackend::createDrmPipelineLayer(DrmPipeline *pipeline)
|
||||
{
|
||||
return QSharedPointer<EglGbmLayer>::create(this, displayDevice);
|
||||
return QSharedPointer<EglGbmLayer>::create(this, pipeline);
|
||||
}
|
||||
|
||||
QSharedPointer<DrmOutputLayer> EglGbmBackend::createLayer(DrmVirtualOutput *output)
|
||||
{
|
||||
return QSharedPointer<VirtualEglGbmLayer>::create(this, output);
|
||||
}
|
||||
|
||||
DrmGpu *EglGbmBackend::gpu() const
|
||||
|
|
|
@ -39,6 +39,8 @@ class DrmBackend;
|
|||
class DrmGpu;
|
||||
class EglGbmLayer;
|
||||
class DrmDisplayDevice;
|
||||
class DrmOutputLayer;
|
||||
class DrmPipeline;
|
||||
|
||||
struct GbmFormat {
|
||||
uint32_t drmFormat = 0;
|
||||
|
@ -67,14 +69,14 @@ public:
|
|||
void init() override;
|
||||
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
|
||||
bool prefer10bpc() const override;
|
||||
QSharedPointer<DrmLayer> createLayer(DrmDisplayDevice *displayDevice) override;
|
||||
QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) override;
|
||||
QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) override;
|
||||
|
||||
QSharedPointer<GLTexture> textureForOutput(AbstractOutput *requestedOutput) const override;
|
||||
|
||||
QSharedPointer<DrmBuffer> testBuffer(DrmAbstractOutput *output);
|
||||
EGLConfig config(uint32_t format) const;
|
||||
GbmFormat gbmFormatForDrmFormat(uint32_t format) const;
|
||||
std::optional<uint32_t> chooseFormat(DrmDisplayDevice *displyDevice) const;
|
||||
DrmGpu *gpu() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmDisplayDevice *displayDevice)
|
||||
: DrmLayer(displayDevice)
|
||||
EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline)
|
||||
: DrmPipelineLayer(pipeline)
|
||||
, m_eglBackend(eglBackend)
|
||||
{
|
||||
connect(eglBackend, &EglGbmBackend::aboutToBeDestroyed, this, &EglGbmLayer::destroyResources);
|
||||
|
@ -90,7 +90,7 @@ std::optional<QRegion> EglGbmLayer::startRendering()
|
|||
if (!m_gbmSurface->makeContextCurrent()) {
|
||||
return std::optional<QRegion>();
|
||||
}
|
||||
auto repaintRegion = m_gbmSurface->repaintRegion(m_displayDevice->renderGeometry());
|
||||
auto repaintRegion = m_gbmSurface->repaintRegion(m_pipeline->displayDevice()->renderGeometry());
|
||||
|
||||
// shadow buffer
|
||||
if (doesShadowBufferFit(m_shadowBuffer.data())) {
|
||||
|
@ -99,9 +99,9 @@ std::optional<QRegion> EglGbmLayer::startRendering()
|
|||
if (doesShadowBufferFit(m_oldShadowBuffer.data())) {
|
||||
m_shadowBuffer = m_oldShadowBuffer;
|
||||
} else {
|
||||
if (m_displayDevice->softwareTransforms() != DrmPlane::Transformations(DrmPlane::Transformation::Rotate0)) {
|
||||
if (m_pipeline->pending.bufferTransformation != m_pipeline->pending.sourceTransformation) {
|
||||
const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format());
|
||||
m_shadowBuffer = QSharedPointer<ShadowBuffer>::create(m_displayDevice->sourceSize(), format);
|
||||
m_shadowBuffer = QSharedPointer<ShadowBuffer>::create(m_pipeline->sourceSize(), format);
|
||||
if (!m_shadowBuffer->isComplete()) {
|
||||
return std::optional<QRegion>();
|
||||
}
|
||||
|
@ -121,11 +121,23 @@ std::optional<QRegion> EglGbmLayer::startRendering()
|
|||
return repaintRegion;
|
||||
}
|
||||
|
||||
void EglGbmLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
||||
{
|
||||
if (m_gbmSurface->bufferAge() > 0 && !damagedRegion.isEmpty() && m_eglBackend->supportsPartialUpdate()) {
|
||||
QVector<EGLint> rects = m_pipeline->displayDevice()->regionToRects(damagedRegion);
|
||||
const bool correct = eglSetDamageRegionKHR(m_eglBackend->eglDisplay(), m_gbmSurface->eglSurface(), rects.data(), rects.count() / 4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_DRM) << "eglSetDamageRegionKHR failed:" << getEglErrorString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EglGbmLayer::endRendering(const QRegion &damagedRegion)
|
||||
{
|
||||
if (m_shadowBuffer) {
|
||||
GLRenderTarget::popRenderTarget();
|
||||
m_shadowBuffer->render(m_displayDevice);
|
||||
// TODO handle m_pipeline->pending.bufferTransformation != Rotate0
|
||||
m_shadowBuffer->render(m_pipeline->pending.sourceTransformation);
|
||||
}
|
||||
GLRenderTarget::popRenderTarget();
|
||||
const auto buffer = m_gbmSurface->swapBuffersForDrm(damagedRegion);
|
||||
|
@ -166,70 +178,83 @@ bool EglGbmLayer::renderTestBuffer()
|
|||
return false;
|
||||
}
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (!endRendering(m_displayDevice->renderGeometry())) {
|
||||
if (!endRendering(m_pipeline->displayDevice()->renderGeometry())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EglGbmLayer::createGbmSurface()
|
||||
bool EglGbmLayer::createGbmSurface(uint32_t format, const QVector<uint64_t> &modifiers)
|
||||
{
|
||||
static bool modifiersEnvSet = false;
|
||||
static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0;
|
||||
|
||||
auto format = m_eglBackend->chooseFormat(m_displayDevice);
|
||||
if (!format || m_importMode == MultiGpuImportMode::DumbBufferXrgb8888) {
|
||||
format = DRM_FORMAT_XRGB8888;
|
||||
}
|
||||
const auto modifiers = m_displayDevice->supportedModifiers(format.value());
|
||||
const auto size = m_displayDevice->bufferSize();
|
||||
const auto config = m_eglBackend->config(format.value());
|
||||
const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && m_displayDevice->gpu()->addFB2ModifiersSupported()
|
||||
const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && m_pipeline->gpu()->addFB2ModifiersSupported()
|
||||
&& ((m_eglBackend->gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv));
|
||||
|
||||
const auto size = m_pipeline->bufferSize();
|
||||
const auto config = m_eglBackend->config(format);
|
||||
|
||||
QSharedPointer<GbmSurface> gbmSurface;
|
||||
#if HAVE_GBM_BO_GET_FD_FOR_PLANE
|
||||
if (!allowModifiers) {
|
||||
#else
|
||||
// modifiers have to be disabled with multi-gpu if gbm_bo_get_fd_for_plane is not available
|
||||
if (!allowModifiers || m_displayDevice->gpu() != m_eglBackend->gpu()) {
|
||||
if (!allowModifiers || m_pipeline->gpu() != m_eglBackend->gpu()) {
|
||||
#endif
|
||||
int flags = GBM_BO_USE_RENDERING;
|
||||
if (m_displayDevice->gpu() == m_eglBackend->gpu()) {
|
||||
if (m_pipeline->gpu() == m_eglBackend->gpu()) {
|
||||
flags |= GBM_BO_USE_SCANOUT;
|
||||
} else {
|
||||
flags |= GBM_BO_USE_LINEAR;
|
||||
}
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format.value(), flags, config);
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format, flags, config);
|
||||
} else {
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format.value(), modifiers, config);
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format, modifiers, config);
|
||||
if (!gbmSurface->isValid()) {
|
||||
// the egl / gbm implementation may reject the modifier list from another gpu
|
||||
// as a fallback use linear, to at least make CPU copy more efficient
|
||||
const QVector<uint64_t> linear = {DRM_FORMAT_MOD_LINEAR};
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format.value(), linear, config);
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, format, linear, config);
|
||||
}
|
||||
}
|
||||
if (!gbmSurface->isValid()) {
|
||||
if (gbmSurface->isValid()) {
|
||||
m_oldGbmSurface = m_gbmSurface;
|
||||
m_gbmSurface = gbmSurface;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
m_oldGbmSurface = m_gbmSurface;
|
||||
m_gbmSurface = gbmSurface;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EglGbmLayer::createGbmSurface()
|
||||
{
|
||||
const auto tranches = m_eglBackend->dmabuf()->tranches();
|
||||
for (const auto &tranche : tranches) {
|
||||
for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
|
||||
const uint32_t &format = it.key();
|
||||
if (m_importMode == MultiGpuImportMode::DumbBufferXrgb8888 && format != DRM_FORMAT_XRGB8888) {
|
||||
continue;
|
||||
}
|
||||
if (m_pipeline->isFormatSupported(format) && createGbmSurface(format, m_pipeline->supportedModifiers(format))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EglGbmLayer::doesGbmSurfaceFit(GbmSurface *surf) const
|
||||
{
|
||||
return surf && surf->size() == m_displayDevice->bufferSize()
|
||||
&& m_displayDevice->isFormatSupported(surf->format())
|
||||
return surf && surf->size() == m_pipeline->bufferSize()
|
||||
&& m_pipeline->isFormatSupported(surf->format())
|
||||
&& (m_importMode != MultiGpuImportMode::DumbBufferXrgb8888 || surf->format() == DRM_FORMAT_XRGB8888)
|
||||
&& (surf->modifiers().isEmpty() || m_displayDevice->supportedModifiers(surf->format()) == surf->modifiers());
|
||||
&& (surf->modifiers().isEmpty() || m_pipeline->supportedModifiers(surf->format()) == surf->modifiers());
|
||||
}
|
||||
|
||||
bool EglGbmLayer::doesShadowBufferFit(ShadowBuffer *buffer) const
|
||||
{
|
||||
if (m_displayDevice->softwareTransforms() != DrmPlane::Transformations(DrmPlane::Transformation::Rotate0)) {
|
||||
return buffer && buffer->texture()->size() == m_displayDevice->sourceSize() && buffer->drmFormat() == m_gbmSurface->format();
|
||||
if (m_pipeline->pending.bufferTransformation != m_pipeline->pending.sourceTransformation) {
|
||||
return buffer && buffer->texture()->size() == m_pipeline->sourceSize() && buffer->drmFormat() == m_gbmSurface->format();
|
||||
} else {
|
||||
return buffer == nullptr;
|
||||
}
|
||||
|
@ -237,7 +262,7 @@ bool EglGbmLayer::doesShadowBufferFit(ShadowBuffer *buffer) const
|
|||
|
||||
bool EglGbmLayer::doesSwapchainFit(DumbSwapchain *swapchain) const
|
||||
{
|
||||
return swapchain && swapchain->size() == m_displayDevice->sourceSize() && swapchain->drmFormat() == m_gbmSurface->format();
|
||||
return swapchain && swapchain->size() == m_pipeline->sourceSize() && swapchain->drmFormat() == m_gbmSurface->format();
|
||||
}
|
||||
|
||||
QSharedPointer<GLTexture> EglGbmLayer::texture() const
|
||||
|
@ -248,7 +273,7 @@ QSharedPointer<GLTexture> EglGbmLayer::texture() const
|
|||
qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << getEglErrorString();
|
||||
return QSharedPointer<EGLImageTexture>(nullptr);
|
||||
}
|
||||
return QSharedPointer<EGLImageTexture>::create(m_eglBackend->eglDisplay(), image, GL_RGBA8, m_displayDevice->sourceSize());
|
||||
return QSharedPointer<EGLImageTexture>::create(m_eglBackend->eglDisplay(), image, GL_RGBA8, m_pipeline->sourceSize());
|
||||
};
|
||||
if (m_scanoutBuffer) {
|
||||
return createImage(dynamic_cast<GbmBuffer*>(m_scanoutBuffer.data()));
|
||||
|
@ -315,7 +340,7 @@ QSharedPointer<DrmBuffer> EglGbmLayer::importDmabuf()
|
|||
data.strides[i] = gbm_bo_get_stride_for_plane(bo, i);
|
||||
data.offsets[i] = gbm_bo_get_offset(bo, i);
|
||||
}
|
||||
importedBuffer = gbm_bo_import(m_displayDevice->gpu()->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
importedBuffer = gbm_bo_import(m_pipeline->gpu()->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
} else {
|
||||
#endif
|
||||
gbm_import_fd_data data = {
|
||||
|
@ -329,7 +354,7 @@ QSharedPointer<DrmBuffer> EglGbmLayer::importDmabuf()
|
|||
qCWarning(KWIN_DRM, "failed to export gbm_bo as dma-buf: %s", strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
importedBuffer = gbm_bo_import(m_displayDevice->gpu()->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
importedBuffer = gbm_bo_import(m_pipeline->gpu()->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
#if HAVE_GBM_BO_GET_FD_FOR_PLANE
|
||||
}
|
||||
#endif
|
||||
|
@ -337,7 +362,7 @@ QSharedPointer<DrmBuffer> EglGbmLayer::importDmabuf()
|
|||
qCWarning(KWIN_DRM, "failed to import gbm_bo for multi-gpu usage: %s", strerror(errno));
|
||||
return nullptr;
|
||||
}
|
||||
const auto buffer = QSharedPointer<DrmGbmBuffer>::create(m_displayDevice->gpu(), importedBuffer, nullptr);
|
||||
const auto buffer = QSharedPointer<DrmGbmBuffer>::create(m_pipeline->gpu(), nullptr, importedBuffer);
|
||||
return buffer->bufferId() ? buffer : nullptr;
|
||||
}
|
||||
|
||||
|
@ -349,7 +374,7 @@ QSharedPointer<DrmBuffer> EglGbmLayer::importWithCpu()
|
|||
if (doesSwapchainFit(m_oldImportSwapchain.data())) {
|
||||
m_importSwapchain = m_oldImportSwapchain;
|
||||
} else {
|
||||
const auto swapchain = QSharedPointer<DumbSwapchain>::create(m_displayDevice->gpu(), m_displayDevice->sourceSize(), m_gbmSurface->format());
|
||||
const auto swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->sourceSize(), m_gbmSurface->format());
|
||||
if (swapchain->isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -386,7 +411,7 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem)
|
|||
return false;
|
||||
}
|
||||
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(item->surface()->buffer());
|
||||
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_displayDevice->sourceSize()) {
|
||||
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_pipeline->sourceSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -396,51 +421,14 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem)
|
|||
m_scanoutCandidate.surface = item->surface();
|
||||
m_scanoutCandidate.attemptedThisFrame = true;
|
||||
|
||||
if (!m_displayDevice->isFormatSupported(buffer->format())) {
|
||||
if (!m_pipeline->isFormatSupported(buffer->format())) {
|
||||
sendDmabufFeedback(buffer);
|
||||
return false;
|
||||
}
|
||||
const auto planes = buffer->planes();
|
||||
gbm_bo *importedBuffer;
|
||||
if (planes.first().modifier != DRM_FORMAT_MOD_INVALID || planes.first().offset > 0 || planes.count() > 1) {
|
||||
if (!m_displayDevice->gpu()->addFB2ModifiersSupported() || !m_displayDevice->supportedModifiers(buffer->format()).contains(planes.first().modifier)) {
|
||||
return false;
|
||||
}
|
||||
gbm_import_fd_modifier_data data = {};
|
||||
data.format = buffer->format();
|
||||
data.width = (uint32_t) buffer->size().width();
|
||||
data.height = (uint32_t) buffer->size().height();
|
||||
data.num_fds = planes.count();
|
||||
data.modifier = planes.first().modifier;
|
||||
for (int i = 0; i < planes.count(); i++) {
|
||||
data.fds[i] = planes[i].fd;
|
||||
data.offsets[i] = planes[i].offset;
|
||||
data.strides[i] = planes[i].stride;
|
||||
}
|
||||
importedBuffer = gbm_bo_import(m_displayDevice->gpu()->gbmDevice(), GBM_BO_IMPORT_FD_MODIFIER, &data, GBM_BO_USE_SCANOUT);
|
||||
} else {
|
||||
const auto &plane = planes.first();
|
||||
gbm_import_fd_data data = {};
|
||||
data.fd = plane.fd;
|
||||
data.width = (uint32_t) buffer->size().width();
|
||||
data.height = (uint32_t) buffer->size().height();
|
||||
data.stride = plane.stride;
|
||||
data.format = buffer->format();
|
||||
importedBuffer = gbm_bo_import(m_displayDevice->gpu()->gbmDevice(), GBM_BO_IMPORT_FD, &data, GBM_BO_USE_SCANOUT);
|
||||
}
|
||||
if (!importedBuffer) {
|
||||
m_scanoutBuffer = QSharedPointer<DrmGbmBuffer>::create(m_pipeline->gpu(), buffer);
|
||||
if (!m_scanoutBuffer || !m_scanoutBuffer->bufferId()) {
|
||||
sendDmabufFeedback(buffer);
|
||||
if (errno != EINVAL) {
|
||||
qCWarning(KWIN_DRM) << "Importing buffer for direct scanout failed:" << strerror(errno);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
m_scanoutBuffer = QSharedPointer<DrmGbmBuffer>::create(m_displayDevice->gpu(), importedBuffer, buffer);
|
||||
if (!m_scanoutBuffer->bufferId()) {
|
||||
// buffer can't actually be scanned out. Mesa is supposed to prevent this from happening
|
||||
// in gbm_bo_import but apparently that doesn't always work
|
||||
m_scanoutBuffer.reset();
|
||||
sendDmabufFeedback(buffer);
|
||||
return false;
|
||||
}
|
||||
// damage tracking for screen casting
|
||||
|
@ -450,13 +438,13 @@ bool EglGbmLayer::scanout(SurfaceItem *surfaceItem)
|
|||
surfaceItem->resetDamage();
|
||||
for (const auto &rect : trackedDamage) {
|
||||
auto damageRect = QRect(rect);
|
||||
damageRect.translate(m_displayDevice->renderGeometry().topLeft());
|
||||
damageRect.translate(m_pipeline->displayDevice()->renderGeometry().topLeft());
|
||||
damage |= damageRect;
|
||||
}
|
||||
} else {
|
||||
damage = m_displayDevice->renderGeometry();
|
||||
damage = m_pipeline->displayDevice()->renderGeometry();
|
||||
}
|
||||
if (m_displayDevice->testScanout()) {
|
||||
if (m_pipeline->testScanout()) {
|
||||
m_currentBuffer = m_scanoutBuffer;
|
||||
m_currentDamage = damage;
|
||||
return true;
|
||||
|
@ -471,9 +459,9 @@ void EglGbmLayer::sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer *
|
|||
if (!m_scanoutCandidate.attemptedFormats[failedBuffer->format()].contains(failedBuffer->planes().first().modifier)) {
|
||||
m_scanoutCandidate.attemptedFormats[failedBuffer->format()] << failedBuffer->planes().first().modifier;
|
||||
}
|
||||
if (const auto &drmOutput = dynamic_cast<DrmOutput *>(m_displayDevice); drmOutput && m_scanoutCandidate.surface->dmabufFeedbackV1()) {
|
||||
if (m_scanoutCandidate.surface->dmabufFeedbackV1()) {
|
||||
QVector<KWaylandServer::LinuxDmaBufV1Feedback::Tranche> scanoutTranches;
|
||||
const auto &drmFormats = drmOutput->pipeline()->supportedFormats();
|
||||
const auto &drmFormats = m_pipeline->supportedFormats();
|
||||
const auto tranches = m_eglBackend->dmabuf()->tranches();
|
||||
for (const auto &tranche : tranches) {
|
||||
KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche;
|
||||
|
@ -488,7 +476,7 @@ void EglGbmLayer::sendDmabufFeedback(KWaylandServer::LinuxDmaBufV1ClientBuffer *
|
|||
}
|
||||
}
|
||||
if (!scanoutTranche.formatTable.isEmpty()) {
|
||||
scanoutTranche.device = m_displayDevice->gpu()->deviceId();
|
||||
scanoutTranche.device = m_pipeline->gpu()->deviceId();
|
||||
scanoutTranche.flags = KWaylandServer::LinuxDmaBufV1Feedback::TrancheFlag::Scanout;
|
||||
scanoutTranches << scanoutTranche;
|
||||
}
|
||||
|
@ -502,16 +490,6 @@ QSharedPointer<DrmBuffer> EglGbmLayer::currentBuffer() const
|
|||
return m_scanoutBuffer ? m_scanoutBuffer : m_currentBuffer;
|
||||
}
|
||||
|
||||
int EglGbmLayer::bufferAge() const
|
||||
{
|
||||
return m_gbmSurface ? m_gbmSurface->bufferAge() : 0;
|
||||
}
|
||||
|
||||
EGLSurface EglGbmLayer::eglSurface() const
|
||||
{
|
||||
return m_gbmSurface ? m_gbmSurface->eglSurface() : EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
bool EglGbmLayer::hasDirectScanoutBuffer() const
|
||||
{
|
||||
return m_scanoutBuffer != nullptr;
|
||||
|
|
|
@ -33,26 +33,26 @@ class DrmGpu;
|
|||
class SurfaceItem;
|
||||
class GLTexture;
|
||||
class EglGbmBackend;
|
||||
class DrmPipeline;
|
||||
|
||||
class EglGbmLayer : public DrmLayer
|
||||
class EglGbmLayer : public DrmPipelineLayer
|
||||
{
|
||||
public:
|
||||
EglGbmLayer(EglGbmBackend *eglBackend, DrmDisplayDevice *displayDevice);
|
||||
EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline);
|
||||
~EglGbmLayer();
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
void aboutToStartPainting(const QRegion &damagedRegion) override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
bool hasDirectScanoutBuffer() const override;
|
||||
QRegion currentDamage() const override;
|
||||
QSharedPointer<GLTexture> texture() const;
|
||||
|
||||
int bufferAge() const;
|
||||
EGLSurface eglSurface() const;
|
||||
QSharedPointer<GLTexture> texture() const override;
|
||||
|
||||
private:
|
||||
bool createGbmSurface(uint32_t format, const QVector<uint64_t> &modifiers);
|
||||
bool createGbmSurface();
|
||||
bool doesGbmSurfaceFit(GbmSurface *surf) const;
|
||||
bool doesShadowBufferFit(ShadowBuffer *buffer) const;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "drm_buffer.h"
|
||||
#include "renderloop_p.h"
|
||||
#include "drm_qpainter_layer.h"
|
||||
#include "drm_virtual_output.h"
|
||||
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
|
@ -34,7 +35,7 @@ DrmQPainterBackend::~DrmQPainterBackend()
|
|||
QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output)
|
||||
{
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput*>(output);
|
||||
return static_cast<DrmDumbBuffer*>(drmOutput->outputLayer()->currentBuffer().data())->image();
|
||||
return dynamic_cast<QPainterLayer*>(drmOutput->outputLayer())->image();
|
||||
}
|
||||
|
||||
QRegion DrmQPainterBackend::beginFrame(AbstractOutput *output)
|
||||
|
@ -51,9 +52,14 @@ void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &rendere
|
|||
static_cast<DrmAbstractOutput*>(output)->present();
|
||||
}
|
||||
|
||||
QSharedPointer<DrmLayer> DrmQPainterBackend::createLayer(DrmDisplayDevice *displayDevice)
|
||||
QSharedPointer<DrmPipelineLayer> DrmQPainterBackend::createDrmPipelineLayer(DrmPipeline *pipeline)
|
||||
{
|
||||
return QSharedPointer<DrmQPainterLayer>::create(displayDevice);
|
||||
return QSharedPointer<DrmQPainterLayer>::create(pipeline);
|
||||
}
|
||||
|
||||
QSharedPointer<DrmOutputLayer> DrmQPainterBackend::createLayer(DrmVirtualOutput *output)
|
||||
{
|
||||
return QSharedPointer<DrmVirtualQPainterLayer>::create(output);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace KWin
|
|||
class DrmBackend;
|
||||
class DrmAbstractOutput;
|
||||
class DrmQPainterLayer;
|
||||
class DrmPipeline;
|
||||
|
||||
class DrmQPainterBackend : public QPainterBackend, public DrmRenderBackend
|
||||
{
|
||||
|
@ -32,7 +33,8 @@ public:
|
|||
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
QSharedPointer<DrmLayer> createLayer(DrmDisplayDevice *displayDevice) override;
|
||||
QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) override;
|
||||
QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void aboutToBeDestroyed();
|
||||
|
|
|
@ -56,10 +56,9 @@ ShadowBuffer::~ShadowBuffer()
|
|||
{
|
||||
}
|
||||
|
||||
void ShadowBuffer::render(DrmDisplayDevice *displayDevice)
|
||||
void ShadowBuffer::render(DrmPlane::Transformations transform)
|
||||
{
|
||||
QMatrix4x4 mvpMatrix;
|
||||
const auto transform = displayDevice->softwareTransforms();
|
||||
if (transform & DrmPlane::Transformation::Rotate90) {
|
||||
mvpMatrix.rotate(90, 0, 0, 1);
|
||||
} else if (transform & DrmPlane::Transformation::Rotate180) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <kwinglutils.h>
|
||||
|
||||
#include "egl_gbm_backend.h"
|
||||
#include "drm_object_plane.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -25,7 +26,7 @@ public:
|
|||
~ShadowBuffer();
|
||||
|
||||
bool isComplete() const;
|
||||
void render(DrmDisplayDevice *displayDevice);
|
||||
void render(DrmPlane::Transformations transform);
|
||||
|
||||
GLRenderTarget *renderTarget() const;
|
||||
QSharedPointer<GLTexture> texture() const;
|
||||
|
|
190
src/backends/drm/virtual_egl_gbm_layer.cpp
Normal file
190
src/backends/drm/virtual_egl_gbm_layer.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
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 "virtual_egl_gbm_layer.h"
|
||||
#include "gbm_surface.h"
|
||||
#include "drm_abstract_output.h"
|
||||
#include "drm_gpu.h"
|
||||
#include "egl_gbm_backend.h"
|
||||
#include "shadowbuffer.h"
|
||||
#include "drm_output.h"
|
||||
#include "drm_pipeline.h"
|
||||
#include "dumb_swapchain.h"
|
||||
#include "logging.h"
|
||||
#include "egl_dmabuf.h"
|
||||
#include "surfaceitem_wayland.h"
|
||||
#include "kwineglimagetexture.h"
|
||||
#include "drm_backend.h"
|
||||
#include "drm_virtual_output.h"
|
||||
#include "kwineglutils_p.h"
|
||||
|
||||
#include "KWaylandServer/surface_interface.h"
|
||||
#include "KWaylandServer/linuxdmabufv1clientbuffer.h"
|
||||
|
||||
#include <QRegion>
|
||||
#include <drm_fourcc.h>
|
||||
#include <gbm.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
VirtualEglGbmLayer::VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output)
|
||||
: m_output(output)
|
||||
, m_eglBackend(eglBackend)
|
||||
{
|
||||
connect(eglBackend, &EglGbmBackend::aboutToBeDestroyed, this, &VirtualEglGbmLayer::destroyResources);
|
||||
}
|
||||
|
||||
void VirtualEglGbmLayer::destroyResources()
|
||||
{
|
||||
m_gbmSurface.reset();
|
||||
m_oldGbmSurface.reset();
|
||||
}
|
||||
|
||||
void VirtualEglGbmLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
||||
{
|
||||
if (m_gbmSurface->bufferAge() > 0 && !damagedRegion.isEmpty() && m_eglBackend->supportsPartialUpdate()) {
|
||||
const QRegion region = damagedRegion & m_output->geometry();
|
||||
|
||||
QVector<EGLint> rects = m_output->regionToRects(region);
|
||||
const bool correct = eglSetDamageRegionKHR(m_eglBackend->eglDisplay(), m_gbmSurface->eglSurface(), rects.data(), rects.count() / 4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_DRM) << "eglSetDamageRegionKHR failed:" << getEglErrorString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<QRegion> VirtualEglGbmLayer::startRendering()
|
||||
{
|
||||
// gbm surface
|
||||
if (doesGbmSurfaceFit(m_gbmSurface.data())) {
|
||||
m_oldGbmSurface.reset();
|
||||
} else {
|
||||
if (doesGbmSurfaceFit(m_oldGbmSurface.data())) {
|
||||
m_gbmSurface = m_oldGbmSurface;
|
||||
} else {
|
||||
if (!createGbmSurface()) {
|
||||
return std::optional<QRegion>();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_gbmSurface->makeContextCurrent()) {
|
||||
return std::optional<QRegion>();
|
||||
}
|
||||
GLRenderTarget::pushRenderTarget(m_gbmSurface->renderTarget());
|
||||
return m_gbmSurface->repaintRegion(m_output->geometry());
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::endRendering(const QRegion &damagedRegion)
|
||||
{
|
||||
GLRenderTarget::popRenderTarget();
|
||||
const auto buffer = m_gbmSurface->swapBuffers(damagedRegion.intersected(m_output->geometry()));
|
||||
if (buffer) {
|
||||
m_currentBuffer = buffer;
|
||||
m_currentDamage = damagedRegion;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QRegion VirtualEglGbmLayer::currentDamage() const
|
||||
{
|
||||
return m_currentDamage;
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::createGbmSurface()
|
||||
{
|
||||
static bool modifiersEnvSet = false;
|
||||
static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0;
|
||||
|
||||
const auto tranches = m_eglBackend->dmabuf()->tranches();
|
||||
for (const auto &tranche : tranches) {
|
||||
for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) {
|
||||
const auto size = m_output->pixelSize();
|
||||
const auto config = m_eglBackend->config(it.key());
|
||||
const auto modifiers = it.value();
|
||||
const bool allowModifiers = m_eglBackend->gpu()->addFB2ModifiersSupported() && ((m_eglBackend->gpu()->isNVidia() && !modifiersEnvSet) || (modifiersEnvSet && modifiersEnv));
|
||||
|
||||
QSharedPointer<GbmSurface> gbmSurface;
|
||||
if (!allowModifiers) {
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, it.key(), GBM_BO_USE_RENDERING, config);
|
||||
} else {
|
||||
gbmSurface = QSharedPointer<GbmSurface>::create(m_eglBackend->gpu(), size, it.key(), it.value(), config);
|
||||
}
|
||||
if (!gbmSurface->isValid()) {
|
||||
continue;
|
||||
}
|
||||
m_oldGbmSurface = m_gbmSurface;
|
||||
m_gbmSurface = gbmSurface;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::doesGbmSurfaceFit(GbmSurface *surf) const
|
||||
{
|
||||
return surf && surf->size() == m_output->pixelSize();
|
||||
}
|
||||
|
||||
QSharedPointer<GLTexture> VirtualEglGbmLayer::texture() const
|
||||
{
|
||||
GbmBuffer *gbmBuffer = m_gbmSurface->currentBuffer().get();
|
||||
if (!gbmBuffer) {
|
||||
qCWarning(KWIN_DRM) << "Failed to record frame: No gbm buffer!";
|
||||
return nullptr;
|
||||
}
|
||||
EGLImageKHR image = eglCreateImageKHR(m_eglBackend->eglDisplay(), nullptr, EGL_NATIVE_PIXMAP_KHR, gbmBuffer->getBo(), nullptr);
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
qCWarning(KWIN_DRM) << "Failed to record frame: Error creating EGLImageKHR - " << glGetError();
|
||||
return nullptr;
|
||||
}
|
||||
return QSharedPointer<EGLImageTexture>::create(m_eglBackend->eglDisplay(), image, GL_RGBA8, m_gbmSurface->size());
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::scanout(SurfaceItem *surfaceItem)
|
||||
{
|
||||
static bool valid;
|
||||
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
|
||||
if (directScanoutDisabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SurfaceItemWayland *item = qobject_cast<SurfaceItemWayland *>(surfaceItem);
|
||||
if (!item || !item->surface()) {
|
||||
return false;
|
||||
}
|
||||
const auto buffer = qobject_cast<KWaylandServer::LinuxDmaBufV1ClientBuffer *>(item->surface()->buffer());
|
||||
if (!buffer || buffer->planes().isEmpty() || buffer->size() != m_output->pixelSize()) {
|
||||
return false;
|
||||
}
|
||||
const auto scanoutBuffer = QSharedPointer<GbmBuffer>::create(m_output->gpu(), buffer);
|
||||
if (!scanoutBuffer->getBo()) {
|
||||
return false;
|
||||
}
|
||||
// damage tracking for screen casting
|
||||
QRegion damage;
|
||||
if (m_scanoutSurface == item->surface()) {
|
||||
QRegion trackedDamage = surfaceItem->damage();
|
||||
surfaceItem->resetDamage();
|
||||
for (const auto &rect : trackedDamage) {
|
||||
auto damageRect = QRect(rect);
|
||||
damageRect.translate(m_output->geometry().topLeft());
|
||||
damage |= damageRect;
|
||||
}
|
||||
} else {
|
||||
damage = m_output->geometry();
|
||||
}
|
||||
m_scanoutSurface = item->surface();
|
||||
m_currentBuffer = scanoutBuffer;
|
||||
m_currentDamage = damage;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
61
src/backends/drm/virtual_egl_gbm_layer.h
Normal file
61
src/backends/drm/virtual_egl_gbm_layer.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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 "drm_layer.h"
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <QPointer>
|
||||
#include <QMap>
|
||||
#include <QRegion>
|
||||
#include <optional>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class SurfaceInterface;
|
||||
}
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class GbmSurface;
|
||||
class GLTexture;
|
||||
class EglGbmBackend;
|
||||
class GbmBuffer;
|
||||
class DrmVirtualOutput;
|
||||
|
||||
class VirtualEglGbmLayer : public DrmOutputLayer
|
||||
{
|
||||
public:
|
||||
VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output);
|
||||
|
||||
void aboutToStartPainting(const QRegion &damagedRegion) override;
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
|
||||
QRegion currentDamage() const override;
|
||||
QSharedPointer<GLTexture> texture() const override;
|
||||
|
||||
private:
|
||||
bool createGbmSurface();
|
||||
bool doesGbmSurfaceFit(GbmSurface *surf) const;
|
||||
void destroyResources();
|
||||
|
||||
QPointer<KWaylandServer::SurfaceInterface> m_scanoutSurface;
|
||||
QSharedPointer<GbmBuffer> m_currentBuffer;
|
||||
QRegion m_currentDamage;
|
||||
QSharedPointer<GbmSurface> m_gbmSurface;
|
||||
QSharedPointer<GbmSurface> m_oldGbmSurface;
|
||||
|
||||
DrmVirtualOutput *const m_output;
|
||||
EglGbmBackend *const m_eglBackend;
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue