diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp
index 7b67778789..6fa1b3393e 100644
--- a/libkwineffects/kwingltexture.cpp
+++ b/libkwineffects/kwingltexture.cpp
@@ -26,6 +26,8 @@ along with this program. If not, see .
#include "kwinglutils_funcs.h"
#include "kwinglutils.h"
+#include "kwingltexture_p.h"
+
#include
#include
#include
@@ -40,52 +42,62 @@ namespace KWin
// GLTexture
//****************************************
-bool GLTexture::sNPOTTextureSupported = false;
-bool GLTexture::sFramebufferObjectSupported = false;
-bool GLTexture::sSaturationSupported = false;
+bool GLTexturePrivate::sNPOTTextureSupported = false;
+bool GLTexturePrivate::sFramebufferObjectSupported = false;
+bool GLTexturePrivate::sSaturationSupported = false;
GLTexture::GLTexture()
+ : d_ptr(new GLTexturePrivate())
+{
+}
+
+GLTexture::GLTexture(GLTexturePrivate& dd)
+ : d_ptr(&dd)
+{
+}
+
+GLTexture::GLTexture(const GLTexture& tex)
+ : d_ptr(tex.d_ptr)
{
- init();
}
GLTexture::GLTexture(const QImage& image, GLenum target)
+ : d_ptr(new GLTexturePrivate())
{
- init();
load(image, target);
}
GLTexture::GLTexture(const QPixmap& pixmap, GLenum target)
+ : d_ptr(new GLTexturePrivate())
{
- init();
load(pixmap, target);
}
GLTexture::GLTexture(const QString& fileName)
+ : d_ptr(new GLTexturePrivate())
{
- init();
load(fileName);
}
GLTexture::GLTexture(int width, int height)
+ : d_ptr(new GLTexturePrivate())
{
- init();
-
+ Q_D(GLTexture);
if (NPOTTextureSupported() || (isPowerOfTwo(width) && isPowerOfTwo(height))) {
- mTarget = GL_TEXTURE_2D;
- mScale.setWidth(1.0 / width);
- mScale.setHeight(1.0 / height);
- mSize = QSize(width, height);
- can_use_mipmaps = true;
+ d->m_target = GL_TEXTURE_2D;
+ d->m_scale.setWidth(1.0 / width);
+ d->m_scale.setHeight(1.0 / height);
+ d->m_size = QSize(width, height);
+ d->m_canUseMipmaps = true;
- glGenTextures(1, &mTexture);
+ glGenTextures(1, &d->m_texture);
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
- glTexImage2D(mTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexImage2D(d->m_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#else
- glTexImage2D(mTarget, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
+ glTexImage2D(d->m_target, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0);
#endif
unbind();
}
@@ -93,26 +105,38 @@ GLTexture::GLTexture(int width, int height)
GLTexture::~GLTexture()
{
- delete m_vbo;
- discard();
- assert(mUnnormalizeActive == 0);
- assert(mNormalizeActive == 0);
}
-void GLTexture::init()
+GLTexture& GLTexture::operator = (const GLTexture& tex)
{
- mTexture = None;
- mTarget = 0;
- mFilter = 0;
- y_inverted = false;
- can_use_mipmaps = false;
- has_valid_mipmaps = false;
- mUnnormalizeActive = 0;
- mNormalizeActive = 0;
+ d_ptr = tex.d_ptr;
+ return *this;
+}
+
+GLTexturePrivate::GLTexturePrivate()
+{
+ m_texture = 0;
+ m_target = 0;
+ m_filter = 0;
+ m_yInverted = false;
+ m_canUseMipmaps = false;
+ m_hasValidMipmaps = false;
+ m_unnormalizeActive = 0;
+ m_normalizeActive = 0;
m_vbo = 0;
}
-void GLTexture::initStatic()
+GLTexturePrivate::~GLTexturePrivate()
+{
+ if (m_vbo != 0) {
+ delete m_vbo;
+ }
+ if (m_texture != 0) {
+ glDeleteTextures(1, &m_texture);
+ }
+}
+
+void GLTexturePrivate::initStatic()
{
#ifdef KWIN_HAVE_OPENGLES
sNPOTTextureSupported = true;
@@ -129,22 +153,28 @@ void GLTexture::initStatic()
bool GLTexture::isNull() const
{
- return mTexture == None;
+ Q_D(const GLTexture);
+ return None == d->m_texture;
}
QSize GLTexture::size() const
{
- return mSize;
+ Q_D(const GLTexture);
+ return d->m_size;
}
bool GLTexture::load(const QImage& image, GLenum target)
{
+ // decrease the reference counter for the old texture
+ d_ptr = new GLTexturePrivate();
+
+ Q_D(GLTexture);
if (image.isNull())
return false;
QImage img = image;
- mTarget = target;
+ d->m_target = target;
#ifndef KWIN_HAVE_OPENGLES
- if (mTarget != GL_TEXTURE_RECTANGLE_ARB) {
+ if (d->m_target != GL_TEXTURE_RECTANGLE_ARB) {
#endif
if (!NPOTTextureSupported()
&& (!isPowerOfTwo(image.width()) || !isPowerOfTwo(image.height()))) {
@@ -152,33 +182,33 @@ bool GLTexture::load(const QImage& image, GLenum target)
img = img.scaled(nearestPowerOfTwo(image.width()),
nearestPowerOfTwo(image.height()));
}
- mScale.setWidth(1.0 / img.width());
- mScale.setHeight(1.0 / img.height());
- can_use_mipmaps = true;
+ d->m_scale.setWidth(1.0 / img.width());
+ d->m_scale.setHeight(1.0 / img.height());
+ d->m_canUseMipmaps = true;
#ifndef KWIN_HAVE_OPENGLES
} else {
- mScale.setWidth(1.0);
- mScale.setHeight(1.0);
- can_use_mipmaps = false;
+ d->m_scale.setWidth(1.0);
+ d->m_scale.setHeight(1.0);
+ d->m_canUseMipmaps = false;
}
#endif
setFilter(GL_LINEAR);
- mSize = img.size();
- y_inverted = true;
+ d->m_size = img.size();
+ d->m_yInverted = true;
- img = convertToGLFormat(img);
+ img = d->convertToGLFormat(img);
setDirty();
if (isNull()) {
- glGenTextures(1, &mTexture);
+ glGenTextures(1, &d->m_texture);
}
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
- glTexImage2D(mTarget, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
+ glTexImage2D(d->m_target, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
#else
- glTexImage2D(mTarget, 0, GL_RGBA8, img.width(), img.height(), 0,
+ glTexImage2D(d->m_target, 0, GL_RGBA8, img.width(), img.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, img.bits());
#endif
unbind();
@@ -201,37 +231,47 @@ bool GLTexture::load(const QString& fileName)
void GLTexture::discard()
{
- setDirty();
- if (mTexture != None)
- glDeleteTextures(1, &mTexture);
- mTexture = None;
+ d_ptr = new GLTexturePrivate();
+}
+
+void GLTexturePrivate::bind()
+{
+#ifndef KWIN_HAVE_OPENGLES
+ glEnable(m_target);
+#endif
+ glBindTexture(m_target, m_texture);
+ enableFilter();
}
void GLTexture::bind()
{
+ Q_D(GLTexture);
+ d->bind();
+}
+
+void GLTexturePrivate::unbind()
+{
+ glBindTexture(m_target, 0);
#ifndef KWIN_HAVE_OPENGLES
- glEnable(mTarget);
+ glDisable(m_target);
#endif
- glBindTexture(mTarget, mTexture);
- enableFilter();
}
void GLTexture::unbind()
{
- glBindTexture(mTarget, 0);
-#ifndef KWIN_HAVE_OPENGLES
- glDisable(mTarget);
-#endif
+ Q_D(GLTexture);
+ d->unbind();
}
void GLTexture::render(QRegion region, const QRect& rect)
{
- if (rect.size() != m_cachedSize) {
- m_cachedSize = rect.size();
+ Q_D(GLTexture);
+ if (rect.size() != d->m_cachedSize) {
+ d->m_cachedSize = rect.size();
QRect r(rect);
r.moveTo(0, 0);
- if (!m_vbo) {
- m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static);
+ if (!d->m_vbo) {
+ d->m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static);
}
const float verts[ 4 * 2 ] = {
// NOTICE: r.x/y could be replaced by "0", but that would make it unreadable...
@@ -241,12 +281,12 @@ void GLTexture::render(QRegion region, const QRect& rect)
r.x() + rect.width(), r.y() + rect.height()
};
const float texcoords[ 4 * 2 ] = {
- 0.0f, y_inverted ? 0.0f : 1.0f, // y needs to be swapped (normalized coords)
- 0.0f, y_inverted ? 1.0f : 0.0f,
- 1.0f, y_inverted ? 0.0f : 1.0f,
- 1.0f, y_inverted ? 1.0f : 0.0f
+ 0.0f, d->m_yInverted ? 0.0f : 1.0f, // y needs to be swapped (normalized coords)
+ 0.0f, d->m_yInverted ? 1.0f : 0.0f,
+ 1.0f, d->m_yInverted ? 0.0f : 1.0f,
+ 1.0f, d->m_yInverted ? 1.0f : 0.0f
};
- m_vbo->setData(4, 2, verts, texcoords);
+ d->m_vbo->setData(4, 2, verts, texcoords);
}
QMatrix4x4 translation;
translation.translate(rect.x(), rect.y());
@@ -257,7 +297,7 @@ void GLTexture::render(QRegion region, const QRect& rect)
} else {
pushMatrix(translation);
}
- m_vbo->render(region, GL_TRIANGLE_STRIP);
+ d->m_vbo->render(region, GL_TRIANGLE_STRIP);
if (ShaderManager::instance()->isShaderBound()) {
GLShader *shader = ShaderManager::instance()->getBoundShader();
shader->setUniform(GLShader::WindowTransformation, QMatrix4x4());
@@ -268,85 +308,94 @@ void GLTexture::render(QRegion region, const QRect& rect)
GLuint GLTexture::texture() const
{
- return mTexture;
+ Q_D(const GLTexture);
+ return d->m_texture;
}
GLenum GLTexture::target() const
{
- return mTarget;
+ Q_D(const GLTexture);
+ return d->m_target;
}
GLenum GLTexture::filter() const
{
- return mFilter;
+ Q_D(const GLTexture);
+ return d->m_filter;
}
bool GLTexture::isDirty() const
{
- return has_valid_mipmaps;
+ Q_D(const GLTexture);
+ return d->m_hasValidMipmaps;
}
void GLTexture::setTexture(GLuint texture)
{
+ Q_D(GLTexture);
discard();
- mTexture = texture;
+ d->m_texture = texture;
}
void GLTexture::setTarget(GLenum target)
{
- mTarget = target;
+ Q_D(GLTexture);
+ d->m_target = target;
}
void GLTexture::setFilter(GLenum filter)
{
- mFilter = filter;
+ Q_D(GLTexture);
+ d->m_filter = filter;
}
void GLTexture::setWrapMode(GLenum mode)
{
+ Q_D(GLTexture);
bind();
- glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, mode);
- glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, mode);
+ glTexParameteri(d->m_target, GL_TEXTURE_WRAP_S, mode);
+ glTexParameteri(d->m_target, GL_TEXTURE_WRAP_T, mode);
unbind();
}
void GLTexture::setDirty()
{
- has_valid_mipmaps = false;
+ Q_D(GLTexture);
+ d->m_hasValidMipmaps = false;
}
-void GLTexture::enableFilter()
+void GLTexturePrivate::enableFilter()
{
- if (mFilter == GL_LINEAR_MIPMAP_LINEAR) {
+ if (m_filter == GL_LINEAR_MIPMAP_LINEAR) {
// trilinear filtering requested, but is it possible?
- if (NPOTTextureSupported()
- && framebufferObjectSupported()
- && can_use_mipmaps) {
- glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- if (!has_valid_mipmaps) {
- glGenerateMipmap(mTarget);
- has_valid_mipmaps = true;
+ if (sNPOTTextureSupported
+ && sFramebufferObjectSupported
+ && m_canUseMipmaps) {
+ glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (!m_hasValidMipmaps) {
+ glGenerateMipmap(m_target);
+ m_hasValidMipmaps = true;
}
} else {
// can't use trilinear, so use bilinear
- setFilter(GL_LINEAR);
- glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ m_filter = GL_LINEAR;
+ glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
- } else if (mFilter == GL_LINEAR) {
- glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ } else if (m_filter == GL_LINEAR) {
+ glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
// if neither trilinear nor bilinear, default to fast filtering
- setFilter(GL_NEAREST);
- glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ m_filter = GL_NEAREST;
+ glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
-QImage GLTexture::convertToGLFormat(const QImage& img) const
+QImage GLTexturePrivate::convertToGLFormat(const QImage& img) const
{
// Copied from Qt's QGLWidget::convertToGLFormat()
QImage res;
@@ -410,7 +459,52 @@ QImage GLTexture::convertToGLFormat(const QImage& img) const
bool GLTexture::isYInverted() const
{
- return y_inverted;
+ Q_D(const GLTexture);
+ return d->m_yInverted;
+}
+
+void GLTexture::setYInverted(bool inverted)
+{
+ Q_D(GLTexture);
+ d->m_yInverted = inverted;
+}
+
+int GLTexture::width() const
+{
+ Q_D(const GLTexture);
+ return d->m_size.width();
+}
+
+int GLTexture::height() const
+{
+ Q_D(const GLTexture);
+ return d->m_size.height();
+}
+
+bool GLTexture::NPOTTextureSupported()
+{
+ return GLTexturePrivate::sNPOTTextureSupported;
+}
+
+bool GLTexture::framebufferObjectSupported()
+{
+ return GLTexturePrivate::sFramebufferObjectSupported;
+}
+
+bool GLTexture::saturationSupported()
+{
+ return GLTexturePrivate::sSaturationSupported;
+}
+
+void GLTexture::release()
+{
+ Q_D(GLTexture);
+ d->release();
+}
+
+void GLTexturePrivate::release()
+{
+ // nothing to do because we are not bound to any specific data
}
} // namespace KWin
diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h
index 9a8d4168b6..b114838a51 100644
--- a/libkwineffects/kwingltexture.h
+++ b/libkwineffects/kwingltexture.h
@@ -25,7 +25,8 @@ along with this program. If not, see .
#include "kwinglobals.h"
#include
-#include
+#include
+#include
class QImage;
class QPixmap;
@@ -37,37 +38,45 @@ namespace KWin
{
class GLVertexBuffer;
+class GLTexturePrivate;
class KWIN_EXPORT GLTexture
- : public QSharedData
{
public:
GLTexture();
+ GLTexture(const GLTexture& tex);
explicit GLTexture(const QImage& image, GLenum target = GL_TEXTURE_2D);
explicit GLTexture(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D);
GLTexture(const QString& fileName);
GLTexture(int width, int height);
virtual ~GLTexture();
+ GLTexture & operator = (const GLTexture& tex);
+
bool isNull() const;
QSize size() const;
- int width() const {
- return mSize.width(); /// @since 4.5
- }
- int height() const {
- return mSize.height(); /// @since 4.5
- }
+ int width() const;
+ int height() const;
/**
* @since 4.7
**/
bool isYInverted() const;
+ /**
+ * @since 4.8
+ **/
+ void setYInverted(bool inverted);
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);
virtual void discard();
- virtual void bind();
- virtual void unbind();
+ void bind();
+ void unbind();
+ /**
+ * Release the data which is bound to the texture.
+ * @since 4.8
+ **/
+ void release();
void render(QRegion region, const QRect& rect);
GLuint texture() const;
@@ -80,41 +89,19 @@ public:
void setWrapMode(GLenum mode);
virtual void setDirty();
- static void initStatic();
- static bool NPOTTextureSupported() {
- return sNPOTTextureSupported;
- }
- static bool framebufferObjectSupported() {
- return sFramebufferObjectSupported;
- }
- static bool saturationSupported() {
- return sSaturationSupported;
- }
+ static bool NPOTTextureSupported();
+ static bool framebufferObjectSupported();
+ static bool saturationSupported();
protected:
void enableFilter();
QImage convertToGLFormat(const QImage& img) const;
- GLuint mTexture;
- GLenum mTarget;
- GLenum mFilter;
- QSize mSize;
- QSizeF mScale; // to un-normalize GL_TEXTURE_2D
- bool y_inverted; // texture has y inverted
- bool can_use_mipmaps;
- bool has_valid_mipmaps;
+ QExplicitlySharedDataPointer d_ptr;
+ GLTexture(GLTexturePrivate& dd);
private:
- void init();
- int mUnnormalizeActive; // 0 - no, otherwise refcount
- int mNormalizeActive; // 0 - no, otherwise refcount
- GLVertexBuffer* m_vbo;
- QSize m_cachedSize;
-
- static bool sNPOTTextureSupported;
- static bool sFramebufferObjectSupported;
- static bool sSaturationSupported;
- Q_DISABLE_COPY(GLTexture)
+ Q_DECLARE_PRIVATE(GLTexture);
};
} // namespace
diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltexture_p.h
new file mode 100644
index 0000000000..be879e3073
--- /dev/null
+++ b/libkwineffects/kwingltexture_p.h
@@ -0,0 +1,74 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2006-2007 Rivo Laks
+Copyright (C) 2010, 2011 Martin Gräßlin
+Copyright (C) 2011 Philipp Knechtges
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+
+#ifndef KWIN_GLTEXTURE_P_H
+#define KWIN_GLTEXTURE_P_H
+
+#include "kwinconfig.h" // KWIN_HAVE_OPENGL
+#include "kwinglobals.h"
+
+#include
+#include
+
+namespace KWin
+{
+
+class KWIN_EXPORT GLTexturePrivate
+ : public QSharedData
+{
+public:
+ GLTexturePrivate();
+ virtual ~GLTexturePrivate();
+
+ virtual void bind();
+ virtual void unbind();
+ virtual void release();
+
+ void enableFilter();
+ QImage convertToGLFormat(const QImage& img) const;
+
+ GLuint m_texture;
+ GLenum m_target;
+ GLenum m_filter;
+ QSize m_size;
+ QSizeF m_scale; // to un-normalize GL_TEXTURE_2D
+ bool m_yInverted; // texture has y inverted
+ bool m_canUseMipmaps;
+ bool m_hasValidMipmaps;
+
+ int m_unnormalizeActive; // 0 - no, otherwise refcount
+ int m_normalizeActive; // 0 - no, otherwise refcount
+ GLVertexBuffer* m_vbo;
+ QSize m_cachedSize;
+
+ static void initStatic();
+
+ static bool sNPOTTextureSupported;
+ static bool sFramebufferObjectSupported;
+ static bool sSaturationSupported;
+private:
+ Q_DISABLE_COPY(GLTexturePrivate)
+};
+
+} // namespace
+
+#endif
\ No newline at end of file
diff --git a/libkwineffects/kwinglutils.cpp b/libkwineffects/kwinglutils.cpp
index b9bba5b4e9..19b4ebb011 100644
--- a/libkwineffects/kwinglutils.cpp
+++ b/libkwineffects/kwinglutils.cpp
@@ -21,6 +21,9 @@ along with this program. If not, see .
#include "kwinglutils.h"
+// need to call GLTexturePrivate::initStatic()
+#include "kwingltexture_p.h"
+
#include "kwinglobals.h"
#include "kwineffects.h"
#include "kwinglplatform.h"
@@ -113,7 +116,7 @@ void initGL()
// handle OpenGL extensions functions
glResolveFunctions();
- GLTexture::initStatic();
+ GLTexturePrivate::initStatic();
GLRenderTarget::initStatic();
GLVertexBuffer::initStatic();
}
diff --git a/scene_opengl.cpp b/scene_opengl.cpp
index e0fc5f7b4a..cf3eb654d0 100644
--- a/scene_opengl.cpp
+++ b/scene_opengl.cpp
@@ -268,55 +268,43 @@ void SceneOpenGL::windowOpacityChanged(KWin::Toplevel* t)
// SceneOpenGL::Texture
//****************************************
-SceneOpenGL::Texture::Texture() : GLTexture()
+SceneOpenGL::Texture::Texture() : GLTexture(*new TexturePrivate())
{
- init();
}
-SceneOpenGL::Texture::Texture(const Pixmap& pix, const QSize& size, int depth) : GLTexture()
+SceneOpenGL::Texture::Texture(TexturePrivate& dd) : GLTexture(dd)
+{
+}
+
+SceneOpenGL::Texture::Texture(const SceneOpenGL::Texture& tex) : GLTexture(*tex.d_ptr)
+{
+}
+
+SceneOpenGL::Texture::Texture(const Pixmap& pix, const QSize& size, int depth)
+ : GLTexture(*new TexturePrivate())
{
- init();
load(pix, size, depth);
}
SceneOpenGL::Texture::Texture(const QPixmap& pix, GLenum target)
- : GLTexture()
+ : GLTexture(*new TexturePrivate())
{
- init();
load(pix, target);
}
SceneOpenGL::Texture::~Texture()
{
- discard();
}
-void SceneOpenGL::Texture::createTexture()
+SceneOpenGL::Texture& SceneOpenGL::Texture::operator = (const SceneOpenGL::Texture& tex)
{
- glGenTextures(1, &mTexture);
+ d_ptr = tex.d_ptr;
+ return *this;
}
void SceneOpenGL::Texture::discard()
{
- if (mTexture != None)
- release();
- GLTexture::discard();
-}
-
-QRegion SceneOpenGL::Texture::optimizeBindDamage(const QRegion& reg, int limit)
-{
- if (reg.rects().count() <= 1)
- return reg;
- // try to reduce the number of rects, as especially with SHM mode every rect
- // causes X roundtrip, even for very small areas - so, when the size difference
- // between all the areas and the bounding rectangle is small, simply use
- // only the bounding rectangle
- int size = 0;
- foreach (const QRect & r, reg.rects())
- size += r.width() * r.height();
- if (reg.boundingRect().width() * reg.boundingRect().height() - size < limit)
- return reg.boundingRect();
- return reg;
+ d_ptr = new TexturePrivate();
}
bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size,
@@ -337,6 +325,7 @@ bool SceneOpenGL::Texture::load(const QImage& image, GLenum target)
bool SceneOpenGL::Texture::load(const QPixmap& pixmap, GLenum target)
{
+ Q_D(Texture);
if (pixmap.isNull())
return false;
@@ -345,8 +334,6 @@ bool SceneOpenGL::Texture::load(const QPixmap& pixmap, GLenum target)
return GLTexture::load(pixmap.toImage(), target);
}
- y_inverted = true;
-
// use the X11 pixmap provided by Qt
return load(pixmap.handle(), pixmap.size(), pixmap.depth());
}
@@ -374,9 +361,16 @@ SceneOpenGL::Window::~Window()
bool SceneOpenGL::Window::bindTexture()
{
#ifndef KWIN_HAVE_OPENGLES
- if (texture.texture() != None && toplevel->damage().isEmpty()) {
- // texture doesn't need updating, just bind it
- glBindTexture(texture.target(), texture.texture());
+ if (!texture.isNull()) {
+ if (toplevel->damage().isEmpty()) {
+ // texture doesn't need updating, just bind it
+ glBindTexture(texture.target(), texture.texture());
+ } else {
+ // bind() updates the texture automatically e.g. in case the glx pixmap binding
+ // is strict
+ texture.bind();
+ toplevel->resetDamage(QRect(toplevel->clientPos(), toplevel->clientSize()));
+ }
return true;
}
#endif
@@ -384,8 +378,10 @@ bool SceneOpenGL::Window::bindTexture()
Pixmap pix = toplevel->windowPixmap();
if (pix == None)
return false;
+
bool success = texture.load(pix, toplevel->size(), toplevel->depth(),
toplevel->damage());
+
if (success)
toplevel->resetDamage(QRect(toplevel->clientPos(), toplevel->clientSize()));
else
@@ -417,7 +413,7 @@ void SceneOpenGL::Window::checkTextureSize()
// when the window's composite pixmap is discarded, undo binding it to the texture
void SceneOpenGL::Window::pixmapDiscarded()
{
- texture.release();
+ texture.discard();
}
QMatrix4x4 SceneOpenGL::Window::transformation(int mask, const WindowPaintData &data) const
@@ -640,7 +636,7 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType
}
if (decorationTexture->texture() != None && !updateDeco) {
// texture doesn't need updating, just bind it
- glBindTexture(decorationTexture->target(), decorationTexture->texture());
+ decorationTexture->bind();
} else if (!decoration->isNull()) {
bool success = decorationTexture->load(*decoration);
if (!success) {
diff --git a/scene_opengl.h b/scene_opengl.h
index 52107ea8f9..600ae2e6c2 100644
--- a/scene_opengl.h
+++ b/scene_opengl.h
@@ -26,6 +26,7 @@ along with this program. If not, see .
#include "shadow.h"
#include "kwinglutils.h"
+#include "kwingltexture_p.h"
#ifdef HAVE_XSHM
#include
@@ -41,6 +42,7 @@ class SceneOpenGL
public:
class EffectFrame;
class Texture;
+ class TexturePrivate;
class Window;
SceneOpenGL(Workspace* ws);
virtual ~SceneOpenGL();
@@ -100,40 +102,51 @@ private:
bool debug;
};
+class SceneOpenGL::TexturePrivate
+ : public GLTexturePrivate
+{
+public:
+ TexturePrivate();
+ virtual ~TexturePrivate();
+
+ virtual void bind();
+ virtual void unbind();
+ virtual void release();
+
+#ifndef KWIN_HAVE_OPENGLES
+ GLXPixmap m_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
+#endif
+private:
+ Q_DISABLE_COPY(TexturePrivate)
+};
+
class SceneOpenGL::Texture
: public GLTexture
{
public:
Texture();
+ Texture(const Texture& tex);
Texture(const QPixmap& pix, GLenum target = GL_TEXTURE_2D);
virtual ~Texture();
+ Texture & operator = (const Texture& tex);
+
using GLTexture::load;
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();
- virtual void release(); // undo the tfp_mode binding
- virtual void bind();
- virtual void unbind();
- void setYInverted(bool inverted) {
- y_inverted = inverted;
- }
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();
+ Texture(TexturePrivate& dd);
-#ifndef KWIN_HAVE_OPENGLES
- GLXPixmap glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode
-#endif
+private:
+ Q_DECLARE_PRIVATE(Texture);
friend class SceneOpenGL::Window;
};
diff --git a/scene_opengl_egl.cpp b/scene_opengl_egl.cpp
index 8b1b51225c..4e232c2691 100644
--- a/scene_opengl_egl.cpp
+++ b/scene_opengl_egl.cpp
@@ -210,65 +210,71 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
// SceneOpenGL::Texture
//****************************************
-void SceneOpenGL::Texture::init()
+SceneOpenGL::TexturePrivate::TexturePrivate()
{
- findTarget();
+ m_target = GL_TEXTURE_2D;
}
-void SceneOpenGL::Texture::release()
+SceneOpenGL::TexturePrivate::~TexturePrivate()
{
- mTexture = None;
}
void SceneOpenGL::Texture::findTarget()
{
- mTarget = GL_TEXTURE_2D;
+ Q_D(Texture);
+ d->m_target = GL_TEXTURE_2D;
+}
+
+void SceneOpenGL::TexturePrivate::release()
+{
}
bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size,
int depth, QRegion region)
{
+ // decrease the reference counter for the old texture
+ d_ptr = new TexturePrivate();
+
+ Q_D(Texture);
Q_UNUSED(depth)
Q_UNUSED(region)
if (pix == None)
return false;
- if (mTexture == None) {
- createTexture();
- bind();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- const EGLint attribs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
- EGL_NONE
- };
- EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
- (EGLClientBuffer)pix, attribs);
+ glGenTextures(1, &d->m_texture);
+ bind();
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ const EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_NONE
+ };
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
+ (EGLClientBuffer)pix, attribs);
- if (EGL_NO_IMAGE_KHR == image) {
- kDebug(1212) << "failed to create egl image";
- unbind();
- return false;
- }
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
- eglDestroyImageKHR(dpy, image);
+ if (EGL_NO_IMAGE_KHR == image) {
+ kDebug(1212) << "failed to create egl image";
unbind();
- checkGLError("load texture");
- setYInverted(true);
- mSize = size;
+ return false;
}
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
+ eglDestroyImageKHR(dpy, image);
+ unbind();
+ checkGLError("load texture");
+ setYInverted(true);
+ d->m_size = size;
return true;
}
-void SceneOpenGL::Texture::bind()
+void SceneOpenGL::TexturePrivate::bind()
{
- GLTexture::bind();
+ GLTexturePrivate::bind();
}
-void SceneOpenGL::Texture::unbind()
+void SceneOpenGL::TexturePrivate::unbind()
{
- GLTexture::unbind();
+ GLTexturePrivate::unbind();
}
diff --git a/scene_opengl_glx.cpp b/scene_opengl_glx.cpp
index 9ceeb761db..06a7b0a575 100644
--- a/scene_opengl_glx.cpp
+++ b/scene_opengl_glx.cpp
@@ -55,6 +55,7 @@ SceneOpenGL::SceneOpenGL(Workspace* ws)
return; // error
// Initialize OpenGL
initGL();
+
GLPlatform *glPlatform = GLPlatform::instance();
if (glPlatform->isSoftwareEmulation()) {
kError(1212) << "OpenGL Software Rasterizer detected. Falling back to XRender.";
@@ -544,33 +545,38 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
// SceneOpenGL::Texture
//****************************************
-void SceneOpenGL::Texture::init()
+SceneOpenGL::TexturePrivate::TexturePrivate()
{
- glxpixmap = None;
+ m_glxpixmap = None;
}
-void SceneOpenGL::Texture::release()
+SceneOpenGL::TexturePrivate::~TexturePrivate()
{
- if (glxpixmap != None) {
+ release();
+}
+
+void SceneOpenGL::TexturePrivate::release()
+{
+ if (m_glxpixmap != None) {
if (!options->glStrictBinding) {
- glXReleaseTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT);
+ glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT);
}
- glXDestroyPixmap(display(), glxpixmap);
- glxpixmap = None;
+ glXDestroyPixmap(display(), m_glxpixmap);
}
}
void SceneOpenGL::Texture::findTarget()
{
+ Q_D(Texture);
unsigned int new_target = 0;
- if (glXQueryDrawable && glxpixmap != None)
- glXQueryDrawable(display(), glxpixmap, GLX_TEXTURE_TARGET_EXT, &new_target);
+ if (glXQueryDrawable && d->m_glxpixmap != None)
+ glXQueryDrawable(display(), d->m_glxpixmap, GLX_TEXTURE_TARGET_EXT, &new_target);
// HACK: this used to be a hack for Xgl.
// without this hack the NVIDIA blob aborts when trying to bind a texture from
// a pixmap icon
if (new_target == 0) {
if (NPOTTextureSupported() ||
- (isPowerOfTwo(mSize.width()) && isPowerOfTwo(mSize.height()))) {
+ (isPowerOfTwo(d->m_size.width()) && isPowerOfTwo(d->m_size.height()))) {
new_target = GLX_TEXTURE_2D_EXT;
} else {
new_target = GLX_TEXTURE_RECTANGLE_EXT;
@@ -578,14 +584,14 @@ void SceneOpenGL::Texture::findTarget()
}
switch(new_target) {
case GLX_TEXTURE_2D_EXT:
- mTarget = GL_TEXTURE_2D;
- mScale.setWidth(1.0f / mSize.width());
- mScale.setHeight(1.0f / mSize.height());
+ d->m_target = GL_TEXTURE_2D;
+ d->m_scale.setWidth(1.0f / d->m_size.width());
+ d->m_scale.setHeight(1.0f / d->m_size.height());
break;
case GLX_TEXTURE_RECTANGLE_EXT:
- mTarget = GL_TEXTURE_RECTANGLE_ARB;
- mScale.setWidth(1.0f);
- mScale.setHeight(1.0f);
+ d->m_target = GL_TEXTURE_RECTANGLE_ARB;
+ d->m_scale.setWidth(1.0f);
+ d->m_scale.setHeight(1.0f);
break;
default:
abort();
@@ -595,6 +601,10 @@ void SceneOpenGL::Texture::findTarget()
bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size,
int depth, QRegion region)
{
+ // decrease the reference counter for the old texture
+ d_ptr = new TexturePrivate();
+
+ Q_D(Texture);
#ifdef CHECK_GL_ERROR
checkGLError("TextureLoad1");
#endif
@@ -606,78 +616,65 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size,
return false;
}
- mSize = size;
- if (mTexture == None || !region.isEmpty()) {
- // new texture, or texture contents changed; mipmaps now invalid
- setDirty();
- }
+ d->m_size = size;
+ d->m_yInverted = true;
+ // new texture, or texture contents changed; mipmaps now invalid
+ setDirty();
#ifdef CHECK_GL_ERROR
checkGLError("TextureLoad2");
#endif
// tfp mode, simply bind the pixmap to texture
- if (mTexture == None)
- createTexture();
+ glGenTextures(1, &d->m_texture);
// The GLX pixmap references the contents of the original pixmap, so it doesn't
// need to be recreated when the contents change.
// The texture may or may not use the same storage depending on the EXT_tfp
// implementation. When options->glStrictBinding is true, the texture uses
// a different storage and needs to be updated with a call to
// glXBindTexImageEXT() when the contents of the pixmap has changed.
- if (glxpixmap != None)
- glBindTexture(mTarget, mTexture);
- else {
- int attrs[] = {
- GLX_TEXTURE_FORMAT_EXT, fbcdrawableinfo[ depth ].bind_texture_format,
- GLX_MIPMAP_TEXTURE_EXT, fbcdrawableinfo[ depth ].mipmap,
- None, None, None
- };
- // Specifying the texture target explicitly is reported to cause a performance
- // regression with R300G (see bug #256654).
- if (GLPlatform::instance()->driver() != Driver_R300G) {
- if ((fbcdrawableinfo[ depth ].texture_targets & GLX_TEXTURE_2D_BIT_EXT) &&
- (GLTexture::NPOTTextureSupported() ||
- (isPowerOfTwo(size.width()) && isPowerOfTwo(size.height())))) {
- attrs[ 4 ] = GLX_TEXTURE_TARGET_EXT;
- attrs[ 5 ] = GLX_TEXTURE_2D_EXT;
- } else if (fbcdrawableinfo[ depth ].texture_targets & GLX_TEXTURE_RECTANGLE_BIT_EXT) {
- attrs[ 4 ] = GLX_TEXTURE_TARGET_EXT;
- attrs[ 5 ] = GLX_TEXTURE_RECTANGLE_EXT;
- }
+ int attrs[] = {
+ GLX_TEXTURE_FORMAT_EXT, fbcdrawableinfo[ depth ].bind_texture_format,
+ GLX_MIPMAP_TEXTURE_EXT, fbcdrawableinfo[ depth ].mipmap,
+ None, None, None
+ };
+ // Specifying the texture target explicitly is reported to cause a performance
+ // regression with R300G (see bug #256654).
+ if (GLPlatform::instance()->driver() != Driver_R300G) {
+ if ((fbcdrawableinfo[ depth ].texture_targets & GLX_TEXTURE_2D_BIT_EXT) &&
+ (GLTexture::NPOTTextureSupported() ||
+ (isPowerOfTwo(size.width()) && isPowerOfTwo(size.height())))) {
+ attrs[ 4 ] = GLX_TEXTURE_TARGET_EXT;
+ attrs[ 5 ] = GLX_TEXTURE_2D_EXT;
+ } else if (fbcdrawableinfo[ depth ].texture_targets & GLX_TEXTURE_RECTANGLE_BIT_EXT) {
+ attrs[ 4 ] = GLX_TEXTURE_TARGET_EXT;
+ attrs[ 5 ] = GLX_TEXTURE_RECTANGLE_EXT;
}
- glxpixmap = glXCreatePixmap(display(), fbcdrawableinfo[ depth ].fbconfig, pix, attrs);
-#ifdef CHECK_GL_ERROR
- checkGLError("TextureLoadTFP1");
-#endif
- findTarget();
- y_inverted = fbcdrawableinfo[ depth ].y_inverted ? true : false;
- can_use_mipmaps = fbcdrawableinfo[ depth ].mipmap ? true : false;
- glBindTexture(mTarget, mTexture);
-#ifdef CHECK_GL_ERROR
- checkGLError("TextureLoadTFP2");
-#endif
- if (!options->glStrictBinding)
- glXBindTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
}
- if (options->glStrictBinding)
- // Mark the texture as damaged so it will be updated on the next call to bind()
- glXBindTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
+ d->m_glxpixmap = glXCreatePixmap(display(), fbcdrawableinfo[ depth ].fbconfig, pix, attrs);
+#ifdef CHECK_GL_ERROR
+ checkGLError("TextureLoadTFP1");
+#endif
+ findTarget();
+ d->m_yInverted = fbcdrawableinfo[ depth ].y_inverted ? true : false;
+ d->m_canUseMipmaps = fbcdrawableinfo[ depth ].mipmap ? true : false;
+ glBindTexture(d->m_target, d->m_texture);
+#ifdef CHECK_GL_ERROR
+ checkGLError("TextureLoadTFP2");
+#endif
+ glXBindTexImageEXT(display(), d->m_glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
#ifdef CHECK_GL_ERROR
checkGLError("TextureLoad0");
#endif
return true;
}
-void SceneOpenGL::Texture::bind()
+void SceneOpenGL::TexturePrivate::bind()
{
- glEnable(mTarget);
- glBindTexture(mTarget, mTexture);
- // if one of the GLTexture::load functions is called, the glxpixmap doesn't
- // have to exist
- if (options->glStrictBinding && glxpixmap) {
- glXReleaseTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT);
- glXBindTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
- setDirty(); // Mipmaps have to be regenerated after updating the texture
+ GLTexturePrivate::bind();
+ if (options->glStrictBinding && m_glxpixmap) {
+ glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT);
+ glXBindTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
+ m_hasValidMipmaps = false; // Mipmaps have to be regenerated after updating the texture
}
enableFilter();
if (hasGLVersion(1, 4, 0)) {
@@ -686,17 +683,16 @@ void SceneOpenGL::Texture::bind()
}
}
-void SceneOpenGL::Texture::unbind()
+void SceneOpenGL::TexturePrivate::unbind()
{
if (hasGLVersion(1, 4, 0)) {
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f);
}
- // if one of the GLTexture::load functions is called, the glxpixmap doesn't
- // have to exist
- if (options->glStrictBinding && glxpixmap) {
- glBindTexture(mTarget, mTexture);
- glXReleaseTexImageEXT(display(), glxpixmap, GLX_FRONT_LEFT_EXT);
+ if (options->glStrictBinding && m_glxpixmap) {
+ glBindTexture(m_target, m_texture);
+ glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT);
}
- GLTexture::unbind();
+ GLTexturePrivate::unbind();
}
+