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