OpenGLPaintRedirector updates textures directly
Ownership of decoration textures is moved from SceneOpenGL::Window to OpenGLPaintRedirector. The PaintRedirector is responsible for updating the textures whenever they change. For this GLTexture is extended by an update(QImage, QPoint) method which uses glTexSubImage2D to update only the changed parts. The big advantage compared to before is that if e.g. only a button is animated only the button part is updated instead of the complete deco part.
This commit is contained in:
parent
fba7504063
commit
aa549f45d5
6 changed files with 122 additions and 107 deletions
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -28,6 +28,7 @@ DEALINGS IN THE SOFTWARE.
|
|||
#include "client.h"
|
||||
#include "deleted.h"
|
||||
#include "effects.h"
|
||||
#include <kwinglutils.h>
|
||||
#include <kwinxrenderutils.h>
|
||||
#include <kdebug.h>
|
||||
#include <QPaintEngine>
|
||||
|
@ -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; i<PixmapCount; ++i) {
|
||||
m_textures[i] = NULL;
|
||||
}
|
||||
resizePixmaps();
|
||||
}
|
||||
|
||||
OpenGLPaintRedirector::~OpenGLPaintRedirector()
|
||||
{
|
||||
for (int i=0; i<PixmapCount; ++i) {
|
||||
delete m_textures[i];
|
||||
}
|
||||
}
|
||||
|
||||
const QPixmap *OpenGLPaintRedirector::pixmap(PaintRedirector::DecorationPixmap border) const
|
||||
GLTexture *OpenGLPaintRedirector::texture(PaintRedirector::DecorationPixmap border) const
|
||||
{
|
||||
return &m_pixmaps[border];
|
||||
return m_textures[border];
|
||||
}
|
||||
|
||||
void OpenGLPaintRedirector::resize(PaintRedirector::DecorationPixmap border, const QSize &size)
|
||||
{
|
||||
if (m_pixmaps[border].size() != size) {
|
||||
m_pixmaps[border] = QPixmap(size);
|
||||
if (!m_textures[border] || m_textures[border]->size() != 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)
|
||||
|
|
|
@ -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 <>
|
||||
|
|
109
scene_opengl.cpp
109
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*>();
|
||||
const QPixmap *top = redirector->topDecoPixmap<const QPixmap*>();
|
||||
const QPixmap *right = redirector->rightDecoPixmap<const QPixmap*>();
|
||||
const QPixmap *bottom = redirector->bottomDecoPixmap<const QPixmap*>();
|
||||
|
||||
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*>();
|
||||
GLTexture *top = redirector->topDecoPixmap<GLTexture*>();
|
||||
GLTexture *right = redirector->rightDecoPixmap<GLTexture*>();
|
||||
GLTexture *bottom = redirector->bottomDecoPixmap<GLTexture*>();
|
||||
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<float> vertices;
|
||||
QVector<float> 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<Client*>(toplevel)->decorationPaintRedirector();
|
||||
} else if (toplevel->isDeleted()) {
|
||||
redirector = static_cast<Deleted*>(toplevel)->decorationPaintRedirector();
|
||||
}
|
||||
}
|
||||
switch(type) {
|
||||
case Content:
|
||||
tex = texture;
|
||||
break;
|
||||
case DecorationTop:
|
||||
tex = topTexture;
|
||||
if (redirector) {
|
||||
tex = redirector->topDecoPixmap<GLTexture*>();
|
||||
}
|
||||
break;
|
||||
case DecorationLeft:
|
||||
tex = leftTexture;
|
||||
if (redirector) {
|
||||
tex = redirector->leftDecoPixmap<GLTexture*>();
|
||||
}
|
||||
break;
|
||||
case DecorationRight:
|
||||
tex = rightTexture;
|
||||
if (redirector) {
|
||||
tex = redirector->rightDecoPixmap<GLTexture*>();
|
||||
}
|
||||
break;
|
||||
case DecorationBottom:
|
||||
tex = bottomTexture;
|
||||
if (redirector) {
|
||||
tex = redirector->bottomDecoPixmap<GLTexture*>();
|
||||
}
|
||||
break;
|
||||
case Shadow:
|
||||
tex = static_cast<SceneOpenGLShadow*>(m_shadow)->shadowTexture();
|
||||
|
|
|
@ -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<class T>
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue