File indexing completed on 2024-05-19 16:34:33

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2006-2007 Rivo Laks <rivolaks@hot.ee>
0006     SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
0007     SPDX-FileCopyrightText: 2012 Philipp Knechtges <philipp-dev@knechtges.com>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "kwinconfig.h" // KWIN_HAVE_OPENGL
0013 #include "kwineffects.h"
0014 #include "kwinglplatform.h"
0015 #include "kwinglutils.h"
0016 #include "kwinglutils_funcs.h"
0017 
0018 #include "kwingltexture_p.h"
0019 
0020 #include <QImage>
0021 #include <QPixmap>
0022 #include <QVector2D>
0023 #include <QVector3D>
0024 #include <QVector4D>
0025 
0026 namespace KWin
0027 {
0028 
0029 //****************************************
0030 // GLTexture
0031 //****************************************
0032 
0033 bool GLTexturePrivate::s_supportsFramebufferObjects = false;
0034 bool GLTexturePrivate::s_supportsARGB32 = false;
0035 bool GLTexturePrivate::s_supportsUnpack = false;
0036 bool GLTexturePrivate::s_supportsTextureStorage = false;
0037 bool GLTexturePrivate::s_supportsTextureSwizzle = false;
0038 bool GLTexturePrivate::s_supportsTextureFormatRG = false;
0039 bool GLTexturePrivate::s_supportsTexture16Bit = false;
0040 uint GLTexturePrivate::s_fbo = 0;
0041 
0042 // Table of GL formats/types associated with different values of QImage::Format.
0043 // Zero values indicate a direct upload is not feasible.
0044 //
0045 // Note: Blending is set up to expect premultiplied data, so the non-premultiplied
0046 // Format_ARGB32 must be converted to Format_ARGB32_Premultiplied ahead of time.
0047 struct
0048 {
0049     GLenum internalFormat;
0050     GLenum format;
0051     GLenum type;
0052 } static const formatTable[] = {
0053     {0, 0, 0}, // QImage::Format_Invalid
0054     {0, 0, 0}, // QImage::Format_Mono
0055     {0, 0, 0}, // QImage::Format_MonoLSB
0056     {0, 0, 0}, // QImage::Format_Indexed8
0057     {GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, // QImage::Format_RGB32
0058     {0, 0, 0}, // QImage::Format_ARGB32
0059     {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, // QImage::Format_ARGB32_Premultiplied
0060     {GL_RGB8, GL_BGR, GL_UNSIGNED_SHORT_5_6_5_REV}, // QImage::Format_RGB16
0061     {0, 0, 0}, // QImage::Format_ARGB8565_Premultiplied
0062     {0, 0, 0}, // QImage::Format_RGB666
0063     {0, 0, 0}, // QImage::Format_ARGB6666_Premultiplied
0064     {GL_RGB5, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, // QImage::Format_RGB555
0065     {0, 0, 0}, // QImage::Format_ARGB8555_Premultiplied
0066     {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // QImage::Format_RGB888
0067     {GL_RGB4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // QImage::Format_RGB444
0068     {GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, // QImage::Format_ARGB4444_Premultiplied
0069     {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE}, // QImage::Format_RGBX8888
0070     {0, 0, 0}, // QImage::Format_RGBA8888
0071     {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // QImage::Format_RGBA8888_Premultiplied
0072     {GL_RGB10, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // QImage::Format_BGR30
0073     {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, // QImage::Format_A2BGR30_Premultiplied
0074     {GL_RGB10, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV}, // QImage::Format_RGB30
0075     {GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV}, // QImage::Format_A2RGB30_Premultiplied
0076     {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // QImage::Format_Alpha8
0077     {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, // QImage::Format_Grayscale8
0078     {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // QImage::Format_RGBX64
0079     {0, 0, 0}, // QImage::Format_RGBA64
0080     {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, // QImage::Format_RGBA64_Premultiplied
0081     {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, // QImage::Format_Grayscale16
0082     {0, 0, 0}, // QImage::Format_BGR888
0083 };
0084 
0085 GLTexture::GLTexture(GLenum target)
0086     : d_ptr(new GLTexturePrivate())
0087 {
0088     Q_D(GLTexture);
0089     d->m_target = target;
0090 }
0091 
0092 GLTexture::GLTexture(GLTexturePrivate &dd)
0093     : d_ptr(&dd)
0094 {
0095 }
0096 
0097 GLTexture::GLTexture(const GLTexture &tex)
0098     : d_ptr(tex.d_ptr)
0099 {
0100 }
0101 
0102 GLTexture::GLTexture(const QImage &image, GLenum target)
0103     : d_ptr(new GLTexturePrivate())
0104 {
0105     Q_D(GLTexture);
0106 
0107     if (image.isNull()) {
0108         return;
0109     }
0110 
0111     d->m_target = target;
0112 
0113     if (d->m_target != GL_TEXTURE_RECTANGLE_ARB) {
0114         d->m_scale.setWidth(1.0 / image.width());
0115         d->m_scale.setHeight(1.0 / image.height());
0116     } else {
0117         d->m_scale.setWidth(1.0);
0118         d->m_scale.setHeight(1.0);
0119     }
0120 
0121     d->m_size = image.size();
0122     d->m_yInverted = true;
0123     d->m_canUseMipmaps = false;
0124     d->m_mipLevels = 1;
0125 
0126     d->updateMatrix();
0127 
0128     const bool created = create();
0129     Q_ASSERT(created);
0130     bind();
0131 
0132     if (!GLPlatform::instance()->isGLES()) {
0133         QImage im;
0134         GLenum internalFormat;
0135         GLenum format;
0136         GLenum type;
0137 
0138         const QImage::Format index = image.format();
0139 
0140         if (index < sizeof(formatTable) / sizeof(formatTable[0]) && formatTable[index].internalFormat
0141             && !(formatTable[index].type == GL_UNSIGNED_SHORT && !d->s_supportsTexture16Bit)) {
0142             internalFormat = formatTable[index].internalFormat;
0143             format = formatTable[index].format;
0144             type = formatTable[index].type;
0145             im = image;
0146         } else {
0147             im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
0148             internalFormat = GL_RGBA8;
0149             format = GL_BGRA;
0150             type = GL_UNSIGNED_INT_8_8_8_8_REV;
0151         }
0152 
0153         d->m_internalFormat = internalFormat;
0154 
0155         if (d->s_supportsTextureStorage) {
0156             glTexStorage2D(d->m_target, 1, internalFormat, im.width(), im.height());
0157             glTexSubImage2D(d->m_target, 0, 0, 0, im.width(), im.height(),
0158                             format, type, im.constBits());
0159             d->m_immutable = true;
0160         } else {
0161             glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, d->m_mipLevels - 1);
0162             glTexImage2D(d->m_target, 0, internalFormat, im.width(), im.height(), 0,
0163                          format, type, im.constBits());
0164         }
0165     } else {
0166         d->m_internalFormat = GL_RGBA8;
0167 
0168         if (d->s_supportsARGB32) {
0169             const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
0170             glTexImage2D(d->m_target, 0, GL_BGRA_EXT, im.width(), im.height(),
0171                          0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.constBits());
0172         } else {
0173             const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
0174             glTexImage2D(d->m_target, 0, GL_RGBA, im.width(), im.height(),
0175                          0, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
0176         }
0177     }
0178 
0179     unbind();
0180     setFilter(GL_LINEAR);
0181 }
0182 
0183 GLTexture::GLTexture(const QPixmap &pixmap, GLenum target)
0184     : GLTexture(pixmap.toImage(), target)
0185 {
0186 }
0187 
0188 GLTexture::GLTexture(const QString &fileName)
0189     : GLTexture(QImage(fileName))
0190 {
0191 }
0192 
0193 GLTexture::GLTexture(GLenum internalFormat, int width, int height, int levels, bool needsMutability)
0194     : d_ptr(new GLTexturePrivate())
0195 {
0196     Q_D(GLTexture);
0197 
0198     d->m_target = GL_TEXTURE_2D;
0199     d->m_scale.setWidth(1.0 / width);
0200     d->m_scale.setHeight(1.0 / height);
0201     d->m_size = QSize(width, height);
0202     d->m_canUseMipmaps = levels > 1;
0203     d->m_mipLevels = levels;
0204     d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
0205 
0206     d->updateMatrix();
0207 
0208     create();
0209     bind();
0210 
0211     if (!GLPlatform::instance()->isGLES()) {
0212         if (d->s_supportsTextureStorage && !needsMutability) {
0213             glTexStorage2D(d->m_target, levels, internalFormat, width, height);
0214             d->m_immutable = true;
0215         } else {
0216             glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, levels - 1);
0217             glTexImage2D(d->m_target, 0, internalFormat, width, height, 0,
0218                          GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
0219         }
0220         d->m_internalFormat = internalFormat;
0221     } else {
0222         // The format parameter in glTexSubImage() must match the internal format
0223         // of the texture, so it's important that we allocate the texture with
0224         // the format that will be used in update() and clear().
0225         const GLenum format = d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
0226         glTexImage2D(d->m_target, 0, format, width, height, 0,
0227                      format, GL_UNSIGNED_BYTE, nullptr);
0228 
0229         // This is technically not true, but it means that code that calls
0230         // internalFormat() won't need to be specialized for GLES2.
0231         d->m_internalFormat = GL_RGBA8;
0232     }
0233 
0234     unbind();
0235 }
0236 
0237 GLTexture::GLTexture(GLenum internalFormat, const QSize &size, int levels, bool needsMutability)
0238     : GLTexture(internalFormat, size.width(), size.height(), levels, needsMutability)
0239 {
0240 }
0241 
0242 GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels)
0243     : d_ptr(new GLTexturePrivate())
0244 {
0245     Q_D(GLTexture);
0246     d->m_foreign = true;
0247     d->m_texture = textureId;
0248     d->m_target = GL_TEXTURE_2D;
0249     d->m_scale.setWidth(1.0 / size.width());
0250     d->m_scale.setHeight(1.0 / size.height());
0251     d->m_size = size;
0252     d->m_canUseMipmaps = levels > 1;
0253     d->m_mipLevels = levels;
0254     d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
0255     d->m_internalFormat = internalFormat;
0256 
0257     d->updateMatrix();
0258 }
0259 
0260 GLTexture::~GLTexture()
0261 {
0262 }
0263 
0264 bool GLTexture::create()
0265 {
0266     Q_D(GLTexture);
0267     if (!isNull()) {
0268         return true;
0269     }
0270     glGenTextures(1, &d->m_texture);
0271     return d->m_texture != GL_NONE;
0272 }
0273 
0274 GLTexture &GLTexture::operator=(const GLTexture &tex)
0275 {
0276     d_ptr = tex.d_ptr;
0277     return *this;
0278 }
0279 
0280 GLTexturePrivate::GLTexturePrivate()
0281     : m_texture(0)
0282     , m_target(0)
0283     , m_internalFormat(0)
0284     , m_filter(GL_NEAREST)
0285     , m_wrapMode(GL_REPEAT)
0286     , m_yInverted(false)
0287     , m_canUseMipmaps(false)
0288     , m_markedDirty(false)
0289     , m_filterChanged(true)
0290     , m_wrapModeChanged(false)
0291     , m_immutable(false)
0292     , m_foreign(false)
0293     , m_mipLevels(1)
0294     , m_unnormalizeActive(0)
0295     , m_normalizeActive(0)
0296 {
0297 }
0298 
0299 GLTexturePrivate::~GLTexturePrivate()
0300 {
0301     if (m_texture != 0 && !m_foreign) {
0302         glDeleteTextures(1, &m_texture);
0303     }
0304 }
0305 
0306 void GLTexturePrivate::initStatic()
0307 {
0308     if (!GLPlatform::instance()->isGLES()) {
0309         s_supportsFramebufferObjects = hasGLVersion(3, 0) || hasGLExtension("GL_ARB_framebuffer_object") || hasGLExtension(QByteArrayLiteral("GL_EXT_framebuffer_object"));
0310         s_supportsTextureStorage = hasGLVersion(4, 2) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_storage"));
0311         s_supportsTextureSwizzle = hasGLVersion(3, 3) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_swizzle"));
0312         // see https://www.opengl.org/registry/specs/ARB/texture_rg.txt
0313         s_supportsTextureFormatRG = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_rg"));
0314         s_supportsTexture16Bit = true;
0315         s_supportsARGB32 = true;
0316         s_supportsUnpack = true;
0317     } else {
0318         s_supportsFramebufferObjects = true;
0319         s_supportsTextureStorage = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_texture_storage"));
0320         s_supportsTextureSwizzle = hasGLVersion(3, 0);
0321         // see https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_rg.txt
0322         s_supportsTextureFormatRG = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_texture_rg"));
0323         s_supportsTexture16Bit = hasGLExtension(QByteArrayLiteral("GL_EXT_texture_norm16"));
0324 
0325         // QImage::Format_ARGB32_Premultiplied is a packed-pixel format, so it's only
0326         // equivalent to GL_BGRA/GL_UNSIGNED_BYTE on little-endian systems.
0327         s_supportsARGB32 = QSysInfo::ByteOrder == QSysInfo::LittleEndian && hasGLExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"));
0328 
0329         s_supportsUnpack = hasGLExtension(QByteArrayLiteral("GL_EXT_unpack_subimage"));
0330     }
0331 }
0332 
0333 void GLTexturePrivate::cleanup()
0334 {
0335     s_supportsFramebufferObjects = false;
0336     s_supportsARGB32 = false;
0337     if (s_fbo) {
0338         glDeleteFramebuffers(1, &s_fbo);
0339         s_fbo = 0;
0340     }
0341 }
0342 
0343 bool GLTexture::isNull() const
0344 {
0345     Q_D(const GLTexture);
0346     return GL_NONE == d->m_texture;
0347 }
0348 
0349 QSize GLTexture::size() const
0350 {
0351     Q_D(const GLTexture);
0352     return d->m_size;
0353 }
0354 
0355 void GLTexture::setSize(const QSize &size)
0356 {
0357     Q_D(GLTexture);
0358     if (!isNull()) {
0359         return;
0360     }
0361     d->m_size = size;
0362     d->updateMatrix();
0363 }
0364 
0365 void GLTexture::update(const QImage &image, const QPoint &offset, const QRect &src)
0366 {
0367     if (image.isNull() || isNull()) {
0368         return;
0369     }
0370 
0371     Q_D(GLTexture);
0372     Q_ASSERT(!d->m_foreign);
0373 
0374     GLenum glFormat;
0375     GLenum type;
0376     QImage::Format uploadFormat;
0377     if (!GLPlatform::instance()->isGLES()) {
0378         const QImage::Format index = image.format();
0379 
0380         if (index < sizeof(formatTable) / sizeof(formatTable[0]) && formatTable[index].internalFormat
0381             && !(formatTable[index].type == GL_UNSIGNED_SHORT && !d->s_supportsTexture16Bit)) {
0382             glFormat = formatTable[index].format;
0383             type = formatTable[index].type;
0384             uploadFormat = index;
0385         } else {
0386             glFormat = GL_BGRA;
0387             type = GL_UNSIGNED_INT_8_8_8_8_REV;
0388             uploadFormat = QImage::Format_ARGB32_Premultiplied;
0389         }
0390     } else {
0391         if (d->s_supportsARGB32) {
0392             glFormat = GL_BGRA_EXT;
0393             type = GL_UNSIGNED_BYTE;
0394             uploadFormat = QImage::Format_ARGB32_Premultiplied;
0395         } else {
0396             glFormat = GL_RGBA;
0397             type = GL_UNSIGNED_BYTE;
0398             uploadFormat = QImage::Format_RGBA8888_Premultiplied;
0399         }
0400     }
0401     bool useUnpack = d->s_supportsUnpack && image.format() == uploadFormat && !src.isNull();
0402 
0403     QImage im;
0404     if (useUnpack) {
0405         im = image;
0406         Q_ASSERT(im.depth() % 8 == 0);
0407         glPixelStorei(GL_UNPACK_ROW_LENGTH, im.bytesPerLine() / (im.depth() / 8));
0408         glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.x());
0409         glPixelStorei(GL_UNPACK_SKIP_ROWS, src.y());
0410     } else {
0411         if (src.isNull()) {
0412             im = image;
0413         } else {
0414             im = image.copy(src);
0415         }
0416         if (im.format() != uploadFormat) {
0417             im.convertTo(uploadFormat);
0418         }
0419     }
0420 
0421     int width = image.width();
0422     int height = image.height();
0423     if (!src.isNull()) {
0424         width = src.width();
0425         height = src.height();
0426     }
0427 
0428     bind();
0429 
0430     glTexSubImage2D(d->m_target, 0, offset.x(), offset.y(), width, height, glFormat, type, im.constBits());
0431 
0432     unbind();
0433 
0434     if (useUnpack) {
0435         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
0436         glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
0437         glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
0438     }
0439 }
0440 
0441 void GLTexture::discard()
0442 {
0443     d_ptr = new GLTexturePrivate();
0444 }
0445 
0446 void GLTexture::bind()
0447 {
0448     Q_D(GLTexture);
0449     Q_ASSERT(d->m_texture);
0450 
0451     glBindTexture(d->m_target, d->m_texture);
0452 
0453     if (d->m_markedDirty) {
0454         d->onDamage();
0455     }
0456     if (d->m_filterChanged) {
0457         GLenum minFilter = GL_NEAREST;
0458         GLenum magFilter = GL_NEAREST;
0459 
0460         switch (d->m_filter) {
0461         case GL_NEAREST:
0462             minFilter = magFilter = GL_NEAREST;
0463             break;
0464 
0465         case GL_LINEAR:
0466             minFilter = magFilter = GL_LINEAR;
0467             break;
0468 
0469         case GL_NEAREST_MIPMAP_NEAREST:
0470         case GL_NEAREST_MIPMAP_LINEAR:
0471             magFilter = GL_NEAREST;
0472             minFilter = d->m_canUseMipmaps ? d->m_filter : GL_NEAREST;
0473             break;
0474 
0475         case GL_LINEAR_MIPMAP_NEAREST:
0476         case GL_LINEAR_MIPMAP_LINEAR:
0477             magFilter = GL_LINEAR;
0478             minFilter = d->m_canUseMipmaps ? d->m_filter : GL_LINEAR;
0479             break;
0480         }
0481 
0482         glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, minFilter);
0483         glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, magFilter);
0484 
0485         d->m_filterChanged = false;
0486     }
0487     if (d->m_wrapModeChanged) {
0488         glTexParameteri(d->m_target, GL_TEXTURE_WRAP_S, d->m_wrapMode);
0489         glTexParameteri(d->m_target, GL_TEXTURE_WRAP_T, d->m_wrapMode);
0490         d->m_wrapModeChanged = false;
0491     }
0492 }
0493 
0494 void GLTexture::generateMipmaps()
0495 {
0496     Q_D(GLTexture);
0497 
0498     if (d->m_canUseMipmaps && d->s_supportsFramebufferObjects) {
0499         glGenerateMipmap(d->m_target);
0500     }
0501 }
0502 
0503 void GLTexture::unbind()
0504 {
0505     Q_D(GLTexture);
0506     glBindTexture(d->m_target, 0);
0507 }
0508 
0509 void GLTexture::render(const QRect &rect, qreal scale)
0510 {
0511     render(infiniteRegion(), rect, scale, false);
0512 }
0513 
0514 void GLTexture::render(const QRegion &region, const QRect &rect, qreal scale, bool hardwareClipping)
0515 {
0516     Q_D(GLTexture);
0517     if (rect.isEmpty()) {
0518         return; // nothing to paint and m_vbo is likely nullptr and d->m_cachedSize empty as well, #337090
0519     }
0520 
0521     QRect destinationRect = scaledRect(rect, scale).toRect();
0522     if (destinationRect.size() != d->m_cachedSize) {
0523         d->m_cachedSize = destinationRect.size();
0524         QRect r(destinationRect);
0525         r.moveTo(0, 0);
0526         if (!d->m_vbo) {
0527             d->m_vbo = std::make_unique<GLVertexBuffer>(KWin::GLVertexBuffer::Static);
0528         }
0529 
0530         const float verts[4 * 2] = {
0531             // NOTICE: r.x/y could be replaced by "0", but that would make it unreadable...
0532             static_cast<float>(r.x()), static_cast<float>(r.y()),
0533             static_cast<float>(r.x()), static_cast<float>(r.y() + destinationRect.height()),
0534             static_cast<float>(r.x() + destinationRect.width()), static_cast<float>(r.y()),
0535             static_cast<float>(r.x() + destinationRect.width()), static_cast<float>(r.y() + destinationRect.height())};
0536 
0537         const float texWidth = (target() == GL_TEXTURE_RECTANGLE_ARB) ? width() : 1.0f;
0538         const float texHeight = (target() == GL_TEXTURE_RECTANGLE_ARB) ? height() : 1.0f;
0539 
0540         const float texcoords[4 * 2] = {
0541             0.0f, d->m_yInverted ? 0.0f : texHeight, // y needs to be swapped (normalized coords)
0542             0.0f, d->m_yInverted ? texHeight : 0.0f,
0543             texWidth, d->m_yInverted ? 0.0f : texHeight,
0544             texWidth, d->m_yInverted ? texHeight : 0.0f};
0545 
0546         d->m_vbo->setData(4, 2, verts, texcoords);
0547     }
0548     d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping);
0549 }
0550 
0551 GLuint GLTexture::texture() const
0552 {
0553     Q_D(const GLTexture);
0554     return d->m_texture;
0555 }
0556 
0557 GLenum GLTexture::target() const
0558 {
0559     Q_D(const GLTexture);
0560     return d->m_target;
0561 }
0562 
0563 GLenum GLTexture::filter() const
0564 {
0565     Q_D(const GLTexture);
0566     return d->m_filter;
0567 }
0568 
0569 GLenum GLTexture::internalFormat() const
0570 {
0571     Q_D(const GLTexture);
0572     return d->m_internalFormat;
0573 }
0574 
0575 void GLTexture::clear()
0576 {
0577     Q_D(GLTexture);
0578     Q_ASSERT(!d->m_foreign);
0579     if (!GLTexturePrivate::s_fbo && GLFramebuffer::supported() && GLPlatform::instance()->driver() != Driver_Catalyst) { // fail. -> bug #323065
0580         glGenFramebuffers(1, &GLTexturePrivate::s_fbo);
0581     }
0582 
0583     if (GLTexturePrivate::s_fbo) {
0584         // Clear the texture
0585         GLuint previousFramebuffer = 0;
0586         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast<GLint *>(&previousFramebuffer));
0587         if (GLTexturePrivate::s_fbo != previousFramebuffer) {
0588             glBindFramebuffer(GL_FRAMEBUFFER, GLTexturePrivate::s_fbo);
0589         }
0590         glClearColor(0, 0, 0, 0);
0591         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, d->m_texture, 0);
0592         glClear(GL_COLOR_BUFFER_BIT);
0593         if (GLTexturePrivate::s_fbo != previousFramebuffer) {
0594             glBindFramebuffer(GL_FRAMEBUFFER, previousFramebuffer);
0595         }
0596     } else {
0597         if (const int size = width() * height()) {
0598             std::vector<uint32_t> buffer(size, 0);
0599             bind();
0600             if (!GLPlatform::instance()->isGLES()) {
0601                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(),
0602                                 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer.data());
0603             } else {
0604                 const GLenum format = d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
0605                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(),
0606                                 format, GL_UNSIGNED_BYTE, buffer.data());
0607             }
0608             unbind();
0609         }
0610     }
0611 }
0612 
0613 bool GLTexture::isDirty() const
0614 {
0615     Q_D(const GLTexture);
0616     return d->m_markedDirty;
0617 }
0618 
0619 void GLTexture::setFilter(GLenum filter)
0620 {
0621     Q_D(GLTexture);
0622     if (filter != d->m_filter) {
0623         d->m_filter = filter;
0624         d->m_filterChanged = true;
0625     }
0626 }
0627 
0628 void GLTexture::setWrapMode(GLenum mode)
0629 {
0630     Q_D(GLTexture);
0631     if (mode != d->m_wrapMode) {
0632         d->m_wrapMode = mode;
0633         d->m_wrapModeChanged = true;
0634     }
0635 }
0636 
0637 void GLTexturePrivate::onDamage()
0638 {
0639     // No-op
0640 }
0641 
0642 void GLTexture::setDirty()
0643 {
0644     Q_D(GLTexture);
0645     d->m_markedDirty = true;
0646 }
0647 
0648 void GLTexturePrivate::updateMatrix()
0649 {
0650     m_matrix[NormalizedCoordinates].setToIdentity();
0651     m_matrix[UnnormalizedCoordinates].setToIdentity();
0652 
0653     if (m_target == GL_TEXTURE_RECTANGLE_ARB) {
0654         m_matrix[NormalizedCoordinates].scale(m_size.width(), m_size.height());
0655     } else {
0656         m_matrix[UnnormalizedCoordinates].scale(1.0 / m_size.width(), 1.0 / m_size.height());
0657     }
0658 
0659     if (!m_yInverted) {
0660         m_matrix[NormalizedCoordinates].translate(0.0, 1.0);
0661         m_matrix[NormalizedCoordinates].scale(1.0, -1.0);
0662 
0663         m_matrix[UnnormalizedCoordinates].translate(0.0, m_size.height());
0664         m_matrix[UnnormalizedCoordinates].scale(1.0, -1.0);
0665     }
0666 }
0667 
0668 bool GLTexture::isYInverted() const
0669 {
0670     Q_D(const GLTexture);
0671     return d->m_yInverted;
0672 }
0673 
0674 void GLTexture::setYInverted(bool inverted)
0675 {
0676     Q_D(GLTexture);
0677     if (d->m_yInverted == inverted) {
0678         return;
0679     }
0680 
0681     d->m_yInverted = inverted;
0682     d->updateMatrix();
0683 }
0684 
0685 void GLTexture::setSwizzle(GLenum red, GLenum green, GLenum blue, GLenum alpha)
0686 {
0687     Q_D(GLTexture);
0688 
0689     if (!GLPlatform::instance()->isGLES()) {
0690         const GLuint swizzle[] = {red, green, blue, alpha};
0691         glTexParameteriv(d->m_target, GL_TEXTURE_SWIZZLE_RGBA, (const GLint *)swizzle);
0692     } else {
0693         glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_R, red);
0694         glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_G, green);
0695         glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_B, blue);
0696         glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_A, alpha);
0697     }
0698 }
0699 
0700 int GLTexture::width() const
0701 {
0702     Q_D(const GLTexture);
0703     return d->m_size.width();
0704 }
0705 
0706 int GLTexture::height() const
0707 {
0708     Q_D(const GLTexture);
0709     return d->m_size.height();
0710 }
0711 
0712 QMatrix4x4 GLTexture::matrix(TextureCoordinateType type) const
0713 {
0714     Q_D(const GLTexture);
0715     return d->m_matrix[type];
0716 }
0717 
0718 bool GLTexture::framebufferObjectSupported()
0719 {
0720     return GLTexturePrivate::s_supportsFramebufferObjects;
0721 }
0722 
0723 bool GLTexture::supportsSwizzle()
0724 {
0725     return GLTexturePrivate::s_supportsTextureSwizzle;
0726 }
0727 
0728 bool GLTexture::supportsFormatRG()
0729 {
0730     return GLTexturePrivate::s_supportsTextureFormatRG;
0731 }
0732 
0733 QImage GLTexture::toImage() const
0734 {
0735     if (target() != GL_TEXTURE_2D) {
0736         return QImage();
0737     }
0738     QImage ret(size(), QImage::Format_RGBA8888_Premultiplied);
0739 
0740     GLint currentTextureBinding;
0741     glGetIntegerv(GL_TEXTURE_BINDING_2D, &currentTextureBinding);
0742 
0743     if (GLuint(currentTextureBinding) != texture()) {
0744         glBindTexture(GL_TEXTURE_2D, texture());
0745     }
0746     glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ret.bits());
0747     if (GLuint(currentTextureBinding) != texture()) {
0748         glBindTexture(GL_TEXTURE_2D, currentTextureBinding);
0749     }
0750     return ret;
0751 }
0752 
0753 } // namespace KWin