renderbackend: move render methods to OutputLayer
This is in preparation to using multiple outputlayers per output
This commit is contained in:
parent
8e998a7cfa
commit
7358daa92c
38 changed files with 544 additions and 452 deletions
|
@ -79,7 +79,6 @@ QDebug operator<<(QDebug debug, const AbstractOutput *output)
|
|||
|
||||
AbstractOutput::AbstractOutput(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_layer(new OutputLayer(this))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -87,11 +86,6 @@ AbstractOutput::~AbstractOutput()
|
|||
{
|
||||
}
|
||||
|
||||
OutputLayer *AbstractOutput::layer() const
|
||||
{
|
||||
return m_layer;
|
||||
}
|
||||
|
||||
QUuid AbstractOutput::uuid() const
|
||||
{
|
||||
return QUuid();
|
||||
|
|
|
@ -26,7 +26,6 @@ class OutputChangeSetV2;
|
|||
namespace KWin
|
||||
{
|
||||
class EffectScreenImpl;
|
||||
class OutputLayer;
|
||||
class RenderLoop;
|
||||
|
||||
class KWIN_EXPORT GammaRamp
|
||||
|
@ -99,15 +98,6 @@ public:
|
|||
*/
|
||||
QRect mapFromGlobal(const QRect &rect) const;
|
||||
|
||||
/**
|
||||
* Returns a dummy OutputLayer corresponding to the primary plane.
|
||||
*
|
||||
* TODO: remove this. The Compositor should allocate and deallocate hardware planes
|
||||
* after the pre paint pass. Planes must be allocated based on the bounding rect, transform,
|
||||
* and visibility (for the cursor plane).
|
||||
*/
|
||||
OutputLayer *layer() const;
|
||||
|
||||
/**
|
||||
* Returns a short identifiable name of this output.
|
||||
*/
|
||||
|
@ -285,7 +275,6 @@ Q_SIGNALS:
|
|||
private:
|
||||
Q_DISABLE_COPY(AbstractOutput)
|
||||
EffectScreenImpl *m_effectScreen = nullptr;
|
||||
OutputLayer *m_layer;
|
||||
int m_directScanoutCount = 0;
|
||||
friend class EffectScreenImpl; // to access m_effectScreen
|
||||
};
|
||||
|
|
|
@ -16,28 +16,6 @@ namespace KWin
|
|||
|
||||
DrmOutputLayer::~DrmOutputLayer() = default;
|
||||
|
||||
void DrmOutputLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
bool DrmOutputLayer::scanout(SurfaceItem *surfaceItem)
|
||||
{
|
||||
Q_UNUSED(surfaceItem)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<QRegion> DrmOutputLayer::startRendering()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool DrmOutputLayer::endRendering(const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
return false;
|
||||
}
|
||||
|
||||
QRegion DrmOutputLayer::currentDamage() const
|
||||
{
|
||||
return {};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
#include "outputlayer.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QRegion>
|
||||
|
@ -21,25 +22,12 @@ class DrmBuffer;
|
|||
class GLTexture;
|
||||
class DrmPipeline;
|
||||
|
||||
class DrmOutputLayer : public QObject
|
||||
class DrmOutputLayer : public OutputLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~DrmOutputLayer();
|
||||
|
||||
virtual void aboutToStartPainting(const QRegion &damagedRegion);
|
||||
virtual std::optional<QRegion> startRendering();
|
||||
virtual bool endRendering(const QRegion &damagedRegion);
|
||||
|
||||
/**
|
||||
* attempts to directly scan out the current buffer of the surfaceItem
|
||||
* @returns true if scanout was successful
|
||||
* false if rendering is required
|
||||
*/
|
||||
virtual bool scanout(SurfaceItem *surfaceItem);
|
||||
|
||||
virtual QSharedPointer<GLTexture> texture() const;
|
||||
|
||||
virtual QRegion currentDamage() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -57,4 +57,14 @@ QSharedPointer<DrmBuffer> DrmLeaseEglGbmLayer::currentBuffer() const
|
|||
return m_buffer;
|
||||
}
|
||||
|
||||
QRegion DrmLeaseEglGbmLayer::beginFrame()
|
||||
{
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
void DrmLeaseEglGbmLayer::endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
Q_UNUSED(renderedRegion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ class DrmLeaseEglGbmLayer : public DrmPipelineLayer
|
|||
public:
|
||||
DrmLeaseEglGbmLayer(EglGbmBackend *backend, DrmPipeline *pipeline);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
|
||||
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
|
||||
|
|
|
@ -30,23 +30,23 @@ DrmQPainterLayer::DrmQPainterLayer(DrmQPainterBackend *backend, DrmPipeline *pip
|
|||
});
|
||||
}
|
||||
|
||||
std::optional<QRegion> DrmQPainterLayer::startRendering()
|
||||
QRegion DrmQPainterLayer::beginFrame()
|
||||
{
|
||||
if (!doesSwapchainFit()) {
|
||||
m_swapchain = QSharedPointer<DumbSwapchain>::create(m_pipeline->gpu(), m_pipeline->sourceSize(), DRM_FORMAT_XRGB8888);
|
||||
}
|
||||
QRegion needsRepaint;
|
||||
if (!m_swapchain->acquireBuffer(&needsRepaint)) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
return needsRepaint;
|
||||
}
|
||||
|
||||
bool DrmQPainterLayer::endRendering(const QRegion &damagedRegion)
|
||||
void DrmQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
m_currentDamage = damagedRegion;
|
||||
m_swapchain->releaseBuffer(m_swapchain->currentBuffer(), damagedRegion);
|
||||
return true;
|
||||
}
|
||||
|
||||
QSharedPointer<DrmBuffer> DrmQPainterLayer::testBuffer()
|
||||
|
@ -82,7 +82,7 @@ DrmVirtualQPainterLayer::DrmVirtualQPainterLayer(DrmVirtualOutput *output)
|
|||
{
|
||||
}
|
||||
|
||||
std::optional<QRegion> DrmVirtualQPainterLayer::startRendering()
|
||||
QRegion DrmVirtualQPainterLayer::beginFrame()
|
||||
{
|
||||
if (m_image.isNull() || m_image.size() != m_output->pixelSize()) {
|
||||
m_image = QImage(m_output->pixelSize(), QImage::Format_RGB32);
|
||||
|
@ -90,10 +90,10 @@ std::optional<QRegion> DrmVirtualQPainterLayer::startRendering()
|
|||
return QRegion();
|
||||
}
|
||||
|
||||
bool DrmVirtualQPainterLayer::endRendering(const QRegion &damagedRegion)
|
||||
void DrmVirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
m_currentDamage = damagedRegion;
|
||||
return true;
|
||||
}
|
||||
|
||||
QRegion DrmVirtualQPainterLayer::currentDamage() const
|
||||
|
@ -128,4 +128,14 @@ QSharedPointer<DrmBuffer> DrmLeaseQPainterLayer::currentBuffer() const
|
|||
return m_buffer;
|
||||
}
|
||||
|
||||
QRegion DrmLeaseQPainterLayer::beginFrame()
|
||||
{
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
void DrmLeaseQPainterLayer::endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
Q_UNUSED(renderedRegion)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ class DrmQPainterLayer : public DrmPipelineLayer, public QPainterLayer
|
|||
public:
|
||||
DrmQPainterLayer(DrmQPainterBackend *backend, DrmPipeline *pipeline);
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
QRegion currentDamage() const override;
|
||||
|
@ -52,8 +52,8 @@ class DrmVirtualQPainterLayer : public DrmOutputLayer, public QPainterLayer
|
|||
public:
|
||||
DrmVirtualQPainterLayer(DrmVirtualOutput *output);
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
|
||||
|
||||
QRegion currentDamage() const override;
|
||||
QImage *image() override;
|
||||
|
@ -69,6 +69,9 @@ class DrmLeaseQPainterLayer : public DrmPipelineLayer
|
|||
public:
|
||||
DrmLeaseQPainterLayer(DrmQPainterBackend *backend, DrmPipeline *pipeline);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &damagedRegion, const QRegion &renderedRegion) override;
|
||||
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
|
||||
|
|
|
@ -216,11 +216,6 @@ bool EglGbmBackend::initBufferConfigs()
|
|||
return false;
|
||||
}
|
||||
|
||||
void EglGbmBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion)
|
||||
{
|
||||
static_cast<DrmAbstractOutput *>(output)->outputLayer()->aboutToStartPainting(damagedRegion);
|
||||
}
|
||||
|
||||
SurfaceTexture *EglGbmBackend::createSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
|
||||
{
|
||||
return new BasicEGLSurfaceTextureInternal(this, pixmap);
|
||||
|
@ -231,33 +226,14 @@ SurfaceTexture *EglGbmBackend::createSurfaceTextureWayland(SurfacePixmapWayland
|
|||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
||||
}
|
||||
|
||||
QRegion EglGbmBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
return static_cast<DrmAbstractOutput *>(output)->outputLayer()->startRendering().value_or(QRegion());
|
||||
}
|
||||
|
||||
void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion,
|
||||
const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
|
||||
drmOutput->outputLayer()->endRendering(damagedRegion);
|
||||
}
|
||||
|
||||
void EglGbmBackend::present(AbstractOutput *output)
|
||||
{
|
||||
static_cast<DrmAbstractOutput *>(output)->present();
|
||||
}
|
||||
|
||||
bool EglGbmBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
|
||||
OutputLayer *EglGbmBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
|
||||
if (drmOutput->outputLayer()->scanout(surfaceItem)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return static_cast<DrmAbstractOutput *>(output)->outputLayer();
|
||||
}
|
||||
|
||||
QSharedPointer<GLTexture> EglGbmBackend::textureForOutput(AbstractOutput *output) const
|
||||
|
|
|
@ -64,12 +64,10 @@ public:
|
|||
SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||
SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
void init() override;
|
||||
bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem) override;
|
||||
bool prefer10bpc() const override;
|
||||
QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) override;
|
||||
QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) override;
|
||||
|
@ -84,9 +82,6 @@ public:
|
|||
Q_SIGNALS:
|
||||
void aboutToBeDestroyed();
|
||||
|
||||
protected:
|
||||
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
|
||||
|
||||
private:
|
||||
bool initializeEgl();
|
||||
bool initBufferConfigs();
|
||||
|
|
|
@ -61,7 +61,7 @@ void EglGbmLayer::destroyResources()
|
|||
m_oldGbmSurface.reset();
|
||||
}
|
||||
|
||||
std::optional<QRegion> EglGbmLayer::startRendering()
|
||||
QRegion EglGbmLayer::beginFrame()
|
||||
{
|
||||
m_scanoutBuffer.reset();
|
||||
// dmabuf feedback
|
||||
|
@ -81,14 +81,14 @@ std::optional<QRegion> EglGbmLayer::startRendering()
|
|||
m_gbmSurface = m_oldGbmSurface;
|
||||
} else {
|
||||
if (!createGbmSurface()) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
// dmabuf might work with the new surface
|
||||
m_importMode = MultiGpuImportMode::Dmabuf;
|
||||
}
|
||||
}
|
||||
if (!m_gbmSurface->makeContextCurrent()) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
auto repaintRegion = m_gbmSurface->repaintRegion();
|
||||
|
||||
|
@ -103,7 +103,7 @@ std::optional<QRegion> EglGbmLayer::startRendering()
|
|||
const auto format = m_eglBackend->gbmFormatForDrmFormat(m_gbmSurface->format());
|
||||
m_shadowBuffer = QSharedPointer<ShadowBuffer>::create(m_pipeline->sourceSize(), format);
|
||||
if (!m_shadowBuffer->isComplete()) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
} else {
|
||||
m_shadowBuffer.reset();
|
||||
|
@ -132,8 +132,9 @@ void EglGbmLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
|||
}
|
||||
}
|
||||
|
||||
bool EglGbmLayer::endRendering(const QRegion &damagedRegion)
|
||||
void EglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
if (m_shadowBuffer) {
|
||||
GLRenderTarget::popRenderTarget();
|
||||
// TODO handle m_pipeline->pending.bufferTransformation != Rotate0
|
||||
|
@ -152,7 +153,6 @@ bool EglGbmLayer::endRendering(const QRegion &damagedRegion)
|
|||
m_currentBuffer = buffer;
|
||||
m_currentDamage = damagedRegion;
|
||||
}
|
||||
return !buffer.isNull();
|
||||
}
|
||||
|
||||
QRegion EglGbmLayer::currentDamage() const
|
||||
|
@ -181,14 +181,11 @@ QSharedPointer<DrmBuffer> EglGbmLayer::testBuffer()
|
|||
|
||||
bool EglGbmLayer::renderTestBuffer()
|
||||
{
|
||||
if (!startRendering()) {
|
||||
return false;
|
||||
}
|
||||
const auto oldBuffer = m_currentBuffer;
|
||||
beginFrame();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (!endRendering(infiniteRegion())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
endFrame(QRegion(), infiniteRegion());
|
||||
return m_currentBuffer != oldBuffer;
|
||||
}
|
||||
|
||||
bool EglGbmLayer::createGbmSurface(uint32_t format, const QVector<uint64_t> &modifiers)
|
||||
|
|
|
@ -36,9 +36,9 @@ public:
|
|||
EglGbmLayer(EglGbmBackend *eglBackend, DrmPipeline *pipeline);
|
||||
~EglGbmLayer();
|
||||
|
||||
std::optional<QRegion> startRendering() override;
|
||||
QRegion beginFrame() override;
|
||||
void aboutToStartPainting(const QRegion &damagedRegion) override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
QSharedPointer<DrmBuffer> testBuffer() override;
|
||||
QSharedPointer<DrmBuffer> currentBuffer() const override;
|
||||
|
|
|
@ -39,24 +39,16 @@ QImage *DrmQPainterBackend::bufferForScreen(AbstractOutput *output)
|
|||
return dynamic_cast<QPainterLayer *>(drmOutput->outputLayer())->image();
|
||||
}
|
||||
|
||||
QRegion DrmQPainterBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
|
||||
return drmOutput->outputLayer()->startRendering().value_or(QRegion());
|
||||
}
|
||||
|
||||
void DrmQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damage)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
const auto drmOutput = static_cast<DrmAbstractOutput *>(output);
|
||||
drmOutput->outputLayer()->endRendering(damage);
|
||||
}
|
||||
|
||||
void DrmQPainterBackend::present(AbstractOutput *output)
|
||||
{
|
||||
static_cast<DrmAbstractOutput *>(output)->present();
|
||||
}
|
||||
|
||||
OutputLayer *DrmQPainterBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return static_cast<DrmAbstractOutput *>(output)->outputLayer();
|
||||
}
|
||||
|
||||
QSharedPointer<DrmPipelineLayer> DrmQPainterBackend::createDrmPipelineLayer(DrmPipeline *pipeline)
|
||||
{
|
||||
if (pipeline->output()) {
|
||||
|
|
|
@ -31,9 +31,8 @@ public:
|
|||
~DrmQPainterBackend();
|
||||
|
||||
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
QSharedPointer<DrmPipelineLayer> createDrmPipelineLayer(DrmPipeline *pipeline) override;
|
||||
QSharedPointer<DrmOutputLayer> createLayer(DrmVirtualOutput *output) override;
|
||||
|
|
|
@ -61,7 +61,7 @@ void VirtualEglGbmLayer::aboutToStartPainting(const QRegion &damagedRegion)
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<QRegion> VirtualEglGbmLayer::startRendering()
|
||||
QRegion VirtualEglGbmLayer::beginFrame()
|
||||
{
|
||||
// gbm surface
|
||||
if (doesGbmSurfaceFit(m_gbmSurface.data())) {
|
||||
|
@ -71,18 +71,18 @@ std::optional<QRegion> VirtualEglGbmLayer::startRendering()
|
|||
m_gbmSurface = m_oldGbmSurface;
|
||||
} else {
|
||||
if (!createGbmSurface()) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_gbmSurface->makeContextCurrent()) {
|
||||
return std::optional<QRegion>();
|
||||
return QRegion();
|
||||
}
|
||||
GLRenderTarget::pushRenderTarget(m_gbmSurface->renderTarget());
|
||||
return m_gbmSurface->repaintRegion();
|
||||
}
|
||||
|
||||
bool VirtualEglGbmLayer::endRendering(const QRegion &damagedRegion)
|
||||
void VirtualEglGbmLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
GLRenderTarget::popRenderTarget();
|
||||
const auto buffer = m_gbmSurface->swapBuffers(damagedRegion.intersected(m_output->geometry()));
|
||||
|
@ -90,7 +90,6 @@ bool VirtualEglGbmLayer::endRendering(const QRegion &damagedRegion)
|
|||
m_currentBuffer = buffer;
|
||||
m_currentDamage = damagedRegion;
|
||||
}
|
||||
return !buffer.isNull();
|
||||
}
|
||||
|
||||
QRegion VirtualEglGbmLayer::currentDamage() const
|
||||
|
|
|
@ -36,8 +36,8 @@ public:
|
|||
VirtualEglGbmLayer(EglGbmBackend *eglBackend, DrmVirtualOutput *output);
|
||||
|
||||
void aboutToStartPainting(const QRegion &damagedRegion) override;
|
||||
std::optional<QRegion> startRendering() override;
|
||||
bool endRendering(const QRegion &damagedRegion) override;
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
bool scanout(SurfaceItem *surfaceItem) override;
|
||||
|
||||
QRegion currentDamage() const override;
|
||||
|
|
|
@ -30,9 +30,26 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
VirtualOutputLayer::VirtualOutputLayer(EglGbmBackend *backend)
|
||||
: m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
QRegion VirtualOutputLayer::beginFrame()
|
||||
{
|
||||
return m_backend->beginFrame();
|
||||
}
|
||||
|
||||
void VirtualOutputLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
EglGbmBackend::EglGbmBackend(VirtualBackend *b)
|
||||
: AbstractEglBackend()
|
||||
, m_backend(b)
|
||||
, m_layer(new VirtualOutputLayer(this))
|
||||
{
|
||||
// Egl is always direct rendering
|
||||
setIsDirectRendering(true);
|
||||
|
@ -158,9 +175,8 @@ SurfaceTexture *EglGbmBackend::createSurfaceTextureWayland(SurfacePixmapWayland
|
|||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
||||
}
|
||||
|
||||
QRegion EglGbmBackend::beginFrame(AbstractOutput *output)
|
||||
QRegion EglGbmBackend::beginFrame()
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
if (!GLRenderTarget::currentRenderTarget()) {
|
||||
GLRenderTarget::pushRenderTarget(m_fbo);
|
||||
}
|
||||
|
@ -197,11 +213,10 @@ static void convertFromGLImage(QImage &img, int w, int h)
|
|||
img = img.mirrored();
|
||||
}
|
||||
|
||||
void EglGbmBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
OutputLayer *EglGbmBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
return m_layer.get();
|
||||
}
|
||||
|
||||
void EglGbmBackend::present(AbstractOutput *output)
|
||||
|
|
|
@ -9,12 +9,26 @@
|
|||
#ifndef KWIN_EGL_GBM_BACKEND_H
|
||||
#define KWIN_EGL_GBM_BACKEND_H
|
||||
#include "abstract_egl_backend.h"
|
||||
#include "outputlayer.h"
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class VirtualBackend;
|
||||
class GLTexture;
|
||||
class GLRenderTarget;
|
||||
class EglGbmBackend;
|
||||
|
||||
class VirtualOutputLayer : public OutputLayer
|
||||
{
|
||||
public:
|
||||
VirtualOutputLayer(EglGbmBackend *backend);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
private:
|
||||
EglGbmBackend *const m_backend;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief OpenGL Backend using Egl on a GBM surface.
|
||||
|
@ -28,11 +42,12 @@ public:
|
|||
~EglGbmBackend() override;
|
||||
SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||
SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
void init() override;
|
||||
|
||||
QRegion beginFrame();
|
||||
|
||||
private:
|
||||
bool initializeEgl();
|
||||
bool initBufferConfigs();
|
||||
|
@ -41,6 +56,7 @@ private:
|
|||
GLTexture *m_backBuffer = nullptr;
|
||||
GLRenderTarget *m_fbo = nullptr;
|
||||
int m_frameCounter = 0;
|
||||
QScopedPointer<VirtualOutputLayer> m_layer;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -17,6 +17,30 @@
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
VirtualQPainterLayer::VirtualQPainterLayer(AbstractOutput *output)
|
||||
: m_output(output)
|
||||
, m_image(output->pixelSize(), QImage::Format_RGB32)
|
||||
{
|
||||
m_image.fill(Qt::black);
|
||||
}
|
||||
|
||||
QRegion VirtualQPainterLayer::beginFrame()
|
||||
{
|
||||
return m_output->geometry();
|
||||
}
|
||||
|
||||
void VirtualQPainterLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
QImage *VirtualQPainterLayer::image()
|
||||
{
|
||||
return &m_image;
|
||||
}
|
||||
|
||||
VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
|
||||
: QPainterBackend()
|
||||
, m_backend(backend)
|
||||
|
@ -29,38 +53,29 @@ VirtualQPainterBackend::~VirtualQPainterBackend() = default;
|
|||
|
||||
QImage *VirtualQPainterBackend::bufferForScreen(AbstractOutput *output)
|
||||
{
|
||||
return &m_backBuffers[output];
|
||||
}
|
||||
|
||||
QRegion VirtualQPainterBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
return output->geometry();
|
||||
return m_outputs[output]->image();
|
||||
}
|
||||
|
||||
void VirtualQPainterBackend::createOutputs()
|
||||
{
|
||||
m_backBuffers.clear();
|
||||
m_outputs.clear();
|
||||
const auto outputs = m_backend->enabledOutputs();
|
||||
for (const auto &output : outputs) {
|
||||
QImage buffer(output->pixelSize(), QImage::Format_RGB32);
|
||||
buffer.fill(Qt::black);
|
||||
m_backBuffers.insert(output, buffer);
|
||||
m_outputs.insert(output, QSharedPointer<VirtualQPainterLayer>::create(output));
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
void VirtualQPainterBackend::present(AbstractOutput *output)
|
||||
{
|
||||
static_cast<VirtualOutput *>(output)->vsyncMonitor()->arm();
|
||||
|
||||
if (m_backend->saveFrames()) {
|
||||
m_backBuffers[output].save(QStringLiteral("%1/%s-%3.png").arg(m_backend->screenshotDirPath(), output->name(), QString::number(m_frameCounter++)));
|
||||
m_outputs[output]->image()->save(QStringLiteral("%1/%s-%3.png").arg(m_backend->screenshotDirPath(), output->name(), QString::number(m_frameCounter++)));
|
||||
}
|
||||
}
|
||||
|
||||
OutputLayer *VirtualQPainterBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return m_outputs[output].get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef KWIN_SCENE_QPAINTER_VIRTUAL_BACKEND_H
|
||||
#define KWIN_SCENE_QPAINTER_VIRTUAL_BACKEND_H
|
||||
|
||||
#include "outputlayer.h"
|
||||
#include "qpainterbackend.h"
|
||||
|
||||
#include <QMap>
|
||||
|
@ -20,6 +21,20 @@ namespace KWin
|
|||
|
||||
class VirtualBackend;
|
||||
|
||||
class VirtualQPainterLayer : public OutputLayer
|
||||
{
|
||||
public:
|
||||
VirtualQPainterLayer(AbstractOutput *output);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
QImage *image();
|
||||
|
||||
private:
|
||||
AbstractOutput *const m_output;
|
||||
QImage m_image;
|
||||
};
|
||||
|
||||
class VirtualQPainterBackend : public QPainterBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -28,14 +43,13 @@ public:
|
|||
~VirtualQPainterBackend() override;
|
||||
|
||||
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
private:
|
||||
void createOutputs();
|
||||
|
||||
QMap<AbstractOutput *, QImage> m_backBuffers;
|
||||
QMap<AbstractOutput *, QSharedPointer<VirtualQPainterLayer>> m_outputs;
|
||||
VirtualBackend *m_backend;
|
||||
int m_frameCounter = 0;
|
||||
};
|
||||
|
|
|
@ -44,13 +44,33 @@ namespace KWin
|
|||
namespace Wayland
|
||||
{
|
||||
|
||||
EglWaylandOutput::EglWaylandOutput(WaylandOutput *output, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_waylandOutput(output)
|
||||
static QVector<EGLint> regionToRects(const QRegion ®ion, AbstractWaylandOutput *output)
|
||||
{
|
||||
const int height = output->modeSize().height();
|
||||
const QMatrix4x4 matrix = WaylandOutput::logicalToNativeMatrix(output->rect(),
|
||||
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;
|
||||
}
|
||||
|
||||
EglWaylandOutput::EglWaylandOutput(WaylandOutput *output, EglWaylandBackend *backend)
|
||||
: m_waylandOutput(output)
|
||||
, m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
bool EglWaylandOutput::init(EglWaylandBackend *backend)
|
||||
bool EglWaylandOutput::init()
|
||||
{
|
||||
auto surface = m_waylandOutput->surface();
|
||||
const QSize nativeSize = m_waylandOutput->geometry().size() * m_waylandOutput->scale();
|
||||
|
@ -63,10 +83,10 @@ bool EglWaylandOutput::init(EglWaylandBackend *backend)
|
|||
m_renderTarget.reset(new GLRenderTarget(0, nativeSize));
|
||||
|
||||
EGLSurface eglSurface = EGL_NO_SURFACE;
|
||||
if (backend->havePlatformBase()) {
|
||||
eglSurface = eglCreatePlatformWindowSurfaceEXT(backend->eglDisplay(), backend->config(), (void *)overlay, nullptr);
|
||||
if (m_backend->havePlatformBase()) {
|
||||
eglSurface = eglCreatePlatformWindowSurfaceEXT(m_backend->eglDisplay(), m_backend->config(), (void *)overlay, nullptr);
|
||||
} else {
|
||||
eglSurface = eglCreateWindowSurface(backend->eglDisplay(), backend->config(), overlay, nullptr);
|
||||
eglSurface = eglCreateWindowSurface(m_backend->eglDisplay(), m_backend->config(), overlay, nullptr);
|
||||
}
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND) << "Create Window Surface failed";
|
||||
|
@ -83,6 +103,7 @@ bool EglWaylandOutput::init(EglWaylandBackend *backend)
|
|||
|
||||
EglWaylandOutput::~EglWaylandOutput()
|
||||
{
|
||||
wl_egl_window_destroy(m_overlay);
|
||||
}
|
||||
|
||||
GLRenderTarget *EglWaylandOutput::renderTarget() const
|
||||
|
@ -104,6 +125,76 @@ void EglWaylandOutput::resetBufferAge()
|
|||
m_bufferAge = 0;
|
||||
}
|
||||
|
||||
bool EglWaylandOutput::makeContextCurrent() const
|
||||
{
|
||||
if (m_eglSurface == EGL_NO_SURFACE) {
|
||||
return false;
|
||||
}
|
||||
if (eglMakeCurrent(m_backend->eglDisplay(), m_eglSurface, m_eglSurface, m_backend->context()) == EGL_FALSE) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed";
|
||||
return false;
|
||||
}
|
||||
EGLint error = eglGetError();
|
||||
if (error != EGL_SUCCESS) {
|
||||
qCWarning(KWIN_WAYLAND_BACKEND) << "Error occurred while creating context " << error;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QRegion EglWaylandOutput::beginFrame()
|
||||
{
|
||||
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||
makeContextCurrent();
|
||||
GLRenderTarget::pushRenderTarget(m_renderTarget.get());
|
||||
if (m_backend->supportsBufferAge()) {
|
||||
return m_damageJournal.accumulate(m_bufferAge, infiniteRegion());
|
||||
}
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
void EglWaylandOutput::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
m_damageJournal.add(damagedRegion);
|
||||
GLRenderTarget::popRenderTarget();
|
||||
}
|
||||
|
||||
void EglWaylandOutput::aboutToStartPainting(const QRegion &damage)
|
||||
{
|
||||
if (m_bufferAge > 0 && !damage.isEmpty() && m_backend->supportsPartialUpdate()) {
|
||||
QVector<EGLint> rects = regionToRects(damage, m_waylandOutput);
|
||||
const bool correct = eglSetDamageRegionKHR(m_backend->eglDisplay(), m_eglSurface,
|
||||
rects.data(), rects.count() / 4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EglWaylandOutput::present()
|
||||
{
|
||||
m_waylandOutput->surface()->setupFrameCallback();
|
||||
m_waylandOutput->surface()->setScale(std::ceil(m_waylandOutput->scale()));
|
||||
Q_EMIT m_waylandOutput->outputChange(m_damageJournal.lastDamage());
|
||||
|
||||
if (m_backend->supportsSwapBuffersWithDamage()) {
|
||||
QVector<EGLint> rects = regionToRects(m_damageJournal.lastDamage(), m_waylandOutput);
|
||||
if (!eglSwapBuffersWithDamageEXT(m_backend->eglDisplay(), m_eglSurface,
|
||||
rects.data(), rects.count() / 4)) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffersWithDamage() failed: %x", eglGetError());
|
||||
}
|
||||
} else {
|
||||
if (!eglSwapBuffers(m_backend->eglDisplay(), m_eglSurface)) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
}
|
||||
}
|
||||
|
||||
if (m_backend->supportsBufferAge()) {
|
||||
eglQuerySurface(m_backend->eglDisplay(), m_eglSurface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
|
||||
}
|
||||
}
|
||||
|
||||
EglWaylandBackend::EglWaylandBackend(WaylandBackend *b)
|
||||
: AbstractEglBackend()
|
||||
, m_backend(b)
|
||||
|
@ -123,13 +214,12 @@ EglWaylandBackend::EglWaylandBackend(WaylandBackend *b)
|
|||
|
||||
connect(m_backend, &WaylandBackend::outputAdded, this, &EglWaylandBackend::createEglWaylandOutput);
|
||||
connect(m_backend, &WaylandBackend::outputRemoved, this, [this](AbstractOutput *output) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [output](const EglWaylandOutput *o) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [output](const auto &o) {
|
||||
return o->m_waylandOutput == output;
|
||||
});
|
||||
if (it == m_outputs.end()) {
|
||||
return;
|
||||
}
|
||||
cleanupOutput(*it);
|
||||
m_outputs.erase(it);
|
||||
});
|
||||
}
|
||||
|
@ -141,28 +231,19 @@ EglWaylandBackend::~EglWaylandBackend()
|
|||
|
||||
void EglWaylandBackend::cleanupSurfaces()
|
||||
{
|
||||
for (auto o : qAsConst(m_outputs)) {
|
||||
cleanupOutput(o);
|
||||
}
|
||||
m_outputs.clear();
|
||||
}
|
||||
|
||||
bool EglWaylandBackend::createEglWaylandOutput(AbstractOutput *waylandOutput)
|
||||
{
|
||||
const auto &output = new EglWaylandOutput(static_cast<WaylandOutput *>(waylandOutput), this);
|
||||
if (!output->init(this)) {
|
||||
delete output;
|
||||
const auto output = QSharedPointer<EglWaylandOutput>::create(static_cast<WaylandOutput *>(waylandOutput), this);
|
||||
if (!output->init()) {
|
||||
return false;
|
||||
}
|
||||
m_outputs.insert(waylandOutput, output);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EglWaylandBackend::cleanupOutput(EglWaylandOutput *output)
|
||||
{
|
||||
wl_egl_window_destroy(output->m_overlay);
|
||||
}
|
||||
|
||||
bool EglWaylandBackend::initializeEgl()
|
||||
{
|
||||
initClientExtensions();
|
||||
|
@ -233,30 +314,10 @@ bool EglWaylandBackend::initRenderingContext()
|
|||
return false;
|
||||
}
|
||||
|
||||
auto *firstOutput = m_outputs.first();
|
||||
const auto &firstOutput = m_outputs.first();
|
||||
// set our first surface as the one for the abstract backend, just to make it happy
|
||||
setSurface(firstOutput->m_eglSurface);
|
||||
return makeContextCurrent(firstOutput);
|
||||
}
|
||||
|
||||
bool EglWaylandBackend::makeContextCurrent(EglWaylandOutput *output)
|
||||
{
|
||||
const EGLSurface eglSurface = output->m_eglSurface;
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
return false;
|
||||
}
|
||||
if (eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, context()) == EGL_FALSE) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND) << "Make Context Current failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint error = eglGetError();
|
||||
if (error != EGL_SUCCESS) {
|
||||
qCWarning(KWIN_WAYLAND_BACKEND) << "Error occurred while creating context " << error;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return firstOutput->makeContextCurrent();
|
||||
}
|
||||
|
||||
bool EglWaylandBackend::initBufferConfigs()
|
||||
|
@ -294,26 +355,6 @@ bool EglWaylandBackend::initBufferConfigs()
|
|||
return true;
|
||||
}
|
||||
|
||||
static QVector<EGLint> regionToRects(const QRegion ®ion, AbstractWaylandOutput *output)
|
||||
{
|
||||
const int height = output->modeSize().height();
|
||||
const QMatrix4x4 matrix = WaylandOutput::logicalToNativeMatrix(output->rect(),
|
||||
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;
|
||||
}
|
||||
|
||||
QSharedPointer<KWin::GLTexture> EglWaylandBackend::textureForOutput(KWin::AbstractOutput *output) const
|
||||
{
|
||||
QSharedPointer<GLTexture> texture(new GLTexture(GL_RGBA8, output->pixelSize()));
|
||||
|
@ -324,46 +365,6 @@ QSharedPointer<KWin::GLTexture> EglWaylandBackend::textureForOutput(KWin::Abstra
|
|||
return texture;
|
||||
}
|
||||
|
||||
void EglWaylandBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_ASSERT_X(output, "aboutToStartPainting", "not using per screen rendering");
|
||||
Q_ASSERT(m_outputs.contains(output));
|
||||
const auto &eglOutput = m_outputs[output];
|
||||
if (eglOutput->m_bufferAge > 0 && !damagedRegion.isEmpty() && supportsPartialUpdate()) {
|
||||
QVector<EGLint> rects = regionToRects(damagedRegion, eglOutput->m_waylandOutput);
|
||||
const bool correct = eglSetDamageRegionKHR(eglDisplay(), eglOutput->m_eglSurface,
|
||||
rects.data(), rects.count() / 4);
|
||||
if (!correct) {
|
||||
qCWarning(KWIN_WAYLAND_BACKEND) << "failed eglSetDamageRegionKHR" << eglGetError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EglWaylandBackend::presentOnSurface(EglWaylandOutput *output, const QRegion &damage)
|
||||
{
|
||||
WaylandOutput *waylandOutput = output->m_waylandOutput;
|
||||
|
||||
waylandOutput->surface()->setupFrameCallback();
|
||||
waylandOutput->surface()->setScale(std::ceil(waylandOutput->scale()));
|
||||
Q_EMIT waylandOutput->outputChange(damage);
|
||||
|
||||
if (supportsSwapBuffersWithDamage()) {
|
||||
QVector<EGLint> rects = regionToRects(damage, waylandOutput);
|
||||
if (!eglSwapBuffersWithDamageEXT(eglDisplay(), output->m_eglSurface,
|
||||
rects.data(), rects.count() / 4)) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffersWithDamage() failed: %x", eglGetError());
|
||||
}
|
||||
} else {
|
||||
if (!eglSwapBuffers(eglDisplay(), output->m_eglSurface)) {
|
||||
qCCritical(KWIN_WAYLAND_BACKEND, "eglSwapBuffers() failed: %x", eglGetError());
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
eglQuerySurface(eglDisplay(), output->m_eglSurface, EGL_BUFFER_AGE_EXT, &output->m_bufferAge);
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceTexture *EglWaylandBackend::createSurfaceTextureInternal(SurfacePixmapInternal *pixmap)
|
||||
{
|
||||
return new BasicEGLSurfaceTextureInternal(this, pixmap);
|
||||
|
@ -374,40 +375,14 @@ SurfaceTexture *EglWaylandBackend::createSurfaceTextureWayland(SurfacePixmapWayl
|
|||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
||||
}
|
||||
|
||||
QRegion EglWaylandBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
Q_ASSERT(m_outputs.contains(output));
|
||||
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
|
||||
|
||||
const auto &eglOutput = m_outputs[output];
|
||||
makeContextCurrent(eglOutput);
|
||||
|
||||
GLRenderTarget::pushRenderTarget(eglOutput->renderTarget());
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
return eglOutput->m_damageJournal.accumulate(eglOutput->m_bufferAge, infiniteRegion());
|
||||
}
|
||||
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
void EglWaylandBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_ASSERT(m_outputs.contains(output));
|
||||
Q_UNUSED(renderedRegion);
|
||||
|
||||
m_lastDamagedRegion = damagedRegion;
|
||||
GLRenderTarget::popRenderTarget();
|
||||
}
|
||||
|
||||
void EglWaylandBackend::present(AbstractOutput *output)
|
||||
{
|
||||
const auto &eglOutput = m_outputs[output];
|
||||
presentOnSurface(eglOutput, m_lastDamagedRegion);
|
||||
m_outputs[output]->present();
|
||||
}
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
eglOutput->m_damageJournal.add(m_lastDamagedRegion);
|
||||
}
|
||||
OutputLayer *EglWaylandBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return m_outputs[output].get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef KWIN_EGL_WAYLAND_BACKEND_H
|
||||
#define KWIN_EGL_WAYLAND_BACKEND_H
|
||||
#include "abstract_egl_backend.h"
|
||||
#include "outputlayer.h"
|
||||
#include "utils/damagejournal.h"
|
||||
// wayland
|
||||
#include <wayland-egl.h>
|
||||
|
@ -28,17 +29,22 @@ class WaylandBackend;
|
|||
class WaylandOutput;
|
||||
class EglWaylandBackend;
|
||||
|
||||
class EglWaylandOutput : public QObject
|
||||
class EglWaylandOutput : public OutputLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EglWaylandOutput(WaylandOutput *output, QObject *parent = nullptr);
|
||||
EglWaylandOutput(WaylandOutput *output, EglWaylandBackend *backend);
|
||||
~EglWaylandOutput() override;
|
||||
|
||||
bool init(EglWaylandBackend *backend);
|
||||
bool init();
|
||||
void updateSize();
|
||||
|
||||
GLRenderTarget *renderTarget() const;
|
||||
bool makeContextCurrent() const;
|
||||
void present();
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void aboutToStartPainting(const QRegion &damage) override;
|
||||
|
||||
private:
|
||||
void resetBufferAge();
|
||||
|
@ -49,6 +55,7 @@ private:
|
|||
int m_bufferAge = 0;
|
||||
DamageJournal m_damageJournal;
|
||||
QScopedPointer<GLRenderTarget> m_renderTarget;
|
||||
EglWaylandBackend *const m_backend;
|
||||
|
||||
friend class EglWaylandBackend;
|
||||
};
|
||||
|
@ -75,10 +82,9 @@ public:
|
|||
SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||
SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
void init() override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
bool havePlatformBase() const
|
||||
{
|
||||
|
@ -86,7 +92,6 @@ public:
|
|||
}
|
||||
|
||||
QSharedPointer<KWin::GLTexture> textureForOutput(KWin::AbstractOutput *output) const override;
|
||||
void aboutToStartPainting(AbstractOutput *output, const QRegion &damage) override;
|
||||
|
||||
private:
|
||||
bool initializeEgl();
|
||||
|
@ -96,14 +101,11 @@ private:
|
|||
bool createEglWaylandOutput(AbstractOutput *output);
|
||||
|
||||
void cleanupSurfaces() override;
|
||||
void cleanupOutput(EglWaylandOutput *output);
|
||||
|
||||
bool makeContextCurrent(EglWaylandOutput *output);
|
||||
void presentOnSurface(EglWaylandOutput *output, const QRegion &damagedRegion);
|
||||
|
||||
WaylandBackend *m_backend;
|
||||
QMap<AbstractOutput *, EglWaylandOutput *> m_outputs;
|
||||
QRegion m_lastDamagedRegion;
|
||||
QMap<AbstractOutput *, QSharedPointer<EglWaylandOutput>> m_outputs;
|
||||
bool m_havePlatformBase;
|
||||
friend class EglWaylandTexture;
|
||||
};
|
||||
|
|
|
@ -38,9 +38,8 @@ WaylandQPainterBufferSlot::~WaylandQPainterBufferSlot()
|
|||
buffer->setUsed(false);
|
||||
}
|
||||
|
||||
WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_waylandOutput(output)
|
||||
WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output)
|
||||
: m_waylandOutput(output)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -78,7 +77,7 @@ void WaylandQPainterOutput::updateSize(const QSize &size)
|
|||
m_slots.clear();
|
||||
}
|
||||
|
||||
void WaylandQPainterOutput::present(const QRegion &damage)
|
||||
void WaylandQPainterOutput::present()
|
||||
{
|
||||
for (WaylandQPainterBufferSlot *slot : qAsConst(m_slots)) {
|
||||
if (slot == m_back) {
|
||||
|
@ -90,11 +89,9 @@ void WaylandQPainterOutput::present(const QRegion &damage)
|
|||
|
||||
auto s = m_waylandOutput->surface();
|
||||
s->attachBuffer(m_back->buffer);
|
||||
s->damage(damage);
|
||||
s->damage(m_damageJournal.lastDamage());
|
||||
s->setScale(std::ceil(m_waylandOutput->scale()));
|
||||
s->commit();
|
||||
|
||||
m_damageJournal.add(damage);
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot *WaylandQPainterOutput::back() const
|
||||
|
@ -131,6 +128,19 @@ QRegion WaylandQPainterOutput::accumulateDamage(int bufferAge) const
|
|||
return m_damageJournal.accumulate(bufferAge, infiniteRegion());
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterOutput::beginFrame()
|
||||
{
|
||||
WaylandQPainterBufferSlot *slot = acquire();
|
||||
return accumulateDamage(slot->age);
|
||||
}
|
||||
|
||||
void WaylandQPainterOutput::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
|
||||
m_damageJournal.add(damagedRegion);
|
||||
}
|
||||
|
||||
WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
|
||||
: QPainterBackend()
|
||||
, m_backend(b)
|
||||
|
@ -142,13 +152,12 @@ WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
|
|||
}
|
||||
connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandQPainterBackend::createOutput);
|
||||
connect(m_backend, &WaylandBackend::outputRemoved, this, [this](AbstractOutput *waylandOutput) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [waylandOutput](WaylandQPainterOutput *output) {
|
||||
auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [waylandOutput](const auto &output) {
|
||||
return output->m_waylandOutput == waylandOutput;
|
||||
});
|
||||
if (it == m_outputs.end()) {
|
||||
return;
|
||||
}
|
||||
delete *it;
|
||||
m_outputs.erase(it);
|
||||
});
|
||||
}
|
||||
|
@ -159,36 +168,24 @@ WaylandQPainterBackend::~WaylandQPainterBackend()
|
|||
|
||||
void WaylandQPainterBackend::createOutput(AbstractOutput *waylandOutput)
|
||||
{
|
||||
auto *output = new WaylandQPainterOutput(static_cast<WaylandOutput *>(waylandOutput), this);
|
||||
const auto output = QSharedPointer<WaylandQPainterOutput>::create(static_cast<WaylandOutput *>(waylandOutput));
|
||||
output->init(m_backend->shmPool());
|
||||
m_outputs.insert(waylandOutput, output);
|
||||
}
|
||||
|
||||
void WaylandQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(renderedRegion)
|
||||
|
||||
m_lastDamagedRegion = damagedRegion;
|
||||
}
|
||||
|
||||
QImage *WaylandQPainterBackend::bufferForScreen(AbstractOutput *output)
|
||||
{
|
||||
return &m_outputs[output]->back()->image;
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
WaylandQPainterOutput *rendererOutput = m_outputs[output];
|
||||
Q_ASSERT(rendererOutput);
|
||||
|
||||
WaylandQPainterBufferSlot *slot = rendererOutput->acquire();
|
||||
return rendererOutput->accumulateDamage(slot->age);
|
||||
}
|
||||
|
||||
void WaylandQPainterBackend::present(AbstractOutput *output)
|
||||
{
|
||||
m_outputs[output]->present(m_lastDamagedRegion);
|
||||
m_outputs[output]->present();
|
||||
}
|
||||
|
||||
OutputLayer *WaylandQPainterBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return m_outputs[output].get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef KWIN_SCENE_QPAINTER_WAYLAND_BACKEND_H
|
||||
#define KWIN_SCENE_QPAINTER_WAYLAND_BACKEND_H
|
||||
|
||||
#include "outputlayer.h"
|
||||
#include "qpainterbackend.h"
|
||||
#include "utils/damagejournal.h"
|
||||
|
||||
|
@ -46,13 +47,15 @@ public:
|
|||
int age = 0;
|
||||
};
|
||||
|
||||
class WaylandQPainterOutput : public QObject
|
||||
class WaylandQPainterOutput : public OutputLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WaylandQPainterOutput(WaylandOutput *output, QObject *parent = nullptr);
|
||||
WaylandQPainterOutput(WaylandOutput *output);
|
||||
~WaylandQPainterOutput() override;
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
bool init(KWayland::Client::ShmPool *pool);
|
||||
void updateSize(const QSize &size);
|
||||
void remapBuffer();
|
||||
|
@ -60,7 +63,7 @@ public:
|
|||
WaylandQPainterBufferSlot *back() const;
|
||||
|
||||
WaylandQPainterBufferSlot *acquire();
|
||||
void present(const QRegion &damage);
|
||||
void present();
|
||||
|
||||
QRegion accumulateDamage(int bufferAge) const;
|
||||
|
||||
|
@ -84,17 +87,15 @@ public:
|
|||
|
||||
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
private:
|
||||
void createOutput(AbstractOutput *waylandOutput);
|
||||
void frameRendered();
|
||||
|
||||
WaylandBackend *m_backend;
|
||||
QRegion m_lastDamagedRegion;
|
||||
QMap<AbstractOutput *, WaylandQPainterOutput *> m_outputs;
|
||||
QMap<AbstractOutput *, QSharedPointer<WaylandQPainterOutput>> m_outputs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,9 +26,25 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
EglLayer::EglLayer(EglBackend *backend)
|
||||
: m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
QRegion EglLayer::beginFrame()
|
||||
{
|
||||
return m_backend->beginFrame();
|
||||
}
|
||||
|
||||
void EglLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
m_backend->endFrame(renderedRegion, damagedRegion);
|
||||
}
|
||||
|
||||
EglBackend::EglBackend(Display *display, X11StandalonePlatform *backend)
|
||||
: EglOnXBackend(display)
|
||||
, m_backend(backend)
|
||||
, m_layer(new EglLayer(this))
|
||||
{
|
||||
// There is no any way to determine when a buffer swap completes with EGL. Fallback
|
||||
// to software vblank events. Could we use the Present extension to get notified when
|
||||
|
@ -105,9 +121,8 @@ void EglBackend::screenGeometryChanged()
|
|||
m_renderTarget.reset(new GLRenderTarget(0, screens()->size()));
|
||||
}
|
||||
|
||||
QRegion EglBackend::beginFrame(AbstractOutput *output)
|
||||
QRegion EglBackend::beginFrame()
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
makeCurrent();
|
||||
|
||||
QRegion repaint;
|
||||
|
@ -122,10 +137,8 @@ QRegion EglBackend::beginFrame(AbstractOutput *output)
|
|||
return repaint;
|
||||
}
|
||||
|
||||
void EglBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
void EglBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge()) {
|
||||
m_damageJournal.add(damagedRegion);
|
||||
|
@ -179,6 +192,12 @@ void EglBackend::presentSurface(EGLSurface surface, const QRegion &damage, const
|
|||
}
|
||||
}
|
||||
|
||||
OutputLayer *EglBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
return m_layer.get();
|
||||
}
|
||||
|
||||
void EglBackend::vblank(std::chrono::nanoseconds timestamp)
|
||||
{
|
||||
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(m_backend->renderLoop());
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "eglonxbackend.h"
|
||||
#include "openglsurfacetexture_x11.h"
|
||||
#include "outputlayer.h"
|
||||
#include "utils/damagejournal.h"
|
||||
|
||||
#include <kwingltexture.h>
|
||||
|
@ -19,6 +20,19 @@ namespace KWin
|
|||
class EglPixmapTexturePrivate;
|
||||
class SoftwareVsyncMonitor;
|
||||
class X11StandalonePlatform;
|
||||
class EglBackend;
|
||||
|
||||
class EglLayer : public OutputLayer
|
||||
{
|
||||
public:
|
||||
EglLayer(EglBackend *backend);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
private:
|
||||
EglBackend *const m_backend;
|
||||
};
|
||||
|
||||
class EglBackend : public EglOnXBackend
|
||||
{
|
||||
|
@ -31,9 +45,10 @@ public:
|
|||
void init() override;
|
||||
|
||||
SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *texture) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
QRegion beginFrame();
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
private:
|
||||
void screenGeometryChanged();
|
||||
|
@ -46,6 +61,7 @@ private:
|
|||
QScopedPointer<GLRenderTarget> m_renderTarget;
|
||||
int m_bufferAge = 0;
|
||||
QRegion m_lastRenderedRegion;
|
||||
QScopedPointer<EglLayer> m_layer;
|
||||
};
|
||||
|
||||
class EglPixmapTexture : public GLTexture
|
||||
|
|
|
@ -103,6 +103,21 @@ bool SwapEventFilter::event(xcb_generic_event_t *event)
|
|||
return true;
|
||||
}
|
||||
|
||||
GlxLayer::GlxLayer(GlxBackend *backend)
|
||||
: m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
QRegion GlxLayer::beginFrame()
|
||||
{
|
||||
return m_backend->beginFrame();
|
||||
}
|
||||
|
||||
void GlxLayer::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
m_backend->endFrame(renderedRegion, damagedRegion);
|
||||
}
|
||||
|
||||
GlxBackend::GlxBackend(Display *display, X11StandalonePlatform *backend)
|
||||
: OpenGLBackend()
|
||||
, m_overlayWindow(kwinApp()->platform()->createOverlayWindow())
|
||||
|
@ -113,6 +128,7 @@ GlxBackend::GlxBackend(Display *display, X11StandalonePlatform *backend)
|
|||
, m_bufferAge(0)
|
||||
, m_x11Display(display)
|
||||
, m_backend(backend)
|
||||
, m_layer(new GlxLayer(this))
|
||||
{
|
||||
// Force initialization of GLX integration in the Qt's xcb backend
|
||||
// to make it call XESetWireToEvent callbacks, which is required
|
||||
|
@ -763,10 +779,8 @@ SurfaceTexture *GlxBackend::createSurfaceTextureX11(SurfacePixmapX11 *pixmap)
|
|||
return new GlxSurfaceTextureX11(this, pixmap);
|
||||
}
|
||||
|
||||
QRegion GlxBackend::beginFrame(AbstractOutput *output)
|
||||
QRegion GlxBackend::beginFrame()
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
QRegion repaint;
|
||||
makeCurrent();
|
||||
|
||||
|
@ -780,10 +794,8 @@ QRegion GlxBackend::beginFrame(AbstractOutput *output)
|
|||
return repaint;
|
||||
}
|
||||
|
||||
void GlxBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
void GlxBackend::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
|
||||
// Save the damaged region to history
|
||||
if (supportsBufferAge()) {
|
||||
m_damageJournal.add(damagedRegion);
|
||||
|
@ -846,6 +858,12 @@ OverlayWindow *GlxBackend::overlayWindow() const
|
|||
return m_overlayWindow;
|
||||
}
|
||||
|
||||
OutputLayer *GlxBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
return m_layer.get();
|
||||
}
|
||||
|
||||
GlxSurfaceTextureX11::GlxSurfaceTextureX11(GlxBackend *backend, SurfacePixmapX11 *texture)
|
||||
: OpenGLSurfaceTextureX11(backend, texture)
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define KWIN_GLX_BACKEND_H
|
||||
#include "openglbackend.h"
|
||||
#include "openglsurfacetexture_x11.h"
|
||||
#include "outputlayer.h"
|
||||
#include "utils/damagejournal.h"
|
||||
#include "x11eventfilter.h"
|
||||
|
||||
|
@ -30,6 +31,7 @@ namespace KWin
|
|||
class GlxPixmapTexturePrivate;
|
||||
class VsyncMonitor;
|
||||
class X11StandalonePlatform;
|
||||
class GlxBackend;
|
||||
|
||||
// GLX_MESA_swap_interval
|
||||
using glXSwapIntervalMESA_func = int (*)(unsigned int interval);
|
||||
|
@ -58,6 +60,18 @@ private:
|
|||
xcb_glx_drawable_t m_glxDrawable;
|
||||
};
|
||||
|
||||
class GlxLayer : public OutputLayer
|
||||
{
|
||||
public:
|
||||
GlxLayer(GlxBackend *backend);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
private:
|
||||
GlxBackend *const m_backend;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief OpenGL Backend using GLX over an X overlay window.
|
||||
*/
|
||||
|
@ -69,13 +83,14 @@ public:
|
|||
GlxBackend(Display *display, X11StandalonePlatform *backend);
|
||||
~GlxBackend() override;
|
||||
SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *pixmap) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
QRegion beginFrame();
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
void present(AbstractOutput *output) override;
|
||||
bool makeCurrent() override;
|
||||
void doneCurrent() override;
|
||||
OverlayWindow *overlayWindow() const override;
|
||||
void init() override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
Display *display() const
|
||||
{
|
||||
|
@ -119,6 +134,7 @@ private:
|
|||
Display *m_x11Display;
|
||||
X11StandalonePlatform *m_backend;
|
||||
VsyncMonitor *m_vsyncMonitor = nullptr;
|
||||
QScopedPointer<GlxLayer> m_layer;
|
||||
friend class GlxPixmapTexturePrivate;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,42 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
EglX11Output::EglX11Output(EglX11Backend *backend, AbstractOutput *output, EGLSurface surface)
|
||||
: m_eglSurface(surface)
|
||||
, m_renderTarget(new GLRenderTarget(0, output->pixelSize()))
|
||||
, m_output(output)
|
||||
, m_backend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
EglX11Output::~EglX11Output()
|
||||
{
|
||||
eglDestroySurface(m_backend->eglDisplay(), m_eglSurface);
|
||||
}
|
||||
|
||||
QRegion EglX11Output::beginFrame()
|
||||
{
|
||||
eglMakeCurrent(m_backend->eglDisplay(), m_eglSurface, m_eglSurface, m_backend->context());
|
||||
GLRenderTarget::pushRenderTarget(m_renderTarget.data());
|
||||
return m_output->rect();
|
||||
}
|
||||
|
||||
void EglX11Output::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
m_lastDamage = damagedRegion;
|
||||
}
|
||||
|
||||
EGLSurface EglX11Output::surface() const
|
||||
{
|
||||
return m_eglSurface;
|
||||
}
|
||||
|
||||
QRegion EglX11Output::lastDamage() const
|
||||
{
|
||||
return m_lastDamage;
|
||||
}
|
||||
|
||||
EglX11Backend::EglX11Backend(X11WindowedBackend *backend)
|
||||
: EglOnXBackend(backend->connection(), backend->display(), backend->rootWindow(), backend->screenNumer(), XCB_WINDOW_NONE)
|
||||
, m_backend(backend)
|
||||
|
@ -40,10 +76,7 @@ void EglX11Backend::init()
|
|||
|
||||
void EglX11Backend::cleanupSurfaces()
|
||||
{
|
||||
for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) {
|
||||
eglDestroySurface(eglDisplay(), (*it)->m_eglSurface);
|
||||
}
|
||||
qDeleteAll(m_outputs);
|
||||
m_outputs.clear();
|
||||
}
|
||||
|
||||
bool EglX11Backend::createSurfaces()
|
||||
|
@ -54,38 +87,19 @@ bool EglX11Backend::createSurfaces()
|
|||
if (s == EGL_NO_SURFACE) {
|
||||
return false;
|
||||
}
|
||||
EglX11Output *rendererOutput = new EglX11Output;
|
||||
rendererOutput->m_eglSurface = s;
|
||||
rendererOutput->m_renderTarget.reset(new GLRenderTarget(0, output->pixelSize()));
|
||||
m_outputs[output] = rendererOutput;
|
||||
m_outputs[output] = QSharedPointer<EglX11Output>::create(this, output, s);
|
||||
}
|
||||
if (m_outputs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
setSurface(m_outputs.first()->m_eglSurface);
|
||||
setSurface(m_outputs.first()->surface());
|
||||
return true;
|
||||
}
|
||||
|
||||
QRegion EglX11Backend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
const EglX11Output *rendererOutput = m_outputs[output];
|
||||
makeContextCurrent(rendererOutput->m_eglSurface);
|
||||
GLRenderTarget::pushRenderTarget(rendererOutput->m_renderTarget.data());
|
||||
return output->rect();
|
||||
}
|
||||
|
||||
void EglX11Backend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(damagedRegion)
|
||||
|
||||
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
|
||||
GLRenderTarget::popRenderTarget();
|
||||
m_lastRenderedRegion = renderedRegion;
|
||||
}
|
||||
|
||||
void EglX11Backend::present(AbstractOutput *output)
|
||||
{
|
||||
presentSurface(m_outputs[output]->m_eglSurface, m_lastRenderedRegion, output->geometry());
|
||||
const auto &renderOutput = m_outputs[output];
|
||||
presentSurface(renderOutput->surface(), renderOutput->lastDamage(), output->geometry());
|
||||
}
|
||||
|
||||
void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry)
|
||||
|
@ -106,6 +120,11 @@ void EglX11Backend::presentSurface(EGLSurface surface, const QRegion &damage, co
|
|||
}
|
||||
}
|
||||
|
||||
OutputLayer *EglX11Backend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return m_outputs[output].get();
|
||||
}
|
||||
|
||||
SurfaceTexture *EglX11Backend::createSurfaceTextureWayland(SurfacePixmapWayland *pixmap)
|
||||
{
|
||||
return new BasicEGLSurfaceTextureWayland(this, pixmap);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define KWIN_EGL_X11_BACKEND_H
|
||||
#include "eglonxbackend.h"
|
||||
#include "kwinglutils.h"
|
||||
#include "outputlayer.h"
|
||||
|
||||
#include <QMap>
|
||||
|
||||
|
@ -17,12 +18,26 @@ namespace KWin
|
|||
{
|
||||
|
||||
class X11WindowedBackend;
|
||||
class EglX11Backend;
|
||||
|
||||
class EglX11Output
|
||||
class EglX11Output : public OutputLayer
|
||||
{
|
||||
public:
|
||||
EglX11Output(EglX11Backend *backend, AbstractOutput *output, EGLSurface surface);
|
||||
~EglX11Output();
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
EGLSurface surface() const;
|
||||
QRegion lastDamage() const;
|
||||
|
||||
private:
|
||||
EGLSurface m_eglSurface;
|
||||
QScopedPointer<GLRenderTarget> m_renderTarget;
|
||||
QRegion m_lastDamage;
|
||||
|
||||
AbstractOutput *const m_output;
|
||||
EglX11Backend *const m_backend;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -39,9 +54,9 @@ public:
|
|||
SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override;
|
||||
SurfaceTexture *createSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override;
|
||||
void init() override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion);
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
protected:
|
||||
void cleanupSurfaces() override;
|
||||
|
@ -50,8 +65,7 @@ protected:
|
|||
private:
|
||||
void presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry);
|
||||
|
||||
QMap<AbstractOutput *, EglX11Output *> m_outputs;
|
||||
QRegion m_lastRenderedRegion;
|
||||
QMap<AbstractOutput *, QSharedPointer<EglX11Output>> m_outputs;
|
||||
X11WindowedBackend *m_backend;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,6 +15,26 @@
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
X11WindowedQPainterOutput::X11WindowedQPainterOutput(AbstractOutput *output, xcb_window_t window)
|
||||
: window(window)
|
||||
, buffer(output->pixelSize() * output->scale(), QImage::Format_RGB32)
|
||||
, m_output(output)
|
||||
{
|
||||
buffer.fill(Qt::black);
|
||||
}
|
||||
|
||||
QRegion X11WindowedQPainterOutput::beginFrame()
|
||||
{
|
||||
return m_output->rect();
|
||||
}
|
||||
|
||||
void X11WindowedQPainterOutput::endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
X11WindowedQPainterBackend::X11WindowedQPainterBackend(X11WindowedBackend *backend)
|
||||
: QPainterBackend()
|
||||
, m_backend(backend)
|
||||
|
@ -25,7 +45,7 @@ X11WindowedQPainterBackend::X11WindowedQPainterBackend(X11WindowedBackend *backe
|
|||
|
||||
X11WindowedQPainterBackend::~X11WindowedQPainterBackend()
|
||||
{
|
||||
qDeleteAll(m_outputs);
|
||||
m_outputs.clear();
|
||||
if (m_gc) {
|
||||
xcb_free_gc(m_backend->connection(), m_gc);
|
||||
}
|
||||
|
@ -33,15 +53,10 @@ X11WindowedQPainterBackend::~X11WindowedQPainterBackend()
|
|||
|
||||
void X11WindowedQPainterBackend::createOutputs()
|
||||
{
|
||||
qDeleteAll(m_outputs);
|
||||
m_outputs.clear();
|
||||
const auto &outputs = m_backend->outputs();
|
||||
for (const auto &x11Output : outputs) {
|
||||
Output *output = new Output;
|
||||
output->window = m_backend->windowForScreen(x11Output);
|
||||
output->buffer = QImage(x11Output->pixelSize() * x11Output->scale(), QImage::Format_RGB32);
|
||||
output->buffer.fill(Qt::black);
|
||||
m_outputs.insert(x11Output, output);
|
||||
m_outputs[x11Output] = QSharedPointer<X11WindowedQPainterOutput>::create(x11Output, m_backend->windowForScreen(x11Output));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,18 +65,6 @@ QImage *X11WindowedQPainterBackend::bufferForScreen(AbstractOutput *output)
|
|||
return &m_outputs[output]->buffer;
|
||||
}
|
||||
|
||||
QRegion X11WindowedQPainterBackend::beginFrame(AbstractOutput *output)
|
||||
{
|
||||
return output->rect();
|
||||
}
|
||||
|
||||
void X11WindowedQPainterBackend::endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(renderedRegion)
|
||||
Q_UNUSED(damagedRegion)
|
||||
}
|
||||
|
||||
void X11WindowedQPainterBackend::present(AbstractOutput *output)
|
||||
{
|
||||
static_cast<X11WindowedOutput *>(output)->vsyncMonitor()->arm();
|
||||
|
@ -73,7 +76,7 @@ void X11WindowedQPainterBackend::present(AbstractOutput *output)
|
|||
xcb_create_gc(c, m_gc, window, 0, nullptr);
|
||||
}
|
||||
|
||||
Output *rendererOutput = m_outputs[output];
|
||||
const auto &rendererOutput = m_outputs[output];
|
||||
Q_ASSERT(rendererOutput);
|
||||
|
||||
// TODO: only update changes?
|
||||
|
@ -82,4 +85,9 @@ void X11WindowedQPainterBackend::present(AbstractOutput *output)
|
|||
m_gc, buffer.width(), buffer.height(), 0, 0, 0, 24,
|
||||
buffer.sizeInBytes(), buffer.constBits());
|
||||
}
|
||||
|
||||
OutputLayer *X11WindowedQPainterBackend::primaryLayer(AbstractOutput *output)
|
||||
{
|
||||
return m_outputs[output].get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef KWIN_SCENE_QPAINTER_X11_BACKEND_H
|
||||
#define KWIN_SCENE_QPAINTER_X11_BACKEND_H
|
||||
|
||||
#include "outputlayer.h"
|
||||
#include "qpainterbackend.h"
|
||||
|
||||
#include <QImage>
|
||||
|
@ -23,6 +24,19 @@ namespace KWin
|
|||
|
||||
class X11WindowedBackend;
|
||||
|
||||
class X11WindowedQPainterOutput : public OutputLayer
|
||||
{
|
||||
public:
|
||||
X11WindowedQPainterOutput(AbstractOutput *output, xcb_window_t window);
|
||||
|
||||
QRegion beginFrame() override;
|
||||
void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
|
||||
xcb_window_t window;
|
||||
QImage buffer;
|
||||
AbstractOutput *const m_output;
|
||||
};
|
||||
|
||||
class X11WindowedQPainterBackend : public QPainterBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -31,20 +45,14 @@ public:
|
|||
~X11WindowedQPainterBackend() override;
|
||||
|
||||
QImage *bufferForScreen(AbstractOutput *output) override;
|
||||
QRegion beginFrame(AbstractOutput *output) override;
|
||||
void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
|
||||
void present(AbstractOutput *output) override;
|
||||
OutputLayer *primaryLayer(AbstractOutput *output) override;
|
||||
|
||||
private:
|
||||
void createOutputs();
|
||||
xcb_gcontext_t m_gc = XCB_NONE;
|
||||
X11WindowedBackend *m_backend;
|
||||
struct Output
|
||||
{
|
||||
xcb_window_t window;
|
||||
QImage buffer;
|
||||
};
|
||||
QMap<AbstractOutput *, Output *> m_outputs;
|
||||
QMap<AbstractOutput *, QSharedPointer<X11WindowedQPainterOutput>> m_outputs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -652,7 +652,7 @@ void Compositor::composite(RenderLoop *renderLoop)
|
|||
}
|
||||
|
||||
AbstractOutput *output = findOutput(renderLoop);
|
||||
OutputLayer *outputLayer = output->layer();
|
||||
OutputLayer *outputLayer = m_backend->primaryLayer(output);
|
||||
fTraceDuration("Paint (", output->name(), ")");
|
||||
|
||||
RenderLayer *superLayer = m_superlayers[renderLoop];
|
||||
|
@ -670,7 +670,7 @@ void Compositor::composite(RenderLoop *renderLoop)
|
|||
return sublayer->isVisible();
|
||||
});
|
||||
if (scanoutPossible && !output->directScanoutInhibited()) {
|
||||
directScanout = m_backend->scanout(output, scanoutCandidate);
|
||||
directScanout = outputLayer->scanout(scanoutCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -679,12 +679,12 @@ void Compositor::composite(RenderLoop *renderLoop)
|
|||
outputLayer->resetRepaints();
|
||||
preparePaintPass(superLayer, &surfaceDamage);
|
||||
|
||||
const QRegion repair = m_backend->beginFrame(output);
|
||||
const QRegion repair = outputLayer->beginFrame();
|
||||
const QRegion bufferDamage = surfaceDamage.united(repair).intersected(superLayer->rect());
|
||||
m_backend->aboutToStartPainting(output, bufferDamage);
|
||||
outputLayer->aboutToStartPainting(bufferDamage);
|
||||
|
||||
paintPass(superLayer, bufferDamage);
|
||||
m_backend->endFrame(output, bufferDamage, surfaceDamage);
|
||||
outputLayer->endFrame(bufferDamage, surfaceDamage);
|
||||
}
|
||||
renderLoop->endFrame();
|
||||
|
||||
|
|
|
@ -29,4 +29,15 @@ void OutputLayer::resetRepaints()
|
|||
m_repaints = QRegion();
|
||||
}
|
||||
|
||||
void OutputLayer::aboutToStartPainting(const QRegion &damage)
|
||||
{
|
||||
Q_UNUSED(damage)
|
||||
}
|
||||
|
||||
bool OutputLayer::scanout(SurfaceItem *surfaceItem)
|
||||
{
|
||||
Q_UNUSED(surfaceItem)
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
class SurfaceItem;
|
||||
|
||||
class KWIN_EXPORT OutputLayer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OutputLayer(QObject *parent = nullptr);
|
||||
|
||||
|
@ -25,6 +26,22 @@ public:
|
|||
void resetRepaints();
|
||||
void addRepaint(const QRegion ®ion);
|
||||
|
||||
/**
|
||||
* Notifies about starting to paint.
|
||||
*
|
||||
* @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
|
||||
*/
|
||||
virtual void aboutToStartPainting(const QRegion &damage);
|
||||
|
||||
virtual QRegion beginFrame() = 0;
|
||||
virtual void endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
|
||||
|
||||
/**
|
||||
* Tries to import the newest buffer of the surface for direct scanout
|
||||
* Returns @c true if scanout succeeds, @c false if rendering is necessary
|
||||
*/
|
||||
virtual bool scanout(SurfaceItem *surfaceItem);
|
||||
|
||||
private:
|
||||
QRegion m_repaints;
|
||||
};
|
||||
|
|
|
@ -24,17 +24,4 @@ bool RenderBackend::checkGraphicsReset()
|
|||
return false;
|
||||
}
|
||||
|
||||
void RenderBackend::aboutToStartPainting(AbstractOutput *output, const QRegion &damage)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(damage)
|
||||
}
|
||||
|
||||
bool RenderBackend::scanout(AbstractOutput *output, SurfaceItem *surfaceItem)
|
||||
{
|
||||
Q_UNUSED(output)
|
||||
Q_UNUSED(surfaceItem)
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace KWin
|
|||
|
||||
class AbstractOutput;
|
||||
class OverlayWindow;
|
||||
class SurfaceItem;
|
||||
class OutputLayer;
|
||||
|
||||
/**
|
||||
* The RenderBackend class is the base class for all rendering backends.
|
||||
|
@ -32,22 +32,8 @@ public:
|
|||
|
||||
virtual bool checkGraphicsReset();
|
||||
|
||||
/**
|
||||
* Notifies about starting to paint.
|
||||
*
|
||||
* @p damage contains the reported damage as suggested by windows and effects on prepaint calls.
|
||||
*/
|
||||
virtual void aboutToStartPainting(AbstractOutput *output, const QRegion &damage);
|
||||
|
||||
virtual QRegion beginFrame(AbstractOutput *output) = 0;
|
||||
virtual void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) = 0;
|
||||
virtual OutputLayer *primaryLayer(AbstractOutput *output) = 0;
|
||||
virtual void present(AbstractOutput *output) = 0;
|
||||
|
||||
/**
|
||||
* Tries to directly scan out a surface to the screen
|
||||
* Returns @c true if scanout succeeds, @c false if rendering is necessary
|
||||
*/
|
||||
virtual bool scanout(AbstractOutput *output, SurfaceItem *surfaceItem);
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -76,6 +76,11 @@ public:
|
|||
return region;
|
||||
}
|
||||
|
||||
QRegion lastDamage() const
|
||||
{
|
||||
return m_log.first();
|
||||
}
|
||||
|
||||
private:
|
||||
QList<QRegion> m_log;
|
||||
int m_capacity = 10;
|
||||
|
|
Loading…
Reference in a new issue