sna_io.c revision 42542f5f
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; 488 489 nbox_this_time = tmp_nbox; 490 if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 491 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 492 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 493 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 494 assert(nbox_this_time); 495 tmp_nbox -= nbox_this_time; 496 497 assert(kgem->mode == KGEM_BLT); 498 for (n = 0; n < nbox_this_time; n++) { 499 int height = tmp_box[n].y2 - tmp_box[n].y1; 500 int width = tmp_box[n].x2 - tmp_box[n].x1; 501 int pitch = PITCH(width, cpp); 502 uint32_t *b = kgem->batch + kgem->nbatch; 503 504 DBG((" blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n", 505 offset, 506 tmp_box[n].x1, tmp_box[n].y1, 507 width, height, pitch)); 508 509 assert(tmp_box[n].x1 >= 0); 510 assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch); 511 assert(tmp_box[n].y1 >= 0); 512 assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo)); 513 514 b[0] = cmd; 515 b[1] = br13 | pitch; 516 b[2] = 0; 517 b[3] = height << 16 | width; 518 *(uint64_t *)(b+4) = 519 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 520 I915_GEM_DOMAIN_RENDER << 16 | 521 I915_GEM_DOMAIN_RENDER | 522 KGEM_RELOC_FENCED, 523 offset); 524 b[6] = tmp_box[n].y1 << 16 | tmp_box[n].x1; 525 b[7] = src_pitch; 526 *(uint64_t *)(b+8) = 527 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 528 I915_GEM_DOMAIN_RENDER << 16 | 529 KGEM_RELOC_FENCED, 530 0); 531 kgem->nbatch += 10; 532 533 offset += pitch * height; 534 } 535 536 _kgem_submit(kgem); 537 if (!tmp_nbox) 538 break; 539 540 _kgem_set_mode(kgem, KGEM_BLT); 541 tmp_box += nbox_this_time; 542 } while (1); 543 } else { 544 cmd |= 6; 545 do { 546 int nbox_this_time; 547 548 nbox_this_time = tmp_nbox; 549 if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 550 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 551 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 552 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 553 assert(nbox_this_time); 554 tmp_nbox -= nbox_this_time; 555 556 assert(kgem->mode == KGEM_BLT); 557 for (n = 0; n < nbox_this_time; n++) { 558 int height = tmp_box[n].y2 - tmp_box[n].y1; 559 int width = tmp_box[n].x2 - tmp_box[n].x1; 560 int pitch = PITCH(width, cpp); 561 uint32_t *b = kgem->batch + kgem->nbatch; 562 563 DBG((" blt offset %x: (%d, %d) x (%d, %d), pitch=%d\n", 564 offset, 565 tmp_box[n].x1, tmp_box[n].y1, 566 width, height, pitch)); 567 568 assert(tmp_box[n].x1 >= 0); 569 assert(tmp_box[n].x2 * dst->drawable.bitsPerPixel/8 <= src_bo->pitch); 570 assert(tmp_box[n].y1 >= 0); 571 assert(tmp_box[n].y2 * src_bo->pitch <= kgem_bo_size(src_bo)); 572 573 b[0] = cmd; 574 b[1] = br13 | pitch; 575 b[2] = 0; 576 b[3] = height << 16 | width; 577 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 578 I915_GEM_DOMAIN_RENDER << 16 | 579 I915_GEM_DOMAIN_RENDER | 580 KGEM_RELOC_FENCED, 581 offset); 582 b[5] = tmp_box[n].y1 << 16 | tmp_box[n].x1; 583 b[6] = src_pitch; 584 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 585 I915_GEM_DOMAIN_RENDER << 16 | 586 KGEM_RELOC_FENCED, 587 0); 588 kgem->nbatch += 8; 589 590 offset += pitch * height; 591 } 592 593 _kgem_submit(kgem); 594 if (!tmp_nbox) 595 break; 596 597 _kgem_set_mode(kgem, KGEM_BLT); 598 tmp_box += nbox_this_time; 599 } while (1); 600 } 601 assert(offset == __kgem_buffer_size(dst_bo)); 602 603 kgem_buffer_read_sync(kgem, dst_bo); 604 605 if (sigtrap_get() == 0) { 606 char *src = ptr; 607 do { 608 int height = box->y2 - box->y1; 609 int width = box->x2 - box->x1; 610 int pitch = PITCH(width, cpp); 611 612 DBG((" copy offset %lx [%08x...%08x...%08x]: (%d, %d) x (%d, %d), src pitch=%d, dst pitch=%d, bpp=%d\n", 613 (long)((char *)src - (char *)ptr), 614 *(uint32_t*)src, *(uint32_t*)(src+pitch*height/2 + pitch/2 - 4), *(uint32_t*)(src+pitch*height - 4), 615 box->x1, box->y1, 616 width, height, 617 pitch, dst->devKind, cpp*8)); 618 619 assert(box->x1 >= 0); 620 assert(box->x2 <= dst->drawable.width); 621 assert(box->y1 >= 0); 622 assert(box->y2 <= dst->drawable.height); 623 624 memcpy_blt(src, dst->devPrivate.ptr, cpp*8, 625 pitch, dst->devKind, 626 0, 0, 627 box->x1, box->y1, 628 width, height); 629 box++; 630 631 src += pitch * height; 632 } while (--nbox); 633 assert(src - (char *)ptr == __kgem_buffer_size(dst_bo)); 634 sigtrap_put(); 635 } 636 kgem_bo_destroy(kgem, dst_bo); 637 sna->blt_state.fill_bo = 0; 638} 639 640static bool upload_inplace__tiled(struct kgem *kgem, struct kgem_bo *bo) 641{ 642 DBG(("%s: tiling=%d\n", __FUNCTION__, bo->tiling)); 643 switch (bo->tiling) { 644 case I915_TILING_Y: 645 return false; 646 case I915_TILING_X: 647 if (!kgem->memcpy_to_tiled_x) 648 return false; 649 default: 650 break; 651 } 652 653 return kgem_bo_can_map__cpu(kgem, bo, true); 654} 655 656static bool 657write_boxes_inplace__tiled(struct kgem *kgem, 658 const uint8_t *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 659 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 660 const BoxRec *box, int n) 661{ 662 uint8_t *dst; 663 664 assert(kgem_bo_can_map__cpu(kgem, bo, true)); 665 assert(bo->tiling != I915_TILING_Y); 666 667 dst = kgem_bo_map__cpu(kgem, bo); 668 if (dst == NULL) 669 return false; 670 671 kgem_bo_sync__cpu(kgem, bo); 672 673 if (sigtrap_get()) 674 return false; 675 676 if (bo->tiling) { 677 do { 678 memcpy_to_tiled_x(kgem, src, dst, bpp, stride, bo->pitch, 679 box->x1 + src_dx, box->y1 + src_dy, 680 box->x1 + dst_dx, box->y1 + dst_dy, 681 box->x2 - box->x1, box->y2 - box->y1); 682 box++; 683 } while (--n); 684 } else { 685 do { 686 memcpy_blt(src, dst, bpp, stride, bo->pitch, 687 box->x1 + src_dx, box->y1 + src_dy, 688 box->x1 + dst_dx, box->y1 + dst_dy, 689 box->x2 - box->x1, box->y2 - box->y1); 690 box++; 691 } while (--n); 692 } 693 694 sigtrap_put(); 695 return true; 696} 697 698static bool write_boxes_inplace(struct kgem *kgem, 699 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 700 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 701 const BoxRec *box, int n) 702{ 703 void *dst; 704 705 DBG(("%s x %d, handle=%d, tiling=%d\n", 706 __FUNCTION__, n, bo->handle, bo->tiling)); 707 708 if (upload_inplace__tiled(kgem, bo) && 709 write_boxes_inplace__tiled(kgem, src, stride, bpp, src_dx, src_dy, 710 bo, dst_dx, dst_dy, box, n)) 711 return true; 712 713 if (!kgem_bo_can_map(kgem, bo)) 714 return false; 715 716 kgem_bo_submit(kgem, bo); 717 718 dst = kgem_bo_map(kgem, bo); 719 if (dst == NULL) 720 return false; 721 722 assert(dst != src); 723 724 if (sigtrap_get()) 725 return false; 726 727 do { 728 DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__, 729 box->x1 + src_dx, box->y1 + src_dy, 730 box->x1 + dst_dx, box->y1 + dst_dy, 731 box->x2 - box->x1, box->y2 - box->y1, 732 bpp, stride, bo->pitch)); 733 734 assert(box->x2 > box->x1); 735 assert(box->y2 > box->y1); 736 737 assert(box->x1 + dst_dx >= 0); 738 assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch); 739 assert(box->y1 + dst_dy >= 0); 740 assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo)); 741 742 assert(box->x1 + src_dx >= 0); 743 assert((box->x2 + src_dx)*bpp <= 8*stride); 744 assert(box->y1 + src_dy >= 0); 745 746 memcpy_blt(src, dst, bpp, 747 stride, bo->pitch, 748 box->x1 + src_dx, box->y1 + src_dy, 749 box->x1 + dst_dx, box->y1 + dst_dy, 750 box->x2 - box->x1, box->y2 - box->y1); 751 box++; 752 } while (--n); 753 754 sigtrap_put(); 755 return true; 756} 757 758static bool __upload_inplace(struct kgem *kgem, 759 struct kgem_bo *bo, 760 const BoxRec *box, 761 int n, int bpp) 762{ 763 unsigned int bytes; 764 765 if (FORCE_INPLACE) 766 return FORCE_INPLACE > 0; 767 768 /* If we are writing through the GTT, check first if we might be 769 * able to almagamate a series of small writes into a single 770 * operation. 771 */ 772 bytes = 0; 773 while (n--) { 774 bytes += (box->x2 - box->x1) * (box->y2 - box->y1); 775 box++; 776 } 777 if (__kgem_bo_is_busy(kgem, bo)) 778 return bytes * bpp >> 12 >= kgem->half_cpu_cache_pages; 779 else 780 return bytes * bpp >> 12; 781} 782 783static bool upload_inplace(struct kgem *kgem, 784 struct kgem_bo *bo, 785 const BoxRec *box, 786 int n, int bpp) 787{ 788 if (unlikely(kgem->wedged)) 789 return true; 790 791 if (!kgem_bo_can_map(kgem, bo) && !upload_inplace__tiled(kgem, bo)) 792 return false; 793 794 return __upload_inplace(kgem, bo, box, n,bpp); 795} 796 797bool sna_write_boxes(struct sna *sna, PixmapPtr dst, 798 struct kgem_bo * const dst_bo, int16_t const dst_dx, int16_t const dst_dy, 799 const void * const src, int const stride, int16_t const src_dx, int16_t const src_dy, 800 const BoxRec *box, int nbox) 801{ 802 struct kgem *kgem = &sna->kgem; 803 struct kgem_bo *src_bo; 804 BoxRec extents; 805 void *ptr; 806 int offset; 807 int n, cmd, br13; 808 bool can_blt; 809 810 DBG(("%s x %d, src stride=%d, src dx=(%d, %d)\n", __FUNCTION__, nbox, stride, src_dx, src_dy)); 811 812 if (upload_inplace(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) && 813 write_boxes_inplace(kgem, 814 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 815 dst_bo, dst_dx, dst_dy, 816 box, nbox)) 817 return true; 818 819 if (wedged(sna)) 820 return false; 821 822 can_blt = kgem_bo_can_blt(kgem, dst_bo) && 823 (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 824 extents = box[0]; 825 for (n = 1; n < nbox; n++) { 826 if (box[n].x1 < extents.x1) 827 extents.x1 = box[n].x1; 828 if (box[n].x2 > extents.x2) 829 extents.x2 = box[n].x2; 830 831 if (can_blt) 832 can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 833 834 if (box[n].y1 < extents.y1) 835 extents.y1 = box[n].y1; 836 if (box[n].y2 > extents.y2) 837 extents.y2 = box[n].y2; 838 } 839 840 /* Try to avoid switching rings... */ 841 if (!can_blt || kgem->ring == KGEM_RENDER || 842 upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { 843 DrawableRec tmp; 844 845 tmp.width = extents.x2 - extents.x1; 846 tmp.height = extents.y2 - extents.y1; 847 tmp.depth = dst->drawable.depth; 848 tmp.bitsPerPixel = dst->drawable.bitsPerPixel; 849 850 assert(tmp.width); 851 assert(tmp.height); 852 853 DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n", 854 __FUNCTION__, 855 extents.x1, extents.y1, 856 tmp.width, tmp.height, 857 sna->render.max_3d_size, sna->render.max_3d_size)); 858 if (must_tile(sna, tmp.width, tmp.height)) { 859 BoxRec tile, stack[64], *clipped; 860 int cpp, step; 861 862tile: 863 cpp = dst->drawable.bitsPerPixel / 8; 864 step = MIN(sna->render.max_3d_size, 865 (MAXSHORT&~63) / cpp); 866 while (step * step * cpp > sna->kgem.max_upload_tile_size) 867 step /= 2; 868 869 if (step * cpp > 4096) 870 step = 4096 / cpp; 871 assert(step); 872 873 DBG(("%s: tiling upload, using %dx%d tiles\n", 874 __FUNCTION__, step, step)); 875 876 if (n > ARRAY_SIZE(stack)) { 877 clipped = malloc(sizeof(BoxRec) * n); 878 if (clipped == NULL) 879 goto fallback; 880 } else 881 clipped = stack; 882 883 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 884 int y2 = tile.y1 + step; 885 if (y2 > extents.y2) 886 y2 = extents.y2; 887 tile.y2 = y2; 888 889 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 890 int x2 = tile.x1 + step; 891 if (x2 > extents.x2) 892 x2 = extents.x2; 893 tile.x2 = x2; 894 895 tmp.width = tile.x2 - tile.x1; 896 tmp.height = tile.y2 - tile.y1; 897 898 src_bo = kgem_create_buffer_2d(kgem, 899 tmp.width, 900 tmp.height, 901 tmp.bitsPerPixel, 902 KGEM_BUFFER_WRITE_INPLACE, 903 &ptr); 904 if (!src_bo) { 905 if (clipped != stack) 906 free(clipped); 907 goto fallback; 908 } 909 910 if (sigtrap_get() == 0) { 911 BoxRec *c = clipped; 912 for (n = 0; n < nbox; n++) { 913 *c = box[n]; 914 if (!box_intersect(c, &tile)) 915 continue; 916 917 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 918 __FUNCTION__, 919 c->x1, c->y1, 920 c->x2, c->y2, 921 src_dx, src_dy, 922 c->x1 - tile.x1, 923 c->y1 - tile.y1)); 924 memcpy_blt(src, ptr, tmp.bitsPerPixel, 925 stride, src_bo->pitch, 926 c->x1 + src_dx, 927 c->y1 + src_dy, 928 c->x1 - tile.x1, 929 c->y1 - tile.y1, 930 c->x2 - c->x1, 931 c->y2 - c->y1); 932 c++; 933 } 934 935 if (c != clipped) 936 n = sna->render.copy_boxes(sna, GXcopy, 937 &tmp, src_bo, -tile.x1, -tile.y1, 938 &dst->drawable, dst_bo, dst_dx, dst_dy, 939 clipped, c - clipped, 0); 940 else 941 n = 1; 942 sigtrap_put(); 943 } else 944 n = 0; 945 946 kgem_bo_destroy(&sna->kgem, src_bo); 947 948 if (!n) { 949 if (clipped != stack) 950 free(clipped); 951 goto fallback; 952 } 953 } 954 } 955 956 if (clipped != stack) 957 free(clipped); 958 } else { 959 src_bo = kgem_create_buffer_2d(kgem, 960 tmp.width, 961 tmp.height, 962 tmp.bitsPerPixel, 963 KGEM_BUFFER_WRITE_INPLACE, 964 &ptr); 965 if (!src_bo) 966 goto fallback; 967 968 if (sigtrap_get() == 0) { 969 for (n = 0; n < nbox; n++) { 970 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 971 __FUNCTION__, 972 box[n].x1, box[n].y1, 973 box[n].x2, box[n].y2, 974 src_dx, src_dy, 975 box[n].x1 - extents.x1, 976 box[n].y1 - extents.y1)); 977 memcpy_blt(src, ptr, tmp.bitsPerPixel, 978 stride, src_bo->pitch, 979 box[n].x1 + src_dx, 980 box[n].y1 + src_dy, 981 box[n].x1 - extents.x1, 982 box[n].y1 - extents.y1, 983 box[n].x2 - box[n].x1, 984 box[n].y2 - box[n].y1); 985 } 986 987 n = sna->render.copy_boxes(sna, GXcopy, 988 &tmp, src_bo, -extents.x1, -extents.y1, 989 &dst->drawable, dst_bo, dst_dx, dst_dy, 990 box, nbox, 0); 991 sigtrap_put(); 992 } else 993 n = 0; 994 995 kgem_bo_destroy(&sna->kgem, src_bo); 996 997 if (!n) 998 goto tile; 999 } 1000 1001 return true; 1002 } 1003 1004 cmd = XY_SRC_COPY_BLT_CMD; 1005 br13 = dst_bo->pitch; 1006 if (kgem->gen >= 040 && dst_bo->tiling) { 1007 cmd |= BLT_DST_TILED; 1008 br13 >>= 2; 1009 } 1010 br13 |= 0xcc << 16; 1011 switch (dst->drawable.bitsPerPixel) { 1012 default: 1013 case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 1014 br13 |= 1 << 25; /* RGB8888 */ 1015 case 16: br13 |= 1 << 24; /* RGB565 */ 1016 case 8: break; 1017 } 1018 1019 kgem_set_mode(kgem, KGEM_BLT, dst_bo); 1020 if (!kgem_check_batch(kgem, 10) || 1021 !kgem_check_reloc_and_exec(kgem, 2) || 1022 !kgem_check_bo_fenced(kgem, dst_bo)) { 1023 kgem_submit(kgem); 1024 if (!kgem_check_bo_fenced(kgem, dst_bo)) 1025 goto fallback; 1026 _kgem_set_mode(kgem, KGEM_BLT); 1027 } 1028 1029 if (kgem->gen >= 0100) { 1030 cmd |= 8; 1031 do { 1032 int nbox_this_time; 1033 1034 nbox_this_time = nbox; 1035 if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 1036 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 1037 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1038 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1039 assert(nbox_this_time); 1040 nbox -= nbox_this_time; 1041 1042 /* Count the total number of bytes to be read and allocate a 1043 * single buffer large enough. Or if it is very small, combine 1044 * with other allocations. */ 1045 offset = 0; 1046 for (n = 0; n < nbox_this_time; n++) { 1047 int height = box[n].y2 - box[n].y1; 1048 int width = box[n].x2 - box[n].x1; 1049 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1050 } 1051 1052 src_bo = kgem_create_buffer(kgem, offset, 1053 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1054 &ptr); 1055 if (!src_bo) 1056 break; 1057 1058 if (sigtrap_get() == 0) { 1059 offset = 0; 1060 do { 1061 int height = box->y2 - box->y1; 1062 int width = box->x2 - box->x1; 1063 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1064 uint32_t *b; 1065 1066 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1067 __FUNCTION__, 1068 box->x1 + src_dx, box->y1 + src_dy, 1069 box->x1 + dst_dx, box->y1 + dst_dy, 1070 width, height, 1071 offset, pitch)); 1072 1073 assert(box->x1 + src_dx >= 0); 1074 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1075 assert(box->y1 + src_dy >= 0); 1076 1077 assert(box->x1 + dst_dx >= 0); 1078 assert(box->y1 + dst_dy >= 0); 1079 1080 memcpy_blt(src, (char *)ptr + offset, 1081 dst->drawable.bitsPerPixel, 1082 stride, pitch, 1083 box->x1 + src_dx, box->y1 + src_dy, 1084 0, 0, 1085 width, height); 1086 1087 assert(kgem->mode == KGEM_BLT); 1088 b = kgem->batch + kgem->nbatch; 1089 b[0] = cmd; 1090 b[1] = br13; 1091 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1092 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1093 *(uint64_t *)(b+4) = 1094 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 1095 I915_GEM_DOMAIN_RENDER << 16 | 1096 I915_GEM_DOMAIN_RENDER | 1097 KGEM_RELOC_FENCED, 1098 0); 1099 b[6] = 0; 1100 b[7] = pitch; 1101 *(uint64_t *)(b+8) = 1102 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 1103 I915_GEM_DOMAIN_RENDER << 16 | 1104 KGEM_RELOC_FENCED, 1105 offset); 1106 kgem->nbatch += 10; 1107 1108 box++; 1109 offset += pitch * height; 1110 } while (--nbox_this_time); 1111 assert(offset == __kgem_buffer_size(src_bo)); 1112 sigtrap_put(); 1113 } 1114 1115 if (nbox) { 1116 _kgem_submit(kgem); 1117 _kgem_set_mode(kgem, KGEM_BLT); 1118 } 1119 1120 kgem_bo_destroy(kgem, src_bo); 1121 } while (nbox); 1122 } else { 1123 cmd |= 6; 1124 do { 1125 int nbox_this_time; 1126 1127 nbox_this_time = nbox; 1128 if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 1129 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 1130 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1131 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1132 assert(nbox_this_time); 1133 nbox -= nbox_this_time; 1134 1135 /* Count the total number of bytes to be read and allocate a 1136 * single buffer large enough. Or if it is very small, combine 1137 * with other allocations. */ 1138 offset = 0; 1139 for (n = 0; n < nbox_this_time; n++) { 1140 int height = box[n].y2 - box[n].y1; 1141 int width = box[n].x2 - box[n].x1; 1142 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1143 } 1144 1145 src_bo = kgem_create_buffer(kgem, offset, 1146 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1147 &ptr); 1148 if (!src_bo) 1149 break; 1150 1151 if (sigtrap_get()) { 1152 kgem_bo_destroy(kgem, src_bo); 1153 goto fallback; 1154 } 1155 1156 offset = 0; 1157 do { 1158 int height = box->y2 - box->y1; 1159 int width = box->x2 - box->x1; 1160 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1161 uint32_t *b; 1162 1163 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1164 __FUNCTION__, 1165 box->x1 + src_dx, box->y1 + src_dy, 1166 box->x1 + dst_dx, box->y1 + dst_dy, 1167 width, height, 1168 offset, pitch)); 1169 1170 assert(box->x1 + src_dx >= 0); 1171 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1172 assert(box->y1 + src_dy >= 0); 1173 1174 assert(box->x1 + dst_dx >= 0); 1175 assert(box->y1 + dst_dy >= 0); 1176 1177 memcpy_blt(src, (char *)ptr + offset, 1178 dst->drawable.bitsPerPixel, 1179 stride, pitch, 1180 box->x1 + src_dx, box->y1 + src_dy, 1181 0, 0, 1182 width, height); 1183 1184 assert(kgem->mode == KGEM_BLT); 1185 b = kgem->batch + kgem->nbatch; 1186 b[0] = cmd; 1187 b[1] = br13; 1188 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1189 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1190 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 1191 I915_GEM_DOMAIN_RENDER << 16 | 1192 I915_GEM_DOMAIN_RENDER | 1193 KGEM_RELOC_FENCED, 1194 0); 1195 b[5] = 0; 1196 b[6] = pitch; 1197 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 1198 I915_GEM_DOMAIN_RENDER << 16 | 1199 KGEM_RELOC_FENCED, 1200 offset); 1201 kgem->nbatch += 8; 1202 1203 box++; 1204 offset += pitch * height; 1205 } while (--nbox_this_time); 1206 assert(offset == __kgem_buffer_size(src_bo)); 1207 sigtrap_put(); 1208 1209 if (nbox) { 1210 _kgem_submit(kgem); 1211 _kgem_set_mode(kgem, KGEM_BLT); 1212 } 1213 1214 kgem_bo_destroy(kgem, src_bo); 1215 } while (nbox); 1216 } 1217 1218 sna->blt_state.fill_bo = 0; 1219 return true; 1220 1221fallback: 1222 return write_boxes_inplace(kgem, 1223 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1224 dst_bo, dst_dx, dst_dy, 1225 box, nbox); 1226} 1227 1228static bool 1229write_boxes_inplace__xor(struct kgem *kgem, 1230 const void *src, int stride, int bpp, int16_t src_dx, int16_t src_dy, 1231 struct kgem_bo *bo, int16_t dst_dx, int16_t dst_dy, 1232 const BoxRec *box, int n, 1233 uint32_t and, uint32_t or) 1234{ 1235 void *dst; 1236 1237 DBG(("%s x %d, tiling=%d\n", __FUNCTION__, n, bo->tiling)); 1238 1239 if (!kgem_bo_can_map(kgem, bo)) 1240 return false; 1241 1242 kgem_bo_submit(kgem, bo); 1243 1244 dst = kgem_bo_map(kgem, bo); 1245 if (dst == NULL) 1246 return false; 1247 1248 if (sigtrap_get()) 1249 return false; 1250 1251 do { 1252 DBG(("%s: (%d, %d) -> (%d, %d) x (%d, %d) [bpp=%d, src_pitch=%d, dst_pitch=%d]\n", __FUNCTION__, 1253 box->x1 + src_dx, box->y1 + src_dy, 1254 box->x1 + dst_dx, box->y1 + dst_dy, 1255 box->x2 - box->x1, box->y2 - box->y1, 1256 bpp, stride, bo->pitch)); 1257 1258 assert(box->x2 > box->x1); 1259 assert(box->y2 > box->y1); 1260 1261 assert(box->x1 + dst_dx >= 0); 1262 assert((box->x2 + dst_dx)*bpp <= 8*bo->pitch); 1263 assert(box->y1 + dst_dy >= 0); 1264 assert((box->y2 + dst_dy)*bo->pitch <= kgem_bo_size(bo)); 1265 1266 assert(box->x1 + src_dx >= 0); 1267 assert((box->x2 + src_dx)*bpp <= 8*stride); 1268 assert(box->y1 + src_dy >= 0); 1269 1270 memcpy_xor(src, dst, bpp, 1271 stride, bo->pitch, 1272 box->x1 + src_dx, box->y1 + src_dy, 1273 box->x1 + dst_dx, box->y1 + dst_dy, 1274 box->x2 - box->x1, box->y2 - box->y1, 1275 and, or); 1276 box++; 1277 } while (--n); 1278 1279 sigtrap_put(); 1280 return true; 1281} 1282 1283static bool upload_inplace__xor(struct kgem *kgem, 1284 struct kgem_bo *bo, 1285 const BoxRec *box, 1286 int n, int bpp) 1287{ 1288 if (unlikely(kgem->wedged)) 1289 return true; 1290 1291 if (!kgem_bo_can_map(kgem, bo)) 1292 return false; 1293 1294 return __upload_inplace(kgem, bo, box, n, bpp); 1295} 1296 1297bool sna_write_boxes__xor(struct sna *sna, PixmapPtr dst, 1298 struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy, 1299 const void *src, int stride, int16_t src_dx, int16_t src_dy, 1300 const BoxRec *box, int nbox, 1301 uint32_t and, uint32_t or) 1302{ 1303 struct kgem *kgem = &sna->kgem; 1304 struct kgem_bo *src_bo; 1305 BoxRec extents; 1306 bool can_blt; 1307 void *ptr; 1308 int offset; 1309 int n, cmd, br13; 1310 1311 DBG(("%s x %d\n", __FUNCTION__, nbox)); 1312 1313 if (upload_inplace__xor(kgem, dst_bo, box, nbox, dst->drawable.bitsPerPixel) && 1314 write_boxes_inplace__xor(kgem, 1315 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1316 dst_bo, dst_dx, dst_dy, 1317 box, nbox, 1318 and, or)) 1319 return true; 1320 1321 if (wedged(sna)) 1322 return false; 1323 1324 can_blt = kgem_bo_can_blt(kgem, dst_bo) && 1325 (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 1326 extents = box[0]; 1327 for (n = 1; n < nbox; n++) { 1328 if (box[n].x1 < extents.x1) 1329 extents.x1 = box[n].x1; 1330 if (box[n].x2 > extents.x2) 1331 extents.x2 = box[n].x2; 1332 1333 if (can_blt) 1334 can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); 1335 1336 if (box[n].y1 < extents.y1) 1337 extents.y1 = box[n].y1; 1338 if (box[n].y2 > extents.y2) 1339 extents.y2 = box[n].y2; 1340 } 1341 1342 /* Try to avoid switching rings... */ 1343 if (!can_blt || kgem->ring == KGEM_RENDER || 1344 upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { 1345 DrawableRec tmp; 1346 1347 tmp.width = extents.x2 - extents.x1; 1348 tmp.height = extents.y2 - extents.y1; 1349 tmp.depth = dst->drawable.depth; 1350 tmp.bitsPerPixel = dst->drawable.bitsPerPixel; 1351 1352 assert(tmp.width); 1353 assert(tmp.height); 1354 1355 DBG(("%s: upload (%d, %d)x(%d, %d), max %dx%d\n", 1356 __FUNCTION__, 1357 extents.x1, extents.y1, 1358 tmp.width, tmp.height, 1359 sna->render.max_3d_size, sna->render.max_3d_size)); 1360 if (must_tile(sna, tmp.width, tmp.height)) { 1361 BoxRec tile, stack[64], *clipped; 1362 int step; 1363 1364tile: 1365 step = MIN(sna->render.max_3d_size - 4096 / dst->drawable.bitsPerPixel, 1366 8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel); 1367 while (step * step * 4 > sna->kgem.max_upload_tile_size) 1368 step /= 2; 1369 1370 DBG(("%s: tiling upload, using %dx%d tiles\n", 1371 __FUNCTION__, step, step)); 1372 assert(step); 1373 1374 if (n > ARRAY_SIZE(stack)) { 1375 clipped = malloc(sizeof(BoxRec) * n); 1376 if (clipped == NULL) 1377 goto fallback; 1378 } else 1379 clipped = stack; 1380 1381 for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { 1382 int y2 = tile.y1 + step; 1383 if (y2 > extents.y2) 1384 y2 = extents.y2; 1385 tile.y2 = y2; 1386 1387 for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { 1388 int x2 = tile.x1 + step; 1389 if (x2 > extents.x2) 1390 x2 = extents.x2; 1391 tile.x2 = x2; 1392 1393 tmp.width = tile.x2 - tile.x1; 1394 tmp.height = tile.y2 - tile.y1; 1395 1396 src_bo = kgem_create_buffer_2d(kgem, 1397 tmp.width, 1398 tmp.height, 1399 tmp.bitsPerPixel, 1400 KGEM_BUFFER_WRITE_INPLACE, 1401 &ptr); 1402 if (!src_bo) { 1403 if (clipped != stack) 1404 free(clipped); 1405 goto fallback; 1406 } 1407 1408 if (sigtrap_get() == 0) { 1409 BoxRec *c = clipped; 1410 for (n = 0; n < nbox; n++) { 1411 *c = box[n]; 1412 if (!box_intersect(c, &tile)) 1413 continue; 1414 1415 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1416 __FUNCTION__, 1417 c->x1, c->y1, 1418 c->x2, c->y2, 1419 src_dx, src_dy, 1420 c->x1 - tile.x1, 1421 c->y1 - tile.y1)); 1422 memcpy_xor(src, ptr, tmp.bitsPerPixel, 1423 stride, src_bo->pitch, 1424 c->x1 + src_dx, 1425 c->y1 + src_dy, 1426 c->x1 - tile.x1, 1427 c->y1 - tile.y1, 1428 c->x2 - c->x1, 1429 c->y2 - c->y1, 1430 and, or); 1431 c++; 1432 } 1433 1434 if (c != clipped) 1435 n = sna->render.copy_boxes(sna, GXcopy, 1436 &tmp, src_bo, -tile.x1, -tile.y1, 1437 &dst->drawable, dst_bo, dst_dx, dst_dy, 1438 clipped, c - clipped, 0); 1439 else 1440 n = 1; 1441 1442 sigtrap_put(); 1443 } else 1444 n = 0; 1445 1446 kgem_bo_destroy(&sna->kgem, src_bo); 1447 1448 if (!n) { 1449 if (clipped != stack) 1450 free(clipped); 1451 goto fallback; 1452 } 1453 } 1454 } 1455 1456 if (clipped != stack) 1457 free(clipped); 1458 } else { 1459 src_bo = kgem_create_buffer_2d(kgem, 1460 tmp.width, 1461 tmp.height, 1462 tmp.bitsPerPixel, 1463 KGEM_BUFFER_WRITE_INPLACE, 1464 &ptr); 1465 if (!src_bo) 1466 goto fallback; 1467 1468 if (sigtrap_get() == 0) { 1469 for (n = 0; n < nbox; n++) { 1470 DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n", 1471 __FUNCTION__, 1472 box[n].x1, box[n].y1, 1473 box[n].x2, box[n].y2, 1474 src_dx, src_dy, 1475 box[n].x1 - extents.x1, 1476 box[n].y1 - extents.y1)); 1477 memcpy_xor(src, ptr, tmp.bitsPerPixel, 1478 stride, src_bo->pitch, 1479 box[n].x1 + src_dx, 1480 box[n].y1 + src_dy, 1481 box[n].x1 - extents.x1, 1482 box[n].y1 - extents.y1, 1483 box[n].x2 - box[n].x1, 1484 box[n].y2 - box[n].y1, 1485 and, or); 1486 } 1487 1488 n = sna->render.copy_boxes(sna, GXcopy, 1489 &tmp, src_bo, -extents.x1, -extents.y1, 1490 &dst->drawable, dst_bo, dst_dx, dst_dy, 1491 box, nbox, 0); 1492 sigtrap_put(); 1493 } else 1494 n = 0; 1495 1496 kgem_bo_destroy(&sna->kgem, src_bo); 1497 1498 if (!n) 1499 goto tile; 1500 } 1501 1502 return true; 1503 } 1504 1505 cmd = XY_SRC_COPY_BLT_CMD; 1506 br13 = dst_bo->pitch; 1507 if (kgem->gen >= 040 && dst_bo->tiling) { 1508 cmd |= BLT_DST_TILED; 1509 br13 >>= 2; 1510 } 1511 br13 |= 0xcc << 16; 1512 switch (dst->drawable.bitsPerPixel) { 1513 default: 1514 case 32: cmd |= BLT_WRITE_ALPHA | BLT_WRITE_RGB; 1515 br13 |= 1 << 25; /* RGB8888 */ 1516 case 16: br13 |= 1 << 24; /* RGB565 */ 1517 case 8: break; 1518 } 1519 1520 kgem_set_mode(kgem, KGEM_BLT, dst_bo); 1521 if (!kgem_check_batch(kgem, 10) || 1522 !kgem_check_reloc_and_exec(kgem, 2) || 1523 !kgem_check_bo_fenced(kgem, dst_bo)) { 1524 kgem_submit(kgem); 1525 if (!kgem_check_bo_fenced(kgem, dst_bo)) 1526 goto fallback; 1527 _kgem_set_mode(kgem, KGEM_BLT); 1528 } 1529 1530 if (sna->kgem.gen >= 0100) { 1531 cmd |= 8; 1532 do { 1533 int nbox_this_time; 1534 1535 nbox_this_time = nbox; 1536 if (10*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 1537 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 1538 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1539 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1540 assert(nbox_this_time); 1541 nbox -= nbox_this_time; 1542 1543 /* Count the total number of bytes to be read and allocate a 1544 * single buffer large enough. Or if it is very small, combine 1545 * with other allocations. */ 1546 offset = 0; 1547 for (n = 0; n < nbox_this_time; n++) { 1548 int height = box[n].y2 - box[n].y1; 1549 int width = box[n].x2 - box[n].x1; 1550 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1551 } 1552 1553 src_bo = kgem_create_buffer(kgem, offset, 1554 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1555 &ptr); 1556 if (!src_bo) 1557 goto fallback; 1558 1559 if (sigtrap_get()) { 1560 kgem_bo_destroy(kgem, src_bo); 1561 goto fallback; 1562 } 1563 1564 offset = 0; 1565 do { 1566 int height = box->y2 - box->y1; 1567 int width = box->x2 - box->x1; 1568 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1569 uint32_t *b; 1570 1571 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1572 __FUNCTION__, 1573 box->x1 + src_dx, box->y1 + src_dy, 1574 box->x1 + dst_dx, box->y1 + dst_dy, 1575 width, height, 1576 offset, pitch)); 1577 1578 assert(box->x1 + src_dx >= 0); 1579 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1580 assert(box->y1 + src_dy >= 0); 1581 1582 assert(box->x1 + dst_dx >= 0); 1583 assert(box->y1 + dst_dy >= 0); 1584 1585 memcpy_xor(src, (char *)ptr + offset, 1586 dst->drawable.bitsPerPixel, 1587 stride, pitch, 1588 box->x1 + src_dx, box->y1 + src_dy, 1589 0, 0, 1590 width, height, 1591 and, or); 1592 1593 assert(kgem->mode == KGEM_BLT); 1594 b = kgem->batch + kgem->nbatch; 1595 b[0] = cmd; 1596 b[1] = br13; 1597 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1598 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1599 *(uint64_t *)(b+4) = 1600 kgem_add_reloc64(kgem, kgem->nbatch + 4, dst_bo, 1601 I915_GEM_DOMAIN_RENDER << 16 | 1602 I915_GEM_DOMAIN_RENDER | 1603 KGEM_RELOC_FENCED, 1604 0); 1605 b[6] = 0; 1606 b[7] = pitch; 1607 *(uint64_t *)(b+8) = 1608 kgem_add_reloc64(kgem, kgem->nbatch + 8, src_bo, 1609 I915_GEM_DOMAIN_RENDER << 16 | 1610 KGEM_RELOC_FENCED, 1611 offset); 1612 kgem->nbatch += 10; 1613 1614 box++; 1615 offset += pitch * height; 1616 } while (--nbox_this_time); 1617 assert(offset == __kgem_buffer_size(src_bo)); 1618 sigtrap_put(); 1619 1620 if (nbox) { 1621 _kgem_submit(kgem); 1622 _kgem_set_mode(kgem, KGEM_BLT); 1623 } 1624 1625 kgem_bo_destroy(kgem, src_bo); 1626 } while (nbox); 1627 } else { 1628 cmd |= 6; 1629 do { 1630 int nbox_this_time; 1631 1632 nbox_this_time = nbox; 1633 if (8*nbox_this_time > kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) 1634 nbox_this_time = (kgem->surface - kgem->nbatch - KGEM_BATCH_RESERVED) / 8; 1635 if (2*nbox_this_time > KGEM_RELOC_SIZE(kgem) - kgem->nreloc) 1636 nbox_this_time = (KGEM_RELOC_SIZE(kgem) - kgem->nreloc) / 2; 1637 assert(nbox_this_time); 1638 nbox -= nbox_this_time; 1639 1640 /* Count the total number of bytes to be read and allocate a 1641 * single buffer large enough. Or if it is very small, combine 1642 * with other allocations. */ 1643 offset = 0; 1644 for (n = 0; n < nbox_this_time; n++) { 1645 int height = box[n].y2 - box[n].y1; 1646 int width = box[n].x2 - box[n].x1; 1647 offset += PITCH(width, dst->drawable.bitsPerPixel >> 3) * height; 1648 } 1649 1650 src_bo = kgem_create_buffer(kgem, offset, 1651 KGEM_BUFFER_WRITE_INPLACE | (nbox ? KGEM_BUFFER_LAST : 0), 1652 &ptr); 1653 if (!src_bo) 1654 goto fallback; 1655 1656 if (sigtrap_get()) { 1657 kgem_bo_destroy(kgem, src_bo); 1658 goto fallback; 1659 } 1660 1661 offset = 0; 1662 do { 1663 int height = box->y2 - box->y1; 1664 int width = box->x2 - box->x1; 1665 int pitch = PITCH(width, dst->drawable.bitsPerPixel >> 3); 1666 uint32_t *b; 1667 1668 DBG((" %s: box src=(%d, %d), dst=(%d, %d) size=(%d, %d), dst offset=%d, dst pitch=%d\n", 1669 __FUNCTION__, 1670 box->x1 + src_dx, box->y1 + src_dy, 1671 box->x1 + dst_dx, box->y1 + dst_dy, 1672 width, height, 1673 offset, pitch)); 1674 1675 assert(box->x1 + src_dx >= 0); 1676 assert((box->x2 + src_dx)*dst->drawable.bitsPerPixel <= 8*stride); 1677 assert(box->y1 + src_dy >= 0); 1678 1679 assert(box->x1 + dst_dx >= 0); 1680 assert(box->y1 + dst_dy >= 0); 1681 1682 memcpy_xor(src, (char *)ptr + offset, 1683 dst->drawable.bitsPerPixel, 1684 stride, pitch, 1685 box->x1 + src_dx, box->y1 + src_dy, 1686 0, 0, 1687 width, height, 1688 and, or); 1689 1690 assert(kgem->mode == KGEM_BLT); 1691 b = kgem->batch + kgem->nbatch; 1692 b[0] = cmd; 1693 b[1] = br13; 1694 b[2] = (box->y1 + dst_dy) << 16 | (box->x1 + dst_dx); 1695 b[3] = (box->y2 + dst_dy) << 16 | (box->x2 + dst_dx); 1696 b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo, 1697 I915_GEM_DOMAIN_RENDER << 16 | 1698 I915_GEM_DOMAIN_RENDER | 1699 KGEM_RELOC_FENCED, 1700 0); 1701 b[5] = 0; 1702 b[6] = pitch; 1703 b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo, 1704 I915_GEM_DOMAIN_RENDER << 16 | 1705 KGEM_RELOC_FENCED, 1706 offset); 1707 kgem->nbatch += 8; 1708 1709 box++; 1710 offset += pitch * height; 1711 } while (--nbox_this_time); 1712 assert(offset == __kgem_buffer_size(src_bo)); 1713 sigtrap_put(); 1714 1715 if (nbox) { 1716 _kgem_submit(kgem); 1717 _kgem_set_mode(kgem, KGEM_BLT); 1718 } 1719 1720 kgem_bo_destroy(kgem, src_bo); 1721 } while (nbox); 1722 } 1723 1724 sna->blt_state.fill_bo = 0; 1725 return true; 1726 1727fallback: 1728 return write_boxes_inplace__xor(kgem, 1729 src, stride, dst->drawable.bitsPerPixel, src_dx, src_dy, 1730 dst_bo, dst_dx, dst_dy, 1731 box, nbox, 1732 and, or); 1733} 1734 1735static bool 1736indirect_replace(struct sna *sna, 1737 PixmapPtr pixmap, 1738 struct kgem_bo *bo, 1739 const void *src, int stride) 1740{ 1741 struct kgem *kgem = &sna->kgem; 1742 struct kgem_bo *src_bo; 1743 BoxRec box; 1744 void *ptr; 1745 bool ret; 1746 1747 DBG(("%s: size=%d vs %d\n", 1748 __FUNCTION__, 1749 stride * pixmap->drawable.height >> 12, 1750 kgem->half_cpu_cache_pages)); 1751 1752 if (stride * pixmap->drawable.height >> 12 > kgem->half_cpu_cache_pages) 1753 return false; 1754 1755 if (!kgem_bo_can_blt(kgem, bo) && 1756 must_tile(sna, pixmap->drawable.width, pixmap->drawable.height)) 1757 return false; 1758 1759 src_bo = kgem_create_buffer_2d(kgem, 1760 pixmap->drawable.width, 1761 pixmap->drawable.height, 1762 pixmap->drawable.bitsPerPixel, 1763 KGEM_BUFFER_WRITE_INPLACE, 1764 &ptr); 1765 if (!src_bo) 1766 return false; 1767 1768 if (sigtrap_get() == 0) { 1769 memcpy_blt(src, ptr, pixmap->drawable.bitsPerPixel, 1770 stride, src_bo->pitch, 1771 0, 0, 1772 0, 0, 1773 pixmap->drawable.width, 1774 pixmap->drawable.height); 1775 1776 box.x1 = box.y1 = 0; 1777 box.x2 = pixmap->drawable.width; 1778 box.y2 = pixmap->drawable.height; 1779 1780 ret = sna->render.copy_boxes(sna, GXcopy, 1781 &pixmap->drawable, src_bo, 0, 0, 1782 &pixmap->drawable, bo, 0, 0, 1783 &box, 1, 0); 1784 sigtrap_put(); 1785 } else 1786 ret = false; 1787 1788 kgem_bo_destroy(kgem, src_bo); 1789 1790 return ret; 1791} 1792 1793bool sna_replace(struct sna *sna, PixmapPtr pixmap, 1794 const void *src, int stride) 1795{ 1796 struct sna_pixmap *priv = sna_pixmap(pixmap); 1797 struct kgem_bo *bo = priv->gpu_bo; 1798 void *dst; 1799 1800 assert(bo); 1801 DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d) busy?=%d\n", 1802 __FUNCTION__, bo->handle, 1803 pixmap->drawable.width, 1804 pixmap->drawable.height, 1805 pixmap->drawable.bitsPerPixel, 1806 bo->tiling, 1807 __kgem_bo_is_busy(&sna->kgem, bo))); 1808 1809 assert(!priv->pinned); 1810 1811 kgem_bo_undo(&sna->kgem, bo); 1812 1813 if (__kgem_bo_is_busy(&sna->kgem, bo)) { 1814 struct kgem_bo *new_bo; 1815 1816 if (indirect_replace(sna, pixmap, bo, src, stride)) 1817 return true; 1818 1819 new_bo = kgem_create_2d(&sna->kgem, 1820 pixmap->drawable.width, 1821 pixmap->drawable.height, 1822 pixmap->drawable.bitsPerPixel, 1823 bo->tiling, 1824 CREATE_GTT_MAP | CREATE_INACTIVE); 1825 if (new_bo) 1826 bo = new_bo; 1827 } 1828 1829 if (bo->tiling == I915_TILING_NONE && bo->pitch == stride && 1830 kgem_bo_write(&sna->kgem, bo, src, 1831 (pixmap->drawable.height-1)*stride + pixmap->drawable.width*pixmap->drawable.bitsPerPixel/8)) 1832 goto done; 1833 1834 if (upload_inplace__tiled(&sna->kgem, bo)) { 1835 BoxRec box; 1836 1837 box.x1 = box.y1 = 0; 1838 box.x2 = pixmap->drawable.width; 1839 box.y2 = pixmap->drawable.height; 1840 1841 if (write_boxes_inplace__tiled(&sna->kgem, src, 1842 stride, pixmap->drawable.bitsPerPixel, 0, 0, 1843 bo, 0, 0, &box, 1)) 1844 goto done; 1845 } 1846 1847 if (kgem_bo_can_map(&sna->kgem, bo) && 1848 (dst = kgem_bo_map(&sna->kgem, bo)) != NULL && 1849 sigtrap_get() == 0) { 1850 memcpy_blt(src, dst, pixmap->drawable.bitsPerPixel, 1851 stride, bo->pitch, 1852 0, 0, 1853 0, 0, 1854 pixmap->drawable.width, 1855 pixmap->drawable.height); 1856 sigtrap_put(); 1857 } else { 1858 BoxRec box; 1859 1860 if (bo != priv->gpu_bo) { 1861 kgem_bo_destroy(&sna->kgem, bo); 1862 bo = priv->gpu_bo; 1863 } 1864 1865 box.x1 = box.y1 = 0; 1866 box.x2 = pixmap->drawable.width; 1867 box.y2 = pixmap->drawable.height; 1868 1869 if (!sna_write_boxes(sna, pixmap, 1870 bo, 0, 0, 1871 src, stride, 0, 0, 1872 &box, 1)) 1873 return false; 1874 } 1875 1876done: 1877 if (bo != priv->gpu_bo) { 1878 sna_pixmap_unmap(pixmap, priv); 1879 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1880 priv->gpu_bo = bo; 1881 } 1882 1883 return true; 1884} 1885 1886bool 1887sna_replace__xor(struct sna *sna, PixmapPtr pixmap, 1888 const void *src, int stride, 1889 uint32_t and, uint32_t or) 1890{ 1891 struct sna_pixmap *priv = sna_pixmap(pixmap); 1892 struct kgem_bo *bo = priv->gpu_bo; 1893 void *dst; 1894 1895 DBG(("%s(handle=%d, %dx%d, bpp=%d, tiling=%d)\n", 1896 __FUNCTION__, bo->handle, 1897 pixmap->drawable.width, 1898 pixmap->drawable.height, 1899 pixmap->drawable.bitsPerPixel, 1900 bo->tiling)); 1901 1902 assert(!priv->pinned); 1903 1904 kgem_bo_undo(&sna->kgem, bo); 1905 1906 if (!kgem_bo_can_map(&sna->kgem, bo) || 1907 __kgem_bo_is_busy(&sna->kgem, bo)) { 1908 struct kgem_bo *new_bo; 1909 1910 new_bo = kgem_create_2d(&sna->kgem, 1911 pixmap->drawable.width, 1912 pixmap->drawable.height, 1913 pixmap->drawable.bitsPerPixel, 1914 bo->tiling, 1915 CREATE_GTT_MAP | CREATE_INACTIVE); 1916 if (new_bo) 1917 bo = new_bo; 1918 } 1919 1920 if (kgem_bo_can_map(&sna->kgem, bo) && 1921 (dst = kgem_bo_map(&sna->kgem, bo)) != NULL && 1922 sigtrap_get() == 0) { 1923 memcpy_xor(src, dst, pixmap->drawable.bitsPerPixel, 1924 stride, bo->pitch, 1925 0, 0, 1926 0, 0, 1927 pixmap->drawable.width, 1928 pixmap->drawable.height, 1929 and, or); 1930 sigtrap_put(); 1931 } else { 1932 BoxRec box; 1933 1934 if (bo != priv->gpu_bo) { 1935 kgem_bo_destroy(&sna->kgem, bo); 1936 bo = priv->gpu_bo; 1937 } 1938 1939 box.x1 = box.y1 = 0; 1940 box.x2 = pixmap->drawable.width; 1941 box.y2 = pixmap->drawable.height; 1942 1943 if (!sna_write_boxes__xor(sna, pixmap, 1944 bo, 0, 0, 1945 src, stride, 0, 0, 1946 &box, 1, 1947 and, or)) 1948 return false; 1949 } 1950 1951 if (bo != priv->gpu_bo) { 1952 sna_pixmap_unmap(pixmap, priv); 1953 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1954 priv->gpu_bo = bo; 1955 } 1956 1957 return true; 1958} 1959