diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp index 4155fb16f3..9e577e87e8 100644 --- a/libkwineffects/kwingltexture.cpp +++ b/libkwineffects/kwingltexture.cpp @@ -4,6 +4,7 @@ Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin +Copyright (C) 2012 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 @@ -117,13 +118,16 @@ GLTexturePrivate::GLTexturePrivate() { m_texture = 0; m_target = 0; - m_filter = 0; + m_filter = GL_NEAREST_MIPMAP_LINEAR; + m_wrapMode = GL_REPEAT; m_yInverted = false; m_canUseMipmaps = false; - m_hasValidMipmaps = false; + m_markedDirty = false; m_unnormalizeActive = 0; m_normalizeActive = 0; m_vbo = 0; + m_filterChanged = false; + m_wrapModeChanged = false; } GLTexturePrivate::~GLTexturePrivate() @@ -192,13 +196,11 @@ bool GLTexture::load(const QImage& image, GLenum target) d->m_canUseMipmaps = false; } #endif - setFilter(GL_LINEAR); d->m_size = img.size(); d->m_yInverted = true; img = d->convertToGLFormat(img); - setDirty(); if (isNull()) { glGenTextures(1, &d->m_texture); } @@ -212,6 +214,7 @@ bool GLTexture::load(const QImage& image, GLenum target) GL_BGRA, GL_UNSIGNED_BYTE, img.bits()); #endif unbind(); + setFilter(GL_LINEAR); return true; } @@ -240,13 +243,44 @@ void GLTexturePrivate::bind() glEnable(m_target); #endif glBindTexture(m_target, m_texture); - enableFilter(); } void GLTexture::bind() { Q_D(GLTexture); d->bind(); + if (d->m_markedDirty) { + d->onDamage(); + } + if (d->m_filterChanged) { + if (d->m_filter == GL_LINEAR_MIPMAP_LINEAR) { + // trilinear filtering requested, but is it possible? + if (d->sNPOTTextureSupported + && d->sFramebufferObjectSupported + && d->m_canUseMipmaps) { + glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glGenerateMipmap(d->m_target); + } else { + // can't use trilinear, so use bilinear + d->m_filter = GL_LINEAR; + glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + } else if (d->m_filter == GL_LINEAR) { + glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + // if neither trilinear nor bilinear, default to fast filtering + d->m_filter = GL_NEAREST; + glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + } + if (d->m_wrapModeChanged) { + glTexParameteri(d->m_target, GL_TEXTURE_WRAP_S, d->m_wrapMode); + glTexParameteri(d->m_target, GL_TEXTURE_WRAP_T, d->m_wrapMode); + } } void GLTexturePrivate::unbind() @@ -334,13 +368,13 @@ GLenum GLTexture::filter() const bool GLTexture::isDirty() const { Q_D(const GLTexture); - return d->m_hasValidMipmaps; + return d->m_markedDirty; } void GLTexture::setTexture(GLuint texture) { - Q_D(GLTexture); discard(); + Q_D(GLTexture); d->m_texture = texture; } @@ -353,53 +387,32 @@ void GLTexture::setTarget(GLenum target) void GLTexture::setFilter(GLenum filter) { Q_D(GLTexture); - d->m_filter = filter; + if (filter != d->m_filter) { + d->m_filter = filter; + d->m_filterChanged = true; + } } void GLTexture::setWrapMode(GLenum mode) { Q_D(GLTexture); - bind(); - glTexParameteri(d->m_target, GL_TEXTURE_WRAP_S, mode); - glTexParameteri(d->m_target, GL_TEXTURE_WRAP_T, mode); - unbind(); + if (mode != d->m_wrapMode) { + d->m_wrapMode = mode; + d->m_wrapModeChanged=true; + } +} + +void GLTexturePrivate::onDamage() +{ + if (m_filter == GL_LINEAR_MIPMAP_LINEAR && !m_filterChanged) { + glGenerateMipmap(m_target); + } } void GLTexture::setDirty() { Q_D(GLTexture); - d->m_hasValidMipmaps = false; -} - - -void GLTexturePrivate::enableFilter() -{ - if (m_filter == GL_LINEAR_MIPMAP_LINEAR) { - // trilinear filtering requested, but is it possible? - 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 - m_filter = GL_LINEAR; - glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(m_target, 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 - m_filter = GL_NEAREST; - glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } + d->m_markedDirty = true; } QImage GLTexturePrivate::convertToGLFormat(const QImage& img) const diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h index 6795d0dbf1..b913eca24e 100644 --- a/libkwineffects/kwingltexture.h +++ b/libkwineffects/kwingltexture.h @@ -94,7 +94,6 @@ public: static bool saturationSupported(); protected: - void enableFilter(); QImage convertToGLFormat(const QImage& img) const; QExplicitlySharedDataPointer d_ptr; diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltexture_p.h index 7e04305a92..27c14db550 100644 --- a/libkwineffects/kwingltexture_p.h +++ b/libkwineffects/kwingltexture_p.h @@ -42,18 +42,21 @@ public: virtual void bind(); virtual void unbind(); virtual void release(); + virtual void onDamage(); - void enableFilter(); QImage convertToGLFormat(const QImage& img) const; GLuint m_texture; GLenum m_target; GLenum m_filter; + GLenum m_wrapMode; 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; + bool m_markedDirty; + bool m_filterChanged; + bool m_wrapModeChanged; int m_unnormalizeActive; // 0 - no, otherwise refcount int m_normalizeActive; // 0 - no, otherwise refcount diff --git a/scene_opengl.h b/scene_opengl.h index 5bc9d5e936..957b6b73cd 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -117,6 +117,7 @@ public: virtual void bind(); virtual void unbind(); virtual void release(); + virtual void onDamage(); #ifndef KWIN_HAVE_OPENGLES GLXPixmap m_glxpixmap; // the glx pixmap the texture is bound to, only for tfp_mode diff --git a/scene_opengl_egl.cpp b/scene_opengl_egl.cpp index 90841338f5..6855133880 100644 --- a/scene_opengl_egl.cpp +++ b/scene_opengl_egl.cpp @@ -266,11 +266,9 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size, return false; glGenTextures(1, &d->m_texture); + setWrapMode(GL_CLAMP_TO_EDGE); + setFilter(GL_LINEAR); 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 @@ -281,6 +279,7 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size, if (EGL_NO_IMAGE_KHR == d->m_image) { kDebug(1212) << "failed to create egl image"; unbind(); + discard(); return false; } glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)d->m_image); @@ -291,15 +290,20 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size, return true; } -void SceneOpenGL::TexturePrivate::bind() +void SceneOpenGL::TexturePrivate::onDamage() { - GLTexturePrivate::bind(); if (options->glStrictBinding) { // This is just implemented to be consistent with // the example in mesa/demos/src/egl/opengles1/texture_from_pixmap.c eglWaitNative(EGL_CORE_NATIVE_ENGINE); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) m_image); } + GLTexturePrivate::onDamage(); +} + +void SceneOpenGL::TexturePrivate::bind() +{ + GLTexturePrivate::bind(); } void SceneOpenGL::TexturePrivate::unbind() diff --git a/scene_opengl_glx.cpp b/scene_opengl_glx.cpp index 88c3139cf3..5290edeaee 100644 --- a/scene_opengl_glx.cpp +++ b/scene_opengl_glx.cpp @@ -721,18 +721,22 @@ bool SceneOpenGL::Texture::load(const Pixmap& pix, const QSize& size, #ifdef CHECK_GL_ERROR checkGLError("TextureLoad0"); #endif + unbind(); return true; } +void SceneOpenGL::TexturePrivate::onDamage() +{ + if (options->glStrictBinding && m_glxpixmap) { + glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT); + glXBindTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT, NULL); + } + GLTexturePrivate::onDamage(); +} + void SceneOpenGL::TexturePrivate::bind() { 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)) { // Lod bias makes the trilinear-filtered texture look a bit sharper glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0f); @@ -744,10 +748,6 @@ void SceneOpenGL::TexturePrivate::unbind() if (hasGLVersion(1, 4, 0)) { glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f); } - if (options->glStrictBinding && m_glxpixmap) { - glBindTexture(m_target, m_texture); - glXReleaseTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT); - } GLTexturePrivate::unbind(); }