From f20ec1505335ed9862c1c24ace40d2c75869de6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 11 Feb 2013 21:01:41 +0100 Subject: [PATCH] Port xRenderOffscreenTarget away from QPixmap Instead of having a pointer to a QPixmap the offscreen target holds an xcb_render_picture_t. To make this possible in SceneWindow the tempPixmap is changed from a QPixmap* to a XRenderPicture*. QPixmap was only used for convenience. ScreenShot Effect as only user of the offscreen target is adjusted but as it needs a QImage, still uses a QPixmap wrapper. --- effects/screenshot/screenshot.cpp | 12 ++++++-- libkwineffects/kwinxrenderutils.cpp | 6 ++-- libkwineffects/kwinxrenderutils.h | 4 +-- scene_xrender.cpp | 44 +++++++++++++++++------------ scene_xrender.h | 3 +- 5 files changed, 43 insertions(+), 26 deletions(-) diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp index af62a706db..d3e33c8baf 100644 --- a/effects/screenshot/screenshot.cpp +++ b/effects/screenshot/screenshot.cpp @@ -132,8 +132,16 @@ void ScreenShotEffect::postPaintScreen() if (effects->compositingType() == XRenderCompositing) { setXRenderOffscreen(true); effects->drawWindow(m_scheduledScreenshot, mask, QRegion(0, 0, width, height), d); - if (xRenderOffscreenTarget()) - img = xRenderOffscreenTarget()->toImage().copy(0, 0, width, height); + if (xRenderOffscreenTarget()) { + xcb_pixmap_t xpix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 32, xpix, rootWindow(), width, height); + // TODO: Qt5 - convert from xpixmap to QImage without a QPixmap + QPixmap pixmap = QPixmap::fromX11Pixmap(xpix); + xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, xRenderOffscreenTarget(), + XCB_RENDER_PICTURE_NONE, pixmap.x11PictureHandle(), 0, 0, 0, 0, 0, 0, width, height); + img = pixmap.toImage().copy(0, 0, width, height); + xcb_free_pixmap(connection(), xpix); + } setXRenderOffscreen(false); } #endif diff --git a/libkwineffects/kwinxrenderutils.cpp b/libkwineffects/kwinxrenderutils.cpp index 41a864163b..21d5167cdd 100644 --- a/libkwineffects/kwinxrenderutils.cpp +++ b/libkwineffects/kwinxrenderutils.cpp @@ -132,11 +132,11 @@ XRenderPicture::XRenderPicture(Pixmap pix, int depth) { } -static QPixmap *s_offscreenTarget = 0; +static xcb_render_picture_t s_offscreenTarget = XCB_RENDER_PICTURE_NONE; static QStack s_scene_offscreenTargetStack; static int s_renderOffscreen = 0; -void scene_setXRenderOffscreenTarget(QPixmap *pix) +void scene_setXRenderOffscreenTarget(xcb_render_picture_t pix) { s_offscreenTarget = pix; } @@ -176,7 +176,7 @@ bool xRenderOffscreen() return s_renderOffscreen; } -QPixmap *xRenderOffscreenTarget() +xcb_render_picture_t xRenderOffscreenTarget() { return s_offscreenTarget; } diff --git a/libkwineffects/kwinxrenderutils.h b/libkwineffects/kwinxrenderutils.h index 7069e8201f..9a11c16ab8 100644 --- a/libkwineffects/kwinxrenderutils.h +++ b/libkwineffects/kwinxrenderutils.h @@ -184,13 +184,13 @@ KWIN_EXPORT bool xRenderOffscreen(); /** * The offscreen buffer as set by the renderer because of setXRenderWindowOffscreen(true) */ -KWIN_EXPORT QPixmap *xRenderOffscreenTarget(); +KWIN_EXPORT xcb_render_picture_t xRenderOffscreenTarget(); /** * NOTICE: HANDS OFF!!! * scene_setXRenderWindowOffscreenTarget() is ONLY to be used by the renderer - DO NOT TOUCH! */ -KWIN_EXPORT void scene_setXRenderOffscreenTarget(QPixmap *pix); +KWIN_EXPORT void scene_setXRenderOffscreenTarget(xcb_render_picture_t pix); /** * scene_xRenderWindowOffscreenTarget() is used by the scene to figure the target set by an effect */ diff --git a/scene_xrender.cpp b/scene_xrender.cpp index dc40f66137..c8cb09b5e0 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -94,6 +94,7 @@ SceneXrender::~SceneXrender() m_overlayWindow->destroy(); return; } + SceneXrender::Window::cleanup(); SceneXrender::EffectFrame::cleanup(); XRenderFreePicture(display(), front); XRenderFreePicture(display(), buffer); @@ -276,7 +277,7 @@ void SceneXrender::windowAdded(Toplevel* c) // SceneXrender::Window //**************************************** -QPixmap *SceneXrender::Window::temp_pixmap = 0; +XRenderPicture *SceneXrender::Window::s_tempPicture = 0; QRect SceneXrender::Window::temp_visibleRect; SceneXrender::Window::Window(Toplevel* c) @@ -295,6 +296,12 @@ SceneXrender::Window::~Window() discardShape(); } +void SceneXrender::Window::cleanup() +{ + delete s_tempPicture; + s_tempPicture = NULL; +} + // Create XRender picture for the pixmap with the window contents. Picture SceneXrender::Window::picture() { @@ -406,21 +413,22 @@ QPoint SceneXrender::Window::mapToScreen(int mask, const WindowPaintData &data, void SceneXrender::Window::prepareTempPixmap() { + const QSize oldSize = temp_visibleRect.size(); temp_visibleRect = toplevel->visibleRect().translated(-toplevel->pos()); - - if (temp_pixmap && Extensions::nonNativePixmaps()) - XFreePixmap(display(), temp_pixmap->handle()); // The picture owns the pixmap now - if (!temp_pixmap) - temp_pixmap = new QPixmap(temp_visibleRect.size()); - else if (temp_pixmap->width() < temp_visibleRect.width() || temp_pixmap->height() < temp_visibleRect.height()) { - *temp_pixmap = QPixmap(temp_visibleRect.size()); + if (s_tempPicture && (oldSize.width() < temp_visibleRect.width() || oldSize.height() < temp_visibleRect.height())) { + delete s_tempPicture; + s_tempPicture = NULL; scene_setXRenderOffscreenTarget(0); // invalidate, better crash than cause weird results for developers } - if (Extensions::nonNativePixmaps()) { - Pixmap pix = XCreatePixmap(display(), rootWindow(), temp_pixmap->width(), temp_pixmap->height(), DefaultDepth(display(), DefaultScreen(display()))); - *temp_pixmap = QPixmap::fromX11Pixmap(pix); + if (!s_tempPicture) { + xcb_pixmap_t pix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 32, pix, rootWindow(), temp_visibleRect.width(), temp_visibleRect.height()); + s_tempPicture = new XRenderPicture(pix, 32); + xcb_free_pixmap(connection(), pix); } - temp_pixmap->fill(Qt::transparent); + const xcb_render_color_t transparent = {0, 0, 0, 0}; + const xcb_rectangle_t rect = {0, 0, uint16_t(temp_visibleRect.width()), uint16_t(temp_visibleRect.height())}; + xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, *s_tempPicture, transparent, 1, &rect); } // paint the window @@ -543,7 +551,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat renderTarget = *scene_xRenderOffscreenTarget(); } else { prepareTempPixmap(); - renderTarget = temp_pixmap->x11PictureHandle(); + renderTarget = *s_tempPicture; } } else { XRenderSetPictureTransform(display(), pic, &xform); @@ -699,11 +707,11 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl } if (blitInTempPixmap) { const QRect r = mapToScreen(mask, data, temp_visibleRect); - XRenderSetPictureTransform(display(), temp_pixmap->x11PictureHandle(), &xform); - XRenderSetPictureFilter(display(), temp_pixmap->x11PictureHandle(), const_cast("good"), NULL, 0); - XRenderComposite(display(), PictOpOver, temp_pixmap->x11PictureHandle(), None, buffer, + XRenderSetPictureTransform(display(), *s_tempPicture, &xform); + XRenderSetPictureFilter(display(), *s_tempPicture, const_cast("good"), NULL, 0); + XRenderComposite(display(), PictOpOver, *s_tempPicture, None, buffer, 0, 0, 0, 0, r.x(), r.y(), r.width(), r.height()); - XRenderSetPictureTransform(display(), temp_pixmap->x11PictureHandle(), &identity); + XRenderSetPictureTransform(display(), *s_tempPicture, &identity); } } if (scaled && !blitInTempPixmap) { @@ -716,7 +724,7 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl } } if (xRenderOffscreen()) - scene_setXRenderOffscreenTarget(temp_pixmap); + scene_setXRenderOffscreenTarget(*s_tempPicture); } void SceneXrender::screenGeometryChanged(const QSize &size) diff --git a/scene_xrender.h b/scene_xrender.h index 9f55ebd834..6c26c1786d 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -84,6 +84,7 @@ public: void discardAlpha(); QRegion transformedShape() const; void setTransformedShape(const QRegion& shape); + static void cleanup(); private: Picture picture(); Picture alphaMask(double opacity); @@ -95,8 +96,8 @@ private: Picture alpha; double alpha_cached_opacity; QRegion transformed_shape; - static QPixmap *temp_pixmap; static QRect temp_visibleRect; + static XRenderPicture *s_tempPicture; }; class SceneXrender::EffectFrame