platforms/drm: Add buffer age support in qpainter backend

Currently, the entire screen will be repainted when using the qpainter
render backend. With this change, kwin will repaint only the dirty parts
on the screen.
This commit is contained in:
Vlad Zahorodnii 2021-07-24 12:08:30 +03:00
parent 603db353a3
commit e087b2ce2f
4 changed files with 54 additions and 16 deletions

View file

@ -26,26 +26,42 @@ DumbSwapchain::DumbSwapchain(DrmGpu *gpu, const QSize &size)
break;
}
buffer->image()->fill(Qt::black);
m_buffers << buffer;
m_slots.append(Slot{.buffer = buffer, .age = 0,});
}
if (m_buffers.count() < 2) {
if (m_slots.count() < 2) {
qCWarning(KWIN_DRM) << "Failed to create dumb buffers for swapchain!";
m_buffers.clear();
m_slots.clear();
}
}
QSharedPointer<DrmDumbBuffer> DumbSwapchain::acquireBuffer()
QSharedPointer<DrmDumbBuffer> DumbSwapchain::acquireBuffer(int *age)
{
if (m_buffers.isEmpty()) {
if (m_slots.isEmpty()) {
return nullptr;
}
index = (index + 1) % m_buffers.count();
return m_buffers[index];
index = (index + 1) % m_slots.count();
if (age) {
*age = m_slots[index].age;
}
return m_slots[index].buffer;
}
QSharedPointer<DrmDumbBuffer> DumbSwapchain::currentBuffer() const
{
return m_buffers[index];
return m_slots[index].buffer;
}
void DumbSwapchain::releaseBuffer(QSharedPointer<DrmDumbBuffer> buffer)
{
Q_ASSERT(m_slots[index].buffer == buffer);
for (qsizetype i = 0; i < m_slots.count(); ++i) {
if (m_slots[i].buffer == buffer) {
m_slots[i].age = 1;
} else if (m_slots[i].age > 0) {
m_slots[i].age++;
}
}
}
}

View file

@ -24,22 +24,32 @@ class DumbSwapchain
public:
DumbSwapchain(DrmGpu *gpu, const QSize &size);
QSharedPointer<DrmDumbBuffer> acquireBuffer();
QSharedPointer<DrmDumbBuffer> acquireBuffer(int *age = nullptr);
QSharedPointer<DrmDumbBuffer> currentBuffer() const;
void releaseBuffer(QSharedPointer<DrmDumbBuffer> buffer);
qsizetype slotCount() const {
return m_slots.count();
}
QSize size() const {
return m_size;
}
bool isEmpty() const {
return m_buffers.isEmpty();
return m_slots.isEmpty();
}
private:
QSize m_size;
struct Slot
{
QSharedPointer<DrmDumbBuffer> buffer;
int age = 0;
};
QSize m_size;
int index = 0;
QVector<QSharedPointer<DrmDumbBuffer>> m_buffers;
QVector<Slot> m_slots;
};
}

View file

@ -57,6 +57,7 @@ void DrmQPainterBackend::initOutput(DrmOutput *output)
return;
}
it->swapchain = QSharedPointer<DumbSwapchain>::create(m_gpu, output->pixelSize());
it->damageJournal.setCapacity(it->swapchain->slotCount());
}
);
}
@ -68,21 +69,30 @@ QImage *DrmQPainterBackend::bufferForScreen(int screenId)
QRegion DrmQPainterBackend::beginFrame(int screenId)
{
m_outputs[screenId].swapchain->acquireBuffer();
return m_outputs[screenId].output->geometry();
Output *rendererOutput = &m_outputs[screenId];
int bufferAge;
rendererOutput->swapchain->acquireBuffer(&bufferAge);
return rendererOutput->damageJournal.accumulate(bufferAge, rendererOutput->output->geometry());
}
void DrmQPainterBackend::endFrame(int screenId, const QRegion &damage)
{
Q_UNUSED(damage)
const Output &rendererOutput = m_outputs[screenId];
Output &rendererOutput = m_outputs[screenId];
DrmOutput *drmOutput = rendererOutput.output;
if (!drmOutput->present(rendererOutput.swapchain->currentBuffer(), drmOutput->geometry())) {
QSharedPointer<DrmDumbBuffer> back = rendererOutput.swapchain->currentBuffer();
rendererOutput.swapchain->releaseBuffer(back);
if (!drmOutput->present(back, drmOutput->geometry())) {
RenderLoopPrivate *renderLoopPrivate = RenderLoopPrivate::get(drmOutput->renderLoop());
renderLoopPrivate->notifyFrameFailed();
}
rendererOutput.damageJournal.add(damage);
}
}

View file

@ -9,6 +9,7 @@
#ifndef KWIN_SCENE_QPAINTER_DRM_BACKEND_H
#define KWIN_SCENE_QPAINTER_DRM_BACKEND_H
#include "qpainterbackend.h"
#include "utils.h"
#include <QObject>
#include <QVector>
@ -39,6 +40,7 @@ private:
struct Output {
DrmOutput *output;
QSharedPointer<DumbSwapchain> swapchain;
DamageJournal damageJournal;
};
QVector<Output> m_outputs;
DrmBackend *m_backend;