diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp index c1c3e9409f..77b663a4a3 100644 --- a/libkwineffects/kwingltexture.cpp +++ b/libkwineffects/kwingltexture.cpp @@ -218,6 +218,52 @@ bool GLTexture::load(const QImage& image, GLenum target) return true; } +void GLTexture::update(const QImage &image, const QPoint &offset, const QRect &src) +{ + if (image.isNull() || isNull()) + return; + + Q_D(GLTexture); +#ifdef KWIN_HAVE_OPENGLES + static bool s_supportsUnpack = hasGLExtension("GL_EXT_unpack_subimage"); +#else + static bool s_supportsUnpack = true; +#endif + + int width = image.width(); + int height = image.height(); + QImage tmpImage; + if (!src.isNull()) { + if (s_supportsUnpack) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width()); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.x()); + glPixelStorei(GL_UNPACK_SKIP_ROWS, src.y()); + } else { + tmpImage = image.copy(src); + } + width = src.width(); + height = src.height(); + } + const QImage &img = d->convertToGLFormat(tmpImage.isNull() ? image : tmpImage); + + bind(); +#ifdef KWIN_HAVE_OPENGLES + // format and internal format have to match in ES, GL_RGBA8 and GL_BGRA are not available + // see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml + glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); +#else + glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height, GL_BGRA, GL_UNSIGNED_BYTE, img.bits()); +#endif + checkGLError("update texture"); + unbind(); + setDirty(); + if (!src.isNull() && s_supportsUnpack) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); + } +} + bool GLTexture::load(const QPixmap& pixmap, GLenum target) { if (pixmap.isNull()) @@ -459,8 +505,10 @@ QImage GLTexturePrivate::convertToGLFormat(const QImage& img) const q++; } } - } else { + } else if (img.format() != QImage::Format_ARGB32_Premultiplied) { res = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } else { + return img; } #endif return res; diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h index a60ae48049..71b8078775 100644 --- a/libkwineffects/kwingltexture.h +++ b/libkwineffects/kwingltexture.h @@ -70,6 +70,7 @@ public: virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D); virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D); virtual bool load(const QString& fileName); + void update(const QImage& image, const QPoint &offset = QPoint(0, 0), const QRect &src = QRect()); virtual void discard(); void bind(); void unbind(); diff --git a/paintredirector.cpp b/paintredirector.cpp index 3bbe9d0ef0..ee6b41422b 100644 --- a/paintredirector.cpp +++ b/paintredirector.cpp @@ -28,6 +28,7 @@ DEALINGS IN THE SOFTWARE. #include "client.h" #include "deleted.h" #include "effects.h" +#include #include #include #include @@ -228,7 +229,7 @@ void PaintRedirector::resizePixmaps() } } -const QPixmap *PaintRedirector::pixmap(PaintRedirector::DecorationPixmap border) const +GLTexture *PaintRedirector::texture(PaintRedirector::DecorationPixmap border) const { Q_UNUSED(border) return NULL; @@ -243,34 +244,45 @@ xcb_render_picture_t PaintRedirector::picture(PaintRedirector::DecorationPixmap OpenGLPaintRedirector::OpenGLPaintRedirector(Client *c, QWidget *widget) : PaintRedirector(c, widget) { + for (int i=0; isize() != size) { + delete m_textures[border]; + m_textures[border] = new GLTexture(size.width(), size.height()); + m_textures[border]->setYInverted(true); } - m_pixmaps[border].fill(Qt::transparent); +} + +void OpenGLPaintRedirector::preparePaint(const QPixmap &pending) +{ + m_tempImage = pending.toImage(); } void OpenGLPaintRedirector::paint(PaintRedirector::DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®) { - QPainter pt(&m_pixmaps[border]); - pt.translate(-r.topLeft()); - pt.setCompositionMode(QPainter::CompositionMode_Source); - pt.setClipRegion(reg); - pt.drawPixmap(b.topLeft(), src); - pt.end(); + Q_UNUSED(src) + // clip the sub area + const QRect bounding = reg.boundingRect(); + + m_textures[border]->update(m_tempImage, bounding.topLeft() - r.topLeft(), QRect(bounding.topLeft() - b.topLeft(), bounding.size())); } RasterXRenderPaintRedirector::RasterXRenderPaintRedirector(Client *c, QWidget *widget) diff --git a/paintredirector.h b/paintredirector.h index 06279750f4..68d06acb4a 100644 --- a/paintredirector.h +++ b/paintredirector.h @@ -40,6 +40,7 @@ namespace KWin class Client; class Deleted; class XRenderPicture; +class GLTexture; // This class redirects all painting of a given widget (including its children) // into a paint device (QPixmap). @@ -90,8 +91,8 @@ public slots: void ensurePixmapsPainted(); protected: PaintRedirector(Client *c, QWidget* widget); - virtual const QPixmap *pixmap(DecorationPixmap border) const; virtual xcb_render_picture_t picture(DecorationPixmap border) const; + virtual GLTexture *texture(DecorationPixmap border) const; virtual void resize(DecorationPixmap border, const QSize &size) = 0; virtual void preparePaint(const QPixmap &pending); virtual void paint(DecorationPixmap border, const QRect& r, const QRect &b, const QPixmap& src, const QRegion ®) = 0; @@ -121,12 +122,14 @@ public: virtual ~OpenGLPaintRedirector(); protected: - virtual const QPixmap *pixmap(DecorationPixmap border) const; virtual void resize(DecorationPixmap border, const QSize &size); virtual void paint(DecorationPixmap border, const QRect &r, const QRect &b, const QPixmap &src, const QRegion ®); + virtual GLTexture *texture(DecorationPixmap border) const; + virtual void preparePaint(const QPixmap &pending); private: - QPixmap m_pixmaps[PixmapCount]; + QImage m_tempImage; + GLTexture* m_textures[PixmapCount]; }; class NativeXRenderPaintRedirector : public PaintRedirector @@ -166,30 +169,30 @@ private: template <> inline -const QPixmap *PaintRedirector::bottomDecoPixmap() const +GLTexture *PaintRedirector::bottomDecoPixmap() const { - return pixmap(BottomPixmap); + return texture(BottomPixmap); } template <> inline -const QPixmap *PaintRedirector::leftDecoPixmap() const +GLTexture *PaintRedirector::leftDecoPixmap() const { - return pixmap(LeftPixmap); + return texture(LeftPixmap); } template <> inline -const QPixmap *PaintRedirector::rightDecoPixmap() const +GLTexture *PaintRedirector::rightDecoPixmap() const { - return pixmap(RightPixmap); + return texture(RightPixmap); } template <> inline -const QPixmap *PaintRedirector::topDecoPixmap() const +GLTexture *PaintRedirector::topDecoPixmap() const { - return pixmap(TopPixmap); + return texture(TopPixmap); } template <> diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 793ffbc54b..ff5acc136c 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -900,20 +900,12 @@ SceneOpenGL::Window::Window(Toplevel* c) : Scene::Window(c) , m_scene(NULL) , texture(NULL) - , topTexture(NULL) - , leftTexture(NULL) - , rightTexture(NULL) - , bottomTexture(NULL) { } SceneOpenGL::Window::~Window() { delete texture; - delete topTexture; - delete leftTexture; - delete rightTexture; - delete bottomTexture; } // Bind the window pixmap to an OpenGL texture. @@ -950,21 +942,6 @@ void SceneOpenGL::Window::discardTexture() if (texture) { texture->discard(); } - if (!Extensions::nonNativePixmaps()) { - // only discard if the deco pixmaps use TFP - if (topTexture) { - topTexture->discard(); - } - if (leftTexture) { - leftTexture->discard(); - } - if (rightTexture) { - rightTexture->discard(); - } - if (bottomTexture) { - bottomTexture->discard(); - } - } } // This call is used in SceneOpenGL::windowGeometryShapeChanged(), @@ -1112,15 +1089,9 @@ void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QR } WindowQuadList decoration = data.quads.select(WindowQuadDecoration); QRect topRect, leftRect, rightRect, bottomRect; - const bool updateDeco = redirector->requiresRepaint(); t->layoutDecorationRects(leftRect, topRect, rightRect, bottomRect, Client::WindowRelative); - const QPixmap *left = redirector->leftDecoPixmap(); - const QPixmap *top = redirector->topDecoPixmap(); - const QPixmap *right = redirector->rightDecoPixmap(); - const QPixmap *bottom = redirector->bottomDecoPixmap(); - WindowQuadList topList, leftList, rightList, bottomList; foreach (const WindowQuad & quad, decoration) { @@ -1143,58 +1114,26 @@ void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QR } redirector->ensurePixmapsPainted(); - paintDecoration(top, DecorationTop, region, topRect, data, topList, updateDeco, hardwareClipping); - paintDecoration(left, DecorationLeft, region, leftRect, data, leftList, updateDeco, hardwareClipping); - paintDecoration(right, DecorationRight, region, rightRect, data, rightList, updateDeco, hardwareClipping); - paintDecoration(bottom, DecorationBottom, region, bottomRect, data, bottomList, updateDeco, hardwareClipping); + GLTexture *left = redirector->leftDecoPixmap(); + GLTexture *top = redirector->topDecoPixmap(); + GLTexture *right = redirector->rightDecoPixmap(); + GLTexture *bottom = redirector->bottomDecoPixmap(); + paintDecoration(top, DecorationTop, region, topRect, data, topList, hardwareClipping); + paintDecoration(left, DecorationLeft, region, leftRect, data, leftList, hardwareClipping); + paintDecoration(right, DecorationRight, region, rightRect, data, rightList, hardwareClipping); + paintDecoration(bottom, DecorationBottom, region, bottomRect, data, bottomList, hardwareClipping); redirector->markAsRepainted(); } -void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType decorationType, +void SceneOpenGL::Window::paintDecoration(GLTexture *decorationTexture, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, - const WindowQuadList& quads, bool updateDeco, bool hardwareClipping) + const WindowQuadList& quads, bool hardwareClipping) { - SceneOpenGL::Texture* decorationTexture; - switch(decorationType) { - case DecorationTop: - if (!topTexture) { - topTexture = m_scene->createTexture(); - } - decorationTexture = topTexture; - break; - case DecorationLeft: - if (!leftTexture) { - leftTexture = m_scene->createTexture(); - } - decorationTexture = leftTexture; - break; - case DecorationRight: - if (!rightTexture) { - rightTexture = m_scene->createTexture(); - } - decorationTexture = rightTexture; - break; - case DecorationBottom: - if (!bottomTexture) { - bottomTexture = m_scene->createTexture(); - } - decorationTexture = bottomTexture; - break; - default: + if (!decorationTexture) { return; } - if (decoration->isNull() || !decorationTexture) { - return; - } - if (decorationTexture->isNull() || updateDeco) { - bool success = decorationTexture->load(*decoration); - if (!success) { - kDebug(1212) << "Failed to bind decoartion"; - return; - } - } // We have to update the texture although we do not paint anything. // This is especially needed if we draw the opaque part of the window @@ -1262,7 +1201,7 @@ void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintDa #endif } -void SceneOpenGL::Window::makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const +void SceneOpenGL::Window::makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, GLTexture *tex) const { QVector vertices; QVector texcoords; @@ -1350,21 +1289,37 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu GLTexture *SceneOpenGL::Window::textureForType(SceneOpenGL::Window::TextureType type) { GLTexture *tex = NULL; + PaintRedirector *redirector = NULL; + if (type != Content && type != Shadow) { + if (toplevel->isClient()) { + redirector = static_cast(toplevel)->decorationPaintRedirector(); + } else if (toplevel->isDeleted()) { + redirector = static_cast(toplevel)->decorationPaintRedirector(); + } + } switch(type) { case Content: tex = texture; break; case DecorationTop: - tex = topTexture; + if (redirector) { + tex = redirector->topDecoPixmap(); + } break; case DecorationLeft: - tex = leftTexture; + if (redirector) { + tex = redirector->leftDecoPixmap(); + } break; case DecorationRight: - tex = rightTexture; + if (redirector) { + tex = redirector->rightDecoPixmap(); + } break; case DecorationBottom: - tex = bottomTexture; + if (redirector) { + tex = redirector->bottomDecoPixmap(); + } break; case Shadow: tex = static_cast(m_shadow)->shadowTexture(); diff --git a/scene_opengl.h b/scene_opengl.h index cd3dd86952..9341287aa1 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -216,9 +216,9 @@ protected: }; QMatrix4x4 transformation(int mask, const WindowPaintData &data) const; - void paintDecoration(const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco, bool hardwareClipping); + void paintDecoration(GLTexture *decorationTexture, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool hardwareClipping); void paintShadow(const QRegion ®ion, const WindowPaintData &data, bool hardwareClipping); - void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const; + void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, GLTexture *tex) const; void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized, bool hardwareClipping); /** * @brief Called from performPaint once it is determined whether the window will be painted. @@ -275,10 +275,6 @@ private: template void paintDecorations(const WindowPaintData &data, const QRegion ®ion, bool hardwareClipping); Texture *texture; - Texture *topTexture; - Texture *leftTexture; - Texture *rightTexture; - Texture *bottomTexture; }; class SceneOpenGL2Window : public SceneOpenGL::Window