From fba75040639b75e485f3fca3cb2f319c9d40ab33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 18 Feb 2013 09:07:42 +0100 Subject: [PATCH] Introduce dedicated PaintRedirector subclasses for OpenGL/XRender PaintRedirector is turned into an abstract class providing a factory method which returns either an instance of * OpenGLPaintRedirector * NativeXRenderPaintRedirector * RasterXRenderPaintRedirector OpenGLPaintRedirector is basically doing exactly the same as the parent class used to do before. Though the idea is to extend the functionality to have the PaintRedirector write directly into OpenGL textures to limit copying the complete decorations. NativeXRenderPaintRedirector is similar to OpenGLPaintRedirector by rendering into a QPixmap and providing the pictureHandle for the QPixmap to SceneXRender. RasterXRenderPaintRedirector is providing the functionality for the case that the QPixmap/XPixmap relationship is not present. From the QPixmap containing the pending decoration paint a QImage is created and then the relevent parts are copied directly into the decoration pixmap. REVIEW: 109074 --- client.cpp | 2 +- paintredirector.cpp | 204 ++++++++++++++++++++++++++++++++++++-------- paintredirector.h | 143 +++++++++++++++++++++++++++---- scene_opengl.cpp | 8 +- scene_xrender.cpp | 18 ++-- 5 files changed, 310 insertions(+), 65 deletions(-) diff --git a/client.cpp b/client.cpp index e8d6ee1170..1f4d232880 100644 --- a/client.cpp +++ b/client.cpp @@ -452,7 +452,7 @@ void Client::updateDecoration(bool check_workspace_pos, bool force) move(calculateGravitation(false)); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); if (Compositor::compositing()) { - paintRedirector = new PaintRedirector(this, decoration->widget()); + paintRedirector = PaintRedirector::create(this, decoration->widget()); discardWindowPixmap(); } emit geometryShapeChanged(this, oldgeom); diff --git a/paintredirector.cpp b/paintredirector.cpp index c8892c8f15..3bbe9d0ef0 100644 --- a/paintredirector.cpp +++ b/paintredirector.cpp @@ -28,6 +28,7 @@ DEALINGS IN THE SOFTWARE. #include "client.h" #include "deleted.h" #include "effects.h" +#include #include #include #include @@ -37,25 +38,30 @@ DEALINGS IN THE SOFTWARE. namespace KWin { +PaintRedirector *PaintRedirector::create(Client *c, QWidget *widget) +{ + if (effects->isOpenGLCompositing()) { + return new OpenGLPaintRedirector(c, widget); + } else { + if (!Extensions::nonNativePixmaps()) { + return new NativeXRenderPaintRedirector(c, widget); + } + return new RasterXRenderPaintRedirector(c, widget); + } +} + PaintRedirector::PaintRedirector(Client *c, QWidget* w) : QObject(w) , widget(w) , recursionCheck(false) , m_client(c) - , m_responsibleForPixmap(!effects->isOpenGLCompositing()) , m_requiresRepaint(false) { added(w); - resizePixmaps(); } PaintRedirector::~PaintRedirector() { - if (m_responsibleForPixmap) { - for (int i=0; ilayoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); for (int i=0; ilayoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); for (int i=0; itype() == QPaintEngine::X11) { - XFreePixmap(display(), m_pixmaps[i].handle()); - } - Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), - rects[i].size().width(), rects[i].height(), - 32); - m_pixmaps[i] = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - } - // Make sure the pixmaps are created with alpha channels - m_pixmaps[i].fill(Qt::transparent); + resize(DecorationPixmap(i), rects[i].size()); } // repaint @@ -238,6 +228,150 @@ void PaintRedirector::resizePixmaps() } } +const QPixmap *PaintRedirector::pixmap(PaintRedirector::DecorationPixmap border) const +{ + Q_UNUSED(border) + return NULL; +} + +xcb_render_picture_t PaintRedirector::picture(PaintRedirector::DecorationPixmap border) const +{ + Q_UNUSED(border) + return XCB_RENDER_PICTURE_NONE; +} + +OpenGLPaintRedirector::OpenGLPaintRedirector(Client *c, QWidget *widget) + : PaintRedirector(c, widget) +{ + resizePixmaps(); +} + +OpenGLPaintRedirector::~OpenGLPaintRedirector() +{ +} + +const QPixmap *OpenGLPaintRedirector::pixmap(PaintRedirector::DecorationPixmap border) const +{ + return &m_pixmaps[border]; +} + +void OpenGLPaintRedirector::resize(PaintRedirector::DecorationPixmap border, const QSize &size) +{ + if (m_pixmaps[border].size() != size) { + m_pixmaps[border] = QPixmap(size); + } + m_pixmaps[border].fill(Qt::transparent); +} + +void OpenGLPaintRedirector::paint(PaintRedirector::DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®) +{ + QPainter pt(&m_pixmaps[border]); + pt.translate(-r.topLeft()); + pt.setCompositionMode(QPainter::CompositionMode_Source); + pt.setClipRegion(reg); + pt.drawPixmap(b.topLeft(), src); + pt.end(); +} + +RasterXRenderPaintRedirector::RasterXRenderPaintRedirector(Client *c, QWidget *widget) + : PaintRedirector(c, widget) + , m_gc(0) +{ + for (int i=0; i #include #include +// xcb +#include namespace KWin { + // forward declarations class Client; class Deleted; +class XRenderPicture; // This class redirects all painting of a given widget (including its children) // into a paint device (QPixmap). @@ -51,7 +55,6 @@ public: LeftPixmap, PixmapCount }; - PaintRedirector(Client *c, QWidget* widget); virtual ~PaintRedirector(); QPixmap performPendingPaint(); virtual bool eventFilter(QObject* o, QEvent* e); @@ -66,18 +69,14 @@ public: } void resizePixmaps(); - const QPixmap *topDecoPixmap() const { - return &m_pixmaps[TopPixmap]; - } - const QPixmap *leftDecoPixmap() const { - return &m_pixmaps[LeftPixmap]; - } - const QPixmap *bottomDecoPixmap() const { - return &m_pixmaps[BottomPixmap]; - } - const QPixmap *rightDecoPixmap() const { - return &m_pixmaps[RightPixmap]; - } + template + T topDecoPixmap() const; + template + T leftDecoPixmap() const; + template + T bottomDecoPixmap() const; + template + T rightDecoPixmap() const; /** * Used by Deleted::copyToDeleted() to move the PaintRedirector to the Deleted. @@ -85,16 +84,24 @@ public: * is created. **/ void reparent(Deleted *d); + static PaintRedirector *create(Client *c, QWidget* widget); public slots: void ensurePixmapsPainted(); +protected: + PaintRedirector(Client *c, QWidget* widget); + virtual const QPixmap *pixmap(DecorationPixmap border) const; + virtual xcb_render_picture_t picture(DecorationPixmap border) const; + virtual void resize(DecorationPixmap border, const QSize &size) = 0; + virtual void preparePaint(const QPixmap &pending); + virtual void paint(DecorationPixmap border, const QRect& r, const QRect &b, const QPixmap& src, const QRegion ®) = 0; private: void added(QWidget* widget); void removed(QWidget* widget); bool isToolTip(QWidget* widget) const; void timerEvent(QTimerEvent* event); - void repaintPixmap(QPixmap& pix, const QRect& r, const QPixmap& src, QRegion reg); + void repaintPixmap(DecorationPixmap border, const QRect& r, const QPixmap& src, QRegion reg); QWidget* widget; QRegion pending; QRegion scheduled; @@ -103,12 +110,116 @@ private: QBasicTimer cleanupTimer; Client *m_client; - // we (instead of Qt) initialize the Pixmaps, and have to free them - bool m_responsibleForPixmap; bool m_requiresRepaint; +}; + +class OpenGLPaintRedirector : public PaintRedirector +{ + Q_OBJECT +public: + OpenGLPaintRedirector(Client *c, QWidget *widget); + virtual ~OpenGLPaintRedirector(); + +protected: + virtual const QPixmap *pixmap(DecorationPixmap border) const; + virtual void resize(DecorationPixmap border, const QSize &size); + virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®); + +private: QPixmap m_pixmaps[PixmapCount]; }; +class NativeXRenderPaintRedirector : public PaintRedirector +{ + Q_OBJECT +public: + NativeXRenderPaintRedirector(Client *c, QWidget *widget); + virtual ~NativeXRenderPaintRedirector(); + +protected: + virtual xcb_render_picture_t picture(DecorationPixmap border) const; + virtual void resize(DecorationPixmap border, const QSize &size); + virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®); +private: + QPixmap m_pixmaps[PixmapCount]; +}; + +class RasterXRenderPaintRedirector : public PaintRedirector +{ + Q_OBJECT +public: + RasterXRenderPaintRedirector(Client *c, QWidget *widget); + virtual ~RasterXRenderPaintRedirector(); + +protected: + virtual xcb_render_picture_t picture(DecorationPixmap border) const; + virtual void resize(DecorationPixmap border, const QSize &size); + virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®); + virtual void preparePaint(const QPixmap &pending); +private: + QSize m_sizes[PixmapCount]; + xcb_pixmap_t m_pixmaps[PixmapCount]; + xcb_gcontext_t m_gc; + XRenderPicture* m_pictures[PixmapCount]; + QImage m_tempImage; +}; + +template <> +inline +const QPixmap *PaintRedirector::bottomDecoPixmap() const +{ + return pixmap(BottomPixmap); +} + +template <> +inline +const QPixmap *PaintRedirector::leftDecoPixmap() const +{ + return pixmap(LeftPixmap); +} + +template <> +inline +const QPixmap *PaintRedirector::rightDecoPixmap() const +{ + return pixmap(RightPixmap); +} + +template <> +inline +const QPixmap *PaintRedirector::topDecoPixmap() const +{ + return pixmap(TopPixmap); +} + +template <> +inline +xcb_render_picture_t PaintRedirector::bottomDecoPixmap() const +{ + return picture(BottomPixmap); +} + +template <> +inline +xcb_render_picture_t PaintRedirector::leftDecoPixmap() const +{ + return picture(LeftPixmap); +} + +template <> +inline +xcb_render_picture_t PaintRedirector::rightDecoPixmap() const +{ + return picture(RightPixmap); +} + +template <> +inline +xcb_render_picture_t PaintRedirector::topDecoPixmap() const +{ + return picture(TopPixmap); +} + } // namespace #endif diff --git a/scene_opengl.cpp b/scene_opengl.cpp index fee8db921d..793ffbc54b 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -1116,10 +1116,10 @@ void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QR t->layoutDecorationRects(leftRect, topRect, rightRect, bottomRect, Client::WindowRelative); - const QPixmap *left = redirector->leftDecoPixmap(); - const QPixmap *top = redirector->topDecoPixmap(); - const QPixmap *right = redirector->rightDecoPixmap(); - const QPixmap *bottom = redirector->bottomDecoPixmap(); + const QPixmap *left = redirector->leftDecoPixmap(); + const QPixmap *top = redirector->topDecoPixmap(); + const QPixmap *right = redirector->rightDecoPixmap(); + const QPixmap *bottom = redirector->bottomDecoPixmap(); WindowQuadList topList, leftList, rightList, bottomList; diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 82eb1995fd..2a0bf3e688 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -581,10 +581,10 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat //BEGIN deco preparations bool noBorder = true; - const QPixmap *left = NULL; - const QPixmap *top = NULL; - const QPixmap *right = NULL; - const QPixmap *bottom = NULL; + xcb_render_picture_t left = XCB_RENDER_PICTURE_NONE; + xcb_render_picture_t top = XCB_RENDER_PICTURE_NONE; + xcb_render_picture_t right = XCB_RENDER_PICTURE_NONE; + xcb_render_picture_t bottom = XCB_RENDER_PICTURE_NONE; PaintRedirector *redirector = NULL; QRect dtr, dlr, drr, dbr; if (client || deleted) { @@ -600,10 +600,10 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat } if (redirector) { redirector->ensurePixmapsPainted(); - left = redirector->leftDecoPixmap(); - top = redirector->topDecoPixmap(); - right = redirector->rightDecoPixmap(); - bottom = redirector->bottomDecoPixmap(); + left = redirector->leftDecoPixmap(); + top = redirector->topDecoPixmap(); + right = redirector->rightDecoPixmap(); + bottom = redirector->bottomDecoPixmap(); } if (!noBorder) { MAP_RECT_TO_TARGET(dtr); @@ -677,7 +677,7 @@ XRenderComposite(display(), PictOpOver, m_xrenderShadow->shadowPixmap(SceneXRend } #define RENDER_DECO_PART(_PART_, _RECT_) \ -XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAlpha, renderTarget,\ +XRenderComposite(display(), PictOpOver, _PART_, decorationAlpha, renderTarget,\ 0, 0, 0, 0, _RECT_.x(), _RECT_.y(), _RECT_.width(), _RECT_.height()) if (client || deleted) {