sna_io.c revision 13496ba1
1/* 2 * Copyright (c) 2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Chris Wilson <chris@chris-wilson.co.uk> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "sna.h" 33#include "sna_render.h" 34#include "sna_reg.h" 35 36#include <sys/mman.h> 37 38#define PITCH(x, y) ALIGN((x)*(y), 4) 39 40#define FORCE_INPLACE 0 /* 1 upload directly, -1 force indirect */ 41 42/* XXX Need to avoid using GTT fenced access for I915_TILING_Y on 855GM */ 43 44static inline bool upload_too_large(struct sna *sna, int width, int height) 45{ 46 return width * height * 4 > sna->kgem.max_upload_tile_size; 47} 48 49static inline bool must_tile(struct sna *sna, int width, int height) 50{ 51 return (width > sna->render.max_3d_size || 52 height > sna->render.max_3d_size || 53 upload_too_large(sna, width, height)); 54} 55 56static bool download_inplace__cpu(struct kgem *kgem, 57 PixmapPtr p, struct kgem_bo *bo, 58 const BoxRec *box, int nbox) 59{ 60 BoxRec extents; 61 62 switch (bo->tiling) { 63 case I915_TILING_X: 64 if (!kgem->memcpy_from_tiled_x) 65 return false; 66 case I915_TILING_NONE: 67 break; 68 default: 69 return false; 70 } 71 72 if (!kgem_bo_can_map__cpu(kgem, bo, false)) 73 return false; 74 75 if (kgem->has_llc) 76 return true; 77 78 extents = *box; 79 while (--nbox) { 80 ++box; 81 if (box->x1 < extents.x1) 82 extents.x1 = box->x1; 83 if (box->x2 > extents.x2) 84 extents.x2 = box->x2; 85 extents.y2 = box->y2; 86 } 87 88 if (extents.x2 - extents.x1 == p->drawable.width && 89 extents.y2 - extents.y1 == p->drawable.height) 90 return true; 91 92 return __kgem_bo_size(bo) <= PAGE_SIZE; 93} 94 95static bool 96read_boxes_inplace__cpu(struct kgem *kgem, 97 PixmapPtr pixmap, struct kgem_bo *bo, 98 const BoxRec *box, int n) 99{ 100 int bpp = pixmap->drawable.bitsPerPixel; 101 void *src, *dst = pixmap->devPrivate.ptr; 102 int src_pitch = bo->pitch; 103 int dst_pitch = pixmap->devKind; 104 105 if (!download_inplace__cpu(kgem, dst, bo, box, n)) 106 return false; 107 108 assert(kgem_bo_can_map__cpu(kgem, bo, false)); 109 assert(bo->tiling != I915_TILING_Y); 110 111 src = kgem_bo_map__cpu(kgem, bo); 112 if (src == NULL) 113 return false; 114 115 kgem_bo_sync__cpu_full(kgem, bo, 0); 116 117 if (sigtrap_get()) 118 return false; 119 120 DBG(("%s x %d\n", __FUNCTION__, n)); 121 122 if (bo->tiling == I915_TILING_X) { 123 do { 124 memcpy_from_tiled_x(kgem, src, dst, bpp, src_pitch, dst_pitch, 125 box->x1, box->y1, 126 box->x1, box->y1, 127 box->x2 - box->x1, box->y2 - box->y1); 128 box++; 129 } while (--n); 130 } else { 131 do { 132 memcpy_blt(src, dst, bpp, src_pitch, dst_pitch, 133 box->x1, box->y1, 134 box->x1, box->y1, 135 box->x2 - box->x1, box->y2 - box->y1); 136 box++; 137 } while (--n); 138 } 139 140 sigtrap_put(); 141 return true; 142} 143 144static void read_boxes_inplace(struct kgem *kgem, 145 PixmapPtr pixmap, struct kgem_bo *bo, 146 const BoxRec *box, int n) 147{ 148 int bpp = pixmap->drawable.bitsPerPixel; 149 void *src, *dst = pixmap->devPrivate.ptr; 150 int src_pitch = bo->pitch; 151 int dst_pitch = pixmap->devKind; 152 153 if (read_boxes_inplace__cpu(kgem, pixmap, bo, box, n)) 154 return; 155 156 DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling)); 157 158 if (!kgem_bo_can_map(kgem, bo)) 159 return; 160 161 kgem_bo_submit(kgem, bo); 162 163 src = kgem_bo_map(kgem, bo); 164 if (src == NULL) 165 return; 166 167 if (sigtrap_get()) 168 return; 169 170 assert(src != dst); 171 do { 172 DBG(("%s: copying box (%d, %d), (%d, %d)\n", 173 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 174 175 assert(box->x2 > box->x1); 176 assert(box->y2 > box->y1); 177 178 assert(box->x1 >= 0); 179 assert(box->y1 >= 0); 180 assert(box->x2 <= pixmap->drawable.width); 181 assert(box->y2 <= pixmap->drawable.height); 182 183 assert(box->x1 >= 0); 184 assert(box->y1 >= 0); 185 assert(box->x2 <= pixmap->drawable.width); 186 assert(box->y2 <= pixmap->drawable.height); 187 188 memcpy_blt(src, dst, bpp, 189 src_pitch, dst_pitch, 190 box->x1, box->y1, 191 box->x1, box->y1, 192 box->x2 - box->x1, box->y2 - box->y1); 193 box++; 194 } while (--n); 195 196 sigtrap_put(); 197} 198 199static bool download_inplace(struct kgem *kgem, 200 PixmapPtr p, struct kgem_bo *bo, 201 const BoxRec *box, int nbox) 202{ 203 bool cpu; 204 205 if (unlikely(kgem->wedged)) 206 return true; 207 208 cpu = download_inplace__cpu(kgem, p, bo, box, nbox); 209 if (!cpu && !kgem_bo_can_map(kgem, bo)) 210 return false; 211 212 if (FORCE_INPLACE) 213 return FORCE_INPLACE > 0; 214 215 if (cpu) 216 return true; 217 218 if (kgem->can_blt_cpu && kgem->max_cpu_size) 219 return false; 220 221 return !__kgem_bo_is_busy(kgem, bo); 222} 223 224void sna_read_boxes(struct sna *sna, PixmapPtr dst, struct kgem_bo *src_bo, 225 const BoxRec *box, int nbox) 226{ 227 struct kgem *kgem = &sna->kgem; 228 struct kgem_bo *dst_bo; 229 BoxRec extents; 230 const BoxRec *tmp_box; 231 int tmp_nbox; 232 void *ptr; 233 int src_pitch, cpp, offset; 234 int n, cmd, br13; 235 bool can_blt; 236 237 DBG(("%s x %d, src=(handle=%d), dst=(size=(%d, %d)\n", 238 __FUNCTION__, nbox, src_bo->handle, 239 dst->drawable.width, dst->drawable.height)); 240 241#ifndef NDEBUG 242 for (n = 0; n < nbox; n++) { 243 if (box[n].x1 < 0 || box[n].y1 < 0 || 244 box[n].x2 * dst->drawable.bitsPerPixel/8 > src_bo->pitch || 245 box[n].y2 * src_bo->pitch > kgem_bo_size(src_bo)) 246 { 247 FatalError("source out-of-bounds box[%d]=(%d, %d), (%d, %d), pitch=%d, size=%d\n", n, 248 box[n].x1, box[n].y1, 249 box[n].x2, box[n].y2, 250 src_bo->pitch, kgem_bo_size(src_bo)); 251 } 252 } 253#endif 254 255 /* XXX The gpu is faster to perform detiling in bulk, but takes 256 * longer to setup and retrieve the results, with an additional 257 * copy. The long term solution is to use snoopable bo and avoid 258 * this path. 259 */ 260 261 if (download_inplace(kgem, dst, src_bo, box, nbox)) { 262fallback: 263 read_boxes_inplace(kgem, dst, src_bo, box, nbox); 264 return; 265 } 266 267 can_blt = kgem_bo_can_blt(kgem, src_bo) && 268 (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 269 extents = box[0]; 270 for (n = 1; n < nbox; n++) { 271 if (box[n].x1 < extents.x1) 272 extents.x1 = box[n].x1; 273 if (box[n].x2 > extents.x2) 274 extents.x2 = box[n].x2; 275 276 if (can_blt) 277 can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 278 279 if (box[n].y1 < extents.y1) 280 extents.y1 = box[n].y1; 281 if (box[n].y2 > extents.y2) 282 extents.y2 = box[n].y2; 283 } 284 if (kgem_bo_can_map(kgem, src_bo)) { 285 /* Is it worth detiling? */ 286 if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096) 287 goto fallback; 288 } 289 290 /* Try to avoid switching rings... */ 291 if (!can_blt || kgem->ring == KGEM_RENDER || 292 upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { 293 DrawableRec tmp; 294 295 tmp.width = extents.x2 - extents.x1; 296 tmp.height = extents.y2 - extents.y1; 297 tmp.depth = dst->drawable.depth; 298 tmp.bitsPerPixel = dst->drawable.bitsPerPixel; 299 300 assert(tmp.width); 301 assert(tmp.height); 302 303 if (must_tile(sna, tmp.width, tmp.height)) { 304 BoxRec tile, stack[64], *clipped, *c; 305 int step; 306 307 if (n > ARRAY_SIZE(stack)) { 308 clipped = malloc(sizeof(BoxRec) * n); 309 if (clipped == NULL) 310 goto fallback; 311 } else 312 clipped = stack; 313 314 step = MIN(sna->render.max_3d_size, 315 8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel); 316 while (step * step * 4 > sna->kgem.max_upload_tile_size) 317 step /= 2; 318 319 DBG(("%s: tiling download, using %dx%d tiles\n", 320 __FUNCTION__, step, step)); 321 assert(step); 322 323 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 324 int y2 = tile.y1 + step; 325 if (y2 > extents.y2) 326 y2 = extents.y2; 327 tile.y2 = y2; 328 329 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 330 int x2 = tile.x1 + step; 331 if (x2 > extents.x2) 332 x2 = extents.x2; 333 tile.x2 = x2; 334 335 tmp.width = tile.x2 - tile.x1; 336 tmp.height = tile.y2 - tile.y1; 337 338 c = clipped; 339 for (n = 0; n < nbox; n++) { 340 *c = box[n]; 341 if (!box_intersect(c, &tile)) 342 continue; 343 344 DBG(("%s: box(%d, %d), (%d, %d),, dst=(%d, %d)\n", 345 __FUNCTION__, 346 c->x1, c->y1, 347 c->x2, c->y2, 348 c->x1 - tile.x1, 349 c->y1 - tile.y1)); 350 c++; 351 } 352 if (c == clipped) 353 continue; 354 355 dst_bo = kgem_create_buffer_2d(kgem, 356 tmp.width, 357 tmp.height, 358 tmp.bitsPerPixel, 359 KGEM_BUFFER_LAST, 360 &ptr); 361 if (!dst_bo) { 362 if (clipped != stack) 363 free(clipped); 364 goto fallback; 365 } 366 367 if (!sna->render.copy_boxes(sna, GXcopy, 368 &dst->drawable, src_bo, 0, 0, 369 &tmp, dst_bo, -tile.x1, -tile.y1, 370 clipped, c-clipped, COPY_LAST)) { 371 kgem_bo_destroy(&sna->kgem, dst_bo); 372 if (clipped != stack) 373 free(clipped); 374 goto fallback; 375 } 376 377 kgem_bo_submit(&sna->kgem, dst_bo); 378 kgem_buffer_read_sync(kgem, dst_bo); 379 380 if (sigtrap_get() == 0) { 381 while (c-- != clipped) { 382 memcpy_blt(ptr, dst->devPrivate.ptr, tmp.bitsPerPixel, 383 dst_bo->pitch, dst->devKind, 384 c->x1 - tile.x1, 385 c->y1 - tile.y1, 386 c->x1, c->y1, 387 c->x2 - c->x1, 388 c->y2 - c->y1); 389 } 390 sigtrap_put(); 391 } 392 393 kgem_bo_destroy(&sna->kgem, dst_bo); 394 } 395 } 396 397 if (clipped != stack) 398 free(clipped); 399 } else { 400 dst_bo = kgem_create_buffer_2d(kgem, 401 tmp.width, 402 tmp.height, 403 tmp.bitsPerPixel, 404 KGEM_BUFFER_LAST, 405 &ptr); 406 if (!dst_bo) 407 goto fallback; 408 409 if (!sna->render.copy_boxes(sna, GXcopy, 410 &dst->drawable, src_bo, 0, 0, 411 &tmp, dst_bo, -extents.x1, -extents.y1, 412 box, nbox, COPY_LAST)) { 413 kgem_bo_destroy(&sna->kgem, dst_bo); 414 goto fallback; 415 } 416 417 kgem_bo_submit(&sna->kgem, dst_bo); 418 kgem_buffer_read_sync(kgem, dst_bo); 419 420 if (sigtrap_get() == 0) { 421 for (n = 0; n < nbox; n++) { 422 memcpy_blt(ptr, dst->devPrivate.ptr, tmp.bitsPerPixel, 423 dst_bo->pitch, dst->devKind, 424 box[n].x1 - extents.x1, 425 box[n].y1 - extents.y1, 426 box[n].x1, box[n].y1, 427 box[n].x2 - box[n].x1, 428 box[n].y2 - box[n].y1); 429 } 430 sigtrap_put(); 431 } 432 433 kgem_bo_destroy(&sna->kgem, dst_bo); 434 } 435 return; 436 } 437 438 /* count the total number of bytes to be read and allocate a bo */ 439 cpp = dst->drawable.bitsPerPixel / 8; 440 offset = 0; 441 for (n = 0; n < nbox; n++) { 442 int height = box[n].y2 - box[n].y1; 443 int width = box[n].x2 - box[n].x1; 444 offset += PITCH(width, cpp) * height; 445 } 446 447 DBG((" read buffer size=%d\n", offset)); 448 449 dst_bo = kgem_create_buffer(kgem, offset, KGEM_BUFFER_LAST, &ptr); 450 if (!dst_bo) { 451 read_boxes_inplace(kgem, dst, src_bo, box, nbox); 452 return; 453 } 454 455 cmd = XY_SRC_COPY_BLT_CMD; 456 src_pitch = src_bo->pitch; 457 if (kgem->gen >= 040 && src_bo->tiling) { 458 cmd |= BLT_SRC_TILED; 459 src_pitch >>= 2; 460 } 461 462 br13 = 0xcc << 16; 463 switch (cpp) { 464 default: 465 case 4: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 466 br13 |= 1 << 25; /* RGB8888 */ 467 case 2: br13 |= 1 << 24; /* RGB565 */ 468 case 1: break; 469 } 470 471 kgem_set_mode(kgem, KGEM_BLT, dst_bo); 472 if (!kgem_check_batch(kgem, 10) || 473 !kgem_check_reloc_and_exec(kgem, 2) || 474 !kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) { 475 kgem_submit(kgem); 476 if (!kgem_check_many_bo_fenced(kgem, dst_bo, src_bo, NULL)) 477 goto fallback; 478 _kgem_set_mode(kgem, KGEM_BLT); 479 } 480 481 tmp_nbox = nbox; 482 tmp_box = box; 483 offset = 0; 484 if (sna->kgem.gen >= 0100) { 485 cmd |= 8; 486 do { 487 int nbox_this_time, rem; 488 489 nbox_this_time = tmp_nbox; 490 rem = kgem_batch_space(kgem); 491 if (10*nbox_this_time > rem) 492 nbox_this_time = rem / 8; 493 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 494 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 495 assert(nbox_this_time); 496 tmp_nbox -= nbox_this_time; 497 498 assert(kgem->mode == KGEM_BLT); 499 for (n = 0; n < nbox_this_time; n++) { 500 int height = tmp_box[n].y2 - tmp_box[n].y1; 501 int width = tmp_box[n].x2 - tmp_box[n].x1; 502 int pitch = PITCH(width, cpp); 503 uint32_t *b = kgem->batch + kgem->nbatch; 504 505 DBG((" blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n", 506 offset, 507 tmp_box[n].x1, tmp_box[n].y1, 508 width, height, pitch)); 509 510 assert(tmp_box[n].x1 >= 0); 511 assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch); 512 assert(tmp_box[n].y1 >= 0); 513 assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo)); 514 515 b[0] = cmd; 516 b[1] = br13 | pitch; 517 b[2] = 0; 518 b[3] = height << 16 | width; 519 *(uint64_t *)(b+4) = 520 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 521 I915_GEM_DOMAIN_RENDER << 16 | 522 I915_GEM_DOMAIN_RENDER | 523 KGEM_RELOC_FENCED, 524 offset); 525 b[6] = tmp_box[n].y1 << 16 | tmp_box[n].x1; 526 b[7] = src_pitch; 527 *(uint64_t *)(b+8) = 528 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 529 I915_GEM_DOMAIN_RENDER << 16 | 530 KGEM_RELOC_FENCED, 531 0); 532 kgem->nbatch += 10; 533 534 offset += pitch * height; 535 } 536 537 _kgem_submit(kgem); 538 if (!tmp_nbox) 539 break; 540 541 _kgem_set_mode(kgem, KGEM_BLT); 542 tmp_box += nbox_this_time; 543 } while (1); 544 } else { 545 cmd |= 6; 546 do { 547 int nbox_this_time, rem; 548 549 nbox_this_time = tmp_nbox; 550 rem = kgem_batch_space(kgem); 551 if (8*nbox_this_time > rem) 552 nbox_this_time = rem / 8; 553 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 554 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 555 assert(nbox_this_time); 556 tmp_nbox -= nbox_this_time; 557 558 assert(kgem->mode == KGEM_BLT); 559 for (n = 0; n < nbox_this_time; n++) { 560 int height = tmp_box[n].y2 - tmp_box[n].y1; 561 int width = tmp_box[n].x2 - tmp_box[n].x1; 562 int pitch = PITCH(width, cpp); 563 uint32_t *b = kgem->batch + kgem->nbatch; 564 565 DBG((" blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n", 566 offset, 567 tmp_box[n].x1, tmp_box[n].y1, 568 width, height, pitch)); 569 570 assert(tmp_box[n].x1 >= 0); 571 assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch); 572 assert(tmp_box[n].y1 >= 0); 573 assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo)); 574 575 b[0] = cmd; 576 b[1] = br13 | pitch; 577 b[2] = 0; 578 b[3] = height << 16 | width; 579 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 580 I915_GEM_DOMAIN_RENDER << 16 | 581 I915_GEM_DOMAIN_RENDER | 582 KGEM_RELOC_FENCED, 583 offset); 584 b[5] = tmp_box[n].y1 << 16 | tmp_box[n].x1; 585 b[6] = src_pitch; 586 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 587 I915_GEM_DOMAIN_RENDER << 16 | 588 KGEM_RELOC_FENCED, 589 0); 590 kgem->nbatch += 8; 591 592 offset += pitch * height; 593 } 594 595 _kgem_submit(kgem); 596 if (!tmp_nbox) 597 break; 598 599 _kgem_set_mode(kgem, KGEM_BLT); 600 tmp_box += nbox_this_time; 601 } while (1); 602 } 603 assert(offset == __kgem_buffer_size(dst_bo)); 604 605 kgem_buffer_read_sync(kgem, dst_bo); 606 607 if (sigtrap_get() == 0) { 608 char *src = ptr; 609 do { 610 int height = box->y2 - box->y1; 611 int width = box->x2 - box->x1; 612 int pitch = PITCH(width, cpp); 613 614 DBG((" copy offset %lx [%08x...%08x...%08x]: (%d, %d) x (%d, %d), src pitch=%d, dst pitch=%d, bpp=%d\n", 615 (long)((char *)src - (char *)ptr), 616 *(uint32_t*)src, *(uint32_t*)(src+pitch*height/2 + pitch/2 - 4), *(uint32_t*)(src+pitch*height - 4), 617 box->x1, box->y1, 618 width, height, 619 pitch, dst->devKind, cpp*8)); 620 621 assert(box->x1 >= 0); 622 assert(box->x2 <= dst->drawable.width); 623 assert(box->y1 >= 0); 624 assert(box->y2 <= dst->drawable.height); 625 626 memcpy_blt(src, dst->devPrivate.ptr, cpp*8, 627 pitch, dst->devKind, 628 0, 0, 629 box->x1, box->y1, 630 width, height); 631 box++; 632 633 src += pitch * height; 634 } while (--nbox); 635 assert(src - (char *)ptr == __kgem_buffer_size(dst_bo)); 636 sigtrap_put(); 637 } 638 kgem_bo_destroy(kgem, dst_bo); 639 sna->blt_state.fill_bo = 0; 640} 641 642static bool upload_inplace__tiled(struct kgem *kgem, struct kgem_bo *bo) 643{ 644 DBG(("%s: tiling=%d\n", __FUNCTION__, bo->tiling)); 645 switch (bo->tiling) { 646 case I915_TILING_Y: 647 return false; 648 case I915_TILING_X: 649 if (!kgem->memcpy_to_tiled_x) 650 return false; 651 default: 652 break; 653 } 654 655 if (kgem->has_wc_mmap) 656 return true; 657 658 return kgem_bo_can_map__cpu(kgem, bo, true); 659} 660 661static bool 662write_boxes_inplace__tiled(struct kgem *kgem, 663 const uint8_t *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 664 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 665 const BoxRec *box, int n) 666{ 667 uint8_t *dst; 668 669 assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true)); 670 assert(bo->tiling != I915_TILING_Y); 671 672 if (kgem_bo_can_map__cpu(kgem, bo, true)) { 673 dst = kgem_bo_map__cpu(kgem, bo); 674 if (dst == NULL) 675 return false; 676 677 kgem_bo_sync__cpu(kgem, bo); 678 } else { 679 dst = kgem_bo_map__wc(kgem, bo); 680 if (dst == NULL) 681 return false; 682 683 kgem_bo_sync__gtt(kgem, bo); 684 } 685 686 if (sigtrap_get()) 687 return false; 688 689 if (bo->tiling) { 690 do { 691 memcpy_to_tiled_x(kgem, src, dst, bpp, stride, bo->pitch, 692 box->x1 + src_dx, box->y1 + src_dy, 693 box->x1 + dst_dx, box->y1 + dst_dy, 694 box->x2 - box->x1, box->y2 - box->y1); 695 box++; 696 } while (--n); 697 } else { 698 do { 699 memcpy_blt(src, dst, bpp, stride, bo->pitch, 700 box->x1 + src_dx, box->y1 + src_dy, 701 box->x1 + dst_dx, box->y1 + dst_dy, 702 box->x2 - box->x1, box->y2 - box->y1); 703 box++; 704 } while (--n); 705 } 706 707 sigtrap_put(); 708 return true; 709} 710 711static bool write_boxes_inplace(struct kgem *kgem, 712 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 713 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 714 const BoxRec *box, int n) 715{ 716 void *dst; 717 718 DBG(("%s x %d, handle=%d, tiling=%d\n", 719 __FUNCTION__, n, bo->handle, bo->tiling)); 720 721 if (upload_inplace__tiled(kgem, bo) && 722 write_boxes_inplace__tiled(kgem, src, stride, bpp, src_dx, src_dy, 723 bo, dst_dx, dst_dy, box, n)) 724 return true; 725 726 if (!kgem_bo_can_map(kgem, bo)) 727 return false; 728 729 kgem_bo_submit(kgem, bo); 730 731 dst = kgem_bo_map(kgem, bo); 732 if (dst == NULL) 733 return false; 734 735 assert(dst != src); 736 737 if (sigtrap_get()) 738 return false; 739 740 do { 741 DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__, 742 box->x1 + src_dx, box->y1 + src_dy, 743 box->x1 + dst_dx, box->y1 + dst_dy, 744 box->x2 - box->x1, box->y2 - box->y1, 745 bpp, stride, bo->pitch)); 746 747 assert(box->x2 > box->x1); 748 assert(box->y2 > box->y1); 749 750 assert(box->x1 + dst_dx >= 0); 751 assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch); 752 assert(box->y1 + dst_dy >= 0); 753 assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo)); 754 755 assert(box->x1 + src_dx >= 0); 756 assert((box->x2 + src_dx)*bpp <= 8*stride); 757 assert(box->y1 + src_dy >= 0); 758 759 memcpy_blt(src, dst, bpp, 760 stride, bo->pitch, 761 box->x1 + src_dx, box->y1 + src_dy, 762 box->x1 + dst_dx, box->y1 + dst_dy, 763 box->x2 - box->x1, box->y2 - box->y1); 764 box++; 765 } while (--n); 766 767 sigtrap_put(); 768 return true; 769} 770 771static bool __upload_inplace(struct kgem *kgem, 772 struct kgem_bo *bo, 773 const BoxRec *box, 774 int n, int bpp) 775{ 776 unsigned int bytes; 777 778 if (FORCE_INPLACE) 779 return FORCE_INPLACE > 0; 780 781 /* If we are writing through the GTT, check first if we might be 782 * able to almagamate a series of small writes into a single 783 * operation. 784 */ 785 bytes = 0; 786 while (n--) { 787 bytes += (box->x2 - box->x1) * (box->y2 - box->y1); 788 box++; 789 } 790 if (__kgem_bo_is_busy(kgem, bo)) 791 return bytes * bpp >> 12 >= kgem->half_cpu_cache_pages; 792 else 793 return bytes * bpp >> 12; 794} 795 796static bool upload_inplace(struct kgem *kgem, 797 struct kgem_bo *bo, 798 const BoxRec *box, 799 int n, int bpp) 800{ 801 if (unlikely(kgem->wedged)) 802 return true; 803 804 if (!kgem_bo_can_map(kgem, bo) && !upload_inplace__tiled(kgem, bo)) 805 return false; 806 807 return __upload_inplace(kgem, bo, box, n,bpp); 808} 809 810bool sna_write_boxes(struct sna *sna, PixmapPtr dst, 811 struct kgem_bo * const dst_bo, int16_t const dst_dx, int16_t const dst_dy, 812 const void * const src, int const stride, int16_t const src_dx, int16_t const src_dy, 813 const BoxRec *box, int nbox) 814{ 815 struct kgem *kgem = &sna->kgem; 816 struct kgem_bo *src_bo; 817 BoxRec extents; 818 void *ptr; 819 int offset; 820 int n, cmd, br13; 821 bool can_blt; 822 823 DBG(("%s x %d, src stride=%d, src dx=(%d, %d)\n", __FUNCTION__, nbox, stride, src_dx, src_dy)); 824 825 if (upload_inplace(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) && 826 write_boxes_inplace(kgem, 827 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 828 dst_bo, dst_dx, dst_dy, 829 box, nbox)) 830 return true; 831 832 if (wedged(sna)) 833 return false; 834 835 can_blt = kgem_bo_can_blt(kgem, dst_bo) && 836 (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 837 extents = box[0]; 838 for (n = 1; n < nbox; n++) { 839 if (box[n].x1 < extents.x1) 840 extents.x1 = box[n].x1; 841 if (box[n].x2 > extents.x2) 842 extents.x2 = box[n].x2; 843 844 if (can_blt) 845 can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 846 847 if (box[n].y1 < extents.y1) 848 extents.y1 = box[n].y1; 849 if (box[n].y2 > extents.y2) 850 extents.y2 = box[n].y2; 851 } 852 853 /* Try to avoid switching rings... */ 854 if (!can_blt || kgem->ring == KGEM_RENDER || 855 upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { 856 DrawableRec tmp; 857 858 tmp.width = extents.x2 - extents.x1; 859 tmp.height = extents.y2 - extents.y1; 860 tmp.depth = dst->drawable.depth; 861 tmp.bitsPerPixel = dst->drawable.bitsPerPixel; 862 863 assert(tmp.width); 864 assert(tmp.height); 865 866 DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n", 867 __FUNCTION__, 868 extents.x1, extents.y1, 869 tmp.width, tmp.height, 870 sna->render.max_3d_size, sna->render.max_3d_size)); 871 if (must_tile(sna, tmp.width, tmp.height)) { 872 BoxRec tile, stack[64], *clipped; 873 int cpp, step; 874 875tile: 876 cpp = dst->drawable.bitsPerPixel / 8; 877 step = MIN(sna->render.max_3d_size, 878 (MAXSHORT&~63) / cpp); 879 while (step * step * cpp > sna->kgem.max_upload_tile_size) 880 step /= 2; 881 882 if (step * cpp > 4096) 883 step = 4096 / cpp; 884 assert(step); 885 886 DBG(("%s: tiling upload, using %dx%d tiles\n", 887 __FUNCTION__, step, step)); 888 889 if (n > ARRAY_SIZE(stack)) { 890 clipped = malloc(sizeof(BoxRec) * n); 891 if (clipped == NULL) 892 goto fallback; 893 } else 894 clipped = stack; 895 896 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 897 int y2 = tile.y1 + step; 898 if (y2 > extents.y2) 899 y2 = extents.y2; 900 tile.y2 = y2; 901 902 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 903 int x2 = tile.x1 + step; 904 if (x2 > extents.x2) 905 x2 = extents.x2; 906 tile.x2 = x2; 907 908 tmp.width = tile.x2 - tile.x1; 909 tmp.height = tile.y2 - tile.y1; 910 911 src_bo = kgem_create_buffer_2d(kgem, 912 tmp.width, 913 tmp.height, 914 tmp.bitsPerPixel, 915 KGEM_BUFFER_WRITE_INPLACE, 916 &ptr); 917 if (!src_bo) { 918 if (clipped != stack) 919 free(clipped); 920 goto fallback; 921 } 922 923 if (sigtrap_get() == 0) { 924 BoxRec *c = clipped; 925 for (n = 0; n < nbox; n++) { 926 *c = box[n]; 927 if (!box_intersect(c, &tile)) 928 continue; 929 930 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 931 __FUNCTION__, 932 c->x1, c->y1, 933 c->x2, c->y2, 934 src_dx, src_dy, 935 c->x1 - tile.x1, 936 c->y1 - tile.y1)); 937 memcpy_blt(src, ptr, tmp.bitsPerPixel, 938 stride, src_bo->pitch, 939 c->x1 + src_dx, 940 c->y1 + src_dy, 941 c->x1 - tile.x1, 942 c->y1 - tile.y1, 943 c->x2 - c->x1, 944 c->y2 - c->y1); 945 c++; 946 } 947 948 if (c != clipped) 949 n = sna->render.copy_boxes(sna, GXcopy, 950 &tmp, src_bo, -tile.x1, -tile.y1, 951 &dst->drawable, dst_bo, dst_dx, dst_dy, 952 clipped, c - clipped, 0); 953 else 954 n = 1; 955 sigtrap_put(); 956 } else 957 n = 0; 958 959 kgem_bo_destroy(&sna->kgem, src_bo); 960 961 if (!n) { 962 if (clipped != stack) 963 free(clipped); 964 goto fallback; 965 } 966 } 967 } 968 969 if (clipped != stack) 970 free(clipped); 971 } else { 972 src_bo = kgem_create_buffer_2d(kgem, 973 tmp.width, 974 tmp.height, 975 tmp.bitsPerPixel, 976 KGEM_BUFFER_WRITE_INPLACE, 977 &ptr); 978 if (!src_bo) 979 goto fallback; 980 981 if (sigtrap_get() == 0) { 982 for (n = 0; n < nbox; n++) { 983 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 984 __FUNCTION__, 985 box[n].x1, box[n].y1, 986 box[n].x2, box[n].y2, 987 src_dx, src_dy, 988 box[n].x1 - extents.x1, 989 box[n].y1 - extents.y1)); 990 memcpy_blt(src, ptr, tmp.bitsPerPixel, 991 stride, src_bo->pitch, 992 box[n].x1 + src_dx, 993 box[n].y1 + src_dy, 994 box[n].x1 - extents.x1, 995 box[n].y1 - extents.y1, 996 box[n].x2 - box[n].x1, 997 box[n].y2 - box[n].y1); 998 } 999 1000 n = sna->render.copy_boxes(sna, GXcopy, 1001 &tmp, src_bo, -extents.x1, -extents.y1, 1002 &dst->drawable, dst_bo, dst_dx, dst_dy, 1003 box, nbox, 0); 1004 sigtrap_put(); 1005 } else 1006 n = 0; 1007 1008 kgem_bo_destroy(&sna->kgem, src_bo); 1009 1010 if (!n) 1011 goto tile; 1012 } 1013 1014 return true; 1015 } 1016 1017 cmd = XY_SRC_COPY_BLT_CMD; 1018 br13 = dst_bo->pitch; 1019 if (kgem->gen >= 040 && dst_bo->tiling) { 1020 cmd |= BLT_DST_TILED; 1021 br13 >>= 2; 1022 } 1023 br13 |= 0xcc << 16; 1024 switch (dst->drawable.bitsPerPixel) { 1025 default: 1026 case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 1027 br13 |= 1 << 25; /* RGB8888 */ 1028 case 16: br13 |= 1 << 24; /* RGB565 */ 1029 case 8: break; 1030 } 1031 1032 kgem_set_mode(kgem, KGEM_BLT, dst_bo); 1033 if (!kgem_check_batch(kgem, 10) || 1034 !kgem_check_reloc_and_exec(kgem, 2) || 1035 !kgem_check_bo_fenced(kgem, dst_bo)) { 1036 kgem_submit(kgem); 1037 if (!kgem_check_bo_fenced(kgem, dst_bo)) 1038 goto fallback; 1039 _kgem_set_mode(kgem, KGEM_BLT); 1040 } 1041 1042 if (kgem->gen >= 0100) { 1043 cmd |= 8; 1044 do { 1045 int nbox_this_time, rem; 1046 1047 nbox_this_time = nbox; 1048 rem = kgem_batch_space(kgem); 1049 if (10*nbox_this_time > rem) 1050 nbox_this_time = rem / 8; 1051 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1052 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1053 assert(nbox_this_time); 1054 nbox -= nbox_this_time; 1055 1056 /* Count the total number of bytes to be read and allocate a 1057 * single buffer large enough. Or if it is very small, combine 1058 * with other allocations. */ 1059 offset = 0; 1060 for (n = 0; n < nbox_this_time; n++) { 1061 int height = box[n].y2 - box[n].y1; 1062 int width = box[n].x2 - box[n].x1; 1063 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1064 } 1065 1066 src_bo = kgem_create_buffer(kgem, offset, 1067 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1068 &ptr); 1069 if (!src_bo) 1070 break; 1071 1072 if (sigtrap_get() == 0) { 1073 offset = 0; 1074 do { 1075 int height = box->y2 - box->y1; 1076 int width = box->x2 - box->x1; 1077 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1078 uint32_t *b; 1079 1080 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1081 __FUNCTION__, 1082 box->x1 + src_dx, box->y1 + src_dy, 1083 box->x1 + dst_dx, box->y1 + dst_dy, 1084 width, height, 1085 offset, pitch)); 1086 1087 assert(box->x1 + src_dx >= 0); 1088 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1089 assert(box->y1 + src_dy >= 0); 1090 1091 assert(box->x1 + dst_dx >= 0); 1092 assert(box->y1 + dst_dy >= 0); 1093 1094 memcpy_blt(src, (char *)ptr + offset, 1095 dst->drawable.bitsPerPixel, 1096 stride, pitch, 1097 box->x1 + src_dx, box->y1 + src_dy, 1098 0, 0, 1099 width, height); 1100 1101 assert(kgem->mode == KGEM_BLT); 1102 b = kgem->batch + kgem->nbatch; 1103 b[0] = cmd; 1104 b[1] = br13; 1105 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1106 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1107 *(uint64_t *)(b+4) = 1108 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 1109 I915_GEM_DOMAIN_RENDER << 16 | 1110 I915_GEM_DOMAIN_RENDER | 1111 KGEM_RELOC_FENCED, 1112 0); 1113 b[6] = 0; 1114 b[7] = pitch; 1115 *(uint64_t *)(b+8) = 1116 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 1117 I915_GEM_DOMAIN_RENDER << 16 | 1118 KGEM_RELOC_FENCED, 1119 offset); 1120 kgem->nbatch += 10; 1121 1122 box++; 1123 offset += pitch * height; 1124 } while (--nbox_this_time); 1125 assert(offset == __kgem_buffer_size(src_bo)); 1126 sigtrap_put(); 1127 } 1128 1129 if (nbox) { 1130 _kgem_submit(kgem); 1131 _kgem_set_mode(kgem, KGEM_BLT); 1132 } 1133 1134 kgem_bo_destroy(kgem, src_bo); 1135 } while (nbox); 1136 } else { 1137 cmd |= 6; 1138 do { 1139 int nbox_this_time, rem; 1140 1141 nbox_this_time = nbox; 1142 rem = kgem_batch_space(kgem); 1143 if (8*nbox_this_time > rem) 1144 nbox_this_time = rem / 8; 1145 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1146 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1147 assert(nbox_this_time); 1148 nbox -= nbox_this_time; 1149 1150 /* Count the total number of bytes to be read and allocate a 1151 * single buffer large enough. Or if it is very small, combine 1152 * with other allocations. */ 1153 offset = 0; 1154 for (n = 0; n < nbox_this_time; n++) { 1155 int height = box[n].y2 - box[n].y1; 1156 int width = box[n].x2 - box[n].x1; 1157 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1158 } 1159 1160 src_bo = kgem_create_buffer(kgem, offset, 1161 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1162 &ptr); 1163 if (!src_bo) 1164 break; 1165 1166 if (sigtrap_get()) { 1167 kgem_bo_destroy(kgem, src_bo); 1168 goto fallback; 1169 } 1170 1171 offset = 0; 1172 do { 1173 int height = box->y2 - box->y1; 1174 int width = box->x2 - box->x1; 1175 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1176 uint32_t *b; 1177 1178 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1179 __FUNCTION__, 1180 box->x1 + src_dx, box->y1 + src_dy, 1181 box->x1 + dst_dx, box->y1 + dst_dy, 1182 width, height, 1183 offset, pitch)); 1184 1185 assert(box->x1 + src_dx >= 0); 1186 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1187 assert(box->y1 + src_dy >= 0); 1188 1189 assert(box->x1 + dst_dx >= 0); 1190 assert(box->y1 + dst_dy >= 0); 1191 1192 memcpy_blt(src, (char *)ptr + offset, 1193 dst->drawable.bitsPerPixel, 1194 stride, pitch, 1195 box->x1 + src_dx, box->y1 + src_dy, 1196 0, 0, 1197 width, height); 1198 1199 assert(kgem->mode == KGEM_BLT); 1200 b = kgem->batch + kgem->nbatch; 1201 b[0] = cmd; 1202 b[1] = br13; 1203 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1204 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1205 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 1206 I915_GEM_DOMAIN_RENDER << 16 | 1207 I915_GEM_DOMAIN_RENDER | 1208 KGEM_RELOC_FENCED, 1209 0); 1210 b[5] = 0; 1211 b[6] = pitch; 1212 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 1213 I915_GEM_DOMAIN_RENDER << 16 | 1214 KGEM_RELOC_FENCED, 1215 offset); 1216 kgem->nbatch += 8; 1217 1218 box++; 1219 offset += pitch * height; 1220 } while (--nbox_this_time); 1221 assert(offset == __kgem_buffer_size(src_bo)); 1222 sigtrap_put(); 1223 1224 if (nbox) { 1225 _kgem_submit(kgem); 1226 _kgem_set_mode(kgem, KGEM_BLT); 1227 } 1228 1229 kgem_bo_destroy(kgem, src_bo); 1230 } while (nbox); 1231 } 1232 1233 sna->blt_state.fill_bo = 0; 1234 return true; 1235 1236fallback: 1237 return write_boxes_inplace(kgem, 1238 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1239 dst_bo, dst_dx, dst_dy, 1240 box, nbox); 1241} 1242 1243static bool 1244write_boxes_inplace__xor(struct kgem *kgem, 1245 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 1246 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 1247 const BoxRec *box, int n, 1248 uint32_t and, uint32_t or) 1249{ 1250 void *dst; 1251 1252 DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling)); 1253 1254 if (!kgem_bo_can_map(kgem, bo)) 1255 return false; 1256 1257 kgem_bo_submit(kgem, bo); 1258 1259 dst = kgem_bo_map(kgem, bo); 1260 if (dst == NULL) 1261 return false; 1262 1263 if (sigtrap_get()) 1264 return false; 1265 1266 do { 1267 DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__, 1268 box->x1 + src_dx, box->y1 + src_dy, 1269 box->x1 + dst_dx, box->y1 + dst_dy, 1270 box->x2 - box->x1, box->y2 - box->y1, 1271 bpp, stride, bo->pitch)); 1272 1273 assert(box->x2 > box->x1); 1274 assert(box->y2 > box->y1); 1275 1276 assert(box->x1 + dst_dx >= 0); 1277 assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch); 1278 assert(box->y1 + dst_dy >= 0); 1279 assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo)); 1280 1281 assert(box->x1 + src_dx >= 0); 1282 assert((box->x2 + src_dx)*bpp <= 8*stride); 1283 assert(box->y1 + src_dy >= 0); 1284 1285 memcpy_xor(src, dst, bpp, 1286 stride, bo->pitch, 1287 box->x1 + src_dx, box->y1 + src_dy, 1288 box->x1 + dst_dx, box->y1 + dst_dy, 1289 box->x2 - box->x1, box->y2 - box->y1, 1290 and, or); 1291 box++; 1292 } while (--n); 1293 1294 sigtrap_put(); 1295 return true; 1296} 1297 1298static bool upload_inplace__xor(struct kgem *kgem, 1299 struct kgem_bo *bo, 1300 const BoxRec *box, 1301 int n, int bpp) 1302{ 1303 if (unlikely(kgem->wedged)) 1304 return true; 1305 1306 if (!kgem_bo_can_map(kgem, bo)) 1307 return false; 1308 1309 return __upload_inplace(kgem, bo, box, n, bpp); 1310} 1311 1312bool sna_write_boxes__xor(struct sna *sna, PixmapPtr dst, 1313 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1314 const void *src, int stride, int16_t src_dx, int16_t src_dy, 1315 const BoxRec *box, int nbox, 1316 uint32_t and, uint32_t or) 1317{ 1318 struct kgem *kgem = &sna->kgem; 1319 struct kgem_bo *src_bo; 1320 BoxRec extents; 1321 bool can_blt; 1322 void *ptr; 1323 int offset; 1324 int n, cmd, br13; 1325 1326 DBG(("%s x %d\n", __FUNCTION__, nbox)); 1327 1328 if (upload_inplace__xor(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) && 1329 write_boxes_inplace__xor(kgem, 1330 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1331 dst_bo, dst_dx, dst_dy, 1332 box, nbox, 1333 and, or)) 1334 return true; 1335 1336 if (wedged(sna)) 1337 return false; 1338 1339 can_blt = kgem_bo_can_blt(kgem, dst_bo) && 1340 (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 1341 extents = box[0]; 1342 for (n = 1; n < nbox; n++) { 1343 if (box[n].x1 < extents.x1) 1344 extents.x1 = box[n].x1; 1345 if (box[n].x2 > extents.x2) 1346 extents.x2 = box[n].x2; 1347 1348 if (can_blt) 1349 can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 1350 1351 if (box[n].y1 < extents.y1) 1352 extents.y1 = box[n].y1; 1353 if (box[n].y2 > extents.y2) 1354 extents.y2 = box[n].y2; 1355 } 1356 1357 /* Try to avoid switching rings... */ 1358 if (!can_blt || kgem->ring == KGEM_RENDER || 1359 upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { 1360 DrawableRec tmp; 1361 1362 tmp.width = extents.x2 - extents.x1; 1363 tmp.height = extents.y2 - extents.y1; 1364 tmp.depth = dst->drawable.depth; 1365 tmp.bitsPerPixel = dst->drawable.bitsPerPixel; 1366 1367 assert(tmp.width); 1368 assert(tmp.height); 1369 1370 DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n", 1371 __FUNCTION__, 1372 extents.x1, extents.y1, 1373 tmp.width, tmp.height, 1374 sna->render.max_3d_size, sna->render.max_3d_size)); 1375 if (must_tile(sna, tmp.width, tmp.height)) { 1376 BoxRec tile, stack[64], *clipped; 1377 int step; 1378 1379tile: 1380 step = MIN(sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel, 1381 8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel); 1382 while (step * step * 4 > sna->kgem.max_upload_tile_size) 1383 step /= 2; 1384 1385 DBG(("%s: tiling upload, using %dx%d tiles\n", 1386 __FUNCTION__, step, step)); 1387 assert(step); 1388 1389 if (n > ARRAY_SIZE(stack)) { 1390 clipped = malloc(sizeof(BoxRec) * n); 1391 if (clipped == NULL) 1392 goto fallback; 1393 } else 1394 clipped = stack; 1395 1396 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 1397 int y2 = tile.y1 + step; 1398 if (y2 > extents.y2) 1399 y2 = extents.y2; 1400 tile.y2 = y2; 1401 1402 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 1403 int x2 = tile.x1 + step; 1404 if (x2 > extents.x2) 1405 x2 = extents.x2; 1406 tile.x2 = x2; 1407 1408 tmp.width = tile.x2 - tile.x1; 1409 tmp.height = tile.y2 - tile.y1; 1410 1411 src_bo = kgem_create_buffer_2d(kgem, 1412 tmp.width, 1413 tmp.height, 1414 tmp.bitsPerPixel, 1415 KGEM_BUFFER_WRITE_INPLACE, 1416 &ptr); 1417 if (!src_bo) { 1418 if (clipped != stack) 1419 free(clipped); 1420 goto fallback; 1421 } 1422 1423 if (sigtrap_get() == 0) { 1424 BoxRec *c = clipped; 1425 for (n = 0; n < nbox; n++) { 1426 *c = box[n]; 1427 if (!box_intersect(c, &tile)) 1428 continue; 1429 1430 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1431 __FUNCTION__, 1432 c->x1, c->y1, 1433 c->x2, c->y2, 1434 src_dx, src_dy, 1435 c->x1 - tile.x1, 1436 c->y1 - tile.y1)); 1437 memcpy_xor(src, ptr, tmp.bitsPerPixel, 1438 stride, src_bo->pitch, 1439 c->x1 + src_dx, 1440 c->y1 + src_dy, 1441 c->x1 - tile.x1, 1442 c->y1 - tile.y1, 1443 c->x2 - c->x1, 1444 c->y2 - c->y1, 1445 and, or); 1446 c++; 1447 } 1448 1449 if (c != clipped) 1450 n = sna->render.copy_boxes(sna, GXcopy, 1451 &tmp, src_bo, -tile.x1, -tile.y1, 1452 &dst->drawable, dst_bo, dst_dx, dst_dy, 1453 clipped, c - clipped, 0); 1454 else 1455 n = 1; 1456 1457 sigtrap_put(); 1458 } else 1459 n = 0; 1460 1461 kgem_bo_destroy(&sna->kgem, src_bo); 1462 1463 if (!n) { 1464 if (clipped != stack) 1465 free(clipped); 1466 goto fallback; 1467 } 1468 } 1469 } 1470 1471 if (clipped != stack) 1472 free(clipped); 1473 } else { 1474 src_bo = kgem_create_buffer_2d(kgem, 1475 tmp.width, 1476 tmp.height, 1477 tmp.bitsPerPixel, 1478 KGEM_BUFFER_WRITE_INPLACE, 1479 &ptr); 1480 if (!src_bo) 1481 goto fallback; 1482 1483 if (sigtrap_get() == 0) { 1484 for (n = 0; n < nbox; n++) { 1485 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1486 __FUNCTION__, 1487 box[n].x1, box[n].y1, 1488 box[n].x2, box[n].y2, 1489 src_dx, src_dy, 1490 box[n].x1 - extents.x1, 1491 box[n].y1 - extents.y1)); 1492 memcpy_xor(src, ptr, tmp.bitsPerPixel, 1493 stride, src_bo->pitch, 1494 box[n].x1 + src_dx, 1495 box[n].y1 + src_dy, 1496 box[n].x1 - extents.x1, 1497 box[n].y1 - extents.y1, 1498 box[n].x2 - box[n].x1, 1499 box[n].y2 - box[n].y1, 1500 and, or); 1501 } 1502 1503 n = sna->render.copy_boxes(sna, GXcopy, 1504 &tmp, src_bo, -extents.x1, -extents.y1, 1505 &dst->drawable, dst_bo, dst_dx, dst_dy, 1506 box, nbox, 0); 1507 sigtrap_put(); 1508 } else 1509 n = 0; 1510 1511 kgem_bo_destroy(&sna->kgem, src_bo); 1512 1513 if (!n) 1514 goto tile; 1515 } 1516 1517 return true; 1518 } 1519 1520 cmd = XY_SRC_COPY_BLT_CMD; 1521 br13 = dst_bo->pitch; 1522 if (kgem->gen >= 040 && dst_bo->tiling) { 1523 cmd |= BLT_DST_TILED; 1524 br13 >>= 2; 1525 } 1526 br13 |= 0xcc << 16; 1527 switch (dst->drawable.bitsPerPixel) { 1528 default: 1529 case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 1530 br13 |= 1 << 25; /* RGB8888 */ 1531 case 16: br13 |= 1 << 24; /* RGB565 */ 1532 case 8: break; 1533 } 1534 1535 kgem_set_mode(kgem, KGEM_BLT, dst_bo); 1536 if (!kgem_check_batch(kgem, 10) || 1537 !kgem_check_reloc_and_exec(kgem, 2) || 1538 !kgem_check_bo_fenced(kgem, dst_bo)) { 1539 kgem_submit(kgem); 1540 if (!kgem_check_bo_fenced(kgem, dst_bo)) 1541 goto fallback; 1542 _kgem_set_mode(kgem, KGEM_BLT); 1543 } 1544 1545 if (sna->kgem.gen >= 0100) { 1546 cmd |= 8; 1547 do { 1548 int nbox_this_time, rem; 1549 1550 nbox_this_time = nbox; 1551 rem = kgem_batch_space(kgem); 1552 if (10*nbox_this_time > rem) 1553 nbox_this_time = rem / 8; 1554 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1555 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1556 assert(nbox_this_time); 1557 nbox -= nbox_this_time; 1558 1559 /* Count the total number of bytes to be read and allocate a 1560 * single buffer large enough. Or if it is very small, combine 1561 * with other allocations. */ 1562 offset = 0; 1563 for (n = 0; n < nbox_this_time; n++) { 1564 int height = box[n].y2 - box[n].y1; 1565 int width = box[n].x2 - box[n].x1; 1566 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1567 } 1568 1569 src_bo = kgem_create_buffer(kgem, offset, 1570 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1571 &ptr); 1572 if (!src_bo) 1573 goto fallback; 1574 1575 if (sigtrap_get()) { 1576 kgem_bo_destroy(kgem, src_bo); 1577 goto fallback; 1578 } 1579 1580 offset = 0; 1581 do { 1582 int height = box->y2 - box->y1; 1583 int width = box->x2 - box->x1; 1584 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1585 uint32_t *b; 1586 1587 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1588 __FUNCTION__, 1589 box->x1 + src_dx, box->y1 + src_dy, 1590 box->x1 + dst_dx, box->y1 + dst_dy, 1591 width, height, 1592 offset, pitch)); 1593 1594 assert(box->x1 + src_dx >= 0); 1595 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1596 assert(box->y1 + src_dy >= 0); 1597 1598 assert(box->x1 + dst_dx >= 0); 1599 assert(box->y1 + dst_dy >= 0); 1600 1601 memcpy_xor(src, (char *)ptr + offset, 1602 dst->drawable.bitsPerPixel, 1603 stride, pitch, 1604 box->x1 + src_dx, box->y1 + src_dy, 1605 0, 0, 1606 width, height, 1607 and, or); 1608 1609 assert(kgem->mode == KGEM_BLT); 1610 b = kgem->batch + kgem->nbatch; 1611 b[0] = cmd; 1612 b[1] = br13; 1613 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1614 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1615 *(uint64_t *)(b+4) = 1616 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 1617 I915_GEM_DOMAIN_RENDER << 16 | 1618 I915_GEM_DOMAIN_RENDER | 1619 KGEM_RELOC_FENCED, 1620 0); 1621 b[6] = 0; 1622 b[7] = pitch; 1623 *(uint64_t *)(b+8) = 1624 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 1625 I915_GEM_DOMAIN_RENDER << 16 | 1626 KGEM_RELOC_FENCED, 1627 offset); 1628 kgem->nbatch += 10; 1629 1630 box++; 1631 offset += pitch * height; 1632 } while (--nbox_this_time); 1633 assert(offset == __kgem_buffer_size(src_bo)); 1634 sigtrap_put(); 1635 1636 if (nbox) { 1637 _kgem_submit(kgem); 1638 _kgem_set_mode(kgem, KGEM_BLT); 1639 } 1640 1641 kgem_bo_destroy(kgem, src_bo); 1642 } while (nbox); 1643 } else { 1644 cmd |= 6; 1645 do { 1646 int nbox_this_time, rem; 1647 1648 nbox_this_time = nbox; 1649 rem = kgem_batch_space(kgem); 1650 if (8*nbox_this_time > rem) 1651 nbox_this_time = rem / 8; 1652 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1653 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1654 assert(nbox_this_time); 1655 nbox -= nbox_this_time; 1656 1657 /* Count the total number of bytes to be read and allocate a 1658 * single buffer large enough. Or if it is very small, combine 1659 * with other allocations. */ 1660 offset = 0; 1661 for (n = 0; n < nbox_this_time; n++) { 1662 int height = box[n].y2 - box[n].y1; 1663 int width = box[n].x2 - box[n].x1; 1664 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1665 } 1666 1667 src_bo = kgem_create_buffer(kgem, offset, 1668 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1669 &ptr); 1670 if (!src_bo) 1671 goto fallback; 1672 1673 if (sigtrap_get()) { 1674 kgem_bo_destroy(kgem, src_bo); 1675 goto fallback; 1676 } 1677 1678 offset = 0; 1679 do { 1680 int height = box->y2 - box->y1; 1681 int width = box->x2 - box->x1; 1682 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1683 uint32_t *b; 1684 1685 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1686 __FUNCTION__, 1687 box->x1 + src_dx, box->y1 + src_dy, 1688 box->x1 + dst_dx, box->y1 + dst_dy, 1689 width, height, 1690 offset, pitch)); 1691 1692 assert(box->x1 + src_dx >= 0); 1693 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1694 assert(box->y1 + src_dy >= 0); 1695 1696 assert(box->x1 + dst_dx >= 0); 1697 assert(box->y1 + dst_dy >= 0); 1698 1699 memcpy_xor(src, (char *)ptr + offset, 1700 dst->drawable.bitsPerPixel, 1701 stride, pitch, 1702 box->x1 + src_dx, box->y1 + src_dy, 1703 0, 0, 1704 width, height, 1705 and, or); 1706 1707 assert(kgem->mode == KGEM_BLT); 1708 b = kgem->batch + kgem->nbatch; 1709 b[0] = cmd; 1710 b[1] = br13; 1711 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1712 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1713 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 1714 I915_GEM_DOMAIN_RENDER << 16 | 1715 I915_GEM_DOMAIN_RENDER | 1716 KGEM_RELOC_FENCED, 1717 0); 1718 b[5] = 0; 1719 b[6] = pitch; 1720 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 1721 I915_GEM_DOMAIN_RENDER << 16 | 1722 KGEM_RELOC_FENCED, 1723 offset); 1724 kgem->nbatch += 8; 1725 1726 box++; 1727 offset += pitch * height; 1728 } while (--nbox_this_time); 1729 assert(offset == __kgem_buffer_size(src_bo)); 1730 sigtrap_put(); 1731 1732 if (nbox) { 1733 _kgem_submit(kgem); 1734 _kgem_set_mode(kgem, KGEM_BLT); 1735 } 1736 1737 kgem_bo_destroy(kgem, src_bo); 1738 } while (nbox); 1739 } 1740 1741 sna->blt_state.fill_bo = 0; 1742 return true; 1743 1744fallback: 1745 return write_boxes_inplace__xor(kgem, 1746 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1747 dst_bo, dst_dx, dst_dy, 1748 box, nbox, 1749 and, or); 1750} 1751 1752static bool 1753indirect_replace(struct sna *sna, 1754 PixmapPtr pixmap, 1755 struct kgem_bo *bo, 1756 const void *src, int stride) 1757{ 1758 struct kgem *kgem = &sna->kgem; 1759 struct kgem_bo *src_bo; 1760 BoxRec box; 1761 void *ptr; 1762 bool ret; 1763 1764 DBG(("%s: size=%d vs %d\n", 1765 __FUNCTION__, 1766 stride * pixmap->drawable.height >> 12, 1767 kgem->half_cpu_cache_pages)); 1768 1769 if (stride * pixmap->drawable.height >> 12 > kgem->half_cpu_cache_pages) 1770 return false; 1771 1772 if (!kgem_bo_can_blt(kgem, bo) && 1773 must_tile(sna, pixmap->drawable.width, pixmap->drawable.height)) 1774 return false; 1775 1776 src_bo = kgem_create_buffer_2d(kgem, 1777 pixmap->drawable.width, 1778 pixmap->drawable.height, 1779 pixmap->drawable.bitsPerPixel, 1780 KGEM_BUFFER_WRITE_INPLACE, 1781 &ptr); 1782 if (!src_bo) 1783 return false; 1784 1785 ret = false; 1786 if (sigtrap_get() == 0) { 1787 memcpy_blt(src, ptr, pixmap->drawable.bitsPerPixel, 1788 stride, src_bo->pitch, 1789 0, 0, 1790 0, 0, 1791 pixmap->drawable.width, 1792 pixmap->drawable.height); 1793 1794 box.x1 = box.y1 = 0; 1795 box.x2 = pixmap->drawable.width; 1796 box.y2 = pixmap->drawable.height; 1797 1798 ret = sna->render.copy_boxes(sna, GXcopy, 1799 &pixmap->drawable, src_bo, 0, 0, 1800 &pixmap->drawable, bo, 0, 0, 1801 &box, 1, 0); 1802 sigtrap_put(); 1803 } 1804 1805 kgem_bo_destroy(kgem, src_bo); 1806 1807 return ret; 1808} 1809 1810bool sna_replace(struct sna *sna, PixmapPtr pixmap, 1811 const void *src, int stride) 1812{ 1813 struct sna_pixmap *priv = sna_pixmap(pixmap); 1814 struct kgem_bo *bo = priv->gpu_bo; 1815 void *dst; 1816 1817 assert(bo); 1818 DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d) busy?=%d\n", 1819 __FUNCTION__, bo->handle, 1820 pixmap->drawable.width, 1821 pixmap->drawable.height, 1822 pixmap->drawable.bitsPerPixel, 1823 bo->tiling, 1824 __kgem_bo_is_busy(&sna->kgem, bo))); 1825 1826 assert(!priv->pinned); 1827 1828 kgem_bo_undo(&sna->kgem, bo); 1829 1830 if (__kgem_bo_is_busy(&sna->kgem, bo)) { 1831 struct kgem_bo *new_bo; 1832 1833 if (indirect_replace(sna, pixmap, bo, src, stride)) 1834 return true; 1835 1836 new_bo = kgem_create_2d(&sna->kgem, 1837 pixmap->drawable.width, 1838 pixmap->drawable.height, 1839 pixmap->drawable.bitsPerPixel, 1840 bo->tiling, 1841 CREATE_GTT_MAP | CREATE_INACTIVE); 1842 if (new_bo) 1843 bo = new_bo; 1844 } 1845 1846 if (bo->tiling == I915_TILING_NONE && bo->pitch == stride && 1847 kgem_bo_write(&sna->kgem, bo, src, 1848 (pixmap->drawable.height-1)*stride + pixmap->drawable.width*pixmap->drawable.bitsPerPixel/8)) 1849 goto done; 1850 1851 if (upload_inplace__tiled(&sna->kgem, bo)) { 1852 BoxRec box; 1853 1854 box.x1 = box.y1 = 0; 1855 box.x2 = pixmap->drawable.width; 1856 box.y2 = pixmap->drawable.height; 1857 1858 if (write_boxes_inplace__tiled(&sna->kgem, src, 1859 stride, pixmap->drawable.bitsPerPixel, 0, 0, 1860 bo, 0, 0, &box, 1)) 1861 goto done; 1862 } 1863 1864 if (kgem_bo_can_map(&sna->kgem, bo) && 1865 (dst = kgem_bo_map(&sna->kgem, bo)) != NULL && 1866 sigtrap_get() == 0) { 1867 memcpy_blt(src, dst, pixmap->drawable.bitsPerPixel, 1868 stride, bo->pitch, 1869 0, 0, 1870 0, 0, 1871 pixmap->drawable.width, 1872 pixmap->drawable.height); 1873 sigtrap_put(); 1874 } else { 1875 BoxRec box; 1876 1877 if (bo != priv->gpu_bo) { 1878 kgem_bo_destroy(&sna->kgem, bo); 1879 bo = priv->gpu_bo; 1880 } 1881 1882 box.x1 = box.y1 = 0; 1883 box.x2 = pixmap->drawable.width; 1884 box.y2 = pixmap->drawable.height; 1885 1886 if (!sna_write_boxes(sna, pixmap, 1887 bo, 0, 0, 1888 src, stride, 0, 0, 1889 &box, 1)) 1890 return false; 1891 } 1892 1893done: 1894 if (bo != priv->gpu_bo) { 1895 sna_pixmap_unmap(pixmap, priv); 1896 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1897 priv->gpu_bo = bo; 1898 } 1899 1900 return true; 1901} 1902 1903bool 1904sna_replace__xor(struct sna *sna, PixmapPtr pixmap, 1905 const void *src, int stride, 1906 uint32_t and, uint32_t or) 1907{ 1908 struct sna_pixmap *priv = sna_pixmap(pixmap); 1909 struct kgem_bo *bo = priv->gpu_bo; 1910 void *dst; 1911 1912 DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d)\n", 1913 __FUNCTION__, bo->handle, 1914 pixmap->drawable.width, 1915 pixmap->drawable.height, 1916 pixmap->drawable.bitsPerPixel, 1917 bo->tiling)); 1918 1919 assert(!priv->pinned); 1920 1921 kgem_bo_undo(&sna->kgem, bo); 1922 1923 if (!kgem_bo_can_map(&sna->kgem, bo) || 1924 __kgem_bo_is_busy(&sna->kgem, bo)) { 1925 struct kgem_bo *new_bo; 1926 1927 new_bo = kgem_create_2d(&sna->kgem, 1928 pixmap->drawable.width, 1929 pixmap->drawable.height, 1930 pixmap->drawable.bitsPerPixel, 1931 bo->tiling, 1932 CREATE_GTT_MAP | CREATE_INACTIVE); 1933 if (new_bo) 1934 bo = new_bo; 1935 } 1936 1937 if (kgem_bo_can_map(&sna->kgem, bo) && 1938 (dst = kgem_bo_map(&sna->kgem, bo)) != NULL && 1939 sigtrap_get() == 0) { 1940 memcpy_xor(src, dst, pixmap->drawable.bitsPerPixel, 1941 stride, bo->pitch, 1942 0, 0, 1943 0, 0, 1944 pixmap->drawable.width, 1945 pixmap->drawable.height, 1946 and, or); 1947 sigtrap_put(); 1948 } else { 1949 BoxRec box; 1950 1951 if (bo != priv->gpu_bo) { 1952 kgem_bo_destroy(&sna->kgem, bo); 1953 bo = priv->gpu_bo; 1954 } 1955 1956 box.x1 = box.y1 = 0; 1957 box.x2 = pixmap->drawable.width; 1958 box.y2 = pixmap->drawable.height; 1959 1960 if (!sna_write_boxes__xor(sna, pixmap, 1961 bo, 0, 0, 1962 src, stride, 0, 0, 1963 &box, 1, 1964 and, or)) 1965 return false; 1966 } 1967 1968 if (bo != priv->gpu_bo) { 1969 sna_pixmap_unmap(pixmap, priv); 1970 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1971 priv->gpu_bo = bo; 1972 } 1973 1974 return true; 1975} 1976