add offscreen render support to xrender

REVIEW: 104151
cherry-picked from b9534b4ca82973c2e99451b2e151241fd1b6e7cb
This commit is contained in:
Thomas Lübking 2012-03-04 09:52:32 +01:00
parent e3d2cb9a61
commit 5e2414544f
3 changed files with 99 additions and 5 deletions

View file

@ -23,6 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
#include <QStack>
#include <QVector>
#include <QPixmap>
#include <QPainter>
@ -212,6 +213,55 @@ XRenderPicture::XRenderPicture(Pixmap pix, int depth)
{
}
static QPixmap *s_offscreenTarget = 0;
static QStack<XRenderPicture*> s_scene_offscreenTargetStack;
static int s_renderOffscreen = 0;
void scene_setXRenderOffscreenTarget(QPixmap *pix)
{
s_offscreenTarget = pix;
}
XRenderPicture *scene_xRenderOffscreenTarget()
{
return s_scene_offscreenTargetStack.isEmpty() ? 0 : s_scene_offscreenTargetStack.top();
}
void setXRenderOffscreen(bool b)
{
b ? ++s_renderOffscreen : --s_renderOffscreen;
if (s_renderOffscreen < 0) {
s_renderOffscreen = 0;
qWarning("*** SOMETHING IS MESSED UP WITH YOUR setXRenderOffscreen() USAGE ***");
}
}
void xRenderPushTarget(XRenderPicture *pic)
{
s_scene_offscreenTargetStack.push(pic);
++s_renderOffscreen;
}
void xRenderPopTarget()
{
s_scene_offscreenTargetStack.pop();
--s_renderOffscreen;
if (s_renderOffscreen < 0) {
s_renderOffscreen = 0;
qWarning("*** SOMETHING IS MESSED UP WITH YOUR xRenderPopTarget() USAGE ***");
}
}
bool xRenderOffscreen()
{
return s_renderOffscreen;
}
QPixmap *xRenderOffscreenTarget()
{
return s_offscreenTarget;
}
} // namespace
#endif

View file

@ -126,6 +126,42 @@ KWIN_EXPORT XRenderPicture xRenderBlendPicture(double opacity);
KWIN_EXPORT XRenderPicture xRenderFill(const XRenderColor *c);
KWIN_EXPORT XRenderPicture xRenderFill(const QColor &c);
/**
* Allows to render a window into a (transparent) pixmap
* NOTICE: the result can be queried as xRenderWindowOffscreenTarget()
* NOTICE: it may be 0
* NOTICE: when done call setXRenderWindowOffscreen(false) to continue normal render process
*/
KWIN_EXPORT void setXRenderOffscreen(bool b);
/**
* Allows to define a persistent effect member as render target
* The window (including shadows) is rendered into the top left corner
* NOTICE: do NOT call setXRenderOffscreen(true) in addition!
* NOTICE: do not forget to xRenderPopTarget once you're done to continue the normal render process
*/
KWIN_EXPORT void xRenderPushTarget(XRenderPicture *pic);
KWIN_EXPORT void xRenderPopTarget();
/**
* Whether windows are currently rendered into an offscreen target buffer
*/
KWIN_EXPORT bool xRenderOffscreen();
/**
* The offscreen buffer as set by the renderer because of setXRenderWindowOffscreen(true)
*/
KWIN_EXPORT QPixmap *xRenderOffscreenTarget();
/**
* NOTICE: HANDS OFF!!!
* scene_setXRenderWindowOffscreenTarget() is ONLY to be used by the renderer - DO NOT TOUCH!
*/
KWIN_EXPORT void scene_setXRenderOffscreenTarget(QPixmap *pix);
/**
* scene_xRenderWindowOffscreenTarget() is used by the scene to figure the target set by an effect
*/
KWIN_EXPORT XRenderPicture *scene_xRenderOffscreenTarget();
} // namespace
#endif

View file

@ -417,8 +417,10 @@ void SceneXrender::Window::prepareTempPixmap()
XFreePixmap(display(), temp_pixmap->handle()); // The picture owns the pixmap now
if (!temp_pixmap)
temp_pixmap = new QPixmap(r.width(), r.height());
else if (temp_pixmap->width() < r.width() || temp_pixmap->height() < r.height())
else if (temp_pixmap->width() < r.width() || temp_pixmap->height() < r.height()) {
*temp_pixmap = QPixmap(r.width(), r.height());
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);
@ -532,12 +534,16 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
// the window has border
// This solves a number of glitches and on top of this
// it optimizes painting quite a bit
const bool blitInTempPixmap = scaled && (wantShadow || (client && !client->noBorder()) || (deleted && !deleted->noBorder()));
Picture renderTarget = buffer;
const bool blitInTempPixmap = xRenderOffscreen() || (scaled && (wantShadow || (client && !client->noBorder()) || (deleted && !deleted->noBorder())));
Picture renderTarget = buffer;
if (blitInTempPixmap) {
prepareTempPixmap();
renderTarget = temp_pixmap->x11PictureHandle();
if (scene_xRenderOffscreenTarget())
renderTarget = *scene_xRenderOffscreenTarget();
else {
prepareTempPixmap();
renderTarget = temp_pixmap->x11PictureHandle();
}
} else {
XRenderSetPictureTransform(display(), pic, &xform);
if (filter == ImageFilterGood) {
@ -702,6 +708,8 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
XRenderChangePicture(display(), pic, CPRepeat, &attr);
}
}
if (xRenderOffscreen())
scene_setXRenderOffscreenTarget(temp_pixmap);
}
void SceneXrender::screenGeometryChanged(const QSize &size)