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 
byte_swap_swizzle(GLenum * swizzle)44 static 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  */
67 static Bool
glamor_get_tex_format_type_from_pictformat(ScreenPtr pScreen,PictFormatShort format,PictFormatShort * temp_format,GLenum * tex_format,GLenum * tex_type,GLenum * swizzle)68 glamor_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  */
240 static pixman_image_t *
glamor_get_converted_image(PictFormatShort dst_format,PictFormatShort src_format,void * src_bits,int src_stride,int w,int h)241 glamor_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  */
273 Bool
glamor_upload_picture_to_texture(PicturePtr picture)274 glamor_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         ret = FALSE;
345         goto fail;
346     }
347 
348     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
349 
350     glamor_priv->suppress_gl_out_of_memory_logging = true;
351 
352     /* We can't use glamor_pixmap_loop() because GLAMOR_MEMORY pixmaps
353      * don't have initialized boxes.
354      */
355     glBindTexture(GL_TEXTURE_2D, pixmap_priv->fbo->tex);
356     glTexImage2D(GL_TEXTURE_2D, 0, iformat,
357                  pixmap->drawable.width, pixmap->drawable.height, 0,
358                  format, type, bits);
359 
360     if (needs_swizzle) {
361         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
362         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
363         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
364         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
365     }
366 
367     glamor_priv->suppress_gl_out_of_memory_logging = false;
368     if (glGetError() == GL_OUT_OF_MEMORY) {
369         ret = FALSE;
370     }
371 
372 fail:
373     if (converted_image)
374         pixman_image_unref(converted_image);
375 
376     return ret;
377 }
378