2011-06-22 10:55:04 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2006-2007 Rivo Laks <rivolaks@hot.ee>
|
|
|
|
Copyright (C) 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
2012-01-07 11:12:29 +00:00
|
|
|
Copyright (C) 2012 Philipp Knechtges <philipp-dev@knechtges.com>
|
2011-06-22 10:55:04 +00:00
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#include "kwinconfig.h" // KWIN_HAVE_OPENGL
|
|
|
|
|
|
|
|
#include "kwinglplatform.h"
|
|
|
|
#include "kwinglutils_funcs.h"
|
|
|
|
#include "kwinglutils.h"
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
#include "kwingltexture_p.h"
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
#include <QPixmap>
|
|
|
|
#include <QImage>
|
|
|
|
#include <QVector2D>
|
|
|
|
#include <QVector3D>
|
|
|
|
#include <QVector4D>
|
|
|
|
#include <QMatrix4x4>
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
//****************************************
|
|
|
|
// GLTexture
|
|
|
|
//****************************************
|
|
|
|
|
2014-11-22 15:24:26 +00:00
|
|
|
bool GLTexturePrivate::s_supportsFramebufferObjects = false;
|
2014-11-22 15:44:14 +00:00
|
|
|
bool GLTexturePrivate::s_supportsARGB32 = false;
|
2014-11-22 15:17:51 +00:00
|
|
|
bool GLTexturePrivate::s_supportsUnpack = false;
|
2013-09-05 19:10:13 +00:00
|
|
|
uint GLTexturePrivate::s_textureObjectCounter = 0;
|
|
|
|
uint GLTexturePrivate::s_fbo = 0;
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
|
|
|
|
GLTexture::GLTexture()
|
2011-07-18 15:55:39 +00:00
|
|
|
: d_ptr(new GLTexturePrivate())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::GLTexture(GLTexturePrivate& dd)
|
|
|
|
: d_ptr(&dd)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::GLTexture(const GLTexture& tex)
|
|
|
|
: d_ptr(tex.d_ptr)
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::GLTexture(const QImage& image, GLenum target)
|
2011-07-18 15:55:39 +00:00
|
|
|
: d_ptr(new GLTexturePrivate())
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2014-11-26 20:34:27 +00:00
|
|
|
Q_D(GLTexture);
|
|
|
|
|
|
|
|
if (image.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->m_target = target;
|
|
|
|
|
|
|
|
if (d->m_target != GL_TEXTURE_RECTANGLE_ARB) {
|
|
|
|
d->m_scale.setWidth(1.0 / image.width());
|
|
|
|
d->m_scale.setHeight(1.0 / image.height());
|
|
|
|
} else {
|
|
|
|
d->m_scale.setWidth(1.0);
|
|
|
|
d->m_scale.setHeight(1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
d->m_size = image.size();
|
|
|
|
d->m_yInverted = true;
|
2014-12-10 19:26:23 +00:00
|
|
|
d->m_canUseMipmaps = false;
|
|
|
|
d->m_mipLevels = 1;
|
2014-11-26 20:34:27 +00:00
|
|
|
|
|
|
|
d->updateMatrix();
|
|
|
|
|
|
|
|
glGenTextures(1, &d->m_texture);
|
|
|
|
bind();
|
|
|
|
|
|
|
|
if (!GLPlatform::instance()->isGLES()) {
|
|
|
|
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
2014-12-10 19:26:23 +00:00
|
|
|
glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, d->m_mipLevels - 1);
|
2014-11-26 20:34:27 +00:00
|
|
|
glTexImage2D(d->m_target, 0, GL_RGBA8, im.width(), im.height(), 0,
|
|
|
|
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, im.bits());
|
|
|
|
} else {
|
|
|
|
if (d->s_supportsARGB32) {
|
|
|
|
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
|
|
glTexImage2D(d->m_target, 0, GL_BGRA_EXT, im.width(), im.height(),
|
|
|
|
0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.bits());
|
|
|
|
} else {
|
|
|
|
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
|
|
|
|
glTexImage2D(d->m_target, 0, GL_RGBA, im.width(), im.height(),
|
|
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unbind();
|
|
|
|
setFilter(GL_LINEAR);
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::GLTexture(const QPixmap& pixmap, GLenum target)
|
2014-11-26 20:34:27 +00:00
|
|
|
: GLTexture(pixmap.toImage(), target)
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::GLTexture(const QString& fileName)
|
2014-11-26 20:34:27 +00:00
|
|
|
: GLTexture(QImage(fileName))
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-12-10 19:26:23 +00:00
|
|
|
GLTexture::GLTexture(int width, int height, int levels)
|
2011-07-18 15:55:39 +00:00
|
|
|
: d_ptr(new GLTexturePrivate())
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(GLTexture);
|
2011-06-22 10:55:04 +00:00
|
|
|
|
2014-11-22 14:53:15 +00:00
|
|
|
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);
|
2014-12-10 19:26:23 +00:00
|
|
|
d->m_canUseMipmaps = levels > 1;
|
|
|
|
d->m_mipLevels = levels;
|
2014-11-22 14:53:15 +00:00
|
|
|
d->m_canUseMipmaps = true;
|
2014-12-10 19:26:23 +00:00
|
|
|
d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
|
2012-09-27 19:22:05 +00:00
|
|
|
|
2014-11-22 14:53:15 +00:00
|
|
|
d->updateMatrix();
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2014-11-22 14:53:15 +00:00
|
|
|
glGenTextures(1, &d->m_texture);
|
|
|
|
bind();
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2014-11-22 14:53:15 +00:00
|
|
|
if (!GLPlatform::instance()->isGLES()) {
|
2014-12-10 19:26:23 +00:00
|
|
|
glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, levels - 1);
|
2014-11-22 15:44:14 +00:00
|
|
|
glTexImage2D(d->m_target, 0, GL_RGBA8, width, height, 0,
|
|
|
|
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
|
2014-11-22 14:53:15 +00:00
|
|
|
} else {
|
2014-11-22 15:44:14 +00:00
|
|
|
// The format parameter in glTexSubImage() must match the internal format
|
|
|
|
// of the texture, so it's important that we allocate the texture with
|
|
|
|
// the format that will be used in update() and clear().
|
|
|
|
const GLenum format = d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
|
|
|
|
glTexImage2D(d->m_target, 0, format, width, height, 0,
|
|
|
|
format, GL_UNSIGNED_BYTE, nullptr);
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
2014-11-22 14:53:15 +00:00
|
|
|
|
|
|
|
unbind();
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2014-12-10 19:26:23 +00:00
|
|
|
GLTexture::GLTexture(const QSize &size, int levels)
|
|
|
|
: GLTexture(size.width(), size.height(), levels)
|
2014-02-24 15:08:59 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
GLTexture::~GLTexture()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
GLTexture& GLTexture::operator = (const GLTexture& tex)
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
d_ptr = tex.d_ptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLTexturePrivate::GLTexturePrivate()
|
|
|
|
{
|
|
|
|
m_texture = 0;
|
|
|
|
m_target = 0;
|
2012-06-13 23:23:48 +00:00
|
|
|
m_filter = GL_NEAREST;
|
2012-01-07 11:12:29 +00:00
|
|
|
m_wrapMode = GL_REPEAT;
|
2011-07-18 15:55:39 +00:00
|
|
|
m_yInverted = false;
|
|
|
|
m_canUseMipmaps = false;
|
2014-12-10 19:26:23 +00:00
|
|
|
m_mipLevels = 1;
|
2012-01-07 11:12:29 +00:00
|
|
|
m_markedDirty = false;
|
2011-07-18 15:55:39 +00:00
|
|
|
m_unnormalizeActive = 0;
|
|
|
|
m_normalizeActive = 0;
|
2014-01-08 10:43:02 +00:00
|
|
|
m_vbo = nullptr;
|
2012-06-13 23:23:48 +00:00
|
|
|
m_filterChanged = true;
|
2012-01-07 11:12:29 +00:00
|
|
|
m_wrapModeChanged = false;
|
2013-09-05 19:10:13 +00:00
|
|
|
++s_textureObjectCounter;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
GLTexturePrivate::~GLTexturePrivate()
|
|
|
|
{
|
2014-01-08 10:43:02 +00:00
|
|
|
if (m_vbo != nullptr) {
|
2011-07-18 15:55:39 +00:00
|
|
|
delete m_vbo;
|
|
|
|
}
|
|
|
|
if (m_texture != 0) {
|
|
|
|
glDeleteTextures(1, &m_texture);
|
|
|
|
}
|
2013-09-05 19:10:13 +00:00
|
|
|
// Delete the FBO if this is the last Texture
|
|
|
|
if (--s_textureObjectCounter == 0 && s_fbo) {
|
|
|
|
glDeleteFramebuffers(1, &s_fbo);
|
|
|
|
s_fbo = 0;
|
|
|
|
}
|
2011-07-18 15:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexturePrivate::initStatic()
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2014-11-22 14:01:11 +00:00
|
|
|
if (!GLPlatform::instance()->isGLES()) {
|
2014-11-22 15:24:26 +00:00
|
|
|
s_supportsFramebufferObjects = hasGLVersion(3, 0) ||
|
|
|
|
hasGLExtension("GL_ARB_framebuffer_object") || hasGLExtension(QByteArrayLiteral("GL_EXT_framebuffer_object"));
|
2014-11-22 15:44:14 +00:00
|
|
|
s_supportsARGB32 = true;
|
2014-11-22 15:17:51 +00:00
|
|
|
s_supportsUnpack = true;
|
2014-11-22 14:01:11 +00:00
|
|
|
} else {
|
2014-11-22 15:24:26 +00:00
|
|
|
s_supportsFramebufferObjects = true;
|
2014-11-22 15:44:14 +00:00
|
|
|
|
|
|
|
// QImage::Format_ARGB32_Premultiplied is a packed-pixel format, so it's only
|
|
|
|
// equivalent to GL_BGRA/GL_UNSIGNED_BYTE on little-endian systems.
|
|
|
|
s_supportsARGB32 = QSysInfo::ByteOrder == QSysInfo::LittleEndian &&
|
|
|
|
hasGLExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"));
|
|
|
|
|
2014-11-22 15:17:51 +00:00
|
|
|
s_supportsUnpack = hasGLExtension(QByteArrayLiteral("GL_EXT_unpack_subimage"));
|
2014-11-22 14:01:11 +00:00
|
|
|
}
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2014-04-10 16:04:54 +00:00
|
|
|
void GLTexturePrivate::cleanup()
|
|
|
|
{
|
2014-11-22 15:24:26 +00:00
|
|
|
s_supportsFramebufferObjects = false;
|
2014-11-22 15:44:14 +00:00
|
|
|
s_supportsARGB32 = false;
|
2014-04-10 16:04:54 +00:00
|
|
|
}
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
bool GLTexture::isNull() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return None == d->m_texture;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QSize GLTexture::size() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_size;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2013-02-22 09:13:46 +00:00
|
|
|
void GLTexture::update(const QImage &image, const QPoint &offset, const QRect &src)
|
|
|
|
{
|
|
|
|
if (image.isNull() || isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Q_D(GLTexture);
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2014-11-22 15:44:14 +00:00
|
|
|
bool useUnpack = !src.isNull() && d->s_supportsUnpack && d->s_supportsARGB32 && image.format() == QImage::Format_ARGB32_Premultiplied;
|
|
|
|
|
2013-02-22 09:13:46 +00:00
|
|
|
int width = image.width();
|
|
|
|
int height = image.height();
|
|
|
|
QImage tmpImage;
|
2014-11-22 15:44:14 +00:00
|
|
|
|
2013-02-22 09:13:46 +00:00
|
|
|
if (!src.isNull()) {
|
2014-11-22 15:17:51 +00:00
|
|
|
if (d->s_supportsUnpack) {
|
2013-02-22 09:13:46 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width());
|
|
|
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.x());
|
|
|
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, src.y());
|
|
|
|
} else {
|
|
|
|
tmpImage = image.copy(src);
|
|
|
|
}
|
|
|
|
width = src.width();
|
|
|
|
height = src.height();
|
|
|
|
}
|
2014-11-22 15:44:14 +00:00
|
|
|
|
|
|
|
const QImage &img = tmpImage.isNull() ? image : tmpImage;
|
2013-02-22 09:13:46 +00:00
|
|
|
|
|
|
|
bind();
|
2014-11-22 15:44:14 +00:00
|
|
|
|
|
|
|
if (!GLPlatform::instance()->isGLES()) {
|
|
|
|
const QImage im = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
|
|
glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height,
|
|
|
|
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, im.bits());
|
|
|
|
} else {
|
|
|
|
if (d->s_supportsARGB32) {
|
|
|
|
const QImage im = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
|
|
glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height,
|
|
|
|
GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.bits());
|
|
|
|
} else {
|
|
|
|
const QImage im = img.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
|
|
|
|
glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height,
|
|
|
|
GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 18:02:57 +00:00
|
|
|
|
2013-02-22 09:13:46 +00:00
|
|
|
unbind();
|
2014-11-22 15:44:14 +00:00
|
|
|
|
|
|
|
if (useUnpack) {
|
2013-02-22 09:13:46 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
|
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
|
|
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
void GLTexture::discard()
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
d_ptr = new GLTexturePrivate();
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
void GLTexture::bind()
|
|
|
|
{
|
|
|
|
Q_D(GLTexture);
|
2014-11-26 20:40:11 +00:00
|
|
|
|
|
|
|
glBindTexture(d->m_target, d->m_texture);
|
|
|
|
|
2012-01-07 11:12:29 +00:00
|
|
|
if (d->m_markedDirty) {
|
|
|
|
d->onDamage();
|
|
|
|
}
|
|
|
|
if (d->m_filterChanged) {
|
2014-12-10 19:16:40 +00:00
|
|
|
GLenum minFilter = GL_NEAREST;
|
|
|
|
GLenum magFilter = GL_NEAREST;
|
|
|
|
|
|
|
|
switch (d->m_filter) {
|
|
|
|
case GL_NEAREST:
|
|
|
|
minFilter = magFilter = GL_NEAREST;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_LINEAR:
|
|
|
|
minFilter = magFilter = GL_LINEAR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_NEAREST_MIPMAP_NEAREST:
|
|
|
|
case GL_NEAREST_MIPMAP_LINEAR:
|
|
|
|
magFilter = GL_NEAREST;
|
|
|
|
minFilter = d->m_canUseMipmaps ? d->m_filter : GL_NEAREST;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
case GL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
magFilter = GL_LINEAR;
|
|
|
|
minFilter = d->m_canUseMipmaps ? d->m_filter : GL_LINEAR;
|
|
|
|
break;
|
2012-01-07 11:12:29 +00:00
|
|
|
}
|
2014-12-10 19:16:40 +00:00
|
|
|
|
|
|
|
glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, minFilter);
|
|
|
|
glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, magFilter);
|
|
|
|
|
2013-06-13 16:37:25 +00:00
|
|
|
d->m_filterChanged = false;
|
2012-01-07 11:12:29 +00:00
|
|
|
}
|
|
|
|
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);
|
2013-06-13 16:37:25 +00:00
|
|
|
d->m_wrapModeChanged = false;
|
2012-01-07 11:12:29 +00:00
|
|
|
}
|
2011-07-18 15:55:39 +00:00
|
|
|
}
|
|
|
|
|
2014-12-11 21:22:08 +00:00
|
|
|
void GLTexture::generateMipmaps()
|
|
|
|
{
|
|
|
|
Q_D(GLTexture);
|
|
|
|
|
|
|
|
if (d->m_canUseMipmaps && d->s_supportsFramebufferObjects)
|
|
|
|
glGenerateMipmap(d->m_target);
|
|
|
|
}
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
void GLTexture::unbind()
|
|
|
|
{
|
|
|
|
Q_D(GLTexture);
|
2014-11-26 20:40:11 +00:00
|
|
|
glBindTexture(d->m_target, 0);
|
2011-07-18 15:55:39 +00:00
|
|
|
}
|
|
|
|
|
2012-02-12 15:42:09 +00:00
|
|
|
void GLTexture::render(QRegion region, const QRect& rect, bool hardwareClipping)
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(GLTexture);
|
|
|
|
if (rect.size() != d->m_cachedSize) {
|
|
|
|
d->m_cachedSize = rect.size();
|
2011-06-22 10:55:04 +00:00
|
|
|
QRect r(rect);
|
|
|
|
r.moveTo(0, 0);
|
2011-07-18 15:55:39 +00:00
|
|
|
if (!d->m_vbo) {
|
|
|
|
d->m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static);
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
const float verts[ 4 * 2 ] = {
|
|
|
|
// NOTICE: r.x/y could be replaced by "0", but that would make it unreadable...
|
2012-10-23 21:16:29 +00:00
|
|
|
static_cast<float>(r.x()), static_cast<float>(r.y()),
|
|
|
|
static_cast<float>(r.x()), static_cast<float>(r.y() + rect.height()),
|
|
|
|
static_cast<float>(r.x() + rect.width()), static_cast<float>(r.y()),
|
|
|
|
static_cast<float>(r.x() + rect.width()), static_cast<float>(r.y() + rect.height())
|
2011-06-22 10:55:04 +00:00
|
|
|
};
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2011-10-15 12:14:44 +00:00
|
|
|
const float texWidth = (target() == GL_TEXTURE_RECTANGLE_ARB) ? width() : 1.0f;
|
|
|
|
const float texHeight = (target() == GL_TEXTURE_RECTANGLE_ARB) ? height() : 1.0f;
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
const float texcoords[ 4 * 2 ] = {
|
2011-10-15 12:14:44 +00:00
|
|
|
0.0f, d->m_yInverted ? 0.0f : texHeight, // y needs to be swapped (normalized coords)
|
|
|
|
0.0f, d->m_yInverted ? texHeight : 0.0f,
|
|
|
|
texWidth, d->m_yInverted ? 0.0f : texHeight,
|
|
|
|
texWidth, d->m_yInverted ? texHeight : 0.0f
|
2011-06-22 10:55:04 +00:00
|
|
|
};
|
2014-11-22 14:01:11 +00:00
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
d->m_vbo->setData(4, 2, verts, texcoords);
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
QMatrix4x4 translation;
|
|
|
|
translation.translate(rect.x(), rect.y());
|
2014-02-25 10:02:32 +00:00
|
|
|
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
|
|
|
shader->setUniform(GLShader::Offset, QVector2D(rect.x(), rect.y()));
|
|
|
|
shader->setUniform(GLShader::WindowTransformation, translation);
|
2012-02-12 15:42:09 +00:00
|
|
|
d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping);
|
2014-02-25 10:02:32 +00:00
|
|
|
shader->setUniform(GLShader::WindowTransformation, QMatrix4x4());
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLuint GLTexture::texture() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_texture;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLenum GLTexture::target() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_target;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLenum GLTexture::filter() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_filter;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2013-09-05 19:10:13 +00:00
|
|
|
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();
|
2014-11-22 15:44:14 +00:00
|
|
|
if (!GLPlatform::instance()->isGLES()) {
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(),
|
|
|
|
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
|
|
|
} else {
|
|
|
|
const GLenum format = d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(),
|
|
|
|
format, GL_UNSIGNED_BYTE, buffer);
|
|
|
|
}
|
2013-09-05 19:10:13 +00:00
|
|
|
unbind();
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
bool GLTexture::isDirty() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
2012-01-07 11:12:29 +00:00
|
|
|
return d->m_markedDirty;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::setFilter(GLenum filter)
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(GLTexture);
|
2012-01-07 11:12:29 +00:00
|
|
|
if (filter != d->m_filter) {
|
|
|
|
d->m_filter = filter;
|
|
|
|
d->m_filterChanged = true;
|
|
|
|
}
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::setWrapMode(GLenum mode)
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(GLTexture);
|
2012-01-07 11:12:29 +00:00
|
|
|
if (mode != d->m_wrapMode) {
|
|
|
|
d->m_wrapMode = mode;
|
|
|
|
d->m_wrapModeChanged=true;
|
|
|
|
}
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 11:12:29 +00:00
|
|
|
void GLTexturePrivate::onDamage()
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2014-12-11 21:22:08 +00:00
|
|
|
// No-op
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2012-01-07 11:12:29 +00:00
|
|
|
void GLTexture::setDirty()
|
2011-06-22 10:55:04 +00:00
|
|
|
{
|
2012-01-07 11:12:29 +00:00
|
|
|
Q_D(GLTexture);
|
|
|
|
d->m_markedDirty = true;
|
2011-06-22 10:55:04 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 19:22:05 +00:00
|
|
|
void GLTexturePrivate::updateMatrix()
|
|
|
|
{
|
|
|
|
m_matrix[NormalizedCoordinates].setToIdentity();
|
|
|
|
m_matrix[UnnormalizedCoordinates].setToIdentity();
|
|
|
|
|
|
|
|
if (m_target == GL_TEXTURE_RECTANGLE_ARB)
|
|
|
|
m_matrix[NormalizedCoordinates].scale(m_size.width(), m_size.height());
|
|
|
|
else
|
|
|
|
m_matrix[UnnormalizedCoordinates].scale(1.0 / m_size.width(), 1.0 / m_size.height());
|
|
|
|
|
|
|
|
if (!m_yInverted) {
|
|
|
|
m_matrix[NormalizedCoordinates].translate(0.0, 1.0);
|
|
|
|
m_matrix[NormalizedCoordinates].scale(1.0, -1.0);
|
|
|
|
|
|
|
|
m_matrix[UnnormalizedCoordinates].translate(0.0, m_size.height());
|
|
|
|
m_matrix[UnnormalizedCoordinates].scale(1.0, -1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-03 07:30:38 +00:00
|
|
|
bool GLTexture::isYInverted() const
|
|
|
|
{
|
2011-07-18 15:55:39 +00:00
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_yInverted;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::setYInverted(bool inverted)
|
|
|
|
{
|
|
|
|
Q_D(GLTexture);
|
|
|
|
d->m_yInverted = inverted;
|
2012-09-27 19:22:05 +00:00
|
|
|
d->updateMatrix();
|
2011-07-18 15:55:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2012-09-27 19:22:05 +00:00
|
|
|
QMatrix4x4 GLTexture::matrix(TextureCoordinateType type) const
|
|
|
|
{
|
|
|
|
Q_D(const GLTexture);
|
|
|
|
return d->m_matrix[type];
|
|
|
|
}
|
|
|
|
|
2011-07-18 15:55:39 +00:00
|
|
|
bool GLTexture::framebufferObjectSupported()
|
|
|
|
{
|
2014-11-22 15:24:26 +00:00
|
|
|
return GLTexturePrivate::s_supportsFramebufferObjects;
|
2011-07-18 15:55:39 +00:00
|
|
|
}
|
|
|
|
|
2011-06-22 10:55:04 +00:00
|
|
|
} // namespace KWin
|