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) {
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

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 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;
}

View file

@ -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
*/

View file

@ -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<char*>("good"), NULL, 0);
XRenderComposite(display(), PictOpOver, temp_pixmap->x11PictureHandle(), None, buffer,
XRenderSetPictureTransform(display(), *s_tempPicture, &xform);
XRenderSetPictureFilter(display(), *s_tempPicture, const_cast<char*>("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)

View file

@ -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