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.
This commit is contained in:
Martin Gräßlin 2013-02-11 21:01:41 +01:00
parent 2dcbbd6a3a
commit f20ec15053
5 changed files with 43 additions and 26 deletions

View file

@ -132,8 +132,16 @@ void ScreenShotEffect::postPaintScreen()
if (effects->compositingType() == XRenderCompositing) { if (effects->compositingType() == XRenderCompositing) {
setXRenderOffscreen(true); setXRenderOffscreen(true);
effects->drawWindow(m_scheduledScreenshot, mask, QRegion(0, 0, width, height), d); effects->drawWindow(m_scheduledScreenshot, mask, QRegion(0, 0, width, height), d);
if (xRenderOffscreenTarget()) if (xRenderOffscreenTarget()) {
img = xRenderOffscreenTarget()->toImage().copy(0, 0, width, height); 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); setXRenderOffscreen(false);
} }
#endif #endif

View file

@ -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<XRenderPicture*> s_scene_offscreenTargetStack; static QStack<XRenderPicture*> s_scene_offscreenTargetStack;
static int s_renderOffscreen = 0; static int s_renderOffscreen = 0;
void scene_setXRenderOffscreenTarget(QPixmap *pix) void scene_setXRenderOffscreenTarget(xcb_render_picture_t pix)
{ {
s_offscreenTarget = pix; s_offscreenTarget = pix;
} }
@ -176,7 +176,7 @@ bool xRenderOffscreen()
return s_renderOffscreen; return s_renderOffscreen;
} }
QPixmap *xRenderOffscreenTarget() xcb_render_picture_t xRenderOffscreenTarget()
{ {
return s_offscreenTarget; return s_offscreenTarget;
} }

View file

@ -184,13 +184,13 @@ KWIN_EXPORT bool xRenderOffscreen();
/** /**
* The offscreen buffer as set by the renderer because of setXRenderWindowOffscreen(true) * 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!!! * NOTICE: HANDS OFF!!!
* scene_setXRenderWindowOffscreenTarget() is ONLY to be used by the renderer - DO NOT TOUCH! * 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 * scene_xRenderWindowOffscreenTarget() is used by the scene to figure the target set by an effect
*/ */

View file

@ -94,6 +94,7 @@ SceneXrender::~SceneXrender()
m_overlayWindow->destroy(); m_overlayWindow->destroy();
return; return;
} }
SceneXrender::Window::cleanup();
SceneXrender::EffectFrame::cleanup(); SceneXrender::EffectFrame::cleanup();
XRenderFreePicture(display(), front); XRenderFreePicture(display(), front);
XRenderFreePicture(display(), buffer); XRenderFreePicture(display(), buffer);
@ -276,7 +277,7 @@ void SceneXrender::windowAdded(Toplevel* c)
// SceneXrender::Window // SceneXrender::Window
//**************************************** //****************************************
QPixmap *SceneXrender::Window::temp_pixmap = 0; XRenderPicture *SceneXrender::Window::s_tempPicture = 0;
QRect SceneXrender::Window::temp_visibleRect; QRect SceneXrender::Window::temp_visibleRect;
SceneXrender::Window::Window(Toplevel* c) SceneXrender::Window::Window(Toplevel* c)
@ -295,6 +296,12 @@ SceneXrender::Window::~Window()
discardShape(); discardShape();
} }
void SceneXrender::Window::cleanup()
{
delete s_tempPicture;
s_tempPicture = NULL;
}
// Create XRender picture for the pixmap with the window contents. // Create XRender picture for the pixmap with the window contents.
Picture SceneXrender::Window::picture() Picture SceneXrender::Window::picture()
{ {
@ -406,21 +413,22 @@ QPoint SceneXrender::Window::mapToScreen(int mask, const WindowPaintData &data,
void SceneXrender::Window::prepareTempPixmap() void SceneXrender::Window::prepareTempPixmap()
{ {
const QSize oldSize = temp_visibleRect.size();
temp_visibleRect = toplevel->visibleRect().translated(-toplevel->pos()); temp_visibleRect = toplevel->visibleRect().translated(-toplevel->pos());
if (s_tempPicture && (oldSize.width() < temp_visibleRect.width() || oldSize.height() < temp_visibleRect.height())) {
if (temp_pixmap && Extensions::nonNativePixmaps()) delete s_tempPicture;
XFreePixmap(display(), temp_pixmap->handle()); // The picture owns the pixmap now s_tempPicture = NULL;
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());
scene_setXRenderOffscreenTarget(0); // invalidate, better crash than cause weird results for developers scene_setXRenderOffscreenTarget(0); // invalidate, better crash than cause weird results for developers
} }
if (Extensions::nonNativePixmaps()) { if (!s_tempPicture) {
Pixmap pix = XCreatePixmap(display(), rootWindow(), temp_pixmap->width(), temp_pixmap->height(), DefaultDepth(display(), DefaultScreen(display()))); xcb_pixmap_t pix = xcb_generate_id(connection());
*temp_pixmap = QPixmap::fromX11Pixmap(pix); 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 // paint the window
@ -543,7 +551,7 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
renderTarget = *scene_xRenderOffscreenTarget(); renderTarget = *scene_xRenderOffscreenTarget();
} else { } else {
prepareTempPixmap(); prepareTempPixmap();
renderTarget = temp_pixmap->x11PictureHandle(); renderTarget = *s_tempPicture;
} }
} else { } else {
XRenderSetPictureTransform(display(), pic, &xform); XRenderSetPictureTransform(display(), pic, &xform);
@ -699,11 +707,11 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
} }
if (blitInTempPixmap) { if (blitInTempPixmap) {
const QRect r = mapToScreen(mask, data, temp_visibleRect); const QRect r = mapToScreen(mask, data, temp_visibleRect);
XRenderSetPictureTransform(display(), temp_pixmap->x11PictureHandle(), &xform); XRenderSetPictureTransform(display(), *s_tempPicture, &xform);
XRenderSetPictureFilter(display(), temp_pixmap->x11PictureHandle(), const_cast<char*>("good"), NULL, 0); XRenderSetPictureFilter(display(), *s_tempPicture, const_cast<char*>("good"), NULL, 0);
XRenderComposite(display(), PictOpOver, temp_pixmap->x11PictureHandle(), None, buffer, XRenderComposite(display(), PictOpOver, *s_tempPicture, None, buffer,
0, 0, 0, 0, r.x(), r.y(), r.width(), r.height()); 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) { if (scaled && !blitInTempPixmap) {
@ -716,7 +724,7 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
} }
} }
if (xRenderOffscreen()) if (xRenderOffscreen())
scene_setXRenderOffscreenTarget(temp_pixmap); scene_setXRenderOffscreenTarget(*s_tempPicture);
} }
void SceneXrender::screenGeometryChanged(const QSize &size) void SceneXrender::screenGeometryChanged(const QSize &size)

View file

@ -84,6 +84,7 @@ public:
void discardAlpha(); void discardAlpha();
QRegion transformedShape() const; QRegion transformedShape() const;
void setTransformedShape(const QRegion& shape); void setTransformedShape(const QRegion& shape);
static void cleanup();
private: private:
Picture picture(); Picture picture();
Picture alphaMask(double opacity); Picture alphaMask(double opacity);
@ -95,8 +96,8 @@ private:
Picture alpha; Picture alpha;
double alpha_cached_opacity; double alpha_cached_opacity;
QRegion transformed_shape; QRegion transformed_shape;
static QPixmap *temp_pixmap;
static QRect temp_visibleRect; static QRect temp_visibleRect;
static XRenderPicture *s_tempPicture;
}; };
class SceneXrender::EffectFrame class SceneXrender::EffectFrame