backends: move more things from output layers to kwin core

This commit is contained in:
Xaver Hugl 2024-04-23 13:30:29 +02:00
parent 3232a63ac1
commit 445567f54e
32 changed files with 248 additions and 219 deletions

View file

@ -25,7 +25,7 @@ EglGbmCursorLayer::EglGbmCursorLayer(EglGbmBackend *eglBackend, DrmPipeline *pip
{
}
std::optional<OutputLayerBeginFrameInfo> EglGbmCursorLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> EglGbmCursorLayer::doBeginFrame()
{
if (m_pipeline->amdgpuVrrWorkaroundActive()) {
return std::nullopt;
@ -36,7 +36,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmCursorLayer::beginFrame()
return m_surface.startRendering(m_pipeline->gpu()->cursorSize(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->cursorFormats(), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement());
}
bool EglGbmCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool EglGbmCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
return m_surface.endRendering(damagedRegion);
}

View file

@ -27,8 +27,8 @@ class EglGbmCursorLayer : public DrmPipelineLayer
public:
EglGbmCursorLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
bool checkTestBuffer() override;
void releaseBuffers() override;

View file

@ -33,14 +33,14 @@ EglGbmLayer::EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline)
{
}
std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::doBeginFrame()
{
m_scanoutBuffer.reset();
return m_surface.startRendering(m_pipeline->mode()->size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement());
}
bool EglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
return m_surface.endRendering(damagedRegion);
}
@ -54,7 +54,7 @@ std::shared_ptr<GLTexture> EglGbmLayer::texture() const
{
if (m_scanoutBuffer) {
const auto ret = m_surface.eglBackend()->importDmaBufAsTexture(*m_scanoutBuffer->buffer()->dmabufAttributes());
ret->setContentTransform(m_scanoutBufferTransform.combine(OutputTransform::FlipY));
ret->setContentTransform(offloadTransform().combine(OutputTransform::FlipY));
return ret;
} else {
return m_surface.texture();
@ -66,7 +66,7 @@ ColorDescription EglGbmLayer::colorDescription() const
return m_surface.colorDescription();
}
bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &size, OutputTransform transform, const ColorDescription &color)
bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color)
{
static bool valid;
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
@ -80,21 +80,17 @@ bool EglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceR
// kernel documentation says that
// "Devices that dont support subpixel plane coordinates can ignore the fractional part."
// so we need to make sure that doesn't cause a difference vs the composited result
m_bufferSourceBox = sourceRect.toRect();
if (sourceRect != m_bufferSourceBox) {
if (sourceRect() != sourceRect().toRect()) {
return false;
}
const auto neededTransform = transform.combine(m_pipeline->output()->transform().inverted());
const auto plane = m_pipeline->crtc()->primaryPlane();
if (neededTransform != OutputTransform::Kind::Normal && (!plane || !plane->supportsTransformation(neededTransform))) {
if (offloadTransform() != OutputTransform::Kind::Normal && (!plane || !plane->supportsTransformation(offloadTransform()))) {
return false;
}
// importing a buffer from another GPU without an explicit modifier can mess up the buffer format
if (buffer->dmabufAttributes()->modifier == DRM_FORMAT_MOD_INVALID && m_pipeline->gpu()->platform()->gpuCount() > 1) {
return false;
}
m_scanoutTransform = neededTransform;
m_scanoutBufferTransform = transform;
m_scanoutBuffer = m_pipeline->gpu()->importBuffer(buffer, FileDescriptor{});
if (m_scanoutBuffer && m_pipeline->testScanout()) {
m_surface.forgetDamage(); // TODO: Use absolute frame sequence numbers for indexing the DamageJournal. It's more flexible and less error-prone
@ -121,16 +117,6 @@ std::chrono::nanoseconds EglGbmLayer::queryRenderTime() const
return m_surface.queryRenderTime();
}
OutputTransform EglGbmLayer::hardwareTransform() const
{
return m_scanoutBuffer ? m_scanoutTransform : OutputTransform::Normal;
}
QRect EglGbmLayer::bufferSourceBox() const
{
return m_scanoutBuffer ? m_bufferSourceBox : QRect(QPoint(0, 0), m_surface.currentBuffer()->buffer()->size());
}
DrmDevice *EglGbmLayer::scanoutDevice() const
{
return m_pipeline->gpu()->drmDevice();

View file

@ -27,28 +27,21 @@ class EglGbmLayer : public DrmPipelineLayer
public:
EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
bool checkTestBuffer() override;
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
std::shared_ptr<GLTexture> texture() const override;
ColorDescription colorDescription() const;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
OutputTransform hardwareTransform() const override;
QRect bufferSourceBox() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &size, OutputTransform transform, const ColorDescription &color) override;
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override;
std::shared_ptr<DrmFramebuffer> m_scanoutBuffer;
// the transform the drm plane will apply to the buffer
OutputTransform m_scanoutTransform = OutputTransform::Kind::Normal;
// the output transform the buffer is made for
OutputTransform m_scanoutBufferTransform = OutputTransform::Kind::Normal;
QRect m_bufferSourceBox;
EglGbmLayerSurface m_surface;
};

View file

@ -442,6 +442,17 @@ DrmPipeline::Error DrmGpu::testPendingConfiguration()
return c1->crtcId.value() > c2->crtcId.value();
});
}
// reset all outputs to their most basic configuration (primary plane without scaling)
// for the test, and set the target rects appropriately
for (const auto output : std::as_const(m_drmOutputs)) {
if (!output->lease()) {
const auto primary = output->primaryLayer();
primary->setTargetRect(QRect(QPoint(0, 0), output->connector()->pipeline()->mode()->size()));
primary->setSourceRect(QRect(QPoint(0, 0), output->connector()->pipeline()->mode()->size()));
primary->setEnabled(true);
output->cursorLayer()->setEnabled(false);
}
}
return checkCrtcAssignment(connectors, crtcs);
}

View file

@ -9,6 +9,7 @@
#include "drm_layer.h"
#include "core/graphicsbuffer.h"
#include "drm_buffer.h"
#include "drm_output.h"
#include "drm_pipeline.h"
#include <QMatrix4x4>
@ -17,6 +18,11 @@
namespace KWin
{
DrmOutputLayer::DrmOutputLayer(Output *output)
: OutputLayer(output)
{
}
DrmOutputLayer::~DrmOutputLayer() = default;
std::shared_ptr<GLTexture> DrmOutputLayer::texture() const
@ -25,18 +31,8 @@ std::shared_ptr<GLTexture> DrmOutputLayer::texture() const
}
DrmPipelineLayer::DrmPipelineLayer(DrmPipeline *pipeline)
: m_pipeline(pipeline)
: DrmOutputLayer(pipeline->output())
, m_pipeline(pipeline)
{
}
OutputTransform DrmPipelineLayer::hardwareTransform() const
{
return OutputTransform::Kind::Normal;
}
QRect DrmPipelineLayer::bufferSourceBox() const
{
const auto buffer = currentBuffer();
return buffer ? QRect(QPoint(0, 0), currentBuffer()->buffer()->size()) : QRect();
}
}

View file

@ -24,6 +24,7 @@ class DrmPipeline;
class DrmOutputLayer : public OutputLayer
{
public:
explicit DrmOutputLayer(Output *output);
virtual ~DrmOutputLayer();
virtual std::shared_ptr<GLTexture> texture() const;
@ -37,8 +38,6 @@ public:
virtual bool checkTestBuffer() = 0;
virtual std::shared_ptr<DrmFramebuffer> currentBuffer() const = 0;
virtual OutputTransform hardwareTransform() const;
virtual QRect bufferSourceBox() const;
protected:
DrmPipeline *const m_pipeline;

View file

@ -211,21 +211,6 @@ DrmPipeline::Error DrmPipeline::prepareAtomicCommit(DrmAtomicCommit *commit, Com
return Error::None;
}
static QRect centerBuffer(const QSize &bufferSize, const QSize &modeSize)
{
const double widthScale = bufferSize.width() / double(modeSize.width());
const double heightScale = bufferSize.height() / double(modeSize.height());
if (widthScale > heightScale) {
const QSize size = bufferSize / widthScale;
const uint32_t yOffset = (modeSize.height() - size.height()) / 2;
return QRect(QPoint(0, yOffset), size);
} else {
const QSize size = bufferSize / heightScale;
const uint32_t xOffset = (modeSize.width() - size.width()) / 2;
return QRect(QPoint(xOffset, 0), size);
}
}
DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commit)
{
commit->setPresentationMode(m_pending.presentationMode);
@ -256,7 +241,7 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi
return Error::InvalidArguments;
}
const auto primary = m_pending.crtc->primaryPlane();
const auto transform = m_primaryLayer->hardwareTransform();
const auto transform = m_primaryLayer->offloadTransform();
const auto planeTransform = DrmPlane::outputTransformToPlaneTransform(transform);
if (primary->rotation.isValid()) {
if (!primary->rotation.hasEnum(planeTransform)) {
@ -266,7 +251,7 @@ DrmPipeline::Error DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commi
} else if (planeTransform != DrmPlane::Transformation::Rotate0) {
return Error::InvalidArguments;
}
primary->set(commit, m_primaryLayer->bufferSourceBox(), centerBuffer(transform.map(fb->buffer()->size()), m_pending.mode->size()));
primary->set(commit, m_primaryLayer->sourceRect().toRect(), m_primaryLayer->targetRect());
commit->addBuffer(m_pending.crtc->primaryPlane(), fb);
if (fb->buffer()->dmabufAttributes()->format == DRM_FORMAT_NV12) {
if (!primary->colorEncoding.isValid() || !primary->colorRange.isValid()) {
@ -284,7 +269,7 @@ void DrmPipeline::prepareAtomicCursor(DrmAtomicCommit *commit)
auto plane = m_pending.crtc->cursorPlane();
const auto layer = cursorLayer();
if (layer->isEnabled()) {
plane->set(commit, layer->bufferSourceBox(), QRect(layer->position().toPoint(), gpu()->cursorSize()));
plane->set(commit, layer->sourceRect().toRect(), layer->targetRect());
commit->addProperty(plane->crtcId, m_pending.crtc->id());
commit->addBuffer(plane, layer->currentBuffer());
if (plane->vmHotspotX.isValid() && plane->vmHotspotY.isValid()) {

View file

@ -30,7 +30,7 @@ DrmPipeline::Error DrmPipeline::presentLegacy()
return err;
}
const auto buffer = m_primaryLayer->currentBuffer();
if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) {
if (m_primaryLayer->sourceRect() != m_primaryLayer->targetRect() || m_primaryLayer->targetRect() != QRect(QPoint(0, 0), buffer->buffer()->size())) {
return Error::InvalidArguments;
}
auto commit = std::make_unique<DrmLegacyCommit>(this, buffer);
@ -54,7 +54,7 @@ DrmPipeline::Error DrmPipeline::legacyModeset()
return Error::TestBufferFailed;
}
const auto buffer = m_primaryLayer->currentBuffer();
if (m_primaryLayer->bufferSourceBox() != QRect(QPoint(0, 0), buffer->buffer()->size())) {
if (m_primaryLayer->sourceRect() != QRect(QPoint(0, 0), buffer->buffer()->size())) {
return Error::InvalidArguments;
}
auto commit = std::make_unique<DrmLegacyCommit>(this, buffer);
@ -184,8 +184,8 @@ bool DrmPipeline::setCursorLegacy()
struct drm_mode_cursor2 arg = {
.flags = DRM_MODE_CURSOR_BO | DRM_MODE_CURSOR_MOVE,
.crtc_id = m_pending.crtc->id(),
.x = int32_t(m_cursorLayer->position().x()),
.y = int32_t(m_cursorLayer->position().y()),
.x = int32_t(m_cursorLayer->targetRect().x()),
.y = int32_t(m_cursorLayer->targetRect().y()),
.width = (uint32_t)gpu()->cursorSize().width(),
.height = (uint32_t)gpu()->cursorSize().height(),
.handle = handle,

View file

@ -26,7 +26,7 @@ DrmQPainterLayer::DrmQPainterLayer(DrmPipeline *pipeline)
{
}
std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::doBeginFrame()
{
if (!doesSwapchainFit()) {
m_swapchain = std::make_shared<QPainterSwapchain>(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->mode()->size(), DRM_FORMAT_XRGB8888);
@ -46,7 +46,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmQPainterLayer::beginFrame()
};
}
bool DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool DrmQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{});
@ -111,7 +111,7 @@ DrmCursorQPainterLayer::DrmCursorQPainterLayer(DrmPipeline *pipeline)
{
}
std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::doBeginFrame()
{
if (!m_swapchain) {
m_swapchain = std::make_shared<QPainterSwapchain>(m_pipeline->gpu()->drmDevice()->allocator(), m_pipeline->gpu()->cursorSize(), DRM_FORMAT_ARGB8888);
@ -127,7 +127,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmCursorQPainterLayer::beginFrame()
};
}
bool DrmCursorQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool DrmCursorQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_currentFramebuffer = m_pipeline->gpu()->importBuffer(m_currentBuffer->buffer(), FileDescriptor{});
@ -169,11 +169,11 @@ QHash<uint32_t, QList<uint64_t>> DrmCursorQPainterLayer::supportedDrmFormats() c
}
DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output)
: m_output(output)
: DrmOutputLayer(output)
{
}
std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::doBeginFrame()
{
if (m_image.isNull() || m_image.size() != m_output->modeSize()) {
m_image = QImage(m_output->modeSize(), QImage::Format_RGB32);
@ -185,7 +185,7 @@ std::optional<OutputLayerBeginFrameInfo> DrmVirtualQPainterLayer::beginFrame()
};
}
bool DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool DrmVirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
return true;

View file

@ -27,8 +27,8 @@ class DrmQPainterLayer : public DrmPipelineLayer
public:
DrmQPainterLayer(DrmPipeline *pipeline);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
bool checkTestBuffer() override;
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
void releaseBuffers() override;
@ -52,8 +52,8 @@ class DrmCursorQPainterLayer : public DrmPipelineLayer
public:
DrmCursorQPainterLayer(DrmPipeline *pipeline);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
bool checkTestBuffer() override;
std::shared_ptr<DrmFramebuffer> currentBuffer() const override;
@ -75,8 +75,8 @@ class DrmVirtualQPainterLayer : public DrmOutputLayer
public:
DrmVirtualQPainterLayer(DrmVirtualOutput *output);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void releaseBuffers() override;
std::chrono::nanoseconds queryRenderTime() const override;
@ -85,7 +85,6 @@ public:
private:
QImage m_image;
DrmVirtualOutput *const m_output;
std::chrono::steady_clock::time_point m_renderStart;
std::chrono::nanoseconds m_renderTime;
};

View file

@ -27,14 +27,14 @@ namespace KWin
{
VirtualEglGbmLayer::VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output)
: m_output(output)
: DrmOutputLayer(output)
, m_eglBackend(eglBackend)
{
}
VirtualEglGbmLayer::~VirtualEglGbmLayer() = default;
std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::doBeginFrame()
{
// gbm surface
if (doesGbmSwapchainFit(m_gbmSwapchain.get())) {
@ -79,7 +79,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglGbmLayer::beginFrame()
};
}
bool VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool VirtualEglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
glFlush();
@ -134,7 +134,7 @@ std::shared_ptr<GLTexture> VirtualEglGbmLayer::texture() const
return nullptr;
}
bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color)
bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color)
{
static bool valid;
static const bool directScanoutDisabled = qEnvironmentVariableIntValue("KWIN_DRM_NO_DIRECT_SCANOUT", &valid) == 1 && valid;
@ -142,7 +142,7 @@ bool VirtualEglGbmLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &
return false;
}
if (sourceRect != QRectF(QPointF(0, 0), targetSize) || targetSize != m_output->modeSize() || targetSize != buffer->size()) {
if (sourceRect() != targetRect() || targetRect().topLeft() != QPointF(0, 0) || targetRect().size() != m_output->modeSize() || targetRect().size() != buffer->size() || offloadTransform() != OutputTransform::Kind::Normal) {
return false;
}
m_scanoutBuffer = buffer;

View file

@ -34,8 +34,8 @@ public:
VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output);
~VirtualEglGbmLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::shared_ptr<GLTexture> texture() const override;
void releaseBuffers() override;
@ -45,7 +45,7 @@ public:
const ColorDescription &colorDescription() const;
private:
bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) override;
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override;
std::shared_ptr<EglSwapchain> createGbmSwapchain() const;
bool doesGbmSwapchainFit(EglSwapchain *swapchain) const;
@ -58,7 +58,6 @@ private:
std::shared_ptr<EglSwapchainSlot> m_currentSlot;
std::unique_ptr<GLRenderTimeQuery> m_query;
DrmVirtualOutput *const m_output;
EglGbmBackend *const m_eglBackend;
};

View file

@ -24,8 +24,8 @@ namespace KWin
{
VirtualEglLayer::VirtualEglLayer(Output *output, VirtualEglBackend *backend)
: m_backend(backend)
, m_output(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -34,7 +34,7 @@ std::shared_ptr<GLTexture> VirtualEglLayer::texture() const
return m_current->texture();
}
std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::doBeginFrame()
{
m_backend->makeCurrent();
@ -62,7 +62,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualEglLayer::beginFrame()
};
}
bool VirtualEglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool VirtualEglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
glFlush(); // flush pending rendering commands.

View file

@ -30,8 +30,8 @@ class VirtualEglLayer : public OutputLayer
public:
VirtualEglLayer(Output *output, VirtualEglBackend *backend);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::shared_ptr<GLTexture> texture() const;
std::chrono::nanoseconds queryRenderTime() const override;
@ -40,7 +40,6 @@ public:
private:
VirtualEglBackend *const m_backend;
Output *m_output;
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_current;
std::unique_ptr<GLRenderTimeQuery> m_query;

View file

@ -21,7 +21,7 @@ namespace KWin
{
VirtualQPainterLayer::VirtualQPainterLayer(Output *output, VirtualQPainterBackend *backend)
: m_output(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -30,7 +30,7 @@ VirtualQPainterLayer::~VirtualQPainterLayer()
{
}
std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::doBeginFrame()
{
const QSize nativeSize(m_output->modeSize());
if (!m_swapchain || m_swapchain->size() != nativeSize) {
@ -49,7 +49,7 @@ std::optional<OutputLayerBeginFrameInfo> VirtualQPainterLayer::beginFrame()
};
}
bool VirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool VirtualQPainterLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
return true;

View file

@ -32,15 +32,14 @@ public:
VirtualQPainterLayer(Output *output, VirtualQPainterBackend *backend);
~VirtualQPainterLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
QImage *image();
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
Output *const m_output;
VirtualQPainterBackend *const m_backend;
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_current;

View file

@ -37,7 +37,7 @@ namespace Wayland
static const bool bufferAgeEnabled = qEnvironmentVariable("KWIN_USE_BUFFER_AGE") != QStringLiteral("0");
WaylandEglPrimaryLayer::WaylandEglPrimaryLayer(WaylandOutput *output, WaylandEglBackend *backend)
: m_waylandOutput(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -56,14 +56,14 @@ std::shared_ptr<GLTexture> WaylandEglPrimaryLayer::texture() const
return m_buffer->texture();
}
std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::doBeginFrame()
{
if (!m_backend->openglContext()->makeCurrent()) {
qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed";
return std::nullopt;
}
const QSize nativeSize = m_waylandOutput->modeSize();
const QSize nativeSize = m_output->modeSize();
if (!m_swapchain || m_swapchain->size() != nativeSize) {
const QHash<uint32_t, QList<uint64_t>> formatTable = m_backend->backend()->display()->linuxDmabuf()->formats();
uint32_t format = DRM_FORMAT_INVALID;
@ -102,7 +102,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglPrimaryLayer::beginFrame()
};
}
bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool WaylandEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Flush rendering commands to the dmabuf.
@ -116,14 +116,14 @@ bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegi
return true;
}
bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color)
bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color)
{
Q_ASSERT(!m_presentationBuffer);
// TODO use viewporter to relax this check
if (sourceRect != QRectF(QPointF(0, 0), targetSize) || targetSize != m_waylandOutput->modeSize()) {
if (sourceRect() != targetRect() || targetRect() != QRectF(QPointF(0, 0), m_output->modeSize())) {
return false;
}
if (transform != OutputTransform::Kind::Normal || color != ColorDescription::sRGB) {
if (offloadTransform() != OutputTransform::Kind::Normal || color != ColorDescription::sRGB) {
return false;
}
m_presentationBuffer = m_backend->backend()->importBuffer(buffer);
@ -132,10 +132,11 @@ bool WaylandEglPrimaryLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRec
void WaylandEglPrimaryLayer::present()
{
KWayland::Client::Surface *surface = m_waylandOutput->surface();
const auto waylandOutput = static_cast<WaylandOutput *>(m_output);
KWayland::Client::Surface *surface = waylandOutput->surface();
surface->attachBuffer(m_presentationBuffer);
surface->damage(m_damageJournal.lastDamage());
surface->setScale(std::ceil(m_waylandOutput->scale()));
surface->setScale(std::ceil(waylandOutput->scale()));
surface->commit();
m_presentationBuffer = nullptr;
}
@ -157,7 +158,7 @@ QHash<uint32_t, QList<uint64_t>> WaylandEglPrimaryLayer::supportedDrmFormats() c
}
WaylandEglCursorLayer::WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend)
: m_output(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -167,14 +168,14 @@ WaylandEglCursorLayer::~WaylandEglCursorLayer()
m_backend->openglContext()->makeCurrent();
}
std::optional<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::doBeginFrame()
{
if (!m_backend->openglContext()->makeCurrent()) {
qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed";
return std::nullopt;
}
const auto tmp = size().expandedTo(QSize(64, 64));
const auto tmp = targetRect().size().expandedTo(QSize(64, 64));
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
if (!m_swapchain || m_swapchain->size() != bufferSize) {
const QHash<uint32_t, QList<uint64_t>> formatTable = m_backend->backend()->display()->linuxDmabuf()->formats();
@ -213,7 +214,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandEglCursorLayer::beginFrame()
};
}
bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool WaylandEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
// Flush rendering commands to the dmabuf.
@ -222,7 +223,7 @@ bool WaylandEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegio
wl_buffer *buffer = m_backend->backend()->importBuffer(m_buffer->buffer());
Q_ASSERT(buffer);
m_output->cursor()->update(buffer, scale(), hotspot().toPoint());
static_cast<WaylandOutput *>(m_output)->cursor()->update(buffer, scale(), hotspot().toPoint());
EGLNativeFence releaseFence{m_backend->eglDisplayObject()};
m_swapchain->release(m_buffer, releaseFence.takeFileDescriptor());

View file

@ -42,15 +42,14 @@ public:
std::shared_ptr<GLTexture> texture() const;
void present();
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color) override;
bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color) override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
WaylandOutput *m_waylandOutput;
DamageJournal m_damageJournal;
std::shared_ptr<EglSwapchain> m_swapchain;
std::shared_ptr<EglSwapchainSlot> m_buffer;
@ -69,8 +68,8 @@ public:
WaylandEglCursorLayer(WaylandOutput *output, WaylandEglBackend *backend);
~WaylandEglCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -26,7 +26,8 @@ namespace Wayland
{
WaylandQPainterPrimaryLayer::WaylandQPainterPrimaryLayer(WaylandOutput *output, WaylandQPainterBackend *backend)
: m_waylandOutput(output)
: OutputLayer(output)
, m_waylandOutput(output)
, m_backend(backend)
{
}
@ -54,7 +55,7 @@ QRegion WaylandQPainterPrimaryLayer::accumulateDamage(int bufferAge) const
return m_damageJournal.accumulate(bufferAge, infiniteRegion());
}
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::doBeginFrame()
{
const QSize nativeSize(m_waylandOutput->modeSize());
if (!m_swapchain || m_swapchain->size() != nativeSize) {
@ -73,7 +74,7 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterPrimaryLayer::beginFrame
};
}
bool WaylandQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool WaylandQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_damageJournal.add(damagedRegion);
@ -96,7 +97,7 @@ QHash<uint32_t, QList<uint64_t>> WaylandQPainterPrimaryLayer::supportedDrmFormat
}
WaylandQPainterCursorLayer::WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend)
: m_output(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -105,9 +106,9 @@ WaylandQPainterCursorLayer::~WaylandQPainterCursorLayer()
{
}
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::doBeginFrame()
{
const auto tmp = size().expandedTo(QSize(64, 64));
const auto tmp = targetRect().size().expandedTo(QSize(64, 64));
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
if (!m_swapchain || m_swapchain->size() != bufferSize) {
m_swapchain = std::make_unique<QPainterSwapchain>(m_backend->graphicsBufferAllocator(), bufferSize, DRM_FORMAT_ARGB8888);
@ -125,13 +126,13 @@ std::optional<OutputLayerBeginFrameInfo> WaylandQPainterCursorLayer::beginFrame(
};
}
bool WaylandQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool WaylandQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
wl_buffer *buffer = m_output->backend()->importBuffer(m_back->buffer());
wl_buffer *buffer = static_cast<WaylandOutput *>(m_output)->backend()->importBuffer(m_back->buffer());
Q_ASSERT(buffer);
m_output->cursor()->update(buffer, scale(), hotspot().toPoint());
static_cast<WaylandOutput *>(m_output)->cursor()->update(buffer, scale(), hotspot().toPoint());
m_swapchain->release(m_back);
return true;
}

View file

@ -37,8 +37,8 @@ public:
WaylandQPainterPrimaryLayer(WaylandOutput *output, WaylandQPainterBackend *backend);
~WaylandQPainterPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -68,14 +68,13 @@ public:
WaylandQPainterCursorLayer(WaylandOutput *output, WaylandQPainterBackend *backend);
~WaylandQPainterCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
WaylandOutput *m_output;
WaylandQPainterBackend *m_backend;
std::unique_ptr<QPainterSwapchain> m_swapchain;
std::shared_ptr<QPainterSwapchainSlot> m_back;

View file

@ -31,16 +31,17 @@ namespace KWin
{
EglLayer::EglLayer(EglBackend *backend)
: m_backend(backend)
: OutputLayer(nullptr)
, m_backend(backend)
{
}
std::optional<OutputLayerBeginFrameInfo> EglLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> EglLayer::doBeginFrame()
{
return m_backend->beginFrame();
}
bool EglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool EglLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_backend->endFrame(renderedRegion, damagedRegion);
return true;

View file

@ -35,8 +35,8 @@ class EglLayer : public OutputLayer
public:
EglLayer(EglBackend *backend);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -99,16 +99,17 @@ bool SwapEventFilter::event(xcb_generic_event_t *event)
}
GlxLayer::GlxLayer(GlxBackend *backend)
: m_backend(backend)
: OutputLayer(nullptr)
, m_backend(backend)
{
}
std::optional<OutputLayerBeginFrameInfo> GlxLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> GlxLayer::doBeginFrame()
{
return m_backend->beginFrame();
return m_backend->doBeginFrame();
}
bool GlxLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool GlxLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_backend->endFrame(renderedRegion, damagedRegion);
return true;
@ -660,7 +661,7 @@ std::unique_ptr<SurfaceTexture> GlxBackend::createSurfaceTextureX11(SurfacePixma
return std::make_unique<GlxSurfaceTextureX11>(this, pixmap);
}
OutputLayerBeginFrameInfo GlxBackend::beginFrame()
OutputLayerBeginFrameInfo GlxBackend::doBeginFrame()
{
QRegion repaint;
makeCurrent();

View file

@ -63,8 +63,8 @@ class GlxLayer : public OutputLayer
public:
GlxLayer(GlxBackend *backend);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -84,7 +84,7 @@ public:
GlxBackend(::Display *display, X11StandaloneBackend *backend);
~GlxBackend() override;
std::unique_ptr<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
OutputLayerBeginFrameInfo beginFrame();
OutputLayerBeginFrameInfo doBeginFrame();
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
std::chrono::nanoseconds queryRenderTime();
void present(Output *output, const std::shared_ptr<OutputFrame> &frame) override;

View file

@ -22,7 +22,8 @@ namespace KWin
{
X11WindowedEglPrimaryLayer::X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
: m_output(output)
: OutputLayer(output)
, m_output(output)
, m_backend(backend)
{
}
@ -31,7 +32,7 @@ X11WindowedEglPrimaryLayer::~X11WindowedEglPrimaryLayer()
{
}
std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::doBeginFrame()
{
if (!m_backend->openglContext()->makeCurrent()) {
return std::nullopt;
@ -68,7 +69,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglPrimaryLayer::beginFrame(
};
}
bool X11WindowedEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool X11WindowedEglPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_query->end();
return true;
@ -129,7 +130,7 @@ QHash<uint32_t, QList<uint64_t>> X11WindowedEglPrimaryLayer::supportedDrmFormats
}
X11WindowedEglCursorLayer::X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output)
: m_output(output)
: OutputLayer(output)
, m_backend(backend)
{
}
@ -141,13 +142,13 @@ X11WindowedEglCursorLayer::~X11WindowedEglCursorLayer()
m_texture.reset();
}
std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::doBeginFrame()
{
if (!m_backend->openglContext()->makeCurrent()) {
return std::nullopt;
}
const auto tmp = size().expandedTo(QSize(64, 64));
const auto tmp = targetRect().size().expandedTo(QSize(64, 64));
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
if (!m_texture || m_texture->size() != bufferSize) {
m_texture = GLTexture::allocate(GL_RGBA8, bufferSize);
@ -166,7 +167,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedEglCursorLayer::beginFrame()
};
}
bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool X11WindowedEglCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
QImage buffer(m_framebuffer->size(), QImage::Format_RGBA8888_Premultiplied);
@ -174,7 +175,7 @@ bool X11WindowedEglCursorLayer::endFrame(const QRegion &renderedRegion, const QR
glReadPixels(0, 0, buffer.width(), buffer.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer.bits());
GLFramebuffer::popFramebuffer();
m_output->cursor()->update(buffer.mirrored(false, true), hotspot());
static_cast<X11WindowedOutput *>(m_output)->cursor()->update(buffer.mirrored(false, true), hotspot());
m_query->end();
return true;

View file

@ -28,8 +28,8 @@ public:
X11WindowedEglPrimaryLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output);
~X11WindowedEglPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -53,14 +53,13 @@ public:
X11WindowedEglCursorLayer(X11WindowedEglBackend *backend, X11WindowedOutput *output);
~X11WindowedEglCursorLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
private:
X11WindowedOutput *const m_output;
X11WindowedEglBackend *const m_backend;
std::unique_ptr<GLFramebuffer> m_framebuffer;
std::unique_ptr<GLTexture> m_texture;

View file

@ -23,7 +23,8 @@ namespace KWin
{
X11WindowedQPainterPrimaryLayer::X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output, X11WindowedQPainterBackend *backend)
: m_output(output)
: OutputLayer(output)
, m_output(output)
, m_backend(backend)
{
}
@ -32,7 +33,7 @@ X11WindowedQPainterPrimaryLayer::~X11WindowedQPainterPrimaryLayer()
{
}
std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::doBeginFrame()
{
const QSize bufferSize = m_output->modeSize();
if (!m_swapchain || m_swapchain->size() != bufferSize) {
@ -54,7 +55,7 @@ std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterPrimaryLayer::beginF
};
}
bool X11WindowedQPainterPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool X11WindowedQPainterPrimaryLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
return true;
@ -106,13 +107,14 @@ QHash<uint32_t, QList<uint64_t>> X11WindowedQPainterPrimaryLayer::supportedDrmFo
}
X11WindowedQPainterCursorLayer::X11WindowedQPainterCursorLayer(X11WindowedOutput *output)
: m_output(output)
: OutputLayer(output)
, m_output(output)
{
}
std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::beginFrame()
std::optional<OutputLayerBeginFrameInfo> X11WindowedQPainterCursorLayer::doBeginFrame()
{
const auto tmp = size().expandedTo(QSize(64, 64));
const auto tmp = targetRect().size().expandedTo(QSize(64, 64));
const QSize bufferSize(std::ceil(tmp.width()), std::ceil(tmp.height()));
if (m_buffer.size() != bufferSize) {
m_buffer = QImage(bufferSize, QImage::Format_ARGB32_Premultiplied);
@ -130,7 +132,7 @@ std::chrono::nanoseconds X11WindowedQPainterCursorLayer::queryRenderTime() const
return m_renderTime;
}
bool X11WindowedQPainterCursorLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
bool X11WindowedQPainterCursorLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
m_renderTime = std::chrono::steady_clock::now() - m_renderStart;
m_output->cursor()->update(m_buffer, hotspot());

View file

@ -34,8 +34,8 @@ public:
X11WindowedQPainterPrimaryLayer(X11WindowedOutput *output, X11WindowedQPainterBackend *backend);
~X11WindowedQPainterPrimaryLayer() override;
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;
@ -58,8 +58,8 @@ class X11WindowedQPainterCursorLayer : public OutputLayer
public:
explicit X11WindowedQPainterCursorLayer(X11WindowedOutput *output);
std::optional<OutputLayerBeginFrameInfo> beginFrame() override;
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::optional<OutputLayerBeginFrameInfo> doBeginFrame() override;
bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
std::chrono::nanoseconds queryRenderTime() const override;
DrmDevice *scanoutDevice() const override;
QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const override;

View file

@ -256,6 +256,21 @@ void WaylandCompositor::stop()
Q_EMIT compositingToggled(false);
}
static QRect centerBuffer(const QSizeF &bufferSize, const QSize &modeSize)
{
const double widthScale = bufferSize.width() / double(modeSize.width());
const double heightScale = bufferSize.height() / double(modeSize.height());
if (widthScale > heightScale) {
const QSize size = (bufferSize / widthScale).toSize();
const uint32_t yOffset = (modeSize.height() - size.height()) / 2;
return QRect(QPoint(0, yOffset), size);
} else {
const QSize size = (bufferSize / heightScale).toSize();
const uint32_t xOffset = (modeSize.width() - size.width()) / 2;
return QRect(QPoint(xOffset, 0), size);
}
}
void WaylandCompositor::composite(RenderLoop *renderLoop)
{
if (m_backend->checkGraphicsReset()) {
@ -305,6 +320,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop)
return sublayer->isVisible();
});
if (scanoutPossible) {
primaryLayer->setTargetRect(centerBuffer(output->transform().map(scanoutCandidate->size()), output->modeSize()));
directScanout = primaryLayer->attemptScanout(scanoutCandidate);
}
} else {
@ -312,6 +328,7 @@ void WaylandCompositor::composite(RenderLoop *renderLoop)
}
if (!directScanout) {
primaryLayer->setTargetRect(QRect(QPoint(0, 0), output->modeSize()));
if (auto beginInfo = primaryLayer->beginFrame()) {
auto &[renderTarget, repaint] = beginInfo.value();
@ -392,9 +409,8 @@ void WaylandCompositor::addOutput(Output *output)
bufferSize = *fixedSize;
nativeCursorRect = output->transform().map(QRectF(outputLocalRect.topLeft() * output->scale(), bufferSize), output->pixelSize());
}
outputLayer->setPosition(nativeCursorRect.topLeft());
outputLayer->setHotspot(output->transform().map(cursor->hotspot() * output->scale(), bufferSize));
outputLayer->setSize(bufferSize);
outputLayer->setTargetRect(QRect(nativeCursorRect.topLeft().toPoint(), bufferSize));
if (auto beginInfo = outputLayer->beginFrame()) {
const RenderTarget &renderTarget = beginInfo->renderTarget;
@ -437,8 +453,8 @@ void WaylandCompositor::addOutput(Output *output)
if (outputLayer) {
if (outputLayer->isEnabled()) {
const QRectF nativeCursorRect = output->transform()
.map(QRectF(outputLocalRect.topLeft() * output->scale(), outputLayer->size()), output->pixelSize());
outputLayer->setPosition(nativeCursorRect.topLeft());
.map(QRectF(outputLocalRect.topLeft() * output->scale(), outputLayer->targetRect().size()), output->pixelSize());
outputLayer->setTargetRect(QRect(nativeCursorRect.topLeft().toPoint(), outputLayer->targetRect().size()));
hardwareCursor = output->updateCursorLayer();
} else if (!cursorLayer->isVisible() && !forceSoftwareCursor) {
// this is for the case that the cursor wasn't visible because it was on a different output before

View file

@ -12,8 +12,8 @@
namespace KWin
{
OutputLayer::OutputLayer(QObject *parent)
: QObject(parent)
OutputLayer::OutputLayer(Output *output)
: m_output(output)
{
}
@ -37,16 +37,6 @@ void OutputLayer::setHotspot(const QPointF &hotspot)
m_hotspot = hotspot;
}
QSizeF OutputLayer::size() const
{
return m_size;
}
void OutputLayer::setSize(const QSizeF &size)
{
m_size = size;
}
std::optional<QSize> OutputLayer::fixedSize() const
{
return std::nullopt;
@ -72,7 +62,7 @@ bool OutputLayer::needsRepaint() const
return !m_repaints.isEmpty();
}
bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color)
bool OutputLayer::doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color)
{
return false;
}
@ -97,7 +87,11 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem)
surfaceItem->setScanoutHint(scanoutDevice(), supportedDrmFormats());
return false;
}
const bool ret = doAttemptScanout(buffer, surfaceItem->bufferSourceBox(), surfaceItem->destinationSize(), surfaceItem->bufferTransform(), surfaceItem->colorDescription());
m_sourceRect = surfaceItem->bufferSourceBox();
m_bufferTransform = surfaceItem->bufferTransform();
const auto desiredTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal;
m_offloadTransform = m_bufferTransform.combine(desiredTransform.inverted());
const bool ret = doAttemptScanout(buffer, surfaceItem->colorDescription());
if (ret) {
surfaceItem->resetDamage();
// ensure the pixmap is updated when direct scanout ends
@ -106,6 +100,19 @@ bool OutputLayer::attemptScanout(SurfaceItem *surfaceItem)
return ret;
}
std::optional<OutputLayerBeginFrameInfo> OutputLayer::beginFrame()
{
m_sourceRect = QRectF(QPointF(0, 0), m_targetRect.size());
m_bufferTransform = m_output ? m_output->transform() : OutputTransform::Kind::Normal;
m_offloadTransform = OutputTransform::Kind::Normal;
return doBeginFrame();
}
bool OutputLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
{
return doEndFrame(renderedRegion, damagedRegion);
}
void OutputLayer::notifyNoScanoutCandidate()
{
if (m_scanoutCandidate) {
@ -114,16 +121,6 @@ void OutputLayer::notifyNoScanoutCandidate()
}
}
void OutputLayer::setPosition(const QPointF &position)
{
m_position = position;
}
QPointF OutputLayer::position() const
{
return m_position;
}
void OutputLayer::setEnabled(bool enable)
{
m_enabled = enable;
@ -134,6 +131,36 @@ bool OutputLayer::isEnabled() const
return m_enabled;
}
QRectF OutputLayer::sourceRect() const
{
return m_sourceRect;
}
void OutputLayer::setSourceRect(const QRectF &rect)
{
m_sourceRect = rect;
}
OutputTransform OutputLayer::offloadTransform() const
{
return m_offloadTransform;
}
OutputTransform OutputLayer::bufferTransform() const
{
return m_bufferTransform;
}
QRect OutputLayer::targetRect() const
{
return m_targetRect;
}
void OutputLayer::setTargetRect(const QRect &rect)
{
m_targetRect = rect;
}
} // namespace KWin
#include "moc_outputlayer.cpp"

View file

@ -32,7 +32,7 @@ class KWIN_EXPORT OutputLayer : public QObject
{
Q_OBJECT
public:
explicit OutputLayer(QObject *parent = nullptr);
explicit OutputLayer(Output *output);
qreal scale() const;
void setScale(qreal scale);
@ -40,8 +40,6 @@ public:
QPointF hotspot() const;
void setHotspot(const QPointF &hotspot);
QSizeF size() const;
void setSize(const QSizeF &size);
/**
* For most drm drivers, the buffer used for the cursor has to have a fixed size.
* If such a fixed size is required by the backend, this function should return it
@ -53,20 +51,14 @@ public:
void addRepaint(const QRegion &region);
bool needsRepaint() const;
/**
* @arg position in device coordinates
*/
void setPosition(const QPointF &position);
QPointF position() const;
/**
* Enables or disables this layer. Note that disabling the primary layer will cause problems
*/
void setEnabled(bool enable);
bool isEnabled() const;
virtual std::optional<OutputLayerBeginFrameInfo> beginFrame() = 0;
virtual bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
std::optional<OutputLayerBeginFrameInfo> beginFrame();
bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
/**
* Tries to import the newest buffer of the surface for direct scanout
@ -87,16 +79,40 @@ public:
virtual DrmDevice *scanoutDevice() const = 0;
virtual QHash<uint32_t, QList<uint64_t>> supportedDrmFormats() const = 0;
/**
* Returns the source rect this output layer should sample from, in buffer local coordinates
*/
QRectF sourceRect() const;
void setSourceRect(const QRectF &rect);
/**
* Returns the target rect this output layer should be shown at, in device coordinates
*/
QRect targetRect() const;
void setTargetRect(const QRect &rect);
/**
* Returns the transform this layer will apply to content passed to it
*/
OutputTransform offloadTransform() const;
/**
* Returns the transform a buffer passed into this layer already has
*/
OutputTransform bufferTransform() const;
protected:
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const QRectF &sourceRect, const QSizeF &targetSize, OutputTransform transform, const ColorDescription &color);
virtual bool doAttemptScanout(GraphicsBuffer *buffer, const ColorDescription &color);
virtual std::optional<OutputLayerBeginFrameInfo> doBeginFrame() = 0;
virtual bool doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
QRegion m_repaints;
QPointF m_hotspot;
QPointF m_position;
QSizeF m_size;
QRectF m_sourceRect;
QRect m_targetRect;
qreal m_scale = 1.0;
bool m_enabled = false;
OutputTransform m_offloadTransform = OutputTransform::Kind::Normal;
OutputTransform m_bufferTransform = OutputTransform::Kind::Normal;
QPointer<SurfaceItem> m_scanoutCandidate;
Output *const m_output;
};
} // namespace KWin