Edit

IABSD.fr/xenocara/xserver/glamor/glamor_picture.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2021-11-11 09:03:02
    Hash : e086cf5a
    Message : Update to xserver 21.1.0

  • xserver/glamor/glamor_picture.c
  • /*
     * Copyright © 2016 Broadcom
     * Copyright © 2009 Intel Corporation
     * Copyright © 1998 Keith Packard
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     * IN THE SOFTWARE.
     */
    
    /**
     * @file glamor_picture.c
     *
     * Implements temporary uploads of GL_MEMORY Pixmaps to a texture that
     * is swizzled appropriately for a given Render picture format.
     * laid *
     *
     * This is important because GTK likes to use SHM Pixmaps for Render
     * blending operations, and we don't want a blend operation to fall
     * back to software (readback is more expensive than the upload we do
     * here, and you'd have to re-upload the fallback output anyway).
     */
    
    #include <stdlib.h>
    
    #include "glamor_priv.h"
    #include "mipict.h"
    
    static void byte_swap_swizzle(GLenum *swizzle)
    {
        GLenum temp;
    
        temp = swizzle[0];
        swizzle[0] = swizzle[3];
        swizzle[3] = temp;
    
        temp = swizzle[1];
        swizzle[1] = swizzle[2];
        swizzle[2] = temp;
    }
    
    /**
     * Returns the GL format and type for uploading our bits to a given PictFormat.
     *
     * We may need to tell the caller to translate the bits to another
     * format, as in PICT_a1 (which GL doesn't support).  We may also need
     * to tell the GL to swizzle the texture on sampling, because GLES3
     * doesn't support the GL_UNSIGNED_INT_8_8_8_8{,_REV} types, so we
     * don't have enough channel reordering options at upload time without
     * it.
     */
    static Bool
    glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
                                               PictFormatShort format,
                                               PictFormatShort *temp_format,
                                               GLenum *tex_format,
                                               GLenum *tex_type,
                                               GLenum *swizzle)
    {
        glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
        Bool is_little_endian = IMAGE_BYTE_ORDER == LSBFirst;
    
        *temp_format = format;
        swizzle[0] = GL_RED;
        swizzle[1] = GL_GREEN;
        swizzle[2] = GL_BLUE;
        swizzle[3] = GL_ALPHA;
    
        switch (format) {
        case PICT_a1:
            *tex_format = glamor_priv->formats[1].format;
            *tex_type = GL_UNSIGNED_BYTE;
            *temp_format = PICT_a8;
            break;
    
        case PICT_b8g8r8x8:
        case PICT_b8g8r8a8:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_BGRA;
                *tex_type = GL_UNSIGNED_INT_8_8_8_8;
            } else {
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_BYTE;
    
                swizzle[0] = GL_GREEN;
                swizzle[1] = GL_BLUE;
                swizzle[2] = GL_ALPHA;
                swizzle[3] = GL_RED;
    
                if (!is_little_endian)
                    byte_swap_swizzle(swizzle);
            }
            break;
    
        case PICT_x8r8g8b8:
        case PICT_a8r8g8b8:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_BGRA;
                *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
            } else {
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_BYTE;
    
                swizzle[0] = GL_BLUE;
                swizzle[2] = GL_RED;
    
                if (!is_little_endian)
                    byte_swap_swizzle(swizzle);
                break;
            }
            break;
    
        case PICT_x8b8g8r8:
        case PICT_a8b8g8r8:
            *tex_format = GL_RGBA;
            if (!glamor_priv->is_gles) {
                *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
            } else {
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_BYTE;
    
                if (!is_little_endian)
                    byte_swap_swizzle(swizzle);
            }
            break;
    
        case PICT_x2r10g10b10:
        case PICT_a2r10g10b10:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_BGRA;
                *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
            } else {
                return FALSE;
            }
            break;
    
        case PICT_x2b10g10r10:
        case PICT_a2b10g10r10:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
            } else {
                return FALSE;
            }
            break;
    
        case PICT_r5g6b5:
            *tex_format = GL_RGB;
            *tex_type = GL_UNSIGNED_SHORT_5_6_5;
            break;
        case PICT_b5g6r5:
            *tex_format = GL_RGB;
            if (!glamor_priv->is_gles) {
                *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
            } else {
                *tex_type = GL_UNSIGNED_SHORT_5_6_5;
                swizzle[0] = GL_BLUE;
                swizzle[2] = GL_RED;
            }
            break;
    
        case PICT_x1b5g5r5:
        case PICT_a1b5g5r5:
            *tex_format = GL_RGBA;
            if (!glamor_priv->is_gles) {
                *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
            } else {
                return FALSE;
            }
            break;
    
        case PICT_x1r5g5b5:
        case PICT_a1r5g5b5:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_BGRA;
                *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
            } else {
                return FALSE;
            }
            break;
    
        case PICT_a8:
            *tex_format = glamor_priv->formats[8].format;
            *tex_type = GL_UNSIGNED_BYTE;
            break;
    
        case PICT_x4r4g4b4:
        case PICT_a4r4g4b4:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_BGRA;
                *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
            } else {
                /* XXX */
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
            }
            break;
    
        case PICT_x4b4g4r4:
        case PICT_a4b4g4r4:
            if (!glamor_priv->is_gles) {
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
            } else {
                /* XXX */
                *tex_format = GL_RGBA;
                *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
            }
            break;
    
        default:
            return FALSE;
        }
    
        if (!PICT_FORMAT_A(format))
            swizzle[3] = GL_ONE;
    
        return TRUE;
    }
    
    /**
     * Takes a set of source bits with a given format and returns an
     * in-memory pixman image of those bits in a destination format.
     */
    static pixman_image_t *
    glamor_get_converted_image(PictFormatShort dst_format,
                               PictFormatShort src_format,
                               void *src_bits,
                               int src_stride,
                               int w, int h)
    {
        pixman_image_t *dst_image;
        pixman_image_t *src_image;
    
        dst_image = pixman_image_create_bits(dst_format, w, h, NULL, 0);
        if (dst_image == NULL) {
            return NULL;
        }
    
        src_image = pixman_image_create_bits(src_format, w, h, src_bits, src_stride);
    
        if (src_image == NULL) {
            pixman_image_unref(dst_image);
            return NULL;
        }
    
        pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
                               0, 0, 0, 0, 0, 0, w, h);
    
        pixman_image_unref(src_image);
        return dst_image;
    }
    
    /**
     * Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a
     * temporary FBO.
     */
    Bool
    glamor_upload_picture_to_texture(PicturePtr picture)
    {
        PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
        ScreenPtr screen = pixmap->drawable.pScreen;
        glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
        glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
        PictFormatShort converted_format;
        void *bits = pixmap->devPrivate.ptr;
        int stride = pixmap->devKind;
        GLenum format, type;
        GLenum swizzle[4];
        GLenum iformat;
        Bool ret = TRUE;
        Bool needs_swizzle;
        pixman_image_t *converted_image = NULL;
        const struct glamor_format *f = glamor_format_for_pixmap(pixmap);
    
        assert(glamor_pixmap_is_memory(pixmap));
        assert(!pixmap_priv->fbo);
    
        glamor_make_current(glamor_priv);
    
        /* No handling of large pixmap pictures here (would need to make
         * an FBO array and split the uploads across it).
         */
        if (!glamor_check_fbo_size(glamor_priv,
                                   pixmap->drawable.width,
                                   pixmap->drawable.height)) {
            return FALSE;
        }
    
        if (!glamor_get_tex_format_type_from_pictformat(screen,
                                                        picture->format,
                                                        &converted_format,
                                                        &format,
                                                        &type,
                                                        swizzle)) {
            glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
            return FALSE;
        }
    
        needs_swizzle = (swizzle[0] != GL_RED ||
                         swizzle[1] != GL_GREEN ||
                         swizzle[2] != GL_BLUE ||
                         swizzle[3] != GL_ALPHA);
    
        if (!glamor_priv->has_texture_swizzle && needs_swizzle) {
            glamor_fallback("Couldn't upload temporary picture due to missing "
                            "GL_ARB_texture_swizzle.\n");
            return FALSE;
        }
    
        if (converted_format != picture->format) {
            converted_image = glamor_get_converted_image(converted_format,
                                                         picture->format,
                                                         bits, stride,
                                                         pixmap->drawable.width,
                                                         pixmap->drawable.height);
            if (!converted_image)
                return FALSE;
    
            bits = pixman_image_get_data(converted_image);
            stride = pixman_image_get_stride(converted_image);
        }
    
        if (!glamor_priv->is_gles)
            iformat = f->internalformat;
        else
            iformat = format;
    
        if (!glamor_pixmap_ensure_fbo(pixmap, GLAMOR_CREATE_FBO_NO_FBO)) {
            ret = FALSE;
            goto fail;
        }
    
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    
        glamor_priv->suppress_gl_out_of_memory_logging = true;
    
        /* We can't use glamor_pixmap_loop() because GLAMOR_MEMORY pixmaps
         * don't have initialized boxes.
         */
        glBindTexture(GL_TEXTURE_2D, pixmap_priv->fbo->tex);
        glTexImage2D(GL_TEXTURE_2D, 0, iformat,
                     pixmap->drawable.width, pixmap->drawable.height, 0,
                     format, type, bits);
    
        if (needs_swizzle) {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
        }
    
        glamor_priv->suppress_gl_out_of_memory_logging = false;
        if (glGetError() == GL_OUT_OF_MEMORY) {
            ret = FALSE;
        }
    
    fail:
        if (converted_image)
            pixman_image_unref(converted_image);
    
        return ret;
    }