From 9133c0f9d5bacfd472c7e6f8884ce9d7b1ee32c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 17 Apr 2015 11:17:06 +0200 Subject: [PATCH] [SceneQPainter] Per-Screen rendering The backend can indicate that the rendering needs to be split per screen. In that case it has to provide a different rendering buffer per screen. The painting in the scene is adjusted to either take a splitted path or the existing path for all screens in one go. --- scene_qpainter.cpp | 63 ++++++++++++++++++++++++++++++++++++++-------- scene_qpainter.h | 12 +++++++++ 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/scene_qpainter.cpp b/scene_qpainter.cpp index b48a5f1bc2..f3f89c7eec 100644 --- a/scene_qpainter.cpp +++ b/scene_qpainter.cpp @@ -25,6 +25,7 @@ along with this program. If not, see . #include "deleted.h" #include "effects.h" #include "main.h" +#include "screens.h" #include "toplevel.h" #if HAVE_WAYLAND #if HAVE_DRM @@ -88,6 +89,17 @@ void QPainterBackend::renderCursor(QPainter *painter) Q_UNUSED(painter) } +bool QPainterBackend::perScreenRendering() const +{ + return false; +} + +QImage *QPainterBackend::bufferForScreen(int screenId) +{ + Q_UNUSED(screenId) + return buffer(); +} + #if HAVE_WAYLAND //**************************************** // WaylandQPainterBackend @@ -452,19 +464,48 @@ qint64 SceneQPainter::paint(QRegion damage, ToplevelList toplevels) int mask = 0; m_backend->prepareRenderingFrame(); - m_painter->begin(m_backend->buffer()); - if (m_backend->needsFullRepaint()) { - mask |= Scene::PAINT_SCREEN_BACKGROUND_FIRST; - damage = QRegion(0, 0, displayWidth(), displayHeight()); + if (m_backend->perScreenRendering()) { + 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) { + 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); + + m_painter->restore(); + m_painter->end(); + } + m_backend->showOverlay(); + m_backend->present(mask, overallUpdate); + } else { + m_painter->begin(m_backend->buffer()); + if (m_backend->needsFullRepaint()) { + mask |= Scene::PAINT_SCREEN_BACKGROUND_FIRST; + damage = QRegion(0, 0, displayWidth(), displayHeight()); + } + QRegion updateRegion, validRegion; + paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); + + m_backend->renderCursor(m_painter.data()); + m_backend->showOverlay(); + + m_painter->end(); + m_backend->present(mask, updateRegion); } - QRegion updateRegion, validRegion; - paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); - m_backend->renderCursor(m_painter.data()); - m_backend->showOverlay(); - - m_painter->end(); - m_backend->present(mask, updateRegion); // do cleanup clearStackingOrder(); diff --git a/scene_qpainter.h b/scene_qpainter.h index 170310c9c1..760b99d312 100644 --- a/scene_qpainter.h +++ b/scene_qpainter.h @@ -94,8 +94,20 @@ public: } 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 void renderCursor(QPainter *painter); + /** + * Whether the rendering needs to be split per screen. + * Default implementation returns @c false. + **/ + virtual bool perScreenRendering() const; protected: QPainterBackend();