56    {GL_RGB8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, 
 
   58    {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}, 
 
   59    {GL_RGB8, GL_BGR, GL_UNSIGNED_SHORT_5_6_5_REV}, 
 
   63    {GL_RGB5, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}, 
 
   65    {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, 
 
   66    {GL_RGB4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, 
 
   67    {GL_RGBA4, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV}, 
 
   68    {GL_RGB8, GL_RGBA, GL_UNSIGNED_BYTE}, 
 
   70    {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, 
 
   71    {GL_RGB10, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, 
 
   72    {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}, 
 
   73    {GL_RGB10, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV}, 
 
   74    {GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV}, 
 
   75    {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, 
 
   76    {GL_R8, GL_RED, GL_UNSIGNED_BYTE}, 
 
   77    {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, 
 
   79    {GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT}, 
 
   80    {GL_R16, GL_RED, GL_UNSIGNED_SHORT}, 
 
   94    d->m_texture = textureId;
 
   95    d->m_scale.setWidth(1.0 / 
size.width());
 
   96    d->m_scale.setHeight(1.0 / 
size.height());
 
   98    d->m_canUseMipmaps = levels > 1;
 
   99    d->m_mipLevels = levels;
 
  100    d->m_filter = levels > 1 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST;
 
  102    d->m_textureToBufferTransform = transform;
 
 
  116    glGenTextures(1, &
d->m_texture);
 
  117    return d->m_texture != GL_NONE;
 
 
  123    , m_internalFormat(0)
 
  124    , m_filter(GL_NEAREST)
 
  125    , m_wrapMode(GL_REPEAT)
 
  126    , m_canUseMipmaps(false)
 
  127    , m_markedDirty(false)
 
  128    , m_filterChanged(true)
 
  129    , m_wrapModeChanged(false)
 
  132    , m_unnormalizeActive(0)
 
  133    , m_normalizeActive(0)
 
 
  171void GLTexturePrivate::cleanup()
 
  176        glDeleteFramebuffers(1, &
s_fbo);
 
  183    return GL_NONE == 
d->m_texture;
 
 
  202    if (image.isNull() || 
isNull()) {
 
  206    Q_ASSERT(
d->m_owning);
 
  210    QImage::Format uploadFormat;
 
  212        const QImage::Format index = image.format();
 
  215            && !(
formatTable[index].
type == GL_UNSIGNED_SHORT && !
d->s_supportsTexture16Bit)) {
 
  218            uploadFormat = index;
 
  221            type = GL_UNSIGNED_INT_8_8_8_8_REV;
 
  222            uploadFormat = QImage::Format_ARGB32_Premultiplied;
 
  225        if (
d->s_supportsARGB32) {
 
  226            glFormat = GL_BGRA_EXT;
 
  227            type = GL_UNSIGNED_BYTE;
 
  228            uploadFormat = QImage::Format_ARGB32_Premultiplied;
 
  231            type = GL_UNSIGNED_BYTE;
 
  232            uploadFormat = QImage::Format_RGBA8888_Premultiplied;
 
  235    bool useUnpack = 
d->s_supportsUnpack && image.format() == uploadFormat && !src.isNull();
 
  240        Q_ASSERT(im.depth() % 8 == 0);
 
  241        glPixelStorei(GL_UNPACK_ROW_LENGTH, im.bytesPerLine() / (im.depth() / 8));
 
  242        glPixelStorei(GL_UNPACK_SKIP_PIXELS, src.x());
 
  243        glPixelStorei(GL_UNPACK_SKIP_ROWS, src.y());
 
  248            im = image.copy(src);
 
  250        if (im.format() != uploadFormat) {
 
  251            im.convertTo(uploadFormat);
 
  255    int width = image.width();
 
  256    int height = image.height();
 
  264    glTexSubImage2D(
d->m_target, 0, offset.x(), offset.y(), 
width, 
height, glFormat, 
type, im.constBits());
 
  269        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 
  270        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 
  271        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
 
 
  277    Q_ASSERT(
d->m_texture);
 
  279    glBindTexture(
d->m_target, 
d->m_texture);
 
  281    if (
d->m_markedDirty) {
 
  284    if (
d->m_filterChanged) {
 
  285        GLenum minFilter = GL_NEAREST;
 
  286        GLenum magFilter = GL_NEAREST;
 
  288        switch (
d->m_filter) {
 
  290            minFilter = magFilter = GL_NEAREST;
 
  294            minFilter = magFilter = GL_LINEAR;
 
  297        case GL_NEAREST_MIPMAP_NEAREST:
 
  298        case GL_NEAREST_MIPMAP_LINEAR:
 
  299            magFilter = GL_NEAREST;
 
  300            minFilter = 
d->m_canUseMipmaps ? 
d->m_filter : GL_NEAREST;
 
  303        case GL_LINEAR_MIPMAP_NEAREST:
 
  304        case GL_LINEAR_MIPMAP_LINEAR:
 
  305            magFilter = GL_LINEAR;
 
  306            minFilter = 
d->m_canUseMipmaps ? 
d->m_filter : GL_LINEAR;
 
  310        glTexParameteri(
d->m_target, GL_TEXTURE_MIN_FILTER, minFilter);
 
  311        glTexParameteri(
d->m_target, GL_TEXTURE_MAG_FILTER, magFilter);
 
  313        d->m_filterChanged = 
false;
 
  315    if (
d->m_wrapModeChanged) {
 
  316        glTexParameteri(
d->m_target, GL_TEXTURE_WRAP_S, 
d->m_wrapMode);
 
  317        glTexParameteri(
d->m_target, GL_TEXTURE_WRAP_T, 
d->m_wrapMode);
 
  318        d->m_wrapModeChanged = 
false;
 
 
  324    if (
d->m_canUseMipmaps && 
d->s_supportsFramebufferObjects) {
 
  325        glGenerateMipmap(
d->m_target);
 
 
  331    glBindTexture(
d->m_target, 0);
 
 
  341    const auto rotatedSize = 
d->m_textureToBufferTransform.map(
size());
 
  342    render(QRectF(QPoint(), rotatedSize), region, targetSize, hardwareClipping);
 
 
  345void GLTexture::render(
const QRectF &source, 
const QRegion ®ion, 
const QSizeF &targetSize, 
bool hardwareClipping)
 
  347    if (targetSize.isEmpty()) {
 
  351    const QSize destinationSize = targetSize.toSize(); 
 
  352    if (targetSize != 
d->m_cachedSize || 
d->m_cachedSource != source || 
d->m_cachedContentTransform != 
d->m_textureToBufferTransform) {
 
  353        d->m_cachedSize = destinationSize;
 
  354        d->m_cachedSource = source;
 
  355        d->m_cachedContentTransform = 
d->m_textureToBufferTransform;
 
  357        const float texWidth = (
target() == GL_TEXTURE_RECTANGLE_ARB) ? 
width() : 1.0f;
 
  358        const float texHeight = (
target() == GL_TEXTURE_RECTANGLE_ARB) ? 
height() : 1.0f;
 
  360        const QSize rotatedSize = 
d->m_textureToBufferTransform.map(
size());
 
  362        QMatrix4x4 textureMat;
 
  363        textureMat.translate(texWidth / 2, texHeight / 2);
 
  365        textureMat.scale(1, -1);
 
  366        textureMat *= 
d->m_textureToBufferTransform.toMatrix();
 
  367        textureMat.translate(-texWidth / 2, -texHeight / 2);
 
  368        textureMat.scale(texWidth / rotatedSize.width(), texHeight / rotatedSize.height());
 
  370        const QPointF p1 = textureMat.map(QPointF(source.x(), source.y()));
 
  371        const QPointF p2 = textureMat.map(QPointF(source.x(), source.y() + source.height()));
 
  372        const QPointF p3 = textureMat.map(QPointF(source.x() + source.width(), source.y()));
 
  373        const QPointF p4 = textureMat.map(QPointF(source.x() + source.width(), source.y() + source.height()));
 
  378        const std::array<GLVertex2D, 4> data{
 
  381                .texcoord = QVector2D(p1),
 
  384                .
position = QVector2D(0, destinationSize.height()),
 
  385                .texcoord = QVector2D(p2),
 
  388                .
position = QVector2D(destinationSize.width(), 0),
 
  389                .texcoord = QVector2D(p3),
 
  392                .
position = QVector2D(destinationSize.width(), destinationSize.height()),
 
  393                .texcoord = QVector2D(p4),
 
  396        d->m_vbo->setVertices(data);
 
  399    d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping);
 
 
  420    return d->m_internalFormat;
 
 
  425    Q_ASSERT(
d->m_owning);
 
  432        GLuint previousFramebuffer = 0;
 
  433        glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, 
reinterpret_cast<GLint *
>(&previousFramebuffer));
 
  437        glClearColor(0, 0, 0, 0);
 
  438        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 
d->m_texture, 0);
 
  439        glClear(GL_COLOR_BUFFER_BIT);
 
  441            glBindFramebuffer(GL_FRAMEBUFFER, previousFramebuffer);
 
  445            std::vector<uint32_t> buffer(
size, 0);
 
  448                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 
width(), 
height(),
 
  449                                GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer.data());
 
  451                const GLenum 
format = 
d->s_supportsARGB32 ? GL_BGRA_EXT : GL_RGBA;
 
  452                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 
width(), 
height(),
 
  453                                format, GL_UNSIGNED_BYTE, buffer.data());
 
 
  462    return d->m_markedDirty;
 
 
  469        d->m_filterChanged = 
true;
 
 
  475    if (mode != 
d->m_wrapMode) {
 
  476        d->m_wrapMode = mode;
 
  477        d->m_wrapModeChanged = 
true;
 
 
  483    d->m_markedDirty = 
true;
 
 
  497    if (
m_target == GL_TEXTURE_RECTANGLE_ARB) {
 
 
  517    if (
d->m_textureToBufferTransform != transform) {
 
  518        d->m_textureToBufferTransform = transform;
 
 
  525    return d->m_textureToBufferTransform;
 
 
  531        const GLuint swizzle[] = {red, green, blue, alpha};
 
  532        glTexParameteriv(
d->m_target, GL_TEXTURE_SWIZZLE_RGBA, (
const GLint *)swizzle);
 
  534        glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_R, red);
 
  535        glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_G, green);
 
  536        glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_B, blue);
 
  537        glTexParameteri(
d->m_target, GL_TEXTURE_SWIZZLE_A, alpha);
 
 
  543    return d->m_size.width();
 
 
  548    return d->m_size.height();
 
 
  553    return d->m_matrix[
type];
 
 
  573    if (
target() != GL_TEXTURE_2D) {
 
  576    QImage ret(
size(), QImage::Format_RGBA8888_Premultiplied);
 
  581        glReadPixels(0, 0, 
width(), 
height(), GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ret.bits());
 
  584        GLint currentTextureBinding;
 
  585        glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤tTextureBinding);
 
  586        if (GLuint(currentTextureBinding) != 
texture()) {
 
  587            glBindTexture(GL_TEXTURE_2D, 
texture());
 
  589        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ret.bits());
 
  590        if (GLuint(currentTextureBinding) != 
texture()) {
 
  591            glBindTexture(GL_TEXTURE_2D, currentTextureBinding);
 
 
  607        qCWarning(KWIN_OPENGL, 
"generating OpenGL texture handle failed");
 
  610    glBindTexture(GL_TEXTURE_2D, 
texture);
 
  616            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels - 1);
 
  618                         GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 
nullptr);
 
  625        glTexImage2D(GL_TEXTURE_2D, 0, 
format, 
size.width(), 
size.height(), 0,
 
  626                     format, GL_UNSIGNED_BYTE, 
nullptr);
 
  631    glBindTexture(GL_TEXTURE_2D, 0);
 
 
  637    if (image.isNull()) {
 
  643        qCWarning(KWIN_OPENGL, 
"generating OpenGL texture handle failed");
 
  646    glBindTexture(GL_TEXTURE_2D, 
texture);
 
  654        const QImage::Format index = image.format();
 
  663            im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
 
  666            type = GL_UNSIGNED_INT_8_8_8_8_REV;
 
  670            glTexStorage2D(GL_TEXTURE_2D, 1, 
internalFormat, im.width(), im.height());
 
  671            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, im.width(), im.height(),
 
  674            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
 
  675            glTexImage2D(GL_TEXTURE_2D, 0, 
internalFormat, im.width(), im.height(), 0,
 
  682            const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
 
  683            glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, im.width(), im.height(),
 
  684                         0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.constBits());
 
  686            const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
 
  687            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(), im.height(),
 
  688                         0, GL_RGBA, GL_UNSIGNED_BYTE, im.constBits());
 
  691    glBindTexture(GL_TEXTURE_2D, 0);
 
 
  697    return upload(pixmap.toImage());
 
 
OpenGL framebuffer object.
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
const std::unique_ptr< GLTexturePrivate > d
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
OutputTransform contentTransform() const
void setContentTransform(OutputTransform transform)
static bool supportsFormatRG()
void setFilter(GLenum filter)
static std::unique_ptr< GLTexture > createNonOwningWrapper(GLuint textureId, GLenum internalFormat, const QSize &size)
GLenum internalFormat() const
void setSize(const QSize &size)
void update(const QImage &image, const QPoint &offset=QPoint(0, 0), const QRect &src=QRect())
void setSwizzle(GLenum red, GLenum green, GLenum blue, GLenum alpha)
static std::unique_ptr< GLTexture > upload(const QImage &image)
void clear()
Make the texture fully transparent.
QMatrix4x4 matrix(TextureCoordinateType type) const
void render(const QSizeF &size)
static bool framebufferObjectSupported()
void setWrapMode(GLenum mode)
static bool supportsSwizzle()
static bool s_supportsTexture16Bit
static bool s_supportsTextureFormatRG
static bool s_supportsARGB32
static bool s_supportsTextureSwizzle
static bool s_supportsTextureStorage
static bool s_supportsFramebufferObjects
virtual ~GLTexturePrivate()
static bool s_supportsUnpack
OutputTransform m_textureToBufferTransform
@ Static
No changes to data.
KWIN_EXPORT QRect infiniteRegion()
bool hasGLVersion(int major, int minor, int release)
struct KWin::@10 formatTable[]
bool hasGLExtension(const QByteArray &extension)
@ UnnormalizedCoordinates