glamor_picture.c 11.4 KB
Newer Older
1
/*
2
 * Copyright © 2016 Broadcom
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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.
24 25 26 27
 */

/**
 * @file glamor_picture.c
28
 *
29 30 31
 * Implements temporary uploads of GL_MEMORY Pixmaps to a texture that
 * is swizzled appropriately for a given Render picture format.
 * laid *
32
 *
33 34 35 36
 * 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).
37 38
 */

39 40 41
#include <stdlib.h>

#include "glamor_priv.h"
42
#include "mipict.h"
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
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.
59
 *
60 61 62 63 64 65 66
 * 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.
 */
67 68 69
static Bool
glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
                                           PictFormatShort format,
70
                                           PictFormatShort *temp_format,
71 72
                                           GLenum *tex_format,
                                           GLenum *tex_type,
73
                                           GLenum *swizzle)
74
{
75
    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
76 77
    Bool is_little_endian = IMAGE_BYTE_ORDER == LSBFirst;

78 79 80 81 82
    *temp_format = format;
    swizzle[0] = GL_RED;
    swizzle[1] = GL_GREEN;
    swizzle[2] = GL_BLUE;
    swizzle[3] = GL_ALPHA;
83

84 85
    switch (format) {
    case PICT_a1:
86
        *tex_format = glamor_priv->one_channel_format;
87
        *tex_type = GL_UNSIGNED_BYTE;
88
        *temp_format = PICT_a8;
89 90 91 92
        break;

    case PICT_b8g8r8x8:
    case PICT_b8g8r8a8:
93
        if (!glamor_priv->is_gles) {
94 95 96 97 98
            *tex_format = GL_BGRA;
            *tex_type = GL_UNSIGNED_INT_8_8_8_8;
        } else {
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_BYTE;
99 100 101 102 103 104 105 106

            swizzle[0] = GL_GREEN;
            swizzle[1] = GL_BLUE;
            swizzle[2] = GL_ALPHA;
            swizzle[3] = GL_RED;

            if (!is_little_endian)
                byte_swap_swizzle(swizzle);
107
        }
108 109 110 111
        break;

    case PICT_x8r8g8b8:
    case PICT_a8r8g8b8:
112
        if (!glamor_priv->is_gles) {
113 114 115 116 117
            *tex_format = GL_BGRA;
            *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
        } else {
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_BYTE;
118 119 120 121 122 123

            swizzle[0] = GL_BLUE;
            swizzle[2] = GL_RED;

            if (!is_little_endian)
                byte_swap_swizzle(swizzle);
124 125
            break;
        }
126 127 128 129 130
        break;

    case PICT_x8b8g8r8:
    case PICT_a8b8g8r8:
        *tex_format = GL_RGBA;
131
        if (!glamor_priv->is_gles) {
132 133
            *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
        } else {
134
            *tex_format = GL_RGBA;
135
            *tex_type = GL_UNSIGNED_BYTE;
136 137 138

            if (!is_little_endian)
                byte_swap_swizzle(swizzle);
139
        }
140 141 142 143
        break;

    case PICT_x2r10g10b10:
    case PICT_a2r10g10b10:
144
        if (!glamor_priv->is_gles) {
145 146 147
            *tex_format = GL_BGRA;
            *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
        } else {
148
            return FALSE;
149
        }
150 151 152 153
        break;

    case PICT_x2b10g10r10:
    case PICT_a2b10g10r10:
154
        if (!glamor_priv->is_gles) {
155 156 157
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
        } else {
158
            return FALSE;
159
        }
160 161 162 163 164 165 166 167
        break;

    case PICT_r5g6b5:
        *tex_format = GL_RGB;
        *tex_type = GL_UNSIGNED_SHORT_5_6_5;
        break;
    case PICT_b5g6r5:
        *tex_format = GL_RGB;
168
        if (!glamor_priv->is_gles) {
169 170 171
            *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
        } else {
            *tex_type = GL_UNSIGNED_SHORT_5_6_5;
172 173
            swizzle[0] = GL_BLUE;
            swizzle[2] = GL_RED;
174
        }
175 176 177 178 179
        break;

    case PICT_x1b5g5r5:
    case PICT_a1b5g5r5:
        *tex_format = GL_RGBA;
180
        if (!glamor_priv->is_gles) {
181 182
            *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
        } else {
183
            return FALSE;
184
        }
185 186 187 188
        break;

    case PICT_x1r5g5b5:
    case PICT_a1r5g5b5:
189
        if (!glamor_priv->is_gles) {
190 191 192
            *tex_format = GL_BGRA;
            *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
        } else {
193
            return FALSE;
194
        }
195 196 197
        break;

    case PICT_a8:
198
        *tex_format = glamor_priv->one_channel_format;
199 200 201 202 203
        *tex_type = GL_UNSIGNED_BYTE;
        break;

    case PICT_x4r4g4b4:
    case PICT_a4r4g4b4:
204
        if (!glamor_priv->is_gles) {
205 206 207
            *tex_format = GL_BGRA;
            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
        } else {
208
            /* XXX */
209 210 211
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
        }
212 213 214 215
        break;

    case PICT_x4b4g4r4:
    case PICT_a4b4g4r4:
216
        if (!glamor_priv->is_gles) {
217 218 219
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
        } else {
220
            /* XXX */
221 222 223
            *tex_format = GL_RGBA;
            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
        }
224 225 226
        break;

    default:
227
        return FALSE;
228
    }
229 230 231 232

    if (!PICT_FORMAT_A(format))
        swizzle[3] = GL_ONE;

233
    return TRUE;
234 235
}

236 237 238 239 240 241 242 243 244 245
/**
 * 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)
246 247 248 249
{
    pixman_image_t *dst_image;
    pixman_image_t *src_image;

250
    dst_image = pixman_image_create_bits(dst_format, w, h, NULL, 0);
251 252 253 254
    if (dst_image == NULL) {
        return NULL;
    }

255
    src_image = pixman_image_create_bits(src_format, w, h, src_bits, src_stride);
256 257 258 259 260 261 262 263 264 265

    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);
266
    return dst_image;
267 268
}

269 270 271 272
/**
 * Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a
 * temporary FBO.
 */
273 274
Bool
glamor_upload_picture_to_texture(PicturePtr picture)
275
{
276
    PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
277 278
    ScreenPtr screen = pixmap->drawable.pScreen;
    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
279
    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
280 281 282 283 284 285 286 287 288
    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;
289

290 291 292
    assert(glamor_pixmap_is_memory(pixmap));
    assert(!pixmap_priv->fbo);

293 294
    glamor_make_current(glamor_priv);

295 296 297 298 299 300 301 302 303
    /* 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;
    }

304 305
    if (!glamor_get_tex_format_type_from_pictformat(screen,
                                                    picture->format,
306
                                                    &converted_format,
307 308
                                                    &format,
                                                    &type,
309
                                                    swizzle)) {
310 311 312
        glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
        return FALSE;
    }
313 314 315 316 317 318 319 320 321

    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");
322
        return FALSE;
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
    }

    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);
    }

338
    if (!glamor_priv->is_gles)
339 340 341 342
        iformat = gl_iformat_for_pixmap(pixmap);
    else
        iformat = format;

343
    if (!glamor_pixmap_ensure_fbo(pixmap, GLAMOR_CREATE_FBO_NO_FBO)) {
344
        ret = FALSE;
345
        goto fail;
346
    }
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374

    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);
375

376
    return ret;
Eric Anholt's avatar
Eric Anholt committed
377
}