platforms/wayland: Add support for buffer age in qpainter backend
This commit is contained in:
parent
1cbf232b98
commit
d2b6d7ee59
4 changed files with 81 additions and 66 deletions
|
@ -362,17 +362,7 @@ QRegion EglWaylandBackend::beginFrame(int screenId)
|
|||
auto *output = m_outputs.at(screenId);
|
||||
makeContextCurrent(output);
|
||||
if (supportsBufferAge()) {
|
||||
QRegion region;
|
||||
|
||||
// Note: An age of zero means the buffer contents are undefined
|
||||
if (output->m_bufferAge > 0 && output->m_bufferAge <= output->m_damageHistory.count()) {
|
||||
for (int i = 0; i < output->m_bufferAge - 1; i++)
|
||||
region |= output->m_damageHistory[i];
|
||||
} else {
|
||||
region = output->m_waylandOutput->geometry();
|
||||
}
|
||||
|
||||
return region;
|
||||
return output->m_damageJournal.accumulate(output->m_bufferAge, output->m_waylandOutput->geometry());
|
||||
}
|
||||
return QRegion();
|
||||
}
|
||||
|
@ -385,11 +375,7 @@ void EglWaylandBackend::endFrame(int screenId, const QRegion &renderedRegion, co
|
|||
presentOnSurface(output, damage);
|
||||
|
||||
if (supportsBufferAge()) {
|
||||
if (output->m_damageHistory.count() > 10) {
|
||||
output->m_damageHistory.removeLast();
|
||||
}
|
||||
|
||||
output->m_damageHistory.prepend(damage);
|
||||
output->m_damageJournal.add(damage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef KWIN_EGL_WAYLAND_BACKEND_H
|
||||
#define KWIN_EGL_WAYLAND_BACKEND_H
|
||||
#include "abstract_egl_backend.h"
|
||||
#include "utils.h"
|
||||
// wayland
|
||||
#include <wayland-egl.h>
|
||||
|
||||
|
@ -41,10 +42,7 @@ private:
|
|||
wl_egl_window *m_overlay = nullptr;
|
||||
EGLSurface m_eglSurface = EGL_NO_SURFACE;
|
||||
int m_bufferAge = 0;
|
||||
/**
|
||||
* @brief The damage history for the past 10 frames.
|
||||
*/
|
||||
QVector<QRegion> m_damageHistory;
|
||||
DamageJournal m_damageJournal;
|
||||
|
||||
friend class EglWaylandBackend;
|
||||
};
|
||||
|
|
|
@ -25,6 +25,18 @@ namespace KWin
|
|||
namespace Wayland
|
||||
{
|
||||
|
||||
WaylandQPainterBufferSlot::WaylandQPainterBufferSlot(QSharedPointer<KWayland::Client::Buffer> buffer)
|
||||
: buffer(buffer)
|
||||
, image(buffer->address(), buffer->size().width(), buffer->size().height(), QImage::Format_RGB32)
|
||||
{
|
||||
buffer->setUsed(true);
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot::~WaylandQPainterBufferSlot()
|
||||
{
|
||||
buffer->setUsed(false);
|
||||
}
|
||||
|
||||
WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_waylandOutput(output)
|
||||
|
@ -33,15 +45,13 @@ WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output, QObject *par
|
|||
|
||||
WaylandQPainterOutput::~WaylandQPainterOutput()
|
||||
{
|
||||
if (m_buffer) {
|
||||
m_buffer.toStrongRef()->setUsed(false);
|
||||
}
|
||||
qDeleteAll(m_slots);
|
||||
m_slots.clear();
|
||||
}
|
||||
|
||||
bool WaylandQPainterOutput::init(KWayland::Client::ShmPool *pool)
|
||||
{
|
||||
m_pool = pool;
|
||||
m_backBuffer = QImage(QSize(), QImage::Format_RGB32);
|
||||
|
||||
connect(pool, &KWayland::Client::ShmPool::poolResized, this, &WaylandQPainterOutput::remapBuffer);
|
||||
connect(m_waylandOutput, &WaylandOutput::sizeChanged, this, &WaylandQPainterOutput::updateSize);
|
||||
|
@ -51,67 +61,73 @@ bool WaylandQPainterOutput::init(KWayland::Client::ShmPool *pool)
|
|||
|
||||
void WaylandQPainterOutput::remapBuffer()
|
||||
{
|
||||
if (!m_buffer) {
|
||||
return;
|
||||
}
|
||||
auto b = m_buffer.toStrongRef();
|
||||
if (!b->isUsed()){
|
||||
return;
|
||||
}
|
||||
const QSize size = m_backBuffer.size();
|
||||
m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32);
|
||||
qCDebug(KWIN_WAYLAND_BACKEND) << "Remapped back buffer of surface" << m_waylandOutput->surface();
|
||||
|
||||
const QSize nativeSize(m_waylandOutput->geometry().size() * m_waylandOutput->scale());
|
||||
for (WaylandQPainterBufferSlot *slot : qAsConst(m_slots)) {
|
||||
slot->image = QImage(slot->buffer->address(), nativeSize.width(), nativeSize.height(), QImage::Format_ARGB32);
|
||||
}
|
||||
}
|
||||
|
||||
void WaylandQPainterOutput::updateSize(const QSize &size)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
if (!m_buffer) {
|
||||
return;
|
||||
}
|
||||
m_buffer.toStrongRef()->setUsed(false);
|
||||
m_buffer.clear();
|
||||
m_back = nullptr;
|
||||
qDeleteAll(m_slots);
|
||||
m_slots.clear();
|
||||
}
|
||||
|
||||
void WaylandQPainterOutput::present(const QRegion &damage)
|
||||
{
|
||||
for (WaylandQPainterBufferSlot *slot : qAsConst(m_slots)) {
|
||||
if (slot == m_back) {
|
||||
slot->age = 1;
|
||||
} else if (slot->age > 0) {
|
||||
slot->age++;
|
||||
}
|
||||
}
|
||||
|
||||
auto s = m_waylandOutput->surface();
|
||||
s->attachBuffer(m_buffer);
|
||||
s->attachBuffer(m_back->buffer);
|
||||
s->damage(damage);
|
||||
s->setScale(std::ceil(m_waylandOutput->scale()));
|
||||
s->commit();
|
||||
|
||||
m_damageJournal.add(damage);
|
||||
}
|
||||
|
||||
void WaylandQPainterOutput::prepareRenderingFrame()
|
||||
WaylandQPainterBufferSlot *WaylandQPainterOutput::back() const
|
||||
{
|
||||
if (m_buffer) {
|
||||
auto b = m_buffer.toStrongRef();
|
||||
if (b->isReleased()) {
|
||||
// we can re-use this buffer
|
||||
b->setReleased(false);
|
||||
return;
|
||||
} else {
|
||||
// buffer is still in use, get a new one
|
||||
b->setUsed(false);
|
||||
return m_back;
|
||||
}
|
||||
|
||||
WaylandQPainterBufferSlot *WaylandQPainterOutput::acquire()
|
||||
{
|
||||
for (WaylandQPainterBufferSlot *slot : qAsConst(m_slots)) {
|
||||
if (slot->buffer->isReleased()) {
|
||||
m_back = slot;
|
||||
slot->buffer->setReleased(false);
|
||||
return m_back;
|
||||
}
|
||||
}
|
||||
m_buffer.clear();
|
||||
|
||||
const QSize nativeSize(m_waylandOutput->geometry().size() * m_waylandOutput->scale());
|
||||
|
||||
m_buffer = m_pool->getBuffer(nativeSize, nativeSize.width() * 4);
|
||||
if (!m_buffer) {
|
||||
auto buffer = m_pool->getBuffer(nativeSize, nativeSize.width() * 4).toStrongRef();
|
||||
if (!buffer) {
|
||||
qCDebug(KWIN_WAYLAND_BACKEND) << "Did not get a new Buffer from Shm Pool";
|
||||
m_backBuffer = QImage();
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto b = m_buffer.toStrongRef();
|
||||
b->setUsed(true);
|
||||
m_back = new WaylandQPainterBufferSlot(buffer);
|
||||
m_slots.append(m_back);
|
||||
|
||||
m_backBuffer = QImage(b->address(), nativeSize.width(), nativeSize.height(), QImage::Format_RGB32);
|
||||
m_backBuffer.fill(Qt::transparent);
|
||||
// qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer for output surface" << m_waylandOutput->surface();
|
||||
return m_back;
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterOutput::accumulateDamage(int bufferAge) const
|
||||
{
|
||||
return m_damageJournal.accumulate(bufferAge, m_waylandOutput->geometry());
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterOutput::mapToLocal(const QRegion ®ion) const
|
||||
|
@ -166,8 +182,7 @@ void WaylandQPainterBackend::endFrame(int screenId, const QRegion &damage)
|
|||
|
||||
QImage *WaylandQPainterBackend::bufferForScreen(int screenId)
|
||||
{
|
||||
auto *output = m_outputs[screenId];
|
||||
return &output->m_backBuffer;
|
||||
return &m_outputs[screenId]->back()->image;
|
||||
}
|
||||
|
||||
QRegion WaylandQPainterBackend::beginFrame(int screenId)
|
||||
|
@ -175,8 +190,8 @@ QRegion WaylandQPainterBackend::beginFrame(int screenId)
|
|||
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
|
||||
Q_ASSERT(rendererOutput);
|
||||
|
||||
rendererOutput->prepareRenderingFrame();
|
||||
return rendererOutput->m_waylandOutput->geometry();
|
||||
WaylandQPainterBufferSlot *slot = rendererOutput->acquire();
|
||||
return rendererOutput->accumulateDamage(slot->age);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define KWIN_SCENE_QPAINTER_WAYLAND_BACKEND_H
|
||||
|
||||
#include "qpainterbackend.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
|
@ -34,6 +35,17 @@ class WaylandBackend;
|
|||
class WaylandOutput;
|
||||
class WaylandQPainterBackend;
|
||||
|
||||
class WaylandQPainterBufferSlot
|
||||
{
|
||||
public:
|
||||
WaylandQPainterBufferSlot(QSharedPointer<KWayland::Client::Buffer> buffer);
|
||||
~WaylandQPainterBufferSlot();
|
||||
|
||||
QSharedPointer<KWayland::Client::Buffer> buffer;
|
||||
QImage image;
|
||||
int age = 0;
|
||||
};
|
||||
|
||||
class WaylandQPainterOutput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -45,17 +57,21 @@ public:
|
|||
void updateSize(const QSize &size);
|
||||
void remapBuffer();
|
||||
|
||||
void prepareRenderingFrame();
|
||||
WaylandQPainterBufferSlot *back() const;
|
||||
|
||||
WaylandQPainterBufferSlot *acquire();
|
||||
void present(const QRegion &damage);
|
||||
|
||||
QRegion accumulateDamage(int bufferAge) const;
|
||||
QRegion mapToLocal(const QRegion ®ion) const;
|
||||
|
||||
private:
|
||||
WaylandOutput *m_waylandOutput;
|
||||
KWayland::Client::ShmPool *m_pool;
|
||||
DamageJournal m_damageJournal;
|
||||
|
||||
QWeakPointer<KWayland::Client::Buffer> m_buffer;
|
||||
QImage m_backBuffer;
|
||||
QVector<WaylandQPainterBufferSlot *> m_slots;
|
||||
WaylandQPainterBufferSlot *m_back = nullptr;
|
||||
|
||||
friend class WaylandQPainterBackend;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue