glamor_picture.c revision 35c4bbdf
1/* 2 * Copyright © 2009 Intel Corporation 3 * Copyright © 1998 Keith Packard 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 * 24 * Authors: 25 * Zhigang Gong <zhigang.gong@gmail.com> 26 * 27 */ 28 29#include <stdlib.h> 30 31#include "glamor_priv.h" 32#include "mipict.h" 33 34/* 35 * Map picture's format to the correct gl texture format and type. 36 * no_alpha is used to indicate whehter we need to wire alpha to 1. 37 * 38 * Although opengl support A1/GL_BITMAP, we still don't use it 39 * here, it seems that mesa has bugs when uploading a A1 bitmap. 40 * 41 * Return 0 if find a matched texture type. Otherwise return -1. 42 **/ 43static int 44glamor_get_tex_format_type_from_pictformat_gl(ScreenPtr pScreen, 45 PictFormatShort format, 46 GLenum *tex_format, 47 GLenum *tex_type, 48 int *no_alpha, 49 int *revert, 50 int *swap_rb, int is_upload) 51{ 52 glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen); 53 *no_alpha = 0; 54 *revert = REVERT_NONE; 55 *swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING; 56 switch (format) { 57 case PICT_a1: 58 *tex_format = glamor_priv->one_channel_format; 59 *tex_type = GL_UNSIGNED_BYTE; 60 *revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1; 61 break; 62 case PICT_b8g8r8x8: 63 *no_alpha = 1; 64 case PICT_b8g8r8a8: 65 *tex_format = GL_BGRA; 66 *tex_type = GL_UNSIGNED_INT_8_8_8_8; 67 break; 68 69 case PICT_x8r8g8b8: 70 *no_alpha = 1; 71 case PICT_a8r8g8b8: 72 *tex_format = GL_BGRA; 73 *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; 74 break; 75 case PICT_x8b8g8r8: 76 *no_alpha = 1; 77 case PICT_a8b8g8r8: 78 *tex_format = GL_RGBA; 79 *tex_type = GL_UNSIGNED_INT_8_8_8_8_REV; 80 break; 81 case PICT_x2r10g10b10: 82 *no_alpha = 1; 83 case PICT_a2r10g10b10: 84 *tex_format = GL_BGRA; 85 *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV; 86 break; 87 case PICT_x2b10g10r10: 88 *no_alpha = 1; 89 case PICT_a2b10g10r10: 90 *tex_format = GL_RGBA; 91 *tex_type = GL_UNSIGNED_INT_2_10_10_10_REV; 92 break; 93 94 case PICT_r5g6b5: 95 *tex_format = GL_RGB; 96 *tex_type = GL_UNSIGNED_SHORT_5_6_5; 97 break; 98 case PICT_b5g6r5: 99 *tex_format = GL_RGB; 100 *tex_type = GL_UNSIGNED_SHORT_5_6_5_REV; 101 break; 102 case PICT_x1b5g5r5: 103 *no_alpha = 1; 104 case PICT_a1b5g5r5: 105 *tex_format = GL_RGBA; 106 *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; 107 break; 108 109 case PICT_x1r5g5b5: 110 *no_alpha = 1; 111 case PICT_a1r5g5b5: 112 *tex_format = GL_BGRA; 113 *tex_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; 114 break; 115 case PICT_a8: 116 *tex_format = glamor_priv->one_channel_format; 117 *tex_type = GL_UNSIGNED_BYTE; 118 break; 119 case PICT_x4r4g4b4: 120 *no_alpha = 1; 121 case PICT_a4r4g4b4: 122 *tex_format = GL_BGRA; 123 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV; 124 break; 125 126 case PICT_x4b4g4r4: 127 *no_alpha = 1; 128 case PICT_a4b4g4r4: 129 *tex_format = GL_RGBA; 130 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4_REV; 131 break; 132 133 default: 134 return -1; 135 } 136 return 0; 137} 138 139#define IS_LITTLE_ENDIAN (IMAGE_BYTE_ORDER == LSBFirst) 140 141static int 142glamor_get_tex_format_type_from_pictformat_gles2(ScreenPtr pScreen, 143 PictFormatShort format, 144 GLenum *tex_format, 145 GLenum *tex_type, 146 int *no_alpha, 147 int *revert, 148 int *swap_rb, int is_upload) 149{ 150 glamor_screen_private *glamor_priv = glamor_get_screen_private(pScreen); 151 int need_swap_rb = 0; 152 153 *no_alpha = 0; 154 *revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL; 155 156 switch (format) { 157 case PICT_b8g8r8x8: 158 *no_alpha = 1; 159 case PICT_b8g8r8a8: 160 *tex_format = GL_RGBA; 161 *tex_type = GL_UNSIGNED_BYTE; 162 need_swap_rb = 1; 163 *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE; 164 break; 165 166 case PICT_x8r8g8b8: 167 *no_alpha = 1; 168 case PICT_a8r8g8b8: 169 *tex_format = GL_RGBA; 170 *tex_type = GL_UNSIGNED_BYTE; 171 need_swap_rb = 1; 172 break; 173 174 case PICT_x8b8g8r8: 175 *no_alpha = 1; 176 case PICT_a8b8g8r8: 177 *tex_format = GL_RGBA; 178 *tex_type = GL_UNSIGNED_BYTE; 179 break; 180 181 case PICT_x2r10g10b10: 182 *no_alpha = 1; 183 case PICT_a2r10g10b10: 184 *tex_format = GL_RGBA; 185 /* glReadPixmap doesn't support GL_UNSIGNED_INT_10_10_10_2. 186 * we have to use GL_UNSIGNED_BYTE and do the conversion in 187 * shader latter.*/ 188 *tex_type = GL_UNSIGNED_BYTE; 189 if (is_upload == 1) { 190 if (!IS_LITTLE_ENDIAN) 191 *revert = REVERT_UPLOADING_10_10_10_2; 192 else 193 *revert = REVERT_UPLOADING_2_10_10_10; 194 } 195 else { 196 if (!IS_LITTLE_ENDIAN) { 197 *revert = REVERT_DOWNLOADING_10_10_10_2; 198 } 199 else { 200 *revert = REVERT_DOWNLOADING_2_10_10_10; 201 } 202 } 203 need_swap_rb = 1; 204 205 break; 206 207 case PICT_x2b10g10r10: 208 *no_alpha = 1; 209 case PICT_a2b10g10r10: 210 *tex_format = GL_RGBA; 211 *tex_type = GL_UNSIGNED_BYTE; 212 if (is_upload == 1) { 213 if (!IS_LITTLE_ENDIAN) 214 *revert = REVERT_UPLOADING_10_10_10_2; 215 else 216 *revert = REVERT_UPLOADING_2_10_10_10; 217 } 218 else { 219 if (!IS_LITTLE_ENDIAN) { 220 *revert = REVERT_DOWNLOADING_10_10_10_2; 221 } 222 else { 223 *revert = REVERT_DOWNLOADING_2_10_10_10; 224 } 225 } 226 break; 227 228 case PICT_r5g6b5: 229 *tex_format = GL_RGB; 230 *tex_type = GL_UNSIGNED_SHORT_5_6_5; 231 *revert = IS_LITTLE_ENDIAN ? REVERT_NONE : REVERT_NORMAL; 232 233 break; 234 235 case PICT_b5g6r5: 236 *tex_format = GL_RGB; 237 *tex_type = GL_UNSIGNED_SHORT_5_6_5; 238 need_swap_rb = IS_LITTLE_ENDIAN ? 1 : 0; 239 break; 240 241 case PICT_x1b5g5r5: 242 *no_alpha = 1; 243 case PICT_a1b5g5r5: 244 *tex_format = GL_RGBA; 245 *tex_type = GL_UNSIGNED_SHORT_5_5_5_1; 246 if (IS_LITTLE_ENDIAN) { 247 *revert = 248 is_upload ? REVERT_UPLOADING_1_5_5_5 : 249 REVERT_DOWNLOADING_1_5_5_5; 250 } 251 else 252 *revert = REVERT_NONE; 253 break; 254 255 case PICT_x1r5g5b5: 256 *no_alpha = 1; 257 case PICT_a1r5g5b5: 258 *tex_format = GL_RGBA; 259 *tex_type = GL_UNSIGNED_SHORT_5_5_5_1; 260 if (IS_LITTLE_ENDIAN) { 261 *revert = 262 is_upload ? REVERT_UPLOADING_1_5_5_5 : 263 REVERT_DOWNLOADING_1_5_5_5; 264 } 265 else 266 *revert = REVERT_NONE; 267 need_swap_rb = 1; 268 break; 269 270 case PICT_a1: 271 *tex_format = glamor_priv->one_channel_format; 272 *tex_type = GL_UNSIGNED_BYTE; 273 *revert = is_upload ? REVERT_UPLOADING_A1 : REVERT_DOWNLOADING_A1; 274 break; 275 276 case PICT_a8: 277 *tex_format = glamor_priv->one_channel_format; 278 *tex_type = GL_UNSIGNED_BYTE; 279 *revert = REVERT_NONE; 280 break; 281 282 case PICT_x4r4g4b4: 283 *no_alpha = 1; 284 case PICT_a4r4g4b4: 285 *tex_format = GL_RGBA; 286 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4; 287 *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE; 288 need_swap_rb = 1; 289 break; 290 291 case PICT_x4b4g4r4: 292 *no_alpha = 1; 293 case PICT_a4b4g4r4: 294 *tex_format = GL_RGBA; 295 *tex_type = GL_UNSIGNED_SHORT_4_4_4_4; 296 *revert = IS_LITTLE_ENDIAN ? REVERT_NORMAL : REVERT_NONE; 297 break; 298 299 default: 300 LogMessageVerb(X_INFO, 0, 301 "fail to get matched format for %x \n", format); 302 return -1; 303 } 304 305 if (need_swap_rb) 306 *swap_rb = is_upload ? SWAP_UPLOADING : SWAP_DOWNLOADING; 307 else 308 *swap_rb = is_upload ? SWAP_NONE_UPLOADING : SWAP_NONE_DOWNLOADING; 309 return 0; 310} 311 312static int 313glamor_get_tex_format_type_from_pixmap(PixmapPtr pixmap, 314 PictFormatShort pict_format, 315 GLenum *format, 316 GLenum *type, 317 int *no_alpha, 318 int *revert, int *swap_rb, int is_upload) 319{ 320 glamor_screen_private *glamor_priv = 321 glamor_get_screen_private(pixmap->drawable.pScreen); 322 323 if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { 324 return glamor_get_tex_format_type_from_pictformat_gl(pixmap->drawable.pScreen, 325 pict_format, 326 format, type, 327 no_alpha, 328 revert, 329 swap_rb, 330 is_upload); 331 } else { 332 return glamor_get_tex_format_type_from_pictformat_gles2(pixmap->drawable.pScreen, 333 pict_format, 334 format, type, 335 no_alpha, 336 revert, 337 swap_rb, 338 is_upload); 339 } 340} 341 342static void * 343_glamor_color_convert_a1_a8(void *src_bits, void *dst_bits, int w, int h, 344 int stride, int revert) 345{ 346 PictFormatShort dst_format, src_format; 347 pixman_image_t *dst_image; 348 pixman_image_t *src_image; 349 int src_stride; 350 351 if (revert == REVERT_UPLOADING_A1) { 352 src_format = PICT_a1; 353 dst_format = PICT_a8; 354 src_stride = PixmapBytePad(w, 1); 355 } 356 else { 357 dst_format = PICT_a1; 358 src_format = PICT_a8; 359 src_stride = (((w * 8 + 7) / 8) + 3) & ~3; 360 } 361 362 dst_image = pixman_image_create_bits(dst_format, w, h, dst_bits, stride); 363 if (dst_image == NULL) { 364 return NULL; 365 } 366 367 src_image = pixman_image_create_bits(src_format, 368 w, h, src_bits, src_stride); 369 370 if (src_image == NULL) { 371 pixman_image_unref(dst_image); 372 return NULL; 373 } 374 375 pixman_image_composite(PictOpSrc, src_image, NULL, dst_image, 376 0, 0, 0, 0, 0, 0, w, h); 377 378 pixman_image_unref(src_image); 379 pixman_image_unref(dst_image); 380 return dst_bits; 381} 382 383#define ADJUST_BITS(d, src_bits, dst_bits) (((dst_bits) == (src_bits)) ? (d) : \ 384 (((dst_bits) > (src_bits)) ? \ 385 (((d) << ((dst_bits) - (src_bits))) \ 386 + (( 1 << ((dst_bits) - (src_bits))) >> 1)) \ 387 : ((d) >> ((src_bits) - (dst_bits))))) 388 389#define GLAMOR_DO_CONVERT(src, dst, no_alpha, swap, \ 390 a_shift_src, a_bits_src, \ 391 b_shift_src, b_bits_src, \ 392 g_shift_src, g_bits_src, \ 393 r_shift_src, r_bits_src, \ 394 a_shift, a_bits, \ 395 b_shift, b_bits, \ 396 g_shift, g_bits, \ 397 r_shift, r_bits) \ 398 do { \ 399 typeof(src) a,b,g,r; \ 400 typeof(src) a_mask_src, b_mask_src, g_mask_src, r_mask_src;\ 401 a_mask_src = (((1 << (a_bits_src)) - 1) << a_shift_src);\ 402 b_mask_src = (((1 << (b_bits_src)) - 1) << b_shift_src);\ 403 g_mask_src = (((1 << (g_bits_src)) - 1) << g_shift_src);\ 404 r_mask_src = (((1 << (r_bits_src)) - 1) << r_shift_src);\ 405 if (no_alpha) \ 406 a = (a_mask_src) >> (a_shift_src); \ 407 else \ 408 a = ((src) & (a_mask_src)) >> (a_shift_src); \ 409 b = ((src) & (b_mask_src)) >> (b_shift_src); \ 410 g = ((src) & (g_mask_src)) >> (g_shift_src); \ 411 r = ((src) & (r_mask_src)) >> (r_shift_src); \ 412 a = ADJUST_BITS(a, a_bits_src, a_bits); \ 413 b = ADJUST_BITS(b, b_bits_src, b_bits); \ 414 g = ADJUST_BITS(g, g_bits_src, g_bits); \ 415 r = ADJUST_BITS(r, r_bits_src, r_bits); \ 416 if (swap == 0) \ 417 (*dst) = ((a) << (a_shift)) | ((b) << (b_shift)) | ((g) << (g_shift)) | ((r) << (r_shift)); \ 418 else \ 419 (*dst) = ((a) << (a_shift)) | ((r) << (b_shift)) | ((g) << (g_shift)) | ((b) << (r_shift)); \ 420 } while (0) 421 422static void * 423_glamor_color_revert_x2b10g10r10(void *src_bits, void *dst_bits, int w, int h, 424 int stride, int no_alpha, int revert, 425 int swap_rb) 426{ 427 int x, y; 428 unsigned int *words, *saved_words, *source_words; 429 int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || 430 swap_rb == SWAP_NONE_UPLOADING); 431 432 source_words = src_bits; 433 words = dst_bits; 434 saved_words = words; 435 436 for (y = 0; y < h; y++) { 437 DEBUGF("Line %d : ", y); 438 for (x = 0; x < w; x++) { 439 unsigned int pixel = source_words[x]; 440 441 if (revert == REVERT_DOWNLOADING_2_10_10_10) 442 GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap, 443 24, 8, 16, 8, 8, 8, 0, 8, 444 30, 2, 20, 10, 10, 10, 0, 10); 445 else 446 GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap, 447 30, 2, 20, 10, 10, 10, 0, 10, 448 24, 8, 16, 8, 8, 8, 0, 8); 449 DEBUGF("%x:%x ", pixel, words[x]); 450 } 451 DEBUGF("\n"); 452 words += stride / sizeof(*words); 453 source_words += stride / sizeof(*words); 454 } 455 DEBUGF("\n"); 456 return saved_words; 457 458} 459 460static void * 461_glamor_color_revert_x1b5g5r5(void *src_bits, void *dst_bits, int w, int h, 462 int stride, int no_alpha, int revert, int swap_rb) 463{ 464 int x, y; 465 unsigned short *words, *saved_words, *source_words; 466 int swap = !(swap_rb == SWAP_NONE_DOWNLOADING || 467 swap_rb == SWAP_NONE_UPLOADING); 468 469 words = dst_bits; 470 source_words = src_bits; 471 saved_words = words; 472 473 for (y = 0; y < h; y++) { 474 DEBUGF("Line %d : ", y); 475 for (x = 0; x < w; x++) { 476 unsigned short pixel = source_words[x]; 477 478 if (revert == REVERT_DOWNLOADING_1_5_5_5) 479 GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap, 480 0, 1, 1, 5, 6, 5, 11, 5, 481 15, 1, 10, 5, 5, 5, 0, 5); 482 else 483 GLAMOR_DO_CONVERT(pixel, &words[x], no_alpha, swap, 484 15, 1, 10, 5, 5, 5, 0, 5, 485 0, 1, 1, 5, 6, 5, 11, 5); 486 DEBUGF("%04x:%04x ", pixel, words[x]); 487 } 488 DEBUGF("\n"); 489 words += stride / sizeof(*words); 490 source_words += stride / sizeof(*words); 491 } 492 DEBUGF("\n"); 493 return saved_words; 494} 495 496/* 497 * This function is to convert an unsupported color format to/from a 498 * supported GL format. 499 * Here are the current scenarios: 500 * 501 * @no_alpha: 502 * If it is set, then we need to wire the alpha value to 1. 503 * @revert: 504 REVERT_DOWNLOADING_A1 : convert an Alpha8 buffer to a A1 buffer. 505 REVERT_UPLOADING_A1 : convert an A1 buffer to an Alpha8 buffer 506 REVERT_DOWNLOADING_2_10_10_10 : convert r10G10b10X2 to X2B10G10R10 507 REVERT_UPLOADING_2_10_10_10 : convert X2B10G10R10 to R10G10B10X2 508 REVERT_DOWNLOADING_1_5_5_5 : convert B5G5R5X1 to X1R5G5B5 509 REVERT_UPLOADING_1_5_5_5 : convert X1R5G5B5 to B5G5R5X1 510 @swap_rb: if we have the swap_rb set, then we need to swap the R and B's position. 511 * 512 */ 513 514static void * 515glamor_color_convert_to_bits(void *src_bits, void *dst_bits, int w, int h, 516 int stride, int no_alpha, int revert, int swap_rb) 517{ 518 if (revert == REVERT_DOWNLOADING_A1 || revert == REVERT_UPLOADING_A1) { 519 return _glamor_color_convert_a1_a8(src_bits, dst_bits, w, h, stride, 520 revert); 521 } 522 else if (revert == REVERT_DOWNLOADING_2_10_10_10 || 523 revert == REVERT_UPLOADING_2_10_10_10) { 524 return _glamor_color_revert_x2b10g10r10(src_bits, dst_bits, w, h, 525 stride, no_alpha, revert, 526 swap_rb); 527 } 528 else if (revert == REVERT_DOWNLOADING_1_5_5_5 || 529 revert == REVERT_UPLOADING_1_5_5_5) { 530 return _glamor_color_revert_x1b5g5r5(src_bits, dst_bits, w, h, stride, 531 no_alpha, revert, swap_rb); 532 } 533 else 534 ErrorF("convert a non-supported mode %x.\n", revert); 535 536 return NULL; 537} 538 539/** 540 * Upload pixmap to a specified texture. 541 * This texture may not be the one attached to it. 542 **/ 543static Bool 544__glamor_upload_pixmap_to_texture(PixmapPtr pixmap, unsigned int *tex, 545 GLenum format, 546 GLenum type, 547 int x, int y, int w, int h, 548 void *bits, int pbo) 549{ 550 glamor_screen_private *glamor_priv = 551 glamor_get_screen_private(pixmap->drawable.pScreen); 552 int non_sub = 0; 553 unsigned int iformat = 0; 554 555 glamor_make_current(glamor_priv); 556 if (*tex == 0) { 557 glGenTextures(1, tex); 558 if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) 559 iformat = gl_iformat_for_pixmap(pixmap); 560 else 561 iformat = format; 562 non_sub = 1; 563 assert(x == 0 && y == 0); 564 } 565 566 glBindTexture(GL_TEXTURE_2D, *tex); 567 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 568 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 569 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 570 571 assert(pbo || bits != 0); 572 if (bits == NULL) { 573 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); 574 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 575 } 576 glamor_priv->suppress_gl_out_of_memory_logging = true; 577 if (non_sub) 578 glTexImage2D(GL_TEXTURE_2D, 0, iformat, w, h, 0, format, type, bits); 579 else 580 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, format, type, bits); 581 glamor_priv->suppress_gl_out_of_memory_logging = false; 582 if (glGetError() == GL_OUT_OF_MEMORY) { 583 if (non_sub) { 584 glDeleteTextures(1, tex); 585 *tex = 0; 586 } 587 return FALSE; 588 } 589 590 if (bits == NULL) 591 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 592 593 return TRUE; 594} 595 596static Bool 597_glamor_upload_bits_to_pixmap_texture(PixmapPtr pixmap, GLenum format, 598 GLenum type, int no_alpha, int revert, 599 int swap_rb, int x, int y, int w, int h, 600 int stride, void *bits, int pbo) 601{ 602 ScreenPtr screen = pixmap->drawable.pScreen; 603 glamor_pixmap_private *pixmap_priv = glamor_get_pixmap_private(pixmap); 604 glamor_screen_private *glamor_priv = 605 glamor_get_screen_private(pixmap->drawable.pScreen); 606 float dst_xscale, dst_yscale; 607 GLuint tex = 0; 608 int need_free_bits = 0; 609 610 if (bits == NULL) 611 goto ready_to_upload; 612 613 if (revert > REVERT_NORMAL) { 614 /* XXX if we are restoring the pixmap, then we may not need to allocate 615 * new buffer */ 616 void *converted_bits; 617 618 if (pixmap->drawable.depth == 1) 619 stride = (((w * 8 + 7) / 8) + 3) & ~3; 620 621 converted_bits = xallocarray(h, stride); 622 623 if (converted_bits == NULL) 624 return FALSE; 625 bits = glamor_color_convert_to_bits(bits, converted_bits, w, h, 626 stride, no_alpha, revert, swap_rb); 627 if (bits == NULL) { 628 free(converted_bits); 629 ErrorF("Failed to convert pixmap no_alpha %d," 630 "revert mode %d, swap mode %d\n", no_alpha, revert, swap_rb); 631 return FALSE; 632 } 633 no_alpha = 0; 634 revert = REVERT_NONE; 635 swap_rb = SWAP_NONE_UPLOADING; 636 need_free_bits = TRUE; 637 } 638 639 ready_to_upload: 640 641 /* Try fast path firstly, upload the pixmap to the texture attached 642 * to the fbo directly. */ 643 if (no_alpha == 0 644 && revert == REVERT_NONE && swap_rb == SWAP_NONE_UPLOADING 645#ifdef WALKAROUND_LARGE_TEXTURE_MAP 646 && glamor_pixmap_priv_is_small(pixmap_priv) 647#endif 648 ) { 649 int fbo_x_off, fbo_y_off; 650 651 assert(pixmap_priv->fbo->tex); 652 pixmap_priv_get_fbo_off(pixmap_priv, &fbo_x_off, &fbo_y_off); 653 654 assert(x + fbo_x_off >= 0 && y + fbo_y_off >= 0); 655 assert(x + fbo_x_off + w <= pixmap_priv->fbo->width); 656 assert(y + fbo_y_off + h <= pixmap_priv->fbo->height); 657 if (!__glamor_upload_pixmap_to_texture(pixmap, &pixmap_priv->fbo->tex, 658 format, type, 659 x + fbo_x_off, y + fbo_y_off, 660 w, h, 661 bits, pbo)) { 662 if (need_free_bits) 663 free(bits); 664 return FALSE; 665 } 666 } else { 667 static const float texcoords_inv[8] = { 0, 0, 668 1, 0, 669 1, 1, 670 0, 1 671 }; 672 GLfloat *v; 673 char *vbo_offset; 674 675 v = glamor_get_vbo_space(screen, 16 * sizeof(GLfloat), &vbo_offset); 676 677 pixmap_priv_get_dest_scale(pixmap, pixmap_priv, &dst_xscale, &dst_yscale); 678 glamor_set_normalize_vcoords(pixmap_priv, dst_xscale, 679 dst_yscale, 680 x, y, 681 x + w, y + h, 682 v); 683 /* Slow path, we need to flip y or wire alpha to 1. */ 684 glamor_make_current(glamor_priv); 685 686 if (!__glamor_upload_pixmap_to_texture(pixmap, &tex, 687 format, type, 0, 0, w, h, bits, 688 pbo)) { 689 if (need_free_bits) 690 free(bits); 691 return FALSE; 692 } 693 694 memcpy(&v[8], texcoords_inv, 8 * sizeof(GLfloat)); 695 696 glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, 697 GL_FALSE, 2 * sizeof(float), vbo_offset); 698 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 699 glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, 700 GL_FALSE, 2 * sizeof(float), vbo_offset + 8 * sizeof(GLfloat)); 701 glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 702 703 glamor_put_vbo_space(screen); 704 glamor_set_destination_pixmap_priv_nc(glamor_priv, pixmap, pixmap_priv); 705 glamor_set_alu(screen, GXcopy); 706 glActiveTexture(GL_TEXTURE0); 707 glBindTexture(GL_TEXTURE_2D, tex); 708 709 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 710 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 711 glUseProgram(glamor_priv->finish_access_prog[no_alpha]); 712 glUniform1i(glamor_priv->finish_access_revert[no_alpha], revert); 713 glUniform1i(glamor_priv->finish_access_swap_rb[no_alpha], swap_rb); 714 715 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 716 717 glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 718 glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); 719 glDeleteTextures(1, &tex); 720 glBindFramebuffer(GL_FRAMEBUFFER, 0); 721 } 722 723 if (need_free_bits) 724 free(bits); 725 return TRUE; 726} 727 728/* 729 * Prepare to upload a pixmap to texture memory. 730 * no_alpha equals 1 means the format needs to wire alpha to 1. 731 */ 732static int 733glamor_pixmap_upload_prepare(PixmapPtr pixmap, GLenum format, int no_alpha, 734 int revert, int swap_rb) 735{ 736 int flag = 0; 737 glamor_pixmap_private *pixmap_priv; 738 glamor_screen_private *glamor_priv; 739 glamor_pixmap_fbo *fbo; 740 GLenum iformat; 741 742 pixmap_priv = glamor_get_pixmap_private(pixmap); 743 glamor_priv = glamor_get_screen_private(pixmap->drawable.pScreen); 744 745 if (pixmap_priv->gl_fbo != GLAMOR_FBO_UNATTACHED) 746 return 0; 747 748 if (pixmap_priv->fbo 749 && (pixmap_priv->fbo->width < pixmap->drawable.width 750 || pixmap_priv->fbo->height < pixmap->drawable.height)) { 751 fbo = glamor_pixmap_detach_fbo(pixmap_priv); 752 glamor_destroy_fbo(glamor_priv, fbo); 753 } 754 755 if (pixmap_priv->fbo && pixmap_priv->fbo->fb) 756 return 0; 757 758 if (!(no_alpha || (revert == REVERT_NORMAL) 759 || (swap_rb != SWAP_NONE_UPLOADING))) { 760 /* We don't need a fbo, a simple texture uploading should work. */ 761 762 flag = GLAMOR_CREATE_FBO_NO_FBO; 763 } 764 765 if ((flag == GLAMOR_CREATE_FBO_NO_FBO 766 && pixmap_priv->fbo && pixmap_priv->fbo->tex)) 767 return 0; 768 769 if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) 770 iformat = gl_iformat_for_pixmap(pixmap); 771 else 772 iformat = format; 773 774 if (!glamor_pixmap_ensure_fbo(pixmap, iformat, flag)) 775 return -1; 776 777 return 0; 778} 779 780/* 781 * upload sub region to a large region. 782 * */ 783static void 784glamor_put_bits(char *dst_bits, int dst_stride, char *src_bits, 785 int src_stride, int bpp, int x, int y, int w, int h) 786{ 787 int j; 788 int byte_per_pixel; 789 790 byte_per_pixel = bpp / 8; 791 src_bits += y * src_stride + (x * byte_per_pixel); 792 793 for (j = y; j < y + h; j++) { 794 memcpy(dst_bits, src_bits, w * byte_per_pixel); 795 src_bits += src_stride; 796 dst_bits += dst_stride; 797 } 798} 799 800static Bool 801glamor_upload_sub_pixmap_to_texture(PixmapPtr pixmap, int x, int y, int w, 802 int h, int stride, void *bits, int pbo, 803 PictFormatShort pict_format) 804{ 805 ScreenPtr screen = pixmap->drawable.pScreen; 806 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 807 GLenum format, type; 808 int no_alpha, revert, swap_rb; 809 glamor_pixmap_private *pixmap_priv; 810 Bool force_clip; 811 812 if (glamor_get_tex_format_type_from_pixmap(pixmap, 813 pict_format, 814 &format, 815 &type, 816 &no_alpha, 817 &revert, &swap_rb, 1)) { 818 glamor_fallback("Unknown pixmap depth %d.\n", pixmap->drawable.depth); 819 return FALSE; 820 } 821 if (glamor_pixmap_upload_prepare(pixmap, format, no_alpha, revert, swap_rb)) 822 return FALSE; 823 824 pixmap_priv = glamor_get_pixmap_private(pixmap); 825 force_clip = glamor_priv->gl_flavor != GLAMOR_GL_DESKTOP 826 && !glamor_check_fbo_size(glamor_priv, w, h); 827 828 if (glamor_pixmap_priv_is_large(pixmap_priv) || force_clip) { 829 RegionRec region; 830 BoxRec box; 831 int n_region; 832 glamor_pixmap_clipped_regions *clipped_regions; 833 void *sub_bits; 834 int i, j; 835 836 sub_bits = xallocarray(h, stride); 837 if (sub_bits == NULL) 838 return FALSE; 839 box.x1 = x; 840 box.y1 = y; 841 box.x2 = x + w; 842 box.y2 = y + h; 843 RegionInitBoxes(®ion, &box, 1); 844 if (!force_clip) 845 clipped_regions = 846 glamor_compute_clipped_regions(pixmap, ®ion, &n_region, 847 0, 0, 0); 848 else 849 clipped_regions = 850 glamor_compute_clipped_regions_ext(pixmap, ®ion, 851 &n_region, 852 pixmap_priv->block_w, 853 pixmap_priv->block_h, 854 0, 855 0); 856 DEBUGF("prepare upload %dx%d to a large pixmap %p\n", w, h, pixmap); 857 for (i = 0; i < n_region; i++) { 858 BoxPtr boxes; 859 int nbox; 860 int temp_stride; 861 void *temp_bits; 862 863 assert(pbo == 0); 864 865 glamor_set_pixmap_fbo_current(pixmap_priv, clipped_regions[i].block_idx); 866 867 boxes = RegionRects(clipped_regions[i].region); 868 nbox = RegionNumRects(clipped_regions[i].region); 869 DEBUGF("split to %d boxes\n", nbox); 870 for (j = 0; j < nbox; j++) { 871 temp_stride = PixmapBytePad(boxes[j].x2 - boxes[j].x1, 872 pixmap->drawable.depth); 873 874 if (boxes[j].x1 == x && temp_stride == stride) { 875 temp_bits = (char *) bits + (boxes[j].y1 - y) * stride; 876 } 877 else { 878 temp_bits = sub_bits; 879 glamor_put_bits(temp_bits, temp_stride, bits, stride, 880 pixmap->drawable.bitsPerPixel, 881 boxes[j].x1 - x, boxes[j].y1 - y, 882 boxes[j].x2 - boxes[j].x1, 883 boxes[j].y2 - boxes[j].y1); 884 } 885 DEBUGF("upload x %d y %d w %d h %d temp stride %d \n", 886 boxes[j].x1 - x, boxes[j].y1 - y, 887 boxes[j].x2 - boxes[j].x1, 888 boxes[j].y2 - boxes[j].y1, temp_stride); 889 if (_glamor_upload_bits_to_pixmap_texture 890 (pixmap, format, type, no_alpha, revert, swap_rb, 891 boxes[j].x1, boxes[j].y1, boxes[j].x2 - boxes[j].x1, 892 boxes[j].y2 - boxes[j].y1, temp_stride, temp_bits, 893 pbo) == FALSE) { 894 RegionUninit(®ion); 895 free(sub_bits); 896 assert(0); 897 return FALSE; 898 } 899 } 900 RegionDestroy(clipped_regions[i].region); 901 } 902 free(sub_bits); 903 free(clipped_regions); 904 RegionUninit(®ion); 905 return TRUE; 906 } 907 else 908 return _glamor_upload_bits_to_pixmap_texture(pixmap, format, type, 909 no_alpha, revert, swap_rb, 910 x, y, w, h, stride, bits, 911 pbo); 912} 913 914/* Upload picture to texture. We may need to flip the y axis or 915 * wire alpha to 1. So we may conditional create fbo for the picture. 916 * */ 917enum glamor_pixmap_status 918glamor_upload_picture_to_texture(PicturePtr picture) 919{ 920 PixmapPtr pixmap; 921 922 assert(picture->pDrawable); 923 pixmap = glamor_get_drawable_pixmap(picture->pDrawable); 924 925 if (glamor_upload_sub_pixmap_to_texture(pixmap, 0, 0, 926 pixmap->drawable.width, 927 pixmap->drawable.height, 928 pixmap->devKind, 929 pixmap->devPrivate.ptr, 0, 930 picture->format)) 931 return GLAMOR_UPLOAD_DONE; 932 else 933 return GLAMOR_UPLOAD_FAILED; 934} 935