diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp index 3818fe242..7ba5c8642 100644 --- a/libkwineffects/kwingltexture.cpp +++ b/libkwineffects/kwingltexture.cpp @@ -1,658 +1,679 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin Copyright (C) 2012 Philipp Knechtges 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 . *********************************************************************/ #include "kwinconfig.h" // KWIN_HAVE_OPENGL #include "kwinglplatform.h" #include "kwinglutils_funcs.h" #include "kwinglutils.h" #include "kwingltexture_p.h" #include #include #include #include #include #include namespace KWin { //**************************************** // GLTexture //**************************************** bool GLTexturePrivate::s_supportsFramebufferObjects = false; bool GLTexturePrivate::s_supportsARGB32 = false; bool GLTexturePrivate::s_supportsUnpack = false; bool GLTexturePrivate::s_supportsTextureStorage = false; bool GLTexturePrivate::s_supportsTextureSwizzle = false; bool GLTexturePrivate::s_supportsTextureFormatRG = false; uint GLTexturePrivate::s_textureObjectCounter = 0; uint GLTexturePrivate::s_fbo = 0; GLTexture::GLTexture() : d_ptr(new GLTexturePrivate()) { } GLTexture::GLTexture(GLTexturePrivate& dd) : d_ptr(&dd) { } GLTexture::GLTexture(const GLTexture& tex) : d_ptr(tex.d_ptr) { } GLTexture::GLTexture(const QImage& image, GLenum target) : d_ptr(new GLTexturePrivate()) { 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; d->m_canUseMipmaps = false; d->m_mipLevels = 1; d->updateMatrix(); glGenTextures(1, &d->m_texture); bind(); if (!GLPlatform::instance()->isGLES()) { // Note: Blending is set up to expect premultiplied data, so non-premultiplied // formats must always be converted. struct { GLenum internalFormat; GLenum format; GLenum type; } static const table[] = { { 0, 0, 0 }, // QImage::Format_Invalid { 0, 0, 0 }, // QImage::Format_Mono { 0, 0, 0 }, // QImage::Format_MonoLSB { GL_R8, GL_RED, GL_UNSIGNED_BYTE }, // QImage::Format_Indexed8 { GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV }, // QImage::Format_RGB32 { 0, 0, 0 }, // QImage::Format_ARGB32 { GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV }, // QImage::Format_ARGB32_Premultiplied { GL_RGB8, GL_BGR, GL_UNSIGNED_SHORT_5_6_5_REV }, // QImage::Format_RGB16 { 0, 0, 0 }, // QImage::Format_ARGB8565_Premultiplied { 0, 0, 0 }, // QImage::Format_RGB666 { 0, 0, 0 }, // QImage::Format_ARGB6666_Premultiplied { GL_RGB5, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV }, // QImage::Format_RGB555 { 0, 0, 0 }, // QImage::Format_ARGB8555_Premultiplied { GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE }, // QImage::Format_RGB888 { GL_RGB4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV }, // QImage::Format_RGB444 { GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV }, // QImage::Format_ARGB4444_Premultiplied { GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE }, // QImage::Format_RGBX8888 { 0, 0, 0 }, // QImage::Format_RGBA8888 { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, // QImage::Format_RGBA8888_Premultiplied { GL_RGB10, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV }, // QImage::Format_BGR30 { GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV }, // QImage::Format_A2BGR30_Premultiplied { GL_RGB10, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV }, // QImage::Format_RGB30 { GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV }, // QImage::Format_A2RGB30_Premultiplied { GL_R8, GL_RED, GL_UNSIGNED_BYTE }, // QImage::Format_Alpha8 { GL_R8, GL_RED, GL_UNSIGNED_BYTE }, // QImage::Format_Grayscale8 }; QImage im; GLenum internalFormat; GLenum format; GLenum type; const QImage::Format index = image.format(); if (index < sizeof(table) / sizeof(table[0]) && table[index].internalFormat && !(index == QImage::Format_Indexed8 && image.colorCount() > 0)) { internalFormat = table[index].internalFormat; format = table[index].format; type = table[index].type; im = image; } else { im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); internalFormat = GL_RGBA8; format = GL_BGRA; type = GL_UNSIGNED_INT_8_8_8_8_REV; } d->m_internalFormat = internalFormat; if (d->s_supportsTextureStorage) { glTexStorage2D(d->m_target, 1, internalFormat, im.width(), im.height()); glTexSubImage2D(d->m_target, 0, 0, 0, im.width(), im.height(), format, type, im.bits()); d->m_immutable = true; } else { glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, d->m_mipLevels - 1); glTexImage2D(d->m_target, 0, internalFormat, im.width(), im.height(), 0, format, type, im.bits()); } } else { d->m_internalFormat = GL_RGBA8; 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); } GLTexture::GLTexture(const QPixmap& pixmap, GLenum target) : GLTexture(pixmap.toImage(), target) { } GLTexture::GLTexture(const QString& fileName) : GLTexture(QImage(fileName)) { } GLTexture::GLTexture(GLenum internalFormat, int width, int height, int levels) : d_ptr(new GLTexturePrivate()) { Q_D(GLTexture); 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); d->m_canUseMipmaps = levels > 1; d->m_mipLevels = levels; d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; d->updateMatrix(); glGenTextures(1, &d->m_texture); bind(); if (!GLPlatform::instance()->isGLES()) { if (d->s_supportsTextureStorage) { glTexStorage2D(d->m_target, levels, internalFormat, width, height); d->m_immutable = true; } else { glTexParameteri(d->m_target, GL_TEXTURE_MAX_LEVEL, levels - 1); glTexImage2D(d->m_target, 0, internalFormat, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr); } d->m_internalFormat = internalFormat; } else { // 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); // This is technically not true, but it means that code that calls // internalFormat() won't need to be specialized for GLES2. d->m_internalFormat = GL_RGBA8; } unbind(); } GLTexture::GLTexture(GLenum internalFormat, const QSize &size, int levels) : GLTexture(internalFormat, size.width(), size.height(), levels) { } +GLTexture::GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels) + : d_ptr(new GLTexturePrivate()) +{ + Q_D(GLTexture); + d->m_foreign = true; + d->m_texture = textureId; + d->m_target = GL_TEXTURE_2D; + d->m_scale.setWidth(1.0 / size.width()); + d->m_scale.setHeight(1.0 / size.height()); + d->m_size = size; + d->m_canUseMipmaps = levels > 1; + d->m_mipLevels = levels; + d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST; + d->m_internalFormat = internalFormat; + + d->updateMatrix(); +} + GLTexture::~GLTexture() { } GLTexture& GLTexture::operator = (const GLTexture& tex) { d_ptr = tex.d_ptr; return *this; } GLTexturePrivate::GLTexturePrivate() : m_texture(0) , m_target(0) , m_internalFormat(0) , m_filter(GL_NEAREST) , m_wrapMode(GL_REPEAT) , m_yInverted(false) , m_canUseMipmaps(false) , m_markedDirty(false) , m_filterChanged(true) , m_wrapModeChanged(false) , m_immutable(false) + , m_foreign(false) , m_mipLevels(1) , m_unnormalizeActive(0) , m_normalizeActive(0) , m_vbo(nullptr) { ++s_textureObjectCounter; } GLTexturePrivate::~GLTexturePrivate() { delete m_vbo; - if (m_texture != 0) { + if (m_texture != 0 && !m_foreign) { 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() { if (!GLPlatform::instance()->isGLES()) { s_supportsFramebufferObjects = hasGLVersion(3, 0) || hasGLExtension("GL_ARB_framebuffer_object") || hasGLExtension(QByteArrayLiteral("GL_EXT_framebuffer_object")); s_supportsTextureStorage = hasGLVersion(4, 2) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_storage")); s_supportsTextureSwizzle = hasGLVersion(3, 3) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_swizzle")); // see https://www.opengl.org/registry/specs/ARB/texture_rg.txt s_supportsTextureFormatRG = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_ARB_texture_rg")); s_supportsARGB32 = true; s_supportsUnpack = true; } else { s_supportsFramebufferObjects = true; s_supportsTextureStorage = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_texture_storage")); s_supportsTextureSwizzle = hasGLVersion(3, 0); // see https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_rg.txt s_supportsTextureFormatRG = hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_texture_rg")); // 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")); s_supportsUnpack = hasGLExtension(QByteArrayLiteral("GL_EXT_unpack_subimage")); } } void GLTexturePrivate::cleanup() { s_supportsFramebufferObjects = false; s_supportsARGB32 = false; } bool GLTexture::isNull() const { Q_D(const GLTexture); return GL_NONE == d->m_texture; } QSize GLTexture::size() const { Q_D(const GLTexture); return d->m_size; } void GLTexture::update(const QImage &image, const QPoint &offset, const QRect &src) { if (image.isNull() || isNull()) return; Q_D(GLTexture); + Q_ASSERT(!d->m_foreign); bool useUnpack = !src.isNull() && d->s_supportsUnpack && d->s_supportsARGB32 && image.format() == QImage::Format_ARGB32_Premultiplied; int width = image.width(); int height = image.height(); QImage tmpImage; if (!src.isNull()) { if (useUnpack) { 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(); } const QImage &img = tmpImage.isNull() ? image : tmpImage; bind(); 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()); } } unbind(); if (useUnpack) { glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } } void GLTexture::discard() { d_ptr = new GLTexturePrivate(); } void GLTexture::bind() { Q_D(GLTexture); glBindTexture(d->m_target, d->m_texture); if (d->m_markedDirty) { d->onDamage(); } if (d->m_filterChanged) { 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; } glTexParameteri(d->m_target, GL_TEXTURE_MIN_FILTER, minFilter); glTexParameteri(d->m_target, GL_TEXTURE_MAG_FILTER, magFilter); d->m_filterChanged = false; } 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); d->m_wrapModeChanged = false; } } void GLTexture::generateMipmaps() { Q_D(GLTexture); if (d->m_canUseMipmaps && d->s_supportsFramebufferObjects) glGenerateMipmap(d->m_target); } void GLTexture::unbind() { Q_D(GLTexture); glBindTexture(d->m_target, 0); } void GLTexture::render(QRegion region, const QRect& rect, bool hardwareClipping) { Q_D(GLTexture); if (rect.isEmpty()) return; // nothing to paint and m_vbo is likely nullptr and d->m_cachedSize empty as well, #337090 if (rect.size() != d->m_cachedSize) { d->m_cachedSize = rect.size(); QRect r(rect); r.moveTo(0, 0); if (!d->m_vbo) { d->m_vbo = new GLVertexBuffer(KWin::GLVertexBuffer::Static); } const float verts[ 4 * 2 ] = { // NOTICE: r.x/y could be replaced by "0", but that would make it unreadable... static_cast(r.x()), static_cast(r.y()), static_cast(r.x()), static_cast(r.y() + rect.height()), static_cast(r.x() + rect.width()), static_cast(r.y()), static_cast(r.x() + rect.width()), static_cast(r.y() + rect.height()) }; const float texWidth = (target() == GL_TEXTURE_RECTANGLE_ARB) ? width() : 1.0f; const float texHeight = (target() == GL_TEXTURE_RECTANGLE_ARB) ? height() : 1.0f; const float texcoords[ 4 * 2 ] = { 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 }; d->m_vbo->setData(4, 2, verts, texcoords); } d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping); } GLuint GLTexture::texture() const { Q_D(const GLTexture); return d->m_texture; } GLenum GLTexture::target() const { Q_D(const GLTexture); return d->m_target; } GLenum GLTexture::filter() const { Q_D(const GLTexture); return d->m_filter; } GLenum GLTexture::internalFormat() const { Q_D(const GLTexture); return d->m_internalFormat; } void GLTexture::clear() { Q_D(GLTexture); + Q_ASSERT(!d->m_foreign); 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(); 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); } unbind(); delete[] buffer; } } } bool GLTexture::isDirty() const { Q_D(const GLTexture); return d->m_markedDirty; } void GLTexture::setFilter(GLenum filter) { Q_D(GLTexture); if (filter != d->m_filter) { d->m_filter = filter; d->m_filterChanged = true; } } void GLTexture::setWrapMode(GLenum mode) { Q_D(GLTexture); if (mode != d->m_wrapMode) { d->m_wrapMode = mode; d->m_wrapModeChanged=true; } } void GLTexturePrivate::onDamage() { // No-op } void GLTexture::setDirty() { Q_D(GLTexture); d->m_markedDirty = true; } 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); } } bool GLTexture::isYInverted() const { Q_D(const GLTexture); return d->m_yInverted; } void GLTexture::setYInverted(bool inverted) { Q_D(GLTexture); d->m_yInverted = inverted; d->updateMatrix(); } void GLTexture::setSwizzle(GLenum red, GLenum green, GLenum blue, GLenum alpha) { Q_D(GLTexture); if (!GLPlatform::instance()->isGLES()) { const GLuint swizzle[] = { red, green, blue, alpha }; glTexParameteriv(d->m_target, GL_TEXTURE_SWIZZLE_RGBA, (const GLint *) swizzle); } else { glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_R, red); glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_G, green); glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_B, blue); glTexParameteri(d->m_target, GL_TEXTURE_SWIZZLE_A, alpha); } } 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(); } QMatrix4x4 GLTexture::matrix(TextureCoordinateType type) const { Q_D(const GLTexture); return d->m_matrix[type]; } bool GLTexture::framebufferObjectSupported() { return GLTexturePrivate::s_supportsFramebufferObjects; } bool GLTexture::supportsSwizzle() { return GLTexturePrivate::s_supportsTextureSwizzle; } bool GLTexture::supportsFormatRG() { return GLTexturePrivate::s_supportsTextureFormatRG; } } // namespace KWin diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h index 98b409848..a4bd482a3 100644 --- a/libkwineffects/kwingltexture.h +++ b/libkwineffects/kwingltexture.h @@ -1,153 +1,160 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin 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 . *********************************************************************/ #ifndef KWIN_GLTEXTURE_H #define KWIN_GLTEXTURE_H #include #include #include #include #include #include #include class QImage; class QPixmap; /** @addtogroup kwineffects */ /** @{ */ namespace KWin { class GLVertexBuffer; class GLTexturePrivate; enum TextureCoordinateType { NormalizedCoordinates = 0, UnnormalizedCoordinates }; class KWINGLUTILS_EXPORT GLTexture { public: GLTexture(); GLTexture(const GLTexture& tex); explicit GLTexture(const QImage& image, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D); explicit GLTexture(const QString& fileName); GLTexture(GLenum internalFormat, int width, int height, int levels = 1); explicit GLTexture(GLenum internalFormat, const QSize &size, int levels = 1); + + /** + * Create a GLTexture wrapper around an existing texture. + * Management of the underlying texture remains the responsibility of the caller. + * @since 5.18 + */ + explicit GLTexture(GLuint textureId, GLenum internalFormat, const QSize &size, int levels = 1); virtual ~GLTexture(); GLTexture & operator = (const GLTexture& tex); bool isNull() const; QSize size() const; int width() const; int height() const; /** * @since 4.7 */ bool isYInverted() const; /** * @since 4.8 */ void setYInverted(bool inverted); /** * Specifies which component of a texel is placed in each respective * component of the vector returned to the shader. * * Valid values are GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ONE and GL_ZERO. * * @see swizzleSupported() * @since 5.2 */ void setSwizzle(GLenum red, GLenum green, GLenum blue, GLenum alpha); /** * Returns a matrix that transforms texture coordinates of the given type, * taking the texture target and the y-inversion flag into account. * * @since 4.11 */ QMatrix4x4 matrix(TextureCoordinateType type) const; void update(const QImage& image, const QPoint &offset = QPoint(0, 0), const QRect &src = QRect()); virtual void discard(); void bind(); void unbind(); void render(QRegion region, const QRect& rect, bool hardwareClipping = false); GLuint texture() const; GLenum target() const; GLenum filter() const; GLenum internalFormat() 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); void setDirty(); void generateMipmaps(); static bool framebufferObjectSupported(); /** * Returns true if texture swizzle is supported, and false otherwise * * Texture swizzle requires OpenGL 3.3, GL_ARB_texture_swizzle, or OpenGL ES 3.0. * * @since 5.2 */ static bool supportsSwizzle(); /** * Returns @c true if texture formats R* are supported, and @c false otherwise. * * This requires OpenGL 3.0, GL_ARB_texture_rg or OpenGL ES 3.0 or GL_EXT_texture_rg. * * @since 5.2.1 */ static bool supportsFormatRG(); protected: QExplicitlySharedDataPointer d_ptr; GLTexture(GLTexturePrivate& dd); private: Q_DECLARE_PRIVATE(GLTexture) }; } // namespace /** @} */ #endif diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltexture_p.h index 0eaca55b0..68d0847e0 100644 --- a/libkwineffects/kwingltexture_p.h +++ b/libkwineffects/kwingltexture_p.h @@ -1,91 +1,92 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2006-2007 Rivo Laks Copyright (C) 2010, 2011 Martin Gräßlin Copyright (C) 2011 Philipp Knechtges 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 . *********************************************************************/ #ifndef KWIN_GLTEXTURE_P_H #define KWIN_GLTEXTURE_P_H #include "kwinconfig.h" // KWIN_HAVE_OPENGL #include "kwinglutils.h" #include #include #include #include #include #include namespace KWin { // forward declarations class GLVertexBuffer; class KWINGLUTILS_EXPORT GLTexturePrivate : public QSharedData { public: GLTexturePrivate(); virtual ~GLTexturePrivate(); virtual void onDamage(); void updateMatrix(); GLuint m_texture; GLenum m_target; GLenum m_internalFormat; GLenum m_filter; GLenum m_wrapMode; QSize m_size; QSizeF m_scale; // to un-normalize GL_TEXTURE_2D QMatrix4x4 m_matrix[2]; bool m_yInverted; // texture is y-inverted bool m_canUseMipmaps; bool m_markedDirty; bool m_filterChanged; bool m_wrapModeChanged; bool m_immutable; + bool m_foreign; int m_mipLevels; int m_unnormalizeActive; // 0 - no, otherwise refcount int m_normalizeActive; // 0 - no, otherwise refcount GLVertexBuffer* m_vbo; QSize m_cachedSize; static void initStatic(); static bool s_supportsFramebufferObjects; static bool s_supportsARGB32; static bool s_supportsUnpack; static bool s_supportsTextureStorage; static bool s_supportsTextureSwizzle; static bool s_supportsTextureFormatRG; static GLuint s_fbo; static uint s_textureObjectCounter; private: friend void KWin::cleanupGL(); static void cleanup(); Q_DISABLE_COPY(GLTexturePrivate) }; } // namespace #endif