kwin: improving the texture update handling
This patch changes the behavior of strictly bound textures such that they are only updated if the corresponding window has been damaged. Additionally GLTexture now keeps track of the current filter and wrapmode setting. REVIEW: 103655
This commit is contained in:
parent
5fde665578
commit
87bcabdf99
6 changed files with 83 additions and 63 deletions
|
@ -4,6 +4,7 @@
|
|||
|
||||
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
|
||||
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||
Copyright (C) 2012 Philipp Knechtges <philipp-dev@knechtges.com>
|
||||
|
||||
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
|
||||
|
|
|
@ -94,7 +94,6 @@ public:
|
|||
static bool saturationSupported();
|
||||
|
||||
protected:
|
||||
void enableFilter();
|
||||
QImage convertToGLFormat(const QImage& img) const;
|
||||
|
||||
QExplicitlySharedDataPointer<GLTexturePrivate> d_ptr;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue