Commit 94b731c1 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Prepare QPainter render backend for per screen rendering

parent edfb0a3f
......@@ -39,10 +39,4 @@ bool QPainterBackend::perScreenRendering() const
return false;
}
QImage *QPainterBackend::bufferForScreen(int screenId)
{
Q_UNUSED(screenId)
return buffer();
}
}
......@@ -21,8 +21,8 @@ class QPainterBackend
{
public:
virtual ~QPainterBackend();
virtual void present(int mask, const QRegion &damage) = 0;
virtual void prepareRenderingFrame() = 0;
virtual void present(int screenId, int mask, const QRegion &damage) = 0;
virtual void prepareRenderingFrame(int screenId) = 0;
/**
* @brief React on screen geometry changes.
*
......@@ -42,16 +42,14 @@ public:
bool isFailed() const {
return m_failed;
}
virtual QImage *buffer() = 0;
/**
* Overload for the case that there is a different buffer per screen.
* Default implementation just calls buffer.
* @param screenId The id of the screen as used in Screens
* @todo Get a better identifier for screen then a counter variable
*/
virtual QImage *bufferForScreen(int screenId);
virtual bool needsFullRepaint() const = 0;
virtual QImage *bufferForScreen(int screenId) = 0;
virtual bool needsFullRepaint(int screenId) const = 0;
/**
* Whether the rendering needs to be split per screen.
* Default implementation returns @c false.
......
......@@ -88,40 +88,34 @@ void DrmQPainterBackend::initOutput(DrmOutput *output)
m_outputs << o;
}
QImage *DrmQPainterBackend::buffer()
{
return bufferForScreen(0);
}
QImage *DrmQPainterBackend::bufferForScreen(int screenId)
{
const Output &o = m_outputs.at(screenId);
return o.buffer[o.index]->image();
}
bool DrmQPainterBackend::needsFullRepaint() const
bool DrmQPainterBackend::needsFullRepaint(int screenId) const
{
Q_UNUSED(screenId)
return true;
}
void DrmQPainterBackend::prepareRenderingFrame()
void DrmQPainterBackend::prepareRenderingFrame(int screenId)
{
for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) {
(*it).index = ((*it).index + 1) % 2;
}
Output &rendererOutput = m_outputs[screenId];
rendererOutput.index = (rendererOutput.index + 1) % 2;
}
void DrmQPainterBackend::present(int mask, const QRegion &damage)
void DrmQPainterBackend::present(int screenId, int mask, const QRegion &damage)
{
Q_UNUSED(mask)
Q_UNUSED(damage)
if (!LogindIntegration::self()->isActiveSession()) {
return;
}
for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) {
const Output &o = *it;
m_backend->present(o.buffer[o.index], o.output);
}
const Output &rendererOutput = m_outputs[screenId];
m_backend->present(rendererOutput.buffer[rendererOutput.index], rendererOutput.output);
}
bool DrmQPainterBackend::perScreenRendering() const
......
......@@ -27,11 +27,10 @@ public:
DrmQPainterBackend(DrmBackend *backend, DrmGpu *gpu);
~DrmQPainterBackend() override;
QImage *buffer() override;
QImage *bufferForScreen(int screenId) override;
bool needsFullRepaint() const override;
void prepareRenderingFrame() override;
void present(int mask, const QRegion &damage) override;
bool needsFullRepaint(int screenId) const override;
void prepareRenderingFrame(int screenId) override;
void present(int screenId, int mask, const QRegion &damage) override;
bool perScreenRendering() const override;
private:
......
......@@ -47,29 +47,27 @@ FramebufferQPainterBackend::FramebufferQPainterBackend(FramebufferBackend *backe
FramebufferQPainterBackend::~FramebufferQPainterBackend() = default;
QImage* FramebufferQPainterBackend::buffer()
{
return bufferForScreen(0);
}
QImage* FramebufferQPainterBackend::bufferForScreen(int screenId)
{
Q_UNUSED(screenId)
return &m_renderBuffer;
}
bool FramebufferQPainterBackend::needsFullRepaint() const
bool FramebufferQPainterBackend::needsFullRepaint(int screenId) const
{
Q_UNUSED(screenId)
return m_needsFullRepaint;
}
void FramebufferQPainterBackend::prepareRenderingFrame()
void FramebufferQPainterBackend::prepareRenderingFrame(int screenId)
{
Q_UNUSED(screenId)
m_needsFullRepaint = true;
}
void FramebufferQPainterBackend::present(int mask, const QRegion &damage)
void FramebufferQPainterBackend::present(int screenId, int mask, const QRegion &damage)
{
Q_UNUSED(screenId)
Q_UNUSED(mask)
Q_UNUSED(damage)
......
......@@ -24,11 +24,10 @@ public:
FramebufferQPainterBackend(FramebufferBackend *backend);
~FramebufferQPainterBackend() override;
QImage *buffer() override;
QImage *bufferForScreen(int screenId) override;
bool needsFullRepaint() const override;
void prepareRenderingFrame() override;
void present(int mask, const QRegion &damage) override;
bool needsFullRepaint(int screenId) const override;
void prepareRenderingFrame(int screenId) override;
void present(int screenId, int mask, const QRegion &damage) override;
bool perScreenRendering() const override;
private:
......
......@@ -25,23 +25,20 @@ VirtualQPainterBackend::VirtualQPainterBackend(VirtualBackend *backend)
VirtualQPainterBackend::~VirtualQPainterBackend() = default;
QImage *VirtualQPainterBackend::buffer()
{
return &m_backBuffers[0];
}
QImage *VirtualQPainterBackend::bufferForScreen(int screen)
{
return &m_backBuffers[screen];
}
bool VirtualQPainterBackend::needsFullRepaint() const
bool VirtualQPainterBackend::needsFullRepaint(int screenId) const
{
Q_UNUSED(screenId)
return true;
}
void VirtualQPainterBackend::prepareRenderingFrame()
void VirtualQPainterBackend::prepareRenderingFrame(int screenId)
{
Q_UNUSED(screenId)
}
void VirtualQPainterBackend::createOutputs()
......@@ -54,14 +51,12 @@ void VirtualQPainterBackend::createOutputs()
}
}
void VirtualQPainterBackend::present(int mask, const QRegion &damage)
void VirtualQPainterBackend::present(int screenId, int mask, const QRegion &damage)
{
Q_UNUSED(mask)
Q_UNUSED(damage)
if (m_backend->saveFrames()) {
for (int i=0; i < m_backBuffers.size() ; i++) {
m_backBuffers[i].save(QStringLiteral("%1/screen%2-%3.png").arg(m_backend->screenshotDirPath(), QString::number(i), QString::number(m_frameCounter++)));
}
m_backBuffers[screenId].save(QStringLiteral("%1/screen%2-%3.png").arg(m_backend->screenshotDirPath(), QString::number(screenId), QString::number(m_frameCounter++)));
}
}
......
......@@ -26,11 +26,10 @@ public:
VirtualQPainterBackend(VirtualBackend *backend);
~VirtualQPainterBackend() override;
QImage *buffer() override;
QImage *bufferForScreen(int screenId) override;
bool needsFullRepaint() const override;
void prepareRenderingFrame() override;
void present(int mask, const QRegion &damage) override;
bool needsFullRepaint(int screenId) const override;
void prepareRenderingFrame(int screenId) override;
void present(int screenId, int mask, const QRegion &damage) override;
bool perScreenRendering() const override;
private:
......
......@@ -36,6 +36,16 @@ WaylandQPainterOutput::~WaylandQPainterOutput()
}
}
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;
......@@ -111,10 +121,14 @@ void WaylandQPainterOutput::prepareRenderingFrame()
// qCDebug(KWIN_WAYLAND_BACKEND) << "Created a new back buffer for output surface" << m_waylandOutput->surface();
}
QRegion WaylandQPainterOutput::mapToLocal(const QRegion &region) const
{
return region.translated(-m_waylandOutput->geometry().topLeft());
}
WaylandQPainterBackend::WaylandQPainterBackend(Wayland::WaylandBackend *b)
: QPainterBackend()
, m_backend(b)
, m_needsFullRepaint(true)
{
const auto waylandOutputs = m_backend->waylandOutputs();
......@@ -154,21 +168,19 @@ void WaylandQPainterBackend::createOutput(WaylandOutput *waylandOutput)
m_outputs << output;
}
void WaylandQPainterBackend::present(int mask, const QRegion &damage)
void WaylandQPainterBackend::present(int screenId, int mask, const QRegion &damage)
{
Q_UNUSED(mask)
Compositor::self()->aboutToSwapBuffers();
m_needsFullRepaint = false;
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
Q_ASSERT(rendererOutput);
for (auto *output : m_outputs) {
output->present(damage);
if (screenId == 0) {
Compositor::self()->aboutToSwapBuffers();
}
}
QImage *WaylandQPainterBackend::buffer()
{
return bufferForScreen(0);
rendererOutput->setNeedsFullRepaint(false);
rendererOutput->present(rendererOutput->mapToLocal(damage));
}
QImage *WaylandQPainterBackend::bufferForScreen(int screenId)
......@@ -177,17 +189,20 @@ QImage *WaylandQPainterBackend::bufferForScreen(int screenId)
return &output->m_backBuffer;
}
void WaylandQPainterBackend::prepareRenderingFrame()
void WaylandQPainterBackend::prepareRenderingFrame(int screenId)
{
for (auto *output : m_outputs) {
output->prepareRenderingFrame();
}
m_needsFullRepaint = true;
WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
Q_ASSERT(rendererOutput);
rendererOutput->prepareRenderingFrame();
rendererOutput->setNeedsFullRepaint(true);
}
bool WaylandQPainterBackend::needsFullRepaint() const
bool WaylandQPainterBackend::needsFullRepaint(int screenId) const
{
return m_needsFullRepaint;
const WaylandQPainterOutput *rendererOutput = m_outputs.value(screenId);
Q_ASSERT(rendererOutput);
return rendererOutput->needsFullRepaint();
}
}
......
......@@ -47,12 +47,18 @@ public:
void prepareRenderingFrame();
void present(const QRegion &damage);
bool needsFullRepaint() const;
void setNeedsFullRepaint(bool set);
QRegion mapToLocal(const QRegion &region) const;
private:
WaylandOutput *m_waylandOutput;
KWayland::Client::ShmPool *m_pool;
QWeakPointer<KWayland::Client::Buffer> m_buffer;
QImage m_backBuffer;
bool m_needsFullRepaint = true;
friend class WaylandQPainterBackend;
};
......@@ -64,13 +70,12 @@ public:
explicit WaylandQPainterBackend(WaylandBackend *b);
~WaylandQPainterBackend() override;
QImage *buffer() override;
QImage *bufferForScreen(int screenId) override;
void present(int mask, const QRegion& damage) override;
void prepareRenderingFrame() override;
void present(int screenId, int mask, const QRegion& damage) override;
void prepareRenderingFrame(int screenId) override;
bool needsFullRepaint() const override;
bool needsFullRepaint(int screenId) const override;
bool perScreenRendering() const override;
private:
......@@ -78,8 +83,6 @@ private:
void frameRendered();
WaylandBackend *m_backend;
bool m_needsFullRepaint;
QVector<WaylandQPainterOutput*> m_outputs;
};
......
......@@ -39,12 +39,6 @@ void X11WindowedQPainterBackend::createOutputs()
output->buffer.fill(Qt::black);
m_outputs << output;
}
m_needsFullRepaint = true;
}
QImage *X11WindowedQPainterBackend::buffer()
{
return bufferForScreen(0);
}
QImage *X11WindowedQPainterBackend::bufferForScreen(int screen)
......@@ -52,16 +46,19 @@ QImage *X11WindowedQPainterBackend::bufferForScreen(int screen)
return &m_outputs.at(screen)->buffer;
}
bool X11WindowedQPainterBackend::needsFullRepaint() const
bool X11WindowedQPainterBackend::needsFullRepaint(int screenId) const
{
return m_needsFullRepaint;
const Output *rendererOutput = m_outputs.value(screenId);
Q_ASSERT(rendererOutput);
return rendererOutput->needsFullRepaint;
}
void X11WindowedQPainterBackend::prepareRenderingFrame()
void X11WindowedQPainterBackend::prepareRenderingFrame(int screenId)
{
Q_UNUSED(screenId)
}
void X11WindowedQPainterBackend::present(int mask, const QRegion &damage)
void X11WindowedQPainterBackend::present(int screenId, int mask, const QRegion &damage)
{
Q_UNUSED(mask)
Q_UNUSED(damage)
......@@ -71,13 +68,17 @@ void X11WindowedQPainterBackend::present(int mask, const QRegion &damage)
m_gc = xcb_generate_id(c);
xcb_create_gc(c, m_gc, window, 0, nullptr);
}
for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) {
// TODO: only update changes?
const QImage &buffer = (*it)->buffer;
xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, (*it)->window, m_gc,
buffer.width(), buffer.height(), 0, 0, 0, 24,
buffer.sizeInBytes(), buffer.constBits());
}
Output *rendererOutput = m_outputs.value(screenId);
Q_ASSERT(rendererOutput);
// TODO: only update changes?
const QImage &buffer = rendererOutput->buffer;
xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, rendererOutput->window,
m_gc, buffer.width(), buffer.height(), 0, 0, 0, 24,
buffer.sizeInBytes(), buffer.constBits());
rendererOutput->needsFullRepaint = false;
}
bool X11WindowedQPainterBackend::perScreenRendering() const
......
......@@ -29,21 +29,20 @@ public:
X11WindowedQPainterBackend(X11WindowedBackend *backend);
~X11WindowedQPainterBackend() override;
QImage *buffer() override;
QImage *bufferForScreen(int screenId) override;
bool needsFullRepaint() const override;
void prepareRenderingFrame() override;
void present(int mask, const QRegion &damage) override;
bool needsFullRepaint(int screenId) const override;
void prepareRenderingFrame(int screenId) override;
void present(int screenId, int mask, const QRegion &damage) override;
bool perScreenRendering() const override;
private:
void createOutputs();
bool m_needsFullRepaint = true;
xcb_gcontext_t m_gc = XCB_NONE;
X11WindowedBackend *m_backend;
struct Output {
xcb_window_t window;
QImage buffer;
bool needsFullRepaint = true;
};
QVector<Output*> m_outputs;
};
......
......@@ -90,34 +90,31 @@ qint64 SceneQPainter::paint(const QRegion &_damage, const QList<Toplevel *> &top
createStackingOrder(toplevels);
QRegion damage = _damage;
int mask = 0;
m_backend->prepareRenderingFrame();
const bool needsFullRepaint = m_backend->needsFullRepaint();
if (needsFullRepaint) {
mask |= Scene::PAINT_SCREEN_BACKGROUND_FIRST;
damage = screens()->geometry();
}
QRegion overallUpdate;
for (int i = 0; i < screens()->count(); ++i) {
int mask = 0;
painted_screen = i;
m_backend->prepareRenderingFrame(i);
const bool needsFullRepaint = m_backend->needsFullRepaint(i);
if (needsFullRepaint) {
mask |= Scene::PAINT_SCREEN_BACKGROUND_FIRST;
damage = screens()->geometry();
}
const QRect geometry = screens()->geometry(i);
QImage *buffer = m_backend->bufferForScreen(i);
if (!buffer || buffer->isNull()) {
continue;
}
m_painter->begin(buffer);
m_painter->save();
m_painter->setWindow(geometry);
QRegion updateRegion, validRegion;
paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion);
overallUpdate = overallUpdate.united(updateRegion);
paintCursor(updateRegion);
m_painter->restore();
m_painter->end();
m_backend->present(i, mask, updateRegion);
}
m_backend->present(mask, overallUpdate);
// do cleanup
clearStackingOrder();
......@@ -184,7 +181,7 @@ void SceneQPainter::screenGeometryChanged(const QSize &size)
QImage *SceneQPainter::qpainterRenderBuffer() const
{
return m_backend->buffer();
return m_backend->bufferForScreen(0);
}
//****************************************
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment