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->formats[1].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->is_gles) { 94 *tex_format = GL_BGRA; 95 *tex_type = GL_UNSIGNED_INT_8_8_8_8; 96 } else { 97 *tex_format = GL_BGRA; 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->is_gles) { 113 *tex_format = GL_BGRA; 114 *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; 115 } else { 116 *tex_format = GL_BGRA; 117 *tex_type = GL_UNSIGNED_BYTE; 118 119 if (!is_little_endian) 120 byte_swap_swizzle(swizzle); 121 break; 122 } 123 break; 124 125 case PICT_x8b8g8r8: 126 case PICT_a8b8g8r8: 127 *tex_format = GL_RGBA; 128 if (!glamor_priv->is_gles) { 129 *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; 130 } else { 131 *tex_format = GL_RGBA; 132 *tex_type = GL_UNSIGNED_BYTE; 133 134 if (!is_little_endian) 135 byte_swap_swizzle(swizzle); 136 } 137 break; 138 139 case PICT_x2r10g10b10: 140 case PICT_a2r10g10b10: 141 if (!glamor_priv->is_gles) { 142 *tex_format = GL_BGRA; 143 *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV; 144 } else { 145 return FALSE; 146 } 147 break; 148 149 case PICT_x2b10g10r10: 150 case PICT_a2b10g10r10: 151 if (!glamor_priv->is_gles) { 152 *tex_format = GL_RGBA; 153 *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV; 154 } else { 155 return FALSE; 156 } 157 break; 158 159 case PICT_r5g6b5: 160 *tex_format = GL_RGB; 161 *tex_type = GL_UNSIGNED_SHORT_5_6_5; 162 break; 163 case PICT_b5g6r5: 164 *tex_format = GL_RGB; 165 if (!glamor_priv->is_gles) { 166 *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV; 167 } else { 168 *tex_type = GL_UNSIGNED_SHORT_5_6_5; 169 swizzle[0] = GL_BLUE; 170 swizzle[2] = GL_RED; 171 } 172 break; 173 174 case PICT_x1b5g5r5: 175 case PICT_a1b5g5r5: 176 *tex_format = GL_RGBA; 177 if (!glamor_priv->is_gles) { 178 *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; 179 } else { 180 return FALSE; 181 } 182 break; 183 184 case PICT_x1r5g5b5: 185 case PICT_a1r5g5b5: 186 if (!glamor_priv->is_gles) { 187 *tex_format = GL_BGRA; 188 *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; 189 } else { 190 return FALSE; 191 } 192 break; 193 194 case PICT_a8: 195 *tex_format = glamor_priv->formats[8].format; 196 *tex_type = GL_UNSIGNED_BYTE; 197 break; 198 199 case PICT_x4r4g4b4: 200 case PICT_a4r4g4b4: 201 if (!glamor_priv->is_gles) { 202 *tex_format = GL_BGRA; 203 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV; 204 } else { 205 /* XXX */ 206 *tex_format = GL_RGBA; 207 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4; 208 } 209 break; 210 211 case PICT_x4b4g4r4: 212 case PICT_a4b4g4r4: 213 if (!glamor_priv->is_gles) { 214 *tex_format = GL_RGBA; 215 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV; 216 } else { 217 /* XXX */ 218 *tex_format = GL_RGBA; 219 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4; 220 } 221 break; 222 223 default: 224 return FALSE; 225 } 226 227 if (!PICT_FORMAT_A(format)) 228 swizzle[3] = GL_ONE; 229 230 return TRUE; 231} 232 233/** 234 * Takes a set of source bits with a given format and returns an 235 * in-memory pixman image of those bits in a destination format. 236 */ 237static pixman_image_t * 238glamor_get_converted_image(PictFormatShort dst_format, 239 PictFormatShort src_format, 240 void *src_bits, 241 int src_stride, 242 int w, int h) 243{ 244 pixman_image_t *dst_image; 245 pixman_image_t *src_image; 246 247 dst_image = pixman_image_create_bits(dst_format, w, h, NULL, 0); 248 if (dst_image == NULL) { 249 return NULL; 250 } 251 252 src_image = pixman_image_create_bits(src_format, w, h, src_bits, src_stride); 253 254 if (src_image == NULL) { 255 pixman_image_unref(dst_image); 256 return NULL; 257 } 258 259 pixman_image_composite(PictOpSrc, src_image, NULL, dst_image, 260 0, 0, 0, 0, 0, 0, w, h); 261 262 pixman_image_unref(src_image); 263 return dst_image; 264} 265 266/** 267 * Uploads a picture based on a GLAMOR_MEMORY pixmap to a texture in a 268 * temporary FBO. 269 */ 270Bool 271glamor_upload_picture_to_texture(PicturePtr picture) 272{ 273 PixmapPtr pixmap = glamor_get_drawable_pixmap(picture->pDrawable); 274 ScreenPtr screen = pixmap->drawable.pScreen; 275 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 276 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 277 PictFormatShort converted_format; 278 void *bits = pixmap->devPrivate.ptr; 279 int stride = pixmap->devKind; 280 GLenum format, type; 281 GLenum swizzle[4]; 282 GLenum iformat; 283 Bool ret = TRUE; 284 Bool needs_swizzle; 285 pixman_image_t *converted_image = NULL; 286 const struct glamor_format *f = glamor_format_for_pixmap(pixmap); 287 288 assert(glamor_pixmap_is_memory(pixmap)); 289 assert(!pixmap_priv->fbo); 290 291 glamor_make_current(glamor_priv); 292 293 /* No handling of large pixmap pictures here (would need to make 294 * an FBO array and split the uploads across it). 295 */ 296 if (!glamor_check_fbo_size(glamor_priv, 297 pixmap->drawable.width, 298 pixmap->drawable.height)) { 299 return FALSE; 300 } 301 302 if (!glamor_get_tex_format_type_from_pictformat(screen, 303 picture->format, 304 &converted_format, 305 &format, 306 &type, 307 swizzle)) { 308 glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth); 309 return FALSE; 310 } 311 312 needs_swizzle = (swizzle[0] != GL_RED || 313 swizzle[1] != GL_GREEN || 314 swizzle[2] != GL_BLUE || 315 swizzle[3] != GL_ALPHA); 316 317 if (!glamor_priv->has_texture_swizzle && needs_swizzle) { 318 glamor_fallback("Couldn't upload temporary picture due to missing " 319 "GL_ARB_texture_swizzle.\n"); 320 return FALSE; 321 } 322 323 if (converted_format != picture->format) { 324 converted_image = glamor_get_converted_image(converted_format, 325 picture->format, 326 bits, stride, 327 pixmap->drawable.width, 328 pixmap->drawable.height); 329 if (!converted_image) 330 return FALSE; 331 332 bits = pixman_image_get_data(converted_image); 333 stride = pixman_image_get_stride(converted_image); 334 } 335 336 if (!glamor_priv->is_gles) 337 iformat = f->internalformat; 338 else 339 iformat = format; 340 341 if (!glamor_pixmap_ensure_fbo(pixmap, GLAMOR_CREATE_FBO_NO_FBO)) { 342 ret = FALSE; 343 goto fail; 344 } 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