sna_accel.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_reg.h" 34#include "sna_video.h" 35#include "rop.h" 36 37#include "intel_options.h" 38 39#include <X11/fonts/font.h> 40#include <X11/fonts/fontstruct.h> 41 42#include <dixfontstr.h> 43 44#include <mi.h> 45#include <migc.h> 46#include <miline.h> 47#include <micmap.h> 48#ifdef RENDER 49#include <mipict.h> 50#endif 51#include <shmint.h> 52 53#include <sys/time.h> 54#include <sys/mman.h> 55#include <unistd.h> 56 57#ifdef HAVE_VALGRIND 58#include <valgrind.h> 59#include <memcheck.h> 60#endif 61 62#define FAULT_INJECTION 0 63 64#define FORCE_INPLACE 0 65#define FORCE_FALLBACK 0 66#define FORCE_FLUSH 0 67#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */ 68 69#define DEFAULT_TILING I915_TILING_X 70 71#define USE_INPLACE 1 72#define USE_WIDE_SPANS 0 /* -1 force CPU, 1 force GPU */ 73#define USE_ZERO_SPANS 1 /* -1 force CPU, 1 force GPU */ 74#define USE_CPU_BO 1 75#define USE_USERPTR_UPLOADS 1 76#define USE_USERPTR_DOWNLOADS 1 77#define USE_COW 1 78#define UNDO 1 79 80#define MIGRATE_ALL 0 81#define DBG_NO_PARTIAL_MOVE_TO_CPU 0 82#define DBG_NO_CPU_UPLOAD 0 83#define DBG_NO_CPU_DOWNLOAD 0 84 85#define ACCEL_FILL_SPANS 1 86#define ACCEL_SET_SPANS 1 87#define ACCEL_PUT_IMAGE 1 88#define ACCEL_GET_IMAGE 1 89#define ACCEL_COPY_AREA 1 90#define ACCEL_COPY_PLANE 1 91#define ACCEL_COPY_WINDOW 1 92#define ACCEL_POLY_POINT 1 93#define ACCEL_POLY_LINE 1 94#define ACCEL_POLY_SEGMENT 1 95#define ACCEL_POLY_RECTANGLE 1 96#define ACCEL_POLY_ARC 1 97#define ACCEL_POLY_FILL_POLYGON 1 98#define ACCEL_POLY_FILL_RECT 1 99#define ACCEL_POLY_FILL_ARC 1 100#define ACCEL_POLY_TEXT8 1 101#define ACCEL_POLY_TEXT16 1 102#define ACCEL_POLY_GLYPH 1 103#define ACCEL_IMAGE_TEXT8 1 104#define ACCEL_IMAGE_TEXT16 1 105#define ACCEL_IMAGE_GLYPH 1 106#define ACCEL_PUSH_PIXELS 1 107 108#define NO_TILE_8x8 0 109#define NO_STIPPLE_8x8 0 110 111#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) 112#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) 113#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) 114 115#if 0 116static void __sna_fallback_flush(DrawablePtr d) 117{ 118 PixmapPtr pixmap = get_drawable_pixmap(d); 119 struct sna *sna = to_sna_from_pixmap(pixmap); 120 struct sna_pixmap *priv; 121 BoxRec box; 122 PixmapPtr tmp; 123 int i, j; 124 char *src, *dst; 125 126 DBG(("%s: uploading CPU damage...\n", __FUNCTION__)); 127 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 128 if (priv == NULL) 129 return; 130 131 DBG(("%s: downloading GPU damage...\n", __FUNCTION__)); 132 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 133 return; 134 135 box.x1 = box.y1 = 0; 136 box.x2 = pixmap->drawable.width; 137 box.y2 = pixmap->drawable.height; 138 139 tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen, 140 pixmap->drawable.width, 141 pixmap->drawable.height, 142 pixmap->drawable.depth, 143 0); 144 145 DBG(("%s: comparing with direct read...\n", __FUNCTION__)); 146 sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1); 147 148 src = pixmap->devPrivate.ptr; 149 dst = tmp->devPrivate.ptr; 150 for (i = 0; i < tmp->drawable.height; i++) { 151 if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) { 152 for (j = 0; src[j] == dst[j]; j++) 153 ; 154 ERR(("mismatch at (%d, %d)\n", 155 8*j / tmp->drawable.bitsPerPixel, i)); 156 abort(); 157 } 158 src += pixmap->devKind; 159 dst += tmp->devKind; 160 } 161 tmp->drawable.pScreen->DestroyPixmap(tmp); 162} 163#define FALLBACK_FLUSH(d) __sna_fallback_flush(d) 164#else 165#define FALLBACK_FLUSH(d) 166#endif 167 168static int sna_font_key; 169 170static const uint8_t copy_ROP[] = { 171 ROP_0, /* GXclear */ 172 ROP_DSa, /* GXand */ 173 ROP_SDna, /* GXandReverse */ 174 ROP_S, /* GXcopy */ 175 ROP_DSna, /* GXandInverted */ 176 ROP_D, /* GXnoop */ 177 ROP_DSx, /* GXxor */ 178 ROP_DSo, /* GXor */ 179 ROP_DSon, /* GXnor */ 180 ROP_DSxn, /* GXequiv */ 181 ROP_Dn, /* GXinvert */ 182 ROP_SDno, /* GXorReverse */ 183 ROP_Sn, /* GXcopyInverted */ 184 ROP_DSno, /* GXorInverted */ 185 ROP_DSan, /* GXnand */ 186 ROP_1 /* GXset */ 187}; 188static const uint8_t fill_ROP[] = { 189 ROP_0, 190 ROP_DPa, 191 ROP_PDna, 192 ROP_P, 193 ROP_DPna, 194 ROP_D, 195 ROP_DPx, 196 ROP_DPo, 197 ROP_DPon, 198 ROP_PDxn, 199 ROP_Dn, 200 ROP_PDno, 201 ROP_Pn, 202 ROP_DPno, 203 ROP_DPan, 204 ROP_1 205}; 206 207static const GCOps sna_gc_ops; 208static const GCOps sna_gc_ops__cpu; 209static GCOps sna_gc_ops__tmp; 210static const GCFuncs sna_gc_funcs; 211static const GCFuncs sna_gc_funcs__cpu; 212 213static void 214sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect); 215 216static inline void region_set(RegionRec *r, const BoxRec *b) 217{ 218 r->extents = *b; 219 r->data = NULL; 220} 221 222static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip) 223{ 224 if (clip->data && !RegionIntersect(r, r, clip)) 225 return false; 226 227 return !box_empty(&r->extents); 228} 229 230static inline bool region_is_singular(const RegionRec *r) 231{ 232 return r->data == NULL; 233} 234 235static inline bool region_is_unclipped(const RegionRec *r, int w, int h) 236{ 237 return (region_is_singular(r) && 238 w == r->extents.x2 - r->extents.x1 && 239 h == r->extents.y2 - r->extents.y1); 240} 241 242typedef struct box32 { 243 int32_t x1, y1, x2, y2; 244} Box32Rec; 245 246#define PM_IS_SOLID(_draw, _pm) \ 247 (((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth)) 248 249#ifndef NDEBUG 250static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function) 251{ 252 if (box->x1 < 0 || box->y1 < 0 || 253 box->x2 > pixmap->drawable.width || 254 box->y2 > pixmap->drawable.height) 255 { 256 FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n", 257 function, box->x1, box->y1, box->x2, box->y2, 258 pixmap->drawable.serialNumber, 259 pixmap->drawable.width, 260 pixmap->drawable.height); 261 } 262} 263 264static void 265_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function) 266{ 267 if (damage == NULL) 268 return; 269 270 _assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function); 271} 272#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__) 273#else 274#define assert_pixmap_contains_damage(p,d) 275#endif 276 277#define __assert_pixmap_damage(p) do { \ 278 struct sna_pixmap *priv__ = sna_pixmap(p); \ 279 if (priv__) { \ 280 assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \ 281 assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \ 282 assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \ 283 assert_pixmap_contains_damage(p, priv__->gpu_damage); \ 284 assert_pixmap_contains_damage(p, priv__->cpu_damage); \ 285 assert_pixmap_map(p, priv__); \ 286 } \ 287} while (0) 288 289#ifdef DEBUG_PIXMAP 290static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function) 291{ 292 BoxRec b = *box; 293 b.x1 += dx; b.x2 += dx; 294 b.y1 += dy; b.y2 += dy; 295 _assert_pixmap_contains_box(pixmap, &b, function); 296} 297 298static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function) 299{ 300 BoxRec extents; 301 302 extents = *box; 303 while (--n) { 304 ++box; 305 306 if (box->x1 < extents.x1) 307 extents.x1 = box->x1; 308 if (box->x2 > extents.x2) 309 extents.x2 = box->x2; 310 311 if (box->y1 < extents.y1) 312 extents.y1 = box->y1; 313 if (box->y2 > extents.y2) 314 extents.y2 = box->y2; 315 } 316 extents.x1 += dx; 317 extents.x2 += dx; 318 extents.y1 += dy; 319 extents.y2 += dy; 320 _assert_pixmap_contains_box(pixmap, &extents, function); 321} 322 323 324static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function) 325{ 326 BoxRec extents; 327 328 extents.x2 = extents.x1 = pt->x; 329 extents.y2 = extents.y1 = pt->y; 330 while (--n) { 331 ++pt; 332 333 if (pt->x < extents.x1) 334 extents.x1 = pt->x; 335 else if (pt->x > extents.x2) 336 extents.x2 = pt->x; 337 338 if (pt->y < extents.y1) 339 extents.y1 = pt->y; 340 else if (pt->y > extents.y2) 341 extents.y2 = pt->y; 342 } 343 extents.x1 += dx; 344 extents.x2 += dx + 1; 345 extents.y1 += dy; 346 extents.y2 += dy + 1; 347 _assert_pixmap_contains_box(pixmap, &extents, function); 348} 349 350static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function) 351{ 352 if (box->x1 < drawable->x || 353 box->y1 < drawable->y || 354 box->x2 > drawable->x + drawable->width || 355 box->y2 > drawable->y + drawable->height) 356 { 357 FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n", 358 function, 359 box->x1, box->y1, box->x2, box->y2, 360 drawable->x, drawable->y, 361 drawable->width, drawable->height); 362 } 363} 364 365static void assert_pixmap_damage(PixmapPtr p) 366{ 367 struct sna_pixmap *priv; 368 RegionRec reg, cpu, gpu; 369 370 priv = sna_pixmap(p); 371 if (priv == NULL) 372 return; 373 374 __assert_pixmap_damage(p); 375 376 if (priv->clear) { 377 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 378 assert(priv->cpu_damage == NULL); 379 } 380 381 if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) { 382 /* special upload buffer */ 383 assert(priv->gpu_bo && priv->gpu_bo->proxy); 384 assert(priv->cpu_bo == NULL); 385 return; 386 } 387 388 assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL); 389 assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL); 390 391 /* Avoid reducing damage to minimise interferrence */ 392 RegionNull(®); 393 RegionNull(&gpu); 394 RegionNull(&cpu); 395 396 if (priv->gpu_damage) 397 _sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu); 398 399 if (priv->cpu_damage) 400 _sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu); 401 402 RegionIntersect(®, &cpu, &gpu); 403 assert(RegionNil(®)); 404 405 RegionUninit(®); 406 RegionUninit(&gpu); 407 RegionUninit(&cpu); 408} 409 410#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 411#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__) 412#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__) 413#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__) 414#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__) 415 416#else 417#define assert_pixmap_contains_box(p, b) 418#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) 419#define assert_pixmap_contains_boxes(p, b, n, x, y) 420#define assert_pixmap_contains_points(p, pt, n, x, y) 421#define assert_drawable_contains_box(d, b) 422#ifndef NDEBUG 423#define assert_pixmap_damage(p) __assert_pixmap_damage(p) 424#else 425#define assert_pixmap_damage(p) 426#endif 427#endif 428 429jmp_buf sigjmp[4]; 430volatile sig_atomic_t sigtrap; 431 432static int sigtrap_handler(int sig) 433{ 434 /* XXX rate-limited squawk? */ 435 DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap)); 436 sna_threads_trap(sig); 437 438 if (sigtrap) 439 siglongjmp(sigjmp[--sigtrap], sig); 440 441 return -1; 442} 443 444static void sigtrap_init(void) 445{ 446#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 447 OsRegisterSigWrapper(sigtrap_handler); 448#endif 449} 450 451inline static bool 452sna_fill_init_blt(struct sna_fill_op *fill, 453 struct sna *sna, 454 PixmapPtr pixmap, 455 struct kgem_bo *bo, 456 uint8_t alu, 457 uint32_t pixel, 458 unsigned flags) 459{ 460 return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill); 461} 462 463static bool 464sna_copy_init_blt(struct sna_copy_op *copy, 465 struct sna *sna, 466 PixmapPtr src, struct kgem_bo *src_bo, 467 PixmapPtr dst, struct kgem_bo *dst_bo, 468 uint8_t alu) 469{ 470 memset(copy, 0, sizeof(*copy)); 471 return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); 472} 473 474static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv) 475{ 476 DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned)); 477 assert(priv->gpu_damage == NULL || priv->gpu_bo); 478 479 if (priv->cow) 480 sna_pixmap_undo_cow(sna, priv, MOVE_WRITE); 481 assert(priv->cow == NULL); 482 483 if (priv->move_to_gpu) { 484 sna_pixmap_discard_shadow_damage(priv, NULL); 485 priv->move_to_gpu(sna, priv, MOVE_WRITE); 486 } 487 488 sna_damage_destroy(&priv->gpu_damage); 489 priv->clear = false; 490 491 if (priv->gpu_bo) { 492 if (!priv->pinned) { 493 assert(!priv->flush); 494 assert(!priv->move_to_gpu); 495 sna_pixmap_unmap(priv->pixmap, priv); 496 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 497 priv->gpu_bo = NULL; 498 } else 499 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 500 } 501 502 /* and reset the upload counter */ 503 priv->source_count = SOURCE_BIAS; 504} 505 506static bool must_check 507sna_pixmap_alloc_cpu(struct sna *sna, 508 PixmapPtr pixmap, 509 struct sna_pixmap *priv, 510 unsigned flags) 511{ 512 /* Restore after a GTT mapping? */ 513 assert(priv->gpu_damage == NULL || priv->gpu_bo); 514 assert(!priv->shm); 515 if (priv->ptr) 516 goto done; 517 518 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 519 assert(priv->stride); 520 521 if (priv->create & KGEM_CAN_CREATE_CPU) { 522 unsigned hint; 523 524 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__, 525 pixmap->drawable.width, pixmap->drawable.height)); 526 527 hint = 0; 528 if ((flags & MOVE_ASYNC_HINT) == 0 && 529 ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc))) 530 hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE; 531 532 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem, 533 pixmap->drawable.width, 534 pixmap->drawable.height, 535 pixmap->drawable.bitsPerPixel, 536 hint); 537 if (priv->cpu_bo) { 538 priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 539 if (priv->ptr) { 540 DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__, 541 priv->cpu_bo->handle, priv->cpu_bo->snoop)); 542 priv->stride = priv->cpu_bo->pitch; 543#ifdef DEBUG_MEMORY 544 sna->debug_memory.cpu_bo_allocs++; 545 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 546#endif 547 } else { 548 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 549 priv->cpu_bo = NULL; 550 } 551 } 552 } 553 554 if (priv->ptr == NULL) { 555 DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n", 556 __FUNCTION__, priv->stride * pixmap->drawable.height)); 557 priv->ptr = malloc(priv->stride * pixmap->drawable.height); 558 } 559 560done: 561 assert(priv->stride); 562 assert(!priv->mapped); 563 pixmap->devPrivate.ptr = PTR(priv->ptr); 564 pixmap->devKind = priv->stride; 565 return priv->ptr != NULL; 566} 567 568static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 569{ 570 if (priv->cpu_bo) { 571 DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n", 572 __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo))); 573#ifdef DEBUG_MEMORY 574 sna->debug_memory.cpu_bo_allocs--; 575 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 576#endif 577 if (priv->cpu_bo->flush) { 578 assert(!priv->cpu_bo->reusable); 579 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 580 sna_accel_watch_flush(sna, -1); 581 } 582 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 583 } else if (!IS_STATIC_PTR(priv->ptr)) 584 free(priv->ptr); 585} 586 587static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active) 588{ 589 if (active) 590 return false; 591 592 if (IS_STATIC_PTR(priv->ptr)) 593 return false; 594 595 if (priv->ptr == NULL) 596 return true; 597 598 __sna_pixmap_free_cpu(sna, priv); 599 600 priv->cpu_bo = NULL; 601 priv->ptr = NULL; 602 603 if (priv->mapped == MAPPED_NONE) 604 priv->pixmap->devPrivate.ptr = NULL; 605 606 return true; 607} 608 609static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) 610{ 611#if DEFAULT_TILING == I915_TILING_NONE 612 return I915_TILING_NONE; 613#elif DEFAULT_TILING == I915_TILING_X 614 return I915_TILING_X; 615#else 616 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ 617 if (sna->kgem.gen == 021) 618 return I915_TILING_X; 619 620 /* Only on later generations was the render pipeline 621 * more flexible than the BLT. So on gen2/3, prefer to 622 * keep large objects accessible through the BLT. 623 */ 624 if (sna->kgem.gen < 040 && 625 (pixmap->drawable.width > sna->render.max_3d_size || 626 pixmap->drawable.height > sna->render.max_3d_size)) 627 return I915_TILING_X; 628 629 if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage, 630 pixmap->drawable.width, 631 pixmap->drawable.height)) { 632 DBG(("%s: entire source is damaged, using Y-tiling\n", 633 __FUNCTION__)); 634 sna_damage_destroy(&sna_pixmap(priv)->gpu_damage); 635 return I915_TILING_Y; 636 } 637 638 return I915_TILING_Y; 639#endif 640} 641 642pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap) 643{ 644 /* Also adjust tiling if it is not supported or likely to 645 * slow us down, 646 */ 647 return kgem_choose_tiling(&sna->kgem, 648 default_tiling(sna, pixmap), 649 pixmap->drawable.width, 650 pixmap->drawable.height, 651 pixmap->drawable.bitsPerPixel); 652} 653 654struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) 655{ 656 struct sna_pixmap *priv = sna_pixmap(pixmap); 657 struct sna *sna = to_sna_from_pixmap(pixmap); 658 struct kgem_bo *bo; 659 BoxRec box; 660 661 DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n", 662 __FUNCTION__, priv->gpu_bo->tiling, tiling, 663 pixmap->drawable.width, pixmap->drawable.height)); 664 assert(priv->gpu_damage == NULL || priv->gpu_bo); 665 666 if (priv->pinned) { 667 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 668 return NULL; 669 } 670 671 if (wedged(sna)) { 672 DBG(("%s: can't convert bo, wedged\n", __FUNCTION__)); 673 return NULL; 674 } 675 676 assert_pixmap_damage(pixmap); 677 assert(!priv->move_to_gpu); 678 679 bo = kgem_create_2d(&sna->kgem, 680 pixmap->drawable.width, 681 pixmap->drawable.height, 682 pixmap->drawable.bitsPerPixel, 683 tiling, 0); 684 if (bo == NULL) { 685 DBG(("%s: allocation failed\n", __FUNCTION__)); 686 return NULL; 687 } 688 689 box.x1 = box.y1 = 0; 690 box.x2 = pixmap->drawable.width; 691 box.y2 = pixmap->drawable.height; 692 693 if (!sna->render.copy_boxes(sna, GXcopy, 694 &pixmap->drawable, priv->gpu_bo, 0, 0, 695 &pixmap->drawable, bo, 0, 0, 696 &box, 1, 0)) { 697 DBG(("%s: copy failed\n", __FUNCTION__)); 698 kgem_bo_destroy(&sna->kgem, bo); 699 return NULL; 700 } 701 702 sna_pixmap_unmap(pixmap, priv); 703 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 704 705 return priv->gpu_bo = bo; 706} 707 708static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna) 709{ 710 ((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna; 711 assert(sna_pixmap(pixmap) == sna); 712} 713 714static struct sna_pixmap * 715_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) 716{ 717 list_init(&priv->flush_list); 718 list_init(&priv->cow_list); 719 priv->source_count = SOURCE_BIAS; 720 priv->pixmap = pixmap; 721 722 return priv; 723} 724 725static struct sna_pixmap * 726_sna_pixmap_reset(PixmapPtr pixmap) 727{ 728 struct sna_pixmap *priv; 729 730 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 731 assert(pixmap->drawable.class == 0); 732 assert(pixmap->drawable.x == 0); 733 assert(pixmap->drawable.y == 0); 734 735 priv = sna_pixmap(pixmap); 736 assert(priv != NULL); 737 738 memset(priv, 0, sizeof(*priv)); 739 return _sna_pixmap_init(priv, pixmap); 740} 741 742static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) 743{ 744 struct sna_pixmap *priv; 745 746 priv = calloc(1, sizeof(*priv)); 747 if (!priv) 748 return NULL; 749 750 sna_set_pixmap(pixmap, priv); 751 return _sna_pixmap_init(priv, pixmap); 752} 753 754struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) 755{ 756 struct sna_pixmap *priv; 757 758 assert(bo); 759 assert(bo->proxy == NULL); 760 assert(bo->unique_id); 761 762 priv = sna_pixmap_attach(pixmap); 763 if (!priv) 764 return NULL; 765 766 DBG(("%s: attaching %s handle=%d to pixmap=%ld\n", 767 __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber)); 768 769 assert(!priv->mapped); 770 assert(!priv->move_to_gpu); 771 772 if (bo->snoop) { 773 priv->cpu_bo = bo; 774 sna_damage_all(&priv->cpu_damage, pixmap); 775 } else { 776 priv->gpu_bo = bo; 777 sna_damage_all(&priv->gpu_damage, pixmap); 778 } 779 780 return priv; 781} 782 783static int bits_per_pixel(int depth) 784{ 785 switch (depth) { 786 case 1: return 1; 787 case 4: 788 case 8: return 8; 789 case 15: 790 case 16: return 16; 791 case 24: 792 case 30: 793 case 32: return 32; 794 default: return 0; 795 } 796} 797static PixmapPtr 798create_pixmap(struct sna *sna, ScreenPtr screen, 799 int width, int height, int depth, 800 unsigned usage_hint) 801{ 802 PixmapPtr pixmap; 803 size_t datasize; 804 size_t stride; 805 int base, bpp; 806 807 bpp = bits_per_pixel(depth); 808 if (bpp == 0) 809 return NullPixmap; 810 811 stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 812 if (stride / 4 > 32767 || height > 32767) 813 return NullPixmap; 814 815 datasize = height * stride; 816 base = screen->totalPixmapSize; 817 if (datasize && base & 15) { 818 int adjust = 16 - (base & 15); 819 base += adjust; 820 datasize += adjust; 821 } 822 823 DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n", 824 __FUNCTION__, width, height, depth, (long)datasize)); 825 pixmap = AllocatePixmap(screen, datasize); 826 if (!pixmap) 827 return NullPixmap; 828 829 ((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna; 830 assert(to_sna_from_pixmap(pixmap) == sna); 831 832 pixmap->drawable.type = DRAWABLE_PIXMAP; 833 pixmap->drawable.class = 0; 834 pixmap->drawable.pScreen = screen; 835 pixmap->drawable.depth = depth; 836 pixmap->drawable.bitsPerPixel = bpp; 837 pixmap->drawable.id = 0; 838 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 839 pixmap->drawable.x = 0; 840 pixmap->drawable.y = 0; 841 pixmap->drawable.width = width; 842 pixmap->drawable.height = height; 843 pixmap->devKind = stride; 844 pixmap->refcnt = 1; 845 pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL; 846 847#ifdef COMPOSITE 848 pixmap->screen_x = 0; 849 pixmap->screen_y = 0; 850#endif 851 852 pixmap->usage_hint = usage_hint; 853#if DEBUG_MEMORY 854 sna->debug_memory.pixmap_allocs++; 855#endif 856 857 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 858 __FUNCTION__, 859 pixmap->drawable.serialNumber, 860 pixmap->usage_hint, 861 pixmap->drawable.width, 862 pixmap->drawable.height)); 863 864 return pixmap; 865} 866 867static PixmapPtr 868__pop_freed_pixmap(struct sna *sna) 869{ 870 PixmapPtr pixmap; 871 872 assert(sna->freed_pixmap); 873 874 pixmap = sna->freed_pixmap; 875 sna->freed_pixmap = pixmap->devPrivate.ptr; 876 877 assert(pixmap->refcnt == 0); 878 assert(sna_pixmap(pixmap)); 879 assert(sna_pixmap(pixmap)->header); 880 881#if DEBUG_MEMORY 882 sna->debug_memory.pixmap_cached--; 883#endif 884 885 return pixmap; 886} 887 888inline static PixmapPtr 889create_pixmap_hdr(struct sna *sna, ScreenPtr screen, 890 int width, int height, int depth, int usage, 891 struct sna_pixmap **priv) 892{ 893 PixmapPtr pixmap; 894 895 if (sna->freed_pixmap == NULL) { 896 pixmap = create_pixmap(sna, screen, 0, 0, depth, usage); 897 if (pixmap == NullPixmap) 898 return NullPixmap; 899 900 *priv = sna_pixmap_attach(pixmap); 901 if (!*priv) { 902 FreePixmap(pixmap); 903 return NullPixmap; 904 } 905 } else { 906 pixmap = __pop_freed_pixmap(sna); 907 *priv = _sna_pixmap_reset(pixmap); 908 909 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 910 assert(pixmap->drawable.class == 0); 911 assert(pixmap->drawable.pScreen == screen); 912 assert(pixmap->drawable.x == 0); 913 assert(pixmap->drawable.y == 0); 914 915 pixmap->drawable.id = 0; 916 917 pixmap->drawable.depth = depth; 918 pixmap->drawable.bitsPerPixel = bits_per_pixel(depth); 919 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 920 921 pixmap->devKind = 0; 922 pixmap->devPrivate.ptr = NULL; 923 924#ifdef COMPOSITE 925 pixmap->screen_x = 0; 926 pixmap->screen_y = 0; 927#endif 928 929#if DEBUG_MEMORY 930 sna->debug_memory.pixmap_allocs++; 931#endif 932 933 pixmap->refcnt = 1; 934 } 935 936 pixmap->drawable.width = width; 937 pixmap->drawable.height = height; 938 pixmap->usage_hint = usage; 939 940 (*priv)->header = true; 941 return pixmap; 942} 943 944static PixmapPtr 945sna_pixmap_create_shm(ScreenPtr screen, 946 int width, int height, int depth, 947 char *addr) 948{ 949 struct sna *sna = to_sna_from_screen(screen); 950 int bpp = bits_per_pixel(depth); 951 int pitch = PixmapBytePad(width, depth); 952 struct sna_pixmap *priv; 953 PixmapPtr pixmap; 954 955 DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n", 956 __FUNCTION__, width, height, depth, bpp, pitch)); 957 958 if (wedged(sna) || bpp == 0 || pitch*height < 4096) { 959fallback: 960 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 961 if (pixmap == NULL) 962 return NULL; 963 964 if (!screen->ModifyPixmapHeader(pixmap, width, height, depth, 965 bpp, pitch, addr)) { 966 screen->DestroyPixmap(pixmap); 967 return NULL; 968 } 969 970 return pixmap; 971 } 972 973 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv); 974 if (pixmap == NullPixmap) { 975 DBG(("%s: allocation failed\n", __FUNCTION__)); 976 goto fallback; 977 } 978 979 priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false); 980 if (priv->cpu_bo == NULL) { 981 DBG(("%s: mapping SHM segment failed\n", __FUNCTION__)); 982 sna_pixmap_destroy(pixmap); 983 goto fallback; 984 } 985 priv->cpu_bo->pitch = pitch; 986 kgem_bo_mark_unreusable(priv->cpu_bo); 987 sna_accel_watch_flush(sna, 1); 988#ifdef DEBUG_MEMORY 989 sna->debug_memory.cpu_bo_allocs++; 990 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 991#endif 992 993 /* Be wary as we cannot cache SHM Pixmap in our freed cache */ 994 priv->header = false; 995 priv->cpu = true; 996 priv->shm = true; 997 priv->stride = pitch; 998 priv->ptr = MAKE_STATIC_PTR(addr); 999 sna_damage_all(&priv->cpu_damage, pixmap); 1000 1001 pixmap->devKind = pitch; 1002 pixmap->devPrivate.ptr = addr; 1003 1004 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1005 __FUNCTION__, 1006 pixmap->drawable.serialNumber, 1007 pixmap->drawable.width, 1008 pixmap->drawable.height, 1009 pixmap->usage_hint)); 1010 return pixmap; 1011} 1012 1013PixmapPtr 1014sna_pixmap_create_unattached(ScreenPtr screen, 1015 int width, int height, int depth) 1016{ 1017 return create_pixmap(to_sna_from_screen(screen), 1018 screen, width, height, depth, 1019 -1); 1020} 1021 1022static PixmapPtr 1023sna_pixmap_create_scratch(ScreenPtr screen, 1024 int width, int height, int depth, 1025 uint32_t tiling) 1026{ 1027 struct sna *sna = to_sna_from_screen(screen); 1028 struct sna_pixmap *priv; 1029 PixmapPtr pixmap; 1030 int bpp; 1031 1032 DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__, 1033 width, height, depth, tiling)); 1034 1035 bpp = bits_per_pixel(depth); 1036 if (tiling == I915_TILING_Y && 1037 (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0) 1038 tiling = I915_TILING_X; 1039 1040 if (tiling == I915_TILING_Y && 1041 (width > sna->render.max_3d_size || 1042 height > sna->render.max_3d_size)) 1043 tiling = I915_TILING_X; 1044 1045 tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp); 1046 1047 /* you promise never to access this via the cpu... */ 1048 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv); 1049 if (pixmap == NullPixmap) 1050 return NullPixmap; 1051 1052 priv->stride = PixmapBytePad(width, depth); 1053 1054 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1055 width, height, bpp, tiling, 1056 CREATE_TEMPORARY); 1057 if (priv->gpu_bo == NULL) { 1058 free(priv); 1059 FreePixmap(pixmap); 1060 return NullPixmap; 1061 } 1062 1063 sna_damage_all(&priv->gpu_damage, pixmap); 1064 1065 assert(to_sna_from_pixmap(pixmap) == sna); 1066 assert(pixmap->drawable.pScreen == screen); 1067 assert(pixmap->refcnt == 1); 1068 1069 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1070 __FUNCTION__, 1071 pixmap->drawable.serialNumber, 1072 pixmap->drawable.width, 1073 pixmap->drawable.height, 1074 pixmap->usage_hint)); 1075 return pixmap; 1076} 1077 1078#ifdef CREATE_PIXMAP_USAGE_SHARED 1079static Bool 1080sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle) 1081{ 1082 struct sna *sna = to_sna_from_pixmap(pixmap); 1083 struct sna_pixmap *priv; 1084 int fd; 1085 1086 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1087 1088 priv = sna_pixmap_move_to_gpu(pixmap, 1089 MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_FORCE); 1090 if (priv == NULL) 1091 return FALSE; 1092 1093 assert(!priv->shm); 1094 assert(priv->gpu_bo); 1095 assert(priv->stride); 1096 1097 /* XXX negotiate format and stride restrictions */ 1098 if (priv->gpu_bo->tiling != I915_TILING_NONE || 1099 priv->gpu_bo->pitch & 255) { 1100 struct kgem_bo *bo; 1101 BoxRec box; 1102 1103 DBG(("%s: removing tiling %d, and aligning pitch for %dx%d pixmap=%ld\n", 1104 __FUNCTION__, priv->gpu_bo->tiling, 1105 pixmap->drawable.width, pixmap->drawable.height, 1106 pixmap->drawable.serialNumber)); 1107 1108 if (priv->pinned) { 1109 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 1110 return FALSE; 1111 } 1112 1113 assert_pixmap_damage(pixmap); 1114 1115 bo = kgem_create_2d(&sna->kgem, 1116 pixmap->drawable.width, 1117 pixmap->drawable.height, 1118 pixmap->drawable.bitsPerPixel, 1119 I915_TILING_NONE, 1120 CREATE_GTT_MAP | CREATE_PRIME); 1121 if (bo == NULL) { 1122 DBG(("%s: allocation failed\n", __FUNCTION__)); 1123 return FALSE; 1124 } 1125 1126 box.x1 = box.y1 = 0; 1127 box.x2 = pixmap->drawable.width; 1128 box.y2 = pixmap->drawable.height; 1129 1130 assert(!wedged(sna)); /* XXX */ 1131 if (!sna->render.copy_boxes(sna, GXcopy, 1132 &pixmap->drawable, priv->gpu_bo, 0, 0, 1133 &pixmap->drawable, bo, 0, 0, 1134 &box, 1, 0)) { 1135 DBG(("%s: copy failed\n", __FUNCTION__)); 1136 kgem_bo_destroy(&sna->kgem, bo); 1137 return FALSE; 1138 } 1139 1140 sna_pixmap_unmap(pixmap, priv); 1141 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1142 priv->gpu_bo = bo; 1143 } 1144 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1145 assert((priv->gpu_bo->pitch & 255) == 0); 1146 1147 /* And export the bo->pitch via pixmap->devKind */ 1148 if (!priv->mapped) { 1149 void *ptr; 1150 1151 ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1152 if (ptr == NULL) 1153 return FALSE; 1154 1155 pixmap->devPrivate.ptr = ptr; 1156 pixmap->devKind = priv->gpu_bo->pitch; 1157 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1158 } 1159 assert_pixmap_map(pixmap, priv); 1160 1161 fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo); 1162 if (fd == -1) 1163 return FALSE; 1164 1165 priv->pinned |= PIN_PRIME; 1166 1167 *fd_handle = (void *)(intptr_t)fd; 1168 return TRUE; 1169} 1170 1171static Bool 1172sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle) 1173{ 1174 struct sna *sna = to_sna_from_pixmap(pixmap); 1175 struct sna_pixmap *priv; 1176 struct kgem_bo *bo; 1177 1178 DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n", 1179 __FUNCTION__, pixmap->drawable.serialNumber, 1180 pixmap->drawable.width, pixmap->drawable.height, 1181 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, 1182 pixmap->devKind)); 1183 1184 priv = sna_pixmap(pixmap); 1185 if (priv == NULL) 1186 return FALSE; 1187 1188 assert(!priv->pinned); 1189 assert(priv->gpu_bo == NULL); 1190 assert(priv->cpu_bo == NULL); 1191 assert(priv->cpu_damage == NULL); 1192 assert(priv->gpu_damage == NULL); 1193 1194 bo = kgem_create_for_prime(&sna->kgem, 1195 (intptr_t)fd_handle, 1196 pixmap->devKind * pixmap->drawable.height); 1197 if (bo == NULL) 1198 return FALSE; 1199 1200 sna_damage_all(&priv->gpu_damage, pixmap); 1201 1202 bo->pitch = pixmap->devKind; 1203 priv->stride = pixmap->devKind; 1204 1205 assert(!priv->mapped); 1206 priv->gpu_bo = bo; 1207 priv->pinned |= PIN_PRIME; 1208 1209 close((intptr_t)fd_handle); 1210 return TRUE; 1211} 1212 1213static PixmapPtr 1214sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, 1215 int width, int height, int depth) 1216{ 1217 PixmapPtr pixmap; 1218 struct sna_pixmap *priv; 1219 1220 DBG(("%s: depth=%d\n", __FUNCTION__, depth)); 1221 1222 /* Create a stub to be attached later */ 1223 pixmap = create_pixmap_hdr(sna, screen, 1224 width, height, depth, 0, 1225 &priv); 1226 if (pixmap == NullPixmap) 1227 return NullPixmap; 1228 1229 assert(!priv->mapped); 1230 priv->stride = 0; 1231 priv->create = 0; 1232 1233 if (width|height) { 1234 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1235 width, height, 1236 pixmap->drawable.bitsPerPixel, 1237 I915_TILING_NONE, 1238 CREATE_GTT_MAP | CREATE_PRIME); 1239 if (priv->gpu_bo == NULL) { 1240 free(priv); 1241 FreePixmap(pixmap); 1242 return NullPixmap; 1243 } 1244 1245 /* minimal interface for sharing is linear, 256 byte pitch */ 1246 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1247 assert((priv->gpu_bo->pitch & 255) == 0); 1248 1249 pixmap->devPrivate.ptr = 1250 kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1251 if (pixmap->devPrivate.ptr == NULL) { 1252 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1253 free(priv); 1254 FreePixmap(pixmap); 1255 return FALSE; 1256 } 1257 1258 pixmap->devKind = priv->gpu_bo->pitch; 1259 1260 priv->stride = priv->gpu_bo->pitch; 1261 priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1262 assert_pixmap_map(pixmap, priv); 1263 1264 sna_damage_all(&priv->gpu_damage, pixmap); 1265 } 1266 1267 return pixmap; 1268} 1269#endif 1270 1271static PixmapPtr sna_create_pixmap(ScreenPtr screen, 1272 int width, int height, int depth, 1273 unsigned int usage) 1274{ 1275 struct sna *sna = to_sna_from_screen(screen); 1276 PixmapPtr pixmap; 1277 struct sna_pixmap *priv; 1278 unsigned flags; 1279 int pad; 1280 void *ptr; 1281 1282 DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__, 1283 width, height, depth, usage)); 1284 1285#ifdef CREATE_PIXMAP_USAGE_SHARED 1286 if (usage == CREATE_PIXMAP_USAGE_SHARED) 1287 return sna_create_pixmap_shared(sna, screen, 1288 width, height, depth); 1289#endif 1290 1291 if ((width|height) == 0) { 1292 usage = -1; 1293 goto fallback; 1294 } 1295 assert(width && height); 1296 1297 flags = kgem_can_create_2d(&sna->kgem, width, height, depth); 1298 if (flags == 0) { 1299 DBG(("%s: can not use GPU, just creating shadow\n", 1300 __FUNCTION__)); 1301 goto fallback; 1302 } 1303 1304 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)) 1305 flags &= ~KGEM_CAN_CREATE_GPU; 1306 if (wedged(sna)) 1307 flags &= ~KGEM_CAN_CREATE_GTT; 1308 1309 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags)); 1310 switch (usage) { 1311 case CREATE_PIXMAP_USAGE_SCRATCH: 1312 if (flags & KGEM_CAN_CREATE_GPU) 1313 return sna_pixmap_create_scratch(screen, 1314 width, height, depth, 1315 I915_TILING_X); 1316 else 1317 goto fallback; 1318 1319 case SNA_CREATE_SCRATCH: 1320 if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU)) 1321 return sna_pixmap_create_scratch(screen, 1322 width, height, depth, 1323 I915_TILING_Y); 1324 else 1325 return NullPixmap; 1326 } 1327 1328 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) 1329 flags &= ~KGEM_CAN_CREATE_GPU; 1330 if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 1331 usage = 0; 1332 1333 pad = PixmapBytePad(width, depth); 1334 if (pad * height < 4096) { 1335 DBG(("%s: small buffer [%d], attaching to shadow pixmap\n", 1336 __FUNCTION__, pad * height)); 1337 pixmap = create_pixmap(sna, screen, 1338 width, height, depth, usage); 1339 if (pixmap == NullPixmap) 1340 return NullPixmap; 1341 1342 ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 1343 pad = pixmap->devKind; 1344 flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU); 1345 1346 priv = sna_pixmap_attach(pixmap); 1347 if (priv == NULL) { 1348 free(pixmap); 1349 goto fallback; 1350 } 1351 } else { 1352 DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n", 1353 __FUNCTION__, width, height, pad, flags)); 1354 1355 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv); 1356 if (pixmap == NullPixmap) 1357 return NullPixmap; 1358 1359 ptr = NULL; 1360 } 1361 1362 priv->stride = pad; 1363 priv->create = flags; 1364 priv->ptr = ptr; 1365 1366 assert(to_sna_from_pixmap(pixmap) == sna); 1367 assert(pixmap->drawable.pScreen == screen); 1368 assert(pixmap->refcnt == 1); 1369 1370 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1371 __FUNCTION__, 1372 pixmap->drawable.serialNumber, 1373 pixmap->drawable.width, 1374 pixmap->drawable.height, 1375 pixmap->usage_hint)); 1376 return pixmap; 1377 1378fallback: 1379 return create_pixmap(sna, screen, width, height, depth, usage); 1380} 1381 1382void sna_add_flush_pixmap(struct sna *sna, 1383 struct sna_pixmap *priv, 1384 struct kgem_bo *bo) 1385{ 1386 DBG(("%s: marking pixmap=%ld for flushing\n", 1387 __FUNCTION__, priv->pixmap->drawable.serialNumber)); 1388 assert(bo); 1389 assert(bo->flush); 1390 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1391 list_move(&priv->flush_list, &sna->flush_pixmaps); 1392 1393 if (bo->exec == NULL && kgem_is_idle(&sna->kgem)) { 1394 DBG(("%s: new flush bo, flushin before\n", __FUNCTION__)); 1395 kgem_submit(&sna->kgem); 1396 } 1397} 1398 1399static void __sna_free_pixmap(struct sna *sna, 1400 PixmapPtr pixmap, 1401 struct sna_pixmap *priv) 1402{ 1403 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1404 list_del(&priv->flush_list); 1405 1406 assert(priv->gpu_damage == NULL); 1407 assert(priv->cpu_damage == NULL); 1408 1409 __sna_pixmap_free_cpu(sna, priv); 1410 1411 if (priv->header) { 1412 assert(pixmap->drawable.pScreen == sna->scrn->pScreen); 1413 assert(!priv->shm); 1414 pixmap->devPrivate.ptr = sna->freed_pixmap; 1415 sna->freed_pixmap = pixmap; 1416#if DEBUG_MEMORY 1417 sna->debug_memory.pixmap_cached++; 1418#endif 1419 } else { 1420 free(priv); 1421 FreePixmap(pixmap); 1422 } 1423} 1424 1425static Bool sna_destroy_pixmap(PixmapPtr pixmap) 1426{ 1427 struct sna *sna; 1428 struct sna_pixmap *priv; 1429 1430 assert(pixmap->refcnt > 0); 1431 if (--pixmap->refcnt) 1432 return TRUE; 1433 1434#if DEBUG_MEMORY 1435 to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--; 1436#endif 1437 1438 priv = sna_pixmap(pixmap); 1439 DBG(("%s: pixmap=%ld, attached?=%d\n", 1440 __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL)); 1441 if (priv == NULL) { 1442 FreePixmap(pixmap); 1443 return TRUE; 1444 } 1445 1446 assert_pixmap_damage(pixmap); 1447 sna = to_sna_from_pixmap(pixmap); 1448 1449 sna_damage_destroy(&priv->gpu_damage); 1450 sna_damage_destroy(&priv->cpu_damage); 1451 1452 list_del(&priv->cow_list); 1453 if (priv->cow) { 1454 struct sna_cow *cow = COW(priv->cow); 1455 DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", 1456 __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); 1457 assert(cow->refcnt); 1458 if (!--cow->refcnt) 1459 free(cow); 1460 priv->cow = NULL; 1461 } else 1462 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1463 1464 if (priv->move_to_gpu) 1465 (void)priv->move_to_gpu(sna, priv, 0); 1466 1467 /* Always release the gpu bo back to the lower levels of caching */ 1468 if (priv->gpu_bo) { 1469 sna_pixmap_unmap(pixmap, priv); 1470 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1471 priv->gpu_bo = NULL; 1472 } 1473 1474 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { 1475 DBG(("%s: deferring release of active SHM pixmap=%ld\n", 1476 __FUNCTION__, pixmap->drawable.serialNumber)); 1477 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 1478 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ 1479 } else 1480 __sna_free_pixmap(sna, pixmap, priv); 1481 return TRUE; 1482} 1483 1484void sna_pixmap_destroy(PixmapPtr pixmap) 1485{ 1486 assert(pixmap->refcnt == 1); 1487 assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true); 1488 1489 sna_destroy_pixmap(pixmap); 1490} 1491 1492static inline bool has_coherent_map(struct sna *sna, 1493 struct kgem_bo *bo, 1494 unsigned flags) 1495{ 1496 assert(bo); 1497 1498 if (kgem_bo_mapped(&sna->kgem, bo)) 1499 return true; 1500 1501 if (bo->tiling == I915_TILING_Y) 1502 return false; 1503 1504 return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE); 1505} 1506 1507static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1508{ 1509 if (priv == NULL) 1510 return true; 1511 1512 if (flags & MOVE_ASYNC_HINT) { 1513 /* Not referencing the pointer itself, so do not care */ 1514 return true; 1515 } 1516 1517 if (!priv->mapped) { 1518 if (!priv->cpu_bo) 1519 return true; 1520 1521 assert(!priv->cpu_bo->needs_flush); 1522 assert(priv->pixmap->devKind == priv->cpu_bo->pitch); 1523 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu); 1524 } 1525 1526 assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0); 1527 1528 assert_pixmap_map(priv->pixmap, priv); 1529 assert(priv->pixmap->devKind == priv->gpu_bo->pitch); 1530 1531 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) { 1532 assert(priv->mapped == MAPPED_CPU); 1533 1534 if (priv->gpu_bo->tiling != I915_TILING_NONE) 1535 return false; 1536 1537 return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE); 1538 } 1539 1540 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) { 1541 assert(priv->mapped == MAPPED_GTT); 1542 1543 if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21) 1544 return false; 1545 1546 return true; 1547 } 1548 1549 return false; 1550} 1551 1552static inline bool pixmap_inplace(struct sna *sna, 1553 PixmapPtr pixmap, 1554 struct sna_pixmap *priv, 1555 unsigned flags) 1556{ 1557 if (FORCE_INPLACE) 1558 return FORCE_INPLACE > 0; 1559 1560 if (wedged(sna) && !priv->pinned) { 1561 DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__)); 1562 return false; 1563 } 1564 1565 if (priv->move_to_gpu && flags & MOVE_WRITE) 1566 return false; 1567 1568 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 1569 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) { 1570 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__)); 1571 return false; 1572 } 1573 1574 if ((flags & MOVE_READ) == 0) { 1575 DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes")); 1576 return !priv->pinned; 1577 } 1578 } 1579 1580 if (priv->mapped) { 1581 DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 1582 return has_coherent_map(sna, priv->gpu_bo, flags); 1583 } 1584 1585 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 1586 DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__)); 1587 return true; 1588 } 1589 1590 if (priv->cpu_bo && priv->cpu) { 1591 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 1592 return false; 1593 } 1594 1595 if (flags & MOVE_READ && 1596 (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) { 1597 DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__)); 1598 return false; 1599 } 1600 1601 return (priv->stride * pixmap->drawable.height >> 12) > 1602 sna->kgem.half_cpu_cache_pages; 1603} 1604 1605static bool sna_pixmap_alloc_gpu(struct sna *sna, 1606 PixmapPtr pixmap, 1607 struct sna_pixmap *priv, 1608 unsigned flags) 1609{ 1610 uint32_t tiling; 1611 1612 /* Use tiling by default, but disable per user request */ 1613 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) { 1614 flags |= CREATE_SCANOUT; 1615 tiling = -I915_TILING_X; 1616 } else 1617 tiling = sna_pixmap_default_tiling(sna, pixmap); 1618 1619 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1620 1621 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1622 pixmap->drawable.width, 1623 pixmap->drawable.height, 1624 pixmap->drawable.bitsPerPixel, 1625 tiling, flags); 1626 return priv->gpu_bo != NULL; 1627} 1628 1629static bool 1630sna_pixmap_create_mappable_gpu(PixmapPtr pixmap, 1631 bool can_replace) 1632{ 1633 struct sna *sna = to_sna_from_pixmap(pixmap); 1634 struct sna_pixmap *priv = sna_pixmap(pixmap); 1635 1636 if (wedged(sna)) 1637 goto out; 1638 1639 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) 1640 goto out; 1641 1642 assert_pixmap_damage(pixmap); 1643 1644 if (can_replace && priv->gpu_bo && 1645 (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) || 1646 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1647 if (priv->pinned) 1648 return false; 1649 1650 DBG(("%s: discard busy GPU bo\n", __FUNCTION__)); 1651 sna_pixmap_free_gpu(sna, priv); 1652 } 1653 1654 if (priv->gpu_bo == NULL) { 1655 assert_pixmap_damage(pixmap); 1656 assert(priv->gpu_damage == NULL); 1657 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE); 1658 } 1659 1660out: 1661 if (priv->gpu_bo == NULL) 1662 return false; 1663 1664 return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1665 !kgem_bo_is_busy(priv->gpu_bo)); 1666} 1667 1668static inline bool gpu_bo_download(struct sna *sna, 1669 struct sna_pixmap *priv, 1670 int n, const BoxRec *box, 1671 bool idle) 1672{ 1673 char *src; 1674 1675 if (!USE_INPLACE) 1676 return false; 1677 1678 switch (priv->gpu_bo->tiling) { 1679 case I915_TILING_Y: 1680 return false; 1681 case I915_TILING_X: 1682 if (!sna->kgem.memcpy_from_tiled_x) 1683 return false; 1684 default: 1685 break; 1686 } 1687 1688 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 1689 return false; 1690 1691 if (idle) { 1692 if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 1693 return false; 1694 1695 if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) 1696 return false; 1697 } 1698 1699 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 1700 if (src == NULL) 1701 return false; 1702 1703 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 1704 1705 if (priv->cpu_bo) 1706 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1707 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1708 1709 if (sigtrap_get()) 1710 return false; 1711 1712 if (priv->gpu_bo->tiling) { 1713 int bpp = priv->pixmap->drawable.bitsPerPixel; 1714 void *dst = priv->pixmap->devPrivate.ptr; 1715 int dst_pitch = priv->pixmap->devKind; 1716 1717 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 1718 do { 1719 DBG(("%s: box (%d, %d), (%d, %d)\n", 1720 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1721 memcpy_from_tiled_x(&sna->kgem, src, dst, bpp, 1722 priv->gpu_bo->pitch, dst_pitch, 1723 box->x1, box->y1, 1724 box->x1, box->y1, 1725 box->x2 - box->x1, box->y2 - box->y1); 1726 box++; 1727 } while (--n); 1728 } else { 1729 int bpp = priv->pixmap->drawable.bitsPerPixel; 1730 void *dst = priv->pixmap->devPrivate.ptr; 1731 int dst_pitch = priv->pixmap->devKind; 1732 1733 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 1734 do { 1735 DBG(("%s: box (%d, %d), (%d, %d)\n", 1736 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1737 memcpy_blt(src, dst, bpp, 1738 priv->gpu_bo->pitch, dst_pitch, 1739 box->x1, box->y1, 1740 box->x1, box->y1, 1741 box->x2 - box->x1, box->y2 - box->y1); 1742 box++; 1743 } while (--n); 1744 } 1745 1746 sigtrap_put(); 1747 return true; 1748} 1749 1750static inline bool cpu_bo_download(struct sna *sna, 1751 struct sna_pixmap *priv, 1752 int n, const BoxRec *box) 1753{ 1754 if (DBG_NO_CPU_DOWNLOAD) 1755 return false; 1756 1757 if (wedged(sna)) 1758 return false; 1759 1760 if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu) 1761 return false; 1762 1763 if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) { 1764 /* Is it worth detiling? */ 1765 assert(box[0].y1 < box[n-1].y2); 1766 if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1767 (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) { 1768 DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n", 1769 __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch)); 1770 return false; 1771 } 1772 } 1773 1774 DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__)); 1775 return sna->render.copy_boxes(sna, GXcopy, 1776 &priv->pixmap->drawable, priv->gpu_bo, 0, 0, 1777 &priv->pixmap->drawable, priv->cpu_bo, 0, 0, 1778 box, n, COPY_LAST); 1779} 1780 1781static void download_boxes(struct sna *sna, 1782 struct sna_pixmap *priv, 1783 int n, const BoxRec *box) 1784{ 1785 bool ok; 1786 1787 DBG(("%s: nbox=%d\n", __FUNCTION__, n)); 1788 1789 ok = gpu_bo_download(sna, priv, n, box, true); 1790 if (!ok) 1791 ok = cpu_bo_download(sna, priv, n, box); 1792 if (!ok) 1793 ok = gpu_bo_download(sna, priv, n, box, false); 1794 if (!ok) { 1795 if (priv->cpu_bo) 1796 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1797 assert(priv->mapped == MAPPED_NONE); 1798 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1799 sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n); 1800 } 1801} 1802 1803static inline bool use_cpu_bo_for_upload(struct sna *sna, 1804 struct sna_pixmap *priv, 1805 unsigned flags) 1806{ 1807 if (DBG_NO_CPU_UPLOAD) 1808 return false; 1809 1810 if (wedged(sna)) 1811 return false; 1812 1813 if (priv->cpu_bo == NULL) 1814 return false; 1815 1816 DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__, 1817 flags, 1818 kgem_bo_is_busy(priv->gpu_bo), 1819 kgem_bo_is_busy(priv->cpu_bo))); 1820 1821 if (!priv->cpu) 1822 return true; 1823 1824 if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) 1825 return true; 1826 1827 if (priv->gpu_bo->tiling) 1828 return true; 1829 1830 return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo); 1831} 1832 1833bool 1834sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1835{ 1836 struct sna_cow *cow = COW(priv->cow); 1837 1838 DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n", 1839 __FUNCTION__, 1840 priv->pixmap->drawable.serialNumber, 1841 priv->gpu_bo->handle, 1842 priv->gpu_bo->refcnt, 1843 cow->refcnt, 1844 flags)); 1845 1846 assert(priv->gpu_bo == cow->bo); 1847 assert(cow->refcnt); 1848 1849 if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow)) 1850 return true; 1851 1852 if (!IS_COW_OWNER(priv->cow)) 1853 list_del(&priv->cow_list); 1854 1855 if (!--cow->refcnt) { 1856 DBG(("%s: freeing cow\n", __FUNCTION__)); 1857 assert(list_is_empty(&cow->list)); 1858 free(cow); 1859 } else if (IS_COW_OWNER(priv->cow) && priv->pinned) { 1860 PixmapPtr pixmap = priv->pixmap; 1861 struct kgem_bo *bo; 1862 BoxRec box; 1863 1864 DBG(("%s: copying the Holy cow\n", __FUNCTION__)); 1865 1866 box.x1 = box.y1 = 0; 1867 box.x2 = pixmap->drawable.width; 1868 box.y2 = pixmap->drawable.height; 1869 1870 bo = kgem_create_2d(&sna->kgem, 1871 box.x2, box.y2, 1872 pixmap->drawable.bitsPerPixel, 1873 sna_pixmap_default_tiling(sna, pixmap), 1874 0); 1875 if (bo == NULL) { 1876 cow->refcnt++; 1877 DBG(("%s: allocation failed\n", __FUNCTION__)); 1878 return false; 1879 } 1880 1881 if (!sna->render.copy_boxes(sna, GXcopy, 1882 &pixmap->drawable, priv->gpu_bo, 0, 0, 1883 &pixmap->drawable, bo, 0, 0, 1884 &box, 1, 0)) { 1885 DBG(("%s: copy failed\n", __FUNCTION__)); 1886 kgem_bo_destroy(&sna->kgem, bo); 1887 cow->refcnt++; 1888 return false; 1889 } 1890 1891 assert(!list_is_empty(&cow->list)); 1892 while (!list_is_empty(&cow->list)) { 1893 struct sna_pixmap *clone; 1894 1895 clone = list_first_entry(&cow->list, 1896 struct sna_pixmap, cow_list); 1897 list_del(&clone->cow_list); 1898 1899 assert(clone->gpu_bo == cow->bo); 1900 sna_pixmap_unmap(clone->pixmap, clone); 1901 kgem_bo_destroy(&sna->kgem, clone->gpu_bo); 1902 clone->gpu_bo = kgem_bo_reference(bo); 1903 } 1904 cow->bo = bo; 1905 kgem_bo_destroy(&sna->kgem, bo); 1906 } else { 1907 struct kgem_bo *bo = NULL; 1908 1909 if (flags & MOVE_READ) { 1910 PixmapPtr pixmap = priv->pixmap; 1911 BoxRec box; 1912 1913 DBG(("%s: copying cow\n", __FUNCTION__)); 1914 1915 box.x1 = box.y1 = 0; 1916 box.x2 = pixmap->drawable.width; 1917 box.y2 = pixmap->drawable.height; 1918 1919 bo = kgem_create_2d(&sna->kgem, 1920 box.x2, box.y2, 1921 pixmap->drawable.bitsPerPixel, 1922 sna_pixmap_default_tiling(sna, pixmap), 1923 0); 1924 if (bo == NULL) { 1925 cow->refcnt++; 1926 DBG(("%s: allocation failed\n", __FUNCTION__)); 1927 return false; 1928 } 1929 1930 if (!sna->render.copy_boxes(sna, GXcopy, 1931 &pixmap->drawable, priv->gpu_bo, 0, 0, 1932 &pixmap->drawable, bo, 0, 0, 1933 &box, 1, 0)) { 1934 DBG(("%s: copy failed\n", __FUNCTION__)); 1935 kgem_bo_destroy(&sna->kgem, bo); 1936 cow->refcnt++; 1937 return false; 1938 } 1939 } 1940 1941 assert(priv->gpu_bo); 1942 sna_pixmap_unmap(priv->pixmap, priv); 1943 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1944 priv->gpu_bo = bo; 1945 } 1946 1947 priv->cow = NULL; 1948 return true; 1949} 1950 1951static bool 1952sna_pixmap_make_cow(struct sna *sna, 1953 struct sna_pixmap *src_priv, 1954 struct sna_pixmap *dst_priv) 1955{ 1956 struct sna_cow *cow; 1957 1958 assert(src_priv->gpu_bo); 1959 1960 if (!USE_COW) 1961 return false; 1962 1963 if (src_priv->gpu_bo->proxy) 1964 return false; 1965 1966 DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n", 1967 __FUNCTION__, 1968 src_priv->pixmap->drawable.serialNumber, 1969 dst_priv->pixmap->drawable.serialNumber, 1970 src_priv->gpu_bo->handle, 1971 src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0, 1972 dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0)); 1973 1974 if (dst_priv->pinned) { 1975 DBG(("%s: can't cow, dst_pinned=%x\n", 1976 __FUNCTION__, dst_priv->pinned)); 1977 return false; 1978 } 1979 1980 assert(dst_priv->move_to_gpu == NULL); 1981 assert(!dst_priv->flush); 1982 assert(list_is_empty(&dst_priv->cow_list)); 1983 1984 cow = COW(src_priv->cow); 1985 if (cow == NULL) { 1986 cow = malloc(sizeof(*cow)); 1987 if (cow == NULL) 1988 return false; 1989 1990 list_init(&cow->list); 1991 1992 cow->bo = src_priv->gpu_bo; 1993 cow->refcnt = 1; 1994 1995 DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n", 1996 __FUNCTION__, 1997 src_priv->pixmap->drawable.serialNumber, 1998 cow->bo->handle)); 1999 2000 src_priv->cow = MAKE_COW_OWNER(cow); 2001 } 2002 2003 if (cow == COW(dst_priv->cow)) { 2004 assert(dst_priv->gpu_bo == cow->bo); 2005 return true; 2006 } 2007 2008 if (dst_priv->cow) 2009 sna_pixmap_undo_cow(sna, dst_priv, 0); 2010 2011 if (dst_priv->gpu_bo) { 2012 sna_pixmap_unmap(dst_priv->pixmap, dst_priv); 2013 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 2014 } 2015 assert(!dst_priv->mapped); 2016 dst_priv->gpu_bo = kgem_bo_reference(cow->bo); 2017 dst_priv->cow = cow; 2018 list_add(&dst_priv->cow_list, &cow->list); 2019 cow->refcnt++; 2020 2021 DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n", 2022 __FUNCTION__, 2023 dst_priv->pixmap->drawable.serialNumber, 2024 src_priv->pixmap->drawable.serialNumber, 2025 cow->bo->handle)); 2026 2027 return true; 2028} 2029 2030static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags) 2031{ 2032 if (!USE_INPLACE) 2033 return false; 2034 2035 if ((flags & MOVE_INPLACE_HINT) == 0) { 2036 DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__)); 2037 return false; 2038 } 2039 2040 assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE)); 2041 2042 if (priv->move_to_gpu && flags & MOVE_WRITE) { 2043 DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__)); 2044 return false; 2045 } 2046 2047 if (priv->cow && flags & MOVE_WRITE) { 2048 DBG(("%s: no, has COW\n", __FUNCTION__)); 2049 return false; 2050 } 2051 2052 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) { 2053 DBG(("%s: no, not accessible via GTT\n", __FUNCTION__)); 2054 return false; 2055 } 2056 2057 if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) { 2058 DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__)); 2059 return false; 2060 } 2061 2062 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 2063 DBG(("%s: yes, CPU is busy\n", __FUNCTION__)); 2064 return true; 2065 } 2066 2067 if (priv->create & KGEM_CAN_CREATE_LARGE) { 2068 DBG(("%s: large object, has GPU? %d\n", 2069 __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0)); 2070 return priv->gpu_bo != NULL; 2071 } 2072 2073 if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) { 2074 DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__)); 2075 return false; 2076 } 2077 2078 return true; 2079} 2080 2081bool 2082_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) 2083{ 2084 struct sna *sna = to_sna_from_pixmap(pixmap); 2085 struct sna_pixmap *priv; 2086 2087 DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__, 2088 pixmap->drawable.serialNumber, 2089 pixmap->drawable.width, 2090 pixmap->drawable.height, 2091 flags)); 2092 2093 assert(flags & (MOVE_READ | MOVE_WRITE)); 2094 assert_pixmap_damage(pixmap); 2095 2096 priv = sna_pixmap(pixmap); 2097 if (priv == NULL) { 2098 DBG(("%s: not attached\n", __FUNCTION__)); 2099 return true; 2100 } 2101 2102 DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n", 2103 __FUNCTION__, 2104 priv->gpu_bo ? priv->gpu_bo->handle : 0, 2105 priv->gpu_damage, priv->cpu_damage, priv->clear)); 2106 2107 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2108 2109 if ((flags & MOVE_READ) == 0 && UNDO) { 2110 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 2111 if (priv->move_to_gpu) 2112 sna_pixmap_discard_shadow_damage(priv, NULL); 2113 } 2114 2115 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2116 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2117 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2118 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2119 goto skip; 2120 } 2121 2122 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2123 assert(priv->gpu_damage == NULL); 2124 assert(!priv->pinned); 2125 assert(!priv->mapped); 2126 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2127 priv->gpu_bo = NULL; 2128 } 2129 2130 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 2131 DBG(("%s: CPU all-damaged\n", __FUNCTION__)); 2132 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); 2133 assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0); 2134 goto done; 2135 } 2136 2137 if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) { 2138 assert(flags & MOVE_WRITE); 2139 DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n", 2140 __FUNCTION__, priv->gpu_damage != NULL, priv->clear)); 2141 2142 if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) && 2143 pixmap_inplace(sna, pixmap, priv, flags) && 2144 sna_pixmap_create_mappable_gpu(pixmap, true)) { 2145 void *ptr; 2146 2147 DBG(("%s: write inplace\n", __FUNCTION__)); 2148 assert(!priv->shm); 2149 assert(priv->cow == NULL); 2150 assert(priv->move_to_gpu == NULL); 2151 assert(priv->gpu_bo->exec == NULL); 2152 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2153 2154 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2155 if (ptr == NULL) 2156 goto skip_inplace_map; 2157 2158 pixmap->devPrivate.ptr = ptr; 2159 pixmap->devKind = priv->gpu_bo->pitch; 2160 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2161 assert(has_coherent_ptr(sna, priv, flags)); 2162 2163 assert(priv->gpu_bo->proxy == NULL); 2164 sna_damage_all(&priv->gpu_damage, pixmap); 2165 sna_damage_destroy(&priv->cpu_damage); 2166 priv->clear = false; 2167 list_del(&priv->flush_list); 2168 2169 assert(!priv->shm); 2170 assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush); 2171 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2172 priv->cpu &= priv->mapped == MAPPED_CPU; 2173 2174 assert_pixmap_damage(pixmap); 2175 return true; 2176 } 2177 2178skip_inplace_map: 2179 sna_damage_destroy(&priv->gpu_damage); 2180 priv->clear = false; 2181 if ((flags & MOVE_ASYNC_HINT) == 0 && 2182 priv->cpu_bo && !priv->cpu_bo->flush && 2183 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2184 DBG(("%s: discarding busy CPU bo\n", __FUNCTION__)); 2185 assert(!priv->shm); 2186 assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL); 2187 2188 sna_damage_destroy(&priv->cpu_damage); 2189 sna_pixmap_free_cpu(sna, priv, false); 2190 2191 assert(priv->mapped == MAPPED_NONE); 2192 if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0)) 2193 return false; 2194 assert(priv->mapped == MAPPED_NONE); 2195 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2196 2197 goto mark_damage; 2198 } 2199 } 2200 2201 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2202 2203 if (operate_inplace(priv, flags) && 2204 pixmap_inplace(sna, pixmap, priv, flags) && 2205 sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) { 2206 void *ptr; 2207 2208 DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__)); 2209 assert(priv->gpu_bo); 2210 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2211 assert(!priv->move_to_gpu); 2212 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2213 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2214 /* XXX only sync for writes? */ 2215 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2216 assert(priv->gpu_bo->exec == NULL); 2217 2218 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2219 if (ptr != NULL) { 2220 pixmap->devPrivate.ptr = ptr; 2221 pixmap->devKind = priv->gpu_bo->pitch; 2222 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2223 assert(has_coherent_ptr(sna, priv, flags)); 2224 2225 if (flags & MOVE_WRITE) { 2226 assert(priv->gpu_bo->proxy == NULL); 2227 sna_damage_all(&priv->gpu_damage, pixmap); 2228 sna_damage_destroy(&priv->cpu_damage); 2229 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2230 list_del(&priv->flush_list); 2231 priv->clear = false; 2232 } 2233 priv->cpu &= priv->mapped == MAPPED_CPU; 2234 2235 assert_pixmap_damage(pixmap); 2236 DBG(("%s: operate inplace (GTT)\n", __FUNCTION__)); 2237 return true; 2238 } 2239 } 2240 2241 sna_pixmap_unmap(pixmap, priv); 2242 2243 if (USE_INPLACE && 2244 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL && 2245 priv->gpu_bo->tiling == I915_TILING_NONE && 2246 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) && 2247 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2248 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) { 2249 void *ptr; 2250 2251 DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__)); 2252 assert(priv->gpu_bo); 2253 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2254 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2255 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2256 2257 assert(!priv->mapped); 2258 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 2259 2260 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2261 if (ptr != NULL) { 2262 pixmap->devPrivate.ptr = ptr; 2263 pixmap->devKind = priv->gpu_bo->pitch; 2264 priv->mapped = MAPPED_CPU; 2265 assert(has_coherent_ptr(sna, priv, flags)); 2266 2267 if (flags & MOVE_WRITE) { 2268 assert(priv->gpu_bo->proxy == NULL); 2269 sna_damage_all(&priv->gpu_damage, pixmap); 2270 sna_damage_destroy(&priv->cpu_damage); 2271 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2272 list_del(&priv->flush_list); 2273 priv->clear = false; 2274 priv->cpu = true; 2275 } 2276 2277 assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)); 2278 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2279 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2280 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2281 assert_pixmap_damage(pixmap); 2282 assert(has_coherent_ptr(sna, priv, flags)); 2283 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2284 return true; 2285 } 2286 } 2287 2288 assert(priv->mapped == MAPPED_NONE); 2289 if (((flags & MOVE_READ) == 0 || priv->clear) && 2290 priv->cpu_bo && !priv->cpu_bo->flush && 2291 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2292 assert(!priv->shm); 2293 sna_pixmap_free_cpu(sna, priv, false); 2294 } 2295 2296 assert(priv->mapped == MAPPED_NONE); 2297 if (pixmap->devPrivate.ptr == NULL && 2298 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2299 return false; 2300 assert(priv->mapped == MAPPED_NONE); 2301 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2302 2303 if (flags & MOVE_READ) { 2304 if (priv->clear) { 2305 DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n", 2306 __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height, 2307 pixmap->devKind, pixmap->devKind * pixmap->drawable.height)); 2308 2309 if (priv->cpu_bo) { 2310 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2311 sna->render.fill_one(sna, 2312 pixmap, priv->cpu_bo, priv->clear_color, 2313 0, 0, 2314 pixmap->drawable.width, 2315 pixmap->drawable.height, 2316 GXcopy)) 2317 goto clear_done; 2318 2319 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2320 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2321 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2322 } 2323 2324 assert(pixmap->devKind); 2325 if (priv->clear_color == 0 || 2326 pixmap->drawable.bitsPerPixel == 8 || 2327 priv->clear_color == (1 << pixmap->drawable.depth) - 1) { 2328 memset(pixmap->devPrivate.ptr, priv->clear_color, 2329 (size_t)pixmap->devKind * pixmap->drawable.height); 2330 } else { 2331 pixman_fill(pixmap->devPrivate.ptr, 2332 pixmap->devKind/sizeof(uint32_t), 2333 pixmap->drawable.bitsPerPixel, 2334 0, 0, 2335 pixmap->drawable.width, 2336 pixmap->drawable.height, 2337 priv->clear_color); 2338 } 2339 2340clear_done: 2341 sna_damage_all(&priv->cpu_damage, pixmap); 2342 sna_pixmap_free_gpu(sna, priv); 2343 assert(priv->gpu_damage == NULL); 2344 assert(priv->clear == false); 2345 } 2346 2347 if (priv->gpu_damage) { 2348 const BoxRec *box; 2349 int n; 2350 2351 DBG(("%s: flushing GPU damage\n", __FUNCTION__)); 2352 assert(priv->gpu_bo); 2353 2354 n = sna_damage_get_boxes(priv->gpu_damage, &box); 2355 if (n) { 2356 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) { 2357 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2358 return false; 2359 } 2360 2361 download_boxes(sna, priv, n, box); 2362 } 2363 2364 __sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage)); 2365 priv->gpu_damage = NULL; 2366 } 2367 } 2368 2369 if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) { 2370mark_damage: 2371 DBG(("%s: marking as damaged\n", __FUNCTION__)); 2372 sna_damage_all(&priv->cpu_damage, pixmap); 2373 sna_pixmap_free_gpu(sna, priv); 2374 assert(priv->gpu_damage == NULL); 2375 assert(priv->clear == false); 2376 2377 if (priv->flush) { 2378 assert(!priv->shm); 2379 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2380 } 2381 } 2382 2383done: 2384 if (flags & MOVE_WRITE) { 2385 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2386 assert(priv->gpu_damage == NULL); 2387 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2388 if (priv->cow) 2389 sna_pixmap_undo_cow(sna, priv, 0); 2390 if (priv->gpu_bo && priv->gpu_bo->rq == NULL) { 2391 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__)); 2392 sna_pixmap_free_gpu(sna, priv); 2393 } 2394 priv->source_count = SOURCE_BIAS; 2395 } 2396 2397 if (priv->cpu_bo) { 2398 if ((flags & MOVE_ASYNC_HINT) == 0) { 2399 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2400 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2401 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2402 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2403 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2404 } 2405 } 2406skip: 2407 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 2408 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2409 assert(pixmap->devKind); 2410 assert_pixmap_damage(pixmap); 2411 assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags)); 2412 return true; 2413} 2414 2415static bool 2416region_overlaps_damage(const RegionRec *region, 2417 struct sna_damage *damage, 2418 int dx, int dy) 2419{ 2420 const BoxRec *re, *de; 2421 2422 DBG(("%s?\n", __FUNCTION__)); 2423 2424 if (damage == NULL) 2425 return false; 2426 2427 if (DAMAGE_IS_ALL(damage)) 2428 return true; 2429 2430 re = ®ion->extents; 2431 de = &DAMAGE_PTR(damage)->extents; 2432 DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n", 2433 __FUNCTION__, 2434 re->x1, re->y1, re->x2, re->y2, 2435 de->x1, de->y1, de->x2, de->y2)); 2436 2437 return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 && 2438 re->y1 + dy < de->y2 && re->y2 + dy > de->y1); 2439} 2440 2441static inline bool region_inplace(struct sna *sna, 2442 PixmapPtr pixmap, 2443 RegionPtr region, 2444 struct sna_pixmap *priv, 2445 unsigned flags) 2446{ 2447 assert_pixmap_damage(pixmap); 2448 2449 if (FORCE_INPLACE) 2450 return FORCE_INPLACE > 0; 2451 2452 if (wedged(sna) && !priv->pinned) 2453 return false; 2454 2455 if (priv->gpu_damage && 2456 (priv->clear || (flags & MOVE_READ) == 0) && 2457 kgem_bo_is_busy(priv->gpu_bo)) 2458 return false; 2459 2460 if (flags & MOVE_READ && 2461 (priv->cpu || 2462 priv->gpu_damage == NULL || 2463 region_overlaps_damage(region, priv->cpu_damage, 0, 0))) { 2464 DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__)); 2465 return false; 2466 } 2467 2468 if (priv->mapped) { 2469 DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__, 2470 has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 2471 return has_coherent_map(sna, priv->gpu_bo, flags); 2472 } 2473 2474 if (priv->flush) { 2475 DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__)); 2476 return true; 2477 } 2478 2479 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2480 DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__)); 2481 assert(priv->gpu_bo); 2482 return true; 2483 } 2484 2485 if (priv->cpu_bo && priv->cpu) { 2486 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 2487 return false; 2488 } 2489 2490 DBG(("%s: (%dx%d), inplace? %d\n", 2491 __FUNCTION__, 2492 region->extents.x2 - region->extents.x1, 2493 region->extents.y2 - region->extents.y1, 2494 ((int)(region->extents.x2 - region->extents.x1) * 2495 (int)(region->extents.y2 - region->extents.y1) * 2496 pixmap->drawable.bitsPerPixel >> 12) 2497 >= sna->kgem.half_cpu_cache_pages)); 2498 return ((int)(region->extents.x2 - region->extents.x1) * 2499 (int)(region->extents.y2 - region->extents.y1) * 2500 pixmap->drawable.bitsPerPixel >> 12) 2501 >= sna->kgem.half_cpu_cache_pages; 2502} 2503 2504static bool cpu_clear_boxes(struct sna *sna, 2505 PixmapPtr pixmap, 2506 struct sna_pixmap *priv, 2507 const BoxRec *box, int n) 2508{ 2509 struct sna_fill_op fill; 2510 2511 if (!sna_fill_init_blt(&fill, sna, 2512 pixmap, priv->cpu_bo, 2513 GXcopy, priv->clear_color, 2514 FILL_BOXES)) { 2515 DBG(("%s: unsupported fill\n", 2516 __FUNCTION__)); 2517 return false; 2518 } 2519 2520 fill.boxes(sna, &fill, box, n); 2521 fill.done(sna, &fill); 2522 return true; 2523} 2524 2525bool 2526sna_drawable_move_region_to_cpu(DrawablePtr drawable, 2527 RegionPtr region, 2528 unsigned flags) 2529{ 2530 PixmapPtr pixmap = get_drawable_pixmap(drawable); 2531 struct sna *sna = to_sna_from_pixmap(pixmap); 2532 struct sna_pixmap *priv; 2533 int16_t dx, dy; 2534 2535 DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n", 2536 __FUNCTION__, pixmap->drawable.serialNumber, 2537 pixmap->drawable.width, pixmap->drawable.height, 2538 RegionExtents(region)->x1, RegionExtents(region)->y1, 2539 RegionExtents(region)->x2, RegionExtents(region)->y2, 2540 flags)); 2541 2542 assert_pixmap_damage(pixmap); 2543 if (flags & MOVE_WRITE) { 2544 assert_drawable_contains_box(drawable, ®ion->extents); 2545 } 2546 assert(flags & (MOVE_WRITE | MOVE_READ)); 2547 2548 if (box_empty(®ion->extents)) 2549 return true; 2550 2551 if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) { 2552 if (!region_subsumes_pixmap(region, pixmap)) 2553 flags |= MOVE_READ; 2554 return _sna_pixmap_move_to_cpu(pixmap, flags); 2555 } 2556 2557 priv = sna_pixmap(pixmap); 2558 if (priv == NULL) { 2559 DBG(("%s: not attached to pixmap %ld (depth %d)\n", 2560 __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth)); 2561 return true; 2562 } 2563 2564 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2565 2566 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2567 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2568 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2569 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2570 goto skip; 2571 } 2572 2573 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2574 assert(priv->gpu_damage == NULL); 2575 assert(!priv->pinned); 2576 assert(!priv->mapped); 2577 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2578 priv->gpu_bo = NULL; 2579 } 2580 2581 if (sna_damage_is_all(&priv->cpu_damage, 2582 pixmap->drawable.width, 2583 pixmap->drawable.height)) { 2584 bool discard_gpu = priv->cpu; 2585 2586 DBG(("%s: pixmap=%ld all damaged on CPU\n", 2587 __FUNCTION__, pixmap->drawable.serialNumber)); 2588 assert(!priv->clear); 2589 2590 sna_damage_destroy(&priv->gpu_damage); 2591 2592 if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2593 priv->cpu_bo && !priv->cpu_bo->flush && 2594 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2595 DBG(("%s: active CPU bo replacing\n", __FUNCTION__)); 2596 assert(!priv->shm); 2597 assert(!IS_STATIC_PTR(priv->ptr)); 2598 2599 if (!region_subsumes_pixmap(region, pixmap)) { 2600 DBG(("%s: partial replacement\n", __FUNCTION__)); 2601 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 2602 RegionTranslate(region, dx, dy); 2603 2604 if (sna->kgem.has_llc && !priv->pinned && 2605 sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) { 2606#ifdef DEBUG_MEMORY 2607 sna->debug_memory.cpu_bo_allocs--; 2608 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 2609#endif 2610 DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__)); 2611 if (priv->gpu_bo) 2612 sna_pixmap_free_gpu(sna, priv); 2613 priv->gpu_bo = priv->cpu_bo; 2614 priv->cpu_bo = NULL; 2615 priv->ptr = NULL; 2616 pixmap->devPrivate.ptr = NULL; 2617 2618 priv->gpu_damage = priv->cpu_damage; 2619 priv->cpu_damage = NULL; 2620 2621 sna_damage_subtract(&priv->gpu_damage, region); 2622 discard_gpu = false; 2623 } else { 2624 DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__)); 2625 sna_damage_subtract(&priv->cpu_damage, region); 2626 assert(priv->cpu_damage); 2627 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2628 sna_pixmap_free_cpu(sna, priv, false); 2629 if (priv->flush) 2630 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2631 2632 assert(priv->cpu_damage == NULL); 2633 sna_damage_all(&priv->gpu_damage, pixmap); 2634 sna_damage_subtract(&priv->gpu_damage, region); 2635 discard_gpu = false; 2636 } 2637 } 2638 sna_damage_add(&priv->cpu_damage, region); 2639 2640 if (dx | dy) 2641 RegionTranslate(region, -dx, -dy); 2642 } else 2643 sna_pixmap_free_cpu(sna, priv, false); 2644 } 2645 2646 if (flags & MOVE_WRITE && discard_gpu) 2647 sna_pixmap_free_gpu(sna, priv); 2648 2649 sna_pixmap_unmap(pixmap, priv); 2650 assert(priv->mapped == MAPPED_NONE); 2651 if (pixmap->devPrivate.ptr == NULL && 2652 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2653 return false; 2654 assert(priv->mapped == MAPPED_NONE); 2655 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2656 2657 goto out; 2658 } 2659 2660 if (USE_INPLACE && 2661 (priv->create & KGEM_CAN_CREATE_LARGE || 2662 ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2663 (priv->flush || 2664 (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) || 2665 box_inplace(pixmap, ®ion->extents))))) { 2666 DBG(("%s: marking for inplace hint (%d, %d)\n", 2667 __FUNCTION__, priv->flush, box_inplace(pixmap, ®ion->extents))); 2668 flags |= MOVE_INPLACE_HINT; 2669 } 2670 2671 if (region_subsumes_pixmap(region, pixmap)) { 2672 DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n", 2673 __FUNCTION__, 2674 region->extents.x1, 2675 region->extents.y1, 2676 region->extents.x2, 2677 region->extents.y2, 2678 get_drawable_dx(drawable), get_drawable_dy(drawable), 2679 pixmap->drawable.width, 2680 pixmap->drawable.height)); 2681 return _sna_pixmap_move_to_cpu(pixmap, flags); 2682 } 2683 2684 if (priv->move_to_gpu) { 2685 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 2686 if ((flags & MOVE_READ) == 0) 2687 sna_pixmap_discard_shadow_damage(priv, region); 2688 if (!priv->move_to_gpu(sna, priv, MOVE_READ)) { 2689 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2690 return NULL; 2691 } 2692 } 2693 2694 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2695 2696 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 2697 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 2698 RegionTranslate(region, dx, dy); 2699 } 2700 2701 if (operate_inplace(priv, flags) && 2702 region_inplace(sna, pixmap, region, priv, flags) && 2703 sna_pixmap_create_mappable_gpu(pixmap, false)) { 2704 void *ptr; 2705 2706 DBG(("%s: try to operate inplace\n", __FUNCTION__)); 2707 assert(priv->gpu_bo); 2708 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2709 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2710 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2711 2712 /* XXX only sync for writes? */ 2713 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2714 assert(priv->gpu_bo->exec == NULL); 2715 2716 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2717 if (ptr != NULL) { 2718 pixmap->devPrivate.ptr = ptr; 2719 pixmap->devKind = priv->gpu_bo->pitch; 2720 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2721 assert(has_coherent_ptr(sna, priv, flags)); 2722 2723 if (flags & MOVE_WRITE) { 2724 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2725 assert(!priv->clear); 2726 sna_damage_add(&priv->gpu_damage, region); 2727 if (sna_damage_is_all(&priv->gpu_damage, 2728 pixmap->drawable.width, 2729 pixmap->drawable.height)) { 2730 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2731 __FUNCTION__)); 2732 sna_damage_destroy(&priv->cpu_damage); 2733 list_del(&priv->flush_list); 2734 } else 2735 sna_damage_subtract(&priv->cpu_damage, 2736 region); 2737 } 2738 priv->clear = false; 2739 } 2740 priv->cpu &= priv->mapped == MAPPED_CPU; 2741 assert_pixmap_damage(pixmap); 2742 if (dx | dy) 2743 RegionTranslate(region, -dx, -dy); 2744 DBG(("%s: operate inplace\n", __FUNCTION__)); 2745 return true; 2746 } 2747 } 2748 2749 if (priv->clear && flags & MOVE_WRITE) { 2750 DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__)); 2751demote_to_cpu: 2752 if (dx | dy) 2753 RegionTranslate(region, -dx, -dy); 2754 return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ); 2755 } 2756 2757 if (flags & MOVE_WHOLE_HINT) { 2758 DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n", 2759 __FUNCTION__, 2760 region->extents.x1, 2761 region->extents.y1, 2762 region->extents.x2, 2763 region->extents.y2, 2764 pixmap->drawable.width, 2765 pixmap->drawable.height)); 2766move_to_cpu: 2767 if ((flags & MOVE_READ) == 0) 2768 sna_damage_subtract(&priv->gpu_damage, region); 2769 goto demote_to_cpu; 2770 } 2771 2772 sna_pixmap_unmap(pixmap, priv); 2773 2774 if (USE_INPLACE && 2775 priv->gpu_damage && 2776 priv->gpu_bo->tiling == I915_TILING_NONE && 2777 ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) && 2778 (DAMAGE_IS_ALL(priv->gpu_damage) || 2779 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2780 ®ion->extents)) && 2781 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) && 2782 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2783 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 2784 void *ptr; 2785 2786 DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n", 2787 __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE))); 2788 assert(priv->gpu_bo); 2789 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2790 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2791 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2792 2793 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2794 if (ptr != NULL) { 2795 pixmap->devPrivate.ptr = ptr; 2796 pixmap->devKind = priv->gpu_bo->pitch; 2797 priv->mapped = MAPPED_CPU; 2798 assert(has_coherent_ptr(sna, priv, flags)); 2799 2800 if (flags & MOVE_WRITE) { 2801 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2802 assert(!priv->clear); 2803 sna_damage_add(&priv->gpu_damage, region); 2804 if (sna_damage_is_all(&priv->gpu_damage, 2805 pixmap->drawable.width, 2806 pixmap->drawable.height)) { 2807 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2808 __FUNCTION__)); 2809 sna_damage_destroy(&priv->cpu_damage); 2810 list_del(&priv->flush_list); 2811 } else 2812 sna_damage_subtract(&priv->cpu_damage, 2813 region); 2814 } 2815 priv->clear = false; 2816 } 2817 assert_pixmap_damage(pixmap); 2818 2819 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2820 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2821 priv->cpu = true; 2822 2823 assert_pixmap_map(pixmap, priv); 2824 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2825 if (dx | dy) 2826 RegionTranslate(region, -dx, -dy); 2827 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2828 return true; 2829 } 2830 } 2831 2832 if ((priv->clear || (flags & MOVE_READ) == 0) && 2833 priv->cpu_bo && !priv->cpu_bo->flush && 2834 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2835 sna_damage_subtract(&priv->cpu_damage, region); 2836 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2837 assert(priv->gpu_bo); 2838 sna_damage_all(&priv->gpu_damage, pixmap); 2839 sna_pixmap_free_cpu(sna, priv, false); 2840 } 2841 } 2842 2843 assert(priv->mapped == MAPPED_NONE); 2844 if (pixmap->devPrivate.ptr == NULL && 2845 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) { 2846 DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__)); 2847 goto move_to_cpu; 2848 } 2849 assert(priv->mapped == MAPPED_NONE); 2850 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2851 2852 if (priv->gpu_bo == NULL) { 2853 assert(priv->gpu_damage == NULL); 2854 goto done; 2855 } 2856 2857 assert(priv->gpu_bo->proxy == NULL); 2858 2859 if ((flags & MOVE_READ) == 0) { 2860 assert(flags & MOVE_WRITE); 2861 sna_damage_subtract(&priv->gpu_damage, region); 2862 priv->clear = false; 2863 goto done; 2864 } 2865 2866 if (priv->clear) { 2867 int n = region_num_rects(region); 2868 const BoxRec *box = region_rects(region); 2869 2870 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 2871 assert(priv->cpu_damage == NULL); 2872 2873 DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__)); 2874 if (priv->cpu_bo) { 2875 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2876 cpu_clear_boxes(sna, pixmap, priv, box, n)) 2877 goto clear_done; 2878 2879 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2880 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2881 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2882 } 2883 2884 assert(pixmap->devKind); 2885 do { 2886 pixman_fill(pixmap->devPrivate.ptr, 2887 pixmap->devKind/sizeof(uint32_t), 2888 pixmap->drawable.bitsPerPixel, 2889 box->x1, box->y1, 2890 box->x2 - box->x1, 2891 box->y2 - box->y1, 2892 priv->clear_color); 2893 box++; 2894 } while (--n); 2895 2896clear_done: 2897 if (flags & MOVE_WRITE || 2898 region->extents.x2 - region->extents.x1 > 1 || 2899 region->extents.y2 - region->extents.y1 > 1) { 2900 sna_damage_subtract(&priv->gpu_damage, region); 2901 priv->clear = false; 2902 } 2903 goto done; 2904 } 2905 2906 if (priv->gpu_damage && 2907 (DAMAGE_IS_ALL(priv->gpu_damage) || 2908 sna_damage_overlaps_box(priv->gpu_damage, ®ion->extents))) { 2909 DBG(("%s: region (%dx%d) overlaps gpu damage\n", 2910 __FUNCTION__, 2911 region->extents.x2 - region->extents.x1, 2912 region->extents.y2 - region->extents.y1)); 2913 assert(priv->gpu_bo); 2914 2915 if (priv->cpu_damage == NULL) { 2916 if ((flags & MOVE_WRITE) == 0 && 2917 region->extents.x2 - region->extents.x1 == 1 && 2918 region->extents.y2 - region->extents.y1 == 1) { 2919 /* Often associated with synchronisation, KISS */ 2920 DBG(("%s: single pixel read\n", __FUNCTION__)); 2921 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2922 ®ion->extents, 1); 2923 goto done; 2924 } 2925 } else { 2926 if (DAMAGE_IS_ALL(priv->cpu_damage) || 2927 sna_damage_contains_box__no_reduce(priv->cpu_damage, 2928 ®ion->extents)) { 2929 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2930 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2931 2932 DBG(("%s: region already in CPU damage\n", 2933 __FUNCTION__)); 2934 goto already_damaged; 2935 } 2936 } 2937 2938 if (sna_damage_contains_box(&priv->gpu_damage, 2939 ®ion->extents) != PIXMAN_REGION_OUT) { 2940 RegionRec want, *r = region; 2941 2942 DBG(("%s: region (%dx%d) intersects gpu damage\n", 2943 __FUNCTION__, 2944 region->extents.x2 - region->extents.x1, 2945 region->extents.y2 - region->extents.y1)); 2946 2947 if ((flags & MOVE_WRITE) == 0 && 2948 region->extents.x2 - region->extents.x1 == 1 && 2949 region->extents.y2 - region->extents.y1 == 1) { 2950 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2951 ®ion->extents, 1); 2952 goto done; 2953 } 2954 2955 /* Expand the region to move 32x32 pixel blocks at a 2956 * time, as we assume that we will continue writing 2957 * afterwards and so aim to coallesce subsequent 2958 * reads. 2959 */ 2960 if (flags & MOVE_WRITE) { 2961 int n = region_num_rects(region), i; 2962 const BoxRec *boxes = region_rects(region); 2963 BoxPtr blocks; 2964 2965 blocks = NULL; 2966 if (priv->cpu_damage == NULL) 2967 blocks = malloc(sizeof(BoxRec) * n); 2968 if (blocks) { 2969 for (i = 0; i < n; i++) { 2970 blocks[i].x1 = boxes[i].x1 & ~31; 2971 if (blocks[i].x1 < 0) 2972 blocks[i].x1 = 0; 2973 2974 blocks[i].x2 = (boxes[i].x2 + 31) & ~31; 2975 if (blocks[i].x2 > pixmap->drawable.width) 2976 blocks[i].x2 = pixmap->drawable.width; 2977 2978 blocks[i].y1 = boxes[i].y1 & ~31; 2979 if (blocks[i].y1 < 0) 2980 blocks[i].y1 = 0; 2981 2982 blocks[i].y2 = (boxes[i].y2 + 31) & ~31; 2983 if (blocks[i].y2 > pixmap->drawable.height) 2984 blocks[i].y2 = pixmap->drawable.height; 2985 } 2986 if (pixman_region_init_rects(&want, blocks, i)) 2987 r = &want; 2988 free(blocks); 2989 } 2990 } 2991 2992 if (region_subsumes_damage(r, priv->gpu_damage)) { 2993 const BoxRec *box; 2994 int n; 2995 2996 DBG(("%s: region wholly contains damage\n", 2997 __FUNCTION__)); 2998 2999 n = sna_damage_get_boxes(priv->gpu_damage, &box); 3000 if (n) 3001 download_boxes(sna, priv, n, box); 3002 3003 sna_damage_destroy(&priv->gpu_damage); 3004 } else if (DAMAGE_IS_ALL(priv->gpu_damage) || 3005 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3006 &r->extents)) { 3007 3008 DBG(("%s: region wholly inside damage\n", 3009 __FUNCTION__)); 3010 3011 assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN); 3012 assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT); 3013 3014 download_boxes(sna, priv, 3015 region_num_rects(r), 3016 region_rects(r)); 3017 sna_damage_subtract(&priv->gpu_damage, r); 3018 } else { 3019 RegionRec need; 3020 3021 pixman_region_init(&need); 3022 if (sna_damage_intersect(priv->gpu_damage, r, &need)) { 3023 DBG(("%s: region intersects damage\n", 3024 __FUNCTION__)); 3025 3026 download_boxes(sna, priv, 3027 region_num_rects(&need), 3028 region_rects(&need)); 3029 sna_damage_subtract(&priv->gpu_damage, r); 3030 RegionUninit(&need); 3031 } 3032 } 3033 if (r == &want) 3034 pixman_region_fini(&want); 3035 } 3036 } 3037 3038done: 3039 if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) { 3040 DBG(("%s: applying cpu damage\n", __FUNCTION__)); 3041 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3042 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 3043 sna_damage_add(&priv->cpu_damage, region); 3044 sna_damage_reduce_all(&priv->cpu_damage, pixmap); 3045 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3046 DBG(("%s: replaced entire pixmap\n", __FUNCTION__)); 3047 sna_pixmap_free_gpu(sna, priv); 3048 } 3049 if (priv->flush) { 3050 assert(!priv->shm); 3051 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3052 } 3053 } 3054 3055already_damaged: 3056 if (dx | dy) 3057 RegionTranslate(region, -dx, -dy); 3058 3059out: 3060 if (flags & MOVE_WRITE) { 3061 assert(!DAMAGE_IS_ALL(priv->gpu_damage)); 3062 priv->source_count = SOURCE_BIAS; 3063 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3064 assert(priv->gpu_bo || priv->gpu_damage == NULL); 3065 assert(!priv->flush || !list_is_empty(&priv->flush_list)); 3066 assert(!priv->clear); 3067 } 3068 if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) { 3069 DBG(("%s: syncing cpu bo\n", __FUNCTION__)); 3070 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 3071 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 3072 FORCE_FULL_SYNC || flags & MOVE_WRITE); 3073 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 3074 } 3075skip: 3076 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 3077 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 3078 assert(pixmap->devKind); 3079 assert_pixmap_damage(pixmap); 3080 assert(has_coherent_ptr(sna, priv, flags)); 3081 return true; 3082} 3083 3084bool 3085sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags) 3086{ 3087 RegionRec region; 3088 PixmapPtr pixmap; 3089 int16_t dx, dy; 3090 3091 if (drawable->type == DRAWABLE_PIXMAP) 3092 return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags); 3093 3094 pixmap = get_window_pixmap((WindowPtr)drawable); 3095 get_drawable_deltas(drawable, pixmap, &dx, &dy); 3096 3097 DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n", 3098 __FUNCTION__, 3099 drawable->x, drawable->y, 3100 drawable->width, drawable->height, 3101 dx, dy, flags)); 3102 3103 region.extents.x1 = drawable->x + dx; 3104 region.extents.y1 = drawable->y + dy; 3105 region.extents.x2 = region.extents.x1 + drawable->width; 3106 region.extents.y2 = region.extents.y1 + drawable->height; 3107 region.data = NULL; 3108 3109 if (region.extents.x1 < 0) 3110 region.extents.x1 = 0; 3111 if (region.extents.y1 < 0) 3112 region.extents.y1 = 0; 3113 if (region.extents.x2 > pixmap->drawable.width) 3114 region.extents.x2 = pixmap->drawable.width; 3115 if (region.extents.y2 > pixmap->drawable.height) 3116 region.extents.y2 = pixmap->drawable.height; 3117 3118 if (box_empty(®ion.extents)) 3119 return true; 3120 3121 return sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags); 3122} 3123 3124pure static bool alu_overwrites(uint8_t alu) 3125{ 3126 switch (alu) { 3127 case GXclear: 3128 case GXcopy: 3129 case GXcopyInverted: 3130 case GXset: 3131 return true; 3132 default: 3133 return false; 3134 } 3135} 3136 3137inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc) 3138{ 3139 if (!alu_overwrites(gc->alu)) 3140 return false; 3141 3142 if (!PM_IS_SOLID(draw, gc->planemask)) 3143 return false; 3144 3145 if (gc->fillStyle == FillStippled) 3146 return false; 3147 3148 return true; 3149} 3150 3151inline static unsigned 3152drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial) 3153{ 3154 assert(sna_gc(gc)->changes == 0); 3155 3156 if (gc->fillStyle == FillStippled) { 3157 DBG(("%s: read due to fill %d\n", 3158 __FUNCTION__, gc->fillStyle)); 3159 return MOVE_READ | MOVE_WRITE; 3160 } 3161 3162 if (fb_gc(gc)->and | fb_gc(gc)->bgand) { 3163 DBG(("%s: read due to rrop %d:%x\n", 3164 __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and)); 3165 return MOVE_READ | MOVE_WRITE; 3166 } 3167 3168 DBG(("%s: try operating on drawable inplace [hint? %d]\n", 3169 __FUNCTION__, drawable_gc_inplace_hint(draw, gc))); 3170 3171 return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT; 3172} 3173 3174static inline struct sna_pixmap * 3175sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv) 3176{ 3177 assert(priv->gpu_bo); 3178 DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__, 3179 priv->pixmap->drawable.serialNumber, 3180 priv->gpu_bo->handle)); 3181 return priv; 3182} 3183 3184inline static struct sna_pixmap * 3185__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags) 3186{ 3187 struct sna_pixmap *priv; 3188 3189 if ((flags & __MOVE_FORCE) == 0 && wedged(sna)) 3190 return NULL; 3191 3192 priv = sna_pixmap(pixmap); 3193 if (priv == NULL) { 3194 DBG(("%s: not attached\n", __FUNCTION__)); 3195 if ((flags & __MOVE_DRI) == 0) 3196 return NULL; 3197 3198 if (pixmap->usage_hint == -1) { 3199 DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__)); 3200 return NULL; 3201 } 3202 3203 DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__)); 3204 3205 priv = sna_pixmap_attach(pixmap); 3206 if (priv == NULL) 3207 return NULL; 3208 3209 sna_damage_all(&priv->cpu_damage, pixmap); 3210 3211 assert(priv->gpu_bo == NULL); 3212 assert(priv->gpu_damage == NULL); 3213 } 3214 3215 return priv; 3216} 3217 3218struct sna_pixmap * 3219sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags) 3220{ 3221 struct sna *sna = to_sna_from_pixmap(pixmap); 3222 struct sna_pixmap *priv; 3223 RegionRec i, r; 3224 3225 DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n", 3226 __FUNCTION__, pixmap->drawable.serialNumber, 3227 box->x1, box->y1, box->x2, box->y2, flags)); 3228 3229 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 3230 if (priv == NULL) 3231 return NULL; 3232 3233 assert(box->x2 > box->x1 && box->y2 > box->y1); 3234 assert_pixmap_damage(pixmap); 3235 assert_pixmap_contains_box(pixmap, box); 3236 assert(priv->gpu_damage == NULL || priv->gpu_bo); 3237 3238 if ((flags & MOVE_READ) == 0) 3239 sna_damage_subtract_box(&priv->cpu_damage, box); 3240 3241 if (priv->move_to_gpu) { 3242 unsigned int hint; 3243 3244 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3245 hint = flags | MOVE_READ; 3246 if ((flags & MOVE_READ) == 0) { 3247 RegionRec region; 3248 3249 region.extents = *box; 3250 region.data = NULL; 3251 sna_pixmap_discard_shadow_damage(priv, ®ion); 3252 if (region_subsumes_pixmap(®ion, pixmap)) 3253 hint &= ~MOVE_READ; 3254 } else { 3255 if (priv->cpu_damage) 3256 hint |= MOVE_WRITE; 3257 } 3258 if (!priv->move_to_gpu(sna, priv, hint)) { 3259 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3260 return NULL; 3261 } 3262 } 3263 3264 if (priv->cow) { 3265 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 3266 3267 if ((flags & MOVE_READ) == 0) { 3268 if (priv->gpu_damage) { 3269 r.extents = *box; 3270 r.data = NULL; 3271 if (!region_subsumes_damage(&r, priv->gpu_damage)) 3272 cow |= MOVE_READ; 3273 } 3274 } else { 3275 if (priv->cpu_damage) { 3276 r.extents = *box; 3277 r.data = NULL; 3278 if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0)) 3279 cow |= MOVE_WRITE; 3280 } 3281 } 3282 3283 if (cow) { 3284 if (!sna_pixmap_undo_cow(sna, priv, cow)) 3285 return NULL; 3286 3287 if (priv->gpu_bo == NULL) 3288 sna_damage_destroy(&priv->gpu_damage); 3289 } 3290 } 3291 3292 if (sna_damage_is_all(&priv->gpu_damage, 3293 pixmap->drawable.width, 3294 pixmap->drawable.height)) { 3295 assert(priv->gpu_bo); 3296 assert(priv->gpu_bo->proxy == NULL); 3297 sna_damage_destroy(&priv->cpu_damage); 3298 list_del(&priv->flush_list); 3299 goto done; 3300 } 3301 3302 if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 3303 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 3304 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3305 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3306 assert(!priv->pinned); 3307 assert(!priv->mapped); 3308 sna_damage_destroy(&priv->gpu_damage); 3309 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 3310 priv->gpu_bo = NULL; 3311 } 3312 3313 sna_damage_reduce(&priv->cpu_damage); 3314 assert_pixmap_damage(pixmap); 3315 3316 if (priv->cpu_damage == NULL) { 3317 list_del(&priv->flush_list); 3318 return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags); 3319 } 3320 3321 if (priv->gpu_bo == NULL) { 3322 assert(priv->gpu_damage == NULL); 3323 3324 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) 3325 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE); 3326 3327 if (priv->gpu_bo == NULL) 3328 return NULL; 3329 3330 DBG(("%s: created gpu bo\n", __FUNCTION__)); 3331 } 3332 3333 if (priv->gpu_bo->proxy) { 3334 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 3335 assert((flags & MOVE_WRITE) == 0); 3336 assert(priv->gpu_damage == NULL); 3337 return priv; 3338 } 3339 3340 if (priv->shm) { 3341 assert(!priv->flush); 3342 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3343 } 3344 3345 assert(priv->cpu_damage); 3346 region_set(&r, box); 3347 if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) { 3348 bool ok = false; 3349 int n; 3350 3351 n = sna_damage_get_boxes(priv->cpu_damage, &box); 3352 assert(n); 3353 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3354 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3355 ok = sna->render.copy_boxes(sna, GXcopy, 3356 &pixmap->drawable, priv->cpu_bo, 0, 0, 3357 &pixmap->drawable, priv->gpu_bo, 0, 0, 3358 box, n, 0); 3359 } 3360 if (!ok) { 3361 sna_pixmap_unmap(pixmap, priv); 3362 if (pixmap->devPrivate.ptr == NULL) 3363 return NULL; 3364 3365 assert(pixmap->devKind); 3366 if (n == 1 && !priv->pinned && 3367 box->x1 <= 0 && box->y1 <= 0 && 3368 box->x2 >= pixmap->drawable.width && 3369 box->y2 >= pixmap->drawable.height) { 3370 ok = sna_replace(sna, pixmap, 3371 pixmap->devPrivate.ptr, 3372 pixmap->devKind); 3373 } else { 3374 ok = sna_write_boxes(sna, pixmap, 3375 priv->gpu_bo, 0, 0, 3376 pixmap->devPrivate.ptr, 3377 pixmap->devKind, 3378 0, 0, 3379 box, n); 3380 } 3381 if (!ok) 3382 return NULL; 3383 } 3384 3385 sna_damage_destroy(&priv->cpu_damage); 3386 } else if (DAMAGE_IS_ALL(priv->cpu_damage) || 3387 sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) { 3388 bool ok = false; 3389 3390 assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT); 3391 assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN); 3392 3393 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3394 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3395 ok = sna->render.copy_boxes(sna, GXcopy, 3396 &pixmap->drawable, priv->cpu_bo, 0, 0, 3397 &pixmap->drawable, priv->gpu_bo, 0, 0, 3398 box, 1, 0); 3399 } 3400 if (!ok) { 3401 sna_pixmap_unmap(pixmap, priv); 3402 if (pixmap->devPrivate.ptr != NULL) { 3403 assert(pixmap->devKind); 3404 ok = sna_write_boxes(sna, pixmap, 3405 priv->gpu_bo, 0, 0, 3406 pixmap->devPrivate.ptr, 3407 pixmap->devKind, 3408 0, 0, 3409 box, 1); 3410 } 3411 } 3412 if (!ok) 3413 return NULL; 3414 3415 sna_damage_subtract(&priv->cpu_damage, &r); 3416 } else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) { 3417 int n = region_num_rects(&i); 3418 bool ok; 3419 3420 box = region_rects(&i); 3421 ok = false; 3422 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3423 DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n)); 3424 ok = sna->render.copy_boxes(sna, GXcopy, 3425 &pixmap->drawable, priv->cpu_bo, 0, 0, 3426 &pixmap->drawable, priv->gpu_bo, 0, 0, 3427 box, n, 0); 3428 } 3429 if (!ok) { 3430 sna_pixmap_unmap(pixmap, priv); 3431 if (pixmap->devPrivate.ptr != NULL) { 3432 assert(pixmap->devKind); 3433 ok = sna_write_boxes(sna, pixmap, 3434 priv->gpu_bo, 0, 0, 3435 pixmap->devPrivate.ptr, 3436 pixmap->devKind, 3437 0, 0, 3438 box, n); 3439 } 3440 } 3441 if (!ok) 3442 return NULL; 3443 3444 sna_damage_subtract(&priv->cpu_damage, &r); 3445 RegionUninit(&i); 3446 } 3447 3448done: 3449 if (priv->cpu_damage == NULL && priv->flush) 3450 list_del(&priv->flush_list); 3451 if (flags & MOVE_WRITE) { 3452 priv->clear = false; 3453 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 3454 priv->cpu_damage == NULL && 3455 (box_covers_pixmap(pixmap, &r.extents) || 3456 box_inplace(pixmap, &r.extents))) { 3457 DBG(("%s: large operation on undamaged, promoting to full GPU\n", 3458 __FUNCTION__)); 3459 assert(priv->gpu_bo); 3460 assert(priv->gpu_bo->proxy == NULL); 3461 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) 3462 sna_damage_all(&priv->gpu_damage, pixmap); 3463 } 3464 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3465 sna_pixmap_free_cpu(sna, priv, priv->cpu); 3466 sna_damage_destroy(&priv->cpu_damage); 3467 list_del(&priv->flush_list); 3468 } 3469 priv->cpu = false; 3470 } 3471 3472 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3473 return sna_pixmap_mark_active(sna, priv); 3474} 3475 3476struct kgem_bo * 3477sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box, 3478 struct sna_damage ***damage) 3479{ 3480 PixmapPtr pixmap = get_drawable_pixmap(drawable); 3481 struct sna_pixmap *priv = sna_pixmap(pixmap); 3482 struct sna *sna; 3483 RegionRec region; 3484 int16_t dx, dy; 3485 int ret; 3486 3487 DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n", 3488 __FUNCTION__, 3489 pixmap->drawable.serialNumber, 3490 box->x1, box->y1, box->x2, box->y2, 3491 flags)); 3492 3493 assert(box->x2 > box->x1 && box->y2 > box->y1); 3494 assert(pixmap->refcnt); 3495 assert_pixmap_damage(pixmap); 3496 assert_drawable_contains_box(drawable, box); 3497 3498 if (priv == NULL) { 3499 DBG(("%s: not attached\n", __FUNCTION__)); 3500 return NULL; 3501 } 3502 3503 if (priv->cow) { 3504 unsigned cow = MOVE_WRITE | MOVE_READ; 3505 3506 if (flags & IGNORE_DAMAGE) { 3507 if (priv->gpu_damage) { 3508 region.extents = *box; 3509 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3510 region.extents.x1 += dx; 3511 region.extents.x2 += dx; 3512 region.extents.y1 += dy; 3513 region.extents.y2 += dy; 3514 } 3515 region.data = NULL; 3516 if (region_subsumes_damage(®ion, 3517 priv->gpu_damage)) 3518 cow &= ~MOVE_READ; 3519 } else 3520 cow &= ~MOVE_READ; 3521 } 3522 3523 if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow)) 3524 return NULL; 3525 3526 if (priv->gpu_bo == NULL) 3527 sna_damage_destroy(&priv->gpu_damage); 3528 } 3529 3530 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 3531 DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__)); 3532 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3533 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3534 assert(!priv->pinned); 3535 assert(!priv->mapped); 3536 sna_damage_destroy(&priv->gpu_damage); 3537 kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem, 3538 priv->gpu_bo); 3539 priv->gpu_bo = NULL; 3540 goto use_cpu_bo; 3541 } 3542 3543 if (priv->flush) { 3544 DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__)); 3545 flags |= PREFER_GPU; 3546 } 3547 if (priv->shm) { 3548 DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__)); 3549 flags &= ~PREFER_GPU; 3550 } 3551 if (priv->pinned) { 3552 DBG(("%s: pinned, never REPLACES\n", __FUNCTION__)); 3553 flags &= ~REPLACES; 3554 } 3555 if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) { 3556 DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__)); 3557 flags &= ~PREFER_GPU; 3558 } 3559 3560 if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) { 3561 if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) { 3562 DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__)); 3563 flags |= PREFER_GPU; 3564 } 3565 } 3566 3567 DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n", 3568 __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags)); 3569 3570 if ((flags & PREFER_GPU) == 0 && 3571 (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) { 3572 DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__)); 3573 goto use_cpu_bo; 3574 } 3575 3576 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3577 DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__)); 3578 assert(priv->cpu_damage == NULL); 3579 assert(priv->gpu_bo); 3580 assert(priv->gpu_bo->proxy == NULL); 3581 goto use_gpu_bo; 3582 } 3583 3584 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3585 assert(priv->gpu_damage == NULL); 3586 if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) { 3587 DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n", 3588 __FUNCTION__)); 3589 goto use_cpu_bo; 3590 } 3591 } 3592 3593 DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__, 3594 priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL, 3595 priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL)); 3596 if (priv->gpu_bo == NULL) { 3597 unsigned int move; 3598 3599 if ((flags & FORCE_GPU) == 0 && 3600 (priv->create & KGEM_CAN_CREATE_GPU) == 0) { 3601 DBG(("%s: untiled, will not force allocation\n", 3602 __FUNCTION__)); 3603 goto use_cpu_bo; 3604 } 3605 3606 if ((flags & IGNORE_DAMAGE) == 0) { 3607 if (priv->cpu_bo) { 3608 if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) { 3609 if (kgem_bo_is_busy(priv->cpu_bo)) { 3610 DBG(("%s: already using CPU bo, will not force allocation\n", 3611 __FUNCTION__)); 3612 goto use_cpu_bo; 3613 } 3614 3615 if ((flags & RENDER_GPU) == 0) { 3616 DBG(("%s: prefer cpu", __FUNCTION__)); 3617 goto use_cpu_bo; 3618 } 3619 } else { 3620 if (kgem_bo_is_busy(priv->cpu_bo)) { 3621 DBG(("%s: CPU bo active, must force allocation\n", 3622 __FUNCTION__)); 3623 goto create_gpu_bo; 3624 } 3625 } 3626 } 3627 3628 if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) { 3629 if ((flags & PREFER_GPU) == 0) { 3630 DBG(("%s: already damaged and prefer cpu", 3631 __FUNCTION__)); 3632 goto use_cpu_bo; 3633 } 3634 3635 if (!box_inplace(pixmap, box)) { 3636 DBG(("%s: damaged with a small operation, will not force allocation\n", 3637 __FUNCTION__)); 3638 goto use_cpu_bo; 3639 } 3640 } 3641 } else if (priv->cpu_damage) { 3642 region.extents = *box; 3643 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3644 region.extents.x1 += dx; 3645 region.extents.x2 += dx; 3646 region.extents.y1 += dy; 3647 region.extents.y2 += dy; 3648 } 3649 region.data = NULL; 3650 3651 sna_damage_subtract(&priv->cpu_damage, ®ion); 3652 if (priv->cpu_damage == NULL) { 3653 list_del(&priv->flush_list); 3654 priv->cpu = false; 3655 } 3656 } 3657 3658create_gpu_bo: 3659 move = MOVE_WRITE | MOVE_READ; 3660 if (flags & FORCE_GPU) 3661 move |= __MOVE_FORCE; 3662 if (!sna_pixmap_move_to_gpu(pixmap, move)) 3663 goto use_cpu_bo; 3664 3665 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3666 goto done; 3667 } 3668 3669 3670 region.extents = *box; 3671 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3672 region.extents.x1 += dx; 3673 region.extents.x2 += dx; 3674 region.extents.y1 += dy; 3675 region.extents.y2 += dy; 3676 } 3677 region.data = NULL; 3678 3679 DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__, 3680 region.extents.x1, region.extents.y1, 3681 region.extents.x2, region.extents.y2)); 3682 3683 if (priv->gpu_damage) { 3684 assert(priv->gpu_bo); 3685 if (!priv->cpu_damage || flags & IGNORE_DAMAGE) { 3686 if (flags & REPLACES || box_covers_pixmap(pixmap, ®ion.extents)) { 3687 unsigned int move; 3688 3689 if (flags & IGNORE_DAMAGE) 3690 move = MOVE_WRITE; 3691 else 3692 move = MOVE_WRITE | MOVE_READ; 3693 3694 if (sna_pixmap_move_to_gpu(pixmap, move)) 3695 goto use_gpu_bo; 3696 } 3697 3698 if (DAMAGE_IS_ALL(priv->gpu_damage) || 3699 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3700 ®ion.extents)) { 3701 DBG(("%s: region wholly contained within GPU damage\n", 3702 __FUNCTION__)); 3703 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3704 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3705 goto use_gpu_bo; 3706 } else { 3707 DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n", 3708 __FUNCTION__)); 3709 goto move_to_gpu; 3710 } 3711 } 3712 3713 ret = sna_damage_contains_box(&priv->gpu_damage, ®ion.extents); 3714 if (ret == PIXMAN_REGION_IN) { 3715 DBG(("%s: region wholly contained within GPU damage\n", 3716 __FUNCTION__)); 3717 goto use_gpu_bo; 3718 } 3719 3720 if (ret != PIXMAN_REGION_OUT) { 3721 DBG(("%s: region partially contained within GPU damage\n", 3722 __FUNCTION__)); 3723 goto move_to_gpu; 3724 } 3725 } 3726 3727 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) { 3728 ret = sna_damage_contains_box(&priv->cpu_damage, ®ion.extents); 3729 if (ret == PIXMAN_REGION_IN) { 3730 DBG(("%s: region wholly contained within CPU damage\n", 3731 __FUNCTION__)); 3732 goto use_cpu_bo; 3733 } 3734 3735 if (box_inplace(pixmap, box)) { 3736 DBG(("%s: forcing inplace\n", __FUNCTION__)); 3737 goto move_to_gpu; 3738 } 3739 3740 if (ret != PIXMAN_REGION_OUT) { 3741 DBG(("%s: region partially contained within CPU damage\n", 3742 __FUNCTION__)); 3743 goto use_cpu_bo; 3744 } 3745 } 3746 3747move_to_gpu: 3748 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion.extents, 3749 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) { 3750 DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__)); 3751 assert(priv->gpu_bo == NULL); 3752 goto use_cpu_bo; 3753 } 3754 3755done: 3756 assert(priv->move_to_gpu == NULL); 3757 assert(priv->gpu_bo != NULL); 3758 assert(priv->gpu_bo->refcnt); 3759 if (sna_damage_is_all(&priv->gpu_damage, 3760 pixmap->drawable.width, 3761 pixmap->drawable.height)) { 3762 sna_damage_destroy(&priv->cpu_damage); 3763 list_del(&priv->flush_list); 3764 *damage = NULL; 3765 } else 3766 *damage = &priv->gpu_damage; 3767 3768 DBG(("%s: using GPU bo with damage? %d\n", 3769 __FUNCTION__, *damage != NULL)); 3770 assert(*damage == NULL || !DAMAGE_IS_ALL(*damage)); 3771 assert(priv->gpu_bo->proxy == NULL); 3772 assert(priv->clear == false); 3773 assert(priv->cpu == false); 3774 assert(!priv->shm); 3775 return priv->gpu_bo; 3776 3777use_gpu_bo: 3778 if (priv->move_to_gpu) { 3779 unsigned hint = MOVE_READ | MOVE_WRITE; 3780 3781 sna = to_sna_from_pixmap(pixmap); 3782 3783 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3784 if (flags & IGNORE_DAMAGE) { 3785 region.extents = *box; 3786 region.data = NULL; 3787 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3788 region.extents.x1 += dx; 3789 region.extents.x2 += dx; 3790 region.extents.y1 += dy; 3791 region.extents.y2 += dy; 3792 } 3793 sna_pixmap_discard_shadow_damage(priv, ®ion); 3794 if (region_subsumes_pixmap(®ion, pixmap)) { 3795 DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__)); 3796 hint = MOVE_WRITE; 3797 } 3798 } 3799 3800 if (!priv->move_to_gpu(sna, priv, hint)) { 3801 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3802 goto use_cpu_bo; 3803 } 3804 } 3805 3806 if (priv->shm) { 3807 assert(!priv->flush); 3808 list_move(&priv->flush_list, &sna->flush_pixmaps); 3809 } 3810 3811 DBG(("%s: using whole GPU bo\n", __FUNCTION__)); 3812 assert(priv->gpu_bo != NULL); 3813 assert(priv->gpu_bo->refcnt); 3814 assert(priv->gpu_bo->proxy == NULL); 3815 assert(priv->gpu_damage); 3816 priv->cpu = false; 3817 priv->clear = false; 3818 *damage = NULL; 3819 return priv->gpu_bo; 3820 3821use_cpu_bo: 3822 if (!USE_CPU_BO || priv->cpu_bo == NULL) { 3823 if ((flags & FORCE_GPU) == 0) { 3824 DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__)); 3825 return NULL; 3826 } 3827 3828 flags &= ~FORCE_GPU; 3829 3830 region.extents = *box; 3831 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3832 region.extents.x1 += dx; 3833 region.extents.x2 += dx; 3834 region.extents.y1 += dy; 3835 region.extents.y2 += dy; 3836 } 3837 region.data = NULL; 3838 3839 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3840 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) || 3841 priv->cpu_bo == NULL) { 3842 DBG(("%s: did not create CPU bo\n", __FUNCTION__)); 3843cpu_fail: 3844 if (priv->gpu_bo) 3845 goto move_to_gpu; 3846 3847 return NULL; 3848 } 3849 } 3850 3851 assert(priv->cpu_bo->refcnt); 3852 3853 sna = to_sna_from_pixmap(pixmap); 3854 if ((flags & FORCE_GPU) == 0 && 3855 !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 3856 DBG(("%s: has CPU bo, but is idle and acceleration not forced\n", 3857 __FUNCTION__)); 3858 return NULL; 3859 } 3860 3861 region.extents = *box; 3862 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3863 region.extents.x1 += dx; 3864 region.extents.x2 += dx; 3865 region.extents.y1 += dy; 3866 region.extents.y2 += dy; 3867 } 3868 region.data = NULL; 3869 3870 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 3871 DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n", 3872 __FUNCTION__)); 3873 goto move_to_gpu; 3874 } 3875 3876 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3877 3878 if (flags & RENDER_GPU) { 3879 flags &= ~RENDER_GPU; 3880 3881 if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) { 3882 DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__)); 3883 3884prefer_gpu_bo: 3885 if (priv->gpu_bo == NULL) { 3886 if ((flags & FORCE_GPU) == 0) { 3887 DBG(("%s: untiled, will not force allocation\n", 3888 __FUNCTION__)); 3889 return NULL; 3890 } 3891 3892 if (flags & IGNORE_DAMAGE) { 3893 sna_damage_subtract(&priv->cpu_damage, ®ion); 3894 if (priv->cpu_damage == NULL) { 3895 list_del(&priv->flush_list); 3896 priv->cpu = false; 3897 } 3898 } 3899 3900 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | __MOVE_FORCE)) 3901 return NULL; 3902 3903 sna_damage_all(&priv->gpu_damage, pixmap); 3904 3905 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3906 goto done; 3907 } 3908 goto move_to_gpu; 3909 } 3910 3911 if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) { 3912 if (priv->gpu_bo && priv->gpu_bo->tiling) { 3913 DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__)); 3914 goto prefer_gpu_bo; 3915 } 3916 3917 if (priv->cpu_bo->pitch >= 4096) { 3918 DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__)); 3919 goto prefer_gpu_bo; 3920 } 3921 } 3922 3923 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) { 3924 DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__)); 3925 goto prefer_gpu_bo; 3926 } 3927 3928 if (!sna->kgem.can_blt_cpu) { 3929 DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__)); 3930 goto prefer_gpu_bo; 3931 } 3932 } 3933 3934 if (!sna->kgem.can_blt_cpu) 3935 goto cpu_fail; 3936 3937 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3938 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) { 3939 DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__)); 3940 goto cpu_fail; 3941 } 3942 3943 if (priv->shm) { 3944 assert(!priv->flush); 3945 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3946 3947 /* As we may have flushed and retired,, recheck for busy bo */ 3948 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo)) 3949 return NULL; 3950 } 3951 if (priv->flush) { 3952 assert(!priv->shm); 3953 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3954 } 3955 3956 if (sna_damage_is_all(&priv->cpu_damage, 3957 pixmap->drawable.width, 3958 pixmap->drawable.height)) { 3959 sna_damage_destroy(&priv->gpu_damage); 3960 *damage = NULL; 3961 } else { 3962 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3963 if (priv->cpu_damage && 3964 sna_damage_contains_box__no_reduce(priv->cpu_damage, 3965 ®ion.extents)) { 3966 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3967 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3968 *damage = NULL; 3969 } else 3970 *damage = &priv->cpu_damage; 3971 } 3972 3973 DBG(("%s: using CPU bo with damage? %d\n", 3974 __FUNCTION__, *damage != NULL)); 3975 assert(damage == NULL || !DAMAGE_IS_ALL(*damage)); 3976 assert(priv->clear == false); 3977 priv->cpu = false; 3978 return priv->cpu_bo; 3979} 3980 3981PixmapPtr 3982sna_pixmap_create_upload(ScreenPtr screen, 3983 int width, int height, int depth, 3984 unsigned flags) 3985{ 3986 struct sna *sna = to_sna_from_screen(screen); 3987 PixmapPtr pixmap; 3988 struct sna_pixmap *priv; 3989 void *ptr; 3990 3991 DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__, 3992 width, height, depth, flags)); 3993 assert(width); 3994 assert(height); 3995 3996 if (depth == 1) 3997 return create_pixmap(sna, screen, width, height, depth, 3998 CREATE_PIXMAP_USAGE_SCRATCH); 3999 4000 pixmap = create_pixmap_hdr(sna, screen, 4001 width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, 4002 &priv); 4003 if (!pixmap) 4004 return NullPixmap; 4005 4006 priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem, 4007 width, height, 4008 pixmap->drawable.bitsPerPixel, 4009 flags, &ptr); 4010 if (!priv->gpu_bo) { 4011 free(priv); 4012 FreePixmap(pixmap); 4013 return NullPixmap; 4014 } 4015 4016 /* Marking both the shadow and the GPU bo is a little dubious, 4017 * but will work so long as we always check before doing the 4018 * transfer. 4019 */ 4020 sna_damage_all(&priv->gpu_damage, pixmap); 4021 sna_damage_all(&priv->cpu_damage, pixmap); 4022 4023 pixmap->devKind = priv->gpu_bo->pitch; 4024 pixmap->devPrivate.ptr = ptr; 4025 priv->ptr = MAKE_STATIC_PTR(ptr); 4026 priv->stride = priv->gpu_bo->pitch; 4027 priv->create = 0; 4028 4029 pixmap->usage_hint = 0; 4030 if (!kgem_buffer_is_inplace(priv->gpu_bo)) 4031 pixmap->usage_hint = 1; 4032 4033 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 4034 __FUNCTION__, 4035 pixmap->drawable.serialNumber, 4036 pixmap->drawable.width, 4037 pixmap->drawable.height, 4038 pixmap->usage_hint)); 4039 return pixmap; 4040} 4041 4042struct sna_pixmap * 4043sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags) 4044{ 4045 struct sna *sna = to_sna_from_pixmap(pixmap); 4046 struct sna_pixmap *priv; 4047 const BoxRec *box; 4048 int n; 4049 4050 DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n", 4051 __FUNCTION__, 4052 pixmap->drawable.serialNumber, 4053 pixmap->usage_hint, 4054 flags)); 4055 4056 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 4057 if (priv == NULL) 4058 return NULL; 4059 4060 assert_pixmap_damage(pixmap); 4061 4062 if (priv->move_to_gpu && 4063 !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) { 4064 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 4065 return NULL; 4066 } 4067 4068 if ((flags & MOVE_READ) == 0 && UNDO) 4069 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4070 4071 if (priv->cow) { 4072 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 4073 if (flags & MOVE_READ && priv->cpu_damage) 4074 cow |= MOVE_WRITE; 4075 if (cow) { 4076 if (!sna_pixmap_undo_cow(sna, priv, cow)) 4077 return NULL; 4078 4079 if (priv->gpu_bo == NULL) 4080 sna_damage_destroy(&priv->gpu_damage); 4081 } 4082 } 4083 4084 if (sna_damage_is_all(&priv->gpu_damage, 4085 pixmap->drawable.width, 4086 pixmap->drawable.height)) { 4087 DBG(("%s: already all-damaged\n", __FUNCTION__)); 4088 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 4089 assert(priv->gpu_bo); 4090 assert(priv->gpu_bo->proxy == NULL); 4091 assert_pixmap_map(pixmap, priv); 4092 sna_damage_destroy(&priv->cpu_damage); 4093 list_del(&priv->flush_list); 4094 goto active; 4095 } 4096 4097 if ((flags & MOVE_READ) == 0) 4098 sna_damage_destroy(&priv->cpu_damage); 4099 4100 sna_damage_reduce(&priv->cpu_damage); 4101 assert_pixmap_damage(pixmap); 4102 DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL)); 4103 if (priv->gpu_bo == NULL || 4104 kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 4105 struct kgem_bo *proxy; 4106 4107 proxy = priv->gpu_bo; 4108 priv->gpu_bo = NULL; 4109 4110 DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n", 4111 __FUNCTION__, 4112 pixmap->drawable.width, 4113 pixmap->drawable.height, 4114 pixmap->drawable.bitsPerPixel, 4115 priv->create)); 4116 assert(!priv->mapped); 4117 assert(list_is_empty(&priv->flush_list)); 4118 4119 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) { 4120 bool is_linear; 4121 4122 assert(pixmap->drawable.width > 0); 4123 assert(pixmap->drawable.height > 0); 4124 assert(pixmap->drawable.bitsPerPixel >= 8); 4125 4126 is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE; 4127 if (is_linear && flags & __MOVE_TILED) { 4128 DBG(("%s: not creating linear GPU bo\n", __FUNCTION__)); 4129 return NULL; 4130 } 4131 4132 if (is_linear && priv->cpu_bo && !priv->shm && 4133 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4134 assert(!priv->mapped); 4135 assert(!IS_STATIC_PTR(priv->ptr)); 4136#ifdef DEBUG_MEMORY 4137 sna->debug_memory.cpu_bo_allocs--; 4138 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4139#endif 4140 priv->gpu_bo = priv->cpu_bo; 4141 priv->cpu_bo = NULL; 4142 priv->ptr = NULL; 4143 pixmap->devPrivate.ptr = NULL; 4144 sna_damage_all(&priv->gpu_damage, pixmap); 4145 sna_damage_destroy(&priv->cpu_damage); 4146 } else { 4147 unsigned create = 0; 4148 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL)) 4149 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4150 4151 sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4152 } 4153 } 4154 4155 if (priv->gpu_bo == NULL) { 4156 DBG(("%s: not creating GPU bo\n", __FUNCTION__)); 4157 assert(priv->gpu_damage == NULL); 4158 priv->gpu_bo = proxy; 4159 if (proxy) 4160 sna_damage_all(&priv->cpu_damage, pixmap); 4161 return NULL; 4162 } 4163 4164 if (proxy) { 4165 DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle)); 4166 4167 if (priv->cpu_damage && 4168 sna->render.copy_boxes(sna, GXcopy, 4169 &pixmap->drawable, proxy, 0, 0, 4170 &pixmap->drawable, priv->gpu_bo, 0, 0, 4171 region_rects(DAMAGE_REGION(priv->cpu_damage)), 4172 region_num_rects(DAMAGE_REGION(priv->cpu_damage)), 4173 0)) 4174 sna_damage_destroy(&priv->cpu_damage); 4175 4176 kgem_bo_destroy(&sna->kgem, proxy); 4177 } 4178 4179 if (flags & MOVE_WRITE && priv->cpu_damage == NULL) { 4180 /* Presume that we will only ever write to the GPU 4181 * bo. Readbacks are expensive but fairly constant 4182 * in cost for all sizes i.e. it is the act of 4183 * synchronisation that takes the most time. This is 4184 * mitigated by avoiding fallbacks in the first place. 4185 */ 4186 assert(priv->gpu_bo); 4187 assert(priv->gpu_bo->proxy == NULL); 4188 sna_damage_all(&priv->gpu_damage, pixmap); 4189 DBG(("%s: marking as all-damaged for GPU\n", 4190 __FUNCTION__)); 4191 goto active; 4192 } 4193 } 4194 4195 if (priv->gpu_bo->proxy) { 4196 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 4197 assert((flags & MOVE_WRITE) == 0); 4198 assert(priv->gpu_damage == NULL); 4199 return priv; 4200 } 4201 4202 if (priv->cpu_damage == NULL) 4203 goto done; 4204 4205 if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo && 4206 !priv->pinned && !priv->shm && 4207 priv->gpu_bo->tiling == I915_TILING_NONE && 4208 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4209 assert(!priv->mapped); 4210 assert(!IS_STATIC_PTR(priv->ptr)); 4211#ifdef DEBUG_MEMORY 4212 sna->debug_memory.cpu_bo_allocs--; 4213 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4214#endif 4215 sna_pixmap_free_gpu(sna, priv); 4216 priv->gpu_bo = priv->cpu_bo; 4217 priv->cpu_bo = NULL; 4218 priv->ptr = NULL; 4219 pixmap->devPrivate.ptr = NULL; 4220 sna_damage_all(&priv->gpu_damage, pixmap); 4221 sna_damage_destroy(&priv->cpu_damage); 4222 goto done; 4223 } 4224 4225 if (priv->shm) { 4226 assert(!priv->flush); 4227 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 4228 } 4229 4230 n = sna_damage_get_boxes(priv->cpu_damage, &box); 4231 assert(n); 4232 if (n) { 4233 bool ok; 4234 4235 assert_pixmap_contains_damage(pixmap, priv->cpu_damage); 4236 DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n)); 4237 4238 ok = false; 4239 if (use_cpu_bo_for_upload(sna, priv, flags)) { 4240 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 4241 ok = sna->render.copy_boxes(sna, GXcopy, 4242 &pixmap->drawable, priv->cpu_bo, 0, 0, 4243 &pixmap->drawable, priv->gpu_bo, 0, 0, 4244 box, n, 0); 4245 } 4246 if (!ok) { 4247 sna_pixmap_unmap(pixmap, priv); 4248 if (pixmap->devPrivate.ptr == NULL) 4249 return NULL; 4250 4251 assert(pixmap->devKind); 4252 if (n == 1 && !priv->pinned && 4253 (box->x2 - box->x1) >= pixmap->drawable.width && 4254 (box->y2 - box->y1) >= pixmap->drawable.height) { 4255 ok = sna_replace(sna, pixmap, 4256 pixmap->devPrivate.ptr, 4257 pixmap->devKind); 4258 } else { 4259 ok = sna_write_boxes(sna, pixmap, 4260 priv->gpu_bo, 0, 0, 4261 pixmap->devPrivate.ptr, 4262 pixmap->devKind, 4263 0, 0, 4264 box, n); 4265 } 4266 if (!ok) 4267 return NULL; 4268 } 4269 } 4270 4271 __sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage)); 4272 priv->cpu_damage = NULL; 4273 4274 /* For large bo, try to keep only a single copy around */ 4275 if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) { 4276 DBG(("%s: disposing of system copy for large/source\n", 4277 __FUNCTION__)); 4278 assert(!priv->shm); 4279 assert(priv->gpu_bo); 4280 assert(priv->gpu_bo->proxy == NULL); 4281 sna_damage_all(&priv->gpu_damage, pixmap); 4282 sna_pixmap_free_cpu(sna, priv, 4283 (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu); 4284 } 4285done: 4286 list_del(&priv->flush_list); 4287 4288 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4289 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4290 sna_pixmap_free_cpu(sna, priv, priv->cpu); 4291 4292active: 4293 if (flags & MOVE_WRITE) { 4294 priv->clear = false; 4295 priv->cpu = false; 4296 } 4297 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 4298 return sna_pixmap_mark_active(sna, priv); 4299} 4300 4301static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap) 4302{ 4303 DBG(("%s: target bpp=%d, source bpp=%d\n", 4304 __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel)); 4305 4306 if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel && 4307 FbEvenTile(pixmap->drawable.width * 4308 pixmap->drawable.bitsPerPixel)) { 4309 DBG(("%s: flushing pixmap\n", __FUNCTION__)); 4310 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 4311 return false; 4312 4313 fbPadPixmap(pixmap); 4314 } 4315 4316 return true; 4317} 4318 4319static bool must_check sna_gc_move_to_cpu(GCPtr gc, 4320 DrawablePtr drawable, 4321 RegionPtr region) 4322{ 4323 struct sna_gc *sgc = sna_gc(gc); 4324 long changes = sgc->changes; 4325 4326 DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes)); 4327 assert(drawable); 4328 assert(region); 4329 4330 assert(gc->ops == (GCOps *)&sna_gc_ops); 4331 gc->ops = (GCOps *)&sna_gc_ops__cpu; 4332 4333 assert(gc->funcs); 4334 sgc->old_funcs = gc->funcs; 4335 gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu; 4336 4337 assert(gc->pCompositeClip); 4338 sgc->priv = gc->pCompositeClip; 4339 gc->pCompositeClip = region; 4340 4341 if (gc->clientClipType == CT_PIXMAP) { 4342 PixmapPtr clip = gc->clientClip; 4343 gc->clientClip = region_from_bitmap(gc->pScreen, clip); 4344 gc->pScreen->DestroyPixmap(clip); 4345 gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE; 4346 changes |= GCClipMask; 4347 } else 4348 changes &= ~GCClipMask; 4349 4350 if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) { 4351 long tmp = gc->serialNumber; 4352 gc->serialNumber = sgc->serial; 4353 4354 if (fb_gc(gc)->bpp != drawable->bitsPerPixel) { 4355 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask; 4356 fb_gc(gc)->bpp = drawable->bitsPerPixel; 4357 } 4358 4359 if (changes & GCTile && !gc->tileIsPixel) { 4360 DBG(("%s: flushing tile pixmap\n", __FUNCTION__)); 4361 if (!sna_validate_pixmap(drawable, gc->tile.pixmap)) 4362 return false; 4363 } 4364 4365 if (changes & GCStipple && gc->stipple) { 4366 DBG(("%s: flushing stipple pixmap\n", __FUNCTION__)); 4367 if (!sna_validate_pixmap(drawable, gc->stipple)) 4368 return false; 4369 } 4370 4371 fbValidateGC(gc, changes, drawable); 4372 gc->serialNumber = tmp; 4373 } 4374 sgc->changes = 0; 4375 4376 switch (gc->fillStyle) { 4377 case FillTiled: 4378 DBG(("%s: moving tile to cpu\n", __FUNCTION__)); 4379 return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ); 4380 case FillStippled: 4381 case FillOpaqueStippled: 4382 DBG(("%s: moving stipple to cpu\n", __FUNCTION__)); 4383 return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ); 4384 default: 4385 return true; 4386 } 4387} 4388 4389static void sna_gc_move_to_gpu(GCPtr gc) 4390{ 4391 DBG(("%s(%p)\n", __FUNCTION__, gc)); 4392 4393 assert(gc->ops == (GCOps *)&sna_gc_ops__cpu); 4394 assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu); 4395 4396 gc->ops = (GCOps *)&sna_gc_ops; 4397 gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs; 4398 assert(gc->funcs); 4399 gc->pCompositeClip = sna_gc(gc)->priv; 4400 assert(gc->pCompositeClip); 4401} 4402 4403static inline bool clip_box(BoxPtr box, GCPtr gc) 4404{ 4405 const BoxRec *clip; 4406 bool clipped; 4407 4408 assert(gc->pCompositeClip); 4409 clip = &gc->pCompositeClip->extents; 4410 4411 clipped = !region_is_singular(gc->pCompositeClip); 4412 if (box->x1 < clip->x1) 4413 box->x1 = clip->x1, clipped = true; 4414 if (box->x2 > clip->x2) 4415 box->x2 = clip->x2, clipped = true; 4416 4417 if (box->y1 < clip->y1) 4418 box->y1 = clip->y1, clipped = true; 4419 if (box->y2 > clip->y2) 4420 box->y2 = clip->y2, clipped = true; 4421 4422 return clipped; 4423} 4424 4425static inline void translate_box(BoxPtr box, DrawablePtr d) 4426{ 4427 box->x1 += d->x; 4428 box->x2 += d->x; 4429 4430 box->y1 += d->y; 4431 box->y2 += d->y; 4432} 4433 4434static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc) 4435{ 4436 translate_box(box, d); 4437 return clip_box(box, gc); 4438} 4439 4440static inline bool box32_clip(Box32Rec *box, GCPtr gc) 4441{ 4442 bool clipped = !region_is_singular(gc->pCompositeClip); 4443 const BoxRec *clip = &gc->pCompositeClip->extents; 4444 4445 if (box->x1 < clip->x1) 4446 box->x1 = clip->x1, clipped = true; 4447 if (box->x2 > clip->x2) 4448 box->x2 = clip->x2, clipped = true; 4449 4450 if (box->y1 < clip->y1) 4451 box->y1 = clip->y1, clipped = true; 4452 if (box->y2 > clip->y2) 4453 box->y2 = clip->y2, clipped = true; 4454 4455 return clipped; 4456} 4457 4458static inline void box32_translate(Box32Rec *box, DrawablePtr d) 4459{ 4460 box->x1 += d->x; 4461 box->x2 += d->x; 4462 4463 box->y1 += d->y; 4464 box->y2 += d->y; 4465} 4466 4467static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc) 4468{ 4469 box32_translate(box, d); 4470 return box32_clip(box, gc); 4471} 4472 4473static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y) 4474{ 4475 if (box->x1 > x) 4476 box->x1 = x; 4477 else if (box->x2 < x) 4478 box->x2 = x; 4479 4480 if (box->y1 > y) 4481 box->y1 = y; 4482 else if (box->y2 < y) 4483 box->y2 = y; 4484} 4485 4486static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16) 4487{ 4488 b16->x1 = b32->x1; 4489 b16->y1 = b32->y1; 4490 b16->x2 = b32->x2; 4491 b16->y2 = b32->y2; 4492 4493 return b16->x2 > b16->x1 && b16->y2 > b16->y1; 4494} 4495 4496static inline void box32_add_rect(Box32Rec *box, const xRectangle *r) 4497{ 4498 int32_t v; 4499 4500 v = r->x; 4501 if (box->x1 > v) 4502 box->x1 = v; 4503 v += r->width; 4504 if (box->x2 < v) 4505 box->x2 = v; 4506 4507 v = r->y; 4508 if (box->y1 > v) 4509 box->y1 = v; 4510 v += r->height; 4511 if (box->y2 < v) 4512 box->y2 = v; 4513} 4514 4515static bool 4516can_create_upload_tiled_x(struct sna *sna, 4517 PixmapPtr pixmap, 4518 struct sna_pixmap *priv, 4519 bool replaces) 4520{ 4521 if (priv->shm || (priv->cpu && !replaces)) 4522 return false; 4523 4524 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 4525 return false; 4526 4527 if (sna->kgem.has_llc) 4528 return true; 4529 4530 if (sna_pixmap_default_tiling(sna, pixmap)) 4531 return false; 4532 4533 return true; 4534} 4535 4536static bool 4537create_upload_tiled_x(struct sna *sna, 4538 PixmapPtr pixmap, 4539 struct sna_pixmap *priv, 4540 bool replaces) 4541{ 4542 unsigned create; 4543 4544 if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces)) 4545 return false; 4546 4547 assert(priv->gpu_bo == NULL); 4548 assert(priv->gpu_damage == NULL); 4549 4550 create = CREATE_CPU_MAP | CREATE_INACTIVE; 4551 if (!sna->kgem.has_llc) 4552 create |= CREATE_CACHED; 4553 4554 return sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4555} 4556 4557static bool 4558try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region, 4559 int x, int y, int w, int h, char *bits, int stride) 4560{ 4561 struct sna *sna = to_sna_from_pixmap(pixmap); 4562 struct sna_pixmap *priv = sna_pixmap(pixmap); 4563 const BoxRec *box; 4564 uint8_t *dst; 4565 int n; 4566 4567 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) { 4568 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4569 return false; 4570 } 4571 4572 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4573 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4574 return false; 4575 4576 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4577 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4578 return false; 4579 4580 dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 4581 if (dst == NULL) 4582 return false; 4583 4584 kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo); 4585 4586 box = region_rects(region); 4587 n = region_num_rects(region); 4588 4589 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4590 4591 if (sigtrap_get()) 4592 return false; 4593 4594 if (priv->gpu_bo->tiling) { 4595 do { 4596 DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n", 4597 __FUNCTION__, 4598 box->x1 - x, box->y1 - y, 4599 box->x1, box->y1, 4600 box->x2 - box->x1, box->y2 - box->y1)); 4601 4602 assert(box->x2 > box->x1); 4603 assert(box->y2 > box->y1); 4604 4605 assert(box->x1 >= 0); 4606 assert(box->y1 >= 0); 4607 assert(box->x2 <= pixmap->drawable.width); 4608 assert(box->y2 <= pixmap->drawable.height); 4609 4610 assert(box->x1 - x >= 0); 4611 assert(box->y1 - y >= 0); 4612 assert(box->x2 - x <= w); 4613 assert(box->y2 - y <= h); 4614 4615 memcpy_to_tiled_x(&sna->kgem, bits, dst, 4616 pixmap->drawable.bitsPerPixel, 4617 stride, priv->gpu_bo->pitch, 4618 box->x1 - x, box->y1 - y, 4619 box->x1, box->y1, 4620 box->x2 - box->x1, box->y2 - box->y1); 4621 box++; 4622 } while (--n); 4623 } else { 4624 do { 4625 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4626 __FUNCTION__, 4627 box->x1 - x, box->y1 - y, 4628 box->x1, box->y1, 4629 box->x2 - box->x1, box->y2 - box->y1)); 4630 4631 assert(box->x2 > box->x1); 4632 assert(box->y2 > box->y1); 4633 4634 assert(box->x1 >= 0); 4635 assert(box->y1 >= 0); 4636 assert(box->x2 <= pixmap->drawable.width); 4637 assert(box->y2 <= pixmap->drawable.height); 4638 4639 assert(box->x1 - x >= 0); 4640 assert(box->y1 - y >= 0); 4641 assert(box->x2 - x <= w); 4642 assert(box->y2 - y <= h); 4643 4644 memcpy_blt(bits, dst, 4645 pixmap->drawable.bitsPerPixel, 4646 stride, priv->gpu_bo->pitch, 4647 box->x1 - x, box->y1 - y, 4648 box->x1, box->y1, 4649 box->x2 - box->x1, box->y2 - box->y1); 4650 box++; 4651 } while (--n); 4652 4653 if (!priv->shm) { 4654 assert(dst == MAP(priv->gpu_bo->map__cpu)); 4655 pixmap->devPrivate.ptr = dst; 4656 pixmap->devKind = priv->gpu_bo->pitch; 4657 priv->mapped = MAPPED_CPU; 4658 assert_pixmap_map(pixmap, priv); 4659 priv->cpu = true; 4660 } 4661 } 4662 4663 sigtrap_put(); 4664 return true; 4665} 4666 4667static bool 4668try_upload__inplace(PixmapPtr pixmap, RegionRec *region, 4669 int x, int y, int w, int h, char *bits, int stride) 4670{ 4671 struct sna *sna = to_sna_from_pixmap(pixmap); 4672 struct sna_pixmap *priv = sna_pixmap(pixmap); 4673 bool ignore_cpu = false; 4674 bool replaces; 4675 const BoxRec *box; 4676 uint8_t *dst; 4677 int n; 4678 4679 if (!USE_INPLACE) 4680 return false; 4681 4682 assert(priv); 4683 4684 if (priv->shm && priv->gpu_damage == NULL) 4685 return false; 4686 4687 replaces = region_subsumes_pixmap(region, pixmap); 4688 4689 DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__, 4690 priv->gpu_bo != NULL, 4691 priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0, 4692 replaces)); 4693 4694 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 4695 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 4696 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 4697 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 4698 assert(!priv->pinned); 4699 assert(!priv->mapped); 4700 sna_damage_destroy(&priv->gpu_damage); 4701 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 4702 priv->gpu_bo = NULL; 4703 } 4704 4705 if (priv->gpu_bo && replaces) { 4706 if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4707 if (can_create_upload_tiled_x(sna, pixmap, priv, true) && 4708 (priv->cow || 4709 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4710 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4711 DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4712 kgem_bo_is_busy(priv->gpu_bo), 4713 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4714 sna_pixmap_free_gpu(sna, priv); 4715 ignore_cpu = true; 4716 } 4717 } 4718 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4719 4720 if (priv->cow || 4721 (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) { 4722 DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n", 4723 __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL)); 4724 return false; 4725 } 4726 4727 if (priv->gpu_damage && 4728 region_subsumes_damage(region, priv->gpu_damage)) { 4729 if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo); 4730 if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) && 4731 (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4732 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4733 DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4734 kgem_bo_is_busy(priv->gpu_bo), 4735 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4736 sna_pixmap_free_gpu(sna, priv); 4737 ignore_cpu = priv->cpu_damage == NULL; 4738 if (priv->ptr) 4739 sna_damage_all(&priv->cpu_damage, pixmap); 4740 } 4741 } 4742 4743 if (priv->gpu_bo == NULL && 4744 !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu)) 4745 return false; 4746 4747 DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling)); 4748 switch (priv->gpu_bo->tiling) { 4749 case I915_TILING_Y: 4750 break; 4751 case I915_TILING_X: 4752 if (!sna->kgem.memcpy_to_tiled_x) 4753 break; 4754 default: 4755 if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride)) 4756 goto done; 4757 break; 4758 } 4759 4760 if (priv->gpu_damage == NULL && !box_inplace(pixmap, ®ion->extents)) { 4761 DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__)); 4762 return false; 4763 } 4764 4765 if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 4766 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4767 return false; 4768 } 4769 4770 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4771 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4772 return false; 4773 4774 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4775 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4776 return false; 4777 4778 dst = kgem_bo_map(&sna->kgem, priv->gpu_bo); 4779 if (dst == NULL) 4780 return false; 4781 4782 pixmap->devPrivate.ptr = dst; 4783 pixmap->devKind = priv->gpu_bo->pitch; 4784 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 4785 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 4786 4787 box = region_rects(region); 4788 n = region_num_rects(region); 4789 4790 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4791 4792 if (sigtrap_get()) 4793 return false; 4794 4795 do { 4796 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4797 __FUNCTION__, 4798 box->x1 - x, box->y1 - y, 4799 box->x1, box->y1, 4800 box->x2 - box->x1, box->y2 - box->y1)); 4801 4802 assert(box->x2 > box->x1); 4803 assert(box->y2 > box->y1); 4804 4805 assert(box->x1 >= 0); 4806 assert(box->y1 >= 0); 4807 assert(box->x2 <= pixmap->drawable.width); 4808 assert(box->y2 <= pixmap->drawable.height); 4809 4810 assert(box->x1 - x >= 0); 4811 assert(box->y1 - y >= 0); 4812 assert(box->x2 - x <= w); 4813 assert(box->y2 - y <= h); 4814 4815 memcpy_blt(bits, dst, 4816 pixmap->drawable.bitsPerPixel, 4817 stride, priv->gpu_bo->pitch, 4818 box->x1 - x, box->y1 - y, 4819 box->x1, box->y1, 4820 box->x2 - box->x1, box->y2 - box->y1); 4821 box++; 4822 } while (--n); 4823 4824 sigtrap_put(); 4825 4826done: 4827 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4828 if (replaces) { 4829 sna_damage_all(&priv->gpu_damage, pixmap); 4830 } else { 4831 sna_damage_add(&priv->gpu_damage, region); 4832 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4833 } 4834 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4835 sna_damage_destroy(&priv->cpu_damage); 4836 else 4837 sna_damage_subtract(&priv->cpu_damage, region); 4838 4839 if (priv->cpu_damage == NULL) { 4840 list_del(&priv->flush_list); 4841 sna_damage_all(&priv->gpu_damage, pixmap); 4842 } 4843 4844 if (priv->shm) 4845 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 4846 } 4847 4848 assert(!priv->clear); 4849 return true; 4850} 4851 4852static bool 4853try_upload__blt(PixmapPtr pixmap, RegionRec *region, 4854 int x, int y, int w, int h, char *bits, int stride) 4855{ 4856 struct sna *sna = to_sna_from_pixmap(pixmap); 4857 struct sna_pixmap *priv; 4858 struct kgem_bo *src_bo; 4859 bool ok; 4860 4861 if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS) 4862 return false; 4863 4864 priv = sna_pixmap(pixmap); 4865 assert(priv); 4866 assert(priv->gpu_bo); 4867 assert(priv->gpu_bo->proxy == NULL); 4868 4869 if (priv->cpu_damage && 4870 (DAMAGE_IS_ALL(priv->cpu_damage) || 4871 sna_damage_contains_box__no_reduce(priv->cpu_damage, 4872 ®ion->extents)) && 4873 !box_inplace(pixmap, ®ion->extents)) { 4874 DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__)); 4875 return false; 4876 } 4877 4878 src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true); 4879 if (src_bo == NULL) 4880 return false; 4881 4882 src_bo->pitch = stride; 4883 kgem_bo_mark_unreusable(src_bo); 4884 4885 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4886 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) { 4887 kgem_bo_destroy(&sna->kgem, src_bo); 4888 return false; 4889 } 4890 4891 DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n", 4892 __FUNCTION__, x, y, w, h, region_num_rects(region))); 4893 4894 if (sigtrap_get() == 0) { 4895 ok = sna->render.copy_boxes(sna, GXcopy, 4896 &pixmap->drawable, src_bo, -x, -y, 4897 &pixmap->drawable, priv->gpu_bo, 0, 0, 4898 region_rects(region), 4899 region_num_rects(region), 4900 COPY_LAST); 4901 sigtrap_put(); 4902 } else 4903 ok = false; 4904 4905 kgem_bo_sync__cpu(&sna->kgem, src_bo); 4906 assert(src_bo->rq == NULL); 4907 kgem_bo_destroy(&sna->kgem, src_bo); 4908 4909 if (!ok) { 4910 DBG(("%s: copy failed!\n", __FUNCTION__)); 4911 return false; 4912 } 4913 4914 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4915 assert(!priv->clear); 4916 if (region_subsumes_drawable(region, &pixmap->drawable)) { 4917 sna_damage_all(&priv->gpu_damage, pixmap); 4918 } else { 4919 sna_damage_add(&priv->gpu_damage, region); 4920 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4921 } 4922 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4923 sna_damage_destroy(&priv->cpu_damage); 4924 else 4925 sna_damage_subtract(&priv->cpu_damage, region); 4926 if (priv->cpu_damage == NULL) { 4927 list_del(&priv->flush_list); 4928 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) 4929 sna_damage_all(&priv->gpu_damage, pixmap); 4930 } 4931 } 4932 priv->cpu = false; 4933 priv->clear = false; 4934 4935 return true; 4936} 4937 4938static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region) 4939{ 4940 if (region_subsumes_pixmap(region, priv->pixmap)) 4941 return true; 4942 4943 if (priv->cpu_damage != NULL) { 4944 if (DAMAGE_IS_ALL(priv->cpu_damage)) 4945 return false; 4946 4947 if (!box_inplace(priv->pixmap, ®ion->extents)) 4948 return false; 4949 4950 if (sna_damage_contains_box__no_reduce(priv->cpu_damage, ®ion->extents)) 4951 return false; 4952 } 4953 4954 return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo); 4955 4956} 4957 4958static bool 4959try_upload__fast(PixmapPtr pixmap, RegionRec *region, 4960 int x, int y, int w, int h, char *bits, int stride) 4961{ 4962 struct sna *sna = to_sna_from_pixmap(pixmap); 4963 struct sna_pixmap *priv; 4964 4965 if (wedged(sna)) 4966 return false; 4967 4968 priv = sna_pixmap(pixmap); 4969 if (priv == NULL) 4970 return false; 4971 4972 if (ignore_cpu_damage(sna, priv, region)) { 4973 DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__)); 4974 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 4975 return true; 4976 } 4977 4978 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) { 4979 DBG(("%s: no, no gpu damage\n", __FUNCTION__)); 4980 return false; 4981 } 4982 4983 assert(priv->gpu_bo); 4984 assert(priv->gpu_bo->proxy == NULL); 4985 4986 if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride)) 4987 return true; 4988 4989 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 4990 return true; 4991 4992 return false; 4993} 4994 4995static bool 4996sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 4997 int x, int y, int w, int h, char *bits, int stride) 4998{ 4999 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5000 unsigned int hint; 5001 const BoxRec *box; 5002 int16_t dx, dy; 5003 int n; 5004 5005 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5006 5007 if (gc->alu != GXcopy) 5008 return false; 5009 5010 if (drawable->depth < 8) 5011 return false; 5012 5013 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5014 x += dx + drawable->x; 5015 y += dy + drawable->y; 5016 assert(region->extents.x1 >= x); 5017 assert(region->extents.y1 >= y); 5018 assert(region->extents.x2 <= x + w); 5019 assert(region->extents.y2 <= y + h); 5020 5021 if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride)) 5022 return true; 5023 5024 hint = MOVE_WRITE; 5025 if (region_is_unclipped(region, pixmap->drawable.width, h) && 5026 (h+1)*stride > 65536) { 5027 DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n", 5028 __FUNCTION__, h*stride)); 5029 hint |= MOVE_WHOLE_HINT; 5030 } 5031 5032 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint)) 5033 return false; 5034 5035 if (sigtrap_get()) 5036 return false; 5037 5038 /* Region is pre-clipped and translated into pixmap space */ 5039 box = region_rects(region); 5040 n = region_num_rects(region); 5041 DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n)); 5042 do { 5043 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 5044 __FUNCTION__, 5045 box->x1 - x, box->y1 - y, 5046 box->x1, box->y1, 5047 box->x2 - box->x1, box->y2 - box->y1)); 5048 5049 assert(box->x2 > box->x1); 5050 assert(box->y2 > box->y1); 5051 5052 assert(box->x1 >= 0); 5053 assert(box->y1 >= 0); 5054 assert(box->x2 <= pixmap->drawable.width); 5055 assert(box->y2 <= pixmap->drawable.height); 5056 5057 assert(box->x1 - x >= 0); 5058 assert(box->y1 - y >= 0); 5059 assert(box->x2 - x <= w); 5060 assert(box->y2 - y <= h); 5061 5062 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE)); 5063 assert(pixmap->devKind); 5064 memcpy_blt(bits, pixmap->devPrivate.ptr, 5065 pixmap->drawable.bitsPerPixel, 5066 stride, pixmap->devKind, 5067 box->x1 - x, box->y1 - y, 5068 box->x1, box->y1, 5069 box->x2 - box->x1, box->y2 - box->y1); 5070 box++; 5071 } while (--n); 5072 5073 sigtrap_put(); 5074 assert_pixmap_damage(pixmap); 5075 return true; 5076} 5077 5078static inline uint8_t byte_reverse(uint8_t b) 5079{ 5080 return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; 5081} 5082 5083static inline uint8_t blt_depth(int depth) 5084{ 5085 switch (depth) { 5086 case 8: return 0; 5087 case 15: return 0x2; 5088 case 16: return 0x1; 5089 default: return 0x3; 5090 } 5091} 5092 5093static bool 5094sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5095 int x, int y, int w, int h, char *bits) 5096{ 5097 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5098 struct sna *sna = to_sna_from_pixmap(pixmap); 5099 struct sna_damage **damage; 5100 struct kgem_bo *bo; 5101 const BoxRec *box; 5102 int16_t dx, dy; 5103 int n; 5104 uint8_t rop = copy_ROP[gc->alu]; 5105 5106 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5107 ®ion->extents, &damage); 5108 if (bo == NULL) 5109 return false; 5110 5111 if (bo->tiling == I915_TILING_Y) { 5112 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5113 assert(bo == __sna_pixmap_get_bo(pixmap)); 5114 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5115 if (bo == NULL) { 5116 DBG(("%s: fallback -- unable to change tiling\n", 5117 __FUNCTION__)); 5118 return false; 5119 } 5120 } 5121 5122 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5123 if (damage) 5124 sna_damage_add(damage, region); 5125 assert_pixmap_damage(pixmap); 5126 5127 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5128 5129 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5130 x += dx + drawable->x; 5131 y += dy + drawable->y; 5132 5133 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5134 5135 /* Region is pre-clipped and translated into pixmap space */ 5136 box = region_rects(region); 5137 n = region_num_rects(region); 5138 do { 5139 int bx1 = (box->x1 - x) & ~7; 5140 int bx2 = (box->x2 - x + 7) & ~7; 5141 int bw = (bx2 - bx1)/8; 5142 int bh = box->y2 - box->y1; 5143 int bstride = ALIGN(bw, 2); 5144 struct kgem_bo *upload; 5145 void *ptr; 5146 5147 if (!kgem_check_batch(&sna->kgem, 10) || 5148 !kgem_check_bo_fenced(&sna->kgem, bo) || 5149 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5150 kgem_submit(&sna->kgem); 5151 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5152 return false; 5153 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5154 } 5155 5156 upload = kgem_create_buffer(&sna->kgem, 5157 bstride*bh, 5158 KGEM_BUFFER_WRITE_INPLACE, 5159 &ptr); 5160 if (!upload) 5161 break; 5162 5163 5164 if (sigtrap_get() == 0) { 5165 int src_stride = BitmapBytePad(w); 5166 uint8_t *dst = ptr; 5167 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5168 uint32_t *b; 5169 5170 bstride -= bw; 5171 src_stride -= bw; 5172 5173 do { 5174 int i = bw; 5175 assert(src >= (uint8_t *)bits); 5176 do { 5177 *dst++ = byte_reverse(*src++); 5178 } while (--i); 5179 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5180 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5181 dst += bstride; 5182 src += src_stride; 5183 } while (--bh); 5184 5185 assert(sna->kgem.mode == KGEM_BLT); 5186 if (sna->kgem.gen >= 0100) { 5187 b = sna->kgem.batch + sna->kgem.nbatch; 5188 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 5189 b[0] |= ((box->x1 - x) & 7) << 17; 5190 b[1] = bo->pitch; 5191 if (bo->tiling) { 5192 b[0] |= BLT_DST_TILED; 5193 b[1] >>= 2; 5194 } 5195 b[1] |= blt_depth(drawable->depth) << 24; 5196 b[1] |= rop << 16; 5197 b[2] = box->y1 << 16 | box->x1; 5198 b[3] = box->y2 << 16 | box->x2; 5199 *(uint64_t *)(b+4) = 5200 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5201 I915_GEM_DOMAIN_RENDER << 16 | 5202 I915_GEM_DOMAIN_RENDER | 5203 KGEM_RELOC_FENCED, 5204 0); 5205 *(uint64_t *)(b+6) = 5206 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5207 I915_GEM_DOMAIN_RENDER << 16 | 5208 KGEM_RELOC_FENCED, 5209 0); 5210 b[8] = gc->bgPixel; 5211 b[9] = gc->fgPixel; 5212 5213 sna->kgem.nbatch += 10; 5214 } else { 5215 b = sna->kgem.batch + sna->kgem.nbatch; 5216 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 5217 b[0] |= ((box->x1 - x) & 7) << 17; 5218 b[1] = bo->pitch; 5219 if (sna->kgem.gen >= 040 && bo->tiling) { 5220 b[0] |= BLT_DST_TILED; 5221 b[1] >>= 2; 5222 } 5223 b[1] |= blt_depth(drawable->depth) << 24; 5224 b[1] |= rop << 16; 5225 b[2] = box->y1 << 16 | box->x1; 5226 b[3] = box->y2 << 16 | box->x2; 5227 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5228 I915_GEM_DOMAIN_RENDER << 16 | 5229 I915_GEM_DOMAIN_RENDER | 5230 KGEM_RELOC_FENCED, 5231 0); 5232 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5233 I915_GEM_DOMAIN_RENDER << 16 | 5234 KGEM_RELOC_FENCED, 5235 0); 5236 b[6] = gc->bgPixel; 5237 b[7] = gc->fgPixel; 5238 5239 sna->kgem.nbatch += 8; 5240 } 5241 sigtrap_put(); 5242 } 5243 kgem_bo_destroy(&sna->kgem, upload); 5244 5245 box++; 5246 } while (--n); 5247 5248 sna->blt_state.fill_bo = 0; 5249 return true; 5250} 5251 5252static bool 5253sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5254 int x, int y, int w, int h, int left,char *bits) 5255{ 5256 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5257 struct sna *sna = to_sna_from_pixmap(pixmap); 5258 struct sna_damage **damage; 5259 struct kgem_bo *bo; 5260 int16_t dx, dy; 5261 unsigned i, skip; 5262 5263 if (gc->alu != GXcopy) 5264 return false; 5265 5266 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5267 ®ion->extents, &damage); 5268 if (bo == NULL) 5269 return false; 5270 5271 if (bo->tiling == I915_TILING_Y) { 5272 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5273 assert(bo == __sna_pixmap_get_bo(pixmap)); 5274 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5275 if (bo == NULL) { 5276 DBG(("%s: fallback -- unable to change tiling\n", 5277 __FUNCTION__)); 5278 return false; 5279 } 5280 } 5281 5282 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5283 if (damage) 5284 sna_damage_add(damage, region); 5285 assert_pixmap_damage(pixmap); 5286 5287 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5288 5289 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5290 x += dx + drawable->x; 5291 y += dy + drawable->y; 5292 5293 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5294 5295 skip = h * BitmapBytePad(w + left); 5296 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { 5297 const BoxRec *box = region_rects(region); 5298 int n = region_num_rects(region); 5299 5300 if ((gc->planemask & i) == 0) 5301 continue; 5302 5303 /* Region is pre-clipped and translated into pixmap space */ 5304 do { 5305 int bx1 = (box->x1 - x) & ~7; 5306 int bx2 = (box->x2 - x + 7) & ~7; 5307 int bw = (bx2 - bx1)/8; 5308 int bh = box->y2 - box->y1; 5309 int bstride = ALIGN(bw, 2); 5310 struct kgem_bo *upload; 5311 void *ptr; 5312 5313 if (!kgem_check_batch(&sna->kgem, 14) || 5314 !kgem_check_bo_fenced(&sna->kgem, bo) || 5315 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5316 kgem_submit(&sna->kgem); 5317 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5318 return false; 5319 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5320 } 5321 5322 upload = kgem_create_buffer(&sna->kgem, 5323 bstride*bh, 5324 KGEM_BUFFER_WRITE_INPLACE, 5325 &ptr); 5326 if (!upload) 5327 break; 5328 5329 if (sigtrap_get() == 0) { 5330 int src_stride = BitmapBytePad(w); 5331 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5332 uint8_t *dst = ptr; 5333 uint32_t *b; 5334 5335 bstride -= bw; 5336 src_stride -= bw; 5337 do { 5338 int j = bw; 5339 assert(src >= (uint8_t *)bits); 5340 do { 5341 *dst++ = byte_reverse(*src++); 5342 } while (--j); 5343 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5344 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5345 dst += bstride; 5346 src += src_stride; 5347 } while (--bh); 5348 5349 assert(sna->kgem.mode == KGEM_BLT); 5350 if (sna->kgem.gen >= 0100) { 5351 assert(sna->kgem.mode == KGEM_BLT); 5352 b = sna->kgem.batch + sna->kgem.nbatch; 5353 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12; 5354 b[0] |= ((box->x1 - x) & 7) << 17; 5355 b[1] = bo->pitch; 5356 if (bo->tiling) { 5357 b[0] |= BLT_DST_TILED; 5358 b[1] >>= 2; 5359 } 5360 b[1] |= 1 << 31; /* solid pattern */ 5361 b[1] |= blt_depth(drawable->depth) << 24; 5362 b[1] |= 0xce << 16; /* S or (D and !P) */ 5363 b[2] = box->y1 << 16 | box->x1; 5364 b[3] = box->y2 << 16 | box->x2; 5365 *(uint64_t *)(b+4) = 5366 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5367 I915_GEM_DOMAIN_RENDER << 16 | 5368 I915_GEM_DOMAIN_RENDER | 5369 KGEM_RELOC_FENCED, 5370 0); 5371 *(uint64_t *)(b+6) = 5372 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5373 I915_GEM_DOMAIN_RENDER << 16 | 5374 KGEM_RELOC_FENCED, 5375 0); 5376 b[8] = 0; 5377 b[9] = i; 5378 b[10] = i; 5379 b[11] = i; 5380 b[12] = -1; 5381 b[13] = -1; 5382 sna->kgem.nbatch += 14; 5383 } else { 5384 b = sna->kgem.batch + sna->kgem.nbatch; 5385 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10; 5386 b[0] |= ((box->x1 - x) & 7) << 17; 5387 b[1] = bo->pitch; 5388 if (sna->kgem.gen >= 040 && bo->tiling) { 5389 b[0] |= BLT_DST_TILED; 5390 b[1] >>= 2; 5391 } 5392 b[1] |= 1 << 31; /* solid pattern */ 5393 b[1] |= blt_depth(drawable->depth) << 24; 5394 b[1] |= 0xce << 16; /* S or (D and !P) */ 5395 b[2] = box->y1 << 16 | box->x1; 5396 b[3] = box->y2 << 16 | box->x2; 5397 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5398 I915_GEM_DOMAIN_RENDER << 16 | 5399 I915_GEM_DOMAIN_RENDER | 5400 KGEM_RELOC_FENCED, 5401 0); 5402 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5403 I915_GEM_DOMAIN_RENDER << 16 | 5404 KGEM_RELOC_FENCED, 5405 0); 5406 b[6] = 0; 5407 b[7] = i; 5408 b[8] = i; 5409 b[9] = i; 5410 b[10] = -1; 5411 b[11] = -1; 5412 sna->kgem.nbatch += 12; 5413 } 5414 sigtrap_put(); 5415 } 5416 kgem_bo_destroy(&sna->kgem, upload); 5417 5418 box++; 5419 } while (--n); 5420 } 5421 5422 sna->blt_state.fill_bo = 0; 5423 return true; 5424} 5425 5426static void 5427sna_put_image(DrawablePtr drawable, GCPtr gc, int depth, 5428 int x, int y, int w, int h, int left, int format, 5429 char *bits) 5430{ 5431 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5432 struct sna *sna = to_sna_from_pixmap(pixmap); 5433 struct sna_pixmap *priv = sna_pixmap(pixmap); 5434 RegionRec region; 5435 int16_t dx, dy; 5436 5437 DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n", 5438 __FUNCTION__, x, y, w, h, depth, format)); 5439 5440 if (w == 0 || h == 0) 5441 return; 5442 5443 region.extents.x1 = x + drawable->x; 5444 region.extents.y1 = y + drawable->y; 5445 region.extents.x2 = region.extents.x1 + w; 5446 region.extents.y2 = region.extents.y1 + h; 5447 region.data = NULL; 5448 5449 if (!region_is_singular(gc->pCompositeClip) || 5450 gc->pCompositeClip->extents.x1 > region.extents.x1 || 5451 gc->pCompositeClip->extents.y1 > region.extents.y1 || 5452 gc->pCompositeClip->extents.x2 < region.extents.x2 || 5453 gc->pCompositeClip->extents.y2 < region.extents.y2) { 5454 if (!RegionIntersect(®ion, ®ion, gc->pCompositeClip) || 5455 box_empty(®ion.extents)) 5456 return; 5457 } 5458 5459 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 5460 RegionTranslate(®ion, dx, dy); 5461 5462 if (priv == NULL) { 5463 DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n", 5464 __FUNCTION__, x, y, w, h)); 5465 goto fallback; 5466 } 5467 5468 if (FORCE_FALLBACK) 5469 goto fallback; 5470 5471 if (wedged(sna)) 5472 goto fallback; 5473 5474 if (!ACCEL_PUT_IMAGE) 5475 goto fallback; 5476 5477 switch (format) { 5478 case ZPixmap: 5479 if (!PM_IS_SOLID(drawable, gc->planemask)) 5480 goto fallback; 5481 5482 if (sna_put_zpixmap_blt(drawable, gc, ®ion, 5483 x, y, w, h, 5484 bits, PixmapBytePad(w, depth))) 5485 return; 5486 break; 5487 5488 case XYBitmap: 5489 if (!PM_IS_SOLID(drawable, gc->planemask)) 5490 goto fallback; 5491 5492 if (sna_put_xybitmap_blt(drawable, gc, ®ion, 5493 x, y, w, h, 5494 bits)) 5495 return; 5496 break; 5497 5498 case XYPixmap: 5499 if (sna_put_xypixmap_blt(drawable, gc, ®ion, 5500 x, y, w, h, left, 5501 bits)) 5502 return; 5503 break; 5504 5505 default: 5506 return; 5507 } 5508 5509fallback: 5510 DBG(("%s: fallback\n", __FUNCTION__)); 5511 RegionTranslate(®ion, -dx, -dy); 5512 5513 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 5514 goto out; 5515 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 5516 format == XYPixmap ? 5517 MOVE_READ | MOVE_WRITE : 5518 drawable_gc_flags(drawable, gc, false))) 5519 goto out; 5520 5521 if (sigtrap_get() == 0) { 5522 DBG(("%s: fbPutImage(%d, %d, %d, %d)\n", 5523 __FUNCTION__, x, y, w, h)); 5524 fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits); 5525 FALLBACK_FLUSH(drawable); 5526 sigtrap_put(); 5527 } 5528out: 5529 sna_gc_move_to_gpu(gc); 5530 RegionUninit(®ion); 5531} 5532 5533static bool 5534source_contains_region(struct sna_damage *damage, 5535 const RegionRec *region, int16_t dx, int16_t dy) 5536{ 5537 BoxRec box; 5538 5539 if (DAMAGE_IS_ALL(damage)) 5540 return true; 5541 5542 if (damage == NULL) 5543 return false; 5544 5545 box = region->extents; 5546 box.x1 += dx; 5547 box.x2 += dx; 5548 box.y1 += dy; 5549 box.y2 += dy; 5550 return sna_damage_contains_box__no_reduce(damage, &box); 5551} 5552 5553static bool 5554move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv, 5555 RegionRec *region, int16_t dx, int16_t dy, 5556 uint8_t alu, bool dst_is_gpu) 5557{ 5558 int w = region->extents.x2 - region->extents.x1; 5559 int h = region->extents.y2 - region->extents.y1; 5560 int count; 5561 5562 assert_pixmap_map(pixmap, priv); 5563 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 5564 assert(priv->gpu_bo); 5565 return true; 5566 } 5567 5568 if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) { 5569 DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n", 5570 __FUNCTION__, 5571 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5572 priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0, 5573 priv->cpu)); 5574 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 5575 return false; 5576 5577 if (priv->cpu && 5578 source_contains_region(priv->cpu_damage, region, dx, dy)) 5579 return false; 5580 } 5581 5582 if (priv->gpu_bo) { 5583 DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n", 5584 __FUNCTION__, 5585 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5586 priv->cpu, priv->gpu_bo->tiling)); 5587 5588 if (priv->cpu_damage == NULL) 5589 return true; 5590 5591 if (alu != GXcopy) 5592 return true; 5593 5594 if (!priv->cpu) 5595 return true; 5596 5597 if (priv->gpu_bo->tiling) 5598 return true; 5599 5600 RegionTranslate(region, dx, dy); 5601 count = region_subsumes_damage(region, priv->cpu_damage); 5602 RegionTranslate(region, -dx, -dy); 5603 if (count) 5604 return true; 5605 } else { 5606 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 5607 return false; 5608 if (priv->shm) 5609 return false; 5610 } 5611 5612 count = priv->source_count++; 5613 if (priv->cpu_bo) { 5614 if (priv->cpu_bo->flush && count > SOURCE_BIAS) 5615 return true; 5616 5617 if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE) 5618 return false; 5619 5620 if (priv->cpu) 5621 return false; 5622 5623 return count > SOURCE_BIAS; 5624 } else { 5625 if (w == pixmap->drawable.width && h == pixmap->drawable.height) 5626 return count > SOURCE_BIAS; 5627 5628 return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height; 5629 } 5630} 5631 5632static const BoxRec * 5633reorder_boxes(const BoxRec *box, int n, int dx, int dy) 5634{ 5635 const BoxRec *next, *base; 5636 BoxRec *new; 5637 5638 DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy)); 5639 5640 if (dy <= 0 && dx <= 0) { 5641 BoxRec *tmp; 5642 5643 new = malloc(sizeof(BoxRec) * n); 5644 if (new == NULL) 5645 return NULL; 5646 5647 tmp = new; 5648 next = box + n; 5649 do { 5650 *tmp++ = *--next; 5651 } while (next != box); 5652 } else if (dy < 0) { 5653 new = malloc(sizeof(BoxRec) * n); 5654 if (new == NULL) 5655 return NULL; 5656 5657 base = next = box + n - 1; 5658 while (base >= box) { 5659 const BoxRec *tmp; 5660 5661 while (next >= box && base->y1 == next->y1) 5662 next--; 5663 tmp = next + 1; 5664 while (tmp <= base) 5665 *new++ = *tmp++; 5666 base = next; 5667 } 5668 new -= n; 5669 } else { 5670 new = malloc(sizeof(BoxRec) * n); 5671 if (!new) 5672 return NULL; 5673 5674 base = next = box; 5675 while (base < box + n) { 5676 const BoxRec *tmp; 5677 5678 while (next < box + n && next->y1 == base->y1) 5679 next++; 5680 tmp = next; 5681 while (tmp != base) 5682 *new++ = *--tmp; 5683 base = next; 5684 } 5685 new -= n; 5686 } 5687 5688 return new; 5689} 5690 5691static void 5692sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5693 RegionPtr region,int dx, int dy, 5694 Pixel bitplane, void *closure) 5695{ 5696 PixmapPtr pixmap = get_drawable_pixmap(src); 5697 struct sna *sna = to_sna_from_pixmap(pixmap); 5698 struct sna_pixmap *priv = sna_pixmap(pixmap); 5699 const BoxRec *box = region_rects(region); 5700 int n = region_num_rects(region); 5701 int alu = gc ? gc->alu : GXcopy; 5702 int16_t tx, ty, sx, sy; 5703 5704 assert(pixmap == get_drawable_pixmap(dst)); 5705 5706 assert(region_num_rects(region)); 5707 if (((dx | dy) == 0 && alu == GXcopy)) 5708 return; 5709 5710 if (n > 1 && (dx | dy) < 0) { 5711 box = reorder_boxes(box, n, dx, dy); 5712 if (box == NULL) 5713 return; 5714 } 5715 5716 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n", 5717 __FUNCTION__, n, 5718 region->extents.x1, region->extents.y1, 5719 region->extents.x2, region->extents.y2, 5720 dx, dy, alu, 5721 pixmap->drawable.width, pixmap->drawable.height)); 5722 5723 get_drawable_deltas(dst, pixmap, &tx, &ty); 5724 get_drawable_deltas(src, pixmap, &sx, &sy); 5725 sx += dx; 5726 sy += dy; 5727 5728 if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) { 5729 DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__)); 5730 goto fallback; 5731 } 5732 5733 if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) { 5734 assert(priv->gpu_bo); 5735 5736 if (alu == GXcopy && priv->clear) 5737 goto free_boxes; 5738 5739 assert(priv->gpu_bo->proxy == NULL); 5740 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) { 5741 DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n", 5742 __FUNCTION__)); 5743 goto fallback; 5744 } 5745 assert(priv->cpu_damage == NULL); 5746 5747 if (!sna->render.copy_boxes(sna, alu, 5748 &pixmap->drawable, priv->gpu_bo, sx, sy, 5749 &pixmap->drawable, priv->gpu_bo, tx, ty, 5750 box, n, 0)) { 5751 DBG(("%s: fallback - accelerated copy boxes failed\n", 5752 __FUNCTION__)); 5753 goto fallback; 5754 } 5755 5756 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5757 assert(!priv->clear); 5758 if (sna_pixmap_free_cpu(sna, priv, false)) { 5759 sna_damage_all(&priv->gpu_damage, pixmap); 5760 } else { 5761 RegionTranslate(region, tx, ty); 5762 sna_damage_add(&priv->gpu_damage, region); 5763 } 5764 } 5765 assert_pixmap_damage(pixmap); 5766 } else { 5767fallback: 5768 DBG(("%s: fallback\n", __FUNCTION__)); 5769 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 5770 goto free_boxes; 5771 5772 if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) { 5773 assert(pixmap->devKind); 5774 if (sigtrap_get() == 0) { 5775 FbBits *dst_bits, *src_bits; 5776 int stride = pixmap->devKind; 5777 int bpp = pixmap->drawable.bitsPerPixel; 5778 int i; 5779 5780 dst_bits = (FbBits *) 5781 ((char *)pixmap->devPrivate.ptr + 5782 ty * stride + tx * bpp / 8); 5783 src_bits = (FbBits *) 5784 ((char *)pixmap->devPrivate.ptr + 5785 sy * stride + sx * bpp / 8); 5786 5787 for (i = 0; i < n; i++) 5788 memmove_box(src_bits, dst_bits, 5789 bpp, stride, box+i, 5790 dx, dy); 5791 sigtrap_put(); 5792 } 5793 } else { 5794 if (gc && !sna_gc_move_to_cpu(gc, dst, region)) 5795 goto out; 5796 5797 if (sigtrap_get() == 0) { 5798 miCopyRegion(src, dst, gc, 5799 region, dx, dy, 5800 fbCopyNtoN, 0, NULL); 5801 sigtrap_put(); 5802 } 5803 5804 if (gc) 5805out: 5806 sna_gc_move_to_gpu(gc); 5807 } 5808 } 5809 5810free_boxes: 5811 if (box != region_rects(region)) 5812 free((void *)box); 5813} 5814 5815static inline bool 5816sna_pixmap_is_gpu(PixmapPtr pixmap) 5817{ 5818 struct sna_pixmap *priv = sna_pixmap(pixmap); 5819 5820 if (priv == NULL || priv->clear) 5821 return false; 5822 5823 if (DAMAGE_IS_ALL(priv->gpu_damage) || 5824 (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy)) 5825 return true; 5826 5827 return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo); 5828} 5829 5830static int 5831copy_prefer_gpu(struct sna *sna, 5832 struct sna_pixmap *dst_priv, 5833 struct sna_pixmap *src_priv, 5834 RegionRec *region, 5835 int16_t dx, int16_t dy) 5836{ 5837 assert(dst_priv); 5838 5839 if (wedged(sna) && !dst_priv->pinned) 5840 return 0; 5841 5842 if (src_priv == NULL) { 5843 DBG(("%s: source unattached, use cpu\n", __FUNCTION__)); 5844 return 0; 5845 } 5846 5847 if (src_priv->clear) { 5848 DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__)); 5849 return 0; 5850 } 5851 5852 if (src_priv->gpu_damage && 5853 !source_contains_region(src_priv->cpu_damage, region, dx, dy)) { 5854 DBG(("%s: source has gpu damage, force gpu? %d\n", 5855 __FUNCTION__, src_priv->cpu_damage == NULL)); 5856 assert(src_priv->gpu_bo); 5857 return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU; 5858 } 5859 5860 if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) { 5861 DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__)); 5862 return PREFER_GPU | FORCE_GPU; 5863 } 5864 5865 if (source_contains_region(src_priv->cpu_damage, region, dx, dy)) 5866 return src_priv->cpu_bo && kgem_is_idle(&sna->kgem); 5867 5868 DBG(("%s: source has GPU bo? %d\n", 5869 __FUNCTION__, src_priv->gpu_bo != NULL)); 5870 return src_priv->gpu_bo != NULL; 5871} 5872 5873static bool use_shm_bo(struct sna *sna, 5874 struct kgem_bo *bo, 5875 struct sna_pixmap *priv, 5876 int alu, bool replaces) 5877{ 5878 if (priv == NULL || priv->cpu_bo == NULL) { 5879 DBG(("%s: no, not attached\n", __FUNCTION__)); 5880 return false; 5881 } 5882 5883 if (!priv->shm && !priv->cpu) { 5884 DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__)); 5885 return true; 5886 } 5887 5888 if (alu != GXcopy) { 5889 DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu)); 5890 return true; 5891 } 5892 5893 if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) { 5894 DBG(("%s: yes, dst is busy\n", __FUNCTION__)); 5895 return true; 5896 } 5897 5898 if (priv->cpu_bo->needs_flush && 5899 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 5900 DBG(("%s: yes, src is busy\n", __FUNCTION__)); 5901 return true; 5902 } 5903 5904 return false; 5905} 5906 5907static bool 5908sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage, 5909 const BoxRec *extents, 5910 int16_t dx, int16_t dy) 5911{ 5912 BoxRec _extents; 5913 5914 if (dx | dy) { 5915 _extents.x1 = extents->x1 + dx; 5916 _extents.x2 = extents->x2 + dx; 5917 _extents.y1 = extents->y1 + dy; 5918 _extents.y2 = extents->y2 + dy; 5919 extents = &_extents; 5920 } 5921 5922 return sna_damage_contains_box__no_reduce(damage, extents); 5923} 5924 5925static bool 5926sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu, 5927 PixmapPtr src_pixmap, struct sna_pixmap *src_priv, 5928 int dx, int dy, 5929 PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv, 5930 bool replaces) 5931{ 5932 const BoxRec *box; 5933 char *ptr; 5934 int n; 5935 5936 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 5937 5938 if (alu != GXcopy) { 5939 DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu)); 5940 return false; 5941 } 5942 5943 if (!USE_INPLACE) { 5944 DBG(("%s - no, compile time disabled\n", __FUNCTION__)); 5945 return false; 5946 } 5947 5948 if (dst_priv == src_priv) { 5949 DBG(("%s - no, dst == src\n", __FUNCTION__)); 5950 return false; 5951 } 5952 5953 if (src_priv == NULL || src_priv->gpu_bo == NULL) { 5954 if (dst_priv && dst_priv->gpu_bo) 5955 goto upload_inplace; 5956 5957 DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__)); 5958 return false; 5959 } 5960 5961 switch (src_priv->gpu_bo->tiling) { 5962 case I915_TILING_Y: 5963 DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__)); 5964 return false; 5965 case I915_TILING_X: 5966 if (!sna->kgem.memcpy_from_tiled_x) { 5967 DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__)); 5968 return false; 5969 } 5970 default: 5971 break; 5972 } 5973 5974 if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) { 5975 DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__)); 5976 return false; 5977 } 5978 5979 if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) { 5980 DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__)); 5981 return false; 5982 } 5983 5984 if (src_priv->gpu_damage == NULL || 5985 !(DAMAGE_IS_ALL(src_priv->gpu_damage) || 5986 sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage, 5987 ®ion->extents, 5988 dx, dy))) { 5989 DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__)); 5990 return false; 5991 } 5992 5993 assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_IN); 5994 assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_OUT); 5995 5996 ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo); 5997 if (ptr == NULL) { 5998 DBG(("%s - no, map failed\n", __FUNCTION__)); 5999 return false; 6000 } 6001 6002 if (dst_priv && 6003 !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6004 region, MOVE_WRITE | MOVE_INPLACE_HINT)) { 6005 DBG(("%s - no, dst sync failed\n", __FUNCTION__)); 6006 return false; 6007 } 6008 6009 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC); 6010 6011 box = region_rects(region); 6012 n = region_num_rects(region); 6013 if (src_priv->gpu_bo->tiling) { 6014 DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__)); 6015 assert(dst_pixmap->devKind); 6016 do { 6017 memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr, 6018 src_pixmap->drawable.bitsPerPixel, 6019 src_priv->gpu_bo->pitch, 6020 dst_pixmap->devKind, 6021 box->x1 + dx, box->y1 + dy, 6022 box->x1, box->y1, 6023 box->x2 - box->x1, box->y2 - box->y1); 6024 box++; 6025 } while (--n); 6026 } else { 6027 DBG(("%s: copy from a linear CPU map\n", __FUNCTION__)); 6028 assert(dst_pixmap->devKind); 6029 do { 6030 memcpy_blt(ptr, dst_pixmap->devPrivate.ptr, 6031 src_pixmap->drawable.bitsPerPixel, 6032 src_priv->gpu_bo->pitch, 6033 dst_pixmap->devKind, 6034 box->x1 + dx, box->y1 + dy, 6035 box->x1, box->y1, 6036 box->x2 - box->x1, box->y2 - box->y1); 6037 box++; 6038 } while (--n); 6039 6040 if (!src_priv->shm) { 6041 assert(ptr == MAP(src_priv->gpu_bo->map__cpu)); 6042 src_pixmap->devPrivate.ptr = ptr; 6043 src_pixmap->devKind = src_priv->gpu_bo->pitch; 6044 src_priv->mapped = MAPPED_CPU; 6045 assert_pixmap_map(src_pixmap, src_priv); 6046 src_priv->cpu = true; 6047 } 6048 } 6049 6050 return true; 6051 6052upload_inplace: 6053 switch (dst_priv->gpu_bo->tiling) { 6054 case I915_TILING_Y: 6055 DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__)); 6056 return false; 6057 case I915_TILING_X: 6058 if (!sna->kgem.memcpy_to_tiled_x) { 6059 DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__)); 6060 return false; 6061 } 6062 default: 6063 break; 6064 } 6065 6066 if (dst_priv->move_to_gpu) { 6067 DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__)); 6068 return false; 6069 } 6070 6071 if (!kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true) || 6072 __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) { 6073 if (replaces && !dst_priv->pinned) { 6074 unsigned create; 6075 struct kgem_bo *bo; 6076 6077 create = CREATE_CPU_MAP | CREATE_INACTIVE; 6078 if (dst_priv->gpu_bo->scanout) 6079 create |= CREATE_SCANOUT; 6080 6081 bo = kgem_create_2d(&sna->kgem, 6082 dst_pixmap->drawable.width, 6083 dst_pixmap->drawable.height, 6084 dst_pixmap->drawable.bitsPerPixel, 6085 dst_priv->gpu_bo->tiling, 6086 create); 6087 if (bo == NULL) 6088 return false; 6089 6090 sna_pixmap_unmap(dst_pixmap, dst_priv); 6091 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 6092 dst_priv->gpu_bo = bo; 6093 } else { 6094 DBG(("%s - no, dst is busy\n", __FUNCTION__)); 6095 return false; 6096 } 6097 6098 if (!kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) { 6099 DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__)); 6100 return false; 6101 } 6102 } 6103 6104 if (src_priv && 6105 !sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6106 region, MOVE_READ)) { 6107 DBG(("%s - no, src sync failed\n", __FUNCTION__)); 6108 return false; 6109 } 6110 6111 ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo); 6112 if (ptr == NULL) { 6113 DBG(("%s - no, map failed\n", __FUNCTION__)); 6114 return false; 6115 } 6116 6117 kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo); 6118 6119 if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) { 6120 assert(!dst_priv->clear); 6121 sna_damage_add(&dst_priv->gpu_damage, region); 6122 if (sna_damage_is_all(&dst_priv->gpu_damage, 6123 dst_pixmap->drawable.width, 6124 dst_pixmap->drawable.height)) { 6125 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 6126 __FUNCTION__)); 6127 sna_damage_destroy(&dst_priv->cpu_damage); 6128 list_del(&dst_priv->flush_list); 6129 } else 6130 sna_damage_subtract(&dst_priv->cpu_damage, 6131 region); 6132 } 6133 dst_priv->clear = false; 6134 6135 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6136 6137 box = region_rects(region); 6138 n = region_num_rects(region); 6139 if (dst_priv->gpu_bo->tiling) { 6140 DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__)); 6141 assert(dst_priv->gpu_bo->tiling == I915_TILING_X); 6142 assert(src_pixmap->devKind); 6143 do { 6144 memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr, 6145 src_pixmap->drawable.bitsPerPixel, 6146 src_pixmap->devKind, 6147 dst_priv->gpu_bo->pitch, 6148 box->x1 + dx, box->y1 + dy, 6149 box->x1, box->y1, 6150 box->x2 - box->x1, box->y2 - box->y1); 6151 box++; 6152 } while (--n); 6153 } else { 6154 DBG(("%s: copy to a linear CPU map\n", __FUNCTION__)); 6155 assert(src_pixmap->devKind); 6156 do { 6157 memcpy_blt(src_pixmap->devPrivate.ptr, ptr, 6158 src_pixmap->drawable.bitsPerPixel, 6159 src_pixmap->devKind, 6160 dst_priv->gpu_bo->pitch, 6161 box->x1 + dx, box->y1 + dy, 6162 box->x1, box->y1, 6163 box->x2 - box->x1, box->y2 - box->y1); 6164 box++; 6165 } while (--n); 6166 6167 if (!dst_priv->shm) { 6168 assert(ptr == MAP(dst_priv->gpu_bo->map__cpu)); 6169 dst_pixmap->devPrivate.ptr = ptr; 6170 dst_pixmap->devKind = dst_priv->gpu_bo->pitch; 6171 dst_priv->mapped = MAPPED_CPU; 6172 assert_pixmap_map(dst_pixmap, dst_priv); 6173 dst_priv->cpu = true; 6174 } 6175 } 6176 6177 return true; 6178} 6179 6180static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv) 6181{ 6182 if (priv->cpu_damage == NULL && !priv->shm) 6183 return; 6184 6185 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 6186 6187 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 6188 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 6189 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 6190 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 6191 assert(!priv->pinned); 6192 assert(!priv->mapped); 6193 sna_damage_destroy(&priv->gpu_damage); 6194 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 6195 priv->gpu_bo = NULL; 6196 } 6197 6198 sna_damage_destroy(&priv->cpu_damage); 6199 list_del(&priv->flush_list); 6200 6201 if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu)) 6202 sna_damage_all(&priv->gpu_damage, priv->pixmap); 6203 priv->cpu = false; 6204} 6205 6206static void 6207sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6208 RegionPtr region, int dx, int dy, 6209 Pixel bitplane, void *closure) 6210{ 6211 PixmapPtr src_pixmap = get_drawable_pixmap(src); 6212 struct sna_pixmap *src_priv = sna_pixmap(src_pixmap); 6213 PixmapPtr dst_pixmap = get_drawable_pixmap(dst); 6214 struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap); 6215 struct sna *sna = to_sna_from_pixmap(src_pixmap); 6216 struct sna_damage **damage; 6217 struct kgem_bo *bo; 6218 int16_t src_dx, src_dy; 6219 int16_t dst_dx, dst_dy; 6220 const BoxRec *box = region_rects(region); 6221 int n = region_num_rects(region); 6222 int alu = gc->alu; 6223 int stride, bpp; 6224 char *bits; 6225 bool replaces; 6226 6227 assert(region_num_rects(region)); 6228 6229 if (src_pixmap == dst_pixmap) 6230 return sna_self_copy_boxes(src, dst, gc, 6231 region, dx, dy, 6232 bitplane, closure); 6233 6234 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src pixmap=%ld+(%d, %d), dst pixmap=%ld+(%d, %d), alu=%d, src.size=%dx%d, dst.size=%dx%d)\n", 6235 __FUNCTION__, n, 6236 box[0].x1, box[0].y1, box[0].x2, box[0].y2, 6237 src_pixmap->drawable.serialNumber, dx, dy, 6238 dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst), 6239 alu, 6240 src_pixmap->drawable.width, src_pixmap->drawable.height, 6241 dst_pixmap->drawable.width, dst_pixmap->drawable.height)); 6242 6243 assert_pixmap_damage(dst_pixmap); 6244 assert_pixmap_damage(src_pixmap); 6245 6246 bpp = dst_pixmap->drawable.bitsPerPixel; 6247 6248 if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy)) 6249 RegionTranslate(region, dst_dx, dst_dy); 6250 get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy); 6251 src_dx += dx - dst_dx; 6252 src_dy += dy - dst_dy; 6253 6254 assert_pixmap_contains_box(dst_pixmap, RegionExtents(region)); 6255 assert_pixmap_contains_box_with_offset(src_pixmap, 6256 RegionExtents(region), 6257 src_dx, src_dy); 6258 6259 replaces = n == 1 && 6260 alu_overwrites(alu) && 6261 box->x1 <= 0 && 6262 box->y1 <= 0 && 6263 box->x2 >= dst_pixmap->drawable.width && 6264 box->y2 >= dst_pixmap->drawable.height; 6265 6266 DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n", 6267 __FUNCTION__, 6268 dst_priv, 6269 dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0, 6270 dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0, 6271 src_priv, 6272 src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0, 6273 src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0, 6274 replaces)); 6275 6276 if (dst_priv == NULL) { 6277 DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__)); 6278 goto fallback; 6279 } 6280 6281 if (alu == GXcopy && 6282 src_priv && src_priv->cow && 6283 COW(src_priv->cow) == COW(dst_priv->cow)) { 6284 if ((dx | dy) == 0) { 6285 DBG(("%s: ignoring cow for no op\n", 6286 __FUNCTION__)); 6287 return; 6288 } else if (IS_COW_OWNER(dst_priv->cow)) { 6289 /* XXX hack for firefox -- subsequent uses of src will be corrupt! */ 6290 DBG(("%s: ignoring cow reference for cousin copy\n", 6291 __FUNCTION__)); 6292 assert(src_priv->cpu_damage == NULL); 6293 assert(dst_priv->move_to_gpu == NULL); 6294 bo = dst_priv->gpu_bo; 6295 damage = NULL; 6296 } else 6297 goto discard_cow; 6298 } else { 6299 unsigned hint; 6300discard_cow: 6301 hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy); 6302 if (replaces) { 6303 discard_cpu_damage(sna, dst_priv); 6304 hint |= REPLACES | IGNORE_DAMAGE; 6305 } else if (alu_overwrites(alu)) { 6306 if (region->data == NULL) 6307 hint |= IGNORE_DAMAGE; 6308 if (dst_priv->cpu_damage && 6309 region_subsumes_damage(region, 6310 dst_priv->cpu_damage)) 6311 discard_cpu_damage(sna, dst_priv); 6312 } 6313 bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint, 6314 ®ion->extents, &damage); 6315 } 6316 if (bo) { 6317 if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) { 6318 uint32_t color; 6319 6320 if (alu == GXset) 6321 color = (1 << dst_pixmap->drawable.depth) - 1; 6322 else if (alu == GXclear) 6323 color = 0; 6324 else 6325 color = src_priv->clear_color; 6326 DBG(("%s: applying src clear [%08x] to dst\n", 6327 __FUNCTION__, src_priv->clear_color)); 6328 6329 if (n == 1) { 6330 if (replaces && UNDO) 6331 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6332 6333 if (!sna->render.fill_one(sna, 6334 dst_pixmap, bo, color, 6335 box->x1, box->y1, 6336 box->x2, box->y2, 6337 alu)) { 6338 DBG(("%s: unsupported fill\n", 6339 __FUNCTION__)); 6340 goto fallback; 6341 } 6342 6343 if (replaces && bo == dst_priv->gpu_bo) { 6344 DBG(("%s: marking dst handle=%d as all clear [%08x]\n", 6345 __FUNCTION__, 6346 dst_priv->gpu_bo->handle, 6347 src_priv->clear_color)); 6348 dst_priv->clear = true; 6349 dst_priv->clear_color = color; 6350 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6351 sna_damage_destroy(&dst_priv->cpu_damage); 6352 list_del(&dst_priv->flush_list); 6353 return; 6354 } 6355 } else { 6356 struct sna_fill_op fill; 6357 6358 if (!sna_fill_init_blt(&fill, sna, 6359 dst_pixmap, bo, 6360 alu, color, 6361 FILL_BOXES)) { 6362 DBG(("%s: unsupported fill\n", 6363 __FUNCTION__)); 6364 goto fallback; 6365 } 6366 6367 fill.boxes(sna, &fill, box, n); 6368 fill.done(sna, &fill); 6369 } 6370 6371 if (damage) 6372 sna_damage_add(damage, region); 6373 return; 6374 } 6375 6376 if (src_priv && 6377 move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) && 6378 sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 6379 DBG(("%s: move whole src_pixmap to GPU and copy\n", 6380 __FUNCTION__)); 6381 if (replaces && UNDO) 6382 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6383 6384 if (replaces && 6385 src_pixmap->drawable.width == dst_pixmap->drawable.width && 6386 src_pixmap->drawable.height == dst_pixmap->drawable.height) { 6387 assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth); 6388 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6389 if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) { 6390 assert(dst_priv->gpu_bo == src_priv->gpu_bo); 6391 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6392 sna_damage_destroy(&dst_priv->cpu_damage); 6393 list_del(&dst_priv->flush_list); 6394 if (dst_priv->shm) 6395 sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo); 6396 return; 6397 } 6398 } 6399 if (!sna->render.copy_boxes(sna, alu, 6400 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6401 &dst_pixmap->drawable, bo, 0, 0, 6402 box, n, 0)) { 6403 DBG(("%s: fallback - accelerated copy boxes failed\n", 6404 __FUNCTION__)); 6405 goto fallback; 6406 } 6407 6408 if (damage) 6409 sna_damage_add(damage, region); 6410 return; 6411 } 6412 6413 if (src_priv && 6414 region_overlaps_damage(region, src_priv->gpu_damage, 6415 src_dx, src_dy)) { 6416 BoxRec area; 6417 6418 DBG(("%s: region overlaps GPU damage, upload and copy\n", 6419 __FUNCTION__)); 6420 6421 area = region->extents; 6422 area.x1 += src_dx; 6423 area.x2 += src_dx; 6424 area.y1 += src_dy; 6425 area.y2 += src_dy; 6426 6427 if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area, 6428 MOVE_READ | MOVE_ASYNC_HINT)) { 6429 DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__)); 6430 goto fallback; 6431 } 6432 6433 if (replaces && UNDO) 6434 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6435 6436 if (!sna->render.copy_boxes(sna, alu, 6437 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6438 &dst_pixmap->drawable, bo, 0, 0, 6439 box, n, 0)) { 6440 DBG(("%s: fallback - accelerated copy boxes failed\n", 6441 __FUNCTION__)); 6442 goto fallback; 6443 } 6444 6445 if (damage) 6446 sna_damage_add(damage, region); 6447 return; 6448 } 6449 6450 if (bo != dst_priv->gpu_bo) 6451 goto fallback; 6452 6453 if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) { 6454 bool ret; 6455 6456 DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n", 6457 __FUNCTION__, src_priv->shm)); 6458 6459 assert(bo != dst_priv->cpu_bo); 6460 6461 RegionTranslate(region, src_dx, src_dy); 6462 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6463 region, 6464 MOVE_READ | MOVE_ASYNC_HINT); 6465 RegionTranslate(region, -src_dx, -src_dy); 6466 if (!ret) { 6467 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6468 goto fallback; 6469 } 6470 6471 if (replaces && UNDO) 6472 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6473 6474 if (src_priv->shm) { 6475 assert(!src_priv->flush); 6476 sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo); 6477 } 6478 6479 if (!sna->render.copy_boxes(sna, alu, 6480 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy, 6481 &dst_pixmap->drawable, bo, 0, 0, 6482 box, n, src_priv->shm ? COPY_LAST : 0)) { 6483 DBG(("%s: fallback - accelerated copy boxes failed\n", 6484 __FUNCTION__)); 6485 goto fallback; 6486 } 6487 6488 if (damage) 6489 sna_damage_add(damage, region); 6490 return; 6491 } 6492 6493 if (src_priv) { 6494 bool ret; 6495 6496 RegionTranslate(region, src_dx, src_dy); 6497 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6498 region, MOVE_READ); 6499 RegionTranslate(region, -src_dx, -src_dy); 6500 if (!ret) { 6501 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6502 goto fallback; 6503 } 6504 6505 assert(!src_priv->mapped); 6506 if (src_pixmap->devPrivate.ptr == NULL) 6507 /* uninitialised!*/ 6508 return; 6509 } 6510 6511 if (USE_USERPTR_UPLOADS && 6512 sna->kgem.has_userptr && 6513 (alu != GXcopy || 6514 (box_inplace(src_pixmap, ®ion->extents) && 6515 __kgem_bo_is_busy(&sna->kgem, bo)))) { 6516 struct kgem_bo *src_bo; 6517 bool ok = false; 6518 6519 DBG(("%s: upload through a temporary map\n", 6520 __FUNCTION__)); 6521 6522 assert(src_pixmap->devKind); 6523 src_bo = kgem_create_map(&sna->kgem, 6524 src_pixmap->devPrivate.ptr, 6525 src_pixmap->devKind * src_pixmap->drawable.height, 6526 true); 6527 if (src_bo) { 6528 src_bo->pitch = src_pixmap->devKind; 6529 kgem_bo_mark_unreusable(src_bo); 6530 6531 ok = sna->render.copy_boxes(sna, alu, 6532 &src_pixmap->drawable, src_bo, src_dx, src_dy, 6533 &dst_pixmap->drawable, bo, 0, 0, 6534 box, n, COPY_LAST); 6535 6536 kgem_bo_sync__cpu(&sna->kgem, src_bo); 6537 assert(src_bo->rq == NULL); 6538 kgem_bo_destroy(&sna->kgem, src_bo); 6539 } 6540 6541 if (ok) { 6542 if (damage) 6543 sna_damage_add(damage, region); 6544 return; 6545 } 6546 } 6547 6548 if (alu != GXcopy) { 6549 PixmapPtr tmp; 6550 struct kgem_bo *src_bo; 6551 int i; 6552 6553 assert(src_pixmap->drawable.depth != 1); 6554 6555 DBG(("%s: creating temporary source upload for non-copy alu [%d]\n", 6556 __FUNCTION__, alu)); 6557 6558 tmp = sna_pixmap_create_upload(src->pScreen, 6559 region->extents.x2 - region->extents.x1, 6560 region->extents.y2 - region->extents.y1, 6561 src->depth, 6562 KGEM_BUFFER_WRITE_INPLACE); 6563 if (tmp == NullPixmap) 6564 return; 6565 6566 src_bo = __sna_pixmap_get_bo(tmp); 6567 assert(src_bo != NULL); 6568 6569 dx = -region->extents.x1; 6570 dy = -region->extents.y1; 6571 for (i = 0; i < n; i++) { 6572 assert(box[i].x1 + src_dx >= 0); 6573 assert(box[i].y1 + src_dy >= 0); 6574 assert(box[i].x2 + src_dx <= src_pixmap->drawable.width); 6575 assert(box[i].y2 + src_dy <= src_pixmap->drawable.height); 6576 6577 assert(box[i].x1 + dx >= 0); 6578 assert(box[i].y1 + dy >= 0); 6579 assert(box[i].x2 + dx <= tmp->drawable.width); 6580 assert(box[i].y2 + dy <= tmp->drawable.height); 6581 6582 assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ)); 6583 assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE)); 6584 assert(src_pixmap->devKind); 6585 assert(tmp->devKind); 6586 memcpy_blt(src_pixmap->devPrivate.ptr, 6587 tmp->devPrivate.ptr, 6588 src_pixmap->drawable.bitsPerPixel, 6589 src_pixmap->devKind, 6590 tmp->devKind, 6591 box[i].x1 + src_dx, 6592 box[i].y1 + src_dy, 6593 box[i].x1 + dx, 6594 box[i].y1 + dy, 6595 box[i].x2 - box[i].x1, 6596 box[i].y2 - box[i].y1); 6597 } 6598 6599 if (n == 1 && 6600 tmp->drawable.width == src_pixmap->drawable.width && 6601 tmp->drawable.height == src_pixmap->drawable.height) { 6602 DBG(("%s: caching upload for src bo\n", 6603 __FUNCTION__)); 6604 assert(src_priv->gpu_damage == NULL); 6605 assert(src_priv->gpu_bo == NULL); 6606 kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo); 6607 } 6608 6609 if (!sna->render.copy_boxes(sna, alu, 6610 &tmp->drawable, src_bo, dx, dy, 6611 &dst_pixmap->drawable, bo, 0, 0, 6612 box, n, 0)) { 6613 DBG(("%s: fallback - accelerated copy boxes failed\n", 6614 __FUNCTION__)); 6615 tmp->drawable.pScreen->DestroyPixmap(tmp); 6616 goto fallback; 6617 } 6618 tmp->drawable.pScreen->DestroyPixmap(tmp); 6619 6620 if (damage) 6621 sna_damage_add(damage, region); 6622 return; 6623 } else { 6624 DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n", 6625 __FUNCTION__)); 6626 6627 assert(src_pixmap->devKind); 6628 if (!dst_priv->pinned && replaces) { 6629 stride = src_pixmap->devKind; 6630 bits = src_pixmap->devPrivate.ptr; 6631 bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8; 6632 6633 if (!sna_replace(sna, dst_pixmap, bits, stride)) { 6634 DBG(("%s: replace failed, fallback\n", __FUNCTION__)); 6635 goto fallback; 6636 } 6637 } else { 6638 assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage)); 6639 if (!sna_write_boxes(sna, dst_pixmap, 6640 dst_priv->gpu_bo, 0, 0, 6641 src_pixmap->devPrivate.ptr, 6642 src_pixmap->devKind, 6643 src_dx, src_dy, 6644 box, n)) { 6645 DBG(("%s: write failed, fallback\n", __FUNCTION__)); 6646 goto fallback; 6647 } 6648 } 6649 6650 assert(dst_priv->clear == false); 6651 dst_priv->cpu = false; 6652 if (damage) { 6653 assert(!dst_priv->clear); 6654 assert(dst_priv->gpu_bo); 6655 assert(dst_priv->gpu_bo->proxy == NULL); 6656 assert(*damage == dst_priv->gpu_damage); 6657 if (replaces) { 6658 sna_damage_destroy(&dst_priv->cpu_damage); 6659 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6660 list_del(&dst_priv->flush_list); 6661 } else 6662 sna_damage_add(&dst_priv->gpu_damage, 6663 region); 6664 assert_pixmap_damage(dst_pixmap); 6665 } 6666 } 6667 6668 return; 6669 } 6670 6671fallback: 6672 if (alu == GXcopy && src_priv && src_priv->clear) { 6673 DBG(("%s: copying clear [%08x]\n", 6674 __FUNCTION__, src_priv->clear_color)); 6675 6676 if (dst_priv) { 6677 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6678 region, 6679 MOVE_WRITE | MOVE_INPLACE_HINT)) 6680 return; 6681 } 6682 6683 assert(dst_pixmap->devPrivate.ptr); 6684 assert(dst_pixmap->devKind); 6685 do { 6686 pixman_fill(dst_pixmap->devPrivate.ptr, 6687 dst_pixmap->devKind/sizeof(uint32_t), 6688 dst_pixmap->drawable.bitsPerPixel, 6689 box->x1, box->y1, 6690 box->x2 - box->x1, 6691 box->y2 - box->y1, 6692 src_priv->clear_color); 6693 box++; 6694 } while (--n); 6695 } else if (!sna_copy_boxes__inplace(sna, region, alu, 6696 src_pixmap, src_priv, 6697 src_dx, src_dy, 6698 dst_pixmap, dst_priv, 6699 replaces)) { 6700 FbBits *dst_bits, *src_bits; 6701 int dst_stride, src_stride; 6702 6703 DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", 6704 __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); 6705 if (src_priv) { 6706 unsigned mode; 6707 6708 RegionTranslate(region, src_dx, src_dy); 6709 6710 assert_pixmap_contains_box(src_pixmap, 6711 RegionExtents(region)); 6712 6713 mode = MOVE_READ; 6714 if (!sna->kgem.can_blt_cpu || 6715 (src_priv->cpu_bo == NULL && 6716 (src_priv->create & KGEM_CAN_CREATE_CPU) == 0)) 6717 mode |= MOVE_INPLACE_HINT; 6718 6719 if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6720 region, mode)) 6721 return; 6722 6723 RegionTranslate(region, -src_dx, -src_dy); 6724 } 6725 assert(src_priv == sna_pixmap(src_pixmap)); 6726 6727 if (dst_priv) { 6728 unsigned mode; 6729 6730 if (alu_overwrites(alu)) 6731 mode = MOVE_WRITE | MOVE_INPLACE_HINT; 6732 else 6733 mode = MOVE_WRITE | MOVE_READ; 6734 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6735 region, mode)) 6736 return; 6737 } 6738 assert(dst_priv == sna_pixmap(dst_pixmap)); 6739 6740 assert(dst_pixmap->devKind); 6741 assert(src_pixmap->devKind); 6742 dst_stride = dst_pixmap->devKind; 6743 src_stride = src_pixmap->devKind; 6744 6745 if (alu == GXcopy && bpp >= 8) { 6746 dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr; 6747 src_bits = (FbBits *) 6748 ((char *)src_pixmap->devPrivate.ptr + 6749 src_dy * src_stride + src_dx * bpp / 8); 6750 6751 do { 6752 DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", 6753 __FUNCTION__, 6754 box->x1, box->y1, 6755 box->x2 - box->x1, 6756 box->y2 - box->y1, 6757 src_dx, src_dy, 6758 src_stride, dst_stride)); 6759 6760 assert(box->x1 >= 0); 6761 assert(box->y1 >= 0); 6762 assert(box->x2 <= dst_pixmap->drawable.width); 6763 assert(box->y2 <= dst_pixmap->drawable.height); 6764 6765 assert(box->x1 + src_dx >= 0); 6766 assert(box->y1 + src_dy >= 0); 6767 assert(box->x2 + src_dx <= src_pixmap->drawable.width); 6768 assert(box->y2 + src_dy <= src_pixmap->drawable.height); 6769 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6770 assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); 6771 assert(src_stride); 6772 assert(dst_stride); 6773 memcpy_blt(src_bits, dst_bits, bpp, 6774 src_stride, dst_stride, 6775 box->x1, box->y1, 6776 box->x1, box->y1, 6777 box->x2 - box->x1, 6778 box->y2 - box->y1); 6779 box++; 6780 } while (--n); 6781 } else { 6782 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); 6783 6784 RegionTranslate(region, -dst_dx, -dst_dy); 6785 6786 if (sna_gc_move_to_cpu(gc, dst, region) && 6787 sigtrap_get() == 0) { 6788 miCopyRegion(src, dst, gc, 6789 region, dx, dy, 6790 fbCopyNtoN, 0, NULL); 6791 sigtrap_put(); 6792 } 6793 6794 sna_gc_move_to_gpu(gc); 6795 } 6796 } 6797} 6798 6799typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6800 RegionPtr region, int dx, int dy, 6801 Pixel bitPlane, void *closure); 6802 6803static inline bool box_equal(const BoxRec *a, const BoxRec *b) 6804{ 6805 return *(const uint64_t *)a == *(const uint64_t *)b; 6806} 6807 6808static RegionPtr 6809sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6810 int sx, int sy, 6811 int width, int height, 6812 int dx, int dy, 6813 sna_copy_func copy, Pixel bitPlane, void *closure) 6814{ 6815 RegionPtr clip; 6816 RegionRec region; 6817 BoxRec src_extents; 6818 bool expose; 6819 6820 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 6821 __FUNCTION__, sx, sy, dx, dy, width, height)); 6822 6823 /* Short cut for unmapped windows */ 6824 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) { 6825 DBG(("%s: unmapped\n", __FUNCTION__)); 6826 return NULL; 6827 } 6828 6829 SourceValidate(src, sx, sy, width, height, gc->subWindowMode); 6830 6831 sx += src->x; 6832 sy += src->y; 6833 6834 dx += dst->x; 6835 dy += dst->y; 6836 6837 DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 6838 __FUNCTION__, sx, sy, dx, dy, width, height)); 6839 6840 region.extents.x1 = dx; 6841 region.extents.y1 = dy; 6842 region.extents.x2 = bound(dx, width); 6843 region.extents.y2 = bound(dy, height); 6844 region.data = NULL; 6845 6846 DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__, 6847 region.extents.x1, region.extents.y1, 6848 region.extents.x2, region.extents.y2, 6849 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 6850 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2, 6851 dst->width, dst->height)); 6852 6853 if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) { 6854 DBG(("%s: dst clipped out\n", __FUNCTION__)); 6855 return NULL; 6856 } 6857 6858 DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6859 region.extents.x1, region.extents.y1, 6860 region.extents.x2, region.extents.y2)); 6861 assert_drawable_contains_box(dst, ®ion.extents); 6862 6863 region.extents.x1 = clamp(region.extents.x1, sx - dx); 6864 region.extents.x2 = clamp(region.extents.x2, sx - dx); 6865 region.extents.y1 = clamp(region.extents.y1, sy - dy); 6866 region.extents.y2 = clamp(region.extents.y2, sy - dy); 6867 6868 src_extents = region.extents; 6869 expose = true; 6870 6871 DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6872 region.extents.x1, region.extents.y1, 6873 region.extents.x2, region.extents.y2)); 6874 6875 if (region.extents.x1 < src->x) 6876 region.extents.x1 = src->x; 6877 if (region.extents.y1 < src->y) 6878 region.extents.y1 = src->y; 6879 if (region.extents.x2 > src->x + (int) src->width) 6880 region.extents.x2 = src->x + (int) src->width; 6881 if (region.extents.y2 > src->y + (int) src->height) 6882 region.extents.y2 = src->y + (int) src->height; 6883 6884 DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6885 region.extents.x1, region.extents.y1, 6886 region.extents.x2, region.extents.y2)); 6887 if (box_empty(®ion.extents)) { 6888 DBG(("%s: src clipped out\n", __FUNCTION__)); 6889 return NULL; 6890 } 6891 6892 /* Compute source clip region */ 6893 if (src->type == DRAWABLE_PIXMAP) { 6894 if (src == dst && gc->clientClipType == CT_NONE) { 6895 DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__)); 6896 clip = gc->pCompositeClip; 6897 } else { 6898 DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__)); 6899 expose = false; 6900 clip = NULL; 6901 } 6902 } else { 6903 WindowPtr w = (WindowPtr)src; 6904 if (gc->subWindowMode == IncludeInferiors) { 6905 DBG(("%s: window -- include inferiors\n", __FUNCTION__)); 6906 6907 if (w->winSize.data) 6908 RegionIntersect(®ion, ®ion, &w->winSize); 6909 else 6910 box_intersect(®ion.extents, &w->winSize.extents); 6911 clip = &w->borderClip; 6912 } else { 6913 DBG(("%s: window -- clip by children\n", __FUNCTION__)); 6914 clip = &w->clipList; 6915 } 6916 } 6917 if (clip != NULL) { 6918 if (clip->data == NULL) { 6919 box_intersect(®ion.extents, &clip->extents); 6920 if (box_equal(&src_extents, ®ion.extents)) 6921 expose = false; 6922 } else 6923 RegionIntersect(®ion, ®ion, clip); 6924 } 6925 DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__, 6926 region.extents.x1, region.extents.y1, 6927 region.extents.x2, region.extents.y2, 6928 region_num_rects(®ion))); 6929 6930 RegionTranslate(®ion, dx-sx, dy-sy); 6931 if (gc->pCompositeClip->data) 6932 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 6933 DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n", 6934 __FUNCTION__, 6935 region.extents.x1, region.extents.y1, 6936 region.extents.x2, region.extents.y2, 6937 region_num_rects(®ion), 6938 sx-dx, sy-dy)); 6939 6940 if (!box_empty(®ion.extents)) 6941 copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure); 6942 assert(gc->pCompositeClip != ®ion); 6943 RegionUninit(®ion); 6944 6945 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 6946 clip = NULL; 6947 if (expose && gc->fExpose) 6948 clip = miHandleExposures(src, dst, gc, 6949 sx - src->x, sy - src->y, 6950 width, height, 6951 dx - dst->x, dy - dst->y, 6952 (unsigned long) bitPlane); 6953 return clip; 6954} 6955 6956static void 6957sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6958 RegionPtr region, int dx, int dy, 6959 Pixel bitplane, void *closure) 6960{ 6961 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n", 6962 __FUNCTION__, region_num_rects(region), 6963 region->extents.x1, region->extents.y1, 6964 region->extents.x2, region->extents.y2, 6965 dx, dy, gc->alu)); 6966 6967 if (!sna_gc_move_to_cpu(gc, dst, region)) 6968 goto out; 6969 6970 RegionTranslate(region, dx, dy); 6971 if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ)) 6972 goto out; 6973 RegionTranslate(region, -dx, -dy); 6974 6975 if (src == dst || 6976 get_drawable_pixmap(src) == get_drawable_pixmap(dst)) { 6977 DBG(("%s: self-copy\n", __FUNCTION__)); 6978 if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ)) 6979 goto out; 6980 } else { 6981 if (!sna_drawable_move_region_to_cpu(dst, region, 6982 drawable_gc_flags(dst, gc, false))) 6983 goto out; 6984 } 6985 6986 if (sigtrap_get() == 0) { 6987 miCopyRegion(src, dst, gc, 6988 region, dx, dy, 6989 fbCopyNtoN, 0, NULL); 6990 FALLBACK_FLUSH(dst); 6991 sigtrap_put(); 6992 } 6993out: 6994 sna_gc_move_to_gpu(gc); 6995} 6996 6997static RegionPtr 6998sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6999 int src_x, int src_y, 7000 int width, int height, 7001 int dst_x, int dst_y) 7002{ 7003 struct sna *sna = to_sna_from_drawable(dst); 7004 sna_copy_func copy; 7005 7006 if (gc->planemask == 0) 7007 return NULL; 7008 7009 DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n", 7010 __FUNCTION__, 7011 src_x, src_y, width, height, src->x, src->y, 7012 dst_x, dst_y, dst->x, dst->y, 7013 gc->alu, gc->planemask, gc->depth)); 7014 7015 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) || 7016 !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) 7017 copy = sna_fallback_copy_boxes; 7018 else if (src == dst) 7019 copy = sna_self_copy_boxes; 7020 else 7021 copy = sna_copy_boxes; 7022 7023 return sna_do_copy(src, dst, gc, 7024 src_x, src_y, 7025 width, height, 7026 dst_x, dst_y, 7027 copy, 0, NULL); 7028} 7029 7030static const BoxRec * 7031find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) 7032{ 7033 const BoxRec *mid; 7034 7035 if (end == begin) 7036 return end; 7037 7038 if (end - begin == 1) { 7039 if (begin->y2 > y) 7040 return begin; 7041 else 7042 return end; 7043 } 7044 7045 mid = begin + (end - begin) / 2; 7046 if (mid->y2 > y) 7047 /* If no box is found in [begin, mid], the function 7048 * will return @mid, which is then known to be the 7049 * correct answer. 7050 */ 7051 return find_clip_box_for_y(begin, mid, y); 7052 else 7053 return find_clip_box_for_y(mid, end, y); 7054} 7055 7056struct sna_fill_spans { 7057 struct sna *sna; 7058 PixmapPtr pixmap; 7059 RegionRec region; 7060 unsigned flags; 7061 uint32_t phase; 7062 struct kgem_bo *bo; 7063 struct sna_damage **damage; 7064 int16_t dx, dy; 7065 void *op; 7066}; 7067 7068static void 7069sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc, 7070 int mode, int n, DDXPointPtr pt) 7071{ 7072 fbPolyPoint(drawable, gc, mode, n, pt, -1); 7073} 7074 7075static void 7076sna_poly_point__fill(DrawablePtr drawable, GCPtr gc, 7077 int mode, int n, DDXPointPtr pt) 7078{ 7079 struct sna_fill_spans *data = sna_gc(gc)->priv; 7080 struct sna_fill_op *op = data->op; 7081 BoxRec box[512]; 7082 DDXPointRec last; 7083 7084 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7085 if (n == 0) 7086 return; 7087 7088 last.x = drawable->x + data->dx; 7089 last.y = drawable->y + data->dy; 7090 if (op->points && mode != CoordModePrevious) { 7091 op->points(data->sna, op, last.x, last.y, pt, n); 7092 } else do { 7093 BoxRec *b = box; 7094 unsigned nbox = n; 7095 if (nbox > ARRAY_SIZE(box)) 7096 nbox = ARRAY_SIZE(box); 7097 n -= nbox; 7098 do { 7099 *(DDXPointRec *)b = *pt++; 7100 7101 b->x1 += last.x; 7102 b->y1 += last.y; 7103 if (mode == CoordModePrevious) 7104 last = *(DDXPointRec *)b; 7105 7106 b->x2 = b->x1 + 1; 7107 b->y2 = b->y1 + 1; 7108 b++; 7109 } while (--nbox); 7110 op->boxes(data->sna, op, box, b - box); 7111 } while (n); 7112} 7113 7114static void 7115sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc, 7116 int mode, int n, DDXPointPtr pt) 7117{ 7118 struct sna_fill_spans *data = sna_gc(gc)->priv; 7119 struct sna_fill_op fill; 7120 BoxRec box[512]; 7121 DDXPointRec last; 7122 7123 if (!sna_fill_init_blt(&fill, 7124 data->sna, data->pixmap, 7125 data->bo, gc->alu, gc->fgPixel, 7126 FILL_POINTS)) 7127 return; 7128 7129 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7130 7131 last.x = drawable->x; 7132 last.y = drawable->y; 7133 while (n) { 7134 BoxRec *b = box; 7135 unsigned nbox = n; 7136 if (nbox > ARRAY_SIZE(box)) 7137 nbox = ARRAY_SIZE(box); 7138 n -= nbox; 7139 do { 7140 *(DDXPointRec *)b = *pt++; 7141 7142 b->x1 += last.x; 7143 b->y1 += last.y; 7144 if (mode == CoordModePrevious) 7145 last = *(DDXPointRec *)b; 7146 7147 if (RegionContainsPoint(&data->region, 7148 b->x1, b->y1, NULL)) { 7149 b->x1 += data->dx; 7150 b->y1 += data->dy; 7151 b->x2 = b->x1 + 1; 7152 b->y2 = b->y1 + 1; 7153 b++; 7154 } 7155 } while (--nbox); 7156 fill.boxes(data->sna, &fill, box, b - box); 7157 } 7158 fill.done(data->sna, &fill); 7159} 7160 7161static void 7162sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc, 7163 int mode, int n, DDXPointPtr pt) 7164{ 7165 struct sna_fill_spans *data = sna_gc(gc)->priv; 7166 struct sna_fill_op *op = data->op; 7167 const BoxRec *extents = &data->region.extents; 7168 BoxRec box[512], *b = box; 7169 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7170 DDXPointRec last; 7171 7172 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7173 7174 last.x = drawable->x + data->dx; 7175 last.y = drawable->y + data->dy; 7176 while (n--) { 7177 *(DDXPointRec *)b = *pt++; 7178 7179 b->x1 += last.x; 7180 b->y1 += last.y; 7181 if (mode == CoordModePrevious) 7182 last = *(DDXPointRec *)b; 7183 7184 if (b->x1 >= extents->x1 && b->x1 < extents->x2 && 7185 b->y1 >= extents->y1 && b->y1 < extents->y2) { 7186 b->x2 = b->x1 + 1; 7187 b->y2 = b->y1 + 1; 7188 if (++b == last_box) { 7189 op->boxes(data->sna, op, box, last_box - box); 7190 b = box; 7191 } 7192 } 7193 } 7194 if (b != box) 7195 op->boxes(data->sna, op, box, b - box); 7196} 7197 7198static void 7199sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc, 7200 int mode, int n, DDXPointPtr pt) 7201{ 7202 struct sna_fill_spans *data = sna_gc(gc)->priv; 7203 struct sna_fill_op *op = data->op; 7204 RegionRec *clip = &data->region; 7205 BoxRec box[512], *b = box; 7206 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7207 DDXPointRec last; 7208 7209 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7210 7211 last.x = drawable->x + data->dx; 7212 last.y = drawable->y + data->dy; 7213 while (n--) { 7214 *(DDXPointRec *)b = *pt++; 7215 7216 b->x1 += last.x; 7217 b->y1 += last.y; 7218 if (mode == CoordModePrevious) 7219 last = *(DDXPointRec *)b; 7220 7221 if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) { 7222 b->x2 = b->x1 + 1; 7223 b->y2 = b->y1 + 1; 7224 if (++b == last_box) { 7225 op->boxes(data->sna, op, box, last_box - box); 7226 b = box; 7227 } 7228 } 7229 } 7230 if (b != box) 7231 op->boxes(data->sna, op, box, b - box); 7232} 7233 7234static void 7235sna_poly_point__dash(DrawablePtr drawable, GCPtr gc, 7236 int mode, int n, DDXPointPtr pt) 7237{ 7238 struct sna_fill_spans *data = sna_gc(gc)->priv; 7239 if (data->phase == gc->fgPixel) 7240 sna_poly_point__fill(drawable, gc, mode, n, pt); 7241} 7242 7243static void 7244sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc, 7245 int mode, int n, DDXPointPtr pt) 7246{ 7247 struct sna_fill_spans *data = sna_gc(gc)->priv; 7248 if (data->phase == gc->fgPixel) 7249 sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt); 7250} 7251 7252static void 7253sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc, 7254 int mode, int n, DDXPointPtr pt) 7255{ 7256 struct sna_fill_spans *data = sna_gc(gc)->priv; 7257 if (data->phase == gc->fgPixel) 7258 sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt); 7259} 7260 7261static void 7262sna_fill_spans__fill(DrawablePtr drawable, 7263 GCPtr gc, int n, 7264 DDXPointPtr pt, int *width, int sorted) 7265{ 7266 struct sna_fill_spans *data = sna_gc(gc)->priv; 7267 struct sna_fill_op *op = data->op; 7268 BoxRec box[512]; 7269 7270 DBG(("%s: alu=%d, fg=%08lx, count=%d\n", 7271 __FUNCTION__, gc->alu, gc->fgPixel, n)); 7272 7273 while (n) { 7274 BoxRec *b = box; 7275 int nbox = n; 7276 if (nbox > ARRAY_SIZE(box)) 7277 nbox = ARRAY_SIZE(box); 7278 n -= nbox; 7279 do { 7280 *(DDXPointRec *)b = *pt++; 7281 b->x2 = b->x1 + (int)*width++; 7282 b->y2 = b->y1 + 1; 7283 DBG(("%s: (%d, %d), (%d, %d)\n", 7284 __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); 7285 assert(b->x1 >= drawable->x); 7286 assert(b->x2 <= drawable->x + drawable->width); 7287 assert(b->y1 >= drawable->y); 7288 assert(b->y2 <= drawable->y + drawable->height); 7289 if (b->x2 > b->x1) { 7290 if (b != box && 7291 b->y1 == b[-1].y2 && 7292 b->x1 == b[-1].x1 && 7293 b->x2 == b[-1].x2) 7294 b[-1].y2 = b->y2; 7295 else 7296 b++; 7297 } 7298 } while (--nbox); 7299 if (b != box) 7300 op->boxes(data->sna, op, box, b - box); 7301 } 7302} 7303 7304static void 7305sna_fill_spans__dash(DrawablePtr drawable, 7306 GCPtr gc, int n, 7307 DDXPointPtr pt, int *width, int sorted) 7308{ 7309 struct sna_fill_spans *data = sna_gc(gc)->priv; 7310 if (data->phase == gc->fgPixel) 7311 sna_fill_spans__fill(drawable, gc, n, pt, width, sorted); 7312} 7313 7314static void 7315sna_fill_spans__fill_offset(DrawablePtr drawable, 7316 GCPtr gc, int n, 7317 DDXPointPtr pt, int *width, int sorted) 7318{ 7319 struct sna_fill_spans *data = sna_gc(gc)->priv; 7320 struct sna_fill_op *op = data->op; 7321 BoxRec box[512]; 7322 7323 DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); 7324 7325 while (n) { 7326 BoxRec *b = box; 7327 int nbox = n; 7328 if (nbox > ARRAY_SIZE(box)) 7329 nbox = ARRAY_SIZE(box); 7330 n -= nbox; 7331 do { 7332 *(DDXPointRec *)b = *pt++; 7333 b->x1 += data->dx; 7334 b->y1 += data->dy; 7335 b->x2 = b->x1 + (int)*width++; 7336 b->y2 = b->y1 + 1; 7337 if (b->x2 > b->x1) 7338 b++; 7339 } while (--nbox); 7340 if (b != box) 7341 op->boxes(data->sna, op, box, b - box); 7342 } 7343} 7344 7345static void 7346sna_fill_spans__dash_offset(DrawablePtr drawable, 7347 GCPtr gc, int n, 7348 DDXPointPtr pt, int *width, int sorted) 7349{ 7350 struct sna_fill_spans *data = sna_gc(gc)->priv; 7351 if (data->phase == gc->fgPixel) 7352 sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted); 7353} 7354 7355static void 7356sna_fill_spans__fill_clip_extents(DrawablePtr drawable, 7357 GCPtr gc, int n, 7358 DDXPointPtr pt, int *width, int sorted) 7359{ 7360 struct sna_fill_spans *data = sna_gc(gc)->priv; 7361 struct sna_fill_op *op = data->op; 7362 const BoxRec *extents = &data->region.extents; 7363 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7364 7365 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7366 __FUNCTION__, gc->alu, gc->fgPixel, n, 7367 extents->x1, extents->y1, 7368 extents->x2, extents->y2)); 7369 7370 while (n--) { 7371 DBG(("%s: [%d] pt=(%d, %d), width=%d\n", 7372 __FUNCTION__, n, pt->x, pt->y, *width)); 7373 *(DDXPointRec *)b = *pt++; 7374 b->x2 = b->x1 + (int)*width++; 7375 b->y2 = b->y1 + 1; 7376 if (box_intersect(b, extents)) { 7377 DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n", 7378 __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2)); 7379 if (data->dx|data->dy) { 7380 b->x1 += data->dx; b->x2 += data->dx; 7381 b->y1 += data->dy; b->y2 += data->dy; 7382 } 7383 if (b != box && 7384 b->y1 == b[-1].y2 && 7385 b->x1 == b[-1].x1 && 7386 b->x2 == b[-1].x2) { 7387 b[-1].y2 = b->y2; 7388 } else if (++b == last_box) { 7389 op->boxes(data->sna, op, box, last_box - box); 7390 b = box; 7391 } 7392 } 7393 } 7394 if (b != box) 7395 op->boxes(data->sna, op, box, b - box); 7396} 7397 7398static void 7399sna_fill_spans__dash_clip_extents(DrawablePtr drawable, 7400 GCPtr gc, int n, 7401 DDXPointPtr pt, int *width, int sorted) 7402{ 7403 struct sna_fill_spans *data = sna_gc(gc)->priv; 7404 if (data->phase == gc->fgPixel) 7405 sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted); 7406} 7407 7408static void 7409sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, 7410 GCPtr gc, int n, 7411 DDXPointPtr pt, int *width, int sorted) 7412{ 7413 struct sna_fill_spans *data = sna_gc(gc)->priv; 7414 struct sna_fill_op *op = data->op; 7415 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7416 const BoxRec * const clip_start = RegionBoxptr(&data->region); 7417 const BoxRec * const clip_end = clip_start + data->region.data->numRects; 7418 7419 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7420 __FUNCTION__, gc->alu, gc->fgPixel, n, 7421 data->region.extents.x1, data->region.extents.y1, 7422 data->region.extents.x2, data->region.extents.y2)); 7423 7424 while (n--) { 7425 int16_t X1 = pt->x; 7426 int16_t y = pt->y; 7427 int16_t X2 = X1 + (int)*width; 7428 const BoxRec *c; 7429 7430 pt++; 7431 width++; 7432 7433 if (y < data->region.extents.y1 || data->region.extents.y2 <= y) 7434 continue; 7435 7436 if (X1 < data->region.extents.x1) 7437 X1 = data->region.extents.x1; 7438 7439 if (X2 > data->region.extents.x2) 7440 X2 = data->region.extents.x2; 7441 7442 if (X1 >= X2) 7443 continue; 7444 7445 c = find_clip_box_for_y(clip_start, clip_end, y); 7446 while (c != clip_end) { 7447 if (y + 1 <= c->y1 || X2 <= c->x1) 7448 break; 7449 7450 if (X1 >= c->x2) { 7451 c++; 7452 continue; 7453 } 7454 7455 b->x1 = c->x1; 7456 b->x2 = c->x2; 7457 c++; 7458 7459 if (b->x1 < X1) 7460 b->x1 = X1; 7461 if (b->x2 > X2) 7462 b->x2 = X2; 7463 if (b->x2 <= b->x1) 7464 continue; 7465 7466 b->x1 += data->dx; 7467 b->x2 += data->dx; 7468 b->y1 = y + data->dy; 7469 b->y2 = b->y1 + 1; 7470 if (++b == last_box) { 7471 op->boxes(data->sna, op, box, last_box - box); 7472 b = box; 7473 } 7474 } 7475 } 7476 if (b != box) 7477 op->boxes(data->sna, op, box, b - box); 7478} 7479 7480static void 7481sna_fill_spans__dash_clip_boxes(DrawablePtr drawable, 7482 GCPtr gc, int n, 7483 DDXPointPtr pt, int *width, int sorted) 7484{ 7485 struct sna_fill_spans *data = sna_gc(gc)->priv; 7486 if (data->phase == gc->fgPixel) 7487 sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted); 7488} 7489 7490static bool 7491sna_fill_spans_blt(DrawablePtr drawable, 7492 struct kgem_bo *bo, struct sna_damage **damage, 7493 GCPtr gc, uint32_t pixel, 7494 int n, DDXPointPtr pt, int *width, int sorted, 7495 const BoxRec *extents, unsigned clipped) 7496{ 7497 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7498 struct sna *sna = to_sna_from_pixmap(pixmap); 7499 int16_t dx, dy; 7500 struct sna_fill_op fill; 7501 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7502 static void * const jump[] = { 7503 &&no_damage, 7504 &&damage, 7505 &&no_damage_clipped, 7506 &&damage_clipped, 7507 }; 7508 unsigned v; 7509 7510 DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n", 7511 __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped)); 7512 7513 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 7514 return false; 7515 7516 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7517 7518 v = (damage != NULL) | clipped; 7519 goto *jump[v]; 7520 7521no_damage: 7522 if (dx|dy) { 7523 do { 7524 int nbox = n; 7525 if (nbox > last_box - box) 7526 nbox = last_box - box; 7527 n -= nbox; 7528 do { 7529 *(DDXPointRec *)b = *pt++; 7530 b->x1 += dx; 7531 b->y1 += dy; 7532 b->x2 = b->x1 + (int)*width++; 7533 b->y2 = b->y1 + 1; 7534 b++; 7535 } while (--nbox); 7536 fill.boxes(sna, &fill, box, b - box); 7537 b = box; 7538 } while (n); 7539 } else { 7540 do { 7541 int nbox = n; 7542 if (nbox > last_box - box) 7543 nbox = last_box - box; 7544 n -= nbox; 7545 do { 7546 *(DDXPointRec *)b = *pt++; 7547 b->x2 = b->x1 + (int)*width++; 7548 b->y2 = b->y1 + 1; 7549 b++; 7550 } while (--nbox); 7551 fill.boxes(sna, &fill, box, b - box); 7552 b = box; 7553 } while (n); 7554 } 7555 goto done; 7556 7557damage: 7558 do { 7559 *(DDXPointRec *)b = *pt++; 7560 b->x1 += dx; 7561 b->y1 += dy; 7562 b->x2 = b->x1 + (int)*width++; 7563 b->y2 = b->y1 + 1; 7564 7565 if (++b == last_box) { 7566 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7567 fill.boxes(sna, &fill, box, last_box - box); 7568 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7569 b = box; 7570 } 7571 } while (--n); 7572 if (b != box) { 7573 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7574 fill.boxes(sna, &fill, box, b - box); 7575 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7576 } 7577 goto done; 7578 7579no_damage_clipped: 7580 { 7581 RegionRec clip; 7582 7583 region_set(&clip, extents); 7584 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7585 return true; 7586 7587 assert(dx + clip.extents.x1 >= 0); 7588 assert(dy + clip.extents.y1 >= 0); 7589 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7590 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7591 7592 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7593 __FUNCTION__, 7594 region_num_rects(&clip), 7595 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7596 n, pt->x, pt->y)); 7597 7598 if (clip.data == NULL) { 7599 do { 7600 *(DDXPointRec *)b = *pt++; 7601 b->x2 = b->x1 + (int)*width++; 7602 b->y2 = b->y1 + 1; 7603 7604 if (box_intersect(b, &clip.extents)) { 7605 if (dx|dy) { 7606 b->x1 += dx; b->x2 += dx; 7607 b->y1 += dy; b->y2 += dy; 7608 } 7609 if (++b == last_box) { 7610 fill.boxes(sna, &fill, box, last_box - box); 7611 b = box; 7612 } 7613 } 7614 } while (--n); 7615 } else { 7616 const BoxRec * const clip_start = RegionBoxptr(&clip); 7617 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7618 do { 7619 int16_t X1 = pt->x; 7620 int16_t y = pt->y; 7621 int16_t X2 = X1 + (int)*width; 7622 const BoxRec *c; 7623 7624 pt++; 7625 width++; 7626 7627 if (y < extents->y1 || extents->y2 <= y) 7628 continue; 7629 7630 if (X1 < extents->x1) 7631 X1 = extents->x1; 7632 7633 if (X2 > extents->x2) 7634 X2 = extents->x2; 7635 7636 if (X1 >= X2) 7637 continue; 7638 7639 c = find_clip_box_for_y(clip_start, 7640 clip_end, 7641 y); 7642 while (c != clip_end) { 7643 if (y + 1 <= c->y1 || X2 <= c->x1) 7644 break; 7645 7646 if (X1 >= c->x2) { 7647 c++; 7648 continue; 7649 } 7650 7651 b->x1 = c->x1; 7652 b->x2 = c->x2; 7653 c++; 7654 7655 if (b->x1 < X1) 7656 b->x1 = X1; 7657 if (b->x2 > X2) 7658 b->x2 = X2; 7659 if (b->x2 <= b->x1) 7660 continue; 7661 7662 b->x1 += dx; 7663 b->x2 += dx; 7664 b->y1 = y + dy; 7665 b->y2 = b->y1 + 1; 7666 if (++b == last_box) { 7667 fill.boxes(sna, &fill, box, last_box - box); 7668 b = box; 7669 } 7670 } 7671 } while (--n); 7672 RegionUninit(&clip); 7673 } 7674 if (b != box) 7675 fill.boxes(sna, &fill, box, b - box); 7676 goto done; 7677 } 7678 7679damage_clipped: 7680 { 7681 RegionRec clip; 7682 7683 region_set(&clip, extents); 7684 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7685 return true; 7686 7687 assert(dx + clip.extents.x1 >= 0); 7688 assert(dy + clip.extents.y1 >= 0); 7689 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7690 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7691 7692 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7693 __FUNCTION__, 7694 region_num_rects(&clip), 7695 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7696 n, pt->x, pt->y)); 7697 7698 if (clip.data == NULL) { 7699 do { 7700 *(DDXPointRec *)b = *pt++; 7701 b->x2 = b->x1 + (int)*width++; 7702 b->y2 = b->y1 + 1; 7703 7704 if (box_intersect(b, &clip.extents)) { 7705 b->x1 += dx; 7706 b->x2 += dx; 7707 b->y1 += dy; 7708 b->y2 += dy; 7709 if (++b == last_box) { 7710 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7711 fill.boxes(sna, &fill, box, last_box - box); 7712 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7713 b = box; 7714 } 7715 } 7716 } while (--n); 7717 } else { 7718 const BoxRec * const clip_start = RegionBoxptr(&clip); 7719 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7720 do { 7721 int16_t X1 = pt->x; 7722 int16_t y = pt->y; 7723 int16_t X2 = X1 + (int)*width; 7724 const BoxRec *c; 7725 7726 pt++; 7727 width++; 7728 7729 if (y < extents->y1 || extents->y2 <= y) 7730 continue; 7731 7732 if (X1 < extents->x1) 7733 X1 = extents->x1; 7734 7735 if (X2 > extents->x2) 7736 X2 = extents->x2; 7737 7738 if (X1 >= X2) 7739 continue; 7740 7741 c = find_clip_box_for_y(clip_start, 7742 clip_end, 7743 y); 7744 while (c != clip_end) { 7745 if (y + 1 <= c->y1 || X2 <= c->x1) 7746 break; 7747 7748 if (X1 >= c->x2) { 7749 c++; 7750 continue; 7751 } 7752 7753 b->x1 = c->x1; 7754 b->x2 = c->x2; 7755 c++; 7756 7757 if (b->x1 < X1) 7758 b->x1 = X1; 7759 if (b->x2 > X2) 7760 b->x2 = X2; 7761 if (b->x2 <= b->x1) 7762 continue; 7763 7764 b->x1 += dx; 7765 b->x2 += dx; 7766 b->y1 = y + dy; 7767 b->y2 = b->y1 + 1; 7768 if (++b == last_box) { 7769 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7770 fill.boxes(sna, &fill, box, last_box - box); 7771 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7772 b = box; 7773 } 7774 } 7775 } while (--n); 7776 RegionUninit(&clip); 7777 } 7778 if (b != box) { 7779 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7780 fill.boxes(sna, &fill, box, b - box); 7781 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7782 } 7783 goto done; 7784 } 7785 7786done: 7787 fill.done(sna, &fill); 7788 assert_pixmap_damage(pixmap); 7789 return true; 7790} 7791 7792static bool 7793sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 7794 struct kgem_bo *bo, 7795 struct sna_damage **damage, 7796 GCPtr gc, int n, xRectangle *rect, 7797 const BoxRec *extents, unsigned clipped); 7798 7799static bool 7800sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 7801 struct kgem_bo *bo, 7802 struct sna_damage **damage, 7803 GCPtr gc, int n, xRectangle *rect, 7804 const BoxRec *extents, unsigned clipped); 7805 7806static inline bool 7807gc_is_solid(GCPtr gc, uint32_t *color) 7808{ 7809 assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask)); 7810 7811 if (gc->alu == GXclear) { 7812 *color = 0; 7813 return true; 7814 } 7815 if (gc->alu == GXset) { 7816 *color = (1 << gc->depth) - 1; 7817 return true; 7818 } 7819 7820 if (gc->fillStyle == FillSolid || 7821 (gc->fillStyle == FillTiled && gc->tileIsPixel) || 7822 (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { 7823 *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; 7824 return true; 7825 } 7826 7827 return false; 7828} 7829 7830static void 7831sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n, 7832 DDXPointPtr pt, int *width, int sorted) 7833{ 7834 struct sna_fill_spans *data = sna_gc(gc)->priv; 7835 uint32_t color; 7836 7837 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 7838 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 7839 7840 assert(PM_IS_SOLID(drawable, gc->planemask)); 7841 if (n == 0) 7842 return; 7843 7844 /* The mi routines do not attempt to keep the spans it generates 7845 * within the clip, so we must run them through the clipper. 7846 */ 7847 7848 if (gc_is_solid(gc, &color)) { 7849 sna_fill_spans_blt(drawable, 7850 data->bo, NULL, 7851 gc, color, n, pt, width, sorted, 7852 &data->region.extents, 2); 7853 } else { 7854 /* Try converting these to a set of rectangles instead */ 7855 xRectangle *rect; 7856 int i; 7857 7858 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 7859 7860 rect = malloc (n * sizeof (xRectangle)); 7861 if (rect == NULL) 7862 return; 7863 7864 for (i = 0; i < n; i++) { 7865 rect[i].x = pt[i].x - drawable->x; 7866 rect[i].width = width[i]; 7867 rect[i].y = pt[i].y - drawable->y; 7868 rect[i].height = 1; 7869 } 7870 7871 if (gc->fillStyle == FillTiled) { 7872 (void)sna_poly_fill_rect_tiled_blt(drawable, 7873 data->bo, NULL, 7874 gc, n, rect, 7875 &data->region.extents, 2); 7876 } else { 7877 (void)sna_poly_fill_rect_stippled_blt(drawable, 7878 data->bo, NULL, 7879 gc, n, rect, 7880 &data->region.extents, 2); 7881 } 7882 free (rect); 7883 } 7884} 7885 7886static unsigned 7887sna_spans_extents(DrawablePtr drawable, GCPtr gc, 7888 int n, DDXPointPtr pt, int *width, 7889 BoxPtr out) 7890{ 7891 BoxRec box; 7892 bool clipped = false; 7893 7894 if (n == 0) 7895 return 0; 7896 7897 box.x1 = pt->x; 7898 box.x2 = box.x1 + *width; 7899 box.y2 = box.y1 = pt->y; 7900 7901 while (--n) { 7902 pt++; 7903 width++; 7904 if (box.x1 > pt->x) 7905 box.x1 = pt->x; 7906 if (box.x2 < pt->x + *width) 7907 box.x2 = pt->x + *width; 7908 7909 if (box.y1 > pt->y) 7910 box.y1 = pt->y; 7911 else if (box.y2 < pt->y) 7912 box.y2 = pt->y; 7913 } 7914 box.y2++; 7915 7916 if (gc) 7917 clipped = clip_box(&box, gc); 7918 if (box_empty(&box)) 7919 return 0; 7920 7921 *out = box; 7922 return 1 | clipped << 1; 7923} 7924 7925static void 7926sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n, 7927 DDXPointPtr pt, int *width, int sorted) 7928{ 7929 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7930 struct sna *sna = to_sna_from_pixmap(pixmap); 7931 struct sna_damage **damage; 7932 struct kgem_bo *bo; 7933 RegionRec region; 7934 unsigned flags; 7935 uint32_t color; 7936 7937 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 7938 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 7939 7940 flags = sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents); 7941 if (flags == 0) 7942 return; 7943 7944 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7945 region.extents.x1, region.extents.y1, 7946 region.extents.x2, region.extents.y2)); 7947 7948 if (FORCE_FALLBACK) 7949 goto fallback; 7950 7951 if (!ACCEL_FILL_SPANS) 7952 goto fallback; 7953 7954 if (wedged(sna)) { 7955 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 7956 goto fallback; 7957 } 7958 7959 DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__, 7960 gc->fillStyle, gc->fillStyle == FillSolid, 7961 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 7962 if (!PM_IS_SOLID(drawable, gc->planemask)) 7963 goto fallback; 7964 7965 bo = sna_drawable_use_bo(drawable, PREFER_GPU, 7966 ®ion.extents, &damage); 7967 if (bo) { 7968 if (gc_is_solid(gc, &color)) { 7969 DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n", 7970 __FUNCTION__, gc->alu, gc->fgPixel)); 7971 7972 sna_fill_spans_blt(drawable, 7973 bo, damage, 7974 gc, color, n, pt, width, sorted, 7975 ®ion.extents, flags & 2); 7976 } else { 7977 /* Try converting these to a set of rectangles instead */ 7978 xRectangle *rect; 7979 int i; 7980 7981 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 7982 7983 rect = malloc (n * sizeof (xRectangle)); 7984 if (rect == NULL) 7985 return; 7986 7987 for (i = 0; i < n; i++) { 7988 rect[i].x = pt[i].x - drawable->x; 7989 rect[i].width = width[i]; 7990 rect[i].y = pt[i].y - drawable->y; 7991 rect[i].height = 1; 7992 } 7993 7994 if (gc->fillStyle == FillTiled) { 7995 i = sna_poly_fill_rect_tiled_blt(drawable, 7996 bo, damage, 7997 gc, n, rect, 7998 ®ion.extents, flags & 2); 7999 } else { 8000 i = sna_poly_fill_rect_stippled_blt(drawable, 8001 bo, damage, 8002 gc, n, rect, 8003 ®ion.extents, flags & 2); 8004 } 8005 free (rect); 8006 8007 if (i) 8008 return; 8009 } 8010 } 8011 8012fallback: 8013 DBG(("%s: fallback\n", __FUNCTION__)); 8014 region.data = NULL; 8015 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8016 return; 8017 8018 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8019 goto out; 8020 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8021 drawable_gc_flags(drawable, gc, n > 1))) 8022 goto out; 8023 8024 if (sigtrap_get() == 0) { 8025 DBG(("%s: fbFillSpans\n", __FUNCTION__)); 8026 fbFillSpans(drawable, gc, n, pt, width, sorted); 8027 FALLBACK_FLUSH(drawable); 8028 sigtrap_put(); 8029 } 8030out: 8031 sna_gc_move_to_gpu(gc); 8032 RegionUninit(®ion); 8033} 8034 8035static void 8036sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 8037 DDXPointPtr pt, int *width, int n, int sorted) 8038{ 8039 RegionRec region; 8040 8041 if (sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents) == 0) 8042 return; 8043 8044 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 8045 region.extents.x1, region.extents.y1, 8046 region.extents.x2, region.extents.y2)); 8047 8048 if (FORCE_FALLBACK) 8049 goto fallback; 8050 8051 if (!ACCEL_SET_SPANS) 8052 goto fallback; 8053 8054fallback: 8055 region.data = NULL; 8056 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8057 return; 8058 8059 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8060 goto out; 8061 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8062 drawable_gc_flags(drawable, gc, n > 1))) 8063 goto out; 8064 8065 if (sigtrap_get() == 0) { 8066 DBG(("%s: fbSetSpans\n", __FUNCTION__)); 8067 fbSetSpans(drawable, gc, src, pt, width, n, sorted); 8068 FALLBACK_FLUSH(drawable); 8069 sigtrap_put(); 8070 } 8071out: 8072 sna_gc_move_to_gpu(gc); 8073 RegionUninit(®ion); 8074} 8075 8076struct sna_copy_plane { 8077 struct sna_damage **damage; 8078 struct kgem_bo *bo; 8079}; 8080 8081static void 8082sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, 8083 RegionRec *region, int sx, int sy, 8084 Pixel bitplane, void *closure) 8085{ 8086 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8087 struct sna *sna = to_sna_from_pixmap(pixmap); 8088 struct sna_copy_plane *arg = closure; 8089 PixmapPtr bitmap = (PixmapPtr)_bitmap; 8090 uint32_t br00, br13; 8091 int16_t dx, dy; 8092 const BoxRec *box; 8093 int n; 8094 8095 DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n", 8096 __FUNCTION__, (unsigned)bitplane, 8097 region->extents.x1, region->extents.y1, 8098 region->extents.x2, region->extents.y2, 8099 region_num_rects(region))); 8100 8101 box = region_rects(region); 8102 n = region_num_rects(region); 8103 assert(n); 8104 8105 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8106 assert_pixmap_contains_boxes(pixmap, box, n, dx, dy); 8107 8108 br00 = 3 << 20; 8109 br13 = arg->bo->pitch; 8110 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8111 br00 |= BLT_DST_TILED; 8112 br13 >>= 2; 8113 } 8114 br13 |= blt_depth(drawable->depth) << 24; 8115 br13 |= copy_ROP[gc->alu] << 16; 8116 8117 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8118 do { 8119 int bx1 = (box->x1 + sx) & ~7; 8120 int bx2 = (box->x2 + sx + 7) & ~7; 8121 int bw = (bx2 - bx1)/8; 8122 int bh = box->y2 - box->y1; 8123 int bstride = ALIGN(bw, 2); 8124 int src_stride; 8125 uint8_t *dst, *src; 8126 uint32_t *b; 8127 8128 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8129 __FUNCTION__, 8130 box->x1, box->y1, 8131 box->x2, box->y2, 8132 sx, sy, bx1, bx2)); 8133 8134 src_stride = bstride*bh; 8135 assert(src_stride > 0); 8136 if (src_stride <= 128) { 8137 src_stride = ALIGN(src_stride, 8) / 4; 8138 assert(src_stride <= 32); 8139 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 8140 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8141 !kgem_check_reloc(&sna->kgem, 1)) { 8142 kgem_submit(&sna->kgem); 8143 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8144 return; /* XXX fallback? */ 8145 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8146 } 8147 8148 assert(sna->kgem.mode == KGEM_BLT); 8149 if (sna->kgem.gen >= 0100) { 8150 b = sna->kgem.batch + sna->kgem.nbatch; 8151 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 8152 b[0] |= ((box->x1 + sx) & 7) << 17; 8153 b[1] = br13; 8154 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8155 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8156 *(uint64_t *)(b+4) = 8157 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8158 I915_GEM_DOMAIN_RENDER << 16 | 8159 I915_GEM_DOMAIN_RENDER | 8160 KGEM_RELOC_FENCED, 8161 0); 8162 b[5] = gc->bgPixel; 8163 b[6] = gc->fgPixel; 8164 8165 dst = (uint8_t *)&b[8]; 8166 sna->kgem.nbatch += 8 + src_stride; 8167 } else { 8168 b = sna->kgem.batch + sna->kgem.nbatch; 8169 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 8170 b[0] |= ((box->x1 + sx) & 7) << 17; 8171 b[1] = br13; 8172 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8173 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8174 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8175 I915_GEM_DOMAIN_RENDER << 16 | 8176 I915_GEM_DOMAIN_RENDER | 8177 KGEM_RELOC_FENCED, 8178 0); 8179 b[5] = gc->bgPixel; 8180 b[6] = gc->fgPixel; 8181 8182 dst = (uint8_t *)&b[7]; 8183 sna->kgem.nbatch += 7 + src_stride; 8184 } 8185 8186 assert(bitmap->devKind); 8187 src_stride = bitmap->devKind; 8188 src = bitmap->devPrivate.ptr; 8189 src += (box->y1 + sy) * src_stride + bx1/8; 8190 src_stride -= bstride; 8191 do { 8192 int i = bstride; 8193 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8194 do { 8195 *dst++ = byte_reverse(*src++); 8196 *dst++ = byte_reverse(*src++); 8197 i -= 2; 8198 } while (i); 8199 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8200 src += src_stride; 8201 } while (--bh); 8202 } else { 8203 struct kgem_bo *upload; 8204 void *ptr; 8205 8206 if (!kgem_check_batch(&sna->kgem, 10) || 8207 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8208 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8209 kgem_submit(&sna->kgem); 8210 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8211 return; /* XXX fallback? */ 8212 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8213 } 8214 8215 upload = kgem_create_buffer(&sna->kgem, 8216 bstride*bh, 8217 KGEM_BUFFER_WRITE_INPLACE, 8218 &ptr); 8219 if (!upload) 8220 break; 8221 8222 if (sigtrap_get() == 0) { 8223 assert(sna->kgem.mode == KGEM_BLT); 8224 b = sna->kgem.batch + sna->kgem.nbatch; 8225 if (sna->kgem.gen >= 0100) { 8226 b[0] = XY_MONO_SRC_COPY | br00 | 8; 8227 b[0] |= ((box->x1 + sx) & 7) << 17; 8228 b[1] = br13; 8229 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8230 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8231 *(uint64_t *)(b+4) = 8232 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8233 I915_GEM_DOMAIN_RENDER << 16 | 8234 I915_GEM_DOMAIN_RENDER | 8235 KGEM_RELOC_FENCED, 8236 0); 8237 *(uint64_t *)(b+6) = 8238 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8239 I915_GEM_DOMAIN_RENDER << 16 | 8240 KGEM_RELOC_FENCED, 8241 0); 8242 b[8] = gc->bgPixel; 8243 b[9] = gc->fgPixel; 8244 8245 sna->kgem.nbatch += 10; 8246 } else { 8247 b[0] = XY_MONO_SRC_COPY | br00 | 6; 8248 b[0] |= ((box->x1 + sx) & 7) << 17; 8249 b[1] = br13; 8250 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8251 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8252 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8253 I915_GEM_DOMAIN_RENDER << 16 | 8254 I915_GEM_DOMAIN_RENDER | 8255 KGEM_RELOC_FENCED, 8256 0); 8257 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8258 I915_GEM_DOMAIN_RENDER << 16 | 8259 KGEM_RELOC_FENCED, 8260 0); 8261 b[6] = gc->bgPixel; 8262 b[7] = gc->fgPixel; 8263 8264 sna->kgem.nbatch += 8; 8265 } 8266 8267 dst = ptr; 8268 assert(bitmap->devKind); 8269 src_stride = bitmap->devKind; 8270 src = bitmap->devPrivate.ptr; 8271 src += (box->y1 + sy) * src_stride + bx1/8; 8272 src_stride -= bstride; 8273 do { 8274 int i = bstride; 8275 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8276 do { 8277 *dst++ = byte_reverse(*src++); 8278 *dst++ = byte_reverse(*src++); 8279 i -= 2; 8280 } while (i); 8281 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8282 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 8283 src += src_stride; 8284 } while (--bh); 8285 8286 sigtrap_put(); 8287 } 8288 8289 kgem_bo_destroy(&sna->kgem, upload); 8290 } 8291 8292 box++; 8293 } while (--n); 8294 8295 if (arg->damage) { 8296 RegionTranslate(region, dx, dy); 8297 sna_damage_add(arg->damage, region); 8298 } 8299 assert_pixmap_damage(pixmap); 8300 sna->blt_state.fill_bo = 0; 8301} 8302 8303static void 8304sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, 8305 RegionPtr region, int sx, int sy, 8306 Pixel bitplane, void *closure) 8307{ 8308 PixmapPtr dst_pixmap = get_drawable_pixmap(drawable); 8309 PixmapPtr src_pixmap = get_drawable_pixmap(source); 8310 struct sna *sna = to_sna_from_pixmap(dst_pixmap); 8311 struct sna_copy_plane *arg = closure; 8312 int16_t dx, dy; 8313 int bit = ffs(bitplane) - 1; 8314 uint32_t br00, br13; 8315 const BoxRec *box = region_rects(region); 8316 int n = region_num_rects(region); 8317 8318 DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__, 8319 (unsigned)bitplane, bit, n)); 8320 8321 if (n == 0) 8322 return; 8323 8324 if (get_drawable_deltas(source, src_pixmap, &dx, &dy)) 8325 sx += dx, sy += dy; 8326 8327 get_drawable_deltas(drawable, dst_pixmap, &dx, &dy); 8328 assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy); 8329 8330 br00 = XY_MONO_SRC_COPY | 3 << 20; 8331 br13 = arg->bo->pitch; 8332 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8333 br00 |= BLT_DST_TILED; 8334 br13 >>= 2; 8335 } 8336 br13 |= blt_depth(drawable->depth) << 24; 8337 br13 |= copy_ROP[gc->alu] << 16; 8338 8339 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8340 do { 8341 int bx1 = (box->x1 + sx) & ~7; 8342 int bx2 = (box->x2 + sx + 7) & ~7; 8343 int bw = (bx2 - bx1)/8; 8344 int bh = box->y2 - box->y1; 8345 int bstride = ALIGN(bw, 2); 8346 struct kgem_bo *upload; 8347 void *ptr; 8348 8349 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8350 __FUNCTION__, 8351 box->x1, box->y1, 8352 box->x2, box->y2, 8353 sx, sy, bx1, bx2)); 8354 8355 if (!kgem_check_batch(&sna->kgem, 10) || 8356 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8357 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8358 kgem_submit(&sna->kgem); 8359 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8360 return; /* XXX fallback? */ 8361 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8362 } 8363 8364 upload = kgem_create_buffer(&sna->kgem, 8365 bstride*bh, 8366 KGEM_BUFFER_WRITE_INPLACE, 8367 &ptr); 8368 if (!upload) 8369 break; 8370 8371 if (sigtrap_get() == 0) { 8372 uint32_t *b; 8373 8374 assert(src_pixmap->devKind); 8375 switch (source->bitsPerPixel) { 8376 case 32: 8377 { 8378 uint32_t *src = src_pixmap->devPrivate.ptr; 8379 int src_stride = src_pixmap->devKind/sizeof(uint32_t); 8380 uint8_t *dst = ptr; 8381 8382 src += (box->y1 + sy) * src_stride; 8383 src += bx1; 8384 8385 src_stride -= bw * 8; 8386 bstride -= bw; 8387 8388 do { 8389 int i = bw; 8390 do { 8391 uint8_t v = 0; 8392 8393 v |= ((*src++ >> bit) & 1) << 7; 8394 v |= ((*src++ >> bit) & 1) << 6; 8395 v |= ((*src++ >> bit) & 1) << 5; 8396 v |= ((*src++ >> bit) & 1) << 4; 8397 v |= ((*src++ >> bit) & 1) << 3; 8398 v |= ((*src++ >> bit) & 1) << 2; 8399 v |= ((*src++ >> bit) & 1) << 1; 8400 v |= ((*src++ >> bit) & 1) << 0; 8401 8402 *dst++ = v; 8403 } while (--i); 8404 dst += bstride; 8405 src += src_stride; 8406 } while (--bh); 8407 break; 8408 } 8409 case 16: 8410 { 8411 uint16_t *src = src_pixmap->devPrivate.ptr; 8412 int src_stride = src_pixmap->devKind/sizeof(uint16_t); 8413 uint8_t *dst = ptr; 8414 8415 src += (box->y1 + sy) * src_stride; 8416 src += bx1; 8417 8418 src_stride -= bw * 8; 8419 bstride -= bw; 8420 8421 do { 8422 int i = bw; 8423 do { 8424 uint8_t v = 0; 8425 8426 v |= ((*src++ >> bit) & 1) << 7; 8427 v |= ((*src++ >> bit) & 1) << 6; 8428 v |= ((*src++ >> bit) & 1) << 5; 8429 v |= ((*src++ >> bit) & 1) << 4; 8430 v |= ((*src++ >> bit) & 1) << 3; 8431 v |= ((*src++ >> bit) & 1) << 2; 8432 v |= ((*src++ >> bit) & 1) << 1; 8433 v |= ((*src++ >> bit) & 1) << 0; 8434 8435 *dst++ = v; 8436 } while (--i); 8437 dst += bstride; 8438 src += src_stride; 8439 } while (--bh); 8440 break; 8441 } 8442 default: 8443 assert(0); 8444 case 8: 8445 { 8446 uint8_t *src = src_pixmap->devPrivate.ptr; 8447 int src_stride = src_pixmap->devKind/sizeof(uint8_t); 8448 uint8_t *dst = ptr; 8449 8450 src += (box->y1 + sy) * src_stride; 8451 src += bx1; 8452 8453 src_stride -= bw * 8; 8454 bstride -= bw; 8455 8456 do { 8457 int i = bw; 8458 do { 8459 uint8_t v = 0; 8460 8461 v |= ((*src++ >> bit) & 1) << 7; 8462 v |= ((*src++ >> bit) & 1) << 6; 8463 v |= ((*src++ >> bit) & 1) << 5; 8464 v |= ((*src++ >> bit) & 1) << 4; 8465 v |= ((*src++ >> bit) & 1) << 3; 8466 v |= ((*src++ >> bit) & 1) << 2; 8467 v |= ((*src++ >> bit) & 1) << 1; 8468 v |= ((*src++ >> bit) & 1) << 0; 8469 8470 *dst++ = v; 8471 } while (--i); 8472 dst += bstride; 8473 src += src_stride; 8474 } while (--bh); 8475 break; 8476 } 8477 } 8478 8479 assert(sna->kgem.mode == KGEM_BLT); 8480 b = sna->kgem.batch + sna->kgem.nbatch; 8481 if (sna->kgem.gen >= 0100) { 8482 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8; 8483 b[1] = br13; 8484 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8485 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8486 *(uint64_t *)(b+4) = 8487 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8488 I915_GEM_DOMAIN_RENDER << 16 | 8489 I915_GEM_DOMAIN_RENDER | 8490 KGEM_RELOC_FENCED, 8491 0); 8492 *(uint64_t *)(b+6) = 8493 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8494 I915_GEM_DOMAIN_RENDER << 16 | 8495 KGEM_RELOC_FENCED, 8496 0); 8497 b[8] = gc->bgPixel; 8498 b[9] = gc->fgPixel; 8499 8500 sna->kgem.nbatch += 10; 8501 } else { 8502 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6; 8503 b[1] = br13; 8504 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8505 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8506 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8507 I915_GEM_DOMAIN_RENDER << 16 | 8508 I915_GEM_DOMAIN_RENDER | 8509 KGEM_RELOC_FENCED, 8510 0); 8511 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8512 I915_GEM_DOMAIN_RENDER << 16 | 8513 KGEM_RELOC_FENCED, 8514 0); 8515 b[6] = gc->bgPixel; 8516 b[7] = gc->fgPixel; 8517 8518 sna->kgem.nbatch += 8; 8519 } 8520 sigtrap_put(); 8521 } 8522 kgem_bo_destroy(&sna->kgem, upload); 8523 8524 box++; 8525 } while (--n); 8526 8527 if (arg->damage) { 8528 RegionTranslate(region, dx, dy); 8529 sna_damage_add(arg->damage, region); 8530 } 8531 assert_pixmap_damage(dst_pixmap); 8532 sna->blt_state.fill_bo = 0; 8533} 8534 8535static RegionPtr 8536sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 8537 int src_x, int src_y, 8538 int w, int h, 8539 int dst_x, int dst_y, 8540 unsigned long bit) 8541{ 8542 PixmapPtr pixmap = get_drawable_pixmap(dst); 8543 struct sna *sna = to_sna_from_pixmap(pixmap); 8544 RegionRec region, *ret = NULL; 8545 struct sna_copy_plane arg; 8546 8547 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__, 8548 src_x, src_y, dst_x, dst_y, w, h)); 8549 8550 if (gc->planemask == 0) 8551 goto empty; 8552 8553 if (src->bitsPerPixel == 1 && (bit&1) == 0) 8554 goto empty; 8555 8556 region.extents.x1 = dst_x + dst->x; 8557 region.extents.y1 = dst_y + dst->y; 8558 region.extents.x2 = region.extents.x1 + w; 8559 region.extents.y2 = region.extents.y1 + h; 8560 region.data = NULL; 8561 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 8562 8563 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", 8564 __FUNCTION__, 8565 region.extents.x1, region.extents.y1, 8566 region.extents.x2, region.extents.y2)); 8567 8568 { 8569 RegionRec clip; 8570 8571 clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x); 8572 clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y); 8573 clip.extents.x2 = clip.extents.x1 + src->width; 8574 clip.extents.y2 = clip.extents.y1 + src->height; 8575 clip.data = NULL; 8576 8577 DBG(("%s: src extents (%d, %d), (%d, %d)\n", 8578 __FUNCTION__, 8579 clip.extents.x1, clip.extents.y1, 8580 clip.extents.x2, clip.extents.y2)); 8581 8582 RegionIntersect(®ion, ®ion, &clip); 8583 } 8584 DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n", 8585 __FUNCTION__, 8586 region.extents.x1, region.extents.y1, 8587 region.extents.x2, region.extents.y2)); 8588 if (box_empty(®ion.extents)) 8589 goto empty; 8590 8591 RegionTranslate(®ion, 8592 src_x - dst_x - dst->x + src->x, 8593 src_y - dst_y - dst->y + src->y); 8594 8595 if (!sna_drawable_move_region_to_cpu(src, ®ion, MOVE_READ)) 8596 goto out; 8597 8598 RegionTranslate(®ion, 8599 -(src_x - dst_x - dst->x + src->x), 8600 -(src_y - dst_y - dst->y + src->y)); 8601 8602 if (FORCE_FALLBACK) 8603 goto fallback; 8604 8605 if (!ACCEL_COPY_PLANE) 8606 goto fallback; 8607 8608 if (wedged(sna)) 8609 goto fallback; 8610 8611 if (!PM_IS_SOLID(dst, gc->planemask)) 8612 goto fallback; 8613 8614 arg.bo = sna_drawable_use_bo(dst, PREFER_GPU, 8615 ®ion.extents, &arg.damage); 8616 if (arg.bo) { 8617 if (arg.bo->tiling == I915_TILING_Y) { 8618 assert(arg.bo == __sna_pixmap_get_bo(pixmap)); 8619 arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 8620 if (arg.bo == NULL) { 8621 DBG(("%s: fallback -- unable to change tiling\n", 8622 __FUNCTION__)); 8623 goto fallback; 8624 } 8625 } 8626 RegionUninit(®ion); 8627 return sna_do_copy(src, dst, gc, 8628 src_x, src_y, 8629 w, h, 8630 dst_x, dst_y, 8631 src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt, 8632 (Pixel)bit, &arg); 8633 } 8634 8635fallback: 8636 DBG(("%s: fallback\n", __FUNCTION__)); 8637 if (!sna_gc_move_to_cpu(gc, dst, ®ion)) 8638 goto out; 8639 if (!sna_drawable_move_region_to_cpu(dst, ®ion, 8640 drawable_gc_flags(dst, gc, false))) 8641 goto out; 8642 8643 if (sigtrap_get() == 0) { 8644 DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n", 8645 __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit)); 8646 ret = miDoCopy(src, dst, gc, 8647 src_x, src_y, w, h, dst_x, dst_y, 8648 src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN, 8649 bit, 0); 8650 FALLBACK_FLUSH(dst); 8651 sigtrap_put(); 8652 } 8653out: 8654 sna_gc_move_to_gpu(gc); 8655 RegionUninit(®ion); 8656 return ret; 8657empty: 8658 return miHandleExposures(src, dst, gc, 8659 src_x, src_y, 8660 w, h, 8661 dst_x, dst_y, bit); 8662} 8663 8664static bool 8665sna_poly_point_blt(DrawablePtr drawable, 8666 struct kgem_bo *bo, 8667 struct sna_damage **damage, 8668 GCPtr gc, int mode, int n, DDXPointPtr pt, 8669 bool clipped) 8670{ 8671 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8672 struct sna *sna = to_sna_from_pixmap(pixmap); 8673 BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box); 8674 struct sna_fill_op fill; 8675 DDXPointRec last; 8676 int16_t dx, dy; 8677 8678 DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n", 8679 __FUNCTION__, gc->alu, gc->fgPixel, clipped)); 8680 8681 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS)) 8682 return false; 8683 8684 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8685 8686 last.x = drawable->x; 8687 last.y = drawable->y; 8688 8689 if (!clipped) { 8690 last.x += dx; 8691 last.y += dy; 8692 8693 assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y); 8694 sna_damage_add_points(damage, pt, n, last.x, last.y); 8695 if (fill.points && mode != CoordModePrevious) { 8696 fill.points(sna, &fill, last.x, last.y, pt, n); 8697 } else { 8698 do { 8699 unsigned nbox = n; 8700 if (nbox > ARRAY_SIZE(box)) 8701 nbox = ARRAY_SIZE(box); 8702 n -= nbox; 8703 do { 8704 *(DDXPointRec *)b = *pt++; 8705 8706 b->x1 += last.x; 8707 b->y1 += last.y; 8708 if (mode == CoordModePrevious) 8709 last = *(DDXPointRec *)b; 8710 8711 b->x2 = b->x1 + 1; 8712 b->y2 = b->y1 + 1; 8713 b++; 8714 } while (--nbox); 8715 fill.boxes(sna, &fill, box, b - box); 8716 b = box; 8717 } while (n); 8718 } 8719 } else { 8720 RegionPtr clip = gc->pCompositeClip; 8721 8722 while (n--) { 8723 int x, y; 8724 8725 x = pt->x; 8726 y = pt->y; 8727 pt++; 8728 if (mode == CoordModePrevious) { 8729 x += last.x; 8730 y += last.y; 8731 last.x = x; 8732 last.y = y; 8733 } else { 8734 x += drawable->x; 8735 y += drawable->y; 8736 } 8737 8738 if (RegionContainsPoint(clip, x, y, NULL)) { 8739 b->x1 = x + dx; 8740 b->y1 = y + dy; 8741 b->x2 = b->x1 + 1; 8742 b->y2 = b->y1 + 1; 8743 if (++b == last_box){ 8744 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 8745 fill.boxes(sna, &fill, box, last_box - box); 8746 if (damage) 8747 sna_damage_add_boxes(damage, box, last_box-box, 0, 0); 8748 b = box; 8749 } 8750 } 8751 } 8752 if (b != box){ 8753 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 8754 fill.boxes(sna, &fill, box, b - box); 8755 if (damage) 8756 sna_damage_add_boxes(damage, box, b-box, 0, 0); 8757 } 8758 } 8759 fill.done(sna, &fill); 8760 assert_pixmap_damage(pixmap); 8761 return true; 8762} 8763 8764static unsigned 8765sna_poly_point_extents(DrawablePtr drawable, GCPtr gc, 8766 int mode, int n, DDXPointPtr pt, BoxPtr out) 8767{ 8768 BoxRec box; 8769 bool clipped; 8770 8771 if (n == 0) 8772 return 0; 8773 8774 box.x2 = box.x1 = pt->x; 8775 box.y2 = box.y1 = pt->y; 8776 if (mode == CoordModePrevious) { 8777 DDXPointRec last = *pt++; 8778 while (--n) { 8779 last.x += pt->x; 8780 last.y += pt->y; 8781 pt++; 8782 box_add_pt(&box, last.x, last.y); 8783 } 8784 } else { 8785 --n; ++pt; 8786 while (n >= 8) { 8787 box_add_pt(&box, pt[0].x, pt[0].y); 8788 box_add_pt(&box, pt[1].x, pt[1].y); 8789 box_add_pt(&box, pt[2].x, pt[2].y); 8790 box_add_pt(&box, pt[3].x, pt[3].y); 8791 box_add_pt(&box, pt[4].x, pt[4].y); 8792 box_add_pt(&box, pt[5].x, pt[5].y); 8793 box_add_pt(&box, pt[6].x, pt[6].y); 8794 box_add_pt(&box, pt[7].x, pt[7].y); 8795 pt += 8; 8796 n -= 8; 8797 } 8798 if (n & 4) { 8799 box_add_pt(&box, pt[0].x, pt[0].y); 8800 box_add_pt(&box, pt[1].x, pt[1].y); 8801 box_add_pt(&box, pt[2].x, pt[2].y); 8802 box_add_pt(&box, pt[3].x, pt[3].y); 8803 pt += 4; 8804 } 8805 if (n & 2) { 8806 box_add_pt(&box, pt[0].x, pt[0].y); 8807 box_add_pt(&box, pt[1].x, pt[1].y); 8808 pt += 2; 8809 } 8810 if (n & 1) 8811 box_add_pt(&box, pt[0].x, pt[0].y); 8812 } 8813 box.x2++; 8814 box.y2++; 8815 8816 clipped = trim_and_translate_box(&box, drawable, gc); 8817 if (box_empty(&box)) 8818 return 0; 8819 8820 *out = box; 8821 return 1 | clipped << 1; 8822} 8823 8824static void 8825sna_poly_point(DrawablePtr drawable, GCPtr gc, 8826 int mode, int n, DDXPointPtr pt) 8827{ 8828 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8829 struct sna *sna = to_sna_from_pixmap(pixmap); 8830 RegionRec region; 8831 unsigned flags; 8832 8833 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n", 8834 __FUNCTION__, mode, n, pt[0].x, pt[0].y)); 8835 8836 flags = sna_poly_point_extents(drawable, gc, mode, n, pt, ®ion.extents); 8837 if (flags == 0) 8838 return; 8839 8840 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 8841 region.extents.x1, region.extents.y1, 8842 region.extents.x2, region.extents.y2, 8843 flags)); 8844 8845 if (FORCE_FALLBACK) 8846 goto fallback; 8847 8848 if (!ACCEL_POLY_POINT) 8849 goto fallback; 8850 8851 if (wedged(sna)) { 8852 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8853 goto fallback; 8854 } 8855 8856 if (PM_IS_SOLID(drawable, gc->planemask)) { 8857 struct sna_damage **damage; 8858 struct kgem_bo *bo; 8859 8860 DBG(("%s: trying solid fill [%08lx] blt paths\n", 8861 __FUNCTION__, gc->fgPixel)); 8862 8863 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8864 ®ion.extents, &damage)) && 8865 sna_poly_point_blt(drawable, bo, damage, 8866 gc, mode, n, pt, flags & 2)) 8867 return; 8868 } 8869 8870fallback: 8871 DBG(("%s: fallback\n", __FUNCTION__)); 8872 region.data = NULL; 8873 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8874 return; 8875 8876 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8877 goto out; 8878 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8879 MOVE_READ | MOVE_WRITE)) 8880 goto out; 8881 8882 if (sigtrap_get() == 0) { 8883 DBG(("%s: fbPolyPoint\n", __FUNCTION__)); 8884 fbPolyPoint(drawable, gc, mode, n, pt, flags); 8885 FALLBACK_FLUSH(drawable); 8886 sigtrap_put(); 8887 } 8888out: 8889 sna_gc_move_to_gpu(gc); 8890 RegionUninit(®ion); 8891} 8892 8893static bool 8894sna_poly_zero_line_blt(DrawablePtr drawable, 8895 struct kgem_bo *bo, 8896 struct sna_damage **damage, 8897 GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt, 8898 const BoxRec *extents, unsigned clipped) 8899{ 8900 static void * const _jump[] = { 8901 &&no_damage, 8902 &&damage, 8903 8904 &&no_damage_offset, 8905 &&damage_offset, 8906 }; 8907 8908 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8909 struct sna *sna = to_sna_from_pixmap(pixmap); 8910 int x2, y2, xstart, ystart, oc2; 8911 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 8912 bool degenerate = true; 8913 struct sna_fill_op fill; 8914 RegionRec clip; 8915 BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box); 8916 const BoxRec *last_extents; 8917 int16_t dx, dy; 8918 void *jump, *ret; 8919 8920 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 8921 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 8922 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS)) 8923 return false; 8924 8925 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8926 8927 region_set(&clip, extents); 8928 if (clipped) { 8929 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 8930 return true; 8931 } 8932 8933 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 8934 DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n", 8935 __FUNCTION__, clipped, 8936 clip.extents.x1, clip.extents.y1, 8937 clip.extents.x2, clip.extents.y2, 8938 dx, dy, damage)); 8939 8940 extents = region_rects(&clip); 8941 last_extents = extents + region_num_rects(&clip); 8942 8943 b = box; 8944 do { 8945 int n = _n; 8946 const DDXPointRec *pt = _pt; 8947 8948 xstart = pt->x + drawable->x; 8949 ystart = pt->y + drawable->y; 8950 8951 x2 = xstart; 8952 y2 = ystart; 8953 oc2 = 0; 8954 OUTCODES(oc2, x2, y2, extents); 8955 8956 while (--n) { 8957 int16_t sdx, sdy; 8958 int adx, ady, length; 8959 int e, e1, e2, e3; 8960 int x1 = x2, x; 8961 int y1 = y2, y; 8962 int oc1 = oc2; 8963 int octant; 8964 8965 ++pt; 8966 8967 x2 = pt->x; 8968 y2 = pt->y; 8969 if (mode == CoordModePrevious) { 8970 x2 += x1; 8971 y2 += y1; 8972 } else { 8973 x2 += drawable->x; 8974 y2 += drawable->y; 8975 } 8976 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 8977 __FUNCTION__, x1, y1, x2, y2)); 8978 if (x2 == x1 && y2 == y1) 8979 continue; 8980 8981 degenerate = false; 8982 8983 oc2 = 0; 8984 OUTCODES(oc2, x2, y2, extents); 8985 if (oc1 & oc2) 8986 continue; 8987 8988 CalcLineDeltas(x1, y1, x2, y2, 8989 adx, ady, sdx, sdy, 8990 1, 1, octant); 8991 8992 DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n", 8993 __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2)); 8994 if (adx == 0 || ady == 0) { 8995 if (x1 <= x2) { 8996 b->x1 = x1; 8997 b->x2 = x2; 8998 } else { 8999 b->x1 = x2; 9000 b->x2 = x1; 9001 } 9002 if (y1 <= y2) { 9003 b->y1 = y1; 9004 b->y2 = y2; 9005 } else { 9006 b->y1 = y2; 9007 b->y2 = y1; 9008 } 9009 b->x2++; 9010 b->y2++; 9011 if (oc1 | oc2) { 9012 bool intersects; 9013 9014 intersects = box_intersect(b, extents); 9015 assert(intersects); 9016 } 9017 if (++b == last_box) { 9018 ret = &&rectangle_continue; 9019 goto *jump; 9020rectangle_continue: 9021 b = box; 9022 } 9023 } else if (adx >= ady) { 9024 int x2_clipped = x2, y2_clipped = y2; 9025 bool dirty; 9026 9027 /* X-major segment */ 9028 e1 = ady << 1; 9029 e2 = e1 - (adx << 1); 9030 e = e1 - adx; 9031 length = adx; 9032 9033 FIXUP_ERROR(e, octant, bias); 9034 9035 x = x1; 9036 y = y1; 9037 9038 if (oc1 | oc2) { 9039 int pt1_clipped, pt2_clipped; 9040 9041 if (miZeroClipLine(extents->x1, extents->y1, 9042 extents->x2-1, extents->y2-1, 9043 &x, &y, &x2_clipped, &y2_clipped, 9044 adx, ady, 9045 &pt1_clipped, &pt2_clipped, 9046 octant, bias, oc1, oc2) == -1) 9047 continue; 9048 9049 length = abs(x2_clipped - x); 9050 if (length == 0) 9051 continue; 9052 9053 if (pt1_clipped) { 9054 int clipdx = abs(x - x1); 9055 int clipdy = abs(y - y1); 9056 e += clipdy * e2 + (clipdx - clipdy) * e1; 9057 } 9058 } 9059 9060 e3 = e2 - e1; 9061 e = e - e1; 9062 9063 b->x1 = x; 9064 b->y1 = y; 9065 dirty = false; 9066 while (length--) { 9067 e += e1; 9068 dirty = true; 9069 if (e >= 0) { 9070 e += e3; 9071 9072 if (sdx < 0) { 9073 b->x2 = b->x1 + 1; 9074 b->x1 = x; 9075 } else 9076 b->x2 = x + 1; 9077 b->y2 = b->y1 + 1; 9078 9079 if (++b == last_box) { 9080 ret = &&X_continue; 9081 goto *jump; 9082X_continue: 9083 b = box; 9084 } 9085 9086 b->x1 = x + sdx; 9087 b->y1 = y += sdy; 9088 dirty = false; 9089 } 9090 x += sdx; 9091 } 9092 if (dirty) { 9093 x -= sdx; 9094 if (sdx < 0) { 9095 b->x2 = b->x1 + 1; 9096 b->x1 = x; 9097 } else 9098 b->x2 = x + 1; 9099 b->y2 = b->y1 + 1; 9100 9101 if (++b == last_box) { 9102 ret = &&X2_continue; 9103 goto *jump; 9104X2_continue: 9105 b = box; 9106 } 9107 } 9108 } else { 9109 int x2_clipped = x2, y2_clipped = y2; 9110 bool dirty; 9111 9112 /* Y-major segment */ 9113 e1 = adx << 1; 9114 e2 = e1 - (ady << 1); 9115 e = e1 - ady; 9116 length = ady; 9117 9118 SetYMajorOctant(octant); 9119 FIXUP_ERROR(e, octant, bias); 9120 9121 x = x1; 9122 y = y1; 9123 9124 if (oc1 | oc2) { 9125 int pt1_clipped, pt2_clipped; 9126 9127 if (miZeroClipLine(extents->x1, extents->y1, 9128 extents->x2-1, extents->y2-1, 9129 &x, &y, &x2_clipped, &y2_clipped, 9130 adx, ady, 9131 &pt1_clipped, &pt2_clipped, 9132 octant, bias, oc1, oc2) == -1) 9133 continue; 9134 9135 length = abs(y2_clipped - y); 9136 if (length == 0) 9137 continue; 9138 9139 if (pt1_clipped) { 9140 int clipdx = abs(x - x1); 9141 int clipdy = abs(y - y1); 9142 e += clipdx * e2 + (clipdy - clipdx) * e1; 9143 } 9144 } 9145 9146 e3 = e2 - e1; 9147 e = e - e1; 9148 9149 b->x1 = x; 9150 b->y1 = y; 9151 dirty = false; 9152 while (length--) { 9153 e += e1; 9154 dirty = true; 9155 if (e >= 0) { 9156 e += e3; 9157 9158 if (sdy < 0) { 9159 b->y2 = b->y1 + 1; 9160 b->y1 = y; 9161 } else 9162 b->y2 = y + 1; 9163 b->x2 = x + 1; 9164 9165 if (++b == last_box) { 9166 ret = &&Y_continue; 9167 goto *jump; 9168Y_continue: 9169 b = box; 9170 } 9171 9172 b->x1 = x += sdx; 9173 b->y1 = y + sdy; 9174 dirty = false; 9175 } 9176 y += sdy; 9177 } 9178 9179 if (dirty) { 9180 y -= sdy; 9181 if (sdy < 0) { 9182 b->y2 = b->y1 + 1; 9183 b->y1 = y; 9184 } else 9185 b->y2 = y + 1; 9186 b->x2 = x + 1; 9187 9188 if (++b == last_box) { 9189 ret = &&Y2_continue; 9190 goto *jump; 9191Y2_continue: 9192 b = box; 9193 } 9194 } 9195 } 9196 } 9197 9198#if 0 9199 /* Only do the CapNotLast check on the last segment 9200 * and only if the endpoint wasn't clipped. And then, if the last 9201 * point is the same as the first point, do not draw it, unless the 9202 * line is degenerate 9203 */ 9204 if (!pt2_clipped && 9205 gc->capStyle != CapNotLast && 9206 !(xstart == x2 && ystart == y2 && !degenerate)) 9207 { 9208 b->x2 = x2; 9209 b->y2 = y2; 9210 if (b->x2 < b->x1) { 9211 int16_t t = b->x1; 9212 b->x1 = b->x2; 9213 b->x2 = t; 9214 } 9215 if (b->y2 < b->y1) { 9216 int16_t t = b->y1; 9217 b->y1 = b->y2; 9218 b->y2 = t; 9219 } 9220 b->x2++; 9221 b->y2++; 9222 b++; 9223 } 9224#endif 9225 } while (++extents != last_extents); 9226 9227 if (b != box) { 9228 ret = &&done; 9229 goto *jump; 9230 } 9231 9232done: 9233 fill.done(sna, &fill); 9234 assert_pixmap_damage(pixmap); 9235 RegionUninit(&clip); 9236 return true; 9237 9238damage: 9239 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9240 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9241no_damage: 9242 fill.boxes(sna, &fill, box, b-box); 9243 goto *ret; 9244 9245no_damage_offset: 9246 { 9247 BoxRec *bb = box; 9248 do { 9249 bb->x1 += dx; 9250 bb->x2 += dx; 9251 bb->y1 += dy; 9252 bb->y2 += dy; 9253 } while (++bb != b); 9254 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9255 fill.boxes(sna, &fill, box, b - box); 9256 } 9257 goto *ret; 9258 9259damage_offset: 9260 { 9261 BoxRec *bb = box; 9262 do { 9263 bb->x1 += dx; 9264 bb->x2 += dx; 9265 bb->y1 += dy; 9266 bb->y2 += dy; 9267 } while (++bb != b); 9268 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9269 fill.boxes(sna, &fill, box, b - box); 9270 sna_damage_add_boxes(damage, box, b - box, 0, 0); 9271 } 9272 goto *ret; 9273} 9274 9275static bool 9276sna_poly_line_blt(DrawablePtr drawable, 9277 struct kgem_bo *bo, 9278 struct sna_damage **damage, 9279 GCPtr gc, uint32_t pixel, 9280 int mode, int n, DDXPointPtr pt, 9281 const BoxRec *extents, bool clipped) 9282{ 9283 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9284 struct sna *sna = to_sna_from_pixmap(pixmap); 9285 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 9286 struct sna_fill_op fill; 9287 DDXPointRec last; 9288 int16_t dx, dy; 9289 9290 DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped)); 9291 9292 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) 9293 return false; 9294 9295 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9296 9297 if (!clipped) { 9298 dx += drawable->x; 9299 dy += drawable->y; 9300 9301 last.x = pt->x + dx; 9302 last.y = pt->y + dy; 9303 pt++; 9304 9305 while (--n) { 9306 DDXPointRec p; 9307 9308 p = *pt++; 9309 if (mode == CoordModePrevious) { 9310 p.x += last.x; 9311 p.y += last.y; 9312 } else { 9313 p.x += dx; 9314 p.y += dy; 9315 } 9316 DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y)); 9317 9318 if (last.x == p.x) { 9319 b->x1 = last.x; 9320 b->x2 = last.x + 1; 9321 } else if (last.x < p.x) { 9322 b->x1 = last.x; 9323 b->x2 = p.x; 9324 } else { 9325 b->x1 = p.x; 9326 b->x2 = last.x; 9327 } 9328 9329 if (last.y == p.y) { 9330 b->y1 = last.y; 9331 b->y2 = last.y + 1; 9332 } else if (last.y < p.y) { 9333 b->y1 = last.y; 9334 b->y2 = p.y; 9335 } else { 9336 b->y1 = p.y; 9337 b->y2 = last.y; 9338 } 9339 b->y2 += last.x == p.x && last.y != p.y; 9340 b->x2 += last.y == p.y && last.x != p.x; 9341 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9342 __FUNCTION__, 9343 b->x1, b->y1, b->x2, b->y2)); 9344 9345 if (++b == last_box) { 9346 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9347 fill.boxes(sna, &fill, boxes, last_box - boxes); 9348 if (damage) 9349 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9350 b = boxes; 9351 } 9352 9353 last = p; 9354 } 9355 } else { 9356 RegionRec clip; 9357 9358 region_set(&clip, extents); 9359 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9360 return true; 9361 9362 last.x = pt->x + drawable->x; 9363 last.y = pt->y + drawable->y; 9364 pt++; 9365 9366 if (clip.data == NULL) { 9367 while (--n) { 9368 DDXPointRec p; 9369 9370 p = *pt++; 9371 if (mode == CoordModePrevious) { 9372 p.x += last.x; 9373 p.y += last.y; 9374 } else { 9375 p.x += drawable->x; 9376 p.y += drawable->y; 9377 } 9378 if (last.x == p.x) { 9379 b->x1 = last.x; 9380 b->x2 = last.x + 1; 9381 } else if (last.x < p.x) { 9382 b->x1 = last.x; 9383 b->x2 = p.x; 9384 } else { 9385 b->x1 = p.x; 9386 b->x2 = last.x; 9387 } 9388 if (last.y == p.y) { 9389 b->y1 = last.y; 9390 b->y2 = last.y + 1; 9391 } else if (last.y < p.y) { 9392 b->y1 = last.y; 9393 b->y2 = p.y; 9394 } else { 9395 b->y1 = p.y; 9396 b->y2 = last.y; 9397 } 9398 b->y2 += last.x == p.x && last.y != p.y; 9399 b->x2 += last.y == p.y && last.x != p.x; 9400 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9401 __FUNCTION__, 9402 b->x1, b->y1, b->x2, b->y2)); 9403 if (box_intersect(b, &clip.extents)) { 9404 b->x1 += dx; 9405 b->x2 += dx; 9406 b->y1 += dy; 9407 b->y2 += dy; 9408 if (++b == last_box) { 9409 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9410 fill.boxes(sna, &fill, boxes, last_box - boxes); 9411 if (damage) 9412 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9413 b = boxes; 9414 } 9415 } 9416 9417 last = p; 9418 } 9419 } else { 9420 const BoxRec * const clip_start = RegionBoxptr(&clip); 9421 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9422 const BoxRec *c; 9423 9424 while (--n) { 9425 DDXPointRec p; 9426 BoxRec box; 9427 9428 p = *pt++; 9429 if (mode == CoordModePrevious) { 9430 p.x += last.x; 9431 p.y += last.y; 9432 } else { 9433 p.x += drawable->x; 9434 p.y += drawable->y; 9435 } 9436 if (last.x == p.x) { 9437 box.x1 = last.x; 9438 box.x2 = last.x + 1; 9439 } else if (last.x < p.x) { 9440 box.x1 = last.x; 9441 box.x2 = p.x; 9442 } else { 9443 box.x1 = p.x; 9444 box.x2 = last.x; 9445 } 9446 if (last.y == p.y) { 9447 box.y1 = last.y; 9448 box.y2 = last.y + 1; 9449 } else if (last.y < p.y) { 9450 box.y1 = last.y; 9451 box.y2 = p.y; 9452 } else { 9453 box.y1 = p.y; 9454 box.y2 = last.y; 9455 } 9456 b->y2 += last.x == p.x && last.y != p.y; 9457 b->x2 += last.y == p.y && last.x != p.x; 9458 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9459 __FUNCTION__, 9460 box.x1, box.y1, box.x2, box.y2)); 9461 9462 c = find_clip_box_for_y(clip_start, 9463 clip_end, 9464 box.y1); 9465 while (c != clip_end) { 9466 if (box.y2 <= c->y1) 9467 break; 9468 9469 *b = box; 9470 if (box_intersect(b, c++)) { 9471 b->x1 += dx; 9472 b->x2 += dx; 9473 b->y1 += dy; 9474 b->y2 += dy; 9475 if (++b == last_box) { 9476 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9477 fill.boxes(sna, &fill, boxes, last_box-boxes); 9478 if (damage) 9479 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9480 b = boxes; 9481 } 9482 } 9483 } 9484 9485 last = p; 9486 } 9487 } 9488 RegionUninit(&clip); 9489 } 9490 if (b != boxes) { 9491 assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0); 9492 fill.boxes(sna, &fill, boxes, b - boxes); 9493 if (damage) 9494 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 9495 } 9496 fill.done(sna, &fill); 9497 assert_pixmap_damage(pixmap); 9498 return true; 9499} 9500 9501static unsigned 9502sna_poly_line_extents(DrawablePtr drawable, GCPtr gc, 9503 int mode, int n, DDXPointPtr pt, 9504 BoxPtr out) 9505{ 9506 BoxRec box; 9507 bool clip, blt = true; 9508 9509 if (n == 0) 9510 return 0; 9511 9512 box.x2 = box.x1 = pt->x; 9513 box.y2 = box.y1 = pt->y; 9514 if (mode == CoordModePrevious) { 9515 int x = box.x1; 9516 int y = box.y1; 9517 while (--n) { 9518 pt++; 9519 x += pt->x; 9520 y += pt->y; 9521 if (blt) 9522 blt &= pt->x == 0 || pt->y == 0; 9523 box_add_pt(&box, x, y); 9524 } 9525 } else { 9526 int x = box.x1; 9527 int y = box.y1; 9528 while (--n) { 9529 pt++; 9530 if (blt) { 9531 blt &= pt->x == x || pt->y == y; 9532 x = pt->x; 9533 y = pt->y; 9534 } 9535 box_add_pt(&box, pt->x, pt->y); 9536 } 9537 } 9538 box.x2++; 9539 box.y2++; 9540 9541 if (gc->lineWidth) { 9542 int extra = gc->lineWidth >> 1; 9543 if (n > 1) { 9544 if (gc->joinStyle == JoinMiter) 9545 extra = 6 * gc->lineWidth; 9546 else if (gc->capStyle == CapProjecting) 9547 extra = gc->lineWidth; 9548 } 9549 if (extra) { 9550 box.x1 -= extra; 9551 box.x2 += extra; 9552 box.y1 -= extra; 9553 box.y2 += extra; 9554 } 9555 } 9556 9557 clip = trim_and_translate_box(&box, drawable, gc); 9558 if (box_empty(&box)) 9559 return 0; 9560 9561 *out = box; 9562 return 1 | blt << 2 | clip << 1; 9563} 9564 9565/* Only use our spans code if the destination is busy and we can't perform 9566 * the operation in place. 9567 * 9568 * Currently it looks to be faster to use the GPU for zero spans on all 9569 * platforms. 9570 */ 9571inline static int 9572_use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 9573{ 9574 if (USE_ZERO_SPANS) 9575 return USE_ZERO_SPANS > 0; 9576 9577 return !drawable_gc_inplace_hint(drawable, gc); 9578} 9579 9580static int 9581use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 9582{ 9583 bool ret = _use_zero_spans(drawable, gc, extents); 9584 DBG(("%s? %d\n", __FUNCTION__, ret)); 9585 return ret; 9586} 9587 9588/* Only use our spans code if the destination is busy and we can't perform 9589 * the operation in place. 9590 * 9591 * Currently it looks to be faster to use the CPU for wide spans on all 9592 * platforms, slow MI code. But that does not take into account the true 9593 * cost of readback? 9594 */ 9595inline static int 9596_use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 9597{ 9598 if (USE_WIDE_SPANS) 9599 return USE_WIDE_SPANS > 0; 9600 9601 return !drawable_gc_inplace_hint(drawable, gc); 9602} 9603 9604static int 9605use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 9606{ 9607 int ret = _use_wide_spans(drawable, gc, extents); 9608 DBG(("%s? %d\n", __FUNCTION__, ret)); 9609 return ret; 9610} 9611 9612static void 9613sna_poly_line(DrawablePtr drawable, GCPtr gc, 9614 int mode, int n, DDXPointPtr pt) 9615{ 9616 struct sna_pixmap *priv; 9617 struct sna_fill_spans data; 9618 uint32_t color; 9619 9620 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n", 9621 __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth)); 9622 9623 data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt, 9624 &data.region.extents); 9625 if (data.flags == 0) 9626 return; 9627 9628 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9629 data.region.extents.x1, data.region.extents.y1, 9630 data.region.extents.x2, data.region.extents.y2, 9631 data.flags)); 9632 9633 data.region.data = NULL; 9634 9635 if (FORCE_FALLBACK) 9636 goto fallback; 9637 9638 if (!ACCEL_POLY_LINE) 9639 goto fallback; 9640 9641 data.pixmap = get_drawable_pixmap(drawable); 9642 data.sna = to_sna_from_pixmap(data.pixmap); 9643 if (wedged(data.sna)) { 9644 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9645 goto fallback; 9646 } 9647 9648 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n", 9649 __FUNCTION__, 9650 gc->fillStyle, gc->fillStyle == FillSolid, 9651 gc->lineStyle, gc->lineStyle == LineSolid, 9652 gc->lineWidth, 9653 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 9654 data.flags & 4)); 9655 9656 if (!PM_IS_SOLID(drawable, gc->planemask)) 9657 goto fallback; 9658 9659 priv = sna_pixmap(data.pixmap); 9660 if (!priv) { 9661 DBG(("%s: not attached to pixmap %ld\n", 9662 __FUNCTION__, data.pixmap->drawable.serialNumber)); 9663 goto fallback; 9664 } 9665 9666 if (gc->lineStyle != LineSolid) { 9667 DBG(("%s: lineStyle, %d, is not solid\n", 9668 __FUNCTION__, gc->lineStyle)); 9669 goto spans_fallback; 9670 } 9671 if (!(gc->lineWidth == 0 || 9672 (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) { 9673 DBG(("%s: non-zero lineWidth %d\n", 9674 __FUNCTION__, gc->lineWidth)); 9675 goto spans_fallback; 9676 } 9677 9678 if (gc_is_solid(gc, &color)) { 9679 DBG(("%s: trying solid fill [%08x]\n", 9680 __FUNCTION__, (unsigned)color)); 9681 9682 if (data.flags & 4) { 9683 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9684 &data.region.extents, 9685 &data.damage); 9686 if (data.bo && 9687 sna_poly_line_blt(drawable, 9688 data.bo, data.damage, 9689 gc, color, mode, n, pt, 9690 &data.region.extents, 9691 data.flags & 2)) 9692 return; 9693 } else { /* !rectilinear */ 9694 if ((data.bo = sna_drawable_use_bo(drawable, 9695 use_zero_spans(drawable, gc, &data.region.extents), 9696 &data.region.extents, 9697 &data.damage)) && 9698 sna_poly_zero_line_blt(drawable, 9699 data.bo, data.damage, 9700 gc, mode, n, pt, 9701 &data.region.extents, 9702 data.flags & 2)) 9703 return; 9704 9705 } 9706 } else if (data.flags & 4) { 9707 /* Try converting these to a set of rectangles instead */ 9708 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9709 &data.region.extents, &data.damage); 9710 if (data.bo) { 9711 DDXPointRec p1, p2; 9712 xRectangle *rect; 9713 int i; 9714 9715 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 9716 9717 rect = malloc (n * sizeof (xRectangle)); 9718 if (rect == NULL) 9719 return; 9720 9721 p1 = pt[0]; 9722 for (i = 1; i < n; i++) { 9723 if (mode == CoordModePrevious) { 9724 p2.x = p1.x + pt[i].x; 9725 p2.y = p1.y + pt[i].y; 9726 } else 9727 p2 = pt[i]; 9728 if (p1.x < p2.x) { 9729 rect[i].x = p1.x; 9730 rect[i].width = p2.x - p1.x + 1; 9731 } else if (p1.x > p2.x) { 9732 rect[i].x = p2.x; 9733 rect[i].width = p1.x - p2.x + 1; 9734 } else { 9735 rect[i].x = p1.x; 9736 rect[i].width = 1; 9737 } 9738 if (p1.y < p2.y) { 9739 rect[i].y = p1.y; 9740 rect[i].height = p2.y - p1.y + 1; 9741 } else if (p1.y > p2.y) { 9742 rect[i].y = p2.y; 9743 rect[i].height = p1.y - p2.y + 1; 9744 } else { 9745 rect[i].y = p1.y; 9746 rect[i].height = 1; 9747 } 9748 9749 /* don't paint last pixel */ 9750 if (gc->capStyle == CapNotLast) { 9751 if (p1.x == p2.x) 9752 rect[i].height--; 9753 else 9754 rect[i].width--; 9755 } 9756 p1 = p2; 9757 } 9758 9759 if (gc->fillStyle == FillTiled) { 9760 i = sna_poly_fill_rect_tiled_blt(drawable, 9761 data.bo, data.damage, 9762 gc, n - 1, rect + 1, 9763 &data.region.extents, 9764 data.flags & 2); 9765 } else { 9766 i = sna_poly_fill_rect_stippled_blt(drawable, 9767 data.bo, data.damage, 9768 gc, n - 1, rect + 1, 9769 &data.region.extents, 9770 data.flags & 2); 9771 } 9772 free (rect); 9773 9774 if (i) 9775 return; 9776 } 9777 } 9778 9779spans_fallback: 9780 if ((data.bo = sna_drawable_use_bo(drawable, 9781 use_wide_spans(drawable, gc, &data.region.extents), 9782 &data.region.extents, &data.damage))) { 9783 DBG(("%s: converting line into spans\n", __FUNCTION__)); 9784 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 9785 sna_gc(gc)->priv = &data; 9786 9787 if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) { 9788 struct sna_fill_op fill; 9789 9790 if (gc->lineStyle == LineSolid) { 9791 if (!sna_fill_init_blt(&fill, 9792 data.sna, data.pixmap, 9793 data.bo, gc->alu, color, 9794 FILL_POINTS | FILL_SPANS)) 9795 goto fallback; 9796 9797 data.op = &fill; 9798 9799 if ((data.flags & 2) == 0) { 9800 if (data.dx | data.dy) 9801 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 9802 else 9803 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 9804 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 9805 } else { 9806 if (!region_maybe_clip(&data.region, 9807 gc->pCompositeClip)) 9808 return; 9809 9810 if (region_is_singular(&data.region)) { 9811 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 9812 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 9813 } else { 9814 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 9815 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 9816 } 9817 } 9818 assert(gc->miTranslate); 9819 9820 gc->ops = &sna_gc_ops__tmp; 9821 DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__)); 9822 miZeroLine(drawable, gc, mode, n, pt); 9823 fill.done(data.sna, &fill); 9824 } else { 9825 data.op = &fill; 9826 9827 if ((data.flags & 2) == 0) { 9828 if (data.dx | data.dy) 9829 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset; 9830 else 9831 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash; 9832 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash; 9833 } else { 9834 if (!region_maybe_clip(&data.region, 9835 gc->pCompositeClip)) 9836 return; 9837 9838 if (region_is_singular(&data.region)) { 9839 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents; 9840 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents; 9841 } else { 9842 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes; 9843 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes; 9844 } 9845 } 9846 assert(gc->miTranslate); 9847 9848 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n", 9849 __FUNCTION__, 9850 !!(data.flags & 2), data.flags & 2 && !region_is_singular(&data.region), 9851 gc->fgPixel)); 9852 9853 if (!sna_fill_init_blt(&fill, 9854 data.sna, data.pixmap, 9855 data.bo, gc->alu, color, 9856 FILL_POINTS | FILL_SPANS)) 9857 goto fallback; 9858 9859 gc->ops = &sna_gc_ops__tmp; 9860 data.phase = gc->fgPixel; 9861 miZeroDashLine(drawable, gc, mode, n, pt); 9862 fill.done(data.sna, &fill); 9863 9864 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n", 9865 __FUNCTION__, 9866 !!(data.flags & 2), data.flags & 2 && !region_is_singular(&data.region), 9867 gc->bgPixel)); 9868 9869 if (sna_fill_init_blt(&fill, 9870 data.sna, data.pixmap, 9871 data.bo, gc->alu, 9872 gc->bgPixel, 9873 FILL_POINTS | FILL_SPANS)) { 9874 data.phase = gc->bgPixel; 9875 miZeroDashLine(drawable, gc, mode, n, pt); 9876 fill.done(data.sna, &fill); 9877 } 9878 } 9879 } else { 9880 /* Note that the WideDash functions alternate 9881 * between filling using fgPixel and bgPixel 9882 * so we need to reset state between FillSpans and 9883 * cannot use the fill fast paths. 9884 */ 9885 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 9886 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 9887 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 9888 gc->ops = &sna_gc_ops__tmp; 9889 9890 switch (gc->lineStyle) { 9891 default: 9892 assert(0); 9893 case LineSolid: 9894 if (gc->lineWidth == 0) { 9895 DBG(("%s: miZeroLine\n", __FUNCTION__)); 9896 miZeroLine(drawable, gc, mode, n, pt); 9897 } else { 9898 DBG(("%s: miWideLine\n", __FUNCTION__)); 9899 miWideLine(drawable, gc, mode, n, pt); 9900 } 9901 break; 9902 case LineOnOffDash: 9903 case LineDoubleDash: 9904 if (gc->lineWidth == 0) { 9905 DBG(("%s: miZeroDashLine\n", __FUNCTION__)); 9906 miZeroDashLine(drawable, gc, mode, n, pt); 9907 } else { 9908 DBG(("%s: miWideDash\n", __FUNCTION__)); 9909 miWideDash(drawable, gc, mode, n, pt); 9910 } 9911 break; 9912 } 9913 } 9914 9915 gc->ops = (GCOps *)&sna_gc_ops; 9916 if (data.damage) { 9917 if (data.dx | data.dy) 9918 pixman_region_translate(&data.region, data.dx, data.dy); 9919 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 9920 sna_damage_add(data.damage, &data.region); 9921 assert_pixmap_damage(data.pixmap); 9922 } 9923 RegionUninit(&data.region); 9924 return; 9925 } 9926 9927fallback: 9928 DBG(("%s: fallback\n", __FUNCTION__)); 9929 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 9930 return; 9931 9932 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 9933 goto out; 9934 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 9935 drawable_gc_flags(drawable, gc, 9936 !(data.flags & 4 && n == 2)))) 9937 goto out; 9938 9939 if (sigtrap_get() == 0) { 9940 DBG(("%s: fbPolyLine\n", __FUNCTION__)); 9941 fbPolyLine(drawable, gc, mode, n, pt); 9942 FALLBACK_FLUSH(drawable); 9943 sigtrap_put(); 9944 } 9945out: 9946 sna_gc_move_to_gpu(gc); 9947 RegionUninit(&data.region); 9948} 9949 9950static inline void box_from_seg(BoxPtr b, xSegment *seg, GCPtr gc) 9951{ 9952 if (seg->x1 == seg->x2) { 9953 if (seg->y1 > seg->y2) { 9954 b->y2 = seg->y1 + 1; 9955 b->y1 = seg->y2 + 1; 9956 if (gc->capStyle != CapNotLast) 9957 b->y1--; 9958 } else { 9959 b->y1 = seg->y1; 9960 b->y2 = seg->y2; 9961 if (gc->capStyle != CapNotLast) 9962 b->y2++; 9963 } 9964 b->x1 = seg->x1; 9965 b->x2 = seg->x1 + 1; 9966 } else { 9967 if (seg->x1 > seg->x2) { 9968 b->x2 = seg->x1 + 1; 9969 b->x1 = seg->x2 + 1; 9970 if (gc->capStyle != CapNotLast) 9971 b->x1--; 9972 } else { 9973 b->x1 = seg->x1; 9974 b->x2 = seg->x2; 9975 if (gc->capStyle != CapNotLast) 9976 b->x2++; 9977 } 9978 b->y1 = seg->y1; 9979 b->y2 = seg->y1 + 1; 9980 } 9981 9982 DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n", 9983 __FUNCTION__, 9984 seg->x1, seg->y1, seg->x2, seg->y2, 9985 b->x1, b->y1, b->x2, b->y2)); 9986} 9987 9988static bool 9989sna_poly_segment_blt(DrawablePtr drawable, 9990 struct kgem_bo *bo, 9991 struct sna_damage **damage, 9992 GCPtr gc, uint32_t pixel, 9993 int n, xSegment *seg, 9994 const BoxRec *extents, unsigned clipped) 9995{ 9996 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9997 struct sna *sna = to_sna_from_pixmap(pixmap); 9998 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 9999 struct sna_fill_op fill; 10000 int16_t dx, dy; 10001 10002 DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n", 10003 __FUNCTION__, n, gc->alu, gc->fgPixel, clipped)); 10004 10005 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 10006 return false; 10007 10008 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10009 10010 if (!clipped) { 10011 dx += drawable->x; 10012 dy += drawable->y; 10013 if (dx|dy) { 10014 do { 10015 unsigned nbox = n; 10016 if (nbox > ARRAY_SIZE(boxes)) 10017 nbox = ARRAY_SIZE(boxes); 10018 n -= nbox; 10019 do { 10020 box_from_seg(b, seg++, gc); 10021 if (b->y2 > b->y1 && b->x2 > b->x1) { 10022 b->x1 += dx; 10023 b->x2 += dx; 10024 b->y1 += dy; 10025 b->y2 += dy; 10026 b++; 10027 } 10028 } while (--nbox); 10029 10030 if (b != boxes) { 10031 fill.boxes(sna, &fill, boxes, b-boxes); 10032 if (damage) 10033 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10034 b = boxes; 10035 } 10036 } while (n); 10037 } else { 10038 do { 10039 unsigned nbox = n; 10040 if (nbox > ARRAY_SIZE(boxes)) 10041 nbox = ARRAY_SIZE(boxes); 10042 n -= nbox; 10043 do { 10044 box_from_seg(b++, seg++, gc); 10045 } while (--nbox); 10046 10047 if (b != boxes) { 10048 fill.boxes(sna, &fill, boxes, b-boxes); 10049 if (damage) 10050 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10051 b = boxes; 10052 } 10053 } while (n); 10054 } 10055 } else { 10056 RegionRec clip; 10057 10058 region_set(&clip, extents); 10059 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10060 goto done; 10061 10062 if (clip.data) { 10063 const BoxRec * const clip_start = RegionBoxptr(&clip); 10064 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10065 const BoxRec *c; 10066 do { 10067 BoxRec box; 10068 10069 box_from_seg(&box, seg++, gc); 10070 box.x1 += drawable->x; 10071 box.x2 += drawable->x; 10072 box.y1 += drawable->y; 10073 box.y2 += drawable->y; 10074 c = find_clip_box_for_y(clip_start, 10075 clip_end, 10076 box.y1); 10077 while (c != clip_end) { 10078 if (box.y2 <= c->y1) 10079 break; 10080 10081 *b = box; 10082 if (box_intersect(b, c++)) { 10083 b->x1 += dx; 10084 b->x2 += dx; 10085 b->y1 += dy; 10086 b->y2 += dy; 10087 if (++b == last_box) { 10088 fill.boxes(sna, &fill, boxes, last_box-boxes); 10089 if (damage) 10090 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10091 b = boxes; 10092 } 10093 } 10094 } 10095 } while (--n); 10096 } else { 10097 do { 10098 box_from_seg(b, seg++, gc); 10099 b->x1 += drawable->x; 10100 b->x2 += drawable->x; 10101 b->y1 += drawable->y; 10102 b->y2 += drawable->y; 10103 if (box_intersect(b, &clip.extents)) { 10104 b->x1 += dx; 10105 b->x2 += dx; 10106 b->y1 += dy; 10107 b->y2 += dy; 10108 if (++b == last_box) { 10109 fill.boxes(sna, &fill, boxes, last_box-boxes); 10110 if (damage) 10111 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10112 b = boxes; 10113 } 10114 } 10115 } while (--n); 10116 } 10117 RegionUninit(&clip); 10118 } 10119 if (b != boxes) { 10120 fill.boxes(sna, &fill, boxes, b - boxes); 10121 if (damage) 10122 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 10123 } 10124done: 10125 fill.done(sna, &fill); 10126 assert_pixmap_damage(pixmap); 10127 return true; 10128} 10129 10130static bool 10131sna_poly_zero_segment_blt(DrawablePtr drawable, 10132 struct kgem_bo *bo, 10133 struct sna_damage **damage, 10134 GCPtr gc, const int _n, const xSegment *_s, 10135 const BoxRec *extents, unsigned clipped) 10136{ 10137 static void * const _jump[] = { 10138 &&no_damage, 10139 &&damage, 10140 10141 &&no_damage_offset, 10142 &&damage_offset, 10143 }; 10144 10145 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10146 struct sna *sna = to_sna_from_pixmap(pixmap); 10147 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 10148 struct sna_fill_op fill; 10149 RegionRec clip; 10150 const BoxRec *last_extents; 10151 BoxRec box[512], *b; 10152 BoxRec *const last_box = box + ARRAY_SIZE(box); 10153 int16_t dx, dy; 10154 void *jump, *ret; 10155 10156 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 10157 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 10158 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10159 return false; 10160 10161 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10162 10163 region_set(&clip, extents); 10164 if (clipped) { 10165 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10166 return true; 10167 } 10168 DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n", 10169 __FUNCTION__, 10170 clip.extents.x1, clip.extents.y1, 10171 clip.extents.x2, clip.extents.y2, 10172 dx, dy)); 10173 10174 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 10175 10176 b = box; 10177 extents = region_rects(&clip); 10178 last_extents = extents + region_num_rects(&clip); 10179 do { 10180 int n = _n; 10181 const xSegment *s = _s; 10182 do { 10183 int16_t sdx, sdy; 10184 int adx, ady, length; 10185 int e, e1, e2, e3; 10186 int x1, x2; 10187 int y1, y2; 10188 int oc1, oc2; 10189 int octant; 10190 10191 x1 = s->x1 + drawable->x; 10192 y1 = s->y1 + drawable->y; 10193 x2 = s->x2 + drawable->x; 10194 y2 = s->y2 + drawable->y; 10195 s++; 10196 10197 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 10198 __FUNCTION__, x1, y1, x2, y2)); 10199 if (x2 == x1 && y2 == y1) 10200 continue; 10201 10202 oc1 = 0; 10203 OUTCODES(oc1, x1, y1, extents); 10204 oc2 = 0; 10205 OUTCODES(oc2, x2, y2, extents); 10206 if (oc1 & oc2) 10207 continue; 10208 10209 CalcLineDeltas(x1, y1, x2, y2, 10210 adx, ady, sdx, sdy, 10211 1, 1, octant); 10212 10213 DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n", 10214 __FUNCTION__, adx, ady, sdx, sdy)); 10215 if (adx == 0 || ady == 0) { 10216 if (x1 <= x2) { 10217 b->x1 = x1; 10218 b->x2 = x2; 10219 } else { 10220 b->x1 = x2; 10221 b->x2 = x1; 10222 } 10223 if (y1 <= y2) { 10224 b->y1 = y1; 10225 b->y2 = y2; 10226 } else { 10227 b->y1 = y2; 10228 b->y2 = y1; 10229 } 10230 b->x2++; 10231 b->y2++; 10232 if (oc1 | oc2) 10233 box_intersect(b, extents); 10234 if (++b == last_box) { 10235 ret = &&rectangle_continue; 10236 goto *jump; 10237rectangle_continue: 10238 b = box; 10239 } 10240 } else if (adx >= ady) { 10241 bool dirty; 10242 10243 /* X-major segment */ 10244 e1 = ady << 1; 10245 e2 = e1 - (adx << 1); 10246 e = e1 - adx; 10247 length = adx; /* don't draw endpoint in main loop */ 10248 10249 FIXUP_ERROR(e, octant, bias); 10250 10251 if (oc1 | oc2) { 10252 int pt1_clipped, pt2_clipped; 10253 int x = x1, y = y1; 10254 10255 if (miZeroClipLine(extents->x1, extents->y1, 10256 extents->x2-1, extents->y2-1, 10257 &x1, &y1, &x2, &y2, 10258 adx, ady, 10259 &pt1_clipped, &pt2_clipped, 10260 octant, bias, oc1, oc2) == -1) 10261 continue; 10262 10263 length = abs(x2 - x1); 10264 if (length == 0) 10265 continue; 10266 10267 if (pt1_clipped) { 10268 int clipdx = abs(x1 - x); 10269 int clipdy = abs(y1 - y); 10270 e += clipdy * e2 + (clipdx - clipdy) * e1; 10271 } 10272 } 10273 e3 = e2 - e1; 10274 e = e - e1; 10275 10276 b->x1 = x1; 10277 b->y1 = y1; 10278 dirty = false; 10279 while (length--) { 10280 dirty = true; 10281 e += e1; 10282 if (e >= 0) { 10283 e += e3; 10284 10285 if (sdx < 0) { 10286 b->x2 = b->x1 + 1; 10287 b->x1 = x1; 10288 } else 10289 b->x2 = x1 + 1; 10290 b->y2 = b->y1 + 1; 10291 10292 DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n", 10293 __FUNCTION__, x1, y1, 10294 b->x1, b->y1, b->x2, b->y2)); 10295 10296 if (++b == last_box) { 10297 ret = &&X_continue; 10298 goto *jump; 10299X_continue: 10300 b = box; 10301 } 10302 10303 b->x1 = x1 + sdx; 10304 b->y1 = y1 += sdy; 10305 dirty = false; 10306 } 10307 x1 += sdx; 10308 } 10309 if (dirty) { 10310 x1 -= sdx; 10311 DBG(("%s: horizontal tail: (%d, %d)\n", 10312 __FUNCTION__, x1, y1)); 10313 if (sdx < 0) { 10314 b->x2 = b->x1 + 1; 10315 b->x1 = x1; 10316 } else 10317 b->x2 = x1 + 1; 10318 b->y2 = b->y1 + 1; 10319 10320 if (++b == last_box) { 10321 ret = &&X2_continue; 10322 goto *jump; 10323X2_continue: 10324 b = box; 10325 } 10326 } 10327 } else { 10328 bool dirty; 10329 10330 /* Y-major segment */ 10331 e1 = adx << 1; 10332 e2 = e1 - (ady << 1); 10333 e = e1 - ady; 10334 length = ady; /* don't draw endpoint in main loop */ 10335 10336 SetYMajorOctant(octant); 10337 FIXUP_ERROR(e, octant, bias); 10338 10339 if (oc1 | oc2) { 10340 int pt1_clipped, pt2_clipped; 10341 int x = x1, y = y1; 10342 10343 if (miZeroClipLine(extents->x1, extents->y1, 10344 extents->x2-1, extents->y2-1, 10345 &x1, &y1, &x2, &y2, 10346 adx, ady, 10347 &pt1_clipped, &pt2_clipped, 10348 octant, bias, oc1, oc2) == -1) 10349 continue; 10350 10351 length = abs(y2 - y1); 10352 if (length == 0) 10353 continue; 10354 10355 if (pt1_clipped) { 10356 int clipdx = abs(x1 - x); 10357 int clipdy = abs(y1 - y); 10358 e += clipdx * e2 + (clipdy - clipdx) * e1; 10359 } 10360 } 10361 10362 e3 = e2 - e1; 10363 e = e - e1; 10364 10365 b->x1 = x1; 10366 b->y1 = y1; 10367 dirty = false; 10368 while (length--) { 10369 e += e1; 10370 dirty = true; 10371 if (e >= 0) { 10372 e += e3; 10373 10374 if (sdy < 0) { 10375 b->y2 = b->y1 + 1; 10376 b->y1 = y1; 10377 } else 10378 b->y2 = y1 + 1; 10379 b->x2 = x1 + 1; 10380 10381 if (++b == last_box) { 10382 ret = &&Y_continue; 10383 goto *jump; 10384Y_continue: 10385 b = box; 10386 } 10387 10388 b->x1 = x1 += sdx; 10389 b->y1 = y1 + sdy; 10390 dirty = false; 10391 } 10392 y1 += sdy; 10393 } 10394 10395 if (dirty) { 10396 y1 -= sdy; 10397 if (sdy < 0) { 10398 b->y2 = b->y1 + 1; 10399 b->y1 = y1; 10400 } else 10401 b->y2 = y1 + 1; 10402 b->x2 = x1 + 1; 10403 10404 if (++b == last_box) { 10405 ret = &&Y2_continue; 10406 goto *jump; 10407Y2_continue: 10408 b = box; 10409 } 10410 } 10411 } 10412 } while (--n); 10413 } while (++extents != last_extents); 10414 10415 if (b != box) { 10416 ret = &&done; 10417 goto *jump; 10418 } 10419 10420done: 10421 fill.done(sna, &fill); 10422 assert_pixmap_damage(pixmap); 10423 RegionUninit(&clip); 10424 return true; 10425 10426damage: 10427 sna_damage_add_boxes(damage, box, b-box, 0, 0); 10428no_damage: 10429 fill.boxes(sna, &fill, box, b-box); 10430 goto *ret; 10431 10432no_damage_offset: 10433 { 10434 BoxRec *bb = box; 10435 do { 10436 bb->x1 += dx; 10437 bb->x2 += dx; 10438 bb->y1 += dy; 10439 bb->y2 += dy; 10440 } while (++bb != b); 10441 fill.boxes(sna, &fill, box, b - box); 10442 } 10443 goto *ret; 10444 10445damage_offset: 10446 { 10447 BoxRec *bb = box; 10448 do { 10449 bb->x1 += dx; 10450 bb->x2 += dx; 10451 bb->y1 += dy; 10452 bb->y2 += dy; 10453 } while (++bb != b); 10454 fill.boxes(sna, &fill, box, b - box); 10455 sna_damage_add_boxes(damage, box, b - box, 0, 0); 10456 } 10457 goto *ret; 10458} 10459 10460static unsigned 10461sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc, 10462 int n, xSegment *seg, 10463 BoxPtr out) 10464{ 10465 BoxRec box; 10466 bool clipped, can_blit; 10467 10468 if (n == 0) 10469 return 0; 10470 10471 if (seg->x2 >= seg->x1) { 10472 box.x1 = seg->x1; 10473 box.x2 = seg->x2; 10474 } else { 10475 box.x2 = seg->x1; 10476 box.x1 = seg->x2; 10477 } 10478 10479 if (seg->y2 >= seg->y1) { 10480 box.y1 = seg->y1; 10481 box.y2 = seg->y2; 10482 } else { 10483 box.y2 = seg->y1; 10484 box.y1 = seg->y2; 10485 } 10486 10487 can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2; 10488 while (--n) { 10489 seg++; 10490 if (seg->x2 > seg->x1) { 10491 if (seg->x1 < box.x1) box.x1 = seg->x1; 10492 if (seg->x2 > box.x2) box.x2 = seg->x2; 10493 } else { 10494 if (seg->x2 < box.x1) box.x1 = seg->x2; 10495 if (seg->x1 > box.x2) box.x2 = seg->x1; 10496 } 10497 10498 if (seg->y2 > seg->y1) { 10499 if (seg->y1 < box.y1) box.y1 = seg->y1; 10500 if (seg->y2 > box.y2) box.y2 = seg->y2; 10501 } else { 10502 if (seg->y2 < box.y1) box.y1 = seg->y2; 10503 if (seg->y1 > box.y2) box.y2 = seg->y1; 10504 } 10505 10506 if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2)) 10507 can_blit = false; 10508 } 10509 10510 box.x2++; 10511 box.y2++; 10512 10513 if (gc->lineWidth) { 10514 int extra = gc->lineWidth; 10515 if (gc->capStyle != CapProjecting) 10516 extra >>= 1; 10517 if (extra) { 10518 box.x1 -= extra; 10519 box.x2 += extra; 10520 box.y1 -= extra; 10521 box.y2 += extra; 10522 } 10523 } 10524 10525 DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n", 10526 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10527 10528 clipped = trim_and_translate_box(&box, drawable, gc); 10529 if (box_empty(&box)) 10530 return 0; 10531 10532 *out = box; 10533 return 1 | clipped << 1 | can_blit << 2; 10534} 10535 10536static void 10537sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg) 10538{ 10539 struct sna_pixmap *priv; 10540 struct sna_fill_spans data; 10541 uint32_t color; 10542 10543 DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n", 10544 __FUNCTION__, 10545 n, seg->x1, seg->y1, seg->x2, seg->y2, 10546 gc->lineWidth)); 10547 10548 data.flags = sna_poly_segment_extents(drawable, gc, n, seg, 10549 &data.region.extents); 10550 if (data.flags == 0) 10551 return; 10552 10553 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 10554 data.region.extents.x1, data.region.extents.y1, 10555 data.region.extents.x2, data.region.extents.y2)); 10556 10557 data.region.data = NULL; 10558 10559 if (FORCE_FALLBACK) 10560 goto fallback; 10561 10562 if (!ACCEL_POLY_SEGMENT) 10563 goto fallback; 10564 10565 data.pixmap = get_drawable_pixmap(drawable); 10566 data.sna = to_sna_from_pixmap(data.pixmap); 10567 priv = sna_pixmap(data.pixmap); 10568 if (priv == NULL) { 10569 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10570 goto fallback; 10571 } 10572 10573 if (wedged(data.sna)) { 10574 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10575 goto fallback; 10576 } 10577 10578 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 10579 __FUNCTION__, 10580 gc->fillStyle, gc->fillStyle == FillSolid, 10581 gc->lineStyle, gc->lineStyle == LineSolid, 10582 gc->lineWidth, 10583 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 10584 data.flags & 4)); 10585 if (!PM_IS_SOLID(drawable, gc->planemask)) 10586 goto fallback; 10587 10588 if (gc->lineStyle != LineSolid || gc->lineWidth > 1) 10589 goto spans_fallback; 10590 if (gc_is_solid(gc, &color)) { 10591 DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n", 10592 __FUNCTION__, (unsigned)color, data.flags)); 10593 10594 if (data.flags & 4) { 10595 if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 10596 &data.region.extents, 10597 &data.damage)) && 10598 sna_poly_segment_blt(drawable, 10599 data.bo, data.damage, 10600 gc, color, n, seg, 10601 &data.region.extents, 10602 data.flags & 2)) 10603 return; 10604 } else { 10605 if ((data.bo = sna_drawable_use_bo(drawable, 10606 use_zero_spans(drawable, gc, &data.region.extents), 10607 &data.region.extents, 10608 &data.damage)) && 10609 sna_poly_zero_segment_blt(drawable, 10610 data.bo, data.damage, 10611 gc, n, seg, 10612 &data.region.extents, 10613 data.flags & 2)) 10614 return; 10615 } 10616 } else if (data.flags & 4) { 10617 /* Try converting these to a set of rectangles instead */ 10618 xRectangle *rect; 10619 int i; 10620 10621 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 10622 &data.region.extents, 10623 &data.damage); 10624 if (data.bo == NULL) 10625 goto fallback; 10626 10627 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 10628 10629 rect = malloc (n * sizeof (xRectangle)); 10630 if (rect == NULL) 10631 return; 10632 10633 for (i = 0; i < n; i++) { 10634 if (seg[i].x1 < seg[i].x2) { 10635 rect[i].x = seg[i].x1; 10636 rect[i].width = seg[i].x2 - seg[i].x1 + 1; 10637 } else if (seg[i].x1 > seg[i].x2) { 10638 rect[i].x = seg[i].x2; 10639 rect[i].width = seg[i].x1 - seg[i].x2 + 1; 10640 } else { 10641 rect[i].x = seg[i].x1; 10642 rect[i].width = 1; 10643 } 10644 if (seg[i].y1 < seg[i].y2) { 10645 rect[i].y = seg[i].y1; 10646 rect[i].height = seg[i].y2 - seg[i].y1 + 1; 10647 } else if (seg[i].y1 > seg[i].y2) { 10648 rect[i].y = seg[i].y2; 10649 rect[i].height = seg[i].y1 - seg[i].y2 + 1; 10650 } else { 10651 rect[i].y = seg[i].y1; 10652 rect[i].height = 1; 10653 } 10654 10655 /* don't paint last pixel */ 10656 if (gc->capStyle == CapNotLast) { 10657 if (seg[i].x1 == seg[i].x2) 10658 rect[i].height--; 10659 else 10660 rect[i].width--; 10661 } 10662 } 10663 10664 if (gc->fillStyle == FillTiled) { 10665 i = sna_poly_fill_rect_tiled_blt(drawable, 10666 data.bo, data.damage, 10667 gc, n, rect, 10668 &data.region.extents, 10669 data.flags & 2); 10670 } else { 10671 i = sna_poly_fill_rect_stippled_blt(drawable, 10672 data.bo, data.damage, 10673 gc, n, rect, 10674 &data.region.extents, 10675 data.flags & 2); 10676 } 10677 free (rect); 10678 10679 if (i) 10680 return; 10681 } 10682 10683spans_fallback: 10684 if ((data.bo = sna_drawable_use_bo(drawable, 10685 use_wide_spans(drawable, gc, &data.region.extents), 10686 &data.region.extents, 10687 &data.damage))) { 10688 void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr); 10689 int i; 10690 10691 DBG(("%s: converting segments into spans\n", __FUNCTION__)); 10692 10693 switch (gc->lineStyle) { 10694 default: 10695 case LineSolid: 10696 if (gc->lineWidth == 0) 10697 line = miZeroLine; 10698 else 10699 line = miWideLine; 10700 break; 10701 case LineOnOffDash: 10702 case LineDoubleDash: 10703 if (gc->lineWidth == 0) 10704 line = miZeroDashLine; 10705 else 10706 line = miWideDash; 10707 break; 10708 } 10709 10710 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10711 sna_gc(gc)->priv = &data; 10712 10713 if (gc->lineWidth == 0 && 10714 gc->lineStyle == LineSolid && 10715 gc_is_solid(gc, &color)) { 10716 struct sna_fill_op fill; 10717 10718 if (!sna_fill_init_blt(&fill, 10719 data.sna, data.pixmap, 10720 data.bo, gc->alu, color, 10721 FILL_POINTS | FILL_SPANS)) 10722 goto fallback; 10723 10724 data.op = &fill; 10725 10726 if ((data.flags & 2) == 0) { 10727 if (data.dx | data.dy) 10728 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10729 else 10730 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10731 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10732 } else { 10733 if (!region_maybe_clip(&data.region, 10734 gc->pCompositeClip)) 10735 return; 10736 10737 if (region_is_singular(&data.region)) { 10738 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10739 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10740 } else { 10741 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10742 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10743 } 10744 } 10745 assert(gc->miTranslate); 10746 gc->ops = &sna_gc_ops__tmp; 10747 for (i = 0; i < n; i++) 10748 line(drawable, gc, CoordModeOrigin, 2, 10749 (DDXPointPtr)&seg[i]); 10750 10751 fill.done(data.sna, &fill); 10752 } else { 10753 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10754 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 10755 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 10756 gc->ops = &sna_gc_ops__tmp; 10757 10758 for (i = 0; i < n; i++) 10759 line(drawable, gc, CoordModeOrigin, 2, 10760 (DDXPointPtr)&seg[i]); 10761 } 10762 10763 gc->ops = (GCOps *)&sna_gc_ops; 10764 if (data.damage) { 10765 if (data.dx | data.dy) 10766 pixman_region_translate(&data.region, data.dx, data.dy); 10767 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10768 sna_damage_add(data.damage, &data.region); 10769 } 10770 assert_pixmap_damage(data.pixmap); 10771 RegionUninit(&data.region); 10772 return; 10773 } 10774 10775fallback: 10776 DBG(("%s: fallback\n", __FUNCTION__)); 10777 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 10778 return; 10779 10780 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10781 goto out; 10782 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10783 drawable_gc_flags(drawable, gc, 10784 !(data.flags & 4 && n == 1)))) 10785 goto out; 10786 10787 if (sigtrap_get() == 0) { 10788 DBG(("%s: fbPolySegment\n", __FUNCTION__)); 10789 fbPolySegment(drawable, gc, n, seg); 10790 FALLBACK_FLUSH(drawable); 10791 sigtrap_put(); 10792 } 10793out: 10794 sna_gc_move_to_gpu(gc); 10795 RegionUninit(&data.region); 10796} 10797 10798static unsigned 10799sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, 10800 int n, xRectangle *r, 10801 BoxPtr out) 10802{ 10803 Box32Rec box; 10804 int extra = gc->lineWidth >> 1; 10805 bool clipped; 10806 bool zero = false; 10807 10808 if (n == 0) 10809 return 0; 10810 10811 box.x1 = r->x; 10812 box.y1 = r->y; 10813 box.x2 = box.x1 + r->width; 10814 box.y2 = box.y1 + r->height; 10815 zero |= (r->width | r->height) == 0; 10816 10817 while (--n) { 10818 r++; 10819 zero |= (r->width | r->height) == 0; 10820 box32_add_rect(&box, r); 10821 } 10822 10823 box.x2++; 10824 box.y2++; 10825 10826 if (extra) { 10827 box.x1 -= extra; 10828 box.x2 += extra; 10829 box.y1 -= extra; 10830 box.y2 += extra; 10831 zero = !zero; 10832 } else 10833 zero = true; 10834 10835 DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n", 10836 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10837 clipped = box32_trim_and_translate(&box, drawable, gc); 10838 if (!box32_to_box16(&box, out)) 10839 return 0; 10840 10841 DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n", 10842 __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped)); 10843 return 1 | clipped << 1 | zero << 2; 10844} 10845 10846static bool 10847sna_poly_rectangle_blt(DrawablePtr drawable, 10848 struct kgem_bo *bo, 10849 struct sna_damage **damage, 10850 GCPtr gc, int n, xRectangle *r, 10851 const BoxRec *extents, unsigned clipped) 10852{ 10853 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10854 struct sna *sna = to_sna_from_pixmap(pixmap); 10855 struct sna_fill_op fill; 10856 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 10857 int16_t dx, dy; 10858 static void * const jump[] = { 10859 &&wide, 10860 &&zero, 10861 &&wide_clipped, 10862 &&zero_clipped, 10863 }; 10864 10865 DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", 10866 __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); 10867 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10868 return false; 10869 10870 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10871 10872 goto *jump[(gc->lineWidth <= 1) | clipped]; 10873 10874zero: 10875 dx += drawable->x; 10876 dy += drawable->y; 10877 10878 do { 10879 xRectangle rr = *r++; 10880 10881 if ((rr.width | rr.height) == 0) 10882 continue; /* XXX -> PolyLine */ 10883 10884 DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 10885 n, rr.x, rr.y, rr.width, rr.height)); 10886 rr.x += dx; 10887 rr.y += dy; 10888 10889 if (b+4 > last_box) { 10890 fill.boxes(sna, &fill, boxes, b-boxes); 10891 if (damage) 10892 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10893 b = boxes; 10894 } 10895 10896 if (rr.width <= 1 || rr.height <= 1) { 10897 b->x1 = rr.x; 10898 b->y1 = rr.y; 10899 b->x2 = rr.x + rr.width + (rr.height != 0); 10900 b->y2 = rr.y + rr.height + (rr.width != 0); 10901 DBG(("%s: blt (%d, %d), (%d, %d)\n", 10902 __FUNCTION__, 10903 b->x1, b->y1, b->x2,b->y2)); 10904 b++; 10905 } else { 10906 b[0].x1 = rr.x; 10907 b[0].y1 = rr.y; 10908 b[0].x2 = rr.x + rr.width + 1; 10909 b[0].y2 = rr.y + 1; 10910 10911 b[1] = b[0]; 10912 b[1].y1 += rr.height; 10913 b[1].y2 += rr.height; 10914 10915 b[2].y1 = rr.y + 1; 10916 b[2].y2 = rr.y + rr.height; 10917 b[2].x1 = rr.x; 10918 b[2].x2 = rr.x + 1; 10919 10920 b[3] = b[2]; 10921 b[3].x1 += rr.width; 10922 b[3].x2 += rr.width; 10923 10924 b += 4; 10925 } 10926 } while (--n); 10927 goto done; 10928 10929zero_clipped: 10930 { 10931 RegionRec clip; 10932 BoxRec box[4]; 10933 int count; 10934 10935 region_set(&clip, extents); 10936 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10937 goto done; 10938 10939 if (clip.data) { 10940 const BoxRec * const clip_start = RegionBoxptr(&clip); 10941 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10942 const BoxRec *c; 10943 do { 10944 xRectangle rr = *r++; 10945 10946 DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 10947 n, rr.x, rr.y, rr.width, rr.height)); 10948 10949 if ((rr.width | rr.height) == 0) 10950 continue; /* XXX -> PolyLine */ 10951 10952 rr.x += drawable->x; 10953 rr.y += drawable->y; 10954 10955 if (rr.width <= 1 || rr.height <= 1) { 10956 box[0].x1 = rr.x; 10957 box[0].y1 = rr.y; 10958 box[0].x2 = rr.x + rr.width + (rr.height != 0); 10959 box[0].y2 = rr.y + rr.height + (rr.width != 0); 10960 count = 1; 10961 } else { 10962 box[0].x1 = rr.x; 10963 box[0].y1 = rr.y; 10964 box[0].x2 = rr.x + rr.width + 1; 10965 box[0].y2 = rr.y + 1; 10966 10967 box[1] = box[0]; 10968 box[1].y1 += rr.height; 10969 box[1].y2 += rr.height; 10970 10971 box[2].y1 = rr.y + 1; 10972 box[2].y2 = rr.y + rr.height; 10973 box[2].x1 = rr.x; 10974 box[2].x2 = rr.x + 1; 10975 10976 box[3] = box[2]; 10977 box[3].x1 += rr.width; 10978 box[3].x2 += rr.width; 10979 count = 4; 10980 } 10981 10982 while (count--) { 10983 c = find_clip_box_for_y(clip_start, 10984 clip_end, 10985 box[count].y1); 10986 while (c != clip_end) { 10987 if (box[count].y2 <= c->y1) 10988 break; 10989 10990 *b = box[count]; 10991 if (box_intersect(b, c++)) { 10992 b->x1 += dx; 10993 b->x2 += dx; 10994 b->y1 += dy; 10995 b->y2 += dy; 10996 if (++b == last_box) { 10997 fill.boxes(sna, &fill, boxes, last_box-boxes); 10998 if (damage) 10999 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11000 b = boxes; 11001 } 11002 } 11003 11004 } 11005 } 11006 } while (--n); 11007 } else { 11008 do { 11009 xRectangle rr = *r++; 11010 DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11011 n, rr.x, rr.y, rr.width, rr.height)); 11012 11013 if ((rr.width | rr.height) == 0) 11014 continue; /* XXX -> PolyLine */ 11015 11016 rr.x += drawable->x; 11017 rr.y += drawable->y; 11018 11019 if (rr.width <= 1 || rr.height <= 1) { 11020 box[0].x1 = rr.x; 11021 box[0].y1 = rr.y; 11022 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11023 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11024 count = 1; 11025 } else { 11026 box[0].x1 = rr.x; 11027 box[0].y1 = rr.y; 11028 box[0].x2 = rr.x + rr.width + 1; 11029 box[0].y2 = rr.y + 1; 11030 11031 box[1] = box[0]; 11032 box[1].y1 += rr.height; 11033 box[1].y2 += rr.height; 11034 11035 box[2].y1 = rr.y + 1; 11036 box[2].y2 = rr.y + rr.height; 11037 box[2].x1 = rr.x; 11038 box[2].x2 = rr.x + 1; 11039 11040 box[3] = box[2]; 11041 box[3].x1 += rr.width; 11042 box[3].x2 += rr.width; 11043 count = 4; 11044 } 11045 11046 while (count--) { 11047 *b = box[count]; 11048 if (box_intersect(b, &clip.extents)) { 11049 b->x1 += dx; 11050 b->x2 += dx; 11051 b->y1 += dy; 11052 b->y2 += dy; 11053 if (++b == last_box) { 11054 fill.boxes(sna, &fill, boxes, last_box-boxes); 11055 if (damage) 11056 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11057 b = boxes; 11058 } 11059 } 11060 11061 } 11062 } while (--n); 11063 } 11064 RegionUninit(&clip); 11065 } 11066 goto done; 11067 11068wide_clipped: 11069 { 11070 RegionRec clip; 11071 BoxRec box[4]; 11072 int16_t offset2 = gc->lineWidth; 11073 int16_t offset1 = offset2 >> 1; 11074 int16_t offset3 = offset2 - offset1; 11075 11076 region_set(&clip, extents); 11077 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11078 goto done; 11079 11080 DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n", 11081 __FUNCTION__, 11082 clip.extents.x1, clip.extents.y1, 11083 clip.extents.x2, clip.extents.y2)); 11084 11085 if (clip.data) { 11086 const BoxRec * const clip_start = RegionBoxptr(&clip); 11087 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11088 const BoxRec *c; 11089 do { 11090 xRectangle rr = *r++; 11091 int count; 11092 11093 if ((rr.width | rr.height) == 0) 11094 continue; /* XXX -> PolyLine */ 11095 11096 rr.x += drawable->x; 11097 rr.y += drawable->y; 11098 11099 if (rr.height <= offset2 || rr.width <= offset2) { 11100 if (rr.height == 0) { 11101 box[0].x1 = rr.x; 11102 box[0].x2 = rr.x + rr.width; 11103 } else { 11104 box[0].x1 = rr.x - offset1; 11105 box[0].x2 = rr.x + rr.width + offset3; 11106 } 11107 if (rr.width == 0) { 11108 box[0].y1 = rr.y; 11109 box[0].y2 = rr.y + rr.height; 11110 } else { 11111 box[0].y1 = rr.y - offset1; 11112 box[0].y2 = rr.y + rr.height + offset3; 11113 } 11114 count = 1; 11115 } else { 11116 box[0].x1 = rr.x - offset1; 11117 box[0].x2 = box[0].x1 + rr.width + offset2; 11118 box[0].y1 = rr.y - offset1; 11119 box[0].y2 = box[0].y1 + offset2; 11120 11121 box[1].x1 = rr.x - offset1; 11122 box[1].x2 = box[1].x1 + offset2; 11123 box[1].y1 = rr.y + offset3; 11124 box[1].y2 = rr.y + rr.height - offset1; 11125 11126 box[2] = box[1]; 11127 box[2].x1 += rr.width; 11128 box[2].x2 += rr.width; 11129 11130 box[3] = box[0]; 11131 box[3].y1 += rr.height; 11132 box[3].y2 += rr.height; 11133 count = 4; 11134 } 11135 11136 while (count--) { 11137 c = find_clip_box_for_y(clip_start, 11138 clip_end, 11139 box[count].y1); 11140 while (c != clip_end) { 11141 if (box[count].y2 <= c->y1) 11142 break; 11143 11144 *b = box[count]; 11145 if (box_intersect(b, c++)) { 11146 b->x1 += dx; 11147 b->x2 += dx; 11148 b->y1 += dy; 11149 b->y2 += dy; 11150 if (++b == last_box) { 11151 fill.boxes(sna, &fill, boxes, last_box-boxes); 11152 if (damage) 11153 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11154 b = boxes; 11155 } 11156 } 11157 } 11158 } 11159 } while (--n); 11160 } else { 11161 DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n", 11162 __FUNCTION__, offset1, offset2, offset3)); 11163 do { 11164 xRectangle rr = *r++; 11165 int count; 11166 rr.x += drawable->x; 11167 rr.y += drawable->y; 11168 11169 DBG(("%s: r=(%d, %d)x(%d, %d)\n", 11170 __FUNCTION__, rr.x, rr.y, rr.width, rr.height)); 11171 if (rr.height <= offset2 || rr.width <= offset2) { 11172 if (rr.height == 0) { 11173 box[0].x1 = rr.x; 11174 box[0].x2 = rr.x + rr.width; 11175 } else { 11176 box[0].x1 = rr.x - offset1; 11177 box[0].x2 = box[0].x1 + rr.width + offset2; 11178 } 11179 if (rr.width == 0) { 11180 box[0].y1 = rr.y; 11181 box[0].y2 = rr.y + rr.height; 11182 } else { 11183 box[0].y1 = rr.y - offset1; 11184 box[0].y2 = box[0].y1 + rr.height + offset2; 11185 } 11186 count = 1; 11187 } else { 11188 box[0].x1 = rr.x - offset1; 11189 box[0].x2 = box[0].x1 + rr.width + offset2; 11190 box[0].y1 = rr.y - offset1; 11191 box[0].y2 = box[0].y1 + offset2; 11192 DBG(("%s: box[0]=(%d, %d), (%d, %d)\n", 11193 __FUNCTION__, 11194 box[0].x1, box[0].y1, 11195 box[0].x2, box[0].y2)); 11196 11197 box[1].x1 = rr.x - offset1; 11198 box[1].x2 = box[1].x1 + offset2; 11199 box[1].y1 = rr.y + offset3; 11200 box[1].y2 = rr.y + rr.height - offset1; 11201 DBG(("%s: box[1]=(%d, %d), (%d, %d)\n", 11202 __FUNCTION__, 11203 box[1].x1, box[1].y1, 11204 box[1].x2, box[1].y2)); 11205 11206 box[2] = box[1]; 11207 box[2].x1 += rr.width; 11208 box[2].x2 += rr.width; 11209 DBG(("%s: box[2]=(%d, %d), (%d, %d)\n", 11210 __FUNCTION__, 11211 box[2].x1, box[2].y1, 11212 box[2].x2, box[2].y2)); 11213 11214 box[3] = box[0]; 11215 box[3].y1 += rr.height; 11216 box[3].y2 += rr.height; 11217 DBG(("%s: box[3]=(%d, %d), (%d, %d)\n", 11218 __FUNCTION__, 11219 box[3].x1, box[3].y1, 11220 box[3].x2, box[3].y2)); 11221 11222 count = 4; 11223 } 11224 11225 while (count--) { 11226 *b = box[count]; 11227 if (box_intersect(b, &clip.extents)) { 11228 b->x1 += dx; 11229 b->x2 += dx; 11230 b->y1 += dy; 11231 b->y2 += dy; 11232 if (++b == last_box) { 11233 fill.boxes(sna, &fill, boxes, last_box-boxes); 11234 if (damage) 11235 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11236 b = boxes; 11237 } 11238 } 11239 } 11240 } while (--n); 11241 } 11242 RegionUninit(&clip); 11243 } 11244 goto done; 11245 11246wide: 11247 { 11248 int offset2 = gc->lineWidth; 11249 int offset1 = offset2 >> 1; 11250 int offset3 = offset2 - offset1; 11251 11252 dx += drawable->x; 11253 dy += drawable->y; 11254 11255 do { 11256 xRectangle rr = *r++; 11257 11258 if ((rr.width | rr.height) == 0) 11259 continue; /* XXX -> PolyLine */ 11260 11261 rr.x += dx; 11262 rr.y += dy; 11263 11264 if (b+4 > last_box) { 11265 fill.boxes(sna, &fill, boxes, last_box-boxes); 11266 if (damage) 11267 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11268 b = boxes; 11269 } 11270 11271 if (rr.height <= offset2 || rr.width <= offset2) { 11272 if (rr.height == 0) { 11273 b->x1 = rr.x; 11274 b->x2 = rr.x + rr.width; 11275 } else { 11276 b->x1 = rr.x - offset1; 11277 b->x2 = rr.x + rr.width + offset3; 11278 } 11279 if (rr.width == 0) { 11280 b->y1 = rr.y; 11281 b->y2 = rr.y + rr.height; 11282 } else { 11283 b->y1 = rr.y - offset1; 11284 b->y2 = rr.y + rr.height + offset3; 11285 } 11286 b++; 11287 } else { 11288 b[0].x1 = rr.x - offset1; 11289 b[0].x2 = b[0].x1 + rr.width + offset2; 11290 b[0].y1 = rr.y - offset1; 11291 b[0].y2 = b[0].y1 + offset2; 11292 11293 b[1].x1 = rr.x - offset1; 11294 b[1].x2 = b[1].x1 + offset2; 11295 b[1].y1 = rr.y + offset3; 11296 b[1].y2 = rr.y + rr.height - offset1; 11297 11298 b[2] = b[1]; 11299 b[2].x1 += rr.width; 11300 b[2].x2 += rr.width; 11301 11302 b[3] = b[0]; 11303 b[3].y1 += rr.height; 11304 b[3].y2 += rr.height; 11305 b += 4; 11306 } 11307 } while (--n); 11308 } 11309 goto done; 11310 11311done: 11312 if (b != boxes) { 11313 fill.boxes(sna, &fill, boxes, b-boxes); 11314 if (damage) 11315 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11316 } 11317 fill.done(sna, &fill); 11318 assert_pixmap_damage(pixmap); 11319 return true; 11320} 11321 11322static void 11323sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) 11324{ 11325 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11326 struct sna *sna = to_sna_from_pixmap(pixmap); 11327 struct sna_damage **damage; 11328 struct kgem_bo *bo; 11329 RegionRec region; 11330 unsigned flags; 11331 11332 DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", 11333 __FUNCTION__, 11334 n, r->x, r->y, r->width, r->height, 11335 gc->lineWidth)); 11336 11337 flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); 11338 if (flags == 0) 11339 return; 11340 11341 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11342 region.extents.x1, region.extents.y1, 11343 region.extents.x2, region.extents.y2, 11344 flags)); 11345 11346 if (FORCE_FALLBACK) 11347 goto fallback; 11348 11349 if (!ACCEL_POLY_RECTANGLE) 11350 goto fallback; 11351 11352 if (wedged(sna)) { 11353 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11354 goto fallback; 11355 } 11356 11357 DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n", 11358 __FUNCTION__, 11359 gc->fillStyle, gc->fillStyle == FillSolid, 11360 gc->lineStyle, gc->lineStyle == LineSolid, 11361 gc->joinStyle, gc->joinStyle == JoinMiter, 11362 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 11363 11364 if (!PM_IS_SOLID(drawable, gc->planemask)) 11365 goto fallback; 11366 11367 if (flags & 4 && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) { 11368 DBG(("%s: trying blt solid fill [%08lx] paths\n", 11369 __FUNCTION__, gc->fgPixel)); 11370 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11371 ®ion.extents, &damage)) && 11372 sna_poly_rectangle_blt(drawable, bo, damage, 11373 gc, n, r, ®ion.extents, flags&2)) 11374 return; 11375 } else { 11376 /* Not a trivial outline, but we still maybe able to break it 11377 * down into simpler operations that we can accelerate. 11378 */ 11379 if (sna_drawable_use_bo(drawable, PREFER_GPU, 11380 ®ion.extents, &damage)) { 11381 miPolyRectangle(drawable, gc, n, r); 11382 return; 11383 } 11384 } 11385 11386fallback: 11387 DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11388 region_num_rects(gc->pCompositeClip), 11389 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 11390 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2)); 11391 11392 region.data = NULL; 11393 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 11394 return; 11395 11396 DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11397 region_num_rects(®ion), 11398 region.extents.x1, region.extents.y1, 11399 region.extents.x2, region.extents.y2)); 11400 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 11401 goto out; 11402 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 11403 drawable_gc_flags(drawable, gc, true))) 11404 goto out; 11405 11406 if (sigtrap_get() == 0) { 11407 DBG(("%s: miPolyRectangle\n", __FUNCTION__)); 11408 miPolyRectangle(drawable, gc, n, r); 11409 FALLBACK_FLUSH(drawable); 11410 sigtrap_put(); 11411 } 11412out: 11413 sna_gc_move_to_gpu(gc); 11414 RegionUninit(®ion); 11415} 11416 11417static unsigned 11418sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, 11419 int n, xArc *arc, 11420 BoxPtr out) 11421{ 11422 BoxRec box; 11423 bool clipped; 11424 int v; 11425 11426 if (n == 0) 11427 return 0; 11428 11429 box.x1 = arc->x; 11430 box.x2 = bound(box.x1, arc->width); 11431 box.y1 = arc->y; 11432 box.y2 = bound(box.y1, arc->height); 11433 11434 while (--n) { 11435 arc++; 11436 if (box.x1 > arc->x) 11437 box.x1 = arc->x; 11438 v = bound(arc->x, arc->width); 11439 if (box.x2 < v) 11440 box.x2 = v; 11441 if (box.y1 > arc->y) 11442 box.y1 = arc->y; 11443 v = bound(arc->y, arc->height); 11444 if (box.y2 < v) 11445 box.y2 = v; 11446 } 11447 11448 v = gc->lineWidth >> 1; 11449 if (v) { 11450 box.x1 -= v; 11451 box.x2 += v; 11452 box.y1 -= v; 11453 box.y2 += v; 11454 } 11455 11456 box.x2++; 11457 box.y2++; 11458 11459 clipped = trim_and_translate_box(&box, drawable, gc); 11460 if (box_empty(&box)) 11461 return 0; 11462 11463 *out = box; 11464 return 1 | clipped << 1; 11465} 11466 11467static void 11468sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc) 11469{ 11470 struct sna_fill_spans data; 11471 struct sna_pixmap *priv; 11472 11473 DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth)); 11474 11475 data.flags = sna_poly_arc_extents(drawable, gc, n, arc, 11476 &data.region.extents); 11477 if (data.flags == 0) 11478 return; 11479 11480 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11481 data.region.extents.x1, data.region.extents.y1, 11482 data.region.extents.x2, data.region.extents.y2, 11483 data.flags)); 11484 11485 data.region.data = NULL; 11486 11487 if (FORCE_FALLBACK) 11488 goto fallback; 11489 11490 if (!ACCEL_POLY_ARC) 11491 goto fallback; 11492 11493 data.pixmap = get_drawable_pixmap(drawable); 11494 data.sna = to_sna_from_pixmap(data.pixmap); 11495 priv = sna_pixmap(data.pixmap); 11496 if (priv == NULL) { 11497 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11498 goto fallback; 11499 } 11500 11501 if (wedged(data.sna)) { 11502 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11503 goto fallback; 11504 } 11505 11506 if (!PM_IS_SOLID(drawable, gc->planemask)) 11507 goto fallback; 11508 11509 if ((data.bo = sna_drawable_use_bo(drawable, 11510 use_wide_spans(drawable, gc, &data.region.extents), 11511 &data.region.extents, &data.damage))) { 11512 uint32_t color; 11513 11514 DBG(("%s: converting arcs into spans\n", __FUNCTION__)); 11515 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 11516 11517 if (gc_is_solid(gc, &color)) { 11518 sna_gc(gc)->priv = &data; 11519 11520 assert(gc->miTranslate); 11521 if (gc->lineStyle == LineSolid) { 11522 struct sna_fill_op fill; 11523 11524 if (!sna_fill_init_blt(&fill, 11525 data.sna, data.pixmap, 11526 data.bo, gc->alu, color, 11527 FILL_POINTS | FILL_SPANS)) 11528 goto fallback; 11529 11530 if ((data.flags & 2) == 0) { 11531 if (data.dx | data.dy) 11532 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 11533 else 11534 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 11535 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 11536 } else { 11537 if (!region_maybe_clip(&data.region, 11538 gc->pCompositeClip)) 11539 return; 11540 11541 if (region_is_singular(&data.region)) { 11542 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 11543 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 11544 } else { 11545 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 11546 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 11547 } 11548 } 11549 11550 data.op = &fill; 11551 gc->ops = &sna_gc_ops__tmp; 11552 if (gc->lineWidth == 0) 11553 miZeroPolyArc(drawable, gc, n, arc); 11554 else 11555 miPolyArc(drawable, gc, n, arc); 11556 gc->ops = (GCOps *)&sna_gc_ops; 11557 11558 fill.done(data.sna, &fill); 11559 } else { 11560 if (!region_maybe_clip(&data.region, 11561 gc->pCompositeClip)) 11562 return; 11563 11564 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11565 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11566 11567 gc->ops = &sna_gc_ops__tmp; 11568 if (gc->lineWidth == 0) 11569 miZeroPolyArc(drawable, gc, n, arc); 11570 else 11571 miPolyArc(drawable, gc, n, arc); 11572 gc->ops = (GCOps *)&sna_gc_ops; 11573 } 11574 11575 if (data.damage) { 11576 if (data.dx | data.dy) 11577 pixman_region_translate(&data.region, data.dx, data.dy); 11578 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11579 sna_damage_add(data.damage, &data.region); 11580 } 11581 assert_pixmap_damage(data.pixmap); 11582 RegionUninit(&data.region); 11583 return; 11584 } 11585 11586 /* XXX still around 10x slower for x11perf -ellipse */ 11587 if (gc->lineWidth == 0) 11588 miZeroPolyArc(drawable, gc, n, arc); 11589 else 11590 miPolyArc(drawable, gc, n, arc); 11591 return; 11592 } 11593 11594fallback: 11595 DBG(("%s -- fallback\n", __FUNCTION__)); 11596 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11597 return; 11598 11599 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11600 goto out; 11601 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11602 drawable_gc_flags(drawable, gc, true))) 11603 goto out; 11604 11605 if (sigtrap_get() == 0) { 11606 DBG(("%s -- fbPolyArc\n", __FUNCTION__)); 11607 fbPolyArc(drawable, gc, n, arc); 11608 FALLBACK_FLUSH(drawable); 11609 sigtrap_put(); 11610 } 11611out: 11612 sna_gc_move_to_gpu(gc); 11613 RegionUninit(&data.region); 11614} 11615 11616static bool 11617sna_poly_fill_rect_blt(DrawablePtr drawable, 11618 struct kgem_bo *bo, 11619 struct sna_damage **damage, 11620 GCPtr gc, uint32_t pixel, 11621 int n, const xRectangle *rect, 11622 const BoxRec *extents, 11623 bool clipped) 11624{ 11625 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11626 struct sna *sna = to_sna_from_pixmap(pixmap); 11627 struct sna_fill_op fill; 11628 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11629 int16_t dx, dy; 11630 11631 DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n", 11632 __FUNCTION__, pixmap->drawable.serialNumber, n, 11633 rect->x, rect->y, rect->width, rect->height, 11634 drawable->x, drawable->y, 11635 clipped)); 11636 11637 if (n == 1 && region_is_singular(gc->pCompositeClip)) { 11638 BoxRec r; 11639 bool success = true; 11640 11641 r.x1 = rect->x + drawable->x; 11642 r.y1 = rect->y + drawable->y; 11643 r.x2 = bound(r.x1, rect->width); 11644 r.y2 = bound(r.y1, rect->height); 11645 if (box_intersect(&r, &gc->pCompositeClip->extents)) { 11646 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 11647 r.x1 += dx; r.y1 += dy; 11648 r.x2 += dx; r.y2 += dy; 11649 } 11650 DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x\n", 11651 __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel)); 11652 11653 if (sna->render.fill_one(sna, pixmap, bo, pixel, 11654 r.x1, r.y1, r.x2, r.y2, 11655 gc->alu)) { 11656 if (damage) { 11657 assert_pixmap_contains_box(pixmap, &r); 11658 if (r.x2 - r.x1 == pixmap->drawable.width && 11659 r.y2 - r.y1 == pixmap->drawable.height) 11660 sna_damage_all(damage, pixmap); 11661 else 11662 sna_damage_add_box(damage, &r); 11663 } 11664 assert_pixmap_damage(pixmap); 11665 11666 if (alu_overwrites(gc->alu) && 11667 r.x2 - r.x1 == pixmap->drawable.width && 11668 r.y2 - r.y1 == pixmap->drawable.height) { 11669 struct sna_pixmap *priv = sna_pixmap(pixmap); 11670 if (bo == priv->gpu_bo) { 11671 assert(priv->gpu_bo->proxy == NULL); 11672 sna_damage_all(&priv->gpu_damage, pixmap); 11673 sna_damage_destroy(&priv->cpu_damage); 11674 list_del(&priv->flush_list); 11675 priv->clear = true; 11676 priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel; 11677 11678 DBG(("%s: pixmap=%ld, marking clear [%08x]\n", 11679 __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); 11680 } 11681 } 11682 } else 11683 success = false; 11684 } 11685 11686 return success; 11687 } 11688 11689 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) { 11690 DBG(("%s: unsupported blt\n", __FUNCTION__)); 11691 return false; 11692 } 11693 11694 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11695 if (!clipped) { 11696 dx += drawable->x; 11697 dy += drawable->y; 11698 11699 sna_damage_add_rectangles(damage, rect, n, dx, dy); 11700 if (dx|dy) { 11701 do { 11702 unsigned nbox = n; 11703 if (nbox > ARRAY_SIZE(boxes)) 11704 nbox = ARRAY_SIZE(boxes); 11705 n -= nbox; 11706 do { 11707 b->x1 = rect->x + dx; 11708 b->y1 = rect->y + dy; 11709 b->x2 = b->x1 + rect->width; 11710 b->y2 = b->y1 + rect->height; 11711 b++; 11712 rect++; 11713 } while (--nbox); 11714 fill.boxes(sna, &fill, boxes, b-boxes); 11715 b = boxes; 11716 } while (n); 11717 } else { 11718 do { 11719 unsigned nbox = n; 11720 if (nbox > ARRAY_SIZE(boxes)) 11721 nbox = ARRAY_SIZE(boxes); 11722 n -= nbox; 11723 do { 11724 b->x1 = rect->x; 11725 b->y1 = rect->y; 11726 b->x2 = b->x1 + rect->width; 11727 b->y2 = b->y1 + rect->height; 11728 b++; 11729 rect++; 11730 } while (--nbox); 11731 fill.boxes(sna, &fill, boxes, b-boxes); 11732 b = boxes; 11733 } while (n); 11734 } 11735 } else { 11736 RegionRec clip; 11737 11738 region_set(&clip, extents); 11739 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11740 goto done; 11741 11742 if (clip.data == NULL) { 11743 do { 11744 b->x1 = rect->x + drawable->x; 11745 b->y1 = rect->y + drawable->y; 11746 b->x2 = bound(b->x1, rect->width); 11747 b->y2 = bound(b->y1, rect->height); 11748 rect++; 11749 11750 if (box_intersect(b, &clip.extents)) { 11751 b->x1 += dx; 11752 b->x2 += dx; 11753 b->y1 += dy; 11754 b->y2 += dy; 11755 if (++b == last_box) { 11756 fill.boxes(sna, &fill, boxes, last_box-boxes); 11757 if (damage) 11758 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11759 b = boxes; 11760 } 11761 } 11762 } while (--n); 11763 } else { 11764 const BoxRec * const clip_start = RegionBoxptr(&clip); 11765 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11766 const BoxRec *c; 11767 11768 do { 11769 BoxRec box; 11770 11771 box.x1 = rect->x + drawable->x; 11772 box.y1 = rect->y + drawable->y; 11773 box.x2 = bound(box.x1, rect->width); 11774 box.y2 = bound(box.y1, rect->height); 11775 rect++; 11776 11777 c = find_clip_box_for_y(clip_start, 11778 clip_end, 11779 box.y1); 11780 while (c != clip_end) { 11781 if (box.y2 <= c->y1) 11782 break; 11783 11784 *b = box; 11785 if (box_intersect(b, c++)) { 11786 b->x1 += dx; 11787 b->x2 += dx; 11788 b->y1 += dy; 11789 b->y2 += dy; 11790 if (++b == last_box) { 11791 fill.boxes(sna, &fill, boxes, last_box-boxes); 11792 if (damage) 11793 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11794 b = boxes; 11795 } 11796 } 11797 11798 } 11799 } while (--n); 11800 } 11801 11802 RegionUninit(&clip); 11803 if (b != boxes) { 11804 fill.boxes(sna, &fill, boxes, b-boxes); 11805 if (damage) 11806 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11807 } 11808 } 11809done: 11810 fill.done(sna, &fill); 11811 assert_pixmap_damage(pixmap); 11812 return true; 11813} 11814 11815static uint32_t 11816get_pixel(PixmapPtr pixmap) 11817{ 11818 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 11819 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 11820 return 0; 11821 11822 switch (pixmap->drawable.bitsPerPixel) { 11823 case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 11824 case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 11825 default: return *(uint8_t *)pixmap->devPrivate.ptr; 11826 } 11827} 11828 11829static void 11830sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, 11831 int shape, int mode, 11832 int n, DDXPointPtr pt) 11833{ 11834 struct sna_fill_spans data; 11835 struct sna_pixmap *priv; 11836 11837 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 11838 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 11839 (gc->fillStyle == FillSolid || 11840 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 11841 gc->fillStyle, gc->tileIsPixel, 11842 gc->alu)); 11843 DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n", 11844 __FUNCTION__, draw->serialNumber, 11845 draw->x, draw->y, draw->width, draw->height)); 11846 11847 data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, 11848 &data.region.extents); 11849 if (data.flags == 0) { 11850 DBG(("%s, nothing to do\n", __FUNCTION__)); 11851 return; 11852 } 11853 11854 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11855 data.region.extents.x1, data.region.extents.y1, 11856 data.region.extents.x2, data.region.extents.y2, 11857 data.flags)); 11858 11859 data.region.data = NULL; 11860 11861 if (FORCE_FALLBACK) 11862 goto fallback; 11863 11864 if (!ACCEL_POLY_FILL_POLYGON) 11865 goto fallback; 11866 11867 data.pixmap = get_drawable_pixmap(draw); 11868 data.sna = to_sna_from_pixmap(data.pixmap); 11869 priv = sna_pixmap(data.pixmap); 11870 if (priv == NULL) { 11871 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11872 goto fallback; 11873 } 11874 11875 if (wedged(data.sna)) { 11876 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11877 goto fallback; 11878 } 11879 11880 if (!PM_IS_SOLID(draw, gc->planemask)) 11881 goto fallback; 11882 11883 if ((data.bo = sna_drawable_use_bo(draw, 11884 (shape == Convex ? use_zero_spans : use_wide_spans)(draw, gc, &data.region.extents), 11885 &data.region.extents, 11886 &data.damage))) { 11887 uint32_t color; 11888 11889 sna_gc(gc)->priv = &data; 11890 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 11891 11892 if (gc_is_solid(gc, &color)) { 11893 struct sna_fill_op fill; 11894 11895 if (!sna_fill_init_blt(&fill, 11896 data.sna, data.pixmap, 11897 data.bo, gc->alu, color, 11898 FILL_SPANS)) 11899 goto fallback; 11900 11901 data.op = &fill; 11902 11903 if ((data.flags & 2) == 0) { 11904 if (data.dx | data.dy) 11905 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 11906 else 11907 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 11908 } else { 11909 if (!region_maybe_clip(&data.region, 11910 gc->pCompositeClip)) 11911 return; 11912 11913 if (region_is_singular(&data.region)) 11914 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 11915 else 11916 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 11917 } 11918 assert(gc->miTranslate); 11919 gc->ops = &sna_gc_ops__tmp; 11920 11921 miFillPolygon(draw, gc, shape, mode, n, pt); 11922 fill.done(data.sna, &fill); 11923 } else { 11924 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11925 gc->ops = &sna_gc_ops__tmp; 11926 11927 miFillPolygon(draw, gc, shape, mode, n, pt); 11928 } 11929 11930 gc->ops = (GCOps *)&sna_gc_ops; 11931 if (data.damage) { 11932 if (data.dx | data.dy) 11933 pixman_region_translate(&data.region, data.dx, data.dy); 11934 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11935 sna_damage_add(data.damage, &data.region); 11936 } 11937 assert_pixmap_damage(data.pixmap); 11938 RegionUninit(&data.region); 11939 return; 11940 } 11941 11942fallback: 11943 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 11944 data.region.extents.x1, data.region.extents.y1, 11945 data.region.extents.x2, data.region.extents.y2)); 11946 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 11947 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 11948 return; 11949 } 11950 11951 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 11952 goto out; 11953 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 11954 drawable_gc_flags(draw, gc, true))) 11955 goto out; 11956 11957 if (sigtrap_get() == 0) { 11958 DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", 11959 __FUNCTION__)); 11960 miFillPolygon(draw, gc, shape, mode, n, pt); 11961 sigtrap_put(); 11962 } 11963out: 11964 sna_gc_move_to_gpu(gc); 11965 RegionUninit(&data.region); 11966} 11967 11968static struct kgem_bo * 11969sna_pixmap_get_source_bo(PixmapPtr pixmap) 11970{ 11971 struct sna_pixmap *priv = sna_pixmap(pixmap); 11972 unsigned flags; 11973 BoxRec box; 11974 11975 box.x1 = box.y1 = 0; 11976 box.x2 = pixmap->drawable.width; 11977 box.y2 = pixmap->drawable.height; 11978 11979 DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__, 11980 pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 11981 11982 if (priv == NULL) { 11983 DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__)); 11984 return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 11985 pixmap->devPrivate.ptr, &box, 11986 pixmap->devKind, 11987 pixmap->drawable.bitsPerPixel); 11988 } 11989 11990 if (priv->gpu_damage) { 11991 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) 11992 return kgem_bo_reference(priv->gpu_bo); 11993 } else if (priv->cpu_damage) { 11994 if (priv->cpu_bo) 11995 return kgem_bo_reference(priv->cpu_bo); 11996 } else { 11997 if (priv->gpu_bo) 11998 return kgem_bo_reference(priv->gpu_bo); 11999 if (priv->cpu_bo) 12000 return kgem_bo_reference(priv->cpu_bo); 12001 } 12002 12003 flags = MOVE_READ | MOVE_ASYNC_HINT; 12004 if (priv->gpu_bo && priv->gpu_bo->proxy) { 12005 struct kgem_bo *bo = priv->gpu_bo; 12006 if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096)) 12007 flags |= __MOVE_FORCE; 12008 } 12009 if (priv->gpu_bo == NULL) { 12010 if (++priv->source_count > SOURCE_BIAS) 12011 flags |= __MOVE_FORCE; 12012 } 12013 12014 if (!sna_pixmap_move_to_gpu(pixmap, flags)) { 12015 struct kgem_bo *upload; 12016 12017 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12018 return NULL; 12019 12020 upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12021 pixmap->devPrivate.ptr, &box, 12022 pixmap->devKind, 12023 pixmap->drawable.bitsPerPixel); 12024 if (upload == NULL) 12025 return NULL; 12026 12027 if (priv->gpu_bo == NULL) { 12028 DBG(("%s: adding upload cache to pixmap=%ld\n", 12029 __FUNCTION__, pixmap->drawable.serialNumber)); 12030 assert(upload->proxy != NULL); 12031 kgem_proxy_bo_attach(upload, &priv->gpu_bo); 12032 } 12033 12034 return upload; 12035 } 12036 12037 return kgem_bo_reference(priv->gpu_bo); 12038} 12039 12040/* 12041static bool 12042tile(DrawablePtr drawable, 12043 struct kgem_bo *bo, struct sna_damage **damage, 12044 PixmapPtr tile, const DDXPointRec * const origin, int alu, 12045 int n, xRectangle *rect, 12046 const BoxRec *extents, unsigned clipped) 12047 */ 12048 12049static bool 12050sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, 12051 struct kgem_bo *bo, struct sna_damage **damage, 12052 struct kgem_bo *tile_bo, GCPtr gc, 12053 int n, const xRectangle *r, 12054 const BoxRec *extents, unsigned clipped) 12055{ 12056 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12057 struct sna *sna = to_sna_from_pixmap(pixmap); 12058 const DDXPointRec * const origin = &gc->patOrg; 12059 uint32_t br00, br13; 12060 int tx, ty; 12061 int16_t dx, dy; 12062 uint32_t *b; 12063 12064 if (NO_TILE_8x8) 12065 return false; 12066 12067 DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n", 12068 __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y)); 12069 12070 DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch)); 12071 if (tile_bo->tiling) 12072 return false; 12073 12074 assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3); 12075 12076 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12077 if (!kgem_check_batch(&sna->kgem, 10+2*3) || 12078 !kgem_check_reloc(&sna->kgem, 2) || 12079 !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) { 12080 kgem_submit(&sna->kgem); 12081 if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) 12082 return false; 12083 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12084 } 12085 12086 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12087 assert(extents->x1 + dx >= 0); 12088 assert(extents->y1 + dy >= 0); 12089 assert(extents->x2 + dx <= pixmap->drawable.width); 12090 assert(extents->y2 + dy <= pixmap->drawable.height); 12091 12092 br00 = XY_SCANLINE_BLT; 12093 tx = (-drawable->x - dx - origin->x) % 8; 12094 if (tx < 0) 12095 tx += 8; 12096 ty = (-drawable->y - dy - origin->y) % 8; 12097 if (ty < 0) 12098 ty += 8; 12099 br00 |= tx << 12 | ty << 8; 12100 12101 br13 = bo->pitch; 12102 if (sna->kgem.gen >= 040 && bo->tiling) { 12103 br00 |= BLT_DST_TILED; 12104 br13 >>= 2; 12105 } 12106 br13 |= blt_depth(drawable->depth) << 24; 12107 br13 |= fill_ROP[gc->alu] << 16; 12108 12109 if (!clipped) { 12110 dx += drawable->x; 12111 dy += drawable->y; 12112 12113 sna_damage_add_rectangles(damage, r, n, dx, dy); 12114 if (n == 1) { 12115 DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12116 __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty)); 12117 12118 assert(r->x + dx >= 0); 12119 assert(r->y + dy >= 0); 12120 assert(r->x + dx + r->width <= pixmap->drawable.width); 12121 assert(r->y + dy + r->height <= pixmap->drawable.height); 12122 12123 assert(sna->kgem.mode == KGEM_BLT); 12124 b = sna->kgem.batch + sna->kgem.nbatch; 12125 if (sna->kgem.gen >= 0100) { 12126 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6; 12127 b[1] = br13; 12128 b[2] = (r->y + dy) << 16 | (r->x + dx); 12129 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12130 *(uint64_t *)(b+4) = 12131 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12132 I915_GEM_DOMAIN_RENDER << 16 | 12133 I915_GEM_DOMAIN_RENDER | 12134 KGEM_RELOC_FENCED, 12135 0); 12136 *(uint64_t *)(b+6) = 12137 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo, 12138 I915_GEM_DOMAIN_RENDER << 16 | 12139 KGEM_RELOC_FENCED, 12140 0); 12141 sna->kgem.nbatch += 8; 12142 } else { 12143 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4; 12144 b[1] = br13; 12145 b[2] = (r->y + dy) << 16 | (r->x + dx); 12146 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12147 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12148 I915_GEM_DOMAIN_RENDER << 16 | 12149 I915_GEM_DOMAIN_RENDER | 12150 KGEM_RELOC_FENCED, 12151 0); 12152 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo, 12153 I915_GEM_DOMAIN_RENDER << 16 | 12154 KGEM_RELOC_FENCED, 12155 0); 12156 sna->kgem.nbatch += 6; 12157 } 12158 } else do { 12159 int n_this_time; 12160 12161 assert(sna->kgem.mode == KGEM_BLT); 12162 b = sna->kgem.batch + sna->kgem.nbatch; 12163 if (sna->kgem.gen >= 0100) { 12164 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12165 b[1] = br13; 12166 b[2] = 0; 12167 b[3] = 0; 12168 *(uint64_t *)(b+4) = 12169 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12170 I915_GEM_DOMAIN_RENDER << 16 | 12171 I915_GEM_DOMAIN_RENDER | 12172 KGEM_RELOC_FENCED, 12173 0); 12174 b[6] = gc->bgPixel; 12175 b[7] = gc->fgPixel; 12176 *(uint64_t *)(b+8) = 12177 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12178 I915_GEM_DOMAIN_RENDER << 16 | 12179 KGEM_RELOC_FENCED, 12180 0); 12181 sna->kgem.nbatch += 10; 12182 } else { 12183 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12184 b[1] = br13; 12185 b[2] = 0; 12186 b[3] = 0; 12187 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12188 I915_GEM_DOMAIN_RENDER << 16 | 12189 I915_GEM_DOMAIN_RENDER | 12190 KGEM_RELOC_FENCED, 12191 0); 12192 b[5] = gc->bgPixel; 12193 b[6] = gc->fgPixel; 12194 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12195 I915_GEM_DOMAIN_RENDER << 16 | 12196 KGEM_RELOC_FENCED, 12197 0); 12198 sna->kgem.nbatch += 8; 12199 } 12200 12201 n_this_time = n; 12202 if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) 12203 n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3; 12204 assert(n_this_time); 12205 n -= n_this_time; 12206 12207 assert(sna->kgem.mode == KGEM_BLT); 12208 b = sna->kgem.batch + sna->kgem.nbatch; 12209 sna->kgem.nbatch += 3*n_this_time; 12210 do { 12211 assert(r->x + dx >= 0); 12212 assert(r->y + dy >= 0); 12213 assert(r->x + dx + r->width <= pixmap->drawable.width); 12214 assert(r->y + dy + r->height <= pixmap->drawable.height); 12215 12216 b[0] = br00; 12217 b[1] = (r->y + dy) << 16 | (r->x + dx); 12218 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12219 b += 3; r++; 12220 } while (--n_this_time); 12221 12222 if (!n) 12223 break; 12224 12225 _kgem_submit(&sna->kgem); 12226 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12227 } while (1); 12228 } else { 12229 RegionRec clip; 12230 uint16_t unwind_batch, unwind_reloc; 12231 12232 region_set(&clip, extents); 12233 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12234 goto done; 12235 12236 unwind_batch = sna->kgem.nbatch; 12237 unwind_reloc = sna->kgem.nreloc; 12238 12239 assert(sna->kgem.mode == KGEM_BLT); 12240 b = sna->kgem.batch + sna->kgem.nbatch; 12241 if (sna->kgem.gen >= 0100) { 12242 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12243 b[1] = br13; 12244 b[2] = 0; 12245 b[3] = 0; 12246 *(uint64_t *)(b+4) = 12247 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12248 I915_GEM_DOMAIN_RENDER << 16 | 12249 I915_GEM_DOMAIN_RENDER | 12250 KGEM_RELOC_FENCED, 12251 0); 12252 b[6] = gc->bgPixel; 12253 b[7] = gc->fgPixel; 12254 *(uint64_t *)(b+8) = 12255 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12256 I915_GEM_DOMAIN_RENDER << 16 | 12257 KGEM_RELOC_FENCED, 12258 0); 12259 sna->kgem.nbatch += 10; 12260 } else { 12261 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12262 b[1] = br13; 12263 b[2] = 0; 12264 b[3] = 0; 12265 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12266 I915_GEM_DOMAIN_RENDER << 16 | 12267 I915_GEM_DOMAIN_RENDER | 12268 KGEM_RELOC_FENCED, 12269 0); 12270 b[5] = gc->bgPixel; 12271 b[6] = gc->fgPixel; 12272 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12273 I915_GEM_DOMAIN_RENDER << 16 | 12274 KGEM_RELOC_FENCED, 12275 0); 12276 sna->kgem.nbatch += 8; 12277 } 12278 12279 if (clip.data == NULL) { 12280 const BoxRec *c = &clip.extents; 12281 DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n)); 12282 while (n--) { 12283 BoxRec box; 12284 12285 box.x1 = r->x + drawable->x; 12286 box.y1 = r->y + drawable->y; 12287 box.x2 = bound(box.x1, r->width); 12288 box.y2 = bound(box.y1, r->height); 12289 r++; 12290 12291 if (box_intersect(&box, c)) { 12292 if (!kgem_check_batch(&sna->kgem, 3)) { 12293 _kgem_submit(&sna->kgem); 12294 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12295 12296 unwind_batch = sna->kgem.nbatch; 12297 unwind_reloc = sna->kgem.nreloc; 12298 12299 assert(sna->kgem.mode == KGEM_BLT); 12300 b = sna->kgem.batch + sna->kgem.nbatch; 12301 if (sna->kgem.gen >= 0100) { 12302 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12303 b[1] = br13; 12304 b[2] = 0; 12305 b[3] = 0; 12306 *(uint64_t *)(b+4) = 12307 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12308 I915_GEM_DOMAIN_RENDER << 16 | 12309 I915_GEM_DOMAIN_RENDER | 12310 KGEM_RELOC_FENCED, 12311 0); 12312 b[6] = gc->bgPixel; 12313 b[7] = gc->fgPixel; 12314 *(uint64_t *)(b+8) = 12315 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12316 I915_GEM_DOMAIN_RENDER << 16 | 12317 KGEM_RELOC_FENCED, 12318 0); 12319 sna->kgem.nbatch += 10; 12320 } else { 12321 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12322 b[1] = br13; 12323 b[2] = 0; 12324 b[3] = 0; 12325 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12326 I915_GEM_DOMAIN_RENDER << 16 | 12327 I915_GEM_DOMAIN_RENDER | 12328 KGEM_RELOC_FENCED, 12329 0); 12330 b[5] = gc->bgPixel; 12331 b[6] = gc->fgPixel; 12332 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12333 I915_GEM_DOMAIN_RENDER << 16 | 12334 KGEM_RELOC_FENCED, 12335 0); 12336 sna->kgem.nbatch += 8; 12337 } 12338 } 12339 12340 assert(box.x1 + dx >= 0); 12341 assert(box.y1 + dy >= 0); 12342 assert(box.x2 + dx <= pixmap->drawable.width); 12343 assert(box.y2 + dy <= pixmap->drawable.height); 12344 12345 DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12346 __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty)); 12347 12348 assert(sna->kgem.mode == KGEM_BLT); 12349 b = sna->kgem.batch + sna->kgem.nbatch; 12350 b[0] = br00; 12351 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 12352 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 12353 sna->kgem.nbatch += 3; 12354 } 12355 } 12356 } else { 12357 const BoxRec * const clip_start = RegionBoxptr(&clip); 12358 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12359 const BoxRec *c; 12360 12361 DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n)); 12362 do { 12363 BoxRec box; 12364 12365 box.x1 = r->x + drawable->x; 12366 box.y1 = r->y + drawable->y; 12367 box.x2 = bound(box.x1, r->width); 12368 box.y2 = bound(box.y1, r->height); 12369 DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__, 12370 r->x, r->y, r->width, r->height, 12371 box.x1, box.y1, box.x2, box.y2)); 12372 r++; 12373 12374 c = find_clip_box_for_y(clip_start, 12375 clip_end, 12376 box.y1); 12377 while (c != clip_end) { 12378 BoxRec bb; 12379 12380 DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2)); 12381 12382 if (box.y2 <= c->y1) 12383 break; 12384 12385 bb = box; 12386 if (box_intersect(&bb, c++)) { 12387 if (!kgem_check_batch(&sna->kgem, 3)) { 12388 DBG(("%s: emitting split batch\n", __FUNCTION__)); 12389 _kgem_submit(&sna->kgem); 12390 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12391 12392 unwind_batch = sna->kgem.nbatch; 12393 unwind_reloc = sna->kgem.nreloc; 12394 12395 assert(sna->kgem.mode == KGEM_BLT); 12396 b = sna->kgem.batch + sna->kgem.nbatch; 12397 if (sna->kgem.gen >= 0100) { 12398 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12399 b[1] = br13; 12400 b[2] = 0; 12401 b[3] = 0; 12402 *(uint64_t *)(b+4) = 12403 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12404 I915_GEM_DOMAIN_RENDER << 16 | 12405 I915_GEM_DOMAIN_RENDER | 12406 KGEM_RELOC_FENCED, 12407 0); 12408 b[6] = gc->bgPixel; 12409 b[7] = gc->fgPixel; 12410 *(uint64_t *)(b+8) = 12411 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12412 I915_GEM_DOMAIN_RENDER << 16 | 12413 KGEM_RELOC_FENCED, 12414 0); 12415 sna->kgem.nbatch += 10; 12416 } else { 12417 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12418 b[1] = br13; 12419 b[2] = 0; 12420 b[3] = 0; 12421 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12422 I915_GEM_DOMAIN_RENDER << 16 | 12423 I915_GEM_DOMAIN_RENDER | 12424 KGEM_RELOC_FENCED, 12425 0); 12426 b[5] = gc->bgPixel; 12427 b[6] = gc->fgPixel; 12428 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12429 I915_GEM_DOMAIN_RENDER << 16 | 12430 KGEM_RELOC_FENCED, 12431 0); 12432 sna->kgem.nbatch += 8; 12433 } 12434 } 12435 12436 assert(bb.x1 + dx >= 0); 12437 assert(bb.y1 + dy >= 0); 12438 assert(bb.x2 + dx <= pixmap->drawable.width); 12439 assert(bb.y2 + dy <= pixmap->drawable.height); 12440 12441 DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n", 12442 __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y)); 12443 12444 assert(sna->kgem.mode == KGEM_BLT); 12445 b = sna->kgem.batch + sna->kgem.nbatch; 12446 b[0] = br00; 12447 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 12448 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 12449 sna->kgem.nbatch += 3; 12450 } 12451 } 12452 } while (--n); 12453 } 12454 12455 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 12456 sna->kgem.nbatch = unwind_batch; 12457 sna->kgem.nreloc = unwind_reloc; 12458 if (sna->kgem.nbatch == 0) 12459 kgem_bo_pair_undo(&sna->kgem, bo, tile_bo); 12460 } 12461 } 12462done: 12463 assert_pixmap_damage(pixmap); 12464 sna->blt_state.fill_bo = 0; 12465 return true; 12466} 12467 12468static bool tile8(int x) 12469{ 12470 switch(x) { 12471 case 1: 12472 case 2: 12473 case 4: 12474 case 8: 12475 return true; 12476 default: 12477 return false; 12478 } 12479} 12480 12481static int next8(int x, int max) 12482{ 12483 if (x > 2 && x <= 4) 12484 x = 4; 12485 else if (x < 8) 12486 x = 8; 12487 return MIN(x, max); 12488} 12489 12490static bool 12491sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable, 12492 struct kgem_bo *bo, 12493 struct sna_damage **damage, 12494 GCPtr gc, int n, const xRectangle *rect, 12495 const BoxRec *extents, unsigned clipped) 12496{ 12497 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12498 struct sna *sna = to_sna_from_pixmap(pixmap); 12499 PixmapPtr tile = gc->tile.pixmap; 12500 int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel; 12501 const DDXPointRec origin = gc->patOrg; 12502 struct kgem_bo *upload; 12503 bool ret = false; 12504 uint8_t *src; 12505 void *ptr; 12506 12507 tx = 0, tw = tile->drawable.width; 12508 if (!tile8(tw) && tw > extents->x2 - extents->x1) { 12509 tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw; 12510 if (tx < 0) 12511 tx += tw; 12512 tw = next8(extents->x2 - extents->x1, tw); 12513 gc->patOrg.x = extents->x1 - drawable->x; 12514 } 12515 12516 ty = 0, th = tile->drawable.height; 12517 if (!tile8(th) && th > extents->y2 - extents->y1) { 12518 ty = (extents->y1 - gc->patOrg.y - drawable->y) % th; 12519 if (ty < 0) 12520 ty += th; 12521 th = next8(extents->y2 - extents->y1, th); 12522 gc->patOrg.y = extents->y1 - drawable->y; 12523 } 12524 12525 DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__, 12526 tw, th, tx, ty, tile->drawable.width, tile->drawable.height)); 12527 assert(tx < tile->drawable.width && tx >= 0); 12528 assert(ty < tile->drawable.height && ty >= 0); 12529 assert(tw && tw <= 8 && tw <= tile->drawable.width); 12530 assert(is_power_of_two(tw)); 12531 assert(th && th <= 8 && th <= tile->drawable.height); 12532 assert(is_power_of_two(th)); 12533 12534 if (!sna_pixmap_move_to_cpu(tile, MOVE_READ)) 12535 goto out_gc; 12536 12537 assert(tile->devKind); 12538 assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ)); 12539 12540 src = tile->devPrivate.ptr; 12541 src += tile->devKind * ty; 12542 src += tx * bpp/8; 12543 12544 if ((tw | th) == 1) { 12545 uint32_t pixel; 12546 switch (bpp) { 12547 case 32: pixel = *(uint32_t *)src; break; 12548 case 16: pixel = *(uint16_t *)src; break; 12549 default: pixel = *(uint8_t *)src; break; 12550 } 12551 return sna_poly_fill_rect_blt(drawable, bo, damage, 12552 gc, pixel, n, rect, 12553 extents, clipped); 12554 } 12555 12556 upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr); 12557 if (upload == NULL) 12558 goto out_gc; 12559 12560 upload->pitch = bpp; /* for sanity checks */ 12561 12562 if (sigtrap_get() == 0) { 12563 uint8_t *dst = ptr; 12564 if (tx + tw > tile->drawable.width || 12565 ty + th > tile->drawable.height) { 12566 int sy = ty; 12567 src = tile->devPrivate.ptr; 12568 for (h = 0; h < th; h++) { 12569 int sx = tx; 12570 for (w = 0; w < tw; w++) { 12571 memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8); 12572 if (++sx == tile->drawable.width) 12573 sx = 0; 12574 } 12575 w *= bpp/8; 12576 while (w < bpp) { 12577 memcpy(dst+w, dst, w); 12578 w *= 2; 12579 } 12580 if (++sy == tile->drawable.height) 12581 sy = 0; 12582 dst += bpp; 12583 } 12584 while (h < 8) { 12585 memcpy(dst, ptr, bpp*h); 12586 dst += bpp * h; 12587 h *= 2; 12588 } 12589 } else { 12590 for (h = 0; h < th; h++) { 12591 w = tw*bpp/8; 12592 memcpy(dst, src, w); 12593 while (w < bpp) { 12594 memcpy(dst+w, dst, w); 12595 w *= 2; 12596 } 12597 assert(w == bpp); 12598 12599 src += tile->devKind; 12600 dst += bpp; 12601 } 12602 while (h < 8) { 12603 memcpy(dst, ptr, bpp*h); 12604 dst += bpp * h; 12605 h *= 2; 12606 } 12607 assert(h == 8); 12608 } 12609 12610 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12611 upload, gc, n, rect, 12612 extents, clipped); 12613 sigtrap_put(); 12614 } 12615 12616 kgem_bo_destroy(&sna->kgem, upload); 12617out_gc: 12618 gc->patOrg = origin; 12619 return ret; 12620} 12621 12622inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel) 12623{ 12624 PixmapPtr tile = gc->tile.pixmap; 12625 struct sna_pixmap *priv; 12626 12627 if ((tile->drawable.width | tile->drawable.height) == 1) { 12628 DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__)); 12629 *pixel = get_pixel(tile); 12630 return true; 12631 } 12632 12633 priv = sna_pixmap(tile); 12634 if (priv == NULL || !priv->clear) 12635 return false; 12636 12637 DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__)); 12638 *pixel = priv->clear_color; 12639 return true; 12640} 12641 12642static bool 12643sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 12644 struct kgem_bo *bo, 12645 struct sna_damage **damage, 12646 GCPtr gc, int n, xRectangle *rect, 12647 const BoxRec *extents, unsigned clipped) 12648{ 12649 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12650 struct sna *sna = to_sna_from_pixmap(pixmap); 12651 PixmapPtr tile = gc->tile.pixmap; 12652 struct kgem_bo *tile_bo; 12653 const DDXPointRec * const origin = &gc->patOrg; 12654 struct sna_copy_op copy; 12655 CARD32 alu = gc->alu; 12656 int tile_width, tile_height; 12657 int16_t dx, dy; 12658 uint32_t pixel; 12659 12660 DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n", 12661 __FUNCTION__, pixmap->drawable.serialNumber, 12662 n, rect->x, rect->y, rect->width, rect->height, 12663 clipped)); 12664 12665 assert(tile->drawable.depth == drawable->depth); 12666 assert(bo); 12667 12668 if (tile_is_solid(gc, &pixel)) 12669 return sna_poly_fill_rect_blt(drawable, bo, damage, 12670 gc, pixel, 12671 n, rect, 12672 extents, clipped); 12673 12674 /* XXX [248]x[238] tiling can be reduced to a pattern fill. 12675 * Also we can do the lg2 reduction for BLT and use repeat modes for 12676 * RENDER. 12677 */ 12678 12679 tile_width = tile->drawable.width; 12680 tile_height = tile->drawable.height; 12681 if ((tile_width | tile_height) == 8) { 12682 bool ret; 12683 12684 DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__)); 12685 12686 tile_bo = sna_pixmap_get_source_bo(tile); 12687 if (tile_bo == NULL) { 12688 DBG(("%s: unable to move tile go GPU, fallback\n", 12689 __FUNCTION__)); 12690 return false; 12691 } 12692 12693 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12694 tile_bo, gc, n, rect, 12695 extents, clipped); 12696 if (ret) { 12697 kgem_bo_destroy(&sna->kgem, tile_bo); 12698 return true; 12699 } 12700 } else { 12701 int w = tile_width, h = tile_height; 12702 struct sna_pixmap *priv = sna_pixmap(tile); 12703 12704 if (priv == NULL || priv->gpu_damage == NULL) { 12705 w = next8(extents->x2 - extents->x1, w); 12706 h = next8(extents->y2 - extents->y1, h); 12707 } 12708 12709 DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n", 12710 __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1)); 12711 12712 if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) && 12713 sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage, 12714 gc, n, rect, 12715 extents, clipped)) 12716 return true; 12717 12718 tile_bo = sna_pixmap_get_source_bo(tile); 12719 if (tile_bo == NULL) { 12720 DBG(("%s: unable to move tile go GPU, fallback\n", 12721 __FUNCTION__)); 12722 return false; 12723 } 12724 } 12725 12726 if (!sna_copy_init_blt(©, sna, tile, tile_bo, pixmap, bo, alu)) { 12727 DBG(("%s: unsupported blt\n", __FUNCTION__)); 12728 kgem_bo_destroy(&sna->kgem, tile_bo); 12729 return false; 12730 } 12731 12732 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12733 DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n", 12734 __FUNCTION__, pixmap->drawable.serialNumber, dx, dy)); 12735 if (!clipped) { 12736 dx += drawable->x; 12737 dy += drawable->y; 12738 12739 sna_damage_add_rectangles(damage, rect, n, dx, dy); 12740 do { 12741 xRectangle r = *rect++; 12742 int16_t tile_y = (r.y - origin->y) % tile_height; 12743 if (tile_y < 0) 12744 tile_y += tile_height; 12745 12746 assert(r.x + dx >= 0); 12747 assert(r.y + dy >= 0); 12748 assert(r.x + dx + r.width <= pixmap->drawable.width); 12749 assert(r.y + dy + r.height <= pixmap->drawable.height); 12750 12751 r.y += dy; 12752 do { 12753 int16_t width = r.width; 12754 int16_t x = r.x + dx, tile_x; 12755 int16_t h = tile_height - tile_y; 12756 if (h > r.height) 12757 h = r.height; 12758 r.height -= h; 12759 12760 tile_x = (r.x - origin->x) % tile_width; 12761 if (tile_x < 0) 12762 tile_x += tile_width; 12763 12764 do { 12765 int16_t w = tile_width - tile_x; 12766 if (w > width) 12767 w = width; 12768 width -= w; 12769 12770 copy.blt(sna, ©, 12771 tile_x, tile_y, 12772 w, h, 12773 x, r.y); 12774 12775 x += w; 12776 tile_x = 0; 12777 } while (width); 12778 r.y += h; 12779 tile_y = 0; 12780 } while (r.height); 12781 } while (--n); 12782 } else { 12783 RegionRec clip; 12784 12785 region_set(&clip, extents); 12786 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12787 goto done; 12788 12789 if (clip.data == NULL) { 12790 const BoxRec *box = &clip.extents; 12791 DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n", 12792 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 12793 while (n--) { 12794 BoxRec r; 12795 12796 r.x1 = rect->x + drawable->x; 12797 r.y1 = rect->y + drawable->y; 12798 r.x2 = bound(r.x1, rect->width); 12799 r.y2 = bound(r.y1, rect->height); 12800 rect++; 12801 12802 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 12803 __FUNCTION__, r.x1, r.y1, r.x2, r.y2)); 12804 12805 if (box_intersect(&r, box)) { 12806 int height = r.y2 - r.y1; 12807 int dst_y = r.y1; 12808 int tile_y = (r.y1 - drawable->y - origin->y) % tile_height; 12809 if (tile_y < 0) 12810 tile_y += tile_height; 12811 12812 assert(r.x1 + dx >= 0); 12813 assert(r.y1 + dy >= 0); 12814 assert(r.x2 + dx <= pixmap->drawable.width); 12815 assert(r.y2 + dy <= pixmap->drawable.height); 12816 12817 while (height) { 12818 int width = r.x2 - r.x1; 12819 int dst_x = r.x1, tile_x; 12820 int h = tile_height - tile_y; 12821 if (h > height) 12822 h = height; 12823 height -= h; 12824 12825 tile_x = (r.x1 - drawable->x - origin->x) % tile_width; 12826 if (tile_x < 0) 12827 tile_x += tile_width; 12828 12829 while (width > 0) { 12830 int w = tile_width - tile_x; 12831 if (w > width) 12832 w = width; 12833 width -= w; 12834 12835 copy.blt(sna, ©, 12836 tile_x, tile_y, 12837 w, h, 12838 dst_x + dx, dst_y + dy); 12839 if (damage) { 12840 BoxRec b; 12841 12842 b.x1 = dst_x + dx; 12843 b.y1 = dst_y + dy; 12844 b.x2 = b.x1 + w; 12845 b.y2 = b.y1 + h; 12846 12847 assert_pixmap_contains_box(pixmap, &b); 12848 sna_damage_add_box(damage, &b); 12849 } 12850 12851 dst_x += w; 12852 tile_x = 0; 12853 } 12854 dst_y += h; 12855 tile_y = 0; 12856 } 12857 } 12858 } 12859 } else { 12860 while (n--) { 12861 RegionRec region; 12862 const BoxRec *box; 12863 int nbox; 12864 12865 region.extents.x1 = rect->x + drawable->x; 12866 region.extents.y1 = rect->y + drawable->y; 12867 region.extents.x2 = bound(region.extents.x1, rect->width); 12868 region.extents.y2 = bound(region.extents.y1, rect->height); 12869 rect++; 12870 12871 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 12872 __FUNCTION__, 12873 region.extents.x1, 12874 region.extents.y1, 12875 region.extents.x2, 12876 region.extents.y2)); 12877 12878 region.data = NULL; 12879 RegionIntersect(®ion, ®ion, &clip); 12880 12881 assert(region.extents.x1 + dx >= 0); 12882 assert(region.extents.y1 + dy >= 0); 12883 assert(region.extents.x2 + dx <= pixmap->drawable.width); 12884 assert(region.extents.y2 + dy <= pixmap->drawable.height); 12885 12886 nbox = region_num_rects(®ion); 12887 box = region_rects(®ion); 12888 DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox)); 12889 while (nbox--) { 12890 int height = box->y2 - box->y1; 12891 int dst_y = box->y1; 12892 int tile_y = (box->y1 - drawable->y - origin->y) % tile_height; 12893 if (tile_y < 0) 12894 tile_y += tile_height; 12895 12896 while (height) { 12897 int width = box->x2 - box->x1; 12898 int dst_x = box->x1, tile_x; 12899 int h = tile_height - tile_y; 12900 if (h > height) 12901 h = height; 12902 height -= h; 12903 12904 tile_x = (box->x1 - drawable->x - origin->x) % tile_width; 12905 if (tile_x < 0) 12906 tile_x += tile_width; 12907 12908 while (width > 0) { 12909 int w = tile_width - tile_x; 12910 if (w > width) 12911 w = width; 12912 width -= w; 12913 12914 copy.blt(sna, ©, 12915 tile_x, tile_y, 12916 w, h, 12917 dst_x + dx, dst_y + dy); 12918 if (damage) { 12919 BoxRec b; 12920 12921 b.x1 = dst_x + dx; 12922 b.y1 = dst_y + dy; 12923 b.x2 = b.x1 + w; 12924 b.y2 = b.y1 + h; 12925 12926 assert_pixmap_contains_box(pixmap, &b); 12927 sna_damage_add_box(damage, &b); 12928 } 12929 12930 dst_x += w; 12931 tile_x = 0; 12932 } 12933 dst_y += h; 12934 tile_y = 0; 12935 } 12936 box++; 12937 } 12938 12939 RegionUninit(®ion); 12940 } 12941 } 12942 12943 RegionUninit(&clip); 12944 } 12945done: 12946 copy.done(sna, ©); 12947 assert_pixmap_damage(pixmap); 12948 kgem_bo_destroy(&sna->kgem, tile_bo); 12949 return true; 12950} 12951 12952static bool 12953sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, 12954 struct kgem_bo *bo, 12955 struct sna_damage **damage, 12956 GCPtr gc, int n, xRectangle *r, 12957 const BoxRec *extents, unsigned clipped) 12958{ 12959 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12960 struct sna *sna = to_sna_from_pixmap(pixmap); 12961 uint32_t pat[2] = {0, 0}, br00, br13; 12962 int16_t dx, dy; 12963 uint32_t *b; 12964 12965 if (NO_STIPPLE_8x8) 12966 return false; 12967 12968 DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n", 12969 __FUNCTION__, gc->alu, 12970 extents->x1, extents->y1, 12971 extents->x2, extents->y2, 12972 gc->patOrg.x, gc->patOrg.y)); 12973 12974 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12975 { 12976 int px, py; 12977 12978 px = (0 - gc->patOrg.x - drawable->x - dx) % 8; 12979 if (px < 0) 12980 px += 8; 12981 12982 py = (0 - gc->patOrg.y - drawable->y - dy) % 8; 12983 if (py < 0) 12984 py += 8; 12985 DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py)); 12986 12987 br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20; 12988 br13 = bo->pitch; 12989 if (sna->kgem.gen >= 040 && bo->tiling) { 12990 br00 |= BLT_DST_TILED; 12991 br13 >>= 2; 12992 } 12993 br13 |= (gc->fillStyle == FillStippled) << 28; 12994 br13 |= blt_depth(drawable->depth) << 24; 12995 br13 |= fill_ROP[gc->alu] << 16; 12996 } 12997 12998 assert(gc->stipple->devKind); 12999 { 13000 uint8_t *dst = (uint8_t *)pat; 13001 const uint8_t *src = gc->stipple->devPrivate.ptr; 13002 int stride = gc->stipple->devKind; 13003 int j = gc->stipple->drawable.height; 13004 do { 13005 *dst++ = byte_reverse(*src); 13006 src += stride; 13007 } while (--j); 13008 } 13009 13010 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13011 if (!kgem_check_batch(&sna->kgem, 10 + 2*3) || 13012 !kgem_check_bo_fenced(&sna->kgem, bo) || 13013 !kgem_check_reloc(&sna->kgem, 1)) { 13014 kgem_submit(&sna->kgem); 13015 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13016 return false; 13017 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13018 } 13019 13020 if (!clipped) { 13021 dx += drawable->x; 13022 dy += drawable->y; 13023 13024 sna_damage_add_rectangles(damage, r, n, dx, dy); 13025 if (n == 1) { 13026 DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n", 13027 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13028 13029 assert(sna->kgem.mode == KGEM_BLT); 13030 b = sna->kgem.batch + sna->kgem.nbatch; 13031 if (sna->kgem.gen >= 0100) { 13032 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8; 13033 b[1] = br13; 13034 b[2] = (r->y + dy) << 16 | (r->x + dx); 13035 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13036 *(uint64_t *)(b+4) = 13037 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13038 I915_GEM_DOMAIN_RENDER << 16 | 13039 I915_GEM_DOMAIN_RENDER | 13040 KGEM_RELOC_FENCED, 13041 0); 13042 b[6] = gc->bgPixel; 13043 b[7] = gc->fgPixel; 13044 b[8] = pat[0]; 13045 b[9] = pat[1]; 13046 sna->kgem.nbatch += 10; 13047 } else { 13048 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7; 13049 b[1] = br13; 13050 b[2] = (r->y + dy) << 16 | (r->x + dx); 13051 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13052 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13053 I915_GEM_DOMAIN_RENDER << 16 | 13054 I915_GEM_DOMAIN_RENDER | 13055 KGEM_RELOC_FENCED, 13056 0); 13057 b[5] = gc->bgPixel; 13058 b[6] = gc->fgPixel; 13059 b[7] = pat[0]; 13060 b[8] = pat[1]; 13061 sna->kgem.nbatch += 9; 13062 } 13063 } else do { 13064 int n_this_time; 13065 13066 assert(sna->kgem.mode == KGEM_BLT); 13067 b = sna->kgem.batch + sna->kgem.nbatch; 13068 if (sna->kgem.gen >= 0100) { 13069 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13070 b[1] = br13; 13071 b[2] = 0; 13072 b[3] = 0; 13073 *(uint64_t *)(b+4) = 13074 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13075 I915_GEM_DOMAIN_RENDER << 16 | 13076 I915_GEM_DOMAIN_RENDER | 13077 KGEM_RELOC_FENCED, 13078 0); 13079 b[6] = gc->bgPixel; 13080 b[7] = gc->fgPixel; 13081 b[8] = pat[0]; 13082 b[9] = pat[1]; 13083 sna->kgem.nbatch += 10; 13084 } else { 13085 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13086 b[1] = br13; 13087 b[2] = 0; 13088 b[3] = 0; 13089 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13090 I915_GEM_DOMAIN_RENDER << 16 | 13091 I915_GEM_DOMAIN_RENDER | 13092 KGEM_RELOC_FENCED, 13093 0); 13094 b[5] = gc->bgPixel; 13095 b[6] = gc->fgPixel; 13096 b[7] = pat[0]; 13097 b[8] = pat[1]; 13098 sna->kgem.nbatch += 9; 13099 } 13100 13101 n_this_time = n; 13102 if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) 13103 n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3; 13104 assert(n_this_time); 13105 n -= n_this_time; 13106 13107 assert(sna->kgem.mode == KGEM_BLT); 13108 b = sna->kgem.batch + sna->kgem.nbatch; 13109 sna->kgem.nbatch += 3 * n_this_time; 13110 do { 13111 DBG(("%s: rect (%d, %d)x(%d, %d)\n", 13112 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13113 assert(r->x + dx >= 0); 13114 assert(r->y + dy >= 0); 13115 assert(r->x + dx + r->width <= pixmap->drawable.width); 13116 assert(r->y + dy + r->height <= pixmap->drawable.height); 13117 13118 b[0] = br00; 13119 b[1] = (r->y + dy) << 16 | (r->x + dx); 13120 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13121 13122 b += 3; r++; 13123 } while(--n_this_time); 13124 13125 if (!n) 13126 break; 13127 13128 _kgem_submit(&sna->kgem); 13129 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13130 } while (1); 13131 } else { 13132 RegionRec clip; 13133 13134 region_set(&clip, extents); 13135 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13136 return true; 13137 13138 assert(sna->kgem.mode == KGEM_BLT); 13139 b = sna->kgem.batch + sna->kgem.nbatch; 13140 if (sna->kgem.gen >= 0100) { 13141 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13142 b[1] = br13; 13143 b[2] = 0; 13144 b[3] = 0; 13145 *(uint64_t *)(b+4) = 13146 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13147 I915_GEM_DOMAIN_RENDER << 16 | 13148 I915_GEM_DOMAIN_RENDER | 13149 KGEM_RELOC_FENCED, 13150 0); 13151 b[6] = gc->bgPixel; 13152 b[7] = gc->fgPixel; 13153 b[8] = pat[0]; 13154 b[9] = pat[1]; 13155 sna->kgem.nbatch += 10; 13156 } else { 13157 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13158 b[1] = br13; 13159 b[2] = 0; 13160 b[3] = 0; 13161 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13162 I915_GEM_DOMAIN_RENDER << 16 | 13163 I915_GEM_DOMAIN_RENDER | 13164 KGEM_RELOC_FENCED, 13165 0); 13166 b[5] = gc->bgPixel; 13167 b[6] = gc->fgPixel; 13168 b[7] = pat[0]; 13169 b[8] = pat[1]; 13170 sna->kgem.nbatch += 9; 13171 } 13172 13173 if (clip.data == NULL) { 13174 do { 13175 BoxRec box; 13176 13177 box.x1 = r->x + drawable->x; 13178 box.y1 = r->y + drawable->y; 13179 box.x2 = bound(box.x1, r->width); 13180 box.y2 = bound(box.y1, r->height); 13181 r++; 13182 13183 if (box_intersect(&box, &clip.extents)) { 13184 if (!kgem_check_batch(&sna->kgem, 3)) { 13185 _kgem_submit(&sna->kgem); 13186 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13187 13188 assert(sna->kgem.mode == KGEM_BLT); 13189 b = sna->kgem.batch + sna->kgem.nbatch; 13190 if (sna->kgem.gen >= 0100) { 13191 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13192 b[1] = br13; 13193 b[2] = 0; 13194 b[3] = 0; 13195 *(uint64_t *)(b+4) = 13196 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13197 I915_GEM_DOMAIN_RENDER << 16 | 13198 I915_GEM_DOMAIN_RENDER | 13199 KGEM_RELOC_FENCED, 13200 0); 13201 b[6] = gc->bgPixel; 13202 b[7] = gc->fgPixel; 13203 b[8] = pat[0]; 13204 b[9] = pat[1]; 13205 sna->kgem.nbatch += 10; 13206 } else { 13207 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13208 b[1] = br13; 13209 b[2] = 0; 13210 b[3] = 0; 13211 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13212 I915_GEM_DOMAIN_RENDER << 16 | 13213 I915_GEM_DOMAIN_RENDER | 13214 KGEM_RELOC_FENCED, 13215 0); 13216 b[5] = gc->bgPixel; 13217 b[6] = gc->fgPixel; 13218 b[7] = pat[0]; 13219 b[8] = pat[1]; 13220 sna->kgem.nbatch += 9; 13221 } 13222 } 13223 13224 assert(sna->kgem.mode == KGEM_BLT); 13225 b = sna->kgem.batch + sna->kgem.nbatch; 13226 sna->kgem.nbatch += 3; 13227 b[0] = br00; 13228 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 13229 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 13230 } 13231 } while (--n); 13232 } else { 13233 const BoxRec * const clip_start = RegionBoxptr(&clip); 13234 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13235 const BoxRec *c; 13236 13237 do { 13238 BoxRec box; 13239 13240 box.x1 = r->x + drawable->x; 13241 box.y1 = r->y + drawable->y; 13242 box.x2 = bound(box.x1, r->width); 13243 box.y2 = bound(box.y1, r->height); 13244 r++; 13245 13246 c = find_clip_box_for_y(clip_start, 13247 clip_end, 13248 box.y1); 13249 while (c != clip_end) { 13250 BoxRec bb; 13251 if (box.y2 <= c->y1) 13252 break; 13253 13254 bb = box; 13255 if (box_intersect(&bb, c++)) { 13256 if (!kgem_check_batch(&sna->kgem, 3)) { 13257 _kgem_submit(&sna->kgem); 13258 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13259 13260 assert(sna->kgem.mode == KGEM_BLT); 13261 b = sna->kgem.batch + sna->kgem.nbatch; 13262 if (sna->kgem.gen >= 0100) { 13263 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13264 b[1] = br13; 13265 b[2] = 0; 13266 b[3] = 0; 13267 *(uint64_t *)(b+4) = 13268 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13269 I915_GEM_DOMAIN_RENDER << 16 | 13270 I915_GEM_DOMAIN_RENDER | 13271 KGEM_RELOC_FENCED, 13272 0); 13273 b[6] = gc->bgPixel; 13274 b[7] = gc->fgPixel; 13275 b[8] = pat[0]; 13276 b[9] = pat[1]; 13277 sna->kgem.nbatch += 10; 13278 } else { 13279 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13280 b[1] = br13; 13281 b[2] = 0; 13282 b[3] = 0; 13283 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13284 I915_GEM_DOMAIN_RENDER << 16 | 13285 I915_GEM_DOMAIN_RENDER | 13286 KGEM_RELOC_FENCED, 13287 0); 13288 b[5] = gc->bgPixel; 13289 b[6] = gc->fgPixel; 13290 b[7] = pat[0]; 13291 b[8] = pat[1]; 13292 sna->kgem.nbatch += 9; 13293 } 13294 } 13295 13296 assert(sna->kgem.mode == KGEM_BLT); 13297 b = sna->kgem.batch + sna->kgem.nbatch; 13298 sna->kgem.nbatch += 3; 13299 b[0] = br00; 13300 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 13301 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 13302 } 13303 } 13304 } while (--n); 13305 } 13306 } 13307 13308 assert_pixmap_damage(pixmap); 13309 sna->blt_state.fill_bo = 0; 13310 return true; 13311} 13312 13313static bool 13314sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable, 13315 struct kgem_bo *bo, 13316 struct sna_damage **damage, 13317 GCPtr gc, int n, xRectangle *r, 13318 const BoxRec *extents, unsigned clipped) 13319{ 13320 PixmapPtr scratch, stipple; 13321 uint8_t bytes[8], *dst = bytes; 13322 const uint8_t *src, *end; 13323 int j, stride; 13324 bool ret; 13325 13326 DBG(("%s: expanding %dx%d stipple to 8x8\n", 13327 __FUNCTION__, 13328 gc->stipple->drawable.width, 13329 gc->stipple->drawable.height)); 13330 13331 scratch = GetScratchPixmapHeader(drawable->pScreen, 13332 8, 8, 1, 1, 1, bytes); 13333 if (scratch == NullPixmap) 13334 return false; 13335 13336 stipple = gc->stipple; 13337 gc->stipple = scratch; 13338 13339 assert(stipple->devKind); 13340 stride = stipple->devKind; 13341 src = stipple->devPrivate.ptr; 13342 end = src + stride * stipple->drawable.height; 13343 for(j = 0; j < 8; j++) { 13344 switch (stipple->drawable.width) { 13345 case 1: *dst = (*src & 1) * 0xff; break; 13346 case 2: *dst = (*src & 3) * 0x55; break; 13347 case 4: *dst = (*src & 15) * 0x11; break; 13348 case 8: *dst = *src; break; 13349 default: assert(0); break; 13350 } 13351 dst++; 13352 src += stride; 13353 if (src == end) 13354 src = stipple->devPrivate.ptr; 13355 } 13356 13357 ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 13358 gc, n, r, extents, clipped); 13359 13360 gc->stipple = stipple; 13361 FreeScratchPixmapHeader(scratch); 13362 13363 return ret; 13364} 13365 13366static bool 13367sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, 13368 struct kgem_bo *bo, 13369 struct sna_damage **damage, 13370 GCPtr gc, int n, xRectangle *r, 13371 const BoxRec *extents, unsigned clipped) 13372{ 13373 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13374 struct sna *sna = to_sna_from_pixmap(pixmap); 13375 PixmapPtr stipple = gc->stipple; 13376 const DDXPointRec *origin = &gc->patOrg; 13377 int16_t dx, dy; 13378 uint32_t br00, br13; 13379 13380 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__, 13381 extents->x1, extents->y1, 13382 extents->x2, extents->y2, 13383 origin->x, origin->y, 13384 clipped)); 13385 13386 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13387 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13388 13389 br00 = 3 << 20; 13390 br13 = bo->pitch; 13391 if (sna->kgem.gen >= 040 && bo->tiling) { 13392 br00 |= BLT_DST_TILED; 13393 br13 >>= 2; 13394 } 13395 br13 |= (gc->fillStyle == FillStippled) << 29; 13396 br13 |= blt_depth(drawable->depth) << 24; 13397 br13 |= copy_ROP[gc->alu] << 16; 13398 13399 if (!clipped) { 13400 dx += drawable->x; 13401 dy += drawable->y; 13402 13403 sna_damage_add_rectangles(damage, r, n, dx, dy); 13404 do { 13405 int bx1 = (r->x - origin->x) & ~7; 13406 int bx2 = (r->x + r->width - origin->x + 7) & ~7; 13407 int bw = (bx2 - bx1)/8; 13408 int bh = r->height; 13409 int bstride = ALIGN(bw, 2); 13410 int src_stride; 13411 uint8_t *dst, *src; 13412 uint32_t *b; 13413 13414 DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n", 13415 __FUNCTION__, 13416 r->x, r->y, r->width, r->height, 13417 bx1, bx2)); 13418 13419 src_stride = bstride*bh; 13420 assert(src_stride > 0); 13421 if (src_stride <= 128) { 13422 src_stride = ALIGN(src_stride, 8) / 4; 13423 assert(src_stride <= 32); 13424 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13425 !kgem_check_bo_fenced(&sna->kgem, bo) || 13426 !kgem_check_reloc(&sna->kgem, 1)) { 13427 kgem_submit(&sna->kgem); 13428 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13429 return false; 13430 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13431 } 13432 13433 assert(sna->kgem.mode == KGEM_BLT); 13434 b = sna->kgem.batch + sna->kgem.nbatch; 13435 if (sna->kgem.gen >= 0100) { 13436 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13437 b[0] |= ((r->x - origin->x) & 7) << 17; 13438 b[1] = br13; 13439 b[2] = (r->y + dy) << 16 | (r->x + dx); 13440 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13441 *(uint64_t *)(b+4) = 13442 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13443 I915_GEM_DOMAIN_RENDER << 16 | 13444 I915_GEM_DOMAIN_RENDER | 13445 KGEM_RELOC_FENCED, 13446 0); 13447 b[6] = gc->bgPixel; 13448 b[7] = gc->fgPixel; 13449 13450 dst = (uint8_t *)&b[8]; 13451 sna->kgem.nbatch += 8 + src_stride; 13452 } else { 13453 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13454 b[0] |= ((r->x - origin->x) & 7) << 17; 13455 b[1] = br13; 13456 b[2] = (r->y + dy) << 16 | (r->x + dx); 13457 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13458 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13459 I915_GEM_DOMAIN_RENDER << 16 | 13460 I915_GEM_DOMAIN_RENDER | 13461 KGEM_RELOC_FENCED, 13462 0); 13463 b[5] = gc->bgPixel; 13464 b[6] = gc->fgPixel; 13465 13466 dst = (uint8_t *)&b[7]; 13467 sna->kgem.nbatch += 7 + src_stride; 13468 } 13469 assert(stipple->devKind); 13470 src_stride = stipple->devKind; 13471 src = stipple->devPrivate.ptr; 13472 src += (r->y - origin->y) * src_stride + bx1/8; 13473 src_stride -= bstride; 13474 do { 13475 int i = bstride; 13476 do { 13477 *dst++ = byte_reverse(*src++); 13478 *dst++ = byte_reverse(*src++); 13479 i -= 2; 13480 } while (i); 13481 src += src_stride; 13482 } while (--bh); 13483 } else { 13484 struct kgem_bo *upload; 13485 void *ptr; 13486 13487 if (!kgem_check_batch(&sna->kgem, 10) || 13488 !kgem_check_bo_fenced(&sna->kgem, bo) || 13489 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13490 kgem_submit(&sna->kgem); 13491 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13492 return false; 13493 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13494 } 13495 13496 upload = kgem_create_buffer(&sna->kgem, 13497 bstride*bh, 13498 KGEM_BUFFER_WRITE_INPLACE, 13499 &ptr); 13500 if (!upload) 13501 break; 13502 13503 if (sigtrap_get() == 0) { 13504 dst = ptr; 13505 assert(stipple->devKind); 13506 src_stride = stipple->devKind; 13507 src = stipple->devPrivate.ptr; 13508 src += (r->y - origin->y) * src_stride + bx1/8; 13509 src_stride -= bstride; 13510 do { 13511 int i = bstride; 13512 do { 13513 *dst++ = byte_reverse(*src++); 13514 *dst++ = byte_reverse(*src++); 13515 i -= 2; 13516 } while (i); 13517 src += src_stride; 13518 } while (--bh); 13519 13520 assert(sna->kgem.mode == KGEM_BLT); 13521 b = sna->kgem.batch + sna->kgem.nbatch; 13522 if (sna->kgem.gen >= 0100) { 13523 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13524 b[0] |= ((r->x - origin->x) & 7) << 17; 13525 b[1] = br13; 13526 b[2] = (r->y + dy) << 16 | (r->x + dx); 13527 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13528 *(uint64_t *)(b+4) = 13529 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13530 I915_GEM_DOMAIN_RENDER << 16 | 13531 I915_GEM_DOMAIN_RENDER | 13532 KGEM_RELOC_FENCED, 13533 0); 13534 *(uint64_t *)(b+6) = 13535 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13536 I915_GEM_DOMAIN_RENDER << 16 | 13537 KGEM_RELOC_FENCED, 13538 0); 13539 b[8] = gc->bgPixel; 13540 b[9] = gc->fgPixel; 13541 sna->kgem.nbatch += 10; 13542 } else { 13543 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13544 b[0] |= ((r->x - origin->x) & 7) << 17; 13545 b[1] = br13; 13546 b[2] = (r->y + dy) << 16 | (r->x + dx); 13547 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13548 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13549 I915_GEM_DOMAIN_RENDER << 16 | 13550 I915_GEM_DOMAIN_RENDER | 13551 KGEM_RELOC_FENCED, 13552 0); 13553 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13554 I915_GEM_DOMAIN_RENDER << 16 | 13555 KGEM_RELOC_FENCED, 13556 0); 13557 b[6] = gc->bgPixel; 13558 b[7] = gc->fgPixel; 13559 13560 sna->kgem.nbatch += 8; 13561 } 13562 sigtrap_put(); 13563 } 13564 13565 kgem_bo_destroy(&sna->kgem, upload); 13566 } 13567 13568 r++; 13569 } while (--n); 13570 } else { 13571 RegionRec clip; 13572 DDXPointRec pat; 13573 13574 region_set(&clip, extents); 13575 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13576 return true; 13577 13578 pat.x = origin->x + drawable->x; 13579 pat.y = origin->y + drawable->y; 13580 13581 if (clip.data == NULL) { 13582 do { 13583 BoxRec box; 13584 int bx1, bx2, bw, bh, bstride; 13585 int src_stride; 13586 uint8_t *dst, *src; 13587 uint32_t *b; 13588 struct kgem_bo *upload; 13589 void *ptr; 13590 13591 box.x1 = r->x + drawable->x; 13592 box.x2 = bound(box.x1, r->width); 13593 box.y1 = r->y + drawable->y; 13594 box.y2 = bound(box.y1, r->height); 13595 r++; 13596 13597 if (!box_intersect(&box, &clip.extents)) 13598 continue; 13599 13600 bx1 = (box.x1 - pat.x) & ~7; 13601 bx2 = (box.x2 - pat.x + 7) & ~7; 13602 bw = (bx2 - bx1)/8; 13603 bh = box.y2 - box.y1; 13604 bstride = ALIGN(bw, 2); 13605 13606 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n", 13607 __FUNCTION__, 13608 r->x, r->y, r->width, r->height, 13609 box.x1, box.y1, box.x2, box.y2, 13610 bx1, bx2, bw, bstride)); 13611 13612 src_stride = bstride*bh; 13613 assert(src_stride > 0); 13614 if (src_stride <= 128) { 13615 src_stride = ALIGN(src_stride, 8) / 4; 13616 assert(src_stride <= 32); 13617 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13618 !kgem_check_bo_fenced(&sna->kgem, bo) || 13619 !kgem_check_reloc(&sna->kgem, 1)) { 13620 kgem_submit(&sna->kgem); 13621 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13622 return false; 13623 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13624 } 13625 13626 assert(sna->kgem.mode == KGEM_BLT); 13627 b = sna->kgem.batch + sna->kgem.nbatch; 13628 if (sna->kgem.gen >= 0100) { 13629 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13630 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13631 b[1] = br13; 13632 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13633 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13634 *(uint64_t *)(b+4) = 13635 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13636 I915_GEM_DOMAIN_RENDER << 16 | 13637 I915_GEM_DOMAIN_RENDER | 13638 KGEM_RELOC_FENCED, 13639 0); 13640 b[6] = gc->bgPixel; 13641 b[7] = gc->fgPixel; 13642 13643 dst = (uint8_t *)&b[8]; 13644 sna->kgem.nbatch += 8 + src_stride; 13645 } else { 13646 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13647 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13648 b[1] = br13; 13649 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13650 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13651 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13652 I915_GEM_DOMAIN_RENDER << 16 | 13653 I915_GEM_DOMAIN_RENDER | 13654 KGEM_RELOC_FENCED, 13655 0); 13656 b[5] = gc->bgPixel; 13657 b[6] = gc->fgPixel; 13658 13659 dst = (uint8_t *)&b[7]; 13660 sna->kgem.nbatch += 7 + src_stride; 13661 } 13662 13663 assert(stipple->devKind); 13664 src_stride = stipple->devKind; 13665 src = stipple->devPrivate.ptr; 13666 src += (box.y1 - pat.y) * src_stride + bx1/8; 13667 src_stride -= bstride; 13668 do { 13669 int i = bstride; 13670 do { 13671 *dst++ = byte_reverse(*src++); 13672 *dst++ = byte_reverse(*src++); 13673 i -= 2; 13674 } while (i); 13675 src += src_stride; 13676 } while (--bh); 13677 } else { 13678 if (!kgem_check_batch(&sna->kgem, 10) || 13679 !kgem_check_bo_fenced(&sna->kgem, bo) || 13680 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13681 kgem_submit(&sna->kgem); 13682 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13683 return false; 13684 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13685 } 13686 13687 upload = kgem_create_buffer(&sna->kgem, 13688 bstride*bh, 13689 KGEM_BUFFER_WRITE_INPLACE, 13690 &ptr); 13691 if (!upload) 13692 break; 13693 13694 if (sigtrap_get() == 0) { 13695 dst = ptr; 13696 assert(stipple->devKind); 13697 src_stride = stipple->devKind; 13698 src = stipple->devPrivate.ptr; 13699 src += (box.y1 - pat.y) * src_stride + bx1/8; 13700 src_stride -= bstride; 13701 do { 13702 int i = bstride; 13703 do { 13704 *dst++ = byte_reverse(*src++); 13705 *dst++ = byte_reverse(*src++); 13706 i -= 2; 13707 } while (i); 13708 src += src_stride; 13709 } while (--bh); 13710 13711 assert(sna->kgem.mode == KGEM_BLT); 13712 b = sna->kgem.batch + sna->kgem.nbatch; 13713 if (sna->kgem.gen >= 0100) { 13714 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13715 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13716 b[1] = br13; 13717 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13718 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13719 *(uint64_t *)(b+4) = 13720 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13721 I915_GEM_DOMAIN_RENDER << 16 | 13722 I915_GEM_DOMAIN_RENDER | 13723 KGEM_RELOC_FENCED, 13724 0); 13725 *(uint64_t *)(b+5) = 13726 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13727 I915_GEM_DOMAIN_RENDER << 16 | 13728 KGEM_RELOC_FENCED, 13729 0); 13730 b[8] = gc->bgPixel; 13731 b[9] = gc->fgPixel; 13732 sna->kgem.nbatch += 10; 13733 } else { 13734 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13735 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13736 b[1] = br13; 13737 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13738 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13739 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13740 I915_GEM_DOMAIN_RENDER << 16 | 13741 I915_GEM_DOMAIN_RENDER | 13742 KGEM_RELOC_FENCED, 13743 0); 13744 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13745 I915_GEM_DOMAIN_RENDER << 16 | 13746 KGEM_RELOC_FENCED, 13747 0); 13748 b[6] = gc->bgPixel; 13749 b[7] = gc->fgPixel; 13750 13751 sna->kgem.nbatch += 8; 13752 } 13753 sigtrap_put(); 13754 } 13755 kgem_bo_destroy(&sna->kgem, upload); 13756 } 13757 } while (--n); 13758 } else { 13759 const BoxRec * const clip_start = RegionBoxptr(&clip); 13760 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13761 const BoxRec *c; 13762 13763 do { 13764 BoxRec unclipped; 13765 int bx1, bx2, bw, bh, bstride; 13766 int src_stride; 13767 uint8_t *dst, *src; 13768 uint32_t *b; 13769 struct kgem_bo *upload; 13770 void *ptr; 13771 13772 unclipped.x1 = r->x + drawable->x; 13773 unclipped.x2 = bound(unclipped.x1, r->width); 13774 unclipped.y1 = r->y + drawable->y; 13775 unclipped.y2 = bound(unclipped.y1, r->height); 13776 r++; 13777 13778 c = find_clip_box_for_y(clip_start, 13779 clip_end, 13780 unclipped.y1); 13781 while (c != clip_end) { 13782 BoxRec box; 13783 13784 if (unclipped.y2 <= c->y1) 13785 break; 13786 13787 box = unclipped; 13788 if (!box_intersect(&box, c++)) 13789 continue; 13790 13791 bx1 = (box.x1 - pat.x) & ~7; 13792 bx2 = (box.x2 - pat.x + 7) & ~7; 13793 bw = (bx2 - bx1)/8; 13794 bh = box.y2 - box.y1; 13795 bstride = ALIGN(bw, 2); 13796 13797 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n", 13798 __FUNCTION__, 13799 r->x, r->y, r->width, r->height, 13800 box.x1, box.y1, box.x2, box.y2, 13801 bx1, bx2)); 13802 13803 src_stride = bstride*bh; 13804 assert(src_stride > 0); 13805 if (src_stride <= 128) { 13806 src_stride = ALIGN(src_stride, 8) / 4; 13807 assert(src_stride <= 32); 13808 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13809 !kgem_check_bo_fenced(&sna->kgem, bo) || 13810 !kgem_check_reloc(&sna->kgem, 1)) { 13811 kgem_submit(&sna->kgem); 13812 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13813 return false; 13814 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13815 } 13816 13817 assert(sna->kgem.mode == KGEM_BLT); 13818 b = sna->kgem.batch + sna->kgem.nbatch; 13819 if (sna->kgem.gen >= 0100) { 13820 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13821 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13822 b[1] = br13; 13823 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13824 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13825 *(uint64_t *)(b+4) = 13826 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13827 I915_GEM_DOMAIN_RENDER << 16 | 13828 I915_GEM_DOMAIN_RENDER | 13829 KGEM_RELOC_FENCED, 13830 0); 13831 b[6] = gc->bgPixel; 13832 b[7] = gc->fgPixel; 13833 13834 dst = (uint8_t *)&b[8]; 13835 sna->kgem.nbatch += 8 + src_stride; 13836 } else { 13837 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13838 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13839 b[1] = br13; 13840 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13841 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13842 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13843 I915_GEM_DOMAIN_RENDER << 16 | 13844 I915_GEM_DOMAIN_RENDER | 13845 KGEM_RELOC_FENCED, 13846 0); 13847 b[5] = gc->bgPixel; 13848 b[6] = gc->fgPixel; 13849 13850 dst = (uint8_t *)&b[7]; 13851 sna->kgem.nbatch += 7 + src_stride; 13852 } 13853 assert(stipple->devKind); 13854 src_stride = stipple->devKind; 13855 src = stipple->devPrivate.ptr; 13856 src += (box.y1 - pat.y) * src_stride + bx1/8; 13857 src_stride -= bstride; 13858 do { 13859 int i = bstride; 13860 do { 13861 *dst++ = byte_reverse(*src++); 13862 *dst++ = byte_reverse(*src++); 13863 i -= 2; 13864 } while (i); 13865 src += src_stride; 13866 } while (--bh); 13867 } else { 13868 if (!kgem_check_batch(&sna->kgem, 10) || 13869 !kgem_check_bo_fenced(&sna->kgem, bo) || 13870 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13871 kgem_submit(&sna->kgem); 13872 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13873 return false; 13874 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13875 } 13876 13877 upload = kgem_create_buffer(&sna->kgem, 13878 bstride*bh, 13879 KGEM_BUFFER_WRITE_INPLACE, 13880 &ptr); 13881 if (!upload) 13882 break; 13883 13884 if (sigtrap_get() == 0) { 13885 dst = ptr; 13886 assert(stipple->devKind); 13887 src_stride = stipple->devKind; 13888 src = stipple->devPrivate.ptr; 13889 src += (box.y1 - pat.y) * src_stride + bx1/8; 13890 src_stride -= bstride; 13891 do { 13892 int i = bstride; 13893 do { 13894 *dst++ = byte_reverse(*src++); 13895 *dst++ = byte_reverse(*src++); 13896 i -= 2; 13897 } while (i); 13898 src += src_stride; 13899 } while (--bh); 13900 13901 assert(sna->kgem.mode == KGEM_BLT); 13902 b = sna->kgem.batch + sna->kgem.nbatch; 13903 if (sna->kgem.gen >= 0100) { 13904 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13905 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13906 b[1] = br13; 13907 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13908 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13909 *(uint64_t *)(b+4) = 13910 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13911 I915_GEM_DOMAIN_RENDER << 16 | 13912 I915_GEM_DOMAIN_RENDER | 13913 KGEM_RELOC_FENCED, 13914 0); 13915 *(uint64_t *)(b+6) = 13916 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13917 I915_GEM_DOMAIN_RENDER << 16 | 13918 KGEM_RELOC_FENCED, 13919 0); 13920 b[8] = gc->bgPixel; 13921 b[9] = gc->fgPixel; 13922 sna->kgem.nbatch += 10; 13923 } else { 13924 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13925 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13926 b[1] = br13; 13927 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13928 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13929 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13930 I915_GEM_DOMAIN_RENDER << 16 | 13931 I915_GEM_DOMAIN_RENDER | 13932 KGEM_RELOC_FENCED, 13933 0); 13934 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13935 I915_GEM_DOMAIN_RENDER << 16 | 13936 KGEM_RELOC_FENCED, 13937 0); 13938 b[6] = gc->bgPixel; 13939 b[7] = gc->fgPixel; 13940 13941 sna->kgem.nbatch += 8; 13942 } 13943 sigtrap_put(); 13944 } 13945 kgem_bo_destroy(&sna->kgem, upload); 13946 } 13947 } 13948 } while (--n); 13949 13950 } 13951 } 13952 13953 sna->blt_state.fill_bo = 0; 13954 return true; 13955} 13956 13957static void 13958sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, 13959 struct kgem_bo *bo, 13960 uint32_t br00, uint32_t br13, 13961 const GC *gc, 13962 const BoxRec *box, 13963 const DDXPointRec *origin) 13964{ 13965 int x1, x2, y1, y2; 13966 uint32_t *b; 13967 13968 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 13969 int oy = (y1 - origin->y) % gc->stipple->drawable.height; 13970 if (oy < 0) 13971 oy += gc->stipple->drawable.height; 13972 13973 y2 = box->y2; 13974 if (y2 - y1 > gc->stipple->drawable.height - oy) 13975 y2 = y1 + gc->stipple->drawable.height - oy; 13976 13977 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 13978 int bx1, bx2, bw, bh, len, ox; 13979 uint8_t *dst, *src; 13980 13981 x2 = box->x2; 13982 ox = (x1 - origin->x) % gc->stipple->drawable.width; 13983 if (ox < 0) 13984 ox += gc->stipple->drawable.width; 13985 bx1 = ox & ~7; 13986 bx2 = ox + (x2 - x1); 13987 if (bx2 > gc->stipple->drawable.width) { 13988 bx2 = gc->stipple->drawable.width; 13989 x2 = x1 + bx2-ox; 13990 } 13991 bw = (bx2 - bx1 + 7)/8; 13992 bw = ALIGN(bw, 2); 13993 bh = y2 - y1; 13994 13995 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n", 13996 __FUNCTION__, 13997 x1, y1, x2-x1, y2-y1, 13998 origin->x, origin->y, 13999 ox, oy, bx1, bx2, 14000 gc->stipple->drawable.width, 14001 gc->stipple->drawable.height)); 14002 14003 len = bw*bh; 14004 len = ALIGN(len, 8) / 4; 14005 assert(len > 0); 14006 assert(len <= 32); 14007 if (!kgem_check_batch(&sna->kgem, 8+len) || 14008 !kgem_check_bo_fenced(&sna->kgem, bo) || 14009 !kgem_check_reloc(&sna->kgem, 1)) { 14010 kgem_submit(&sna->kgem); 14011 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14012 return; /* XXX fallback? */ 14013 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14014 } 14015 14016 assert(sna->kgem.mode == KGEM_BLT); 14017 b = sna->kgem.batch + sna->kgem.nbatch; 14018 if (sna->kgem.gen >= 0100) { 14019 b[0] = br00 | (6 + len) | (ox & 7) << 17; 14020 b[1] = br13; 14021 b[2] = y1 << 16 | x1; 14022 b[3] = y2 << 16 | x2; 14023 *(uint64_t *)(b+4) = 14024 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14025 I915_GEM_DOMAIN_RENDER << 16 | 14026 I915_GEM_DOMAIN_RENDER | 14027 KGEM_RELOC_FENCED, 14028 0); 14029 b[6] = gc->bgPixel; 14030 b[7] = gc->fgPixel; 14031 dst = (uint8_t *)&b[8]; 14032 sna->kgem.nbatch += 8 + len; 14033 } else { 14034 b[0] = br00 | (5 + len) | (ox & 7) << 17; 14035 b[1] = br13; 14036 b[2] = y1 << 16 | x1; 14037 b[3] = y2 << 16 | x2; 14038 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14039 I915_GEM_DOMAIN_RENDER << 16 | 14040 I915_GEM_DOMAIN_RENDER | 14041 KGEM_RELOC_FENCED, 14042 0); 14043 b[5] = gc->bgPixel; 14044 b[6] = gc->fgPixel; 14045 dst = (uint8_t *)&b[7]; 14046 sna->kgem.nbatch += 7 + len; 14047 } 14048 14049 assert(gc->stipple->devKind); 14050 len = gc->stipple->devKind; 14051 src = gc->stipple->devPrivate.ptr; 14052 src += oy*len + ox/8; 14053 len -= bw; 14054 do { 14055 int i = bw; 14056 do { 14057 *dst++ = byte_reverse(*src++); 14058 *dst++ = byte_reverse(*src++); 14059 i -= 2; 14060 } while (i); 14061 src += len; 14062 } while (--bh); 14063 } 14064 } 14065} 14066 14067static void 14068sna_poly_fill_rect_stippled_n_box(struct sna *sna, 14069 struct kgem_bo *bo, 14070 struct kgem_bo **tile, 14071 uint32_t br00, uint32_t br13, 14072 const GC *gc, 14073 const BoxRec *box, 14074 const DDXPointRec *origin) 14075{ 14076 int x1, x2, y1, y2; 14077 int w = gc->stipple->drawable.width; 14078 int h = gc->stipple->drawable.height; 14079 int stride = gc->stipple->devKind; 14080 uint32_t *b; 14081 14082 assert(stride); 14083 if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) { 14084 br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20)); 14085 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14086 br00, br13, gc, 14087 box, origin); 14088 return; 14089 } 14090 14091 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14092 int row, oy = (y1 - origin->y) % gc->stipple->drawable.height; 14093 if (oy < 0) 14094 oy += h; 14095 14096 y2 = box->y2; 14097 if (y2 - y1 > h - oy) 14098 y2 = y1 + h - oy; 14099 14100 row = oy * stride; 14101 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14102 int bx1, bx2, bw, bh, len, ox; 14103 bool use_tile; 14104 14105 x2 = box->x2; 14106 ox = (x1 - origin->x) % w; 14107 if (ox < 0) 14108 ox += w; 14109 bx1 = ox & ~7; 14110 bx2 = ox + (x2 - x1); 14111 if (bx2 > w) { 14112 bx2 = w; 14113 x2 = x1 + bx2-ox; 14114 } 14115 14116 use_tile = y2-y1 == h && x2-x1 == w; 14117 14118 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n", 14119 __FUNCTION__, 14120 x1, y1, x2-x1, y2-y1, 14121 origin->x, origin->y, 14122 ox, oy, bx1, bx2, w, h, 14123 use_tile)); 14124 14125 bw = (bx2 - bx1 + 7)/8; 14126 bw = ALIGN(bw, 2); 14127 bh = y2 - y1; 14128 14129 len = bw*bh; 14130 len = ALIGN(len, 8) / 4; 14131 assert(len > 0); 14132 if (!kgem_check_batch(&sna->kgem, 8+len) || 14133 !kgem_check_bo_fenced(&sna->kgem, bo) || 14134 !kgem_check_reloc(&sna->kgem, 2)) { 14135 kgem_submit(&sna->kgem); 14136 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14137 return; /* XXX fallback? */ 14138 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14139 } 14140 14141 assert(sna->kgem.mode == KGEM_BLT); 14142 b = sna->kgem.batch + sna->kgem.nbatch; 14143 14144 if (!use_tile && len <= 32) { 14145 uint8_t *dst, *src; 14146 14147 if (sna->kgem.gen >= 0100) { 14148 b[0] = XY_MONO_SRC_COPY_IMM; 14149 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14150 b[0] |= (ox & 7) << 17; 14151 b[0] |= (6 + len); 14152 b[1] = br13; 14153 b[2] = y1 << 16 | x1; 14154 b[3] = y2 << 16 | x2; 14155 *(uint64_t *)(b+4) = 14156 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14157 I915_GEM_DOMAIN_RENDER << 16 | 14158 I915_GEM_DOMAIN_RENDER | 14159 KGEM_RELOC_FENCED, 14160 0); 14161 b[6] = gc->bgPixel; 14162 b[7] = gc->fgPixel; 14163 14164 dst = (uint8_t *)&b[8]; 14165 sna->kgem.nbatch += 8 + len; 14166 } else { 14167 b[0] = XY_MONO_SRC_COPY_IMM; 14168 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14169 b[0] |= (ox & 7) << 17; 14170 b[0] |= (5 + len); 14171 b[1] = br13; 14172 b[2] = y1 << 16 | x1; 14173 b[3] = y2 << 16 | x2; 14174 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14175 I915_GEM_DOMAIN_RENDER << 16 | 14176 I915_GEM_DOMAIN_RENDER | 14177 KGEM_RELOC_FENCED, 14178 0); 14179 b[5] = gc->bgPixel; 14180 b[6] = gc->fgPixel; 14181 14182 dst = (uint8_t *)&b[7]; 14183 sna->kgem.nbatch += 7 + len; 14184 } 14185 14186 assert(gc->stipple->devKind); 14187 len = gc->stipple->devKind; 14188 src = gc->stipple->devPrivate.ptr; 14189 src += oy*len + ox/8; 14190 len -= bw; 14191 do { 14192 int i = bw; 14193 do { 14194 *dst++ = byte_reverse(*src++); 14195 *dst++ = byte_reverse(*src++); 14196 i -= 2; 14197 } while (i); 14198 src += len; 14199 } while (--bh); 14200 } else { 14201 bool has_tile = use_tile && *tile; 14202 struct kgem_bo *upload; 14203 uint8_t *dst, *src; 14204 void *ptr; 14205 14206 if (has_tile) { 14207 upload = kgem_bo_reference(*tile); 14208 } else { 14209 upload = kgem_create_buffer(&sna->kgem, bw*bh, 14210 KGEM_BUFFER_WRITE_INPLACE, 14211 &ptr); 14212 if (!upload) 14213 return; 14214 } 14215 14216 assert(sna->kgem.mode == KGEM_BLT); 14217 b = sna->kgem.batch + sna->kgem.nbatch; 14218 if (sna->kgem.gen >= 0100) { 14219 b[0] = br00 | (ox & 7) << 17 | 8; 14220 b[1] = br13; 14221 b[2] = y1 << 16 | x1; 14222 b[3] = y2 << 16 | x2; 14223 *(uint64_t *)(b+4) = 14224 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14225 I915_GEM_DOMAIN_RENDER << 16 | 14226 I915_GEM_DOMAIN_RENDER | 14227 KGEM_RELOC_FENCED, 14228 0); 14229 *(uint64_t *)(b+6) = 14230 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14231 I915_GEM_DOMAIN_RENDER << 16 | 14232 KGEM_RELOC_FENCED, 14233 0); 14234 b[8] = gc->bgPixel; 14235 b[9] = gc->fgPixel; 14236 sna->kgem.nbatch += 10; 14237 } else { 14238 b[0] = br00 | (ox & 7) << 17 | 6; 14239 b[1] = br13; 14240 b[2] = y1 << 16 | x1; 14241 b[3] = y2 << 16 | x2; 14242 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14243 I915_GEM_DOMAIN_RENDER << 16 | 14244 I915_GEM_DOMAIN_RENDER | 14245 KGEM_RELOC_FENCED, 14246 0); 14247 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14248 I915_GEM_DOMAIN_RENDER << 16 | 14249 KGEM_RELOC_FENCED, 14250 0); 14251 b[6] = gc->bgPixel; 14252 b[7] = gc->fgPixel; 14253 sna->kgem.nbatch += 8; 14254 } 14255 14256 if (!has_tile) { 14257 dst = ptr; 14258 len = stride; 14259 src = gc->stipple->devPrivate.ptr; 14260 src += row + (ox >> 3); 14261 len -= bw; 14262 do { 14263 int i = bw; 14264 do { 14265 *dst++ = byte_reverse(*src++); 14266 *dst++ = byte_reverse(*src++); 14267 i -= 2; 14268 } while (i); 14269 src += len; 14270 } while (--bh); 14271 if (use_tile) 14272 *tile = kgem_bo_reference(upload); 14273 } 14274 14275 kgem_bo_destroy(&sna->kgem, upload); 14276 } 14277 } 14278 } 14279} 14280 14281static bool 14282sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, 14283 struct kgem_bo *bo, 14284 struct sna_damage **damage, 14285 GCPtr gc, int n, xRectangle *r, 14286 const BoxRec *extents, unsigned clipped) 14287{ 14288 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14289 struct sna *sna = to_sna_from_pixmap(pixmap); 14290 DDXPointRec origin = gc->patOrg; 14291 int16_t dx, dy; 14292 uint32_t br00, br13; 14293 14294 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14295 extents->x1, extents->y1, 14296 extents->x2, extents->y2, 14297 origin.x, origin.y, 14298 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14299 14300 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14301 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14302 14303 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; 14304 br13 = bo->pitch; 14305 if (sna->kgem.gen >= 040 && bo->tiling) { 14306 br00 |= BLT_DST_TILED; 14307 br13 >>= 2; 14308 } 14309 br13 |= (gc->fillStyle == FillStippled) << 29; 14310 br13 |= blt_depth(drawable->depth) << 24; 14311 br13 |= copy_ROP[gc->alu] << 16; 14312 14313 origin.x += dx + drawable->x; 14314 origin.y += dy + drawable->y; 14315 14316 if (!clipped) { 14317 dx += drawable->x; 14318 dy += drawable->y; 14319 14320 sna_damage_add_rectangles(damage, r, n, dx, dy); 14321 do { 14322 BoxRec box; 14323 14324 box.x1 = r->x + dx; 14325 box.y1 = r->y + dy; 14326 box.x2 = box.x1 + r->width; 14327 box.y2 = box.y1 + r->height; 14328 14329 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14330 br00, br13, gc, 14331 &box, &origin); 14332 r++; 14333 } while (--n); 14334 } else { 14335 RegionRec clip; 14336 14337 region_set(&clip, extents); 14338 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14339 DBG(("%s: all clipped\n", __FUNCTION__)); 14340 return true; 14341 } 14342 14343 if (clip.data == NULL) { 14344 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14345 __FUNCTION__, 14346 clip.extents.x1, clip.extents.y1, 14347 clip.extents.x2, clip.extents.y2)); 14348 do { 14349 BoxRec box; 14350 14351 box.x1 = r->x + drawable->x; 14352 box.x2 = bound(box.x1, r->width); 14353 box.y1 = r->y + drawable->y; 14354 box.y2 = bound(box.y1, r->height); 14355 r++; 14356 14357 DBG(("%s: box (%d, %d), (%d, %d)\n", 14358 __FUNCTION__, 14359 box.x1, box.y1, box.x2, box.y2)); 14360 if (!box_intersect(&box, &clip.extents)) 14361 continue; 14362 14363 box.x1 += dx; box.x2 += dx; 14364 box.y1 += dy; box.y2 += dy; 14365 14366 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14367 br00, br13, gc, 14368 &box, &origin); 14369 } while (--n); 14370 } else { 14371 const BoxRec * const clip_start = RegionBoxptr(&clip); 14372 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14373 const BoxRec *c; 14374 14375 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14376 clip_start->x1, clip_start->y1, 14377 clip_start->x2, clip_start->y2, 14378 clip_end->x1, clip_end->y1, 14379 clip_end->x2, clip_end->y2)); 14380 do { 14381 BoxRec unclipped; 14382 14383 unclipped.x1 = r->x + drawable->x; 14384 unclipped.x2 = bound(unclipped.x1, r->width); 14385 unclipped.y1 = r->y + drawable->y; 14386 unclipped.y2 = bound(unclipped.y1, r->height); 14387 r++; 14388 14389 c = find_clip_box_for_y(clip_start, 14390 clip_end, 14391 unclipped.y1); 14392 while (c != clip_end) { 14393 BoxRec box; 14394 14395 if (unclipped.y2 <= c->y1) 14396 break; 14397 14398 box = unclipped; 14399 if (!box_intersect(&box, c++)) 14400 continue; 14401 14402 box.x1 += dx; box.x2 += dx; 14403 box.y1 += dy; box.y2 += dy; 14404 14405 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14406 br00, br13, gc, 14407 &box, &origin); 14408 } 14409 } while (--n); 14410 } 14411 } 14412 14413 assert_pixmap_damage(pixmap); 14414 sna->blt_state.fill_bo = 0; 14415 return true; 14416} 14417 14418static bool 14419sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, 14420 struct kgem_bo *bo, 14421 struct sna_damage **damage, 14422 GCPtr gc, int n, xRectangle *r, 14423 const BoxRec *extents, unsigned clipped) 14424{ 14425 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14426 struct sna *sna = to_sna_from_pixmap(pixmap); 14427 DDXPointRec origin = gc->patOrg; 14428 struct kgem_bo *tile = NULL; 14429 int16_t dx, dy; 14430 uint32_t br00, br13; 14431 14432 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14433 extents->x1, extents->y1, 14434 extents->x2, extents->y2, 14435 origin.x, origin.y, 14436 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14437 14438 if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0) 14439 return sna_poly_fill_rect_stippled_n_blt__imm(drawable, 14440 bo, damage, 14441 gc, n, r, 14442 extents, clipped); 14443 14444 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14445 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14446 14447 br00 = XY_MONO_SRC_COPY | 3 << 20; 14448 br13 = bo->pitch; 14449 if (sna->kgem.gen >= 040 && bo->tiling) { 14450 br00 |= BLT_DST_TILED; 14451 br13 >>= 2; 14452 } 14453 br13 |= (gc->fillStyle == FillStippled) << 29; 14454 br13 |= blt_depth(drawable->depth) << 24; 14455 br13 |= copy_ROP[gc->alu] << 16; 14456 14457 origin.x += dx + drawable->x; 14458 origin.y += dy + drawable->y; 14459 14460 if (!clipped) { 14461 dx += drawable->x; 14462 dy += drawable->y; 14463 14464 sna_damage_add_rectangles(damage, r, n, dx, dy); 14465 do { 14466 BoxRec box; 14467 14468 box.x1 = r->x + dx; 14469 box.y1 = r->y + dy; 14470 box.x2 = box.x1 + r->width; 14471 box.y2 = box.y1 + r->height; 14472 14473 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14474 br00, br13, gc, 14475 &box, &origin); 14476 r++; 14477 } while (--n); 14478 } else { 14479 RegionRec clip; 14480 14481 region_set(&clip, extents); 14482 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14483 DBG(("%s: all clipped\n", __FUNCTION__)); 14484 return true; 14485 } 14486 14487 if (clip.data == NULL) { 14488 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14489 __FUNCTION__, 14490 clip.extents.x1, clip.extents.y1, 14491 clip.extents.x2, clip.extents.y2)); 14492 do { 14493 BoxRec box; 14494 14495 box.x1 = r->x + drawable->x; 14496 box.x2 = bound(box.x1, r->width); 14497 box.y1 = r->y + drawable->y; 14498 box.y2 = bound(box.y1, r->height); 14499 r++; 14500 14501 DBG(("%s: box (%d, %d), (%d, %d)\n", 14502 __FUNCTION__, 14503 box.x1, box.y1, box.x2, box.y2)); 14504 if (!box_intersect(&box, &clip.extents)) 14505 continue; 14506 14507 box.x1 += dx; box.x2 += dx; 14508 box.y1 += dy; box.y2 += dy; 14509 14510 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14511 br00, br13, gc, 14512 &box, &origin); 14513 } while (--n); 14514 } else { 14515 const BoxRec * const clip_start = RegionBoxptr(&clip); 14516 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14517 const BoxRec *c; 14518 14519 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14520 clip_start->x1, clip_start->y1, 14521 clip_start->x2, clip_start->y2, 14522 clip_end->x1, clip_end->y1, 14523 clip_end->x2, clip_end->y2)); 14524 do { 14525 BoxRec unclipped; 14526 14527 unclipped.x1 = r->x + drawable->x; 14528 unclipped.x2 = bound(unclipped.x1, r->width); 14529 unclipped.y1 = r->y + drawable->y; 14530 unclipped.y2 = bound(unclipped.y1, r->height); 14531 r++; 14532 14533 c = find_clip_box_for_y(clip_start, 14534 clip_end, 14535 unclipped.y1); 14536 while (c != clip_end) { 14537 BoxRec box; 14538 14539 if (unclipped.y2 <= c->y1) 14540 break; 14541 14542 box = unclipped; 14543 if (!box_intersect(&box, c++)) 14544 continue; 14545 14546 box.x1 += dx; box.x2 += dx; 14547 box.y1 += dy; box.y2 += dy; 14548 14549 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14550 br00, br13, gc, 14551 &box, &origin); 14552 } 14553 } while (--n); 14554 } 14555 } 14556 14557 assert_pixmap_damage(pixmap); 14558 if (tile) 14559 kgem_bo_destroy(&sna->kgem, tile); 14560 sna->blt_state.fill_bo = 0; 14561 return true; 14562} 14563 14564static bool 14565sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 14566 struct kgem_bo *bo, 14567 struct sna_damage **damage, 14568 GCPtr gc, int n, xRectangle *rect, 14569 const BoxRec *extents, unsigned clipped) 14570{ 14571 14572 PixmapPtr stipple = gc->stipple; 14573 14574 if (bo->tiling == I915_TILING_Y) { 14575 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14576 14577 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 14578 /* This is cheating, but only the gpu_bo can be tiled */ 14579 assert(bo == __sna_pixmap_get_bo(pixmap)); 14580 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 14581 if (bo == NULL) { 14582 DBG(("%s: fallback -- unable to change tiling\n", 14583 __FUNCTION__)); 14584 return false; 14585 } 14586 } 14587 14588 if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ)) 14589 return false; 14590 14591 DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n", 14592 __FUNCTION__, gc->patOrg.x, gc->patOrg.y, 14593 extents->x2 - gc->patOrg.x - drawable->x, 14594 extents->y2 - gc->patOrg.y - drawable->y, 14595 stipple->drawable.width, stipple->drawable.height)); 14596 14597 if ((stipple->drawable.width | stipple->drawable.height) == 8) 14598 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14599 gc, n, rect, 14600 extents, clipped); 14601 14602 if ((stipple->drawable.width | stipple->drawable.height) <= 0xc && 14603 is_power_of_two(stipple->drawable.width) && 14604 is_power_of_two(stipple->drawable.height)) 14605 return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage, 14606 gc, n, rect, 14607 extents, clipped); 14608 14609 if (extents->x1 - gc->patOrg.x - drawable->x >= 0 && 14610 extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width && 14611 extents->y1 - gc->patOrg.y - drawable->y >= 0 && 14612 extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) { 14613 if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8) 14614 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14615 gc, n, rect, 14616 extents, clipped); 14617 else 14618 return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage, 14619 gc, n, rect, 14620 extents, clipped); 14621 } else { 14622 return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage, 14623 gc, n, rect, 14624 extents, clipped); 14625 } 14626} 14627 14628static unsigned 14629sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc, 14630 int *_n, xRectangle **_r, 14631 BoxPtr out) 14632{ 14633 int n; 14634 xRectangle *r; 14635 Box32Rec box; 14636 bool clipped; 14637 14638 if (*_n == 0) 14639 return 0; 14640 14641 DBG(("%s: [0] = (%d, %d)x(%d, %d)\n", 14642 __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height)); 14643 14644 /* Remove any zero-size rectangles from the array */ 14645 while (*_n && ((*_r)->width == 0 || (*_r)->height == 0)) 14646 --*_n, ++*_r; 14647 14648 if (*_n == 0) 14649 return 0; 14650 14651 n = *_n; 14652 r = *_r; 14653 14654 box.x1 = r->x; 14655 box.x2 = box.x1 + r->width; 14656 box.y1 = r->y; 14657 box.y2 = box.y1 + r->height; 14658 r++; 14659 14660 while (--n) { 14661 if (r->width == 0 || r->height == 0) 14662 goto slow; 14663 14664 box32_add_rect(&box, r++); 14665 } 14666 goto done; 14667slow: 14668 { 14669 xRectangle *rr = r; 14670 do { 14671 do { 14672 --*_n, r++; 14673 } while (--n && (r->width == 0 || r->height == 0)); 14674 while (n && r->width && r->height) { 14675 box32_add_rect(&box, r); 14676 *rr++ = *r++; 14677 n--; 14678 } 14679 } while (n); 14680 } 14681done: 14682 14683 clipped = box32_trim_and_translate(&box, drawable, gc); 14684 if (!box32_to_box16(&box, out)) 14685 return 0; 14686 14687 return 1 | clipped << 1; 14688} 14689 14690static void 14691sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect) 14692{ 14693 PixmapPtr pixmap = get_drawable_pixmap(draw); 14694 struct sna *sna = to_sna_from_pixmap(pixmap); 14695 struct sna_pixmap *priv = sna_pixmap(pixmap); 14696 struct sna_damage **damage; 14697 struct kgem_bo *bo; 14698 RegionRec region; 14699 unsigned flags, hint; 14700 uint32_t color; 14701 14702 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 14703 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 14704 (gc->fillStyle == FillSolid || 14705 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 14706 gc->fillStyle, gc->tileIsPixel, 14707 gc->alu)); 14708 14709 flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, ®ion.extents); 14710 if (flags == 0) { 14711 DBG(("%s, nothing to do\n", __FUNCTION__)); 14712 return; 14713 } 14714 14715 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 14716 region.extents.x1, region.extents.y1, 14717 region.extents.x2, region.extents.y2, 14718 flags)); 14719 14720 if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) { 14721 DBG(("%s: fallback forced\n", __FUNCTION__)); 14722 goto fallback; 14723 } 14724 14725 if (priv == NULL) { 14726 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 14727 goto fallback; 14728 } 14729 14730 if (wedged(sna)) { 14731 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14732 goto fallback; 14733 } 14734 14735 if (!PM_IS_SOLID(draw, gc->planemask)) { 14736 DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n", 14737 __FUNCTION__, gc->planemask)); 14738 goto fallback; 14739 } 14740 14741 /* Clear the cpu damage so that we refresh the GPU status of the 14742 * pixmap upon a redraw after a period of inactivity. 14743 */ 14744 hint = PREFER_GPU; 14745 if (n == 1 && gc->fillStyle != FillStippled && alu_overwrites(gc->alu)) { 14746 int16_t dx, dy; 14747 14748 region.data = NULL; 14749 14750 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) { 14751 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 14752 RegionTranslate(®ion, dx, dy); 14753 } 14754 14755 if ((flags & 2) == 0) { 14756 hint |= IGNORE_DAMAGE; 14757 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 14758 discard_cpu_damage(sna, priv); 14759 hint |= REPLACES; 14760 } else { 14761 if (priv->cpu_damage && 14762 region_subsumes_damage(®ion, priv->cpu_damage)) 14763 discard_cpu_damage(sna, priv); 14764 } 14765 } 14766 if (priv->cpu_damage == NULL) { 14767 if (priv->gpu_bo && 14768 (hint & REPLACES || 14769 box_covers_pixmap(pixmap, ®ion.extents) || 14770 box_inplace(pixmap, ®ion.extents))) { 14771 DBG(("%s: promoting to full GPU\n", 14772 __FUNCTION__)); 14773 assert(priv->gpu_bo->proxy == NULL); 14774 sna_damage_all(&priv->gpu_damage, pixmap); 14775 } 14776 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 14777 priv->cpu = false; 14778 } 14779 14780 if (dx | dy) 14781 RegionTranslate(®ion, -dx, -dy); 14782 } 14783 14784 /* If the source is already on the GPU, keep the operation on the GPU */ 14785 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 14786 sna_pixmap_is_gpu(gc->tile.pixmap)) { 14787 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 14788 hint |= FORCE_GPU; 14789 } 14790 14791 bo = sna_drawable_use_bo(draw, hint, ®ion.extents, &damage); 14792 if (bo == NULL) { 14793 DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint)); 14794 goto fallback; 14795 } 14796 if (hint & REPLACES && UNDO) 14797 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 14798 14799 if (gc_is_solid(gc, &color)) { 14800 DBG(("%s: solid fill [%08x], testing for blt\n", 14801 __FUNCTION__, color)); 14802 14803 if (sna_poly_fill_rect_blt(draw, 14804 bo, damage, 14805 gc, color, n, rect, 14806 ®ion.extents, flags & 2)) 14807 return; 14808 } else if (gc->fillStyle == FillTiled) { 14809 DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__)); 14810 14811 if (sna_poly_fill_rect_tiled_blt(draw, bo, damage, 14812 gc, n, rect, 14813 ®ion.extents, flags & 2)) 14814 return; 14815 } else { 14816 DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__)); 14817 14818 if (sna_poly_fill_rect_stippled_blt(draw, bo, damage, 14819 gc, n, rect, 14820 ®ion.extents, flags & 2)) 14821 return; 14822 } 14823 14824fallback: 14825 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 14826 region.extents.x1, region.extents.y1, 14827 region.extents.x2, region.extents.y2)); 14828 region.data = NULL; 14829 if (!region_maybe_clip(®ion, gc->pCompositeClip)) { 14830 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 14831 return; 14832 } 14833 14834 if (!sna_gc_move_to_cpu(gc, draw, ®ion)) 14835 goto out; 14836 if (!sna_drawable_move_region_to_cpu(draw, ®ion, 14837 drawable_gc_flags(draw, gc, n > 1))) 14838 goto out; 14839 14840 if (sigtrap_get() == 0) { 14841 DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__)); 14842 fbPolyFillRect(draw, gc, n, rect); 14843 FALLBACK_FLUSH(draw); 14844 sigtrap_put(); 14845 } 14846out: 14847 sna_gc_move_to_gpu(gc); 14848 RegionUninit(®ion); 14849} 14850 14851static void 14852sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r) 14853{ 14854 struct sna_fill_spans *data = sna_gc(gc)->priv; 14855 uint32_t color; 14856 14857 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 14858 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 14859 (gc->fillStyle == FillSolid || 14860 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 14861 gc->fillStyle, gc->tileIsPixel, 14862 gc->alu)); 14863 14864 assert(PM_IS_SOLID(draw, gc->planemask)); 14865 if (n == 0) 14866 return; 14867 14868 /* The mi routines do not attempt to keep the spans it generates 14869 * within the clip, so we must run them through the clipper. 14870 */ 14871 14872 if (gc_is_solid(gc, &color)) { 14873 (void)sna_poly_fill_rect_blt(draw, 14874 data->bo, data->damage, 14875 gc, color, n, r, 14876 &data->region.extents, true); 14877 } else if (gc->fillStyle == FillTiled) { 14878 (void)sna_poly_fill_rect_tiled_blt(draw, 14879 data->bo, data->damage, 14880 gc, n, r, 14881 &data->region.extents, true); 14882 } else { 14883 (void)sna_poly_fill_rect_stippled_blt(draw, 14884 data->bo, data->damage, 14885 gc, n, r, 14886 &data->region.extents, true); 14887 } 14888} 14889 14890static void 14891sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc) 14892{ 14893 struct sna_fill_spans data; 14894 struct sna_pixmap *priv; 14895 14896 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 14897 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 14898 (gc->fillStyle == FillSolid || 14899 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 14900 gc->fillStyle, gc->tileIsPixel, 14901 gc->alu)); 14902 14903 data.flags = sna_poly_arc_extents(draw, gc, n, arc, 14904 &data.region.extents); 14905 if (data.flags == 0) 14906 return; 14907 14908 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 14909 data.region.extents.x1, data.region.extents.y1, 14910 data.region.extents.x2, data.region.extents.y2, 14911 data.flags)); 14912 14913 data.region.data = NULL; 14914 14915 if (FORCE_FALLBACK) 14916 goto fallback; 14917 14918 if (!ACCEL_POLY_FILL_ARC) 14919 goto fallback; 14920 14921 data.pixmap = get_drawable_pixmap(draw); 14922 data.sna = to_sna_from_pixmap(data.pixmap); 14923 priv = sna_pixmap(data.pixmap); 14924 if (priv == NULL) { 14925 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 14926 goto fallback; 14927 } 14928 14929 if (wedged(data.sna)) { 14930 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14931 goto fallback; 14932 } 14933 14934 if (!PM_IS_SOLID(draw, gc->planemask)) 14935 goto fallback; 14936 14937 if ((data.bo = sna_drawable_use_bo(draw, PREFER_GPU, 14938 &data.region.extents, 14939 &data.damage))) { 14940 uint32_t color; 14941 14942 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 14943 sna_gc(gc)->priv = &data; 14944 14945 if (gc_is_solid(gc, &color)) { 14946 struct sna_fill_op fill; 14947 14948 if (!sna_fill_init_blt(&fill, 14949 data.sna, data.pixmap, 14950 data.bo, gc->alu, color, 14951 FILL_SPANS)) 14952 goto fallback; 14953 14954 data.op = &fill; 14955 14956 if ((data.flags & 2) == 0) { 14957 if (data.dx | data.dy) 14958 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 14959 else 14960 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 14961 } else { 14962 if (!region_maybe_clip(&data.region, 14963 gc->pCompositeClip)) 14964 return; 14965 14966 if (region_is_singular(&data.region)) 14967 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 14968 else 14969 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 14970 } 14971 assert(gc->miTranslate); 14972 gc->ops = &sna_gc_ops__tmp; 14973 14974 miPolyFillArc(draw, gc, n, arc); 14975 fill.done(data.sna, &fill); 14976 } else { 14977 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 14978 gc->ops = &sna_gc_ops__tmp; 14979 14980 miPolyFillArc(draw, gc, n, arc); 14981 } 14982 14983 gc->ops = (GCOps *)&sna_gc_ops; 14984 if (data.damage) { 14985 if (data.dx | data.dy) 14986 pixman_region_translate(&data.region, data.dx, data.dy); 14987 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 14988 sna_damage_add(data.damage, &data.region); 14989 } 14990 assert_pixmap_damage(data.pixmap); 14991 RegionUninit(&data.region); 14992 return; 14993 } 14994 14995fallback: 14996 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 14997 data.region.extents.x1, data.region.extents.y1, 14998 data.region.extents.x2, data.region.extents.y2)); 14999 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 15000 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15001 return; 15002 } 15003 15004 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 15005 goto out; 15006 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 15007 drawable_gc_flags(draw, gc, true))) 15008 goto out; 15009 15010 if (sigtrap_get() == 0) { 15011 DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n", 15012 __FUNCTION__)); 15013 miPolyFillArc(draw, gc, n, arc); 15014 sigtrap_put(); 15015 } 15016out: 15017 sna_gc_move_to_gpu(gc); 15018 RegionUninit(&data.region); 15019} 15020 15021struct sna_font { 15022 CharInfoRec glyphs8[256]; 15023 CharInfoRec *glyphs16[256]; 15024}; 15025#define GLYPH_INVALID (void *)1 15026#define GLYPH_EMPTY (void *)2 15027 15028static Bool 15029sna_realize_font(ScreenPtr screen, FontPtr font) 15030{ 15031 struct sna_font *priv; 15032 15033 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15034 15035 priv = calloc(1, sizeof(struct sna_font)); 15036 if (priv == NULL) 15037 return FALSE; 15038 15039 if (!FontSetPrivate(font, sna_font_key, priv)) { 15040 free(priv); 15041 return FALSE; 15042 } 15043 15044 return TRUE; 15045} 15046 15047static Bool 15048sna_unrealize_font(ScreenPtr screen, FontPtr font) 15049{ 15050 struct sna_font *priv = FontGetPrivate(font, sna_font_key); 15051 int i, j; 15052 15053 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15054 15055 if (priv == NULL) 15056 return TRUE; 15057 15058 for (i = 0; i < 256; i++) { 15059 if ((uintptr_t)priv->glyphs8[i].bits & ~3) 15060 free(priv->glyphs8[i].bits); 15061 } 15062 for (j = 0; j < 256; j++) { 15063 if (priv->glyphs16[j] == NULL) 15064 continue; 15065 15066 for (i = 0; i < 256; i++) { 15067 if ((uintptr_t)priv->glyphs16[j][i].bits & ~3) 15068 free(priv->glyphs16[j][i].bits); 15069 } 15070 free(priv->glyphs16[j]); 15071 } 15072 free(priv); 15073 15074 FontSetPrivate(font, sna_font_key, NULL); 15075 return TRUE; 15076} 15077 15078static bool 15079sna_glyph_blt(DrawablePtr drawable, GCPtr gc, 15080 int _x, int _y, unsigned int _n, 15081 CharInfoPtr *_info, 15082 RegionRec *clip, 15083 uint32_t fg, uint32_t bg, 15084 bool transparent) 15085{ 15086 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15087 struct sna *sna = to_sna_from_pixmap(pixmap); 15088 struct kgem_bo *bo; 15089 struct sna_damage **damage; 15090 const BoxRec *extents, *last_extents; 15091 uint32_t *b; 15092 int16_t dx, dy; 15093 uint32_t br00; 15094 uint16_t unwind_batch, unwind_reloc; 15095 unsigned hint; 15096 15097 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15098 15099 DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n", 15100 __FUNCTION__, _x, _y, _n, fg, bg, rop)); 15101 15102 if (wedged(sna)) { 15103 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15104 return false; 15105 } 15106 15107 if (!transparent && clip->data == NULL) 15108 hint = PREFER_GPU | IGNORE_DAMAGE; 15109 else 15110 hint = PREFER_GPU; 15111 15112 bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage); 15113 if (bo == NULL) 15114 return false; 15115 15116 if (bo->tiling == I915_TILING_Y) { 15117 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15118 assert(bo == __sna_pixmap_get_bo(pixmap)); 15119 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15120 if (bo == NULL) { 15121 DBG(("%s: fallback -- unable to change tiling\n", 15122 __FUNCTION__)); 15123 return false; 15124 } 15125 } 15126 15127 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15128 RegionTranslate(clip, dx, dy); 15129 _x += drawable->x + dx; 15130 _y += drawable->y + dy; 15131 15132 extents = region_rects(clip); 15133 last_extents = extents + region_num_rects(clip); 15134 15135 if (!transparent) { /* emulate miImageGlyphBlt */ 15136 if (!sna_blt_fill_boxes(sna, GXcopy, 15137 bo, drawable->bitsPerPixel, 15138 bg, extents, last_extents - extents)) { 15139 RegionTranslate(clip, -dx, -dy); 15140 return false; 15141 } 15142 } 15143 15144 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15145 if (!kgem_check_batch(&sna->kgem, 20) || 15146 !kgem_check_bo_fenced(&sna->kgem, bo) || 15147 !kgem_check_reloc(&sna->kgem, 1)) { 15148 kgem_submit(&sna->kgem); 15149 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 15150 RegionTranslate(clip, -dx, -dy); 15151 return false; 15152 } 15153 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15154 } 15155 15156 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15157 __FUNCTION__, 15158 extents->x1, extents->y1, 15159 extents->x2, extents->y2)); 15160 15161 unwind_batch = sna->kgem.nbatch; 15162 unwind_reloc = sna->kgem.nreloc; 15163 15164 assert(sna->kgem.mode == KGEM_BLT); 15165 b = sna->kgem.batch + sna->kgem.nbatch; 15166 if (sna->kgem.gen >= 0100) { 15167 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15168 b[1] = bo->pitch; 15169 if (sna->kgem.gen >= 040 && bo->tiling) { 15170 b[0] |= BLT_DST_TILED; 15171 b[1] >>= 2; 15172 } 15173 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15174 b[2] = extents->y1 << 16 | extents->x1; 15175 b[3] = extents->y2 << 16 | extents->x2; 15176 *(uint64_t *)(b+4) = 15177 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15178 I915_GEM_DOMAIN_RENDER << 16 | 15179 I915_GEM_DOMAIN_RENDER | 15180 KGEM_RELOC_FENCED, 15181 0); 15182 b[6] = bg; 15183 b[7] = fg; 15184 b[8] = 0; 15185 b[9] = 0; 15186 sna->kgem.nbatch += 10; 15187 } else { 15188 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15189 b[1] = bo->pitch; 15190 if (sna->kgem.gen >= 040 && bo->tiling) { 15191 b[0] |= BLT_DST_TILED; 15192 b[1] >>= 2; 15193 } 15194 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15195 b[2] = extents->y1 << 16 | extents->x1; 15196 b[3] = extents->y2 << 16 | extents->x2; 15197 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15198 I915_GEM_DOMAIN_RENDER << 16 | 15199 I915_GEM_DOMAIN_RENDER | 15200 KGEM_RELOC_FENCED, 15201 0); 15202 b[5] = bg; 15203 b[6] = fg; 15204 b[7] = 0; 15205 sna->kgem.nbatch += 8; 15206 } 15207 15208 br00 = XY_TEXT_IMMEDIATE_BLT; 15209 if (bo->tiling && sna->kgem.gen >= 040) 15210 br00 |= BLT_DST_TILED; 15211 15212 do { 15213 CharInfoPtr *info = _info; 15214 int x = _x, y = _y, n = _n; 15215 15216 do { 15217 CharInfoPtr c = *info++; 15218 int w = GLYPHWIDTHPIXELS(c); 15219 int h = GLYPHHEIGHTPIXELS(c); 15220 int w8 = (w + 7) >> 3; 15221 int x1, y1, len; 15222 15223 if (c->bits == GLYPH_EMPTY) 15224 goto skip; 15225 15226 len = (w8 * h + 7) >> 3 << 1; 15227 x1 = x + c->metrics.leftSideBearing; 15228 y1 = y - c->metrics.ascent; 15229 15230 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 15231 x,y, x1, y1, w, w8, h, len)); 15232 15233 if (x1 >= extents->x2 || y1 >= extents->y2) 15234 goto skip; 15235 if (x1 + w <= extents->x1 || y1 + h <= extents->y1) 15236 goto skip; 15237 15238 assert(len > 0); 15239 if (!kgem_check_batch(&sna->kgem, 3+len)) { 15240 _kgem_submit(&sna->kgem); 15241 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15242 15243 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 15244 __FUNCTION__, 15245 extents->x1, extents->y1, 15246 extents->x2, extents->y2)); 15247 15248 unwind_batch = sna->kgem.nbatch; 15249 unwind_reloc = sna->kgem.nreloc; 15250 15251 assert(sna->kgem.mode == KGEM_BLT); 15252 b = sna->kgem.batch + sna->kgem.nbatch; 15253 if (sna->kgem.gen >= 0100) { 15254 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15255 b[1] = bo->pitch; 15256 if (bo->tiling) { 15257 b[0] |= BLT_DST_TILED; 15258 b[1] >>= 2; 15259 } 15260 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15261 b[2] = extents->y1 << 16 | extents->x1; 15262 b[3] = extents->y2 << 16 | extents->x2; 15263 *(uint64_t *)(b+4) = 15264 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15265 I915_GEM_DOMAIN_RENDER << 16 | 15266 I915_GEM_DOMAIN_RENDER | 15267 KGEM_RELOC_FENCED, 15268 0); 15269 b[6] = bg; 15270 b[7] = fg; 15271 b[8] = 0; 15272 b[9] = 0; 15273 sna->kgem.nbatch += 10; 15274 } else { 15275 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15276 b[1] = bo->pitch; 15277 if (sna->kgem.gen >= 040 && bo->tiling) { 15278 b[0] |= BLT_DST_TILED; 15279 b[1] >>= 2; 15280 } 15281 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15282 b[2] = extents->y1 << 16 | extents->x1; 15283 b[3] = extents->y2 << 16 | extents->x2; 15284 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15285 I915_GEM_DOMAIN_RENDER << 16 | 15286 I915_GEM_DOMAIN_RENDER | 15287 KGEM_RELOC_FENCED, 15288 0); 15289 b[5] = bg; 15290 b[6] = fg; 15291 b[7] = 0; 15292 sna->kgem.nbatch += 8; 15293 } 15294 } 15295 15296 assert(sna->kgem.mode == KGEM_BLT); 15297 b = sna->kgem.batch + sna->kgem.nbatch; 15298 sna->kgem.nbatch += 3 + len; 15299 15300 b[0] = br00 | (1 + len); 15301 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 15302 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 15303 { 15304 uint64_t *src = (uint64_t *)c->bits; 15305 uint64_t *dst = (uint64_t *)(b + 3); 15306 do { 15307 *dst++ = *src++; 15308 len -= 2; 15309 } while (len); 15310 } 15311 15312 if (damage) { 15313 BoxRec r; 15314 15315 r.x1 = x1; 15316 r.y1 = y1; 15317 r.x2 = x1 + w; 15318 r.y2 = y1 + h; 15319 if (box_intersect(&r, extents)) 15320 sna_damage_add_box(damage, &r); 15321 } 15322skip: 15323 x += c->metrics.characterWidth; 15324 } while (--n); 15325 15326 if (++extents == last_extents) 15327 break; 15328 15329 if (kgem_check_batch(&sna->kgem, 3)) { 15330 assert(sna->kgem.mode == KGEM_BLT); 15331 b = sna->kgem.batch + sna->kgem.nbatch; 15332 sna->kgem.nbatch += 3; 15333 15334 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15335 __FUNCTION__, 15336 extents->x1, extents->y1, 15337 extents->x2, extents->y2)); 15338 15339 b[0] = XY_SETUP_CLIP; 15340 b[1] = extents->y1 << 16 | extents->x1; 15341 b[2] = extents->y2 << 16 | extents->x2; 15342 } 15343 } while (1); 15344 15345 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 15346 sna->kgem.nbatch = unwind_batch; 15347 sna->kgem.nreloc = unwind_reloc; 15348 if (sna->kgem.nbatch == 0) 15349 kgem_bo_undo(&sna->kgem, bo); 15350 } 15351 15352 assert_pixmap_damage(pixmap); 15353 sna->blt_state.fill_bo = 0; 15354 return true; 15355} 15356 15357static void 15358sna_glyph_extents(FontPtr font, 15359 CharInfoPtr *info, 15360 unsigned long count, 15361 ExtentInfoRec *extents) 15362{ 15363 extents->drawDirection = font->info.drawDirection; 15364 extents->fontAscent = font->info.fontAscent; 15365 extents->fontDescent = font->info.fontDescent; 15366 15367 extents->overallAscent = info[0]->metrics.ascent; 15368 extents->overallDescent = info[0]->metrics.descent; 15369 extents->overallLeft = info[0]->metrics.leftSideBearing; 15370 extents->overallRight = info[0]->metrics.rightSideBearing; 15371 extents->overallWidth = info[0]->metrics.characterWidth; 15372 15373 while (--count) { 15374 CharInfoPtr p =*++info; 15375 int v; 15376 15377 if (p->metrics.ascent > extents->overallAscent) 15378 extents->overallAscent = p->metrics.ascent; 15379 if (p->metrics.descent > extents->overallDescent) 15380 extents->overallDescent = p->metrics.descent; 15381 15382 v = extents->overallWidth + p->metrics.leftSideBearing; 15383 if (v < extents->overallLeft) 15384 extents->overallLeft = v; 15385 15386 v = extents->overallWidth + p->metrics.rightSideBearing; 15387 if (v > extents->overallRight) 15388 extents->overallRight = v; 15389 15390 extents->overallWidth += p->metrics.characterWidth; 15391 } 15392} 15393 15394static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out) 15395{ 15396 int w = GLYPHWIDTHPIXELS(in); 15397 int h = GLYPHHEIGHTPIXELS(in); 15398 int stride = GLYPHWIDTHBYTESPADDED(in); 15399 uint8_t *dst, *src; 15400 int clear = 1; 15401 15402 out->metrics = in->metrics; 15403 15404 /* Skip empty glyphs */ 15405 if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) { 15406 out->bits = GLYPH_EMPTY; 15407 return true; 15408 } 15409 15410 w = (w + 7) >> 3; 15411 15412 out->bits = malloc((w*h + 7) & ~7); 15413 if (out->bits == NULL) 15414 return false; 15415 15416 VG(memset(out->bits, 0, (w*h + 7) & ~7)); 15417 src = (uint8_t *)in->bits; 15418 dst = (uint8_t *)out->bits; 15419 stride -= w; 15420 do { 15421 int i = w; 15422 do { 15423 clear &= *src == 0; 15424 *dst++ = byte_reverse(*src++); 15425 } while (--i); 15426 src += stride; 15427 } while (--h); 15428 15429 if (clear) { 15430 free(out->bits); 15431 out->bits = GLYPH_EMPTY; 15432 } 15433 15434 return true; 15435} 15436 15437inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv, 15438 uint8_t g, CharInfoPtr *out) 15439{ 15440 unsigned long n; 15441 CharInfoPtr p, ret; 15442 15443 p = &priv->glyphs8[g]; 15444 if (p->bits) { 15445 *out = p; 15446 return p->bits != GLYPH_INVALID; 15447 } 15448 15449 font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret); 15450 if (n == 0) { 15451 p->bits = GLYPH_INVALID; 15452 return false; 15453 } 15454 15455 return sna_set_glyph(ret, *out = p); 15456} 15457 15458inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv, 15459 uint16_t g, CharInfoPtr *out) 15460{ 15461 unsigned long n; 15462 CharInfoPtr page, p, ret; 15463 15464 page = priv->glyphs16[g>>8]; 15465 if (page == NULL) 15466 page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec)); 15467 15468 p = &page[g&0xff]; 15469 if (p->bits) { 15470 *out = p; 15471 return p->bits != GLYPH_INVALID; 15472 } 15473 15474 font->get_glyphs(font, 1, (unsigned char *)&g, 15475 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit, 15476 &n, &ret); 15477 if (n == 0) { 15478 p->bits = GLYPH_INVALID; 15479 return false; 15480 } 15481 15482 return sna_set_glyph(ret, *out = p); 15483} 15484 15485static inline bool sna_font_too_large(FontPtr font) 15486{ 15487 int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font)); 15488 int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font)); 15489 int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth)); 15490 DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__, 15491 top, bot, width, (top + bot) * (width + 7)/8)); 15492 return (top + bot) * (width + 7)/8 > 124; 15493} 15494 15495static int 15496sna_poly_text8(DrawablePtr drawable, GCPtr gc, 15497 int x, int y, 15498 int count, char *chars) 15499{ 15500 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15501 CharInfoPtr info[255]; 15502 ExtentInfoRec extents; 15503 RegionRec region; 15504 long unsigned i, n; 15505 uint32_t fg; 15506 15507 for (i = n = 0; i < count; i++) { 15508 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15509 n++; 15510 } 15511 if (n == 0) 15512 return x; 15513 15514 sna_glyph_extents(gc->font, info, n, &extents); 15515 region.extents.x1 = x + extents.overallLeft; 15516 region.extents.y1 = y - extents.overallAscent; 15517 region.extents.x2 = x + extents.overallRight; 15518 region.extents.y2 = y + extents.overallDescent; 15519 15520 translate_box(®ion.extents, drawable); 15521 clip_box(®ion.extents, gc); 15522 if (box_empty(®ion.extents)) 15523 return x + extents.overallRight; 15524 15525 region.data = NULL; 15526 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15527 return x + extents.overallRight; 15528 15529 if (FORCE_FALLBACK) 15530 goto fallback; 15531 15532 if (!ACCEL_POLY_TEXT8) 15533 goto fallback; 15534 15535 if (sna_font_too_large(gc->font)) 15536 goto fallback; 15537 15538 if (!PM_IS_SOLID(drawable, gc->planemask)) 15539 goto fallback; 15540 15541 if (!gc_is_solid(gc, &fg)) 15542 goto fallback; 15543 15544 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15545fallback: 15546 DBG(("%s: fallback\n", __FUNCTION__)); 15547 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15548 Linear8Bit, &n, info); 15549 15550 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15551 goto out; 15552 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15553 MOVE_READ | MOVE_WRITE)) 15554 goto out; 15555 15556 if (sigtrap_get() == 0) { 15557 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15558 fbPolyGlyphBlt(drawable, gc, x, y, n, 15559 info, FONTGLYPHS(gc->font)); 15560 FALLBACK_FLUSH(drawable); 15561 sigtrap_put(); 15562 } 15563out: 15564 sna_gc_move_to_gpu(gc); 15565 } 15566 RegionUninit(®ion); 15567 return x + extents.overallRight; 15568} 15569 15570static int 15571sna_poly_text16(DrawablePtr drawable, GCPtr gc, 15572 int x, int y, 15573 int count, unsigned short *chars) 15574{ 15575 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15576 CharInfoPtr info[255]; 15577 ExtentInfoRec extents; 15578 RegionRec region; 15579 long unsigned i, n; 15580 uint32_t fg; 15581 15582 for (i = n = 0; i < count; i++) { 15583 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15584 n++; 15585 } 15586 if (n == 0) 15587 return x; 15588 15589 sna_glyph_extents(gc->font, info, n, &extents); 15590 region.extents.x1 = x + extents.overallLeft; 15591 region.extents.y1 = y - extents.overallAscent; 15592 region.extents.x2 = x + extents.overallRight; 15593 region.extents.y2 = y + extents.overallDescent; 15594 15595 translate_box(®ion.extents, drawable); 15596 clip_box(®ion.extents, gc); 15597 if (box_empty(®ion.extents)) 15598 return x + extents.overallRight; 15599 15600 region.data = NULL; 15601 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15602 return x + extents.overallRight; 15603 15604 if (FORCE_FALLBACK) 15605 goto fallback; 15606 15607 if (!ACCEL_POLY_TEXT16) 15608 goto fallback; 15609 15610 if (sna_font_too_large(gc->font)) 15611 goto fallback; 15612 15613 if (!PM_IS_SOLID(drawable, gc->planemask)) 15614 goto fallback; 15615 15616 if (!gc_is_solid(gc, &fg)) 15617 goto fallback; 15618 15619 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15620fallback: 15621 DBG(("%s: fallback\n", __FUNCTION__)); 15622 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15623 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15624 &n, info); 15625 15626 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15627 goto out; 15628 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15629 MOVE_READ | MOVE_WRITE)) 15630 goto out; 15631 15632 if (sigtrap_get() == 0) { 15633 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15634 fbPolyGlyphBlt(drawable, gc, x, y, n, 15635 info, FONTGLYPHS(gc->font)); 15636 FALLBACK_FLUSH(drawable); 15637 sigtrap_put(); 15638 } 15639out: 15640 sna_gc_move_to_gpu(gc); 15641 } 15642 RegionUninit(®ion); 15643 return x + extents.overallRight; 15644} 15645 15646static void 15647sna_image_text8(DrawablePtr drawable, GCPtr gc, 15648 int x, int y, 15649 int count, char *chars) 15650{ 15651 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15652 CharInfoPtr info[255]; 15653 ExtentInfoRec extents; 15654 RegionRec region; 15655 long unsigned i, n; 15656 15657 for (i = n = 0; i < count; i++) { 15658 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15659 n++; 15660 } 15661 if (n == 0) 15662 return; 15663 15664 sna_glyph_extents(gc->font, info, n, &extents); 15665 region.extents.x1 = x + MIN(0, extents.overallLeft); 15666 region.extents.y1 = y - extents.fontAscent; 15667 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 15668 region.extents.y2 = y + extents.fontDescent; 15669 15670 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 15671 __FUNCTION__, n, count, 15672 extents.overallLeft, extents.overallRight, extents.overallWidth, 15673 extents.fontAscent, extents.fontDescent, 15674 region.extents.x1, region.extents.y1, 15675 region.extents.x2, region.extents.y2)); 15676 15677 translate_box(®ion.extents, drawable); 15678 clip_box(®ion.extents, gc); 15679 if (box_empty(®ion.extents)) 15680 return; 15681 15682 region.data = NULL; 15683 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15684 return; 15685 15686 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 15687 __FUNCTION__, 15688 region.extents.x1, region.extents.y1, 15689 region.extents.x2, region.extents.y2)); 15690 15691 if (FORCE_FALLBACK) 15692 goto fallback; 15693 15694 if (!ACCEL_IMAGE_TEXT8) 15695 goto fallback; 15696 15697 if (sna_font_too_large(gc->font)) 15698 goto fallback; 15699 15700 if (!PM_IS_SOLID(drawable, gc->planemask)) 15701 goto fallback; 15702 15703 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 15704 gc->fgPixel, gc->bgPixel, false)) { 15705fallback: 15706 DBG(("%s: fallback\n", __FUNCTION__)); 15707 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15708 Linear8Bit, &n, info); 15709 15710 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15711 goto out; 15712 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 15713 goto out; 15714 15715 if (sigtrap_get() == 0) { 15716 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 15717 fbImageGlyphBlt(drawable, gc, x, y, n, 15718 info, FONTGLYPHS(gc->font)); 15719 FALLBACK_FLUSH(drawable); 15720 sigtrap_put(); 15721 } 15722out: 15723 sna_gc_move_to_gpu(gc); 15724 } 15725 RegionUninit(®ion); 15726} 15727 15728static void 15729sna_image_text16(DrawablePtr drawable, GCPtr gc, 15730 int x, int y, 15731 int count, unsigned short *chars) 15732{ 15733 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15734 CharInfoPtr info[255]; 15735 ExtentInfoRec extents; 15736 RegionRec region; 15737 long unsigned i, n; 15738 15739 for (i = n = 0; i < count; i++) { 15740 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15741 n++; 15742 } 15743 if (n == 0) 15744 return; 15745 15746 sna_glyph_extents(gc->font, info, n, &extents); 15747 region.extents.x1 = x + MIN(0, extents.overallLeft); 15748 region.extents.y1 = y - extents.fontAscent; 15749 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 15750 region.extents.y2 = y + extents.fontDescent; 15751 15752 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 15753 __FUNCTION__, n, count, 15754 extents.overallLeft, extents.overallRight, extents.overallWidth, 15755 extents.fontAscent, extents.fontDescent, 15756 region.extents.x1, region.extents.y1, 15757 region.extents.x2, region.extents.y2)); 15758 15759 translate_box(®ion.extents, drawable); 15760 clip_box(®ion.extents, gc); 15761 if (box_empty(®ion.extents)) 15762 return; 15763 15764 region.data = NULL; 15765 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15766 return; 15767 15768 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 15769 __FUNCTION__, 15770 region.extents.x1, region.extents.y1, 15771 region.extents.x2, region.extents.y2)); 15772 15773 if (FORCE_FALLBACK) 15774 goto fallback; 15775 15776 if (!ACCEL_IMAGE_TEXT16) 15777 goto fallback; 15778 15779 if (sna_font_too_large(gc->font)) 15780 goto fallback; 15781 15782 if (!PM_IS_SOLID(drawable, gc->planemask)) 15783 goto fallback; 15784 15785 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 15786 gc->fgPixel, gc->bgPixel, false)) { 15787fallback: 15788 DBG(("%s: fallback\n", __FUNCTION__)); 15789 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15790 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15791 &n, info); 15792 15793 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15794 goto out; 15795 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 15796 goto out; 15797 15798 if (sigtrap_get() == 0) { 15799 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 15800 fbImageGlyphBlt(drawable, gc, x, y, n, 15801 info, FONTGLYPHS(gc->font)); 15802 FALLBACK_FLUSH(drawable); 15803 sigtrap_put(); 15804 } 15805out: 15806 sna_gc_move_to_gpu(gc); 15807 } 15808 RegionUninit(®ion); 15809} 15810 15811/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ 15812static bool 15813sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, 15814 int _x, int _y, unsigned int _n, 15815 CharInfoPtr *_info, pointer _base, 15816 struct kgem_bo *bo, 15817 struct sna_damage **damage, 15818 RegionPtr clip, 15819 uint32_t fg, uint32_t bg, 15820 bool transparent) 15821{ 15822 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15823 struct sna *sna = to_sna_from_pixmap(pixmap); 15824 const BoxRec *extents, *last_extents; 15825 uint32_t *b; 15826 int16_t dx, dy; 15827 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15828 uint16_t unwind_batch, unwind_reloc; 15829 15830 DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n", 15831 __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg)); 15832 15833 if (bo->tiling == I915_TILING_Y) { 15834 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15835 assert(bo == __sna_pixmap_get_bo(pixmap)); 15836 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15837 if (bo == NULL) { 15838 DBG(("%s: fallback -- unable to change tiling\n", 15839 __FUNCTION__)); 15840 return false; 15841 } 15842 } 15843 15844 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15845 RegionTranslate(clip, dx, dy); 15846 _x += drawable->x + dx; 15847 _y += drawable->y + dy; 15848 15849 extents = region_rects(clip); 15850 last_extents = extents + region_num_rects(clip); 15851 15852 if (!transparent) { /* emulate miImageGlyphBlt */ 15853 if (!sna_blt_fill_boxes(sna, GXcopy, 15854 bo, drawable->bitsPerPixel, 15855 bg, extents, last_extents - extents)) { 15856 RegionTranslate(clip, -dx, -dy); 15857 return false; 15858 } 15859 } 15860 15861 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15862 if (!kgem_check_batch(&sna->kgem, 20) || 15863 !kgem_check_bo_fenced(&sna->kgem, bo) || 15864 !kgem_check_reloc(&sna->kgem, 1)) { 15865 kgem_submit(&sna->kgem); 15866 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 15867 RegionTranslate(clip, -dx, -dy); 15868 return false; 15869 } 15870 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15871 } 15872 15873 unwind_batch = sna->kgem.nbatch; 15874 unwind_reloc = sna->kgem.nreloc; 15875 15876 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15877 __FUNCTION__, 15878 extents->x1, extents->y1, 15879 extents->x2, extents->y2)); 15880 15881 assert(sna->kgem.mode == KGEM_BLT); 15882 b = sna->kgem.batch + sna->kgem.nbatch; 15883 if (sna->kgem.gen >= 0100) { 15884 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 15885 b[1] = bo->pitch; 15886 if (sna->kgem.gen >= 040 && bo->tiling) { 15887 b[0] |= BLT_DST_TILED; 15888 b[1] >>= 2; 15889 } 15890 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15891 b[2] = extents->y1 << 16 | extents->x1; 15892 b[3] = extents->y2 << 16 | extents->x2; 15893 *(uint64_t *)(b+4) = 15894 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15895 I915_GEM_DOMAIN_RENDER << 16 | 15896 I915_GEM_DOMAIN_RENDER | 15897 KGEM_RELOC_FENCED, 15898 0); 15899 b[6] = bg; 15900 b[7] = fg; 15901 b[8] = 0; 15902 b[9] = 0; 15903 sna->kgem.nbatch += 10; 15904 } else { 15905 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 15906 b[1] = bo->pitch; 15907 if (sna->kgem.gen >= 040 && bo->tiling) { 15908 b[0] |= BLT_DST_TILED; 15909 b[1] >>= 2; 15910 } 15911 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15912 b[2] = extents->y1 << 16 | extents->x1; 15913 b[3] = extents->y2 << 16 | extents->x2; 15914 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15915 I915_GEM_DOMAIN_RENDER << 16 | 15916 I915_GEM_DOMAIN_RENDER | 15917 KGEM_RELOC_FENCED, 15918 0); 15919 b[5] = bg; 15920 b[6] = fg; 15921 b[7] = 0; 15922 sna->kgem.nbatch += 8; 15923 } 15924 15925 do { 15926 CharInfoPtr *info = _info; 15927 int x = _x, y = _y, n = _n; 15928 15929 do { 15930 CharInfoPtr c = *info++; 15931 uint8_t *glyph = FONTGLYPHBITS(base, c); 15932 int w = GLYPHWIDTHPIXELS(c); 15933 int h = GLYPHHEIGHTPIXELS(c); 15934 int stride = GLYPHWIDTHBYTESPADDED(c); 15935 int w8 = (w + 7) >> 3; 15936 int x1, y1, len, i; 15937 uint8_t *byte; 15938 15939 if (w == 0 || h == 0) 15940 goto skip; 15941 15942 len = (w8 * h + 7) >> 3 << 1; 15943 x1 = x + c->metrics.leftSideBearing; 15944 y1 = y - c->metrics.ascent; 15945 15946 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 15947 x,y, x1, y1, w, w8, h, len)); 15948 15949 if (x1 >= extents->x2 || y1 >= extents->y2 || 15950 x1 + w <= extents->x1 || y1 + h <= extents->y1) { 15951 DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n", 15952 __FUNCTION__, 15953 x1, y1, w, h, 15954 extents->x1, extents->y1, 15955 extents->x2, extents->y2)); 15956 goto skip; 15957 } 15958 15959 { 15960 int clear = 1, j = h; 15961 uint8_t *g = glyph; 15962 15963 do { 15964 i = w8; 15965 do { 15966 clear = *g++ == 0; 15967 } while (clear && --i); 15968 g += stride - w8; 15969 } while (clear && --j); 15970 if (clear) { 15971 DBG(("%s: skipping clear glyph for ImageGlyph\n", 15972 __FUNCTION__)); 15973 goto skip; 15974 } 15975 } 15976 15977 assert(len > 0); 15978 if (!kgem_check_batch(&sna->kgem, 3+len)) { 15979 _kgem_submit(&sna->kgem); 15980 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15981 15982 unwind_batch = sna->kgem.nbatch; 15983 unwind_reloc = sna->kgem.nreloc; 15984 15985 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 15986 __FUNCTION__, 15987 extents->x1, extents->y1, 15988 extents->x2, extents->y2)); 15989 15990 assert(sna->kgem.mode == KGEM_BLT); 15991 b = sna->kgem.batch + sna->kgem.nbatch; 15992 if (sna->kgem.gen >= 0100) { 15993 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 15994 b[1] = bo->pitch; 15995 if (bo->tiling) { 15996 b[0] |= BLT_DST_TILED; 15997 b[1] >>= 2; 15998 } 15999 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16000 b[2] = extents->y1 << 16 | extents->x1; 16001 b[3] = extents->y2 << 16 | extents->x2; 16002 *(uint64_t *)(b+4) = 16003 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16004 I915_GEM_DOMAIN_RENDER << 16 | 16005 I915_GEM_DOMAIN_RENDER | 16006 KGEM_RELOC_FENCED, 16007 0); 16008 b[6] = bg; 16009 b[7] = fg; 16010 b[8] = 0; 16011 b[9] = 0; 16012 sna->kgem.nbatch += 10; 16013 } else { 16014 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16015 b[1] = bo->pitch; 16016 if (sna->kgem.gen >= 040 && bo->tiling) { 16017 b[0] |= BLT_DST_TILED; 16018 b[1] >>= 2; 16019 } 16020 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16021 b[2] = extents->y1 << 16 | extents->x1; 16022 b[3] = extents->y2 << 16 | extents->x2; 16023 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16024 I915_GEM_DOMAIN_RENDER << 16 | 16025 I915_GEM_DOMAIN_RENDER | 16026 KGEM_RELOC_FENCED, 16027 0); 16028 b[5] = bg; 16029 b[6] = fg; 16030 b[7] = 0; 16031 sna->kgem.nbatch += 8; 16032 } 16033 } 16034 16035 assert(sna->kgem.mode == KGEM_BLT); 16036 b = sna->kgem.batch + sna->kgem.nbatch; 16037 sna->kgem.nbatch += 3 + len; 16038 16039 b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); 16040 if (bo->tiling && sna->kgem.gen >= 040) 16041 b[0] |= BLT_DST_TILED; 16042 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 16043 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 16044 16045 byte = (uint8_t *)&b[3]; 16046 stride -= w8; 16047 do { 16048 i = w8; 16049 do { 16050 *byte++ = byte_reverse(*glyph++); 16051 } while (--i); 16052 glyph += stride; 16053 } while (--h); 16054 while ((byte - (uint8_t *)&b[3]) & 7) 16055 *byte++ = 0; 16056 assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); 16057 16058 if (damage) { 16059 BoxRec r; 16060 16061 r.x1 = x1; 16062 r.y1 = y1; 16063 r.x2 = x1 + w; 16064 r.y2 = y1 + h; 16065 if (box_intersect(&r, extents)) 16066 sna_damage_add_box(damage, &r); 16067 } 16068skip: 16069 x += c->metrics.characterWidth; 16070 } while (--n); 16071 16072 if (++extents == last_extents) 16073 break; 16074 16075 if (kgem_check_batch(&sna->kgem, 3 + 5)) { 16076 assert(sna->kgem.mode == KGEM_BLT); 16077 b = sna->kgem.batch + sna->kgem.nbatch; 16078 sna->kgem.nbatch += 3; 16079 16080 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16081 __FUNCTION__, 16082 extents->x1, extents->y1, 16083 extents->x2, extents->y2)); 16084 16085 b[0] = XY_SETUP_CLIP; 16086 b[1] = extents->y1 << 16 | extents->x1; 16087 b[2] = extents->y2 << 16 | extents->x2; 16088 } 16089 } while (1); 16090 16091 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 16092 sna->kgem.nbatch = unwind_batch; 16093 sna->kgem.nreloc = unwind_reloc; 16094 if (sna->kgem.nbatch == 0) 16095 kgem_bo_undo(&sna->kgem, bo); 16096 } 16097 16098 assert_pixmap_damage(pixmap); 16099 sna->blt_state.fill_bo = 0; 16100 return true; 16101} 16102 16103static void 16104sna_image_glyph(DrawablePtr drawable, GCPtr gc, 16105 int x, int y, unsigned int n, 16106 CharInfoPtr *info, pointer base) 16107{ 16108 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16109 struct sna *sna = to_sna_from_pixmap(pixmap); 16110 ExtentInfoRec extents; 16111 RegionRec region; 16112 struct sna_damage **damage; 16113 struct kgem_bo *bo; 16114 unsigned hint; 16115 16116 if (n == 0) 16117 return; 16118 16119 sna_glyph_extents(gc->font, info, n, &extents); 16120 region.extents.x1 = x + MIN(0, extents.overallLeft); 16121 region.extents.y1 = y - extents.fontAscent; 16122 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16123 region.extents.y2 = y + extents.fontDescent; 16124 16125 DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16126 __FUNCTION__, n, 16127 extents.overallLeft, extents.overallRight, extents.overallWidth, 16128 extents.fontAscent, extents.fontDescent, 16129 region.extents.x1, region.extents.y1, 16130 region.extents.x2, region.extents.y2)); 16131 16132 translate_box(®ion.extents, drawable); 16133 clip_box(®ion.extents, gc); 16134 if (box_empty(®ion.extents)) 16135 return; 16136 16137 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16138 region.extents.x1, region.extents.y1, 16139 region.extents.x2, region.extents.y2)); 16140 16141 region.data = NULL; 16142 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16143 return; 16144 16145 if (FORCE_FALLBACK) 16146 goto fallback; 16147 16148 if (!ACCEL_IMAGE_GLYPH) 16149 goto fallback; 16150 16151 if (wedged(sna)) { 16152 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16153 goto fallback; 16154 } 16155 16156 if (!PM_IS_SOLID(drawable, gc->planemask)) 16157 goto fallback; 16158 16159 if (sna_font_too_large(gc->font)) 16160 goto fallback; 16161 16162 if (region.data == NULL) 16163 hint = IGNORE_DAMAGE | PREFER_GPU; 16164 else 16165 hint = PREFER_GPU; 16166 if ((bo = sna_drawable_use_bo(drawable, hint, 16167 ®ion.extents, &damage)) && 16168 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16169 bo, damage, ®ion, 16170 gc->fgPixel, gc->bgPixel, false)) 16171 goto out; 16172 16173fallback: 16174 DBG(("%s: fallback\n", __FUNCTION__)); 16175 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16176 goto out_gc; 16177 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16178 goto out_gc; 16179 16180 if (sigtrap_get() == 0) { 16181 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16182 fbImageGlyphBlt(drawable, gc, x, y, n, info, base); 16183 FALLBACK_FLUSH(drawable); 16184 sigtrap_put(); 16185 } 16186out_gc: 16187 sna_gc_move_to_gpu(gc); 16188out: 16189 RegionUninit(®ion); 16190} 16191 16192static void 16193sna_poly_glyph(DrawablePtr drawable, GCPtr gc, 16194 int x, int y, unsigned int n, 16195 CharInfoPtr *info, pointer base) 16196{ 16197 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16198 struct sna *sna = to_sna_from_pixmap(pixmap); 16199 ExtentInfoRec extents; 16200 RegionRec region; 16201 struct sna_damage **damage; 16202 struct kgem_bo *bo; 16203 uint32_t fg; 16204 16205 if (n == 0) 16206 return; 16207 16208 sna_glyph_extents(gc->font, info, n, &extents); 16209 region.extents.x1 = x + extents.overallLeft; 16210 region.extents.y1 = y - extents.overallAscent; 16211 region.extents.x2 = x + extents.overallRight; 16212 region.extents.y2 = y + extents.overallDescent; 16213 16214 translate_box(®ion.extents, drawable); 16215 clip_box(®ion.extents, gc); 16216 if (box_empty(®ion.extents)) 16217 return; 16218 16219 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16220 region.extents.x1, region.extents.y1, 16221 region.extents.x2, region.extents.y2)); 16222 16223 region.data = NULL; 16224 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16225 return; 16226 16227 if (FORCE_FALLBACK) 16228 goto fallback; 16229 16230 if (!ACCEL_POLY_GLYPH) 16231 goto fallback; 16232 16233 if (wedged(sna)) { 16234 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16235 goto fallback; 16236 } 16237 16238 if (!PM_IS_SOLID(drawable, gc->planemask)) 16239 goto fallback; 16240 16241 if (!gc_is_solid(gc, &fg)) 16242 goto fallback; 16243 16244 if (sna_font_too_large(gc->font)) 16245 goto fallback; 16246 16247 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 16248 ®ion.extents, &damage)) && 16249 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16250 bo, damage, ®ion, fg, -1, true)) 16251 goto out; 16252 16253fallback: 16254 DBG(("%s: fallback\n", __FUNCTION__)); 16255 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16256 goto out_gc; 16257 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16258 MOVE_READ | MOVE_WRITE)) 16259 goto out_gc; 16260 16261 if (sigtrap_get() == 0) { 16262 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 16263 fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); 16264 FALLBACK_FLUSH(drawable); 16265 sigtrap_put(); 16266 } 16267out_gc: 16268 sna_gc_move_to_gpu(gc); 16269out: 16270 RegionUninit(®ion); 16271} 16272 16273static bool 16274sna_push_pixels_solid_blt(GCPtr gc, 16275 PixmapPtr bitmap, 16276 DrawablePtr drawable, 16277 RegionPtr region) 16278{ 16279 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16280 struct sna *sna = to_sna_from_pixmap(pixmap); 16281 struct sna_damage **damage; 16282 struct kgem_bo *bo; 16283 const BoxRec *box; 16284 int16_t dx, dy; 16285 int n; 16286 uint8_t rop = copy_ROP[gc->alu]; 16287 16288 bo = sna_drawable_use_bo(drawable, PREFER_GPU, ®ion->extents, &damage); 16289 if (bo == NULL) 16290 return false; 16291 16292 if (bo->tiling == I915_TILING_Y) { 16293 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16294 assert(bo == __sna_pixmap_get_bo(pixmap)); 16295 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16296 if (bo == NULL) { 16297 DBG(("%s: fallback -- unable to change tiling\n", 16298 __FUNCTION__)); 16299 return false; 16300 } 16301 } 16302 16303 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16304 RegionTranslate(region, dx, dy); 16305 16306 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 16307 if (damage) 16308 sna_damage_add(damage, region); 16309 assert_pixmap_damage(pixmap); 16310 16311 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, 16312 region->extents.x1, region->extents.y1, 16313 region->extents.x2, region->extents.y2)); 16314 16315 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16316 16317 /* Region is pre-clipped and translated into pixmap space */ 16318 box = region_rects(region); 16319 n = region_num_rects(region); 16320 do { 16321 int bx1 = (box->x1 - region->extents.x1) & ~7; 16322 int bx2 = (box->x2 - region->extents.x1 + 7) & ~7; 16323 int bw = (bx2 - bx1)/8; 16324 int bh = box->y2 - box->y1; 16325 int bstride = ALIGN(bw, 2); 16326 struct kgem_bo *upload; 16327 void *ptr; 16328 16329 if (!kgem_check_batch(&sna->kgem, 10) || 16330 !kgem_check_bo_fenced(&sna->kgem, bo) || 16331 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 16332 kgem_submit(&sna->kgem); 16333 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 16334 return false; 16335 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16336 } 16337 16338 upload = kgem_create_buffer(&sna->kgem, 16339 bstride*bh, 16340 KGEM_BUFFER_WRITE_INPLACE, 16341 &ptr); 16342 if (!upload) 16343 break; 16344 16345 if (sigtrap_get() == 0) { 16346 uint8_t *dst = ptr; 16347 16348 int src_stride = bitmap->devKind; 16349 uint8_t *src; 16350 uint32_t *b; 16351 16352 assert(src_stride); 16353 src = (uint8_t*)bitmap->devPrivate.ptr; 16354 src += (box->y1 - region->extents.y1) * src_stride + bx1/8; 16355 src_stride -= bstride; 16356 do { 16357 int i = bstride; 16358 do { 16359 *dst++ = byte_reverse(*src++); 16360 *dst++ = byte_reverse(*src++); 16361 i -= 2; 16362 } while (i); 16363 src += src_stride; 16364 } while (--bh); 16365 16366 assert(sna->kgem.mode == KGEM_BLT); 16367 b = sna->kgem.batch + sna->kgem.nbatch; 16368 if (sna->kgem.gen >= 0100) { 16369 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 16370 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16371 b[1] = bo->pitch; 16372 if (sna->kgem.gen >= 040 && bo->tiling) { 16373 b[0] |= BLT_DST_TILED; 16374 b[1] >>= 2; 16375 } 16376 b[1] |= 1 << 29; 16377 b[1] |= blt_depth(drawable->depth) << 24; 16378 b[1] |= rop << 16; 16379 b[2] = box->y1 << 16 | box->x1; 16380 b[3] = box->y2 << 16 | box->x2; 16381 *(uint64_t *)(b+4) = 16382 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16383 I915_GEM_DOMAIN_RENDER << 16 | 16384 I915_GEM_DOMAIN_RENDER | 16385 KGEM_RELOC_FENCED, 16386 0); 16387 *(uint64_t *)(b+6) = 16388 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 16389 I915_GEM_DOMAIN_RENDER << 16 | 16390 KGEM_RELOC_FENCED, 16391 0); 16392 b[8] = gc->bgPixel; 16393 b[9] = gc->fgPixel; 16394 sna->kgem.nbatch += 10; 16395 } else { 16396 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 16397 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16398 b[1] = bo->pitch; 16399 if (sna->kgem.gen >= 040 && bo->tiling) { 16400 b[0] |= BLT_DST_TILED; 16401 b[1] >>= 2; 16402 } 16403 b[1] |= 1 << 29; 16404 b[1] |= blt_depth(drawable->depth) << 24; 16405 b[1] |= rop << 16; 16406 b[2] = box->y1 << 16 | box->x1; 16407 b[3] = box->y2 << 16 | box->x2; 16408 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16409 I915_GEM_DOMAIN_RENDER << 16 | 16410 I915_GEM_DOMAIN_RENDER | 16411 KGEM_RELOC_FENCED, 16412 0); 16413 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 16414 I915_GEM_DOMAIN_RENDER << 16 | 16415 KGEM_RELOC_FENCED, 16416 0); 16417 b[6] = gc->bgPixel; 16418 b[7] = gc->fgPixel; 16419 16420 sna->kgem.nbatch += 8; 16421 } 16422 sigtrap_put(); 16423 } 16424 16425 kgem_bo_destroy(&sna->kgem, upload); 16426 16427 box++; 16428 } while (--n); 16429 16430 sna->blt_state.fill_bo = 0; 16431 return true; 16432} 16433 16434static void 16435sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable, 16436 int w, int h, 16437 int x, int y) 16438{ 16439 RegionRec region; 16440 16441 if (w == 0 || h == 0) 16442 return; 16443 16444 DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 16445 16446 region.extents.x1 = x; 16447 region.extents.y1 = y; 16448 region.extents.x2 = region.extents.x1 + w; 16449 region.extents.y2 = region.extents.y1 + h; 16450 16451 clip_box(®ion.extents, gc); 16452 if (box_empty(®ion.extents)) 16453 return; 16454 16455 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16456 region.extents.x1, region.extents.y1, 16457 region.extents.x2, region.extents.y2)); 16458 16459 region.data = NULL; 16460 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16461 return; 16462 16463 switch (gc->fillStyle) { 16464 case FillSolid: 16465 if (sna_push_pixels_solid_blt(gc, bitmap, drawable, ®ion)) 16466 return; 16467 break; 16468 default: 16469 break; 16470 } 16471 16472 DBG(("%s: fallback\n", __FUNCTION__)); 16473 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16474 goto out; 16475 if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ)) 16476 goto out; 16477 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16478 drawable_gc_flags(drawable, gc, false))) 16479 goto out; 16480 16481 if (sigtrap_get() == 0) { 16482 DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n", 16483 __FUNCTION__, w, h, x, y)); 16484 fbPushPixels(gc, bitmap, drawable, w, h, x, y); 16485 FALLBACK_FLUSH(drawable); 16486 sigtrap_put(); 16487 } 16488out: 16489 sna_gc_move_to_gpu(gc); 16490 RegionUninit(®ion); 16491} 16492 16493static const GCOps sna_gc_ops = { 16494 sna_fill_spans, 16495 sna_set_spans, 16496 sna_put_image, 16497 sna_copy_area, 16498 sna_copy_plane, 16499 sna_poly_point, 16500 sna_poly_line, 16501 sna_poly_segment, 16502 sna_poly_rectangle, 16503 sna_poly_arc, 16504 sna_poly_fill_polygon, 16505 sna_poly_fill_rect, 16506 sna_poly_fill_arc, 16507 sna_poly_text8, 16508 sna_poly_text16, 16509 sna_image_text8, 16510 sna_image_text16, 16511 sna_image_glyph, 16512 sna_poly_glyph, 16513 sna_push_pixels, 16514}; 16515 16516static const GCOps sna_gc_ops__cpu = { 16517 fbFillSpans, 16518 fbSetSpans, 16519 fbPutImage, 16520 fbCopyArea, 16521 fbCopyPlane, 16522 sna_poly_point__cpu, 16523 fbPolyLine, 16524 fbPolySegment, 16525 miPolyRectangle, 16526 fbPolyArc, 16527 miFillPolygon, 16528 fbPolyFillRect, 16529 miPolyFillArc, 16530 miPolyText8, 16531 miPolyText16, 16532 miImageText8, 16533 miImageText16, 16534 fbImageGlyphBlt, 16535 fbPolyGlyphBlt, 16536 fbPushPixels 16537}; 16538 16539static GCOps sna_gc_ops__tmp = { 16540 sna_fill_spans, 16541 sna_set_spans, 16542 sna_put_image, 16543 sna_copy_area, 16544 sna_copy_plane, 16545 sna_poly_point, 16546 sna_poly_line, 16547 sna_poly_segment, 16548 sna_poly_rectangle, 16549 sna_poly_arc, 16550 sna_poly_fill_polygon, 16551 sna_poly_fill_rect, 16552 sna_poly_fill_arc, 16553 sna_poly_text8, 16554 sna_poly_text16, 16555 sna_image_text8, 16556 sna_image_text16, 16557 sna_image_glyph, 16558 sna_poly_glyph, 16559 sna_push_pixels, 16560}; 16561 16562static void 16563sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) 16564{ 16565 DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc, 16566 changes, gc->serialNumber, drawable->serialNumber)); 16567 16568 if (changes & (GCClipMask|GCSubwindowMode) || 16569 drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) || 16570 (gc->clientClipType != CT_NONE && (changes & (GCClipXOrigin | GCClipYOrigin)))) { 16571 DBG(("%s: recomputing clip\n", __FUNCTION__)); 16572 miComputeCompositeClip(gc, drawable); 16573 DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n", 16574 __FUNCTION__, 16575 region_num_rects(gc->pCompositeClip), 16576 gc->pCompositeClip->extents.x1, 16577 gc->pCompositeClip->extents.y1, 16578 gc->pCompositeClip->extents.x2, 16579 gc->pCompositeClip->extents.y2, 16580 gc->pCompositeClip)); 16581 } 16582 16583 assert(gc->pCompositeClip); 16584 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x); 16585 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y); 16586 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width); 16587 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height); 16588 16589 sna_gc(gc)->changes |= changes; 16590 sna_gc(gc)->serial = gc->serialNumber; 16591} 16592 16593static const GCFuncs sna_gc_funcs = { 16594 sna_validate_gc, 16595 miChangeGC, 16596 miCopyGC, 16597 miDestroyGC, 16598 miChangeClip, 16599 miDestroyClip, 16600 miCopyClip 16601}; 16602 16603static const GCFuncs sna_gc_funcs__cpu = { 16604 fbValidateGC, 16605 miChangeGC, 16606 miCopyGC, 16607 miDestroyGC, 16608 miChangeClip, 16609 miDestroyClip, 16610 miCopyClip 16611}; 16612 16613static int sna_create_gc(GCPtr gc) 16614{ 16615 gc->miTranslate = 1; 16616 gc->fExpose = 1; 16617 16618 gc->freeCompClip = 0; 16619 gc->pCompositeClip = 0; 16620 gc->pRotatedPixmap = 0; 16621 16622 fb_gc(gc)->bpp = bits_per_pixel(gc->depth); 16623 16624 gc->funcs = (GCFuncs *)&sna_gc_funcs; 16625 gc->ops = (GCOps *)&sna_gc_ops; 16626 return true; 16627} 16628 16629static bool 16630sna_get_image__inplace(PixmapPtr pixmap, 16631 RegionPtr region, 16632 char *dst, 16633 unsigned flags, 16634 bool idle) 16635{ 16636 struct sna_pixmap *priv = sna_pixmap(pixmap); 16637 struct sna *sna = to_sna_from_pixmap(pixmap); 16638 char *src; 16639 16640 if (!USE_INPLACE) 16641 return false; 16642 16643 assert(priv && priv->gpu_bo); 16644 16645 switch (priv->gpu_bo->tiling) { 16646 case I915_TILING_Y: 16647 return false; 16648 case I915_TILING_X: 16649 if (!sna->kgem.memcpy_from_tiled_x) 16650 return false; 16651 default: 16652 break; 16653 } 16654 16655 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 16656 return false; 16657 16658 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 16659 return false; 16660 16661 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 16662 return false; 16663 16664 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 16665 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 16666 16667 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 16668 if (src == NULL) 16669 return false; 16670 16671 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 16672 16673 if (sigtrap_get()) 16674 return false; 16675 16676 if (priv->gpu_bo->tiling) { 16677 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 16678 memcpy_from_tiled_x(&sna->kgem, src, dst, 16679 pixmap->drawable.bitsPerPixel, 16680 priv->gpu_bo->pitch, 16681 PixmapBytePad(region->extents.x2 - region->extents.x1, 16682 pixmap->drawable.depth), 16683 region->extents.x1, region->extents.y1, 16684 0, 0, 16685 region->extents.x2 - region->extents.x1, 16686 region->extents.y2 - region->extents.y1); 16687 } else { 16688 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 16689 memcpy_blt(src, dst, 16690 pixmap->drawable.bitsPerPixel, 16691 priv->gpu_bo->pitch, 16692 PixmapBytePad(region->extents.x2 - region->extents.x1, 16693 pixmap->drawable.depth), 16694 region->extents.x1, region->extents.y1, 16695 0, 0, 16696 region->extents.x2 - region->extents.x1, 16697 region->extents.y2 - region->extents.y1); 16698 if (!priv->shm) { 16699 assert(src == MAP(priv->gpu_bo->map__cpu)); 16700 pixmap->devPrivate.ptr = src; 16701 pixmap->devKind = priv->gpu_bo->pitch; 16702 priv->mapped = MAPPED_CPU; 16703 assert_pixmap_map(pixmap, priv); 16704 priv->cpu = true; 16705 } 16706 } 16707 16708 sigtrap_put(); 16709 return true; 16710} 16711 16712static bool 16713sna_get_image__blt(PixmapPtr pixmap, 16714 RegionPtr region, 16715 char *dst, 16716 unsigned flags) 16717{ 16718 struct sna_pixmap *priv = sna_pixmap(pixmap); 16719 struct sna *sna = to_sna_from_pixmap(pixmap); 16720 struct kgem_bo *dst_bo; 16721 bool ok = false; 16722 int pitch; 16723 16724 assert(priv && priv->gpu_bo); 16725 16726 if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS) 16727 return false; 16728 16729 if (!sna->kgem.can_blt_cpu) 16730 return false; 16731 16732 if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT && 16733 kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 16734 if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT)) 16735 return false; 16736 16737 if (priv->gpu_damage == NULL) 16738 return false; 16739 16740 assert(priv->gpu_bo); 16741 if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 16742 return false; 16743 } else { 16744 if (priv->gpu_damage == NULL) 16745 return false; 16746 16747 assert(priv->gpu_bo); 16748 } 16749 16750 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 16751 return false; 16752 16753 DBG(("%s: download through a temporary map\n", __FUNCTION__)); 16754 16755 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 16756 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 16757 16758 pitch = PixmapBytePad(region->extents.x2 - region->extents.x1, 16759 pixmap->drawable.depth); 16760 dst_bo = kgem_create_map(&sna->kgem, dst, 16761 pitch * (region->extents.y2 - region->extents.y1), 16762 false); 16763 if (dst_bo) { 16764 dst_bo->pitch = pitch; 16765 kgem_bo_mark_unreusable(dst_bo); 16766 16767 ok = sna->render.copy_boxes(sna, GXcopy, 16768 &pixmap->drawable, priv->gpu_bo, 0, 0, 16769 &pixmap->drawable, dst_bo, 16770 -region->extents.x1, 16771 -region->extents.y1, 16772 ®ion->extents, 1, 16773 COPY_LAST); 16774 16775 kgem_bo_sync__cpu(&sna->kgem, dst_bo); 16776 assert(dst_bo->rq == NULL); 16777 kgem_bo_destroy(&sna->kgem, dst_bo); 16778 } 16779 16780 return ok; 16781} 16782 16783static bool 16784sna_get_image__fast(PixmapPtr pixmap, 16785 RegionPtr region, 16786 char *dst, 16787 unsigned flags) 16788{ 16789 struct sna_pixmap *priv = sna_pixmap(pixmap); 16790 16791 DBG(("%s: attached?=%d, has gpu damage?=%d\n", 16792 __FUNCTION__, priv != NULL, priv && priv->gpu_damage)); 16793 if (priv == NULL || priv->gpu_damage == NULL) 16794 return false; 16795 16796 if (priv->clear) { 16797 int w = region->extents.x2 - region->extents.x1; 16798 int h = region->extents.y2 - region->extents.y1; 16799 int pitch = PixmapBytePad(w, pixmap->drawable.depth); 16800 16801 DBG(("%s: applying clear [%08x]\n", 16802 __FUNCTION__, priv->clear_color)); 16803 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 16804 assert(priv->cpu_damage == NULL); 16805 16806 if (priv->clear_color == 0 || 16807 pixmap->drawable.bitsPerPixel == 8 || 16808 priv->clear_color == (1U << pixmap->drawable.depth) - 1) { 16809 DBG(("%s: memset clear [%02x]\n", 16810 __FUNCTION__, priv->clear_color & 0xff)); 16811 memset(dst, priv->clear_color, pitch * h); 16812 } else { 16813 pixman_fill((uint32_t *)dst, 16814 pitch/sizeof(uint32_t), 16815 pixmap->drawable.bitsPerPixel, 16816 0, 0, 16817 w, h, 16818 priv->clear_color); 16819 } 16820 16821 return true; 16822 } 16823 16824 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 16825 !sna_damage_contains_box__no_reduce(priv->gpu_damage, 16826 ®ion->extents)) 16827 return false; 16828 16829 if (sna_get_image__inplace(pixmap, region, dst, flags, true)) 16830 return true; 16831 16832 if (sna_get_image__blt(pixmap, region, dst, flags)) 16833 return true; 16834 16835 if (sna_get_image__inplace(pixmap, region, dst, flags, false)) 16836 return true; 16837 16838 return false; 16839} 16840 16841static void 16842sna_get_image(DrawablePtr drawable, 16843 int x, int y, int w, int h, 16844 unsigned int format, unsigned long mask, 16845 char *dst) 16846{ 16847 RegionRec region; 16848 unsigned int flags; 16849 16850 if (!fbDrawableEnabled(drawable)) 16851 return; 16852 16853 DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n", 16854 __FUNCTION__, 16855 (long)get_drawable_pixmap(drawable)->drawable.serialNumber, 16856 x, y, w, h, format, mask, drawable->depth)); 16857 16858 flags = MOVE_READ; 16859 if ((w | h) == 1) 16860 flags |= MOVE_INPLACE_HINT; 16861 if (w == drawable->width) 16862 flags |= MOVE_WHOLE_HINT; 16863 16864 if (ACCEL_GET_IMAGE && 16865 !FORCE_FALLBACK && 16866 format == ZPixmap && 16867 drawable->bitsPerPixel >= 8 && 16868 PM_IS_SOLID(drawable, mask)) { 16869 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16870 int16_t dx, dy; 16871 16872 get_drawable_deltas(drawable, pixmap, &dx, &dy); 16873 region.extents.x1 = x + drawable->x + dx; 16874 region.extents.y1 = y + drawable->y + dy; 16875 region.extents.x2 = region.extents.x1 + w; 16876 region.extents.y2 = region.extents.y1 + h; 16877 region.data = NULL; 16878 16879 if (sna_get_image__fast(pixmap, ®ion, dst, flags)) 16880 return; 16881 16882 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 16883 ®ion, flags)) 16884 return; 16885 16886 DBG(("%s: copy box (%d, %d), (%d, %d)\n", 16887 __FUNCTION__, 16888 region.extents.x1, region.extents.y1, 16889 region.extents.x2, region.extents.y2)); 16890 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ)); 16891 if (sigtrap_get() == 0) { 16892 assert(pixmap->devKind); 16893 memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel, 16894 pixmap->devKind, PixmapBytePad(w, drawable->depth), 16895 region.extents.x1, region.extents.y1, 0, 0, w, h); 16896 sigtrap_put(); 16897 } 16898 } else { 16899 region.extents.x1 = x + drawable->x; 16900 region.extents.y1 = y + drawable->y; 16901 region.extents.x2 = region.extents.x1 + w; 16902 region.extents.y2 = region.extents.y1 + h; 16903 region.data = NULL; 16904 16905 if (sna_drawable_move_region_to_cpu(drawable, ®ion, flags)) 16906 fbGetImage(drawable, x, y, w, h, format, mask, dst); 16907 } 16908} 16909 16910static void 16911sna_get_spans(DrawablePtr drawable, int wMax, 16912 DDXPointPtr pt, int *width, int n, char *start) 16913{ 16914 RegionRec region; 16915 16916 if (!fbDrawableEnabled(drawable)) 16917 return; 16918 16919 if (sna_spans_extents(drawable, NULL, n, pt, width, ®ion.extents) == 0) 16920 return; 16921 16922 region.data = NULL; 16923 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_READ)) 16924 return; 16925 16926 fbGetSpans(drawable, wMax, pt, width, n, start); 16927} 16928 16929static void 16930sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src) 16931{ 16932 PixmapPtr pixmap = get_window_pixmap(win); 16933 struct sna *sna = to_sna_from_pixmap(pixmap); 16934 RegionRec dst; 16935 int dx, dy; 16936 16937 DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y)); 16938 if (!fbWindowEnabled(win)) 16939 return; 16940 16941 dx = origin.x - win->drawable.x; 16942 dy = origin.y - win->drawable.y; 16943 RegionTranslate(src, -dx, -dy); 16944 16945 RegionNull(&dst); 16946 RegionIntersect(&dst, &win->borderClip, src); 16947 if (box_empty(&dst.extents)) 16948 return; 16949 16950#ifdef COMPOSITE 16951 if (pixmap->screen_x | pixmap->screen_y) 16952 RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y); 16953#endif 16954 16955 if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) { 16956 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16957 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 16958 return; 16959 16960 if (sigtrap_get() == 0) { 16961 miCopyRegion(&pixmap->drawable, &pixmap->drawable, 16962 0, &dst, dx, dy, fbCopyNtoN, 0, NULL); 16963 sigtrap_put(); 16964 } 16965 } else { 16966 sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL, 16967 &dst, dx, dy, 0, NULL); 16968 } 16969 16970 RegionUninit(&dst); 16971} 16972 16973static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) 16974{ 16975 bool ret = true; 16976 16977 DBG(("%s\n", __FUNCTION__)); 16978 16979 /* Check if the fb layer wishes to modify the attached pixmaps, 16980 * to fix up mismatches between the window and pixmap depths. 16981 */ 16982 if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) { 16983 DBG(("%s: flushing background pixmap\n", __FUNCTION__)); 16984 ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap); 16985 } 16986 16987 if (mask & CWBorderPixmap && win->borderIsPixel == false) { 16988 DBG(("%s: flushing border pixmap\n", __FUNCTION__)); 16989 ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap); 16990 } 16991 16992 return ret; 16993} 16994 16995void sna_accel_flush(struct sna *sna) 16996{ 16997 struct sna_pixmap *priv; 16998 16999 /* XXX we should be able to reduce the frequency of flushes further 17000 * by checking for outgoing damage events or sync replies. Tricky, 17001 * and doesn't appear to mitigate the performance loss. 17002 */ 17003 DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__, 17004 sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps))); 17005 17006 /* flush any pending damage from shadow copies to tfp clients */ 17007 while (!list_is_empty(&sna->flush_pixmaps)) { 17008 bool ret; 17009 17010 priv = list_first_entry(&sna->flush_pixmaps, 17011 struct sna_pixmap, flush_list); 17012 17013 list_del(&priv->flush_list); 17014 if (priv->shm) { 17015 DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n", 17016 __FUNCTION__, 17017 priv->pixmap->drawable.serialNumber, 17018 priv->pixmap->refcnt)); 17019 assert(!priv->flush); 17020 ret = sna_pixmap_move_to_cpu(priv->pixmap, 17021 MOVE_READ | MOVE_WRITE); 17022 assert(!ret || priv->gpu_bo == NULL); 17023 if (priv->pixmap->refcnt == 0) { 17024 sna_damage_destroy(&priv->cpu_damage); 17025 __sna_free_pixmap(sna, priv->pixmap, priv); 17026 } 17027 } else { 17028 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__, 17029 priv->pixmap->drawable.serialNumber)); 17030 assert(priv->flush); 17031 if (sna_pixmap_move_to_gpu(priv->pixmap, 17032 MOVE_READ | __MOVE_FORCE)) { 17033 if (priv->flush & 2) { 17034 kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 17035 sna_damage_all(&priv->gpu_damage, priv->pixmap); 17036 assert(priv->cpu_damage == NULL); 17037 priv->clear = false; 17038 priv->cpu = false; 17039 } 17040 } 17041 } 17042 (void)ret; 17043 } 17044 17045 if (sna->kgem.flush) 17046 kgem_submit(&sna->kgem); 17047} 17048 17049static void 17050sna_accel_flush_callback(CallbackListPtr *list, 17051 pointer user_data, pointer call_data) 17052{ 17053 sna_accel_flush(user_data); 17054} 17055 17056static struct sna_pixmap *sna_accel_scanout(struct sna *sna) 17057{ 17058 struct sna_pixmap *priv; 17059 17060 if (sna->mode.front_active == 0) 17061 return NULL; 17062 17063 assert(sna->vblank_interval); 17064 assert(sna->front); 17065 17066 priv = sna_pixmap(sna->front); 17067 if (priv->gpu_bo == NULL) 17068 return NULL; 17069 17070 return priv; 17071} 17072 17073#define TIME currentTime.milliseconds 17074static void sna_accel_disarm_timer(struct sna *sna, int id) 17075{ 17076 DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME)); 17077 sna->timer_active &= ~(1<<id); 17078} 17079 17080static bool has_offload_slaves(struct sna *sna) 17081{ 17082#if HAS_PIXMAP_SHARING 17083 ScreenPtr screen = sna->scrn->pScreen; 17084 PixmapDirtyUpdatePtr dirty; 17085 17086 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17087 assert(dirty->src == sna->front); 17088 if (RegionNotEmpty(DamageRegion(dirty->damage))) 17089 return true; 17090 } 17091#endif 17092 return false; 17093} 17094 17095static bool has_shadow(struct sna *sna) 17096{ 17097 DamagePtr damage = sna->mode.shadow_damage; 17098 17099 if (damage == NULL) 17100 return false; 17101 17102 DBG(("%s: has pending damage? %d, outstanding flips: %d\n", 17103 __FUNCTION__, 17104 RegionNotEmpty(DamageRegion(damage)), 17105 sna->mode.flip_active)); 17106 17107 return RegionNotEmpty(DamageRegion(damage)); 17108} 17109 17110static bool start_flush(struct sna *sna) 17111{ 17112 struct sna_pixmap *scanout; 17113 17114 if (has_offload_slaves(sna)) { 17115 DBG(("%s: has offload slaves\n", __FUNCTION__)); 17116 return true; 17117 } 17118 17119 if (has_shadow(sna)) { 17120 DBG(("%s: has dirty shadow\n", __FUNCTION__)); 17121 return true; 17122 } 17123 17124 scanout = sna_accel_scanout(sna); 17125 if (!scanout) 17126 return false; 17127 17128 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17129 scanout->gpu_bo->needs_flush = true; 17130 return true; 17131 } 17132 17133 if (scanout->cpu_damage || scanout->gpu_bo->needs_flush) 17134 return true; 17135 17136 kgem_scanout_flush(&sna->kgem, scanout->gpu_bo); 17137 return false; 17138} 17139 17140static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout) 17141{ 17142 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 17143 __FUNCTION__, 17144 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 17145 has_shadow(sna), has_offload_slaves(sna), 17146 scanout && scanout->cpu_damage != NULL, 17147 scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL)); 17148 17149 if (has_offload_slaves(sna)) 17150 return true; 17151 17152 if (has_shadow(sna)) 17153 return true; 17154 17155 if (!scanout) 17156 return false; 17157 17158 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17159 scanout->gpu_bo->needs_flush = true; 17160 return true; 17161 } 17162 17163 return scanout->cpu_damage || scanout->gpu_bo->needs_flush; 17164} 17165 17166static void timer_enable(struct sna *sna, int whom, int interval) 17167{ 17168 if (!sna->timer_active) 17169 UpdateCurrentTimeIf(); 17170 sna->timer_active |= 1 << whom; 17171 sna->timer_expire[whom] = TIME + interval; 17172 DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); 17173} 17174 17175static bool sna_scanout_do_flush(struct sna *sna) 17176{ 17177 int interval = sna->vblank_interval ?: 50; 17178 if (sna->timer_active & (1<<(FLUSH_TIMER))) { 17179 int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME; 17180 DBG(("%s: flush timer active: delta=%d\n", 17181 __FUNCTION__, delta)); 17182 if (delta <= 3) { 17183 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17184 sna->timer_expire[FLUSH_TIMER] = TIME + interval; 17185 return true; 17186 } 17187 } else { 17188 if (start_flush(sna)) 17189 timer_enable(sna, FLUSH_TIMER, interval/2); 17190 } 17191 17192 return false; 17193} 17194 17195static bool sna_accel_do_throttle(struct sna *sna) 17196{ 17197 if (sna->timer_active & (1<<(THROTTLE_TIMER))) { 17198 int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME; 17199 if (delta <= 3) { 17200 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17201 sna->timer_expire[THROTTLE_TIMER] = TIME + 20; 17202 return true; 17203 } 17204 } else if (!sna->kgem.need_retire) { 17205 DBG(("%s -- no pending activity\n", __FUNCTION__)); 17206 } else 17207 timer_enable(sna, THROTTLE_TIMER, 20); 17208 17209 return false; 17210} 17211 17212static bool sna_accel_do_expire(struct sna *sna) 17213{ 17214 if (sna->timer_active & (1<<(EXPIRE_TIMER))) { 17215 int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME; 17216 if (delta <= 3) { 17217 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17218 sna->timer_expire[EXPIRE_TIMER] = 17219 TIME + MAX_INACTIVE_TIME * 1000; 17220 return true; 17221 } 17222 } else if (sna->kgem.need_expire) 17223 timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000); 17224 17225 return false; 17226} 17227 17228static void sna_accel_post_damage(struct sna *sna) 17229{ 17230#if HAS_PIXMAP_SHARING 17231 ScreenPtr screen = sna->scrn->pScreen; 17232 PixmapDirtyUpdatePtr dirty; 17233 bool flush = false; 17234 17235 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17236 RegionRec region, *damage; 17237 PixmapPtr src, dst; 17238 const BoxRec *box; 17239 int16_t dx, dy; 17240 int n; 17241 17242 assert(dirty->src == sna->front); 17243 17244 damage = DamageRegion(dirty->damage); 17245 if (RegionNil(damage)) 17246 continue; 17247 17248 src = dirty->src; 17249 dst = dirty->slave_dst->master_pixmap; 17250 17251 region.extents.x1 = dirty->x; 17252 region.extents.x2 = dirty->x + dst->drawable.width; 17253 region.extents.y1 = dirty->y; 17254 region.extents.y2 = dirty->y + dst->drawable.height; 17255 region.data = NULL; 17256 17257 DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__, 17258 damage->extents.x1, damage->extents.y1, 17259 damage->extents.x2, damage->extents.y2, 17260 region_num_rects(damage), 17261 dst->drawable.serialNumber, 17262 region.extents.x1, region.extents.y1, 17263 region.extents.x2, region.extents.y2)); 17264 17265 RegionIntersect(®ion, ®ion, damage); 17266 if (RegionNil(®ion)) 17267 goto skip; 17268 17269 dx = -dirty->x; 17270 dy = -dirty->y; 17271#if HAS_DIRTYTRACKING2 17272 dx += dirty->dst_x; 17273 dy += dirty->dst_y; 17274#endif 17275 RegionTranslate(®ion, dx, dy); 17276 DamageRegionAppend(&dirty->slave_dst->drawable, ®ion); 17277 17278 DBG(("%s: slave: ((%d, %d), (%d, %d))x%d\n", __FUNCTION__, 17279 region.extents.x1, region.extents.y1, 17280 region.extents.x2, region.extents.y2, 17281 region_num_rects(®ion))); 17282 17283 box = region_rects(®ion); 17284 n = region_num_rects(®ion); 17285 if (wedged(sna)) { 17286fallback: 17287 if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) 17288 goto skip; 17289 17290 if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT)) 17291 goto skip; 17292 17293 if (sigtrap_get() == 0) { 17294 assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel); 17295 do { 17296 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 17297 __FUNCTION__, 17298 box->x1 - dx, box->y1 - dy, 17299 box->x1, box->y1, 17300 box->x2 - box->x1, box->y2 - box->y1)); 17301 17302 assert(box->x2 > box->x1); 17303 assert(box->y2 > box->y1); 17304 17305 assert(box->x1 - dx >= 0); 17306 assert(box->y1 - dy >= 0); 17307 assert(box->x2 - dx <= src->drawable.width); 17308 assert(box->y2 - dy <= src->drawable.height); 17309 17310 assert(box->x1 >= 0); 17311 assert(box->y1 >= 0); 17312 assert(box->x2 <= src->drawable.width); 17313 assert(box->y2 <= src->drawable.height); 17314 17315 assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ)); 17316 assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE)); 17317 assert(src->devKind); 17318 assert(dst->devKind); 17319 memcpy_blt(src->devPrivate.ptr, 17320 dst->devPrivate.ptr, 17321 src->drawable.bitsPerPixel, 17322 src->devKind, dst->devKind, 17323 box->x1 - dx, box->y1 - dy, 17324 box->x1, box->y1, 17325 box->x2 - box->x1, box->y2 - box->y1); 17326 box++; 17327 } while (--n); 17328 sigtrap_put(); 17329 } 17330 } else { 17331 if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17332 goto fallback; 17333 17334 if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17335 goto fallback; 17336 17337 if (!sna->render.copy_boxes(sna, GXcopy, 17338 &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy, 17339 &dst->drawable, __sna_pixmap_get_bo(dst), 0, 0, 17340 box, n, COPY_LAST)) 17341 goto fallback; 17342 17343 flush = true; 17344 } 17345 17346 DamageRegionProcessPending(&dirty->slave_dst->drawable); 17347skip: 17348 RegionUninit(®ion); 17349 DamageEmpty(dirty->damage); 17350 } 17351 if (flush) 17352 kgem_submit(&sna->kgem); 17353#endif 17354} 17355 17356static void sna_scanout_flush(struct sna *sna) 17357{ 17358 struct sna_pixmap *priv = sna_accel_scanout(sna); 17359 bool busy; 17360 17361 DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n", 17362 __FUNCTION__, (long)TIME, 17363 priv && priv->cpu_damage, 17364 priv && priv->gpu_bo->exec != NULL, 17365 sna->kgem.nbatch, 17366 sna->kgem.busy)); 17367 17368 busy = stop_flush(sna, priv); 17369 if (!sna->kgem.busy && !busy) 17370 sna_accel_disarm_timer(sna, FLUSH_TIMER); 17371 sna->kgem.busy = busy; 17372 17373 if (priv && 17374 sna_pixmap_force_to_gpu(priv->pixmap, 17375 MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) 17376 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 17377 17378 sna_mode_redisplay(sna); 17379 sna_accel_post_damage(sna); 17380} 17381 17382static void sna_accel_throttle(struct sna *sna) 17383{ 17384 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17385 17386 if (sna->kgem.need_throttle) { 17387 kgem_submit(&sna->kgem); 17388 kgem_throttle(&sna->kgem); 17389 } 17390 17391 if (!sna->kgem.need_retire) 17392 sna_accel_disarm_timer(sna, THROTTLE_TIMER); 17393} 17394 17395static void sna_pixmap_expire(struct sna *sna) 17396{ 17397 while (sna->freed_pixmap) { 17398 PixmapPtr pixmap = __pop_freed_pixmap(sna); 17399 free(sna_pixmap(pixmap)); 17400 FreePixmap(pixmap); 17401 } 17402} 17403 17404static void sna_accel_expire(struct sna *sna) 17405{ 17406 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17407 17408 kgem_expire_cache(&sna->kgem); 17409 sna_pixmap_expire(sna); 17410 17411 if (!sna->kgem.need_expire) 17412 sna_accel_disarm_timer(sna, EXPIRE_TIMER); 17413} 17414 17415#ifdef DEBUG_MEMORY 17416static bool sna_accel_do_debug_memory(struct sna *sna) 17417{ 17418 int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME; 17419 17420 if (delta <= 3) { 17421 sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000; 17422 return true; 17423 } else 17424 return false; 17425} 17426 17427static void sna_accel_debug_memory(struct sna *sna) 17428{ 17429 ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n", 17430 sna->debug_memory.pixmap_allocs, 17431 sna->debug_memory.pixmap_cached, 17432 sna->kgem.debug_memory.bo_allocs, 17433 (unsigned long)sna->kgem.debug_memory.bo_bytes, 17434 sna->debug_memory.cpu_bo_allocs, 17435 (unsigned long)sna->debug_memory.cpu_bo_bytes); 17436 17437#ifdef VALGRIND_DO_ADDED_LEAK_CHECK 17438 VG(VALGRIND_DO_ADDED_LEAK_CHECK); 17439#endif 17440} 17441 17442#else 17443#define sna_accel_do_debug_memory(x) 0 17444static void sna_accel_debug_memory(struct sna *sna) { } 17445#endif 17446 17447static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL }; 17448 17449static PixmapPtr 17450sna_get_window_pixmap(WindowPtr window) 17451{ 17452 return get_window_pixmap(window); 17453} 17454 17455static void 17456sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) 17457{ 17458 *(PixmapPtr *)__get_private(window, sna_window_key) = pixmap; 17459} 17460 17461struct sna_visit_set_pixmap_window { 17462 PixmapPtr old, new; 17463}; 17464 17465static int 17466sna_visit_set_window_pixmap(WindowPtr window, pointer data) 17467{ 17468 struct sna_visit_set_pixmap_window *visit = data; 17469 17470 if (sna_get_window_pixmap(window) == visit->old) { 17471 window->drawable.pScreen->SetWindowPixmap(window, visit->new); 17472 return WT_WALKCHILDREN; 17473 } 17474 17475 return WT_DONTWALKCHILDREN; 17476} 17477 17478static void 17479migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front) 17480{ 17481#if HAS_PIXMAP_SHARING 17482 ScreenPtr screen = old_front->drawable.pScreen; 17483 PixmapDirtyUpdatePtr dirty, safe; 17484 17485 xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) { 17486 assert(dirty->src == old_front); 17487 if (dirty->src != old_front) 17488 continue; 17489 17490 DamageUnregister(&dirty->src->drawable, dirty->damage); 17491 DamageDestroy(dirty->damage); 17492 17493 dirty->damage = DamageCreate(NULL, NULL, 17494 DamageReportNone, 17495 TRUE, screen, screen); 17496 if (!dirty->damage) { 17497 xorg_list_del(&dirty->ent); 17498 free(dirty); 17499 continue; 17500 } 17501 17502 DamageRegister(&new_front->drawable, dirty->damage); 17503 dirty->src = new_front; 17504 } 17505#endif 17506} 17507 17508static void 17509sna_set_screen_pixmap(PixmapPtr pixmap) 17510{ 17511 ScreenPtr screen = pixmap->drawable.pScreen; 17512 PixmapPtr old_front = screen->devPrivate; 17513 WindowPtr root; 17514 17515 DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n", 17516 __FUNCTION__, 17517 old_front ? (long)old_front->drawable.serialNumber : 0, 17518 pixmap ? (long)pixmap->drawable.serialNumber : 0, 17519 to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0)); 17520 17521 assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen)); 17522 assert(to_sna_from_pixmap(pixmap)->front == old_front); 17523 17524 if (old_front) { 17525 assert(to_sna_from_pixmap(old_front)->front == old_front); 17526 migrate_dirty_tracking(old_front, pixmap); 17527 } 17528 17529 root = get_root_window(screen); 17530 if (root) { 17531 struct sna_visit_set_pixmap_window visit = { old_front, pixmap }; 17532 TraverseTree(root, sna_visit_set_window_pixmap, &visit); 17533 assert(fbGetWindowPixmap(root) == pixmap); 17534 } 17535 17536 to_sna_from_pixmap(pixmap)->front = pixmap; 17537 screen->devPrivate = pixmap; 17538 pixmap->refcnt++; 17539 17540 if (old_front) 17541 screen->DestroyPixmap(old_front); 17542} 17543 17544static Bool 17545sna_create_window(WindowPtr win) 17546{ 17547 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate); 17548 return TRUE; 17549} 17550 17551static Bool 17552sna_map_window(WindowPtr win) 17553{ 17554 return TRUE; 17555} 17556 17557static Bool 17558sna_position_window(WindowPtr win, int x, int y) 17559{ 17560 return TRUE; 17561} 17562 17563static Bool 17564sna_unmap_window(WindowPtr win) 17565{ 17566 return TRUE; 17567} 17568 17569static Bool 17570sna_destroy_window(WindowPtr win) 17571{ 17572 sna_video_destroy_window(win); 17573 sna_dri2_destroy_window(win); 17574 return TRUE; 17575} 17576 17577static void 17578sna_query_best_size(int class, 17579 unsigned short *width, unsigned short *height, 17580 ScreenPtr screen) 17581{ 17582 unsigned short w; 17583 17584 switch (class) { 17585 case CursorShape: 17586 if (*width > screen->width) 17587 *width = screen->width; 17588 if (*height > screen->height) 17589 *height = screen->height; 17590 break; 17591 17592 case TileShape: 17593 case StippleShape: 17594 w = *width; 17595 if ((w & (w - 1)) && w < FB_UNIT) { 17596 for (w = 1; w < *width; w <<= 1) 17597 ; 17598 *width = w; 17599 } 17600 break; 17601 } 17602} 17603 17604static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def) 17605{ 17606} 17607 17608static bool sna_picture_init(ScreenPtr screen) 17609{ 17610 PictureScreenPtr ps; 17611 17612 DBG(("%s\n", __FUNCTION__)); 17613 17614 if (!miPictureInit(screen, NULL, 0)) 17615 return false; 17616 17617 ps = GetPictureScreen(screen); 17618 assert(ps != NULL); 17619 assert(ps->CreatePicture != NULL); 17620 assert(ps->DestroyPicture != NULL); 17621 17622 ps->Composite = sna_composite; 17623 ps->CompositeRects = sna_composite_rectangles; 17624 ps->Glyphs = sna_glyphs; 17625 if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0])) 17626 ps->Glyphs = sna_glyphs__shared; 17627 ps->UnrealizeGlyph = sna_glyph_unrealize; 17628 ps->AddTraps = sna_add_traps; 17629 ps->Trapezoids = sna_composite_trapezoids; 17630#if HAS_PIXMAN_TRIANGLES 17631 ps->Triangles = sna_composite_triangles; 17632#if PICTURE_SCREEN_VERSION >= 2 17633 ps->TriStrip = sna_composite_tristrip; 17634 ps->TriFan = sna_composite_trifan; 17635#endif 17636#endif 17637 17638 return true; 17639} 17640 17641static bool sna_option_accel_none(struct sna *sna) 17642{ 17643 const char *s; 17644 17645 if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE)) 17646 return true; 17647 17648 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 17649 if (s == NULL) 17650 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 17651 17652 return strcasecmp(s, "none") == 0; 17653} 17654 17655static bool sna_option_accel_blt(struct sna *sna) 17656{ 17657 const char *s; 17658 17659 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 17660 if (s == NULL) 17661 return false; 17662 17663 return strcasecmp(s, "blt") == 0; 17664} 17665 17666bool sna_accel_init(ScreenPtr screen, struct sna *sna) 17667{ 17668 const char *backend; 17669 17670 DBG(("%s\n", __FUNCTION__)); 17671 17672 sna_font_key = AllocateFontPrivateIndex(); 17673 17674 list_init(&sna->flush_pixmaps); 17675 list_init(&sna->active_pixmaps); 17676 17677 AddGeneralSocket(sna->kgem.fd); 17678 17679#ifdef DEBUG_MEMORY 17680 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000; 17681#endif 17682 17683 screen->defColormap = FakeClientID(0); 17684 /* let CreateDefColormap do whatever it wants for pixels */ 17685 screen->blackPixel = screen->whitePixel = (Pixel) 0; 17686 screen->QueryBestSize = sna_query_best_size; 17687 assert(screen->GetImage == NULL); 17688 screen->GetImage = sna_get_image; 17689 assert(screen->GetSpans == NULL); 17690 screen->GetSpans = sna_get_spans; 17691 assert(screen->CreateWindow == NULL); 17692 screen->CreateWindow = sna_create_window; 17693 assert(screen->DestroyWindow == NULL); 17694 screen->DestroyWindow = sna_destroy_window; 17695 screen->PositionWindow = sna_position_window; 17696 screen->ChangeWindowAttributes = sna_change_window_attributes; 17697 screen->RealizeWindow = sna_map_window; 17698 screen->UnrealizeWindow = sna_unmap_window; 17699 screen->CopyWindow = sna_copy_window; 17700 assert(screen->CreatePixmap == NULL); 17701 screen->CreatePixmap = sna_create_pixmap; 17702 assert(screen->DestroyPixmap == NULL); 17703 screen->DestroyPixmap = sna_destroy_pixmap; 17704#ifdef CREATE_PIXMAP_USAGE_SHARED 17705 screen->SharePixmapBacking = sna_share_pixmap_backing; 17706 screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing; 17707#endif 17708 screen->RealizeFont = sna_realize_font; 17709 screen->UnrealizeFont = sna_unrealize_font; 17710 assert(screen->CreateGC == NULL); 17711 screen->CreateGC = sna_create_gc; 17712 screen->CreateColormap = miInitializeColormap; 17713 screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA; 17714 screen->InstallColormap = miInstallColormap; 17715 screen->UninstallColormap = miUninstallColormap; 17716 screen->ListInstalledColormaps = miListInstalledColormaps; 17717 screen->ResolveColor = miResolveColor; 17718 assert(screen->StoreColors == NULL); 17719 screen->StoreColors = sna_store_colors; 17720 screen->BitmapToRegion = fbBitmapToRegion; 17721 17722#if HAS_PIXMAP_SHARING 17723 screen->StartPixmapTracking = PixmapStartDirtyTracking; 17724 screen->StopPixmapTracking = PixmapStopDirtyTracking; 17725#endif 17726 17727 assert(screen->GetWindowPixmap == NULL); 17728 screen->GetWindowPixmap = sna_get_window_pixmap; 17729 assert(screen->SetWindowPixmap == NULL); 17730 screen->SetWindowPixmap = sna_set_window_pixmap; 17731 17732 screen->SetScreenPixmap = sna_set_screen_pixmap; 17733 17734 if (sna->kgem.has_userptr) 17735 ShmRegisterFuncs(screen, &shm_funcs); 17736 else 17737 ShmRegisterFbFuncs(screen); 17738 17739 if (!sna_picture_init(screen)) 17740 return false; 17741 17742 backend = no_render_init(sna); 17743 if (sna_option_accel_none(sna)) { 17744 backend = "disabled"; 17745 sna->kgem.wedged = true; 17746 } else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110) 17747 (void)backend; 17748 else if (sna->info->gen >= 0100) 17749 backend = gen8_render_init(sna, backend); 17750 else if (sna->info->gen >= 070) 17751 backend = gen7_render_init(sna, backend); 17752 else if (sna->info->gen >= 060) 17753 backend = gen6_render_init(sna, backend); 17754 else if (sna->info->gen >= 050) 17755 backend = gen5_render_init(sna, backend); 17756 else if (sna->info->gen >= 040) 17757 backend = gen4_render_init(sna, backend); 17758 else if (sna->info->gen >= 030) 17759 backend = gen3_render_init(sna, backend); 17760 else if (sna->info->gen >= 020) 17761 backend = gen2_render_init(sna, backend); 17762 17763 DBG(("%s(backend=%s, prefer_gpu=%x)\n", 17764 __FUNCTION__, backend, sna->render.prefer_gpu)); 17765 17766 kgem_reset(&sna->kgem); 17767 sigtrap_init(); 17768 17769 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 17770 "SNA initialized with %s backend\n", 17771 backend); 17772 17773 return true; 17774} 17775 17776void sna_accel_create(struct sna *sna) 17777{ 17778 DBG(("%s\n", __FUNCTION__)); 17779 17780 if (!sna_glyphs_create(sna)) 17781 goto fail; 17782 17783 if (!sna_gradients_create(sna)) 17784 goto fail; 17785 17786 if (!sna_composite_create(sna)) 17787 goto fail; 17788 17789 return; 17790 17791fail: 17792 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 17793 "Failed to allocate caches, disabling RENDER acceleration\n"); 17794 no_render_init(sna); 17795} 17796 17797void sna_accel_watch_flush(struct sna *sna, int enable) 17798{ 17799 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 17800 assert(enable); 17801 17802 if (sna->watch_flush == 0) { 17803 DBG(("%s: installing watchers\n", __FUNCTION__)); 17804 assert(enable > 0); 17805 if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) { 17806 xf86DrvMsg(sna->scrn->scrnIndex, X_Error, 17807 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n"); 17808 } 17809 sna->watch_flush++; 17810 } 17811 17812 sna->watch_flush += enable; 17813} 17814 17815void sna_accel_leave(struct sna *sna) 17816{ 17817 DBG(("%s\n", __FUNCTION__)); 17818 17819 /* as root we always have permission to render */ 17820 if (geteuid() == 0) 17821 return; 17822 17823 /* as a user, we can only render now if we have a rendernode */ 17824 if (intel_has_render_node(sna->scrn)) 17825 return; 17826 17827 /* no longer authorized to use our fd */ 17828 DBG(("%s: dropping render privileges\n", __FUNCTION__)); 17829 17830 kgem_submit(&sna->kgem); 17831 sna->kgem.wedged |= 2; 17832} 17833 17834void sna_accel_enter(struct sna *sna) 17835{ 17836 DBG(("%s\n", __FUNCTION__)); 17837 sna->kgem.wedged &= kgem_is_wedged(&sna->kgem); 17838 kgem_throttle(&sna->kgem); 17839} 17840 17841void sna_accel_close(struct sna *sna) 17842{ 17843 DBG(("%s\n", __FUNCTION__)); 17844 17845 sna_composite_close(sna); 17846 sna_gradients_close(sna); 17847 sna_glyphs_close(sna); 17848 17849 sna_pixmap_expire(sna); 17850 17851 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 17852 RemoveGeneralSocket(sna->kgem.fd); 17853 17854 kgem_cleanup_cache(&sna->kgem); 17855} 17856 17857void sna_accel_block_handler(struct sna *sna, struct timeval **tv) 17858{ 17859 sigtrap_assert_inactive(); 17860 17861 if (sna->kgem.need_retire) 17862 kgem_retire(&sna->kgem); 17863 kgem_retire__buffers(&sna->kgem); 17864 17865 if (sna->timer_active) 17866 UpdateCurrentTimeIf(); 17867 17868 if (sna->kgem.nbatch && 17869 (sna->kgem.scanout_busy || 17870 kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) { 17871 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 17872 _kgem_submit(&sna->kgem); 17873 } 17874 17875restart: 17876 if (sna_scanout_do_flush(sna)) 17877 sna_scanout_flush(sna); 17878 assert(sna_accel_scanout(sna) == NULL || 17879 !sna_accel_scanout(sna)->gpu_bo->needs_flush || 17880 sna->timer_active & (1<<(FLUSH_TIMER))); 17881 17882 if (sna_accel_do_throttle(sna)) 17883 sna_accel_throttle(sna); 17884 assert(!sna->kgem.need_retire || 17885 sna->timer_active & (1<<(THROTTLE_TIMER))); 17886 17887 if (sna_accel_do_expire(sna)) 17888 sna_accel_expire(sna); 17889 assert(!sna->kgem.need_expire || 17890 sna->timer_active & (1<<(EXPIRE_TIMER))); 17891 17892 if (sna_accel_do_debug_memory(sna)) 17893 sna_accel_debug_memory(sna); 17894 17895 if (sna->watch_flush == 1) { 17896 DBG(("%s: removing watchers\n", __FUNCTION__)); 17897 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 17898 sna->watch_flush = 0; 17899 } 17900 17901 if (sna->timer_active & 1) { 17902 int32_t timeout; 17903 17904 DBG(("%s: evaluating timers, active=%x\n", 17905 __FUNCTION__, sna->timer_active)); 17906 17907 timeout = sna->timer_expire[FLUSH_TIMER] - TIME; 17908 DBG(("%s: flush timer expires in %d [%d]\n", 17909 __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER])); 17910 if (timeout < 3) 17911 goto restart; 17912 17913 if (*tv == NULL) { 17914 *tv = &sna->timer_tv; 17915 goto set_tv; 17916 } 17917 if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) { 17918set_tv: 17919 (*tv)->tv_sec = timeout / 1000; 17920 (*tv)->tv_usec = timeout % 1000 * 1000; 17921 } 17922 } 17923 17924 sna->kgem.scanout_busy = false; 17925 17926 if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) { 17927 DBG(("%s hardware acceleration\n", 17928 sna->kgem.wedged ? "Re-enabling" : "Disabling")); 17929 kgem_submit(&sna->kgem); 17930 sna->kgem.wedged = !sna->kgem.wedged; 17931 } 17932} 17933 17934void sna_accel_wakeup_handler(struct sna *sna) 17935{ 17936 DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__, 17937 sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge)); 17938 17939 if (!sna->kgem.nbatch) 17940 return; 17941 17942 if (kgem_is_idle(&sna->kgem)) { 17943 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 17944 _kgem_submit(&sna->kgem); 17945 } 17946 17947 sigtrap_assert_inactive(); 17948} 17949 17950void sna_accel_free(struct sna *sna) 17951{ 17952 DBG(("%s\n", __FUNCTION__)); 17953 sigtrap_assert_inactive(); 17954} 17955