f26eeb9706
Currently, the OpenGLBackend and the QPainterBackend have hooks to indicate the start and the end of compositing cycle, but in both cases, the hooks have different names. This change fixes that inconsistency.
207 lines
5.4 KiB
C++
207 lines
5.4 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
|
|
SPDX-FileCopyrightText: 2013, 2015 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
#include "scene_qpainter_wayland_backend.h"
|
|
#include "wayland_backend.h"
|
|
#include "wayland_output.h"
|
|
|
|
#include "composite.h"
|
|
#include "logging.h"
|
|
|
|
#include <KWayland/Client/buffer.h>
|
|
#include <KWayland/Client/shm_pool.h>
|
|
#include <KWayland/Client/surface.h>
|
|
|
|
namespace KWin
|
|
{
|
|
namespace Wayland
|
|
{
|
|
|
|
WaylandQPainterOutput::WaylandQPainterOutput(WaylandOutput *output, QObject *parent)
|
|
: QObject(parent)
|
|
, m_waylandOutput(output)
|
|
{
|
|
}
|
|
|
|
WaylandQPainterOutput::~WaylandQPainterOutput()
|
|
{
|
|
if (m_buffer) {
|
|
m_buffer.toStrongRef()->setUsed(false);
|
|
}
|
|
}
|
|
|
|
bool WaylandQPainterOutput::needsFullRepaint() const
|
|
{
|
|
return m_needsFullRepaint;
|
|
}
|
|
|
|
void WaylandQPainterOutput::setNeedsFullRepaint(bool set)
|
|
{
|
|
m_needsFullRepaint = set;
|
|
}
|
|
|
|
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);
|
|
|
|
return true;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
void WaylandQPainterOutput::updateSize(const QSize &size)
|
|
{
|
|
Q_UNUSED(size)
|
|
if (!m_buffer) {
|
|
return;
|
|
}
|
|
m_buffer.toStrongRef()->setUsed(false);
|
|
m_buffer.clear();
|
|
}
|
|
|
|
void WaylandQPainterOutput::present(const QRegion &damage)
|
|
{
|
|
auto s = m_waylandOutput->surface();
|
|
s->attachBuffer(m_buffer);
|
|
s->damage(damage);
|
|
s->commit();
|
|
}
|
|
|
|
void WaylandQPainterOutput::prepareRenderingFrame()
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
m_buffer.clear();
|
|
|
|
const QSize size(m_waylandOutput->geometry().size());
|
|
|
|
m_buffer = m_pool->getBuffer(size, size.width() * 4);
|
|
if (!m_buffer) {
|
|
qCDebug(KWIN_WAYLAND_BACKEND) << "Did not get a new Buffer from Shm Pool";
|
|
m_backBuffer = QImage();
|
|
return;
|
|
}
|
|
|
|
auto b = m_buffer.toStrongRef();
|
|
b->setUsed(true);
|
|
|
|
m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_RGB32);
|
|
m_backBuffer.fill(Qt::transparent);
|
|
// qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer for output surface" << m_waylandOutput->surface();
|
|
}
|
|
|
|
QRegion WaylandQPainterOutput::mapToLocal(const QRegion ®ion) const
|
|
{
|
|
return region.translated(-m_waylandOutput->geometry().topLeft());
|
|
}
|
|
|
|
WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
|
|
: QPainterBackend()
|
|
, m_backend(b)
|
|
{
|
|
|
|
const auto waylandOutputs = m_backend->waylandOutputs();
|
|
for (auto *output: waylandOutputs) {
|
|
createOutput(output);
|
|
}
|
|
connect(m_backend, &WaylandBackend::outputAdded, this, &WaylandQPainterBackend::createOutput);
|
|
connect(m_backend, &WaylandBackend::outputRemoved, this,
|
|
[this] (WaylandOutput *waylandOutput) {
|
|
auto it = std::find_if(m_outputs.begin(), m_outputs.end(),
|
|
[waylandOutput] (WaylandQPainterOutput *output) {
|
|
return output->m_waylandOutput == waylandOutput;
|
|
}
|
|
);
|
|
if (it == m_outputs.end()) {
|
|
return;
|
|
}
|
|
delete *it;
|
|
m_outputs.erase(it);
|
|
}
|
|
);
|
|
}
|
|
|
|
WaylandQPainterBackend::~WaylandQPainterBackend()
|
|
{
|
|
}
|
|
|
|
bool WaylandQPainterBackend::perScreenRendering() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void WaylandQPainterBackend::createOutput(WaylandOutput *waylandOutput)
|
|
{
|
|
auto *output = new WaylandQPainterOutput(waylandOutput, this);
|
|
output->init(m_backend->shmPool());
|
|
m_outputs << output;
|
|
}
|
|
|
|
void WaylandQPainterBackend::endFrame(int screenId, int mask, const QRegion &damage)
|
|
{
|
|
Q_UNUSED(mask)
|
|
|
|
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
|
|
Q_ASSERT(rendererOutput);
|
|
|
|
Compositor::self()->aboutToSwapBuffers();
|
|
|
|
rendererOutput->setNeedsFullRepaint(false);
|
|
rendererOutput->present(rendererOutput->mapToLocal(damage));
|
|
}
|
|
|
|
QImage *WaylandQPainterBackend::bufferForScreen(int screenId)
|
|
{
|
|
auto *output = m_outputs[screenId];
|
|
return &output->m_backBuffer;
|
|
}
|
|
|
|
void WaylandQPainterBackend::beginFrame(int screenId)
|
|
{
|
|
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
|
|
Q_ASSERT(rendererOutput);
|
|
|
|
rendererOutput->prepareRenderingFrame();
|
|
rendererOutput->setNeedsFullRepaint(true);
|
|
}
|
|
|
|
bool WaylandQPainterBackend::needsFullRepaint(int screenId) const
|
|
{
|
|
const WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
|
|
Q_ASSERT(rendererOutput);
|
|
return rendererOutput->needsFullRepaint();
|
|
}
|
|
|
|
}
|
|
}
|