File indexing completed on 2025-03-23 11:13:58
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 ®ion, 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, ¤tTextureBinding); 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