KWin supports graphicssystem Raster

With raster a QPixmap is no longer a XPixmap which fails all code
which assumes that an QPixmap is an XPixmap. Depending on were in
the codebase we either convert such pixmaps to images (OpenGL) or
create a XPixmap and use QPixmap::fromX11Pixmap to get a "real"
pixmap.

It is possible that there are more code pathes were we would need
a XPixmap. Currently tested is basic functionality of no-compositing,
XRender compositing, OpenGl/GLX and OpenGL ES/EGL compositing.

For OpenGL compositing raster might result in performance improvements,
for XRender it is possible that there are regressions when using raster.
By default KWin uses whatever is the default of the system, so we just
no longer enforce native.

Of course it is a bad idea to use graphicssystem OpenGL. As that
is broken anyways in Qt, we do not check for it.

Many thanks to Philipp Knechtges for bringing up the issue, convincing
me that we need it and providing most of the patch.

REVIEW: 101132
CCMAIL: Philipp.Knechtges@rwth-aachen.de
This commit is contained in:
Martin Gräßlin 2011-05-12 18:52:38 +02:00
parent 264fcfa49f
commit 234ec644d2
10 changed files with 95 additions and 37 deletions

View file

@ -582,17 +582,25 @@ void Client::resizeDecorationPixmaps()
QRect lr, rr, tr, br;
layoutDecorationRects(lr, tr, rr, br, DecorationRelative);
if (decorationPixmapTop.size() != tr.size())
decorationPixmapTop = QPixmap(tr.size());
if (decorationPixmapTop.size() != tr.size()) {
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), tr.width(), tr.height(), 32);
decorationPixmapTop = QPixmap::fromX11Pixmap(pixmap, QPixmap::ExplicitlyShared);
}
if (decorationPixmapBottom.size() != br.size())
decorationPixmapBottom = QPixmap(br.size());
if (decorationPixmapBottom.size() != br.size()) {
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), br.width(), br.height(), 32);
decorationPixmapBottom = QPixmap::fromX11Pixmap(pixmap, QPixmap::ExplicitlyShared);
}
if (decorationPixmapLeft.size() != lr.size())
decorationPixmapLeft = QPixmap(lr.size());
if (decorationPixmapLeft.size() != lr.size()) {
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), lr.width(), lr.height(), 32);
decorationPixmapLeft = QPixmap::fromX11Pixmap(pixmap, QPixmap::ExplicitlyShared);
}
if (decorationPixmapRight.size() != rr.size())
decorationPixmapRight = QPixmap(rr.size());
if (decorationPixmapRight.size() != rr.size()) {
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), rr.width(), rr.height(), 32);
decorationPixmapRight = QPixmap::fromX11Pixmap(pixmap, QPixmap::ExplicitlyShared);
}
#ifdef HAVE_XRENDER
if (Extensions::renderAvailable()) {

View file

@ -116,6 +116,13 @@ void ScreenShotEffect::postPaintScreen()
grabPointerImage(img, m_scheduledScreenshot->x() + left, m_scheduledScreenshot->y() + top);
}
m_lastScreenshot = QPixmap::fromImage(img);
if (m_lastScreenshot.handle() == 0) {
Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_lastScreenshot.width(),
m_lastScreenshot.height(), XDefaultDepth(display(), QX11Info::appScreen()));
m_lastScreenshot = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&m_lastScreenshot);
p.drawImage(QPoint(0, 0), img);
}
emit screenshotCreated(m_lastScreenshot.handle());
}
delete offscreenTexture;

View file

@ -690,9 +690,9 @@ QImage GLTexture::convertToGLFormat(const QImage& img) const
// Copied from Qt's QGLWidget::convertToGLFormat()
QImage res(img.size(), QImage::Format_ARGB32);
#ifdef KWIN_HAVE_OPENGLES
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_RGBA);
#else
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32), GL_BGRA);
convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32_Premultiplied), GL_BGRA);
#endif
return res;
}

View file

@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QPixmap>
#include <QPainter>
#include <kdebug.h>
#include <QPaintEngine>
namespace KWin
{
@ -191,8 +192,17 @@ static Picture createPicture(Pixmap pix, int depth)
}
XRenderPicture::XRenderPicture(QPixmap pix)
: d(new XRenderPictureData(createPicture(pix.handle(), pix.depth())))
{
if (pix.paintEngine()->type() != QPaintEngine::X11 || pix.handle() == 0) {
Pixmap xPix = XCreatePixmap(display(), rootWindow(), pix.width(), pix.height(), pix.depth());
QPixmap tempPix = QPixmap::fromX11Pixmap(xPix);
tempPix.fill(Qt::transparent);
QPainter p(&tempPix);
p.drawPixmap(QPoint(0, 0), pix);
d = new XRenderPictureData(createPicture(tempPix.handle(), tempPix.depth()));
} else {
d = new XRenderPictureData(createPicture(pix.handle(), pix.depth()));
}
}
XRenderPicture::XRenderPicture(Pixmap pix, int depth)

View file

@ -404,10 +404,6 @@ KDE_EXPORT int kdemain(int argc, char * argv[])
}
}
// KWin only works properly with Qt's native X11 backend; override any compile-time
// or command line settings to raster or OpenGL.
QApplication::setGraphicsSystem("native");
Display* dpy = XOpenDisplay(NULL);
if (!dpy) {
fprintf(stderr, "%s: FATAL ERROR while trying to open display %s\n",

View file

@ -96,13 +96,18 @@ void Outline::showWithX()
CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attr);
m_initialized = true;
}
int defaultDepth = XDefaultDepth(QX11Info::display(), QX11Info::appScreen());
// left/right parts are between top/bottom, they don't reach as far as the corners
XMoveResizeWindow(QX11Info::display(), m_leftOutline, m_outlineGeometry.x(), m_outlineGeometry.y() + 5, 5, m_outlineGeometry.height() - 10);
XMoveResizeWindow(QX11Info::display(), m_rightOutline, m_outlineGeometry.x() + m_outlineGeometry.width() - 5, m_outlineGeometry.y() + 5, 5, m_outlineGeometry.height() - 10);
XMoveResizeWindow(QX11Info::display(), m_topOutline, m_outlineGeometry.x(), m_outlineGeometry.y(), m_outlineGeometry.width(), 5);
XMoveResizeWindow(QX11Info::display(), m_bottomOutline, m_outlineGeometry.x(), m_outlineGeometry.y() + m_outlineGeometry.height() - 5, m_outlineGeometry.width(), 5);
{
QPixmap pix(5, m_outlineGeometry.height() - 10);
Pixmap xpix = XCreatePixmap(display(), rootWindow(), 5,
m_outlineGeometry.height() - 10, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(0, 0, 0, pix.height() - 1);
@ -115,9 +120,13 @@ void Outline::showWithX()
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_leftOutline, pix.handle());
XSetWindowBackgroundPixmap(QX11Info::display(), m_rightOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
{
QPixmap pix(m_outlineGeometry.width(), 5);
Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_outlineGeometry.width(),
5, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(0, 0, pix.width() - 1 - 0, 0);
@ -137,9 +146,13 @@ void Outline::showWithX()
p.drawLine(pix.width() - 1 - 2, 2, pix.width() - 1 - 2, 4);
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_topOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
{
QPixmap pix(m_outlineGeometry.width(), 5);
Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_outlineGeometry.width(),
5, defaultDepth);
QPixmap pix = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared);
QPainter p(&pix);
p.setPen(Qt::white);
p.drawLine(4, 0, pix.width() - 1 - 4, 0);
@ -159,6 +172,8 @@ void Outline::showWithX()
p.drawLine(pix.width() - 1 - 2, 0, pix.width() - 1 - 2, 2);
p.end();
XSetWindowBackgroundPixmap(QX11Info::display(), m_bottomOutline, pix.handle());
// According to the XSetWindowBackgroundPixmap documentation the pixmap can be freed.
XFreePixmap (display(), xpix);
}
XClearWindow(QX11Info::display(), m_leftOutline);
XClearWindow(QX11Info::display(), m_rightOutline);

View file

@ -92,6 +92,7 @@ Sources and other compositing managers:
#include <QVector2D>
#include <QVector4D>
#include <QMatrix4x4>
#include <QPaintEngine>
namespace KWin
{
@ -278,6 +279,13 @@ SceneOpenGL::Texture::Texture(const Pixmap& pix, const QSize& size, int depth) :
load(pix, size, depth);
}
SceneOpenGL::Texture::Texture(const QPixmap& pix, GLenum target)
: GLTexture()
{
init();
load(pix, target);
}
SceneOpenGL::Texture::~Texture()
{
discard();
@ -329,9 +337,15 @@ bool SceneOpenGL::Texture::load(const QImage& image, GLenum target)
bool SceneOpenGL::Texture::load(const QPixmap& pixmap, GLenum target)
{
Q_UNUSED(target); // SceneOpenGL::Texture::findTarget() detects the target
if (pixmap.isNull())
return false;
// Checking whether QPixmap comes with its own X11 Pixmap
if (pixmap.paintEngine()->type() != QPaintEngine::X11 || pixmap.handle() == 0) {
return GLTexture::load(pixmap.toImage(), target);
}
// use the X11 pixmap provided by Qt
return load(pixmap.handle(), pixmap.size(), pixmap.depth());
}
@ -618,7 +632,7 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType
// texture doesn't need updating, just bind it
glBindTexture(decorationTexture->target(), decorationTexture->texture());
} else if (!decoration->isNull()) {
bool success = decorationTexture->load(decoration->handle(), decoration->size(), decoration->depth());
bool success = decorationTexture->load(*decoration);
if (!success) {
kDebug(1212) << "Failed to bind decoartion";
return;
@ -1316,8 +1330,7 @@ void SceneOpenGL::EffectFrame::render(QRegion region, double opacity, double fra
if (!m_effectFrame->selection().isNull()) {
if (!m_selectionTexture) { // Lazy creation
QPixmap pixmap = m_effectFrame->selectionFrame().framePixmap();
m_selectionTexture = new Texture(pixmap.handle(), pixmap.size(), pixmap.depth());
m_selectionTexture->setYInverted(true);
m_selectionTexture = new Texture(pixmap);
}
if (shader) {
const float a = opacity * frameOpacity;
@ -1372,10 +1385,7 @@ void SceneOpenGL::EffectFrame::render(QRegion region, double opacity, double fra
}
if (!m_iconTexture) { // lazy creation
m_iconTexture = new Texture(m_effectFrame->icon().handle(),
m_effectFrame->icon().size(),
m_effectFrame->icon().depth());
m_iconTexture->setYInverted(true);
m_iconTexture = new Texture(m_effectFrame->icon());
}
m_iconTexture->bind();
m_iconTexture->render(region, QRect(topLeft, m_effectFrame->iconSize()));
@ -1437,8 +1447,7 @@ void SceneOpenGL::EffectFrame::updateTexture()
delete m_texture;
if (m_effectFrame->style() == EffectFrameStyled) {
QPixmap pixmap = m_effectFrame->frame().framePixmap();
m_texture = new Texture(pixmap.handle(), pixmap.size(), pixmap.depth());
m_texture->setYInverted(true);
m_texture = new Texture(pixmap);
}
}
@ -1472,8 +1481,7 @@ void SceneOpenGL::EffectFrame::updateTextTexture()
p.setPen(Qt::white);
p.drawText(rect, m_effectFrame->alignment(), text);
p.end();
m_textTexture = new Texture(m_textPixmap->handle(), m_textPixmap->size(), m_textPixmap->depth());
m_textTexture->setYInverted(true);
m_textTexture = new Texture(*m_textPixmap);
}
void SceneOpenGL::EffectFrame::updateUnstyledTexture()
@ -1491,8 +1499,7 @@ void SceneOpenGL::EffectFrame::updateUnstyledTexture()
p.drawEllipse(m_unstyledPixmap->rect());
p.end();
#undef CS
m_unstyledTexture = new Texture(m_unstyledPixmap->handle(), m_unstyledPixmap->size(), m_unstyledPixmap->depth());
m_unstyledTexture->setYInverted(true);
m_unstyledTexture = new Texture(*m_unstyledPixmap);
}
void SceneOpenGL::EffectFrame::cleanup()
@ -1563,7 +1570,7 @@ SceneOpenGL::Texture *SceneOpenGLShadow::textureForQuadType(WindowQuadType type)
if (texture->texture() != None) {
glBindTexture(texture->target(), texture->texture());
} else if (!pixmap.isNull()) {
const bool success = texture->load(pixmap.handle(), pixmap.size(), pixmap.depth());
const bool success = texture->load(pixmap);
if (!success) {
kDebug(1212) << "Failed to bind shadow pixmap";
return NULL;

View file

@ -106,13 +106,10 @@ class SceneOpenGL::Texture
{
public:
Texture();
Texture(const Pixmap& pix, const QSize& size, int depth);
Texture(const QPixmap& pix, GLenum target = GL_TEXTURE_2D);
virtual ~Texture();
using GLTexture::load;
virtual bool load(const Pixmap& pix, const QSize& size, int depth,
QRegion region);
virtual bool load(const Pixmap& pix, const QSize& size, int depth);
virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D);
virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
virtual void discard();
@ -124,9 +121,13 @@ public:
}
protected:
Texture(const Pixmap& pix, const QSize& size, int depth);
void findTarget();
QRegion optimizeBindDamage(const QRegion& reg, int limit);
void createTexture();
virtual bool load(const Pixmap& pix, const QSize& size, int depth,
QRegion region);
virtual bool load(const Pixmap& pix, const QSize& size, int depth);
private:
void init();
@ -134,6 +135,8 @@ private:
#ifndef KWIN_HAVE_OPENGLES
GLXPixmap glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
#endif
friend class SceneOpenGL::Window;
};
class SceneOpenGL::Window

View file

@ -258,6 +258,7 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size,
eglDestroyImageKHR(dpy, image);
unbind();
checkGLError("load texture");
setYInverted(true);
}
return true;
}

View file

@ -53,6 +53,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kxerrorhandler.h>
#include <QtGui/QPainter>
#include <QtGui/QPaintEngine>
namespace KWin
{
@ -190,6 +191,12 @@ void SceneXrender::selfCheckSetup()
img.setPixel(1, 1, QColor(Qt::black).rgb());
img.setPixel(2, 1, QColor(Qt::white).rgb());
QPixmap pix = QPixmap::fromImage(img);
if (pix.handle() == 0) {
Pixmap xPix = XCreatePixmap(display(), rootWindow(), pix.width(), pix.height(), DefaultDepth(display(), DefaultScreen(display())));
pix = QPixmap::fromX11Pixmap(xPix);
QPainter p(&pix);
p.drawImage(QPoint(0, 0), img);
}
foreach (const QPoint & p, selfCheckPoints()) {
XSetWindowAttributes wa;
wa.override_redirect = True;
@ -585,6 +592,10 @@ void SceneXrender::Window::prepareTempPixmap(const QPixmap *left, const QPixmap
temp_pixmap = new QPixmap(r.width(), r.height());
else if (temp_pixmap->width() < r.width() || temp_pixmap->height() < r.height())
*temp_pixmap = QPixmap(r.width(), r.height());
if (temp_pixmap->paintEngine()->type() != QPaintEngine::X11 || temp_pixmap->handle() == 0) {
Pixmap pix = XCreatePixmap(display(), rootWindow(), temp_pixmap->width(), temp_pixmap->height(), DefaultDepth(display(), DefaultScreen(display())));
*temp_pixmap = QPixmap::fromX11Pixmap(pix);
}
temp_pixmap->fill(Qt::transparent);