glamor_picture.c revision 1b5d61b8
1/*
2 * Copyright © 2016 Broadcom
3 * Copyright © 2009 Intel Corporation
4 * Copyright © 1998 Keith Packard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 * IN THE SOFTWARE.
24 */
25
26/**
27 * @file glamor_picture.c
28 *
29 * Implements temporary uploads of GL_MEMORY Pixmaps to a texture that
30 * is swizzled appropriately for a given Render picture format.
31 * laid *
32 *
33 * This is important because GTK likes to use SHM Pixmaps for Render
34 * blending operations, and we don't want a blend operation to fall
35 * back to software (readback is more expensive than the upload we do
36 * here, and you'd have to re-upload the fallback output anyway).
37 */
38
39#include <stdlib.h>
40
41#include "glamor_priv.h"
42#include "mipict.h"
43
44static void byte_swap_swizzle(GLenum *swizzle)
45{
46    GLenum temp;
47
48    temp = swizzle[0];
49    swizzle[0] = swizzle[3];
50    swizzle[3] = temp;
51
52    temp = swizzle[1];
53    swizzle[1] = swizzle[2];
54    swizzle[2] = temp;
55}
56
57/**
58 * Returns the GL format and type for uploading our bits to a given PictFormat.
59 *
60 * We may need to tell the caller to translate the bits to another
61 * format, as in PICT_a1 (which GL doesn't support).  We may also need
62 * to tell the GL to swizzle the texture on sampling, because GLES3
63 * doesn't support the GL_UNSIGNED_INT_8_8_8_8{,_REV} types, so we
64 * don't have enough channel reordering options at upload time without
65 * it.
66 */
67static Bool
68glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,
69                                           PictFormatShort format,
70                                           PictFormatShort *temp_format,
71                                           GLenum *tex_format,
72                                           GLenum *tex_type,
73                                           GLenum *swizzle)
74{
75    glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen);
76    Bool is_little_endian = IMAGE_BYTE_ORDER == LSBFirst;
77
78    *temp_format = format;
79    swizzle[0] = GL_RED;
80    swizzle[1] = GL_GREEN;
81    swizzle[2] = GL_BLUE;
82    swizzle[3] = GL_ALPHA;
83
84    switch (format) {
85    case PICT_a1:
86        *tex_format = glamor_priv->one_channel_format;
87        *tex_type = GL_UNSIGNED_BYTE;
88        *temp_format = PICT_a8;
89        break;
90
91    case PICT_b8g8r8x8:
92    case PICT_b8g8r8a8:
93        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
94            *tex_format = GL_BGRA;
95            *tex_type = GL_UNSIGNED_INT_8_8_8_8;
96        } else {
97            *tex_format = GL_RGBA;
98            *tex_type = GL_UNSIGNED_BYTE;
99
100            swizzle[0] = GL_GREEN;
101            swizzle[1] = GL_BLUE;
102            swizzle[2] = GL_ALPHA;
103            swizzle[3] = GL_RED;
104
105            if (!is_little_endian)
106                byte_swap_swizzle(swizzle);
107        }
108        break;
109
110    case PICT_x8r8g8b8:
111    case PICT_a8r8g8b8:
112        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
113            *tex_format = GL_BGRA;
114            *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
115        } else {
116            *tex_format = GL_RGBA;
117            *tex_type = GL_UNSIGNED_BYTE;
118
119            swizzle[0] = GL_BLUE;
120            swizzle[2] = GL_RED;
121
122            if (!is_little_endian)
123                byte_swap_swizzle(swizzle);
124            break;
125        }
126        break;
127
128    case PICT_x8b8g8r8:
129    case PICT_a8b8g8r8:
130        *tex_format = GL_RGBA;
131        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
132            *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV;
133        } else {
134            *tex_format = GL_RGBA;
135            *tex_type = GL_UNSIGNED_BYTE;
136
137            if (!is_little_endian)
138                byte_swap_swizzle(swizzle);
139        }
140        break;
141
142    case PICT_x2r10g10b10:
143    case PICT_a2r10g10b10:
144        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
145            *tex_format = GL_BGRA;
146            *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
147        } else {
148            return FALSE;
149        }
150        break;
151
152    case PICT_x2b10g10r10:
153    case PICT_a2b10g10r10:
154        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
155            *tex_format = GL_RGBA;
156            *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV;
157        } else {
158            return FALSE;
159        }
160        break;
161
162    case PICT_r5g6b5:
163        *tex_format = GL_RGB;
164        *tex_type = GL_UNSIGNED_SHORT_5_6_5;
165        break;
166    case PICT_b5g6r5:
167        *tex_format = GL_RGB;
168        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
169            *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV;
170        } else {
171            *tex_type = GL_UNSIGNED_SHORT_5_6_5;
172            swizzle[0] = GL_BLUE;
173            swizzle[2] = GL_RED;
174        }
175        break;
176
177    case PICT_x1b5g5r5:
178    case PICT_a1b5g5r5:
179        *tex_format = GL_RGBA;
180        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
181            *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
182        } else {
183            return FALSE;
184        }
185        break;
186
187    case PICT_x1r5g5b5:
188    case PICT_a1r5g5b5:
189        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
190            *tex_format = GL_BGRA;
191            *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
192        } else {
193            return FALSE;
194        }
195        break;
196
197    case PICT_a8:
198        *tex_format = glamor_priv->one_channel_format;
199        *tex_type = GL_UNSIGNED_BYTE;
200        break;
201
202    case PICT_x4r4g4b4:
203    case PICT_a4r4g4b4:
204        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
205            *tex_format = GL_BGRA;
206            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
207        } else {
208            /* XXX */
209            *tex_format = GL_RGBA;
210            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
211        }
212        break;
213
214    case PICT_x4b4g4r4:
215    case PICT_a4b4g4r4:
216        if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) {
217            *tex_format = GL_RGBA;
218            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
219        } else {
220            /* XXX */
221            *tex_format = GL_RGBA;
222            *tex_type = GL_UNSIGNED_SHORT_4_4_4_4;
223        }
224        break;
225
226    default:
227        return FALSE;
228    }
229
230    if (!PICT_FORMAT_A(format))
231        swizzle[3] = GL_ONE;
232
233    return TRUE;
234}
235
236/**
237 * Takes a set of source bits with a given format and returns an
238 * in-memory pixman image of those bits in a destination format.
239 */
240static pixman_image_t *
241glamor_get_converted_image(PictFormatShort dst_format,
242                           PictFormatShort src_format,
243                           void *src_bits,
244                           int src_stride,
245                           int w, int h)
246{
247    pixman_image_t *dst_image;
248    pixman_image_t *src_image;
249
250    dst_image = pixman_image_create_bits(dst_format, w, h, NULL, 0);
251    if (dst_image == NULL) {
252        return NULL;
253    }
254
255    src_image = pixman_image_create_bits(src_format, w, h, src_bits, src_stride);
256
257    if (src_image == NULL) {
258        pixman_image_unref(dst_image);
259        return NULL;
260    }
261
262    pixman_image_composite(PictOpSrc, src_image, NULL, dst_image,
263                           0, 0, 0, 0, 0, 0, w, h);
264
265    pixman_image_unref(src_image);
266    return dst_image;
267}
268
269/**
270 * Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a
271 * temporary FBO.
272 */
273Bool
274glamor_upload_picture_to_texture(PicturePtr picture)
275{
276    PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable);
277    ScreenPtr screen = pixmap->drawable.pScreen;
278    glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
279    glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap);
280    PictFormatShort converted_format;
281    void *bits = pixmap->devPrivate.ptr;
282    int stride = pixmap->devKind;
283    GLenum format, type;
284    GLenum swizzle[4];
285    GLenum iformat;
286    Bool ret = TRUE;
287    Bool needs_swizzle;
288    pixman_image_t *converted_image = NULL;
289
290    assert(glamor_pixmap_is_memory(pixmap));
291    assert(!pixmap_priv->fbo);
292
293    glamor_make_current(glamor_priv);
294
295    /* No handling of large pixmap pictures here (would need to make
296     * an FBO array and split the uploads across it).
297     */
298    if (!glamor_check_fbo_size(glamor_priv,
299                               pixmap->drawable.width,
300                               pixmap->drawable.height)) {
301        return FALSE;
302    }
303
304    if (!glamor_get_tex_format_type_from_pictformat(screen,
305                                                    picture->format,
306                                                    &converted_format,
307                                                    &format,
308                                                    &type,
309                                                    swizzle)) {
310        glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth);
311        return FALSE;
312    }
313
314    needs_swizzle = (swizzle[0] != GL_RED ||
315                     swizzle[1] != GL_GREEN ||
316                     swizzle[2] != GL_BLUE ||
317                     swizzle[3] != GL_ALPHA);
318
319    if (!glamor_priv->has_texture_swizzle && needs_swizzle) {
320        glamor_fallback("Couldn't upload temporary picture due to missing "
321                        "GL_ARB_texture_swizzle.\n");
322        return FALSE;
323    }
324
325    if (converted_format != picture->format) {
326        converted_image = glamor_get_converted_image(converted_format,
327                                                     picture->format,
328                                                     bits, stride,
329                                                     pixmap->drawable.width,
330                                                     pixmap->drawable.height);
331        if (!converted_image)
332            return FALSE;
333
334        bits = pixman_image_get_data(converted_image);
335        stride = pixman_image_get_stride(converted_image);
336    }
337
338    if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP)
339        iformat = gl_iformat_for_pixmap(pixmap);
340    else
341        iformat = format;
342
343    if (!glamor_pixmap_ensure_fbo(pixmap, iformat, GLAMOR_CREATE_FBO_NO_FBO))
344        goto fail;
345
346    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
347
348    glamor_priv->suppress_gl_out_of_memory_logging = true;
349
350    /* We can't use glamor_pixmap_loop() because GLAMOR_MEMORY pixmaps
351     * don't have initialized boxes.
352     */
353    glBindTexture(GL_TEXTURE_2D, pixmap_priv->fbo->tex);
354    glTexImage2D(GL_TEXTURE_2D, 0, iformat,
355                 pixmap->drawable.width, pixmap->drawable.height, 0,
356                 format, type, bits);
357
358    if (needs_swizzle) {
359        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
360        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
361        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
362        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
363    }
364
365    glamor_priv->suppress_gl_out_of_memory_logging = false;
366    if (glGetError() == GL_OUT_OF_MEMORY) {
367        ret = FALSE;
368    }
369
370fail:
371    if (converted_image)
372        pixman_image_unref(converted_image);
373
374    return ret;
375}
376