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
This commit is contained in:
Thomas Lübking 2013-09-05 21:10:13 +02:00
parent 4fd554a2e2
commit 3f5ef10c8e
5 changed files with 59 additions and 59 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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)
};

View file

@ -28,6 +28,7 @@ DEALINGS IN THE SOFTWARE.
#include "client.h"
#include "deleted.h"
#include "effects.h"
#include <kwinglplatform.h>
#include <kwinglutils.h>
#include <kwinxrenderutils.h>
#include <kdebug.h>
@ -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)

View file

@ -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