From 3f5ef10c8efbf8d5223013bd821768116429cfe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Thu, 5 Sep 2013 21:10:13 +0200 Subject: [PATCH] introduce GLTexture::clear and use it from paintredirector also work around broken fbo texture clearing on fglrx so far supports FBO/glClear and resorts to glTexSubImage2D if the fbo cannot be created or is (in case of fglrx) known to break, resort to glTexImage2D loading of an argb array of zeros BUG: 323065 FIXED-IN: 4.11.2 REVIEW: 112526 --- libkwineffects/kwingltexture.cpp | 72 ++++++++++++++++++++++---------- libkwineffects/kwingltexture.h | 5 +++ libkwineffects/kwingltexture_p.h | 4 +- paintredirector.cpp | 34 +-------------- paintredirector.h | 3 -- 5 files changed, 59 insertions(+), 59 deletions(-) diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp index f6082d88f8..7423ed4a74 100644 --- a/libkwineffects/kwingltexture.cpp +++ b/libkwineffects/kwingltexture.cpp @@ -46,7 +46,10 @@ namespace KWin bool GLTexturePrivate::sNPOTTextureSupported = false; bool GLTexturePrivate::sFramebufferObjectSupported = false; bool GLTexturePrivate::sSaturationSupported = false; -bool GLTexturePrivate::sTextureFormatBGRA = false; +GLenum GLTexturePrivate::sTextureFormat = GL_RGBA; // custom dummy, GL_BGRA is not present on GLES +uint GLTexturePrivate::s_textureObjectCounter = 0; +uint GLTexturePrivate::s_fbo = 0; + GLTexture::GLTexture() : d_ptr(new GLTexturePrivate()) @@ -97,11 +100,8 @@ GLTexture::GLTexture(int width, int height) glGenTextures(1, &d->m_texture); bind(); #ifdef KWIN_HAVE_OPENGLES - if (GLTexturePrivate::sTextureFormatBGRA) { - glTexImage2D(d->m_target, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0); - } else { - glTexImage2D(d->m_target, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - } + glTexImage2D(d->m_target, 0, GLTexturePrivate::sTextureFormat, width, height, + 0, GLTexturePrivate::sTextureFormat, GL_UNSIGNED_BYTE, 0); #else glTexImage2D(d->m_target, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0); #endif @@ -133,6 +133,7 @@ GLTexturePrivate::GLTexturePrivate() m_vbo = 0; m_filterChanged = true; m_wrapModeChanged = false; + ++s_textureObjectCounter; } GLTexturePrivate::~GLTexturePrivate() @@ -143,6 +144,11 @@ GLTexturePrivate::~GLTexturePrivate() if (m_texture != 0) { glDeleteTextures(1, &m_texture); } + // Delete the FBO if this is the last Texture + if (--s_textureObjectCounter == 0 && s_fbo) { + glDeleteFramebuffers(1, &s_fbo); + s_fbo = 0; + } } void GLTexturePrivate::initStatic() @@ -151,14 +157,17 @@ void GLTexturePrivate::initStatic() sNPOTTextureSupported = true; sFramebufferObjectSupported = true; sSaturationSupported = true; - sTextureFormatBGRA = hasGLExtension("GL_EXT_texture_format_BGRA8888"); + if (hasGLExtension("GL_EXT_texture_format_BGRA8888")) + sTextureFormat = GL_BGRA_EXT; + else + sTextureFormat = GL_RGBA; #else sNPOTTextureSupported = hasGLExtension("GL_ARB_texture_non_power_of_two"); sFramebufferObjectSupported = hasGLExtension("GL_EXT_framebuffer_object"); sSaturationSupported = ((hasGLExtension("GL_ARB_texture_env_crossbar") && hasGLExtension("GL_ARB_texture_env_dot3")) || hasGLVersion(1, 4)) && (glTextureUnitsCount >= 4) && glActiveTexture != NULL; - sTextureFormatBGRA = true; + sTextureFormat = GL_BGRA; #endif } @@ -215,11 +224,8 @@ bool GLTexture::load(const QImage& image, GLenum target) } bind(); #ifdef KWIN_HAVE_OPENGLES - if (GLTexturePrivate::sTextureFormatBGRA) { - glTexImage2D(d->m_target, 0, GL_BGRA_EXT, img.width(), img.height(), 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, img.bits()); - } else { - glTexImage2D(d->m_target, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - } + glTexImage2D(d->m_target, 0, GLTexturePrivate::sTextureFormat, img.width(), img.height(), + 0, GLTexturePrivate::sTextureFormat, GL_UNSIGNED_BYTE, img.bits()); #else glTexImage2D(d->m_target, 0, GL_RGBA8, img.width(), img.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, img.bits()); @@ -258,15 +264,8 @@ void GLTexture::update(const QImage &image, const QPoint &offset, const QRect &s const QImage &img = d->convertToGLFormat(tmpImage.isNull() ? image : tmpImage); bind(); -#ifdef KWIN_HAVE_OPENGLES - if (GLTexturePrivate::sTextureFormatBGRA) { - glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, img.bits()); - } else { - 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 + glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height, + GLTexturePrivate::sTextureFormat, GL_UNSIGNED_BYTE, img.bits()); checkGLError("update texture"); unbind(); setDirty(); @@ -428,6 +427,33 @@ GLenum GLTexture::filter() const return d->m_filter; } +void GLTexture::clear() +{ + Q_D(GLTexture); + if (!GLTexturePrivate::s_fbo && GLRenderTarget::supported() && + GLPlatform::instance()->driver() != Driver_Catalyst) // fail. -> bug #323065 + glGenFramebuffers(1, &GLTexturePrivate::s_fbo); + + if (GLTexturePrivate::s_fbo) { + // Clear the texture + glBindFramebuffer(GL_FRAMEBUFFER, GLTexturePrivate::s_fbo); + glClearColor(0, 0, 0, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, d->m_texture, 0); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } else { + if (const int size = width()*height()) { + uint32_t *buffer = new uint32_t[size]; + memset(buffer, 0, size*sizeof(uint32_t)); + bind(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(), + GLTexturePrivate::sTextureFormat, GL_UNSIGNED_BYTE, buffer); + unbind(); + delete[] buffer; + } + } +} + bool GLTexture::isDirty() const { Q_D(const GLTexture); @@ -470,7 +496,7 @@ QImage GLTexturePrivate::convertToGLFormat(const QImage& img) const // Copied from Qt's QGLWidget::convertToGLFormat() QImage res; - if (sTextureFormatBGRA) { + if (sTextureFormat != GL_RGBA) { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { res = QImage(img.size(), QImage::Format_ARGB32); QImage imgARGB32 = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h index 18e0a80081..200d24f322 100644 --- a/libkwineffects/kwingltexture.h +++ b/libkwineffects/kwingltexture.h @@ -93,6 +93,11 @@ public: GLuint texture() const; GLenum target() const; GLenum filter() const; + /** @short + * Make the texture fully transparent + * Warning: this clobbers the current framebuffer binding except on fglrx + */ + void clear(); bool isDirty() const; void setFilter(GLenum filter); void setWrapMode(GLenum mode); diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltexture_p.h index 2afc9aa7a4..0b57d9742b 100644 --- a/libkwineffects/kwingltexture_p.h +++ b/libkwineffects/kwingltexture_p.h @@ -73,7 +73,9 @@ public: static bool sNPOTTextureSupported; static bool sFramebufferObjectSupported; static bool sSaturationSupported; - static bool sTextureFormatBGRA; + static GLenum sTextureFormat; + static uint s_fbo; + static uint s_textureObjectCounter; private: Q_DISABLE_COPY(GLTexturePrivate) }; diff --git a/paintredirector.cpp b/paintredirector.cpp index 982ab6f58b..528827ea53 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 @@ -310,21 +311,12 @@ void ImageBasedPaintRedirector::discardScratch() // ------------------------------------------------------------------ - -unsigned int OpenGLPaintRedirector::s_count = 0; -unsigned int OpenGLPaintRedirector::s_fbo = 0; - OpenGLPaintRedirector::OpenGLPaintRedirector(Client *c, QWidget *widget) : ImageBasedPaintRedirector(c, widget) { - s_count++; - for (int i = 0; i < TextureCount; ++i) m_textures[i] = NULL; - if (!s_fbo && GLRenderTarget::supported()) - glGenFramebuffers(1, &s_fbo); - PaintRedirector::resizePixmaps(); } @@ -332,12 +324,6 @@ OpenGLPaintRedirector::~OpenGLPaintRedirector() { for (int i = 0; i < TextureCount; ++i) delete m_textures[i]; - - // Delete the FBO if this is the last OpenGLPaintRedirector - if (--s_count == 0 && s_fbo) { - glDeleteFramebuffers(1, &s_fbo); - s_fbo = 0; - } } void OpenGLPaintRedirector::resizePixmaps(const QRect *rects) @@ -355,8 +341,6 @@ void OpenGLPaintRedirector::resizePixmaps(const QRect *rects) } } - bool fbo_bound = false; - for (int i = 0; i < 2; i++) { if (m_textures[i] && m_textures[i]->size() == size[i]) continue; @@ -370,22 +354,8 @@ void OpenGLPaintRedirector::resizePixmaps(const QRect *rects) m_textures[i] = new GLTexture(size[i].width(), size[i].height()); m_textures[i]->setYInverted(true); m_textures[i]->setWrapMode(GL_CLAMP_TO_EDGE); - - if (s_fbo) { - // Clear the texture - if (!fbo_bound) { - glBindFramebuffer(GL_FRAMEBUFFER, s_fbo); - glClearColor(0, 0, 0, 0); - fbo_bound = true; - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_textures[i]->texture(), 0); - glClear(GL_COLOR_BUFFER_BIT); - } + m_textures[i]->clear(); } - - if (fbo_bound) - glBindFramebuffer(GL_FRAMEBUFFER, 0); } void OpenGLPaintRedirector::preparePaint(const QPixmap &pending) diff --git a/paintredirector.h b/paintredirector.h index fbc53042c5..be96f051e6 100644 --- a/paintredirector.h +++ b/paintredirector.h @@ -157,9 +157,6 @@ protected: private: QImage m_tempImage; GLTexture *m_textures[2]; - - static unsigned int s_fbo; - static unsigned int s_count; }; class NativeXRenderPaintRedirector : public PaintRedirector