1/* 2 * Copyright © 2014 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "glamor_priv.h" 24#include "glamor_transfer.h" 25#include "glamor_prepare.h" 26#include "glamor_transform.h" 27 28struct copy_args { 29 PixmapPtr src_pixmap; 30 glamor_pixmap_fbo *src; 31 uint32_t bitplane; 32 int dx, dy; 33}; 34 35static Bool 36use_copyarea(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg) 37{ 38 struct copy_args *args = arg; 39 glamor_pixmap_fbo *src = args->src; 40 41 glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen), 42 GL_TEXTURE0, src, TRUE); 43 44 glUniform2f(prog->fill_offset_uniform, args->dx, args->dy); 45 glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height); 46 47 return TRUE; 48} 49 50static const glamor_facet glamor_facet_copyarea = { 51 "copy_area", 52 .vs_vars = "attribute vec2 primitive;\n", 53 .vs_exec = (GLAMOR_POS(gl_Position, primitive.xy) 54 " fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"), 55 .fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n", 56 .locations = glamor_program_location_fillsamp | glamor_program_location_fillpos, 57 .use = use_copyarea, 58}; 59 60/* 61 * Configure the copy plane program for the current operation 62 */ 63 64static Bool 65use_copyplane(PixmapPtr dst, GCPtr gc, glamor_program *prog, void *arg) 66{ 67 struct copy_args *args = arg; 68 glamor_pixmap_fbo *src = args->src; 69 70 glamor_bind_texture(glamor_get_screen_private(dst->drawable.pScreen), 71 GL_TEXTURE0, src, TRUE); 72 73 glUniform2f(prog->fill_offset_uniform, args->dx, args->dy); 74 glUniform2f(prog->fill_size_inv_uniform, 1.0f/src->width, 1.0f/src->height); 75 76 glamor_set_color(dst, gc->fgPixel, prog->fg_uniform); 77 glamor_set_color(dst, gc->bgPixel, prog->bg_uniform); 78 79 /* XXX handle 2 10 10 10 and 1555 formats; presumably the pixmap private knows this? */ 80 switch (args->src_pixmap->drawable.depth) { 81 case 30: 82 glUniform4ui(prog->bitplane_uniform, 83 (args->bitplane >> 20) & 0x3ff, 84 (args->bitplane >> 10) & 0x3ff, 85 (args->bitplane ) & 0x3ff, 86 0); 87 88 glUniform4f(prog->bitmul_uniform, 0x3ff, 0x3ff, 0x3ff, 0); 89 break; 90 case 24: 91 glUniform4ui(prog->bitplane_uniform, 92 (args->bitplane >> 16) & 0xff, 93 (args->bitplane >> 8) & 0xff, 94 (args->bitplane ) & 0xff, 95 0); 96 97 glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0); 98 break; 99 case 32: 100 glUniform4ui(prog->bitplane_uniform, 101 (args->bitplane >> 16) & 0xff, 102 (args->bitplane >> 8) & 0xff, 103 (args->bitplane ) & 0xff, 104 (args->bitplane >> 24) & 0xff); 105 106 glUniform4f(prog->bitmul_uniform, 0xff, 0xff, 0xff, 0xff); 107 break; 108 case 16: 109 glUniform4ui(prog->bitplane_uniform, 110 (args->bitplane >> 11) & 0x1f, 111 (args->bitplane >> 5) & 0x3f, 112 (args->bitplane ) & 0x1f, 113 0); 114 115 glUniform4f(prog->bitmul_uniform, 0x1f, 0x3f, 0x1f, 0); 116 break; 117 case 15: 118 glUniform4ui(prog->bitplane_uniform, 119 (args->bitplane >> 10) & 0x1f, 120 (args->bitplane >> 5) & 0x1f, 121 (args->bitplane ) & 0x1f, 122 0); 123 124 glUniform4f(prog->bitmul_uniform, 0x1f, 0x1f, 0x1f, 0); 125 break; 126 case 8: 127 glUniform4ui(prog->bitplane_uniform, 128 0, 0, 0, args->bitplane); 129 glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff); 130 break; 131 case 1: 132 glUniform4ui(prog->bitplane_uniform, 133 0, 0, 0, args->bitplane); 134 glUniform4f(prog->bitmul_uniform, 0, 0, 0, 0xff); 135 break; 136 } 137 138 return TRUE; 139} 140 141static const glamor_facet glamor_facet_copyplane = { 142 "copy_plane", 143 .version = 130, 144 .vs_vars = "attribute vec2 primitive;\n", 145 .vs_exec = (GLAMOR_POS(gl_Position, (primitive.xy)) 146 " fill_pos = (fill_offset + primitive.xy) * fill_size_inv;\n"), 147 .fs_exec = (" uvec4 bits = uvec4(round(texture2D(sampler, fill_pos) * bitmul));\n" 148 " if ((bits & bitplane) != uvec4(0,0,0,0))\n" 149 " gl_FragColor = fg;\n" 150 " else\n" 151 " gl_FragColor = bg;\n"), 152 .locations = glamor_program_location_fillsamp|glamor_program_location_fillpos|glamor_program_location_fg|glamor_program_location_bg|glamor_program_location_bitplane, 153 .use = use_copyplane, 154}; 155 156/* 157 * When all else fails, pull the bits out of the GPU and do the 158 * operation with fb 159 */ 160 161static void 162glamor_copy_bail(DrawablePtr src, 163 DrawablePtr dst, 164 GCPtr gc, 165 BoxPtr box, 166 int nbox, 167 int dx, 168 int dy, 169 Bool reverse, 170 Bool upsidedown, 171 Pixel bitplane, 172 void *closure) 173{ 174 if (glamor_prepare_access(dst, GLAMOR_ACCESS_RW) && glamor_prepare_access(src, GLAMOR_ACCESS_RO)) { 175 if (bitplane) { 176 if (src->bitsPerPixel > 1) 177 fbCopyNto1(src, dst, gc, box, nbox, dx, dy, 178 reverse, upsidedown, bitplane, closure); 179 else 180 fbCopy1toN(src, dst, gc, box, nbox, dx, dy, 181 reverse, upsidedown, bitplane, closure); 182 } else { 183 fbCopyNtoN(src, dst, gc, box, nbox, dx, dy, 184 reverse, upsidedown, bitplane, closure); 185 } 186 } 187 glamor_finish_access(dst); 188 glamor_finish_access(src); 189} 190 191/** 192 * Implements CopyPlane and CopyArea from the CPU to the GPU by using 193 * the source as a texture and painting that into the destination. 194 * 195 * This requires that source and dest are different textures, or that 196 * (if the copy area doesn't overlap), GL_NV_texture_barrier is used 197 * to ensure that the caches are flushed at the right times. 198 */ 199static Bool 200glamor_copy_cpu_fbo(DrawablePtr src, 201 DrawablePtr dst, 202 GCPtr gc, 203 BoxPtr box, 204 int nbox, 205 int dx, 206 int dy, 207 Bool reverse, 208 Bool upsidedown, 209 Pixel bitplane, 210 void *closure) 211{ 212 ScreenPtr screen = dst->pScreen; 213 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 214 PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); 215 int dst_xoff, dst_yoff; 216 217 if (gc && gc->alu != GXcopy) 218 goto bail; 219 220 if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask)) 221 goto bail; 222 223 glamor_make_current(glamor_priv); 224 225 if (!glamor_prepare_access(src, GLAMOR_ACCESS_RO)) 226 goto bail; 227 228 glamor_get_drawable_deltas(dst, dst_pixmap, &dst_xoff, &dst_yoff); 229 230 if (bitplane) { 231 FbBits *tmp_bits; 232 FbStride tmp_stride; 233 int tmp_bpp; 234 int tmp_xoff, tmp_yoff; 235 236 PixmapPtr tmp_pix = fbCreatePixmap(screen, dst_pixmap->drawable.width, 237 dst_pixmap->drawable.height, 238 dst->depth, 0); 239 240 if (!tmp_pix) { 241 glamor_finish_access(src); 242 goto bail; 243 } 244 245 tmp_pix->drawable.x = dst_xoff; 246 tmp_pix->drawable.y = dst_yoff; 247 248 fbGetDrawable(&tmp_pix->drawable, tmp_bits, tmp_stride, tmp_bpp, tmp_xoff, 249 tmp_yoff); 250 251 if (src->bitsPerPixel > 1) 252 fbCopyNto1(src, &tmp_pix->drawable, gc, box, nbox, dx, dy, 253 reverse, upsidedown, bitplane, closure); 254 else 255 fbCopy1toN(src, &tmp_pix->drawable, gc, box, nbox, dx, dy, 256 reverse, upsidedown, bitplane, closure); 257 258 glamor_upload_boxes(dst_pixmap, box, nbox, tmp_xoff, tmp_yoff, 259 dst_xoff, dst_yoff, (uint8_t *) tmp_bits, 260 tmp_stride * sizeof(FbBits)); 261 fbDestroyPixmap(tmp_pix); 262 } else { 263 FbBits *src_bits; 264 FbStride src_stride; 265 int src_bpp; 266 int src_xoff, src_yoff; 267 268 fbGetDrawable(src, src_bits, src_stride, src_bpp, src_xoff, src_yoff); 269 glamor_upload_boxes(dst_pixmap, box, nbox, src_xoff + dx, src_yoff + dy, 270 dst_xoff, dst_yoff, 271 (uint8_t *) src_bits, src_stride * sizeof (FbBits)); 272 } 273 glamor_finish_access(src); 274 275 return TRUE; 276 277bail: 278 return FALSE; 279} 280 281/** 282 * Implements CopyArea from the GPU to the CPU using glReadPixels from the 283 * source FBO. 284 */ 285static Bool 286glamor_copy_fbo_cpu(DrawablePtr src, 287 DrawablePtr dst, 288 GCPtr gc, 289 BoxPtr box, 290 int nbox, 291 int dx, 292 int dy, 293 Bool reverse, 294 Bool upsidedown, 295 Pixel bitplane, 296 void *closure) 297{ 298 ScreenPtr screen = dst->pScreen; 299 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 300 PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); 301 FbBits *dst_bits; 302 FbStride dst_stride; 303 int dst_bpp; 304 int src_xoff, src_yoff; 305 int dst_xoff, dst_yoff; 306 307 if (gc && gc->alu != GXcopy) 308 goto bail; 309 310 if (gc && !glamor_pm_is_solid(gc->depth, gc->planemask)) 311 goto bail; 312 313 glamor_make_current(glamor_priv); 314 315 if (!glamor_prepare_access(dst, GLAMOR_ACCESS_RW)) 316 goto bail; 317 318 glamor_get_drawable_deltas(src, src_pixmap, &src_xoff, &src_yoff); 319 320 fbGetDrawable(dst, dst_bits, dst_stride, dst_bpp, dst_xoff, dst_yoff); 321 322 glamor_download_boxes(src_pixmap, box, nbox, src_xoff + dx, src_yoff + dy, 323 dst_xoff, dst_yoff, 324 (uint8_t *) dst_bits, dst_stride * sizeof (FbBits)); 325 glamor_finish_access(dst); 326 327 return TRUE; 328 329bail: 330 return FALSE; 331} 332 333/* Include the enums here for the moment, to keep from needing to bump epoxy. */ 334#ifndef GL_TILE_RASTER_ORDER_FIXED_MESA 335#define GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8 336#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9 337#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA 338#endif 339 340/* 341 * Copy from GPU to GPU by using the source 342 * as a texture and painting that into the destination 343 */ 344 345static Bool 346glamor_copy_fbo_fbo_draw(DrawablePtr src, 347 DrawablePtr dst, 348 GCPtr gc, 349 BoxPtr box, 350 int nbox, 351 int dx, 352 int dy, 353 Bool reverse, 354 Bool upsidedown, 355 Pixel bitplane, 356 void *closure) 357{ 358 ScreenPtr screen = dst->pScreen; 359 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 360 PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); 361 PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); 362 glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap); 363 glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap); 364 int src_box_index, dst_box_index; 365 int dst_off_x, dst_off_y; 366 int src_off_x, src_off_y; 367 GLshort *v; 368 char *vbo_offset; 369 struct copy_args args; 370 glamor_program *prog; 371 const glamor_facet *copy_facet; 372 int n; 373 Bool ret = FALSE; 374 BoxRec bounds = glamor_no_rendering_bounds(); 375 376 glamor_make_current(glamor_priv); 377 378 if (gc && !glamor_set_planemask(gc->depth, gc->planemask)) 379 goto bail_ctx; 380 381 if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy)) 382 goto bail_ctx; 383 384 if (bitplane && !glamor_priv->can_copyplane) 385 goto bail_ctx; 386 387 if (bitplane) { 388 prog = &glamor_priv->copy_plane_prog; 389 copy_facet = &glamor_facet_copyplane; 390 } else { 391 prog = &glamor_priv->copy_area_prog; 392 copy_facet = &glamor_facet_copyarea; 393 } 394 395 if (prog->failed) 396 goto bail_ctx; 397 398 if (!prog->prog) { 399 if (!glamor_build_program(screen, prog, 400 copy_facet, NULL, NULL, NULL)) 401 goto bail_ctx; 402 } 403 404 args.src_pixmap = src_pixmap; 405 args.bitplane = bitplane; 406 407 /* Set up the vertex buffers for the points */ 408 409 v = glamor_get_vbo_space(dst->pScreen, nbox * 8 * sizeof (int16_t), &vbo_offset); 410 411 if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) { 412 glEnable(GL_TILE_RASTER_ORDER_FIXED_MESA); 413 if (dx >= 0) 414 glEnable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA); 415 else 416 glDisable(GL_TILE_RASTER_ORDER_INCREASING_X_MESA); 417 if (dy >= 0) 418 glEnable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA); 419 else 420 glDisable(GL_TILE_RASTER_ORDER_INCREASING_Y_MESA); 421 } 422 423 glEnableVertexAttribArray(GLAMOR_VERTEX_POS); 424 glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_SHORT, GL_FALSE, 425 2 * sizeof (GLshort), vbo_offset); 426 427 if (nbox < 100) { 428 bounds = glamor_start_rendering_bounds(); 429 for (int i = 0; i < nbox; i++) 430 glamor_bounds_union_box(&bounds, &box[i]); 431 } 432 433 for (n = 0; n < nbox; n++) { 434 v[0] = box->x1; v[1] = box->y1; 435 v[2] = box->x1; v[3] = box->y2; 436 v[4] = box->x2; v[5] = box->y2; 437 v[6] = box->x2; v[7] = box->y1; 438 439 v += 8; 440 box++; 441 } 442 443 glamor_put_vbo_space(screen); 444 445 glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y); 446 447 glEnable(GL_SCISSOR_TEST); 448 449 glamor_pixmap_loop(src_priv, src_box_index) { 450 BoxPtr src_box = glamor_pixmap_box_at(src_priv, src_box_index); 451 452 args.dx = dx + src_off_x - src_box->x1; 453 args.dy = dy + src_off_y - src_box->y1; 454 args.src = glamor_pixmap_fbo_at(src_priv, src_box_index); 455 456 if (!glamor_use_program(dst_pixmap, gc, prog, &args)) 457 goto bail_ctx; 458 459 glamor_pixmap_loop(dst_priv, dst_box_index) { 460 BoxRec scissor = { 461 .x1 = max(-args.dx, bounds.x1), 462 .y1 = max(-args.dy, bounds.y1), 463 .x2 = min(-args.dx + src_box->x2 - src_box->x1, bounds.x2), 464 .y2 = min(-args.dy + src_box->y2 - src_box->y1, bounds.y2), 465 }; 466 if (scissor.x1 >= scissor.x2 || scissor.y1 >= scissor.y2) 467 continue; 468 469 if (!glamor_set_destination_drawable(dst, dst_box_index, FALSE, FALSE, 470 prog->matrix_uniform, 471 &dst_off_x, &dst_off_y)) 472 goto bail_ctx; 473 474 glScissor(scissor.x1 + dst_off_x, 475 scissor.y1 + dst_off_y, 476 scissor.x2 - scissor.x1, 477 scissor.y2 - scissor.y1); 478 479 glamor_glDrawArrays_GL_QUADS(glamor_priv, nbox); 480 } 481 } 482 483 ret = TRUE; 484 485bail_ctx: 486 if (src_pixmap == dst_pixmap && glamor_priv->has_mesa_tile_raster_order) { 487 glDisable(GL_TILE_RASTER_ORDER_FIXED_MESA); 488 } 489 glDisable(GL_SCISSOR_TEST); 490 glDisableVertexAttribArray(GLAMOR_VERTEX_POS); 491 492 return ret; 493} 494 495/** 496 * Copies from the GPU to the GPU using a temporary pixmap in between, 497 * to correctly handle overlapping copies. 498 */ 499 500static Bool 501glamor_copy_fbo_fbo_temp(DrawablePtr src, 502 DrawablePtr dst, 503 GCPtr gc, 504 BoxPtr box, 505 int nbox, 506 int dx, 507 int dy, 508 Bool reverse, 509 Bool upsidedown, 510 Pixel bitplane, 511 void *closure) 512{ 513 ScreenPtr screen = dst->pScreen; 514 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 515 PixmapPtr tmp_pixmap; 516 BoxRec bounds; 517 int n; 518 BoxPtr tmp_box; 519 520 if (nbox == 0) 521 return TRUE; 522 523 /* Sanity check state to avoid getting halfway through and bailing 524 * at the last second. Might be nice to have checks that didn't 525 * involve setting state. 526 */ 527 glamor_make_current(glamor_priv); 528 529 if (gc && !glamor_set_planemask(gc->depth, gc->planemask)) 530 goto bail_ctx; 531 532 if (!glamor_set_alu(screen, gc ? gc->alu : GXcopy)) 533 goto bail_ctx; 534 535 /* Find the size of the area to copy 536 */ 537 bounds = box[0]; 538 for (n = 1; n < nbox; n++) { 539 bounds.x1 = min(bounds.x1, box[n].x1); 540 bounds.x2 = max(bounds.x2, box[n].x2); 541 bounds.y1 = min(bounds.y1, box[n].y1); 542 bounds.y2 = max(bounds.y2, box[n].y2); 543 } 544 545 /* Allocate a suitable temporary pixmap 546 */ 547 tmp_pixmap = glamor_create_pixmap(screen, 548 bounds.x2 - bounds.x1, 549 bounds.y2 - bounds.y1, 550 src->depth, 0); 551 if (!tmp_pixmap) 552 goto bail; 553 554 tmp_box = calloc(nbox, sizeof (BoxRec)); 555 if (!tmp_box) 556 goto bail_pixmap; 557 558 /* Convert destination boxes into tmp pixmap boxes 559 */ 560 for (n = 0; n < nbox; n++) { 561 tmp_box[n].x1 = box[n].x1 - bounds.x1; 562 tmp_box[n].x2 = box[n].x2 - bounds.x1; 563 tmp_box[n].y1 = box[n].y1 - bounds.y1; 564 tmp_box[n].y2 = box[n].y2 - bounds.y1; 565 } 566 567 if (!glamor_copy_fbo_fbo_draw(src, 568 &tmp_pixmap->drawable, 569 NULL, 570 tmp_box, 571 nbox, 572 dx + bounds.x1, 573 dy + bounds.y1, 574 FALSE, FALSE, 575 0, NULL)) 576 goto bail_box; 577 578 if (!glamor_copy_fbo_fbo_draw(&tmp_pixmap->drawable, 579 dst, 580 gc, 581 box, 582 nbox, 583 -bounds.x1, 584 -bounds.y1, 585 FALSE, FALSE, 586 bitplane, closure)) 587 goto bail_box; 588 589 free(tmp_box); 590 591 glamor_destroy_pixmap(tmp_pixmap); 592 593 return TRUE; 594bail_box: 595 free(tmp_box); 596bail_pixmap: 597 glamor_destroy_pixmap(tmp_pixmap); 598bail: 599 return FALSE; 600 601bail_ctx: 602 return FALSE; 603} 604 605/** 606 * Returns TRUE if the copy has to be implemented with 607 * glamor_copy_fbo_fbo_temp() instead of glamor_copy_fbo_fbo(). 608 * 609 * If the src and dst are in the same pixmap, then glamor_copy_fbo_fbo()'s 610 * sampling would give undefined results (since the same texture would be 611 * bound as an FBO destination and as a texture source). However, if we 612 * have GL_NV_texture_barrier, we can take advantage of the exception it 613 * added: 614 * 615 * "- If a texel has been written, then in order to safely read the result 616 * a texel fetch must be in a subsequent Draw separated by the command 617 * 618 * void TextureBarrierNV(void); 619 * 620 * TextureBarrierNV() will guarantee that writes have completed and caches 621 * have been invalidated before subsequent Draws are executed." 622 */ 623static Bool 624glamor_copy_needs_temp(DrawablePtr src, 625 DrawablePtr dst, 626 BoxPtr box, 627 int nbox, 628 int dx, 629 int dy) 630{ 631 PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); 632 PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); 633 ScreenPtr screen = dst->pScreen; 634 glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); 635 int n; 636 int dst_off_x, dst_off_y; 637 int src_off_x, src_off_y; 638 BoxRec bounds; 639 640 if (src_pixmap != dst_pixmap) 641 return FALSE; 642 643 if (nbox == 0) 644 return FALSE; 645 646 if (!glamor_priv->has_nv_texture_barrier) 647 return TRUE; 648 649 if (!glamor_priv->has_mesa_tile_raster_order) { 650 glamor_get_drawable_deltas(src, src_pixmap, &src_off_x, &src_off_y); 651 glamor_get_drawable_deltas(dst, dst_pixmap, &dst_off_x, &dst_off_y); 652 653 bounds = box[0]; 654 for (n = 1; n < nbox; n++) { 655 bounds.x1 = min(bounds.x1, box[n].x1); 656 bounds.y1 = min(bounds.y1, box[n].y1); 657 658 bounds.x2 = max(bounds.x2, box[n].x2); 659 bounds.y2 = max(bounds.y2, box[n].y2); 660 } 661 662 /* Check to see if the pixmap-relative boxes overlap in both X and Y, 663 * in which case we can't rely on NV_texture_barrier and must 664 * make a temporary copy 665 * 666 * dst.x1 < src.x2 && 667 * src.x1 < dst.x2 && 668 * 669 * dst.y1 < src.y2 && 670 * src.y1 < dst.y2 671 */ 672 if (bounds.x1 + dst_off_x < bounds.x2 + dx + src_off_x && 673 bounds.x1 + dx + src_off_x < bounds.x2 + dst_off_x && 674 675 bounds.y1 + dst_off_y < bounds.y2 + dy + src_off_y && 676 bounds.y1 + dy + src_off_y < bounds.y2 + dst_off_y) { 677 return TRUE; 678 } 679 } 680 681 glTextureBarrierNV(); 682 683 return FALSE; 684} 685 686static Bool 687glamor_copy_gl(DrawablePtr src, 688 DrawablePtr dst, 689 GCPtr gc, 690 BoxPtr box, 691 int nbox, 692 int dx, 693 int dy, 694 Bool reverse, 695 Bool upsidedown, 696 Pixel bitplane, 697 void *closure) 698{ 699 PixmapPtr src_pixmap = glamor_get_drawable_pixmap(src); 700 PixmapPtr dst_pixmap = glamor_get_drawable_pixmap(dst); 701 glamor_pixmap_private *src_priv = glamor_get_pixmap_private(src_pixmap); 702 glamor_pixmap_private *dst_priv = glamor_get_pixmap_private(dst_pixmap); 703 704 if (GLAMOR_PIXMAP_PRIV_HAS_FBO(dst_priv)) { 705 if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv)) { 706 if (glamor_copy_needs_temp(src, dst, box, nbox, dx, dy)) 707 return glamor_copy_fbo_fbo_temp(src, dst, gc, box, nbox, dx, dy, 708 reverse, upsidedown, bitplane, closure); 709 else 710 return glamor_copy_fbo_fbo_draw(src, dst, gc, box, nbox, dx, dy, 711 reverse, upsidedown, bitplane, closure); 712 } 713 714 return glamor_copy_cpu_fbo(src, dst, gc, box, nbox, dx, dy, 715 reverse, upsidedown, bitplane, closure); 716 } else if (GLAMOR_PIXMAP_PRIV_HAS_FBO(src_priv) && 717 dst_priv->type != GLAMOR_DRM_ONLY && 718 bitplane == 0) { 719 return glamor_copy_fbo_cpu(src, dst, gc, box, nbox, dx, dy, 720 reverse, upsidedown, bitplane, closure); 721 } 722 return FALSE; 723} 724 725void 726glamor_copy(DrawablePtr src, 727 DrawablePtr dst, 728 GCPtr gc, 729 BoxPtr box, 730 int nbox, 731 int dx, 732 int dy, 733 Bool reverse, 734 Bool upsidedown, 735 Pixel bitplane, 736 void *closure) 737{ 738 if (nbox == 0) 739 return; 740 741 if (glamor_copy_gl(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure)) 742 return; 743 glamor_copy_bail(src, dst, gc, box, nbox, dx, dy, reverse, upsidedown, bitplane, closure); 744} 745 746RegionPtr 747glamor_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 748 int srcx, int srcy, int width, int height, int dstx, int dsty) 749{ 750 return miDoCopy(src, dst, gc, 751 srcx, srcy, width, height, 752 dstx, dsty, glamor_copy, 0, NULL); 753} 754 755RegionPtr 756glamor_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 757 int srcx, int srcy, int width, int height, int dstx, int dsty, 758 unsigned long bitplane) 759{ 760 if ((bitplane & FbFullMask(src->depth)) == 0) 761 return miHandleExposures(src, dst, gc, 762 srcx, srcy, width, height, dstx, dsty); 763 return miDoCopy(src, dst, gc, 764 srcx, srcy, width, height, 765 dstx, dsty, glamor_copy, bitplane, NULL); 766} 767 768void 769glamor_copy_window(WindowPtr window, DDXPointRec old_origin, RegionPtr src_region) 770{ 771 PixmapPtr pixmap = glamor_get_drawable_pixmap(&window->drawable); 772 DrawablePtr drawable = &pixmap->drawable; 773 RegionRec dst_region; 774 int dx, dy; 775 776 dx = old_origin.x - window->drawable.x; 777 dy = old_origin.y - window->drawable.y; 778 RegionTranslate(src_region, -dx, -dy); 779 780 RegionNull(&dst_region); 781 782 RegionIntersect(&dst_region, &window->borderClip, src_region); 783 784#ifdef COMPOSITE 785 if (pixmap->screen_x || pixmap->screen_y) 786 RegionTranslate(&dst_region, -pixmap->screen_x, -pixmap->screen_y); 787#endif 788 789 miCopyRegion(drawable, drawable, 790 0, &dst_region, dx, dy, glamor_copy, 0, 0); 791 792 RegionUninit(&dst_region); 793} 794