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