sna_accel.c revision 46edf8f1
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_SPANS 0 /* -1 force CPU, 1 force GPU */ 73#define USE_CPU_BO 1 74#define USE_USERPTR_UPLOADS 1 75#define USE_USERPTR_DOWNLOADS 1 76#define USE_COW 1 77#define UNDO 1 78 79#define MIGRATE_ALL 0 80#define DBG_NO_PARTIAL_MOVE_TO_CPU 0 81#define DBG_NO_CPU_UPLOAD 0 82#define DBG_NO_CPU_DOWNLOAD 0 83 84#define ACCEL_FILL_SPANS 1 85#define ACCEL_SET_SPANS 1 86#define ACCEL_PUT_IMAGE 1 87#define ACCEL_GET_IMAGE 1 88#define ACCEL_COPY_AREA 1 89#define ACCEL_COPY_PLANE 1 90#define ACCEL_COPY_WINDOW 1 91#define ACCEL_POLY_POINT 1 92#define ACCEL_POLY_LINE 1 93#define ACCEL_POLY_SEGMENT 1 94#define ACCEL_POLY_RECTANGLE 1 95#define ACCEL_POLY_ARC 1 96#define ACCEL_POLY_FILL_POLYGON 1 97#define ACCEL_POLY_FILL_RECT 1 98#define ACCEL_POLY_FILL_ARC 1 99#define ACCEL_POLY_TEXT8 1 100#define ACCEL_POLY_TEXT16 1 101#define ACCEL_POLY_GLYPH 1 102#define ACCEL_IMAGE_TEXT8 1 103#define ACCEL_IMAGE_TEXT16 1 104#define ACCEL_IMAGE_GLYPH 1 105#define ACCEL_PUSH_PIXELS 1 106 107#define NO_TILE_8x8 0 108#define NO_STIPPLE_8x8 0 109 110#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) 111#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) 112#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) 113 114#define IS_CLIPPED 0x2 115#define RECTILINEAR 0x4 116#define OVERWRITES 0x8 117 118#if 0 119static void __sna_fallback_flush(DrawablePtr d) 120{ 121 PixmapPtr pixmap = get_drawable_pixmap(d); 122 struct sna *sna = to_sna_from_pixmap(pixmap); 123 struct sna_pixmap *priv; 124 BoxRec box; 125 PixmapPtr tmp; 126 int i, j; 127 char *src, *dst; 128 129 DBG(("%s: uploading CPU damage...\n", __FUNCTION__)); 130 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 131 if (priv == NULL) 132 return; 133 134 DBG(("%s: downloading GPU damage...\n", __FUNCTION__)); 135 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 136 return; 137 138 box.x1 = box.y1 = 0; 139 box.x2 = pixmap->drawable.width; 140 box.y2 = pixmap->drawable.height; 141 142 tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen, 143 pixmap->drawable.width, 144 pixmap->drawable.height, 145 pixmap->drawable.depth, 146 0); 147 148 DBG(("%s: comparing with direct read...\n", __FUNCTION__)); 149 sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1); 150 151 src = pixmap->devPrivate.ptr; 152 dst = tmp->devPrivate.ptr; 153 for (i = 0; i < tmp->drawable.height; i++) { 154 if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) { 155 for (j = 0; src[j] == dst[j]; j++) 156 ; 157 ERR(("mismatch at (%d, %d)\n", 158 8*j / tmp->drawable.bitsPerPixel, i)); 159 abort(); 160 } 161 src += pixmap->devKind; 162 dst += tmp->devKind; 163 } 164 tmp->drawable.pScreen->DestroyPixmap(tmp); 165} 166#define FALLBACK_FLUSH(d) __sna_fallback_flush(d) 167#else 168#define FALLBACK_FLUSH(d) 169#endif 170 171static int sna_font_key; 172 173static const uint8_t copy_ROP[] = { 174 ROP_0, /* GXclear */ 175 ROP_DSa, /* GXand */ 176 ROP_SDna, /* GXandReverse */ 177 ROP_S, /* GXcopy */ 178 ROP_DSna, /* GXandInverted */ 179 ROP_D, /* GXnoop */ 180 ROP_DSx, /* GXxor */ 181 ROP_DSo, /* GXor */ 182 ROP_DSon, /* GXnor */ 183 ROP_DSxn, /* GXequiv */ 184 ROP_Dn, /* GXinvert */ 185 ROP_SDno, /* GXorReverse */ 186 ROP_Sn, /* GXcopyInverted */ 187 ROP_DSno, /* GXorInverted */ 188 ROP_DSan, /* GXnand */ 189 ROP_1 /* GXset */ 190}; 191static const uint8_t fill_ROP[] = { 192 ROP_0, 193 ROP_DPa, 194 ROP_PDna, 195 ROP_P, 196 ROP_DPna, 197 ROP_D, 198 ROP_DPx, 199 ROP_DPo, 200 ROP_DPon, 201 ROP_PDxn, 202 ROP_Dn, 203 ROP_PDno, 204 ROP_Pn, 205 ROP_DPno, 206 ROP_DPan, 207 ROP_1 208}; 209 210static const GCOps sna_gc_ops; 211static const GCOps sna_gc_ops__cpu; 212static GCOps sna_gc_ops__tmp; 213static const GCFuncs sna_gc_funcs; 214static const GCFuncs sna_gc_funcs__cpu; 215 216static void 217sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect); 218 219static inline void region_set(RegionRec *r, const BoxRec *b) 220{ 221 r->extents = *b; 222 r->data = NULL; 223} 224 225static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip) 226{ 227 if (clip->data && !RegionIntersect(r, r, clip)) 228 return false; 229 230 return !box_empty(&r->extents); 231} 232 233static inline bool region_is_singular(const RegionRec *r) 234{ 235 return r->data == NULL; 236} 237 238static inline bool region_is_unclipped(const RegionRec *r, int w, int h) 239{ 240 return (region_is_singular(r) && 241 w == r->extents.x2 - r->extents.x1 && 242 h == r->extents.y2 - r->extents.y1); 243} 244 245typedef struct box32 { 246 int32_t x1, y1, x2, y2; 247} Box32Rec; 248 249#define PM_IS_SOLID(_draw, _pm) \ 250 (((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth)) 251 252#ifndef NDEBUG 253static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function) 254{ 255 if (box->x1 < 0 || box->y1 < 0 || 256 box->x2 > pixmap->drawable.width || 257 box->y2 > pixmap->drawable.height) 258 { 259 FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n", 260 function, box->x1, box->y1, box->x2, box->y2, 261 pixmap->drawable.serialNumber, 262 pixmap->drawable.width, 263 pixmap->drawable.height); 264 } 265} 266 267static void 268_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function) 269{ 270 if (damage == NULL) 271 return; 272 273 _assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function); 274} 275#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__) 276#else 277#define assert_pixmap_contains_damage(p,d) 278#endif 279 280#define __assert_pixmap_damage(p) do { \ 281 struct sna_pixmap *priv__ = sna_pixmap(p); \ 282 if (priv__) { \ 283 assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \ 284 assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \ 285 assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \ 286 assert_pixmap_contains_damage(p, priv__->gpu_damage); \ 287 assert_pixmap_contains_damage(p, priv__->cpu_damage); \ 288 assert_pixmap_map(p, priv__); \ 289 } \ 290} while (0) 291 292#ifdef DEBUG_PIXMAP 293static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function) 294{ 295 BoxRec b = *box; 296 b.x1 += dx; b.x2 += dx; 297 b.y1 += dy; b.y2 += dy; 298 _assert_pixmap_contains_box(pixmap, &b, function); 299} 300 301static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function) 302{ 303 BoxRec extents; 304 305 extents = *box; 306 while (--n) { 307 ++box; 308 309 if (box->x1 < extents.x1) 310 extents.x1 = box->x1; 311 if (box->x2 > extents.x2) 312 extents.x2 = box->x2; 313 314 if (box->y1 < extents.y1) 315 extents.y1 = box->y1; 316 if (box->y2 > extents.y2) 317 extents.y2 = box->y2; 318 } 319 extents.x1 += dx; 320 extents.x2 += dx; 321 extents.y1 += dy; 322 extents.y2 += dy; 323 _assert_pixmap_contains_box(pixmap, &extents, function); 324} 325 326 327static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function) 328{ 329 BoxRec extents; 330 331 extents.x2 = extents.x1 = pt->x; 332 extents.y2 = extents.y1 = pt->y; 333 while (--n) { 334 ++pt; 335 336 if (pt->x < extents.x1) 337 extents.x1 = pt->x; 338 else if (pt->x > extents.x2) 339 extents.x2 = pt->x; 340 341 if (pt->y < extents.y1) 342 extents.y1 = pt->y; 343 else if (pt->y > extents.y2) 344 extents.y2 = pt->y; 345 } 346 extents.x1 += dx; 347 extents.x2 += dx + 1; 348 extents.y1 += dy; 349 extents.y2 += dy + 1; 350 _assert_pixmap_contains_box(pixmap, &extents, function); 351} 352 353static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function) 354{ 355 if (box->x1 < drawable->x || 356 box->y1 < drawable->y || 357 box->x2 > drawable->x + drawable->width || 358 box->y2 > drawable->y + drawable->height) 359 { 360 FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n", 361 function, 362 box->x1, box->y1, box->x2, box->y2, 363 drawable->x, drawable->y, 364 drawable->width, drawable->height); 365 } 366} 367 368static void assert_pixmap_damage(PixmapPtr p) 369{ 370 struct sna_pixmap *priv; 371 RegionRec reg, cpu, gpu; 372 373 priv = sna_pixmap(p); 374 if (priv == NULL) 375 return; 376 377 __assert_pixmap_damage(p); 378 379 if (priv->clear) { 380 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 381 assert(priv->cpu_damage == NULL); 382 } 383 384 if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) { 385 /* special upload buffer */ 386 assert(priv->gpu_bo && priv->gpu_bo->proxy); 387 assert(priv->cpu_bo == NULL); 388 return; 389 } 390 391 assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL); 392 assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL); 393 394 /* Avoid reducing damage to minimise interferrence */ 395 RegionNull(®); 396 RegionNull(&gpu); 397 RegionNull(&cpu); 398 399 if (priv->gpu_damage) 400 _sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu); 401 402 if (priv->cpu_damage) 403 _sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu); 404 405 RegionIntersect(®, &cpu, &gpu); 406 assert(RegionNil(®)); 407 408 RegionUninit(®); 409 RegionUninit(&gpu); 410 RegionUninit(&cpu); 411} 412 413#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 414#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__) 415#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__) 416#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__) 417#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__) 418 419#else 420#define assert_pixmap_contains_box(p, b) 421#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) 422#define assert_pixmap_contains_boxes(p, b, n, x, y) 423#define assert_pixmap_contains_points(p, pt, n, x, y) 424#define assert_drawable_contains_box(d, b) 425#ifndef NDEBUG 426#define assert_pixmap_damage(p) __assert_pixmap_damage(p) 427#else 428#define assert_pixmap_damage(p) 429#endif 430#endif 431 432jmp_buf sigjmp[4]; 433volatile sig_atomic_t sigtrap; 434 435static int sigtrap_handler(int sig) 436{ 437 /* XXX rate-limited squawk? */ 438 DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap)); 439 sna_threads_trap(sig); 440 441 if (sigtrap) 442 siglongjmp(sigjmp[--sigtrap], sig); 443 444 return -1; 445} 446 447static void sigtrap_init(void) 448{ 449#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 450 OsRegisterSigWrapper(sigtrap_handler); 451#endif 452} 453 454inline static bool 455sna_fill_init_blt(struct sna_fill_op *fill, 456 struct sna *sna, 457 PixmapPtr pixmap, 458 struct kgem_bo *bo, 459 uint8_t alu, 460 uint32_t pixel, 461 unsigned flags) 462{ 463 return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill); 464} 465 466static bool 467sna_copy_init_blt(struct sna_copy_op *copy, 468 struct sna *sna, 469 PixmapPtr src, struct kgem_bo *src_bo, 470 PixmapPtr dst, struct kgem_bo *dst_bo, 471 uint8_t alu) 472{ 473 memset(copy, 0, sizeof(*copy)); 474 return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); 475} 476 477static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv) 478{ 479 DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned)); 480 assert(priv->gpu_damage == NULL || priv->gpu_bo); 481 482 if (priv->cow) 483 sna_pixmap_undo_cow(sna, priv, MOVE_WRITE); 484 assert(priv->cow == NULL); 485 486 if (priv->move_to_gpu) { 487 sna_pixmap_discard_shadow_damage(priv, NULL); 488 priv->move_to_gpu(sna, priv, MOVE_WRITE); 489 } 490 491 sna_damage_destroy(&priv->gpu_damage); 492 priv->clear = false; 493 494 if (priv->gpu_bo) { 495 if (!priv->pinned) { 496 assert(!priv->flush); 497 assert(!priv->move_to_gpu); 498 sna_pixmap_unmap(priv->pixmap, priv); 499 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 500 priv->gpu_bo = NULL; 501 } else 502 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 503 } 504 505 /* and reset the upload counter */ 506 priv->source_count = SOURCE_BIAS; 507} 508 509static bool must_check 510sna_pixmap_alloc_cpu(struct sna *sna, 511 PixmapPtr pixmap, 512 struct sna_pixmap *priv, 513 unsigned flags) 514{ 515 /* Restore after a GTT mapping? */ 516 assert(priv->gpu_damage == NULL || priv->gpu_bo); 517 assert(!priv->shm); 518 if (priv->ptr) 519 goto done; 520 521 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 522 assert(priv->stride); 523 524 if (priv->create & KGEM_CAN_CREATE_CPU) { 525 unsigned hint; 526 527 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__, 528 pixmap->drawable.width, pixmap->drawable.height)); 529 530 hint = 0; 531 if ((flags & MOVE_ASYNC_HINT) == 0 && 532 ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc))) 533 hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE; 534 535 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem, 536 pixmap->drawable.width, 537 pixmap->drawable.height, 538 pixmap->drawable.bitsPerPixel, 539 hint); 540 if (priv->cpu_bo) { 541 priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 542 if (priv->ptr) { 543 DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__, 544 priv->cpu_bo->handle, priv->cpu_bo->snoop)); 545 priv->stride = priv->cpu_bo->pitch; 546#ifdef DEBUG_MEMORY 547 sna->debug_memory.cpu_bo_allocs++; 548 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 549#endif 550 } else { 551 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 552 priv->cpu_bo = NULL; 553 } 554 } 555 } 556 557 if (priv->ptr == NULL) { 558 DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n", 559 __FUNCTION__, priv->stride * pixmap->drawable.height)); 560 priv->ptr = malloc(priv->stride * pixmap->drawable.height); 561 } 562 563done: 564 assert(priv->stride); 565 assert(!priv->mapped); 566 pixmap->devPrivate.ptr = PTR(priv->ptr); 567 pixmap->devKind = priv->stride; 568 return priv->ptr != NULL; 569} 570 571static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 572{ 573 if (priv->cpu_bo) { 574 DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n", 575 __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo))); 576#ifdef DEBUG_MEMORY 577 sna->debug_memory.cpu_bo_allocs--; 578 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 579#endif 580 if (priv->cpu_bo->flush) { 581 assert(!priv->cpu_bo->reusable); 582 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 583 sna_accel_watch_flush(sna, -1); 584 } 585 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 586 } else if (!IS_STATIC_PTR(priv->ptr)) 587 free(priv->ptr); 588} 589 590static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active) 591{ 592 if (active) 593 return false; 594 595 if (IS_STATIC_PTR(priv->ptr)) 596 return false; 597 598 if (priv->ptr == NULL) 599 return true; 600 601 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 602 __sna_pixmap_free_cpu(sna, priv); 603 604 priv->cpu_bo = NULL; 605 priv->ptr = NULL; 606 607 if (priv->mapped == MAPPED_NONE) 608 priv->pixmap->devPrivate.ptr = NULL; 609 610 return true; 611} 612 613static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) 614{ 615#if DEFAULT_TILING == I915_TILING_NONE 616 return I915_TILING_NONE; 617#elif DEFAULT_TILING == I915_TILING_X 618 return I915_TILING_X; 619#else 620 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ 621 if (sna->kgem.gen == 021) 622 return I915_TILING_X; 623 624 /* Only on later generations was the render pipeline 625 * more flexible than the BLT. So on gen2/3, prefer to 626 * keep large objects accessible through the BLT. 627 */ 628 if (sna->kgem.gen < 040 && 629 (pixmap->drawable.width > sna->render.max_3d_size || 630 pixmap->drawable.height > sna->render.max_3d_size)) 631 return I915_TILING_X; 632 633 if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage, 634 pixmap->drawable.width, 635 pixmap->drawable.height)) { 636 DBG(("%s: entire source is damaged, using Y-tiling\n", 637 __FUNCTION__)); 638 sna_damage_destroy(&sna_pixmap(priv)->gpu_damage); 639 return I915_TILING_Y; 640 } 641 642 return I915_TILING_Y; 643#endif 644} 645 646pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap) 647{ 648 /* Also adjust tiling if it is not supported or likely to 649 * slow us down, 650 */ 651 return kgem_choose_tiling(&sna->kgem, 652 default_tiling(sna, pixmap), 653 pixmap->drawable.width, 654 pixmap->drawable.height, 655 pixmap->drawable.bitsPerPixel); 656} 657 658struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) 659{ 660 struct sna_pixmap *priv = sna_pixmap(pixmap); 661 struct sna *sna = to_sna_from_pixmap(pixmap); 662 struct kgem_bo *bo; 663 BoxRec box; 664 665 DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n", 666 __FUNCTION__, priv->gpu_bo->tiling, tiling, 667 pixmap->drawable.width, pixmap->drawable.height)); 668 assert(priv->gpu_damage == NULL || priv->gpu_bo); 669 670 if (priv->pinned) { 671 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 672 return NULL; 673 } 674 675 if (wedged(sna)) { 676 DBG(("%s: can't convert bo, wedged\n", __FUNCTION__)); 677 return NULL; 678 } 679 680 assert_pixmap_damage(pixmap); 681 assert(!priv->move_to_gpu); 682 683 bo = kgem_create_2d(&sna->kgem, 684 pixmap->drawable.width, 685 pixmap->drawable.height, 686 pixmap->drawable.bitsPerPixel, 687 tiling, 0); 688 if (bo == NULL) { 689 DBG(("%s: allocation failed\n", __FUNCTION__)); 690 return NULL; 691 } 692 693 box.x1 = box.y1 = 0; 694 box.x2 = pixmap->drawable.width; 695 box.y2 = pixmap->drawable.height; 696 697 if (!sna->render.copy_boxes(sna, GXcopy, 698 &pixmap->drawable, priv->gpu_bo, 0, 0, 699 &pixmap->drawable, bo, 0, 0, 700 &box, 1, 0)) { 701 DBG(("%s: copy failed\n", __FUNCTION__)); 702 kgem_bo_destroy(&sna->kgem, bo); 703 return NULL; 704 } 705 706 sna_pixmap_unmap(pixmap, priv); 707 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 708 709 return priv->gpu_bo = bo; 710} 711 712static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna) 713{ 714 ((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna; 715 assert(sna_pixmap(pixmap) == sna); 716} 717 718static struct sna_pixmap * 719_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) 720{ 721 list_init(&priv->flush_list); 722 list_init(&priv->cow_list); 723 priv->source_count = SOURCE_BIAS; 724 priv->pixmap = pixmap; 725 726 return priv; 727} 728 729static struct sna_pixmap * 730_sna_pixmap_reset(PixmapPtr pixmap) 731{ 732 struct sna_pixmap *priv; 733 734 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 735 assert(pixmap->drawable.class == 0); 736 assert(pixmap->drawable.x == 0); 737 assert(pixmap->drawable.y == 0); 738 739 priv = sna_pixmap(pixmap); 740 assert(priv != NULL); 741 742 memset(priv, 0, sizeof(*priv)); 743 return _sna_pixmap_init(priv, pixmap); 744} 745 746static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) 747{ 748 struct sna_pixmap *priv; 749 750 priv = calloc(1, sizeof(*priv)); 751 if (!priv) 752 return NULL; 753 754 sna_set_pixmap(pixmap, priv); 755 return _sna_pixmap_init(priv, pixmap); 756} 757 758struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) 759{ 760 struct sna_pixmap *priv; 761 762 assert(bo); 763 assert(bo->proxy == NULL); 764 assert(bo->unique_id); 765 766 priv = sna_pixmap_attach(pixmap); 767 if (!priv) 768 return NULL; 769 770 DBG(("%s: attaching %s handle=%d to pixmap=%ld\n", 771 __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber)); 772 773 assert(!priv->mapped); 774 assert(!priv->move_to_gpu); 775 776 if (bo->snoop) { 777 priv->cpu_bo = bo; 778 sna_damage_all(&priv->cpu_damage, pixmap); 779 } else { 780 priv->gpu_bo = bo; 781 sna_damage_all(&priv->gpu_damage, pixmap); 782 } 783 784 return priv; 785} 786 787static int bits_per_pixel(int depth) 788{ 789 switch (depth) { 790 case 1: return 1; 791 case 4: 792 case 8: return 8; 793 case 15: 794 case 16: return 16; 795 case 24: 796 case 30: 797 case 32: return 32; 798 default: return 0; 799 } 800} 801static PixmapPtr 802create_pixmap(struct sna *sna, ScreenPtr screen, 803 int width, int height, int depth, 804 unsigned usage_hint) 805{ 806 PixmapPtr pixmap; 807 size_t datasize; 808 size_t stride; 809 int base, bpp; 810 811 bpp = bits_per_pixel(depth); 812 if (bpp == 0) 813 return NullPixmap; 814 815 stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 816 if (stride / 4 > 32767 || height > 32767) 817 return NullPixmap; 818 819 datasize = height * stride; 820 base = screen->totalPixmapSize; 821 if (datasize && base & 15) { 822 int adjust = 16 - (base & 15); 823 base += adjust; 824 datasize += adjust; 825 } 826 827 DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n", 828 __FUNCTION__, width, height, depth, (long)datasize)); 829 pixmap = AllocatePixmap(screen, datasize); 830 if (!pixmap) 831 return NullPixmap; 832 833 ((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna; 834 assert(to_sna_from_pixmap(pixmap) == sna); 835 836 pixmap->drawable.type = DRAWABLE_PIXMAP; 837 pixmap->drawable.class = 0; 838 pixmap->drawable.pScreen = screen; 839 pixmap->drawable.depth = depth; 840 pixmap->drawable.bitsPerPixel = bpp; 841 pixmap->drawable.id = 0; 842 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 843 pixmap->drawable.x = 0; 844 pixmap->drawable.y = 0; 845 pixmap->drawable.width = width; 846 pixmap->drawable.height = height; 847 pixmap->devKind = stride; 848 pixmap->refcnt = 1; 849 pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL; 850 851#ifdef COMPOSITE 852 pixmap->screen_x = 0; 853 pixmap->screen_y = 0; 854#endif 855 856 pixmap->usage_hint = usage_hint; 857#if DEBUG_MEMORY 858 sna->debug_memory.pixmap_allocs++; 859#endif 860 861 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 862 __FUNCTION__, 863 pixmap->drawable.serialNumber, 864 pixmap->usage_hint, 865 pixmap->drawable.width, 866 pixmap->drawable.height)); 867 868 return pixmap; 869} 870 871static PixmapPtr 872__pop_freed_pixmap(struct sna *sna) 873{ 874 PixmapPtr pixmap; 875 876 assert(sna->freed_pixmap); 877 878 pixmap = sna->freed_pixmap; 879 sna->freed_pixmap = pixmap->devPrivate.ptr; 880 881 assert(pixmap->refcnt == 0); 882 assert(sna_pixmap(pixmap)); 883 assert(sna_pixmap(pixmap)->header); 884 885#if DEBUG_MEMORY 886 sna->debug_memory.pixmap_cached--; 887#endif 888 889 return pixmap; 890} 891 892inline static PixmapPtr 893create_pixmap_hdr(struct sna *sna, ScreenPtr screen, 894 int width, int height, int depth, int usage, 895 struct sna_pixmap **priv) 896{ 897 PixmapPtr pixmap; 898 899 if (sna->freed_pixmap == NULL) { 900 pixmap = create_pixmap(sna, screen, 0, 0, depth, usage); 901 if (pixmap == NullPixmap) 902 return NullPixmap; 903 904 *priv = sna_pixmap_attach(pixmap); 905 if (!*priv) { 906 FreePixmap(pixmap); 907 return NullPixmap; 908 } 909 } else { 910 pixmap = __pop_freed_pixmap(sna); 911 *priv = _sna_pixmap_reset(pixmap); 912 913 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 914 assert(pixmap->drawable.class == 0); 915 assert(pixmap->drawable.pScreen == screen); 916 assert(pixmap->drawable.x == 0); 917 assert(pixmap->drawable.y == 0); 918 919 pixmap->drawable.id = 0; 920 921 pixmap->drawable.depth = depth; 922 pixmap->drawable.bitsPerPixel = bits_per_pixel(depth); 923 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 924 925 pixmap->devKind = 0; 926 pixmap->devPrivate.ptr = NULL; 927 928#ifdef COMPOSITE 929 pixmap->screen_x = 0; 930 pixmap->screen_y = 0; 931#endif 932 933#if DEBUG_MEMORY 934 sna->debug_memory.pixmap_allocs++; 935#endif 936 937 pixmap->refcnt = 1; 938 } 939 940 DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__, 941 pixmap->drawable.serialNumber, width, height, usage)); 942 pixmap->drawable.width = width; 943 pixmap->drawable.height = height; 944 pixmap->usage_hint = usage; 945 946 (*priv)->header = true; 947 return pixmap; 948} 949 950static PixmapPtr 951sna_pixmap_create_shm(ScreenPtr screen, 952 int width, int height, int depth, 953 char *addr) 954{ 955 struct sna *sna = to_sna_from_screen(screen); 956 int bpp = bits_per_pixel(depth); 957 int pitch = PixmapBytePad(width, depth); 958 struct sna_pixmap *priv; 959 PixmapPtr pixmap; 960 961 DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n", 962 __FUNCTION__, width, height, depth, bpp, pitch)); 963 964 if (wedged(sna) || bpp == 0 || pitch*height < 4096) { 965fallback: 966 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 967 if (pixmap == NULL) 968 return NULL; 969 970 if (!screen->ModifyPixmapHeader(pixmap, width, height, depth, 971 bpp, pitch, addr)) { 972 screen->DestroyPixmap(pixmap); 973 return NULL; 974 } 975 976 return pixmap; 977 } 978 979 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv); 980 if (pixmap == NullPixmap) { 981 DBG(("%s: allocation failed\n", __FUNCTION__)); 982 goto fallback; 983 } 984 985 priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false); 986 if (priv->cpu_bo == NULL) { 987 DBG(("%s: mapping SHM segment failed\n", __FUNCTION__)); 988 sna_pixmap_destroy(pixmap); 989 goto fallback; 990 } 991 priv->cpu_bo->pitch = pitch; 992 kgem_bo_mark_unreusable(priv->cpu_bo); 993 sna_accel_watch_flush(sna, 1); 994#ifdef DEBUG_MEMORY 995 sna->debug_memory.cpu_bo_allocs++; 996 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 997#endif 998 999 /* Be wary as we cannot cache SHM Pixmap in our freed cache */ 1000 priv->header = false; 1001 priv->cpu = true; 1002 priv->shm = true; 1003 priv->stride = pitch; 1004 priv->ptr = MAKE_STATIC_PTR(addr); 1005 sna_damage_all(&priv->cpu_damage, pixmap); 1006 1007 pixmap->devKind = pitch; 1008 pixmap->devPrivate.ptr = addr; 1009 1010 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1011 __FUNCTION__, 1012 pixmap->drawable.serialNumber, 1013 pixmap->drawable.width, 1014 pixmap->drawable.height, 1015 pixmap->usage_hint)); 1016 return pixmap; 1017} 1018 1019PixmapPtr 1020sna_pixmap_create_unattached(ScreenPtr screen, 1021 int width, int height, int depth) 1022{ 1023 return create_pixmap(to_sna_from_screen(screen), 1024 screen, width, height, depth, 1025 -1); 1026} 1027 1028static PixmapPtr 1029sna_pixmap_create_scratch(ScreenPtr screen, 1030 int width, int height, int depth, 1031 uint32_t tiling) 1032{ 1033 struct sna *sna = to_sna_from_screen(screen); 1034 struct sna_pixmap *priv; 1035 PixmapPtr pixmap; 1036 int bpp; 1037 1038 DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__, 1039 width, height, depth, tiling)); 1040 1041 bpp = bits_per_pixel(depth); 1042 if (tiling == I915_TILING_Y && 1043 (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0) 1044 tiling = I915_TILING_X; 1045 1046 if (tiling == I915_TILING_Y && 1047 (width > sna->render.max_3d_size || 1048 height > sna->render.max_3d_size)) 1049 tiling = I915_TILING_X; 1050 1051 tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp); 1052 1053 /* you promise never to access this via the cpu... */ 1054 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv); 1055 if (pixmap == NullPixmap) 1056 return NullPixmap; 1057 1058 priv->stride = PixmapBytePad(width, depth); 1059 1060 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1061 width, height, bpp, tiling, 1062 CREATE_TEMPORARY); 1063 if (priv->gpu_bo == NULL) { 1064 free(priv); 1065 FreePixmap(pixmap); 1066 return NullPixmap; 1067 } 1068 1069 sna_damage_all(&priv->gpu_damage, pixmap); 1070 1071 assert(to_sna_from_pixmap(pixmap) == sna); 1072 assert(pixmap->drawable.pScreen == screen); 1073 assert(pixmap->refcnt == 1); 1074 1075 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1076 __FUNCTION__, 1077 pixmap->drawable.serialNumber, 1078 pixmap->drawable.width, 1079 pixmap->drawable.height, 1080 pixmap->usage_hint)); 1081 return pixmap; 1082} 1083 1084#ifdef CREATE_PIXMAP_USAGE_SHARED 1085static Bool 1086sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle) 1087{ 1088 struct sna *sna = to_sna_from_pixmap(pixmap); 1089 struct sna_pixmap *priv; 1090 int fd; 1091 1092 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1093 1094 priv = sna_pixmap_move_to_gpu(pixmap, 1095 MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE); 1096 if (priv == NULL) 1097 return FALSE; 1098 1099 assert(!priv->shm); 1100 assert(priv->gpu_bo); 1101 assert(priv->stride); 1102 1103 /* XXX negotiate format and stride restrictions */ 1104 if (priv->gpu_bo->tiling != I915_TILING_NONE || 1105 priv->gpu_bo->pitch & 255) { 1106 struct kgem_bo *bo; 1107 BoxRec box; 1108 1109 DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n", 1110 __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch, 1111 pixmap->drawable.width, pixmap->drawable.height, 1112 pixmap->drawable.serialNumber)); 1113 1114 if (priv->pinned) { 1115 DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__, 1116 priv->pinned)); 1117 return FALSE; 1118 } 1119 1120 assert_pixmap_damage(pixmap); 1121 1122 bo = kgem_create_2d(&sna->kgem, 1123 pixmap->drawable.width, 1124 pixmap->drawable.height, 1125 pixmap->drawable.bitsPerPixel, 1126 I915_TILING_NONE, 1127 CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT); 1128 if (bo == NULL) { 1129 DBG(("%s: allocation failed\n", __FUNCTION__)); 1130 return FALSE; 1131 } 1132 1133 box.x1 = box.y1 = 0; 1134 box.x2 = pixmap->drawable.width; 1135 box.y2 = pixmap->drawable.height; 1136 1137 assert(!wedged(sna)); /* XXX */ 1138 if (!sna->render.copy_boxes(sna, GXcopy, 1139 &pixmap->drawable, priv->gpu_bo, 0, 0, 1140 &pixmap->drawable, bo, 0, 0, 1141 &box, 1, 0)) { 1142 DBG(("%s: copy failed\n", __FUNCTION__)); 1143 kgem_bo_destroy(&sna->kgem, bo); 1144 return FALSE; 1145 } 1146 1147 sna_pixmap_unmap(pixmap, priv); 1148 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1149 priv->gpu_bo = bo; 1150 } 1151 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1152 assert((priv->gpu_bo->pitch & 255) == 0); 1153 1154 /* And export the bo->pitch via pixmap->devKind */ 1155 if (!priv->mapped) { 1156 void *ptr; 1157 1158 ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1159 if (ptr == NULL) 1160 return FALSE; 1161 1162 pixmap->devPrivate.ptr = ptr; 1163 pixmap->devKind = priv->gpu_bo->pitch; 1164 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1165 } 1166 assert_pixmap_map(pixmap, priv); 1167 1168 fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo); 1169 if (fd == -1) 1170 return FALSE; 1171 1172 priv->pinned |= PIN_PRIME; 1173 1174 *fd_handle = (void *)(intptr_t)fd; 1175 return TRUE; 1176} 1177 1178static Bool 1179sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle) 1180{ 1181 struct sna *sna = to_sna_from_pixmap(pixmap); 1182 struct sna_pixmap *priv; 1183 struct kgem_bo *bo; 1184 1185 DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n", 1186 __FUNCTION__, pixmap->drawable.serialNumber, 1187 pixmap->drawable.width, pixmap->drawable.height, 1188 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, 1189 pixmap->devKind)); 1190 1191 priv = sna_pixmap(pixmap); 1192 if (priv == NULL) 1193 return FALSE; 1194 1195 assert(!priv->pinned); 1196 assert(priv->gpu_bo == NULL); 1197 assert(priv->cpu_bo == NULL); 1198 assert(priv->cpu_damage == NULL); 1199 assert(priv->gpu_damage == NULL); 1200 1201 bo = kgem_create_for_prime(&sna->kgem, 1202 (intptr_t)fd_handle, 1203 pixmap->devKind * pixmap->drawable.height); 1204 if (bo == NULL) 1205 return FALSE; 1206 1207 sna_damage_all(&priv->gpu_damage, pixmap); 1208 1209 bo->pitch = pixmap->devKind; 1210 priv->stride = pixmap->devKind; 1211 1212 assert(!priv->mapped); 1213 priv->gpu_bo = bo; 1214 priv->pinned |= PIN_PRIME; 1215 1216 close((intptr_t)fd_handle); 1217 return TRUE; 1218} 1219 1220static PixmapPtr 1221sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, 1222 int width, int height, int depth) 1223{ 1224 PixmapPtr pixmap; 1225 struct sna_pixmap *priv; 1226 1227 DBG(("%s: width=%d, height=%d, depth=%d\n", 1228 __FUNCTION__, width, height, depth)); 1229 1230 /* Create a stub to be attached later */ 1231 pixmap = create_pixmap_hdr(sna, screen, 1232 width, height, depth, 0, 1233 &priv); 1234 if (pixmap == NullPixmap) 1235 return NullPixmap; 1236 1237 assert(!priv->mapped); 1238 priv->stride = 0; 1239 priv->create = 0; 1240 1241 if (width|height) { 1242 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1243 width, height, 1244 pixmap->drawable.bitsPerPixel, 1245 I915_TILING_NONE, 1246 CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT); 1247 if (priv->gpu_bo == NULL) { 1248 free(priv); 1249 FreePixmap(pixmap); 1250 return NullPixmap; 1251 } 1252 1253 /* minimal interface for sharing is linear, 256 byte pitch */ 1254 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1255 assert((priv->gpu_bo->pitch & 255) == 0); 1256 1257 pixmap->devPrivate.ptr = 1258 kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1259 if (pixmap->devPrivate.ptr == NULL) { 1260 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1261 free(priv); 1262 FreePixmap(pixmap); 1263 return FALSE; 1264 } 1265 1266 pixmap->devKind = priv->gpu_bo->pitch; 1267 1268 priv->stride = priv->gpu_bo->pitch; 1269 priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1270 assert_pixmap_map(pixmap, priv); 1271 1272 sna_damage_all(&priv->gpu_damage, pixmap); 1273 } 1274 1275 return pixmap; 1276} 1277#endif 1278 1279static PixmapPtr sna_create_pixmap(ScreenPtr screen, 1280 int width, int height, int depth, 1281 unsigned int usage) 1282{ 1283 struct sna *sna = to_sna_from_screen(screen); 1284 PixmapPtr pixmap; 1285 struct sna_pixmap *priv; 1286 unsigned flags; 1287 int pad; 1288 void *ptr; 1289 1290 DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__, 1291 width, height, depth, usage)); 1292 1293#ifdef CREATE_PIXMAP_USAGE_SHARED 1294 if (usage == CREATE_PIXMAP_USAGE_SHARED) 1295 return sna_create_pixmap_shared(sna, screen, 1296 width, height, depth); 1297#endif 1298 1299 if ((width|height) == 0) { 1300 usage = -1; 1301 goto fallback; 1302 } 1303 assert(width && height); 1304 1305 flags = kgem_can_create_2d(&sna->kgem, width, height, depth); 1306 if (flags == 0) { 1307 DBG(("%s: can not use GPU, just creating shadow\n", 1308 __FUNCTION__)); 1309 goto fallback; 1310 } 1311 1312 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)) 1313 flags &= ~KGEM_CAN_CREATE_GPU; 1314 if (wedged(sna)) 1315 flags &= ~KGEM_CAN_CREATE_GTT; 1316 1317 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags)); 1318 switch (usage) { 1319 case CREATE_PIXMAP_USAGE_SCRATCH: 1320 if (flags & KGEM_CAN_CREATE_GPU) 1321 return sna_pixmap_create_scratch(screen, 1322 width, height, depth, 1323 I915_TILING_X); 1324 else 1325 goto fallback; 1326 1327 case SNA_CREATE_SCRATCH: 1328 if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU)) 1329 return sna_pixmap_create_scratch(screen, 1330 width, height, depth, 1331 I915_TILING_Y); 1332 else 1333 return NullPixmap; 1334 } 1335 1336 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) 1337 flags &= ~KGEM_CAN_CREATE_GPU; 1338 if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 1339 usage = 0; 1340 1341 pad = PixmapBytePad(width, depth); 1342 if (pad * height < 4096) { 1343 DBG(("%s: small buffer [%d], attaching to shadow pixmap\n", 1344 __FUNCTION__, pad * height)); 1345 pixmap = create_pixmap(sna, screen, 1346 width, height, depth, usage); 1347 if (pixmap == NullPixmap) 1348 return NullPixmap; 1349 1350 ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 1351 pad = pixmap->devKind; 1352 flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU); 1353 1354 priv = sna_pixmap_attach(pixmap); 1355 if (priv == NULL) { 1356 free(pixmap); 1357 goto fallback; 1358 } 1359 } else { 1360 DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n", 1361 __FUNCTION__, width, height, pad, flags)); 1362 1363 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv); 1364 if (pixmap == NullPixmap) 1365 return NullPixmap; 1366 1367 ptr = NULL; 1368 } 1369 1370 priv->stride = pad; 1371 priv->create = flags; 1372 priv->ptr = ptr; 1373 1374 assert(to_sna_from_pixmap(pixmap) == sna); 1375 assert(pixmap->drawable.pScreen == screen); 1376 assert(pixmap->refcnt == 1); 1377 1378 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1379 __FUNCTION__, 1380 pixmap->drawable.serialNumber, 1381 pixmap->drawable.width, 1382 pixmap->drawable.height, 1383 pixmap->usage_hint)); 1384 return pixmap; 1385 1386fallback: 1387 return create_pixmap(sna, screen, width, height, depth, usage); 1388} 1389 1390void sna_add_flush_pixmap(struct sna *sna, 1391 struct sna_pixmap *priv, 1392 struct kgem_bo *bo) 1393{ 1394 DBG(("%s: marking pixmap=%ld for flushing\n", 1395 __FUNCTION__, priv->pixmap->drawable.serialNumber)); 1396 assert(bo); 1397 assert(bo->flush); 1398 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1399 list_move(&priv->flush_list, &sna->flush_pixmaps); 1400 1401 if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) { 1402 DBG(("%s: new flush bo, flushing before\n", __FUNCTION__)); 1403 _kgem_submit(&sna->kgem); 1404 } 1405} 1406 1407static void __sna_free_pixmap(struct sna *sna, 1408 PixmapPtr pixmap, 1409 struct sna_pixmap *priv) 1410{ 1411 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1412 list_del(&priv->flush_list); 1413 1414 assert(priv->gpu_damage == NULL); 1415 assert(priv->cpu_damage == NULL); 1416 1417 __sna_pixmap_free_cpu(sna, priv); 1418 1419 if (priv->flush) 1420 sna_accel_watch_flush(sna, -1); 1421 1422 if (priv->header) { 1423 assert(pixmap->drawable.pScreen == sna->scrn->pScreen); 1424 assert(!priv->shm); 1425 pixmap->devPrivate.ptr = sna->freed_pixmap; 1426 sna->freed_pixmap = pixmap; 1427#if DEBUG_MEMORY 1428 sna->debug_memory.pixmap_cached++; 1429#endif 1430 } else { 1431 free(priv); 1432 FreePixmap(pixmap); 1433 } 1434} 1435 1436static Bool sna_destroy_pixmap(PixmapPtr pixmap) 1437{ 1438 struct sna *sna; 1439 struct sna_pixmap *priv; 1440 1441 assert(pixmap->refcnt > 0); 1442 if (--pixmap->refcnt) 1443 return TRUE; 1444 1445#if DEBUG_MEMORY 1446 to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--; 1447#endif 1448 1449 priv = sna_pixmap(pixmap); 1450 DBG(("%s: pixmap=%ld, attached?=%d\n", 1451 __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL)); 1452 if (priv == NULL) { 1453 FreePixmap(pixmap); 1454 return TRUE; 1455 } 1456 1457 assert_pixmap_damage(pixmap); 1458 sna = to_sna_from_pixmap(pixmap); 1459 1460 sna_damage_destroy(&priv->gpu_damage); 1461 sna_damage_destroy(&priv->cpu_damage); 1462 1463 list_del(&priv->cow_list); 1464 if (priv->cow) { 1465 struct sna_cow *cow = COW(priv->cow); 1466 DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", 1467 __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); 1468 assert(cow->refcnt); 1469 if (!--cow->refcnt) 1470 free(cow); 1471 priv->cow = NULL; 1472 } else 1473 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1474 1475 if (priv->move_to_gpu) 1476 (void)priv->move_to_gpu(sna, priv, 0); 1477 1478 /* Always release the gpu bo back to the lower levels of caching */ 1479 if (priv->gpu_bo) { 1480 sna_pixmap_unmap(pixmap, priv); 1481 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1482 priv->gpu_bo = NULL; 1483 } 1484 1485 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { 1486 DBG(("%s: deferring release of active SHM pixmap=%ld\n", 1487 __FUNCTION__, pixmap->drawable.serialNumber)); 1488 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 1489 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ 1490 } else 1491 __sna_free_pixmap(sna, pixmap, priv); 1492 return TRUE; 1493} 1494 1495void sna_pixmap_destroy(PixmapPtr pixmap) 1496{ 1497 assert(pixmap->refcnt == 1); 1498 assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true); 1499 1500 sna_destroy_pixmap(pixmap); 1501} 1502 1503static inline bool has_coherent_map(struct sna *sna, 1504 struct kgem_bo *bo, 1505 unsigned flags) 1506{ 1507 assert(bo); 1508 1509 if (kgem_bo_mapped(&sna->kgem, bo)) 1510 return true; 1511 1512 if (bo->tiling == I915_TILING_Y) 1513 return false; 1514 1515 return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE); 1516} 1517 1518static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1519{ 1520 if (priv == NULL) 1521 return true; 1522 1523 if (flags & MOVE_ASYNC_HINT) { 1524 /* Not referencing the pointer itself, so do not care */ 1525 return true; 1526 } 1527 1528 if (!priv->mapped) { 1529 if (!priv->cpu_bo) 1530 return true; 1531 1532 assert(!priv->cpu_bo->needs_flush); 1533 assert(priv->pixmap->devKind == priv->cpu_bo->pitch); 1534 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu); 1535 } 1536 1537 assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0); 1538 1539 assert_pixmap_map(priv->pixmap, priv); 1540 assert(priv->pixmap->devKind == priv->gpu_bo->pitch); 1541 1542 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) { 1543 assert(priv->mapped == MAPPED_CPU); 1544 1545 if (priv->gpu_bo->tiling != I915_TILING_NONE) 1546 return false; 1547 1548 return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE); 1549 } 1550 1551 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) { 1552 assert(priv->mapped == MAPPED_GTT); 1553 1554 if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21) 1555 return false; 1556 1557 return true; 1558 } 1559 1560 return false; 1561} 1562 1563static inline bool pixmap_inplace(struct sna *sna, 1564 PixmapPtr pixmap, 1565 struct sna_pixmap *priv, 1566 unsigned flags) 1567{ 1568 if (FORCE_INPLACE) 1569 return FORCE_INPLACE > 0; 1570 1571 if (wedged(sna) && !priv->pinned) { 1572 DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__)); 1573 return false; 1574 } 1575 1576 if (priv->move_to_gpu && flags & MOVE_WRITE) 1577 return false; 1578 1579 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 1580 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) { 1581 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__)); 1582 return false; 1583 } 1584 1585 if ((flags & MOVE_READ) == 0) { 1586 DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes")); 1587 return !priv->pinned; 1588 } 1589 } 1590 1591 if (priv->mapped) { 1592 DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 1593 return has_coherent_map(sna, priv->gpu_bo, flags); 1594 } 1595 1596 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 1597 DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__)); 1598 return true; 1599 } 1600 1601 if (priv->cpu_bo && priv->cpu) { 1602 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 1603 return false; 1604 } 1605 1606 if (flags & MOVE_READ && 1607 (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) { 1608 DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__)); 1609 return false; 1610 } 1611 1612 return (priv->stride * pixmap->drawable.height >> 12) > 1613 sna->kgem.half_cpu_cache_pages; 1614} 1615 1616static bool sna_pixmap_alloc_gpu(struct sna *sna, 1617 PixmapPtr pixmap, 1618 struct sna_pixmap *priv, 1619 unsigned flags) 1620{ 1621 uint32_t tiling; 1622 1623 /* Use tiling by default, but disable per user request */ 1624 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) { 1625 flags |= CREATE_SCANOUT; 1626 tiling = kgem_choose_tiling(&sna->kgem, 1627 -I915_TILING_X, 1628 pixmap->drawable.width, 1629 pixmap->drawable.height, 1630 pixmap->drawable.bitsPerPixel); 1631 } else 1632 tiling = sna_pixmap_default_tiling(sna, pixmap); 1633 1634 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1635 1636 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1637 pixmap->drawable.width, 1638 pixmap->drawable.height, 1639 pixmap->drawable.bitsPerPixel, 1640 tiling, flags); 1641 return priv->gpu_bo != NULL; 1642} 1643 1644static bool 1645sna_pixmap_create_mappable_gpu(PixmapPtr pixmap, 1646 bool can_replace) 1647{ 1648 struct sna *sna = to_sna_from_pixmap(pixmap); 1649 struct sna_pixmap *priv = sna_pixmap(pixmap); 1650 1651 if (wedged(sna)) 1652 goto out; 1653 1654 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) 1655 goto out; 1656 1657 assert_pixmap_damage(pixmap); 1658 1659 if (can_replace && priv->gpu_bo && 1660 (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) || 1661 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1662 if (priv->pinned) 1663 return false; 1664 1665 DBG(("%s: discard busy GPU bo\n", __FUNCTION__)); 1666 sna_pixmap_free_gpu(sna, priv); 1667 } 1668 1669 if (priv->gpu_bo == NULL) { 1670 assert_pixmap_damage(pixmap); 1671 assert(priv->gpu_damage == NULL); 1672 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE); 1673 } 1674 1675out: 1676 if (priv->gpu_bo == NULL) 1677 return false; 1678 1679 return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1680 !kgem_bo_is_busy(priv->gpu_bo)); 1681} 1682 1683static inline bool gpu_bo_download(struct sna *sna, 1684 struct sna_pixmap *priv, 1685 int n, const BoxRec *box, 1686 bool idle) 1687{ 1688 char *src; 1689 1690 if (!USE_INPLACE) 1691 return false; 1692 1693 switch (priv->gpu_bo->tiling) { 1694 case I915_TILING_Y: 1695 return false; 1696 case I915_TILING_X: 1697 if (!sna->kgem.memcpy_from_tiled_x) 1698 return false; 1699 default: 1700 break; 1701 } 1702 1703 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 1704 return false; 1705 1706 if (idle) { 1707 if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 1708 return false; 1709 1710 if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) 1711 return false; 1712 } 1713 1714 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 1715 if (src == NULL) 1716 return false; 1717 1718 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 1719 1720 if (priv->cpu_bo) 1721 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1722 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1723 1724 if (sigtrap_get()) 1725 return false; 1726 1727 if (priv->gpu_bo->tiling) { 1728 int bpp = priv->pixmap->drawable.bitsPerPixel; 1729 void *dst = priv->pixmap->devPrivate.ptr; 1730 int dst_pitch = priv->pixmap->devKind; 1731 1732 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 1733 do { 1734 DBG(("%s: box (%d, %d), (%d, %d)\n", 1735 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1736 memcpy_from_tiled_x(&sna->kgem, src, dst, bpp, 1737 priv->gpu_bo->pitch, dst_pitch, 1738 box->x1, box->y1, 1739 box->x1, box->y1, 1740 box->x2 - box->x1, box->y2 - box->y1); 1741 box++; 1742 } while (--n); 1743 } else { 1744 int bpp = priv->pixmap->drawable.bitsPerPixel; 1745 void *dst = priv->pixmap->devPrivate.ptr; 1746 int dst_pitch = priv->pixmap->devKind; 1747 1748 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 1749 do { 1750 DBG(("%s: box (%d, %d), (%d, %d)\n", 1751 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1752 memcpy_blt(src, dst, bpp, 1753 priv->gpu_bo->pitch, dst_pitch, 1754 box->x1, box->y1, 1755 box->x1, box->y1, 1756 box->x2 - box->x1, box->y2 - box->y1); 1757 box++; 1758 } while (--n); 1759 } 1760 1761 sigtrap_put(); 1762 return true; 1763} 1764 1765static inline bool cpu_bo_download(struct sna *sna, 1766 struct sna_pixmap *priv, 1767 int n, const BoxRec *box) 1768{ 1769 if (DBG_NO_CPU_DOWNLOAD) 1770 return false; 1771 1772 if (wedged(sna)) 1773 return false; 1774 1775 if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu) 1776 return false; 1777 1778 if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) { 1779 /* Is it worth detiling? */ 1780 assert(box[0].y1 < box[n-1].y2); 1781 if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1782 (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) { 1783 DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n", 1784 __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch)); 1785 return false; 1786 } 1787 } 1788 1789 DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__)); 1790 return sna->render.copy_boxes(sna, GXcopy, 1791 &priv->pixmap->drawable, priv->gpu_bo, 0, 0, 1792 &priv->pixmap->drawable, priv->cpu_bo, 0, 0, 1793 box, n, COPY_LAST); 1794} 1795 1796static void download_boxes(struct sna *sna, 1797 struct sna_pixmap *priv, 1798 int n, const BoxRec *box) 1799{ 1800 bool ok; 1801 1802 DBG(("%s: nbox=%d\n", __FUNCTION__, n)); 1803 1804 ok = gpu_bo_download(sna, priv, n, box, true); 1805 if (!ok) 1806 ok = cpu_bo_download(sna, priv, n, box); 1807 if (!ok) 1808 ok = gpu_bo_download(sna, priv, n, box, false); 1809 if (!ok) { 1810 if (priv->cpu_bo) 1811 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1812 assert(priv->mapped == MAPPED_NONE); 1813 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1814 sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n); 1815 } 1816} 1817 1818static inline bool use_cpu_bo_for_upload(struct sna *sna, 1819 struct sna_pixmap *priv, 1820 unsigned flags) 1821{ 1822 if (DBG_NO_CPU_UPLOAD) 1823 return false; 1824 1825 if (wedged(sna)) 1826 return false; 1827 1828 if (priv->cpu_bo == NULL) 1829 return false; 1830 1831 DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__, 1832 flags, 1833 kgem_bo_is_busy(priv->gpu_bo), 1834 kgem_bo_is_busy(priv->cpu_bo))); 1835 1836 if (!priv->cpu) 1837 return true; 1838 1839 if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) 1840 return true; 1841 1842 if (priv->gpu_bo->tiling) 1843 return true; 1844 1845 return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo); 1846} 1847 1848bool 1849sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1850{ 1851 struct sna_cow *cow = COW(priv->cow); 1852 1853 DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n", 1854 __FUNCTION__, 1855 priv->pixmap->drawable.serialNumber, 1856 priv->gpu_bo->handle, 1857 priv->gpu_bo->refcnt, 1858 cow->refcnt, 1859 flags)); 1860 1861 assert(priv->gpu_bo == cow->bo); 1862 assert(cow->refcnt); 1863 1864 if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow)) 1865 return true; 1866 1867 if (!IS_COW_OWNER(priv->cow)) 1868 list_del(&priv->cow_list); 1869 1870 if (!--cow->refcnt) { 1871 DBG(("%s: freeing cow\n", __FUNCTION__)); 1872 assert(list_is_empty(&cow->list)); 1873 free(cow); 1874 } else if (IS_COW_OWNER(priv->cow) && priv->pinned) { 1875 PixmapPtr pixmap = priv->pixmap; 1876 struct kgem_bo *bo; 1877 BoxRec box; 1878 1879 DBG(("%s: copying the Holy cow\n", __FUNCTION__)); 1880 1881 box.x1 = box.y1 = 0; 1882 box.x2 = pixmap->drawable.width; 1883 box.y2 = pixmap->drawable.height; 1884 1885 bo = kgem_create_2d(&sna->kgem, 1886 box.x2, box.y2, 1887 pixmap->drawable.bitsPerPixel, 1888 sna_pixmap_default_tiling(sna, pixmap), 1889 0); 1890 if (bo == NULL) { 1891 cow->refcnt++; 1892 DBG(("%s: allocation failed\n", __FUNCTION__)); 1893 return false; 1894 } 1895 1896 if (!sna->render.copy_boxes(sna, GXcopy, 1897 &pixmap->drawable, priv->gpu_bo, 0, 0, 1898 &pixmap->drawable, bo, 0, 0, 1899 &box, 1, 0)) { 1900 DBG(("%s: copy failed\n", __FUNCTION__)); 1901 kgem_bo_destroy(&sna->kgem, bo); 1902 cow->refcnt++; 1903 return false; 1904 } 1905 1906 assert(!list_is_empty(&cow->list)); 1907 while (!list_is_empty(&cow->list)) { 1908 struct sna_pixmap *clone; 1909 1910 clone = list_first_entry(&cow->list, 1911 struct sna_pixmap, cow_list); 1912 list_del(&clone->cow_list); 1913 1914 assert(clone->gpu_bo == cow->bo); 1915 sna_pixmap_unmap(clone->pixmap, clone); 1916 kgem_bo_destroy(&sna->kgem, clone->gpu_bo); 1917 clone->gpu_bo = kgem_bo_reference(bo); 1918 } 1919 cow->bo = bo; 1920 kgem_bo_destroy(&sna->kgem, bo); 1921 } else { 1922 struct kgem_bo *bo = NULL; 1923 1924 if (flags & MOVE_READ) { 1925 PixmapPtr pixmap = priv->pixmap; 1926 unsigned create, tiling; 1927 BoxRec box; 1928 1929 DBG(("%s: copying cow\n", __FUNCTION__)); 1930 1931 box.x1 = box.y1 = 0; 1932 box.x2 = pixmap->drawable.width; 1933 box.y2 = pixmap->drawable.height; 1934 1935 if (flags & __MOVE_PRIME) { 1936 create = CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT; 1937 tiling = I915_TILING_NONE; 1938 } else { 1939 create = 0; 1940 tiling = sna_pixmap_default_tiling(sna, pixmap); 1941 } 1942 1943 bo = kgem_create_2d(&sna->kgem, 1944 box.x2, box.y2, 1945 pixmap->drawable.bitsPerPixel, 1946 tiling, create); 1947 if (bo == NULL) { 1948 cow->refcnt++; 1949 DBG(("%s: allocation failed\n", __FUNCTION__)); 1950 return false; 1951 } 1952 1953 if (!sna->render.copy_boxes(sna, GXcopy, 1954 &pixmap->drawable, priv->gpu_bo, 0, 0, 1955 &pixmap->drawable, bo, 0, 0, 1956 &box, 1, 0)) { 1957 DBG(("%s: copy failed\n", __FUNCTION__)); 1958 kgem_bo_destroy(&sna->kgem, bo); 1959 cow->refcnt++; 1960 return false; 1961 } 1962 } 1963 1964 assert(priv->gpu_bo); 1965 sna_pixmap_unmap(priv->pixmap, priv); 1966 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1967 priv->gpu_bo = bo; 1968 } 1969 1970 priv->cow = NULL; 1971 return true; 1972} 1973 1974static bool 1975sna_pixmap_make_cow(struct sna *sna, 1976 struct sna_pixmap *src_priv, 1977 struct sna_pixmap *dst_priv) 1978{ 1979 struct sna_cow *cow; 1980 1981 assert(src_priv->gpu_bo); 1982 1983 if (!USE_COW) 1984 return false; 1985 1986 if (src_priv->gpu_bo->proxy) 1987 return false; 1988 1989 DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n", 1990 __FUNCTION__, 1991 src_priv->pixmap->drawable.serialNumber, 1992 dst_priv->pixmap->drawable.serialNumber, 1993 src_priv->gpu_bo->handle, 1994 src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0, 1995 dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0)); 1996 1997 if (dst_priv->pinned) { 1998 DBG(("%s: can't cow, dst_pinned=%x\n", 1999 __FUNCTION__, dst_priv->pinned)); 2000 return false; 2001 } 2002 2003 assert(dst_priv->move_to_gpu == NULL); 2004 assert(!dst_priv->flush); 2005 assert(list_is_empty(&dst_priv->cow_list)); 2006 2007 cow = COW(src_priv->cow); 2008 if (cow == NULL) { 2009 cow = malloc(sizeof(*cow)); 2010 if (cow == NULL) 2011 return false; 2012 2013 list_init(&cow->list); 2014 2015 cow->bo = src_priv->gpu_bo; 2016 cow->refcnt = 1; 2017 2018 DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n", 2019 __FUNCTION__, 2020 src_priv->pixmap->drawable.serialNumber, 2021 cow->bo->handle)); 2022 2023 src_priv->cow = MAKE_COW_OWNER(cow); 2024 } 2025 2026 if (cow == COW(dst_priv->cow)) { 2027 assert(dst_priv->gpu_bo == cow->bo); 2028 return true; 2029 } 2030 2031 if (dst_priv->cow) 2032 sna_pixmap_undo_cow(sna, dst_priv, 0); 2033 2034 if (dst_priv->gpu_bo) { 2035 sna_pixmap_unmap(dst_priv->pixmap, dst_priv); 2036 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 2037 } 2038 assert(!dst_priv->mapped); 2039 dst_priv->gpu_bo = kgem_bo_reference(cow->bo); 2040 dst_priv->cow = cow; 2041 list_add(&dst_priv->cow_list, &cow->list); 2042 cow->refcnt++; 2043 2044 DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n", 2045 __FUNCTION__, 2046 dst_priv->pixmap->drawable.serialNumber, 2047 src_priv->pixmap->drawable.serialNumber, 2048 cow->bo->handle)); 2049 2050 return true; 2051} 2052 2053static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags) 2054{ 2055 if (!USE_INPLACE) 2056 return false; 2057 2058 if ((flags & MOVE_INPLACE_HINT) == 0) { 2059 DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__)); 2060 return false; 2061 } 2062 2063 assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE)); 2064 2065 if (priv->move_to_gpu && flags & MOVE_WRITE) { 2066 DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__)); 2067 return false; 2068 } 2069 2070 if (priv->cow && flags & MOVE_WRITE) { 2071 DBG(("%s: no, has COW\n", __FUNCTION__)); 2072 return false; 2073 } 2074 2075 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) { 2076 DBG(("%s: no, not accessible via GTT\n", __FUNCTION__)); 2077 return false; 2078 } 2079 2080 if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) { 2081 DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__)); 2082 return false; 2083 } 2084 2085 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 2086 DBG(("%s: yes, CPU is busy\n", __FUNCTION__)); 2087 return true; 2088 } 2089 2090 if (priv->create & KGEM_CAN_CREATE_LARGE) { 2091 DBG(("%s: large object, has GPU? %d\n", 2092 __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0)); 2093 return priv->gpu_bo != NULL; 2094 } 2095 2096 if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) { 2097 DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__)); 2098 return false; 2099 } 2100 2101 return true; 2102} 2103 2104bool 2105_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) 2106{ 2107 struct sna *sna = to_sna_from_pixmap(pixmap); 2108 struct sna_pixmap *priv; 2109 2110 DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__, 2111 pixmap->drawable.serialNumber, 2112 pixmap->drawable.width, 2113 pixmap->drawable.height, 2114 flags)); 2115 2116 assert(flags & (MOVE_READ | MOVE_WRITE)); 2117 assert_pixmap_damage(pixmap); 2118 2119 priv = sna_pixmap(pixmap); 2120 if (priv == NULL) { 2121 DBG(("%s: not attached\n", __FUNCTION__)); 2122 return true; 2123 } 2124 2125 DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n", 2126 __FUNCTION__, 2127 priv->gpu_bo ? priv->gpu_bo->handle : 0, 2128 priv->gpu_damage, priv->cpu_damage, priv->clear)); 2129 2130 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2131 2132 if ((flags & MOVE_READ) == 0 && UNDO) { 2133 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 2134 if (priv->move_to_gpu) 2135 sna_pixmap_discard_shadow_damage(priv, NULL); 2136 } 2137 2138 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2139 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2140 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2141 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2142 goto skip; 2143 } 2144 2145 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2146 assert(priv->gpu_damage == NULL); 2147 assert(!priv->pinned); 2148 assert(!priv->mapped); 2149 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2150 priv->gpu_bo = NULL; 2151 } 2152 2153 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 2154 DBG(("%s: CPU all-damaged\n", __FUNCTION__)); 2155 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); 2156 assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0); 2157 goto done; 2158 } 2159 2160 if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) { 2161 assert(flags & MOVE_WRITE); 2162 DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n", 2163 __FUNCTION__, priv->gpu_damage != NULL, priv->clear)); 2164 2165 if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) && 2166 pixmap_inplace(sna, pixmap, priv, flags) && 2167 sna_pixmap_create_mappable_gpu(pixmap, true)) { 2168 void *ptr; 2169 2170 DBG(("%s: write inplace\n", __FUNCTION__)); 2171 assert(!priv->shm); 2172 assert(priv->cow == NULL); 2173 assert(priv->move_to_gpu == NULL); 2174 assert(priv->gpu_bo->exec == NULL); 2175 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2176 2177 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2178 if (ptr == NULL) 2179 goto skip_inplace_map; 2180 2181 pixmap->devPrivate.ptr = ptr; 2182 pixmap->devKind = priv->gpu_bo->pitch; 2183 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2184 assert(has_coherent_ptr(sna, priv, flags)); 2185 2186 assert(priv->gpu_bo->proxy == NULL); 2187 sna_damage_all(&priv->gpu_damage, pixmap); 2188 sna_damage_destroy(&priv->cpu_damage); 2189 priv->clear = false; 2190 list_del(&priv->flush_list); 2191 2192 assert(!priv->shm); 2193 assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush); 2194 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2195 priv->cpu &= priv->mapped == MAPPED_CPU; 2196 2197 assert_pixmap_damage(pixmap); 2198 return true; 2199 } 2200 2201skip_inplace_map: 2202 sna_damage_destroy(&priv->gpu_damage); 2203 priv->clear = false; 2204 if ((flags & MOVE_ASYNC_HINT) == 0 && 2205 priv->cpu_bo && !priv->cpu_bo->flush && 2206 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2207 DBG(("%s: discarding busy CPU bo\n", __FUNCTION__)); 2208 assert(!priv->shm); 2209 assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL); 2210 2211 sna_damage_destroy(&priv->cpu_damage); 2212 sna_pixmap_free_cpu(sna, priv, false); 2213 2214 assert(priv->mapped == MAPPED_NONE); 2215 if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0)) 2216 return false; 2217 assert(priv->mapped == MAPPED_NONE); 2218 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2219 2220 goto mark_damage; 2221 } 2222 } 2223 2224 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2225 2226 if (operate_inplace(priv, flags) && 2227 pixmap_inplace(sna, pixmap, priv, flags) && 2228 sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) { 2229 void *ptr; 2230 2231 DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__)); 2232 assert(priv->gpu_bo); 2233 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2234 assert(!priv->move_to_gpu); 2235 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2236 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2237 /* XXX only sync for writes? */ 2238 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2239 assert(priv->gpu_bo->exec == NULL); 2240 2241 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2242 if (ptr != NULL) { 2243 pixmap->devPrivate.ptr = ptr; 2244 pixmap->devKind = priv->gpu_bo->pitch; 2245 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2246 assert(has_coherent_ptr(sna, priv, flags)); 2247 2248 if (flags & MOVE_WRITE) { 2249 assert(priv->gpu_bo->proxy == NULL); 2250 sna_damage_all(&priv->gpu_damage, pixmap); 2251 sna_damage_destroy(&priv->cpu_damage); 2252 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2253 list_del(&priv->flush_list); 2254 priv->clear = false; 2255 } 2256 priv->cpu &= priv->mapped == MAPPED_CPU; 2257 2258 assert_pixmap_damage(pixmap); 2259 DBG(("%s: operate inplace (GTT)\n", __FUNCTION__)); 2260 return true; 2261 } 2262 } 2263 2264 sna_pixmap_unmap(pixmap, priv); 2265 2266 if (USE_INPLACE && 2267 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL && 2268 priv->gpu_bo->tiling == I915_TILING_NONE && 2269 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) && 2270 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2271 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) { 2272 void *ptr; 2273 2274 DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__)); 2275 assert(priv->gpu_bo); 2276 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2277 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2278 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2279 2280 assert(!priv->mapped); 2281 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 2282 2283 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2284 if (ptr != NULL) { 2285 pixmap->devPrivate.ptr = ptr; 2286 pixmap->devKind = priv->gpu_bo->pitch; 2287 priv->mapped = MAPPED_CPU; 2288 assert(has_coherent_ptr(sna, priv, flags)); 2289 2290 if (flags & MOVE_WRITE) { 2291 assert(priv->gpu_bo->proxy == NULL); 2292 sna_damage_all(&priv->gpu_damage, pixmap); 2293 sna_damage_destroy(&priv->cpu_damage); 2294 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2295 list_del(&priv->flush_list); 2296 priv->clear = false; 2297 priv->cpu = true; 2298 } 2299 2300 assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)); 2301 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2302 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2303 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2304 assert_pixmap_damage(pixmap); 2305 assert(has_coherent_ptr(sna, priv, flags)); 2306 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2307 return true; 2308 } 2309 } 2310 2311 assert(priv->mapped == MAPPED_NONE); 2312 if (((flags & MOVE_READ) == 0 || priv->clear) && 2313 priv->cpu_bo && !priv->cpu_bo->flush && 2314 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2315 assert(!priv->shm); 2316 sna_pixmap_free_cpu(sna, priv, false); 2317 } 2318 2319 assert(priv->mapped == MAPPED_NONE); 2320 if (pixmap->devPrivate.ptr == NULL && 2321 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2322 return false; 2323 assert(priv->mapped == MAPPED_NONE); 2324 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2325 2326 if (flags & MOVE_READ) { 2327 if (priv->clear) { 2328 DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n", 2329 __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height, 2330 pixmap->devKind, pixmap->devKind * pixmap->drawable.height)); 2331 2332 if (priv->cpu_bo) { 2333 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2334 sna->render.fill_one(sna, 2335 pixmap, priv->cpu_bo, priv->clear_color, 2336 0, 0, 2337 pixmap->drawable.width, 2338 pixmap->drawable.height, 2339 GXcopy)) 2340 goto clear_done; 2341 2342 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2343 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2344 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2345 } 2346 2347 assert(pixmap->devKind); 2348 if (priv->clear_color == 0 || 2349 pixmap->drawable.bitsPerPixel == 8 || 2350 priv->clear_color == (1 << pixmap->drawable.depth) - 1) { 2351 memset(pixmap->devPrivate.ptr, priv->clear_color, 2352 (size_t)pixmap->devKind * pixmap->drawable.height); 2353 } else { 2354 pixman_fill(pixmap->devPrivate.ptr, 2355 pixmap->devKind/sizeof(uint32_t), 2356 pixmap->drawable.bitsPerPixel, 2357 0, 0, 2358 pixmap->drawable.width, 2359 pixmap->drawable.height, 2360 priv->clear_color); 2361 } 2362 2363clear_done: 2364 sna_damage_all(&priv->cpu_damage, pixmap); 2365 sna_pixmap_free_gpu(sna, priv); 2366 assert(priv->gpu_damage == NULL); 2367 assert(priv->clear == false); 2368 } 2369 2370 if (priv->gpu_damage) { 2371 const BoxRec *box; 2372 int n; 2373 2374 DBG(("%s: flushing GPU damage\n", __FUNCTION__)); 2375 assert(priv->gpu_bo); 2376 2377 n = sna_damage_get_boxes(priv->gpu_damage, &box); 2378 if (n) { 2379 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) { 2380 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2381 return false; 2382 } 2383 2384 download_boxes(sna, priv, n, box); 2385 } 2386 2387 __sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage)); 2388 priv->gpu_damage = NULL; 2389 } 2390 } 2391 2392 if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) { 2393mark_damage: 2394 DBG(("%s: marking as damaged\n", __FUNCTION__)); 2395 sna_damage_all(&priv->cpu_damage, pixmap); 2396 sna_pixmap_free_gpu(sna, priv); 2397 assert(priv->gpu_damage == NULL); 2398 assert(priv->clear == false); 2399 2400 if (priv->flush) { 2401 assert(!priv->shm); 2402 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2403 } 2404 } 2405 2406done: 2407 if (flags & MOVE_WRITE) { 2408 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2409 assert(priv->gpu_damage == NULL); 2410 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2411 if (priv->cow) 2412 sna_pixmap_undo_cow(sna, priv, 0); 2413 if (priv->gpu_bo && priv->gpu_bo->rq == NULL) { 2414 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__)); 2415 sna_pixmap_free_gpu(sna, priv); 2416 } 2417 priv->source_count = SOURCE_BIAS; 2418 } 2419 2420 if (priv->cpu_bo) { 2421 if ((flags & MOVE_ASYNC_HINT) == 0) { 2422 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2423 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2424 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2425 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2426 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2427 } 2428 } 2429skip: 2430 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 2431 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2432 assert(pixmap->devKind); 2433 assert_pixmap_damage(pixmap); 2434 assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags)); 2435 return true; 2436} 2437 2438static bool 2439region_overlaps_damage(const RegionRec *region, 2440 struct sna_damage *damage, 2441 int dx, int dy) 2442{ 2443 const BoxRec *re, *de; 2444 2445 DBG(("%s?\n", __FUNCTION__)); 2446 2447 if (damage == NULL) 2448 return false; 2449 2450 if (DAMAGE_IS_ALL(damage)) 2451 return true; 2452 2453 re = ®ion->extents; 2454 de = &DAMAGE_PTR(damage)->extents; 2455 DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n", 2456 __FUNCTION__, 2457 re->x1, re->y1, re->x2, re->y2, 2458 de->x1, de->y1, de->x2, de->y2)); 2459 2460 return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 && 2461 re->y1 + dy < de->y2 && re->y2 + dy > de->y1); 2462} 2463 2464static inline bool region_inplace(struct sna *sna, 2465 PixmapPtr pixmap, 2466 RegionPtr region, 2467 struct sna_pixmap *priv, 2468 unsigned flags) 2469{ 2470 assert_pixmap_damage(pixmap); 2471 2472 if (FORCE_INPLACE) 2473 return FORCE_INPLACE > 0; 2474 2475 if (wedged(sna) && !priv->pinned) 2476 return false; 2477 2478 if (priv->gpu_damage && 2479 (priv->clear || (flags & MOVE_READ) == 0) && 2480 kgem_bo_is_busy(priv->gpu_bo)) 2481 return false; 2482 2483 if (flags & MOVE_READ && 2484 (priv->cpu || 2485 priv->gpu_damage == NULL || 2486 region_overlaps_damage(region, priv->cpu_damage, 0, 0))) { 2487 DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__)); 2488 return false; 2489 } 2490 2491 if (priv->mapped) { 2492 DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__, 2493 has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 2494 return has_coherent_map(sna, priv->gpu_bo, flags); 2495 } 2496 2497 if (priv->flush) { 2498 DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__)); 2499 return true; 2500 } 2501 2502 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2503 DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__)); 2504 assert(priv->gpu_bo); 2505 return true; 2506 } 2507 2508 if (priv->cpu_bo && priv->cpu) { 2509 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 2510 return false; 2511 } 2512 2513 DBG(("%s: (%dx%d), inplace? %d\n", 2514 __FUNCTION__, 2515 region->extents.x2 - region->extents.x1, 2516 region->extents.y2 - region->extents.y1, 2517 ((int)(region->extents.x2 - region->extents.x1) * 2518 (int)(region->extents.y2 - region->extents.y1) * 2519 pixmap->drawable.bitsPerPixel >> 12) 2520 >= sna->kgem.half_cpu_cache_pages)); 2521 return ((int)(region->extents.x2 - region->extents.x1) * 2522 (int)(region->extents.y2 - region->extents.y1) * 2523 pixmap->drawable.bitsPerPixel >> 12) 2524 >= sna->kgem.half_cpu_cache_pages; 2525} 2526 2527static bool cpu_clear_boxes(struct sna *sna, 2528 PixmapPtr pixmap, 2529 struct sna_pixmap *priv, 2530 const BoxRec *box, int n) 2531{ 2532 struct sna_fill_op fill; 2533 2534 if (!sna_fill_init_blt(&fill, sna, 2535 pixmap, priv->cpu_bo, 2536 GXcopy, priv->clear_color, 2537 FILL_BOXES)) { 2538 DBG(("%s: unsupported fill\n", 2539 __FUNCTION__)); 2540 return false; 2541 } 2542 2543 fill.boxes(sna, &fill, box, n); 2544 fill.done(sna, &fill); 2545 return true; 2546} 2547 2548bool 2549sna_drawable_move_region_to_cpu(DrawablePtr drawable, 2550 RegionPtr region, 2551 unsigned flags) 2552{ 2553 PixmapPtr pixmap = get_drawable_pixmap(drawable); 2554 struct sna *sna = to_sna_from_pixmap(pixmap); 2555 struct sna_pixmap *priv; 2556 int16_t dx, dy; 2557 2558 DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n", 2559 __FUNCTION__, pixmap->drawable.serialNumber, 2560 pixmap->drawable.width, pixmap->drawable.height, 2561 RegionExtents(region)->x1, RegionExtents(region)->y1, 2562 RegionExtents(region)->x2, RegionExtents(region)->y2, 2563 flags)); 2564 2565 assert_pixmap_damage(pixmap); 2566 if (flags & MOVE_WRITE) { 2567 assert_drawable_contains_box(drawable, ®ion->extents); 2568 } 2569 assert(flags & (MOVE_WRITE | MOVE_READ)); 2570 2571 if (box_empty(®ion->extents)) 2572 return true; 2573 2574 if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) { 2575 if (!region_subsumes_pixmap(region, pixmap)) 2576 flags |= MOVE_READ; 2577 return _sna_pixmap_move_to_cpu(pixmap, flags); 2578 } 2579 2580 priv = sna_pixmap(pixmap); 2581 if (priv == NULL) { 2582 DBG(("%s: not attached to pixmap %ld (depth %d)\n", 2583 __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth)); 2584 return true; 2585 } 2586 2587 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2588 2589 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2590 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2591 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2592 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2593 goto skip; 2594 } 2595 2596 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2597 assert(priv->gpu_damage == NULL); 2598 assert(!priv->pinned); 2599 assert(!priv->mapped); 2600 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2601 priv->gpu_bo = NULL; 2602 } 2603 2604 if (sna_damage_is_all(&priv->cpu_damage, 2605 pixmap->drawable.width, 2606 pixmap->drawable.height)) { 2607 bool discard_gpu = priv->cpu; 2608 2609 DBG(("%s: pixmap=%ld all damaged on CPU\n", 2610 __FUNCTION__, pixmap->drawable.serialNumber)); 2611 assert(!priv->clear); 2612 2613 sna_damage_destroy(&priv->gpu_damage); 2614 2615 if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2616 priv->cpu_bo && !priv->cpu_bo->flush && 2617 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2618 DBG(("%s: active CPU bo replacing\n", __FUNCTION__)); 2619 assert(!priv->shm); 2620 assert(!IS_STATIC_PTR(priv->ptr)); 2621 2622 if (!region_subsumes_pixmap(region, pixmap)) { 2623 DBG(("%s: partial replacement\n", __FUNCTION__)); 2624 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 2625 RegionTranslate(region, dx, dy); 2626 2627 if (sna->kgem.has_llc && !priv->pinned && 2628 sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) { 2629#ifdef DEBUG_MEMORY 2630 sna->debug_memory.cpu_bo_allocs--; 2631 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 2632#endif 2633 DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__)); 2634 if (priv->gpu_bo) 2635 sna_pixmap_free_gpu(sna, priv); 2636 priv->gpu_bo = priv->cpu_bo; 2637 priv->cpu_bo = NULL; 2638 priv->ptr = NULL; 2639 pixmap->devPrivate.ptr = NULL; 2640 2641 priv->gpu_damage = priv->cpu_damage; 2642 priv->cpu_damage = NULL; 2643 2644 sna_damage_subtract(&priv->gpu_damage, region); 2645 discard_gpu = false; 2646 } else { 2647 DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__)); 2648 sna_damage_subtract(&priv->cpu_damage, region); 2649 assert(priv->cpu_damage); 2650 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2651 sna_pixmap_free_cpu(sna, priv, false); 2652 if (priv->flush) 2653 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2654 2655 assert(priv->cpu_damage == NULL); 2656 sna_damage_all(&priv->gpu_damage, pixmap); 2657 sna_damage_subtract(&priv->gpu_damage, region); 2658 discard_gpu = false; 2659 } 2660 } 2661 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 2662 2663 if (dx | dy) 2664 RegionTranslate(region, -dx, -dy); 2665 } else 2666 sna_pixmap_free_cpu(sna, priv, false); 2667 } 2668 2669 if (flags & MOVE_WRITE && discard_gpu) 2670 sna_pixmap_free_gpu(sna, priv); 2671 2672 sna_pixmap_unmap(pixmap, priv); 2673 assert(priv->mapped == MAPPED_NONE); 2674 if (pixmap->devPrivate.ptr == NULL && 2675 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2676 return false; 2677 assert(priv->mapped == MAPPED_NONE); 2678 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2679 2680 goto out; 2681 } 2682 2683 if (USE_INPLACE && 2684 (priv->create & KGEM_CAN_CREATE_LARGE || 2685 ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2686 (priv->flush || 2687 (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) || 2688 box_inplace(pixmap, ®ion->extents))))) { 2689 DBG(("%s: marking for inplace hint (%d, %d)\n", 2690 __FUNCTION__, priv->flush, box_inplace(pixmap, ®ion->extents))); 2691 flags |= MOVE_INPLACE_HINT; 2692 } 2693 2694 if (region_subsumes_pixmap(region, pixmap)) { 2695 DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n", 2696 __FUNCTION__, 2697 region->extents.x1, 2698 region->extents.y1, 2699 region->extents.x2, 2700 region->extents.y2, 2701 get_drawable_dx(drawable), get_drawable_dy(drawable), 2702 pixmap->drawable.width, 2703 pixmap->drawable.height)); 2704 return _sna_pixmap_move_to_cpu(pixmap, flags); 2705 } 2706 2707 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2708 2709 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 2710 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 2711 RegionTranslate(region, dx, dy); 2712 } 2713 2714 if (priv->move_to_gpu) { 2715 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 2716 if ((flags & MOVE_READ) == 0) 2717 sna_pixmap_discard_shadow_damage(priv, region); 2718 if (!priv->move_to_gpu(sna, priv, MOVE_READ)) { 2719 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2720 return NULL; 2721 } 2722 } 2723 2724 if (operate_inplace(priv, flags) && 2725 region_inplace(sna, pixmap, region, priv, flags) && 2726 sna_pixmap_create_mappable_gpu(pixmap, false)) { 2727 void *ptr; 2728 2729 DBG(("%s: try to operate inplace\n", __FUNCTION__)); 2730 assert(priv->gpu_bo); 2731 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2732 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2733 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2734 2735 /* XXX only sync for writes? */ 2736 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2737 assert(priv->gpu_bo->exec == NULL); 2738 2739 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2740 if (ptr != NULL) { 2741 pixmap->devPrivate.ptr = ptr; 2742 pixmap->devKind = priv->gpu_bo->pitch; 2743 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2744 assert(has_coherent_ptr(sna, priv, flags)); 2745 2746 if (flags & MOVE_WRITE) { 2747 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2748 assert(!priv->clear); 2749 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2750 if (sna_damage_is_all(&priv->gpu_damage, 2751 pixmap->drawable.width, 2752 pixmap->drawable.height)) { 2753 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2754 __FUNCTION__)); 2755 sna_damage_destroy(&priv->cpu_damage); 2756 list_del(&priv->flush_list); 2757 } else 2758 sna_damage_subtract(&priv->cpu_damage, 2759 region); 2760 } 2761 priv->clear = false; 2762 } 2763 priv->cpu &= priv->mapped == MAPPED_CPU; 2764 assert_pixmap_damage(pixmap); 2765 if (dx | dy) 2766 RegionTranslate(region, -dx, -dy); 2767 DBG(("%s: operate inplace\n", __FUNCTION__)); 2768 return true; 2769 } 2770 } 2771 2772 if (priv->clear && flags & MOVE_WRITE) { 2773 DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__)); 2774demote_to_cpu: 2775 if (dx | dy) 2776 RegionTranslate(region, -dx, -dy); 2777 return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ); 2778 } 2779 2780 if (flags & MOVE_WHOLE_HINT) { 2781 DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n", 2782 __FUNCTION__, 2783 region->extents.x1, 2784 region->extents.y1, 2785 region->extents.x2, 2786 region->extents.y2, 2787 pixmap->drawable.width, 2788 pixmap->drawable.height)); 2789move_to_cpu: 2790 if ((flags & MOVE_READ) == 0) 2791 sna_damage_subtract(&priv->gpu_damage, region); 2792 goto demote_to_cpu; 2793 } 2794 2795 sna_pixmap_unmap(pixmap, priv); 2796 2797 if (USE_INPLACE && 2798 priv->gpu_damage && 2799 priv->gpu_bo->tiling == I915_TILING_NONE && 2800 ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) && 2801 (DAMAGE_IS_ALL(priv->gpu_damage) || 2802 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2803 ®ion->extents)) && 2804 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) && 2805 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2806 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 2807 void *ptr; 2808 2809 DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n", 2810 __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE))); 2811 assert(priv->gpu_bo); 2812 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2813 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2814 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2815 2816 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2817 if (ptr != NULL) { 2818 pixmap->devPrivate.ptr = ptr; 2819 pixmap->devKind = priv->gpu_bo->pitch; 2820 priv->mapped = MAPPED_CPU; 2821 assert(has_coherent_ptr(sna, priv, flags)); 2822 2823 if (flags & MOVE_WRITE) { 2824 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2825 assert(!priv->clear); 2826 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2827 if (sna_damage_is_all(&priv->gpu_damage, 2828 pixmap->drawable.width, 2829 pixmap->drawable.height)) { 2830 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2831 __FUNCTION__)); 2832 sna_damage_destroy(&priv->cpu_damage); 2833 list_del(&priv->flush_list); 2834 } else 2835 sna_damage_subtract(&priv->cpu_damage, 2836 region); 2837 } 2838 priv->clear = false; 2839 } 2840 assert_pixmap_damage(pixmap); 2841 2842 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2843 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2844 priv->cpu = true; 2845 2846 assert_pixmap_map(pixmap, priv); 2847 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2848 if (dx | dy) 2849 RegionTranslate(region, -dx, -dy); 2850 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2851 return true; 2852 } 2853 } 2854 2855 if ((priv->clear || (flags & MOVE_READ) == 0) && 2856 priv->cpu_bo && !priv->cpu_bo->flush && 2857 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2858 sna_damage_subtract(&priv->cpu_damage, region); 2859 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2860 assert(priv->gpu_bo); 2861 sna_damage_all(&priv->gpu_damage, pixmap); 2862 sna_pixmap_free_cpu(sna, priv, false); 2863 } 2864 } 2865 2866 assert(priv->mapped == MAPPED_NONE); 2867 if (pixmap->devPrivate.ptr == NULL && 2868 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) { 2869 DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__)); 2870 goto move_to_cpu; 2871 } 2872 assert(priv->mapped == MAPPED_NONE); 2873 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2874 2875 if (priv->gpu_bo == NULL) { 2876 assert(priv->gpu_damage == NULL); 2877 goto done; 2878 } 2879 2880 assert(priv->gpu_bo->proxy == NULL); 2881 2882 if ((flags & MOVE_READ) == 0) { 2883 assert(flags & MOVE_WRITE); 2884 sna_damage_subtract(&priv->gpu_damage, region); 2885 priv->clear = false; 2886 goto done; 2887 } 2888 2889 if (priv->clear) { 2890 int n = region_num_rects(region); 2891 const BoxRec *box = region_rects(region); 2892 2893 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 2894 assert(priv->cpu_damage == NULL); 2895 2896 DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__)); 2897 if (priv->cpu_bo) { 2898 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2899 cpu_clear_boxes(sna, pixmap, priv, box, n)) 2900 goto clear_done; 2901 2902 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2903 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2904 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2905 } 2906 2907 assert(pixmap->devKind); 2908 do { 2909 pixman_fill(pixmap->devPrivate.ptr, 2910 pixmap->devKind/sizeof(uint32_t), 2911 pixmap->drawable.bitsPerPixel, 2912 box->x1, box->y1, 2913 box->x2 - box->x1, 2914 box->y2 - box->y1, 2915 priv->clear_color); 2916 box++; 2917 } while (--n); 2918 2919clear_done: 2920 if (flags & MOVE_WRITE || 2921 region->extents.x2 - region->extents.x1 > 1 || 2922 region->extents.y2 - region->extents.y1 > 1) { 2923 sna_damage_subtract(&priv->gpu_damage, region); 2924 priv->clear = false; 2925 } 2926 goto done; 2927 } 2928 2929 if (priv->gpu_damage && 2930 (DAMAGE_IS_ALL(priv->gpu_damage) || 2931 sna_damage_overlaps_box(priv->gpu_damage, ®ion->extents))) { 2932 DBG(("%s: region (%dx%d) overlaps gpu damage\n", 2933 __FUNCTION__, 2934 region->extents.x2 - region->extents.x1, 2935 region->extents.y2 - region->extents.y1)); 2936 assert(priv->gpu_bo); 2937 2938 if (priv->cpu_damage == NULL) { 2939 if ((flags & MOVE_WRITE) == 0 && 2940 region->extents.x2 - region->extents.x1 == 1 && 2941 region->extents.y2 - region->extents.y1 == 1) { 2942 /* Often associated with synchronisation, KISS */ 2943 DBG(("%s: single pixel read\n", __FUNCTION__)); 2944 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2945 ®ion->extents, 1); 2946 goto done; 2947 } 2948 } else { 2949 if (DAMAGE_IS_ALL(priv->cpu_damage) || 2950 sna_damage_contains_box__no_reduce(priv->cpu_damage, 2951 ®ion->extents)) { 2952 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2953 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2954 2955 DBG(("%s: region already in CPU damage\n", 2956 __FUNCTION__)); 2957 goto already_damaged; 2958 } 2959 } 2960 2961 if (sna_damage_contains_box(&priv->gpu_damage, 2962 ®ion->extents) != PIXMAN_REGION_OUT) { 2963 RegionRec want, *r = region; 2964 2965 DBG(("%s: region (%dx%d) intersects gpu damage\n", 2966 __FUNCTION__, 2967 region->extents.x2 - region->extents.x1, 2968 region->extents.y2 - region->extents.y1)); 2969 2970 if ((flags & MOVE_WRITE) == 0 && 2971 region->extents.x2 - region->extents.x1 == 1 && 2972 region->extents.y2 - region->extents.y1 == 1) { 2973 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2974 ®ion->extents, 1); 2975 goto done; 2976 } 2977 2978 /* Expand the region to move 32x32 pixel blocks at a 2979 * time, as we assume that we will continue writing 2980 * afterwards and so aim to coallesce subsequent 2981 * reads. 2982 */ 2983 if (flags & MOVE_WRITE) { 2984 int n = region_num_rects(region), i; 2985 const BoxRec *boxes = region_rects(region); 2986 BoxPtr blocks; 2987 2988 blocks = NULL; 2989 if (priv->cpu_damage == NULL) 2990 blocks = malloc(sizeof(BoxRec) * n); 2991 if (blocks) { 2992 for (i = 0; i < n; i++) { 2993 blocks[i].x1 = boxes[i].x1 & ~31; 2994 if (blocks[i].x1 < 0) 2995 blocks[i].x1 = 0; 2996 2997 blocks[i].x2 = (boxes[i].x2 + 31) & ~31; 2998 if (blocks[i].x2 > pixmap->drawable.width) 2999 blocks[i].x2 = pixmap->drawable.width; 3000 3001 blocks[i].y1 = boxes[i].y1 & ~31; 3002 if (blocks[i].y1 < 0) 3003 blocks[i].y1 = 0; 3004 3005 blocks[i].y2 = (boxes[i].y2 + 31) & ~31; 3006 if (blocks[i].y2 > pixmap->drawable.height) 3007 blocks[i].y2 = pixmap->drawable.height; 3008 } 3009 if (pixman_region_init_rects(&want, blocks, i)) 3010 r = &want; 3011 free(blocks); 3012 } 3013 } 3014 3015 if (region_subsumes_damage(r, priv->gpu_damage)) { 3016 const BoxRec *box; 3017 int n; 3018 3019 DBG(("%s: region wholly contains damage\n", 3020 __FUNCTION__)); 3021 3022 n = sna_damage_get_boxes(priv->gpu_damage, &box); 3023 if (n) 3024 download_boxes(sna, priv, n, box); 3025 3026 sna_damage_destroy(&priv->gpu_damage); 3027 } else if (DAMAGE_IS_ALL(priv->gpu_damage) || 3028 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3029 &r->extents)) { 3030 3031 DBG(("%s: region wholly inside damage\n", 3032 __FUNCTION__)); 3033 3034 assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN); 3035 assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT); 3036 3037 download_boxes(sna, priv, 3038 region_num_rects(r), 3039 region_rects(r)); 3040 sna_damage_subtract(&priv->gpu_damage, r); 3041 } else { 3042 RegionRec need; 3043 3044 pixman_region_init(&need); 3045 if (sna_damage_intersect(priv->gpu_damage, r, &need)) { 3046 DBG(("%s: region intersects damage\n", 3047 __FUNCTION__)); 3048 3049 download_boxes(sna, priv, 3050 region_num_rects(&need), 3051 region_rects(&need)); 3052 sna_damage_subtract(&priv->gpu_damage, r); 3053 RegionUninit(&need); 3054 } 3055 } 3056 if (r == &want) 3057 pixman_region_fini(&want); 3058 } 3059 } 3060 3061done: 3062 if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) { 3063 DBG(("%s: applying cpu damage\n", __FUNCTION__)); 3064 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3065 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 3066 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 3067 sna_damage_reduce_all(&priv->cpu_damage, pixmap); 3068 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3069 DBG(("%s: replaced entire pixmap\n", __FUNCTION__)); 3070 sna_pixmap_free_gpu(sna, priv); 3071 } 3072 if (priv->flush) { 3073 assert(!priv->shm); 3074 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3075 } 3076 } 3077 3078already_damaged: 3079 if (dx | dy) 3080 RegionTranslate(region, -dx, -dy); 3081 3082out: 3083 if (flags & MOVE_WRITE) { 3084 assert(!DAMAGE_IS_ALL(priv->gpu_damage)); 3085 priv->source_count = SOURCE_BIAS; 3086 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3087 assert(priv->gpu_bo || priv->gpu_damage == NULL); 3088 assert(!priv->flush || !list_is_empty(&priv->flush_list)); 3089 assert(!priv->clear); 3090 } 3091 if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) { 3092 DBG(("%s: syncing cpu bo\n", __FUNCTION__)); 3093 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 3094 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 3095 FORCE_FULL_SYNC || flags & MOVE_WRITE); 3096 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 3097 } 3098skip: 3099 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 3100 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 3101 assert(pixmap->devKind); 3102 assert_pixmap_damage(pixmap); 3103 assert(has_coherent_ptr(sna, priv, flags)); 3104 return true; 3105} 3106 3107bool 3108sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags) 3109{ 3110 RegionRec region; 3111 PixmapPtr pixmap; 3112 int16_t dx, dy; 3113 3114 if (drawable->type == DRAWABLE_PIXMAP) 3115 return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags); 3116 3117 pixmap = get_window_pixmap((WindowPtr)drawable); 3118 get_drawable_deltas(drawable, pixmap, &dx, &dy); 3119 3120 DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n", 3121 __FUNCTION__, 3122 drawable->x, drawable->y, 3123 drawable->width, drawable->height, 3124 dx, dy, flags)); 3125 3126 region.extents.x1 = drawable->x + dx; 3127 region.extents.y1 = drawable->y + dy; 3128 region.extents.x2 = region.extents.x1 + drawable->width; 3129 region.extents.y2 = region.extents.y1 + drawable->height; 3130 region.data = NULL; 3131 3132 if (region.extents.x1 < 0) 3133 region.extents.x1 = 0; 3134 if (region.extents.y1 < 0) 3135 region.extents.y1 = 0; 3136 if (region.extents.x2 > pixmap->drawable.width) 3137 region.extents.x2 = pixmap->drawable.width; 3138 if (region.extents.y2 > pixmap->drawable.height) 3139 region.extents.y2 = pixmap->drawable.height; 3140 3141 if (box_empty(®ion.extents)) 3142 return true; 3143 3144 return sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags); 3145} 3146 3147pure static bool alu_overwrites(uint8_t alu) 3148{ 3149 switch (alu) { 3150 case GXclear: 3151 case GXcopy: 3152 case GXcopyInverted: 3153 case GXset: 3154 return true; 3155 default: 3156 return false; 3157 } 3158} 3159 3160inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc) 3161{ 3162 if (!alu_overwrites(gc->alu)) 3163 return false; 3164 3165 if (!PM_IS_SOLID(draw, gc->planemask)) 3166 return false; 3167 3168 if (gc->fillStyle == FillStippled) 3169 return false; 3170 3171 return true; 3172} 3173 3174inline static unsigned 3175drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial) 3176{ 3177 assert(sna_gc(gc)->changes == 0); 3178 3179 if (gc->fillStyle == FillStippled) { 3180 DBG(("%s: read due to fill %d\n", 3181 __FUNCTION__, gc->fillStyle)); 3182 return MOVE_READ | MOVE_WRITE; 3183 } 3184 3185 if (fb_gc(gc)->and | fb_gc(gc)->bgand) { 3186 DBG(("%s: read due to rrop %d:%x\n", 3187 __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and)); 3188 return MOVE_READ | MOVE_WRITE; 3189 } 3190 3191 DBG(("%s: try operating on drawable inplace [hint? %d]\n", 3192 __FUNCTION__, drawable_gc_inplace_hint(draw, gc))); 3193 3194 return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT; 3195} 3196 3197static inline struct sna_pixmap * 3198sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv) 3199{ 3200 assert(priv->gpu_bo); 3201 DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__, 3202 priv->pixmap->drawable.serialNumber, 3203 priv->gpu_bo->handle)); 3204 return priv; 3205} 3206 3207inline static struct sna_pixmap * 3208__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags) 3209{ 3210 struct sna_pixmap *priv; 3211 3212 if ((flags & __MOVE_FORCE) == 0 && wedged(sna)) 3213 return NULL; 3214 3215 priv = sna_pixmap(pixmap); 3216 if (priv == NULL) { 3217 DBG(("%s: not attached\n", __FUNCTION__)); 3218 if ((flags & __MOVE_DRI) == 0) 3219 return NULL; 3220 3221 if (pixmap->usage_hint == -1) { 3222 DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__)); 3223 return NULL; 3224 } 3225 3226 DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__)); 3227 3228 priv = sna_pixmap_attach(pixmap); 3229 if (priv == NULL) 3230 return NULL; 3231 3232 sna_damage_all(&priv->cpu_damage, pixmap); 3233 3234 assert(priv->gpu_bo == NULL); 3235 assert(priv->gpu_damage == NULL); 3236 } 3237 3238 return priv; 3239} 3240 3241struct sna_pixmap * 3242sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags) 3243{ 3244 struct sna *sna = to_sna_from_pixmap(pixmap); 3245 struct sna_pixmap *priv; 3246 RegionRec i, r; 3247 3248 DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n", 3249 __FUNCTION__, pixmap->drawable.serialNumber, 3250 box->x1, box->y1, box->x2, box->y2, flags)); 3251 3252 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 3253 if (priv == NULL) 3254 return NULL; 3255 3256 assert(box->x2 > box->x1 && box->y2 > box->y1); 3257 assert_pixmap_damage(pixmap); 3258 assert_pixmap_contains_box(pixmap, box); 3259 assert(priv->gpu_damage == NULL || priv->gpu_bo); 3260 3261 if ((flags & MOVE_READ) == 0) 3262 sna_damage_subtract_box(&priv->cpu_damage, box); 3263 3264 if (priv->move_to_gpu) { 3265 unsigned int hint; 3266 3267 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3268 hint = flags | MOVE_READ; 3269 if ((flags & MOVE_READ) == 0) { 3270 RegionRec region; 3271 3272 region.extents = *box; 3273 region.data = NULL; 3274 sna_pixmap_discard_shadow_damage(priv, ®ion); 3275 if (region_subsumes_pixmap(®ion, pixmap)) 3276 hint &= ~MOVE_READ; 3277 } else { 3278 if (priv->cpu_damage) 3279 hint |= MOVE_WRITE; 3280 } 3281 if (!priv->move_to_gpu(sna, priv, hint)) { 3282 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3283 return NULL; 3284 } 3285 } 3286 3287 if (priv->cow) { 3288 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 3289 3290 if ((flags & MOVE_READ) == 0) { 3291 if (priv->gpu_damage) { 3292 r.extents = *box; 3293 r.data = NULL; 3294 if (!region_subsumes_damage(&r, priv->gpu_damage)) 3295 cow |= MOVE_READ; 3296 } 3297 } else { 3298 if (priv->cpu_damage) { 3299 r.extents = *box; 3300 r.data = NULL; 3301 if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0)) 3302 cow |= MOVE_WRITE; 3303 } 3304 } 3305 3306 if (cow) { 3307 if (!sna_pixmap_undo_cow(sna, priv, cow)) 3308 return NULL; 3309 3310 if (priv->gpu_bo == NULL) 3311 sna_damage_destroy(&priv->gpu_damage); 3312 } 3313 } 3314 3315 if (sna_damage_is_all(&priv->gpu_damage, 3316 pixmap->drawable.width, 3317 pixmap->drawable.height)) { 3318 assert(priv->gpu_bo); 3319 assert(priv->gpu_bo->proxy == NULL); 3320 sna_damage_destroy(&priv->cpu_damage); 3321 list_del(&priv->flush_list); 3322 goto done; 3323 } 3324 3325 if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 3326 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 3327 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3328 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3329 assert(!priv->pinned); 3330 assert(!priv->mapped); 3331 sna_damage_destroy(&priv->gpu_damage); 3332 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 3333 priv->gpu_bo = NULL; 3334 } 3335 3336 sna_damage_reduce(&priv->cpu_damage); 3337 assert_pixmap_damage(pixmap); 3338 3339 if (priv->cpu_damage == NULL) { 3340 list_del(&priv->flush_list); 3341 return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags); 3342 } 3343 3344 if (priv->gpu_bo == NULL) { 3345 assert(priv->gpu_damage == NULL); 3346 3347 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) 3348 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE); 3349 3350 if (priv->gpu_bo == NULL) 3351 return NULL; 3352 3353 DBG(("%s: created gpu bo\n", __FUNCTION__)); 3354 } 3355 3356 if (priv->gpu_bo->proxy) { 3357 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 3358 assert((flags & MOVE_WRITE) == 0); 3359 assert(priv->gpu_damage == NULL); 3360 return priv; 3361 } 3362 3363 if (priv->shm) { 3364 assert(!priv->flush); 3365 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3366 } 3367 3368 assert(priv->cpu_damage); 3369 region_set(&r, box); 3370 if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) { 3371 bool ok = false; 3372 int n; 3373 3374 n = sna_damage_get_boxes(priv->cpu_damage, &box); 3375 assert(n); 3376 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3377 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3378 ok = sna->render.copy_boxes(sna, GXcopy, 3379 &pixmap->drawable, priv->cpu_bo, 0, 0, 3380 &pixmap->drawable, priv->gpu_bo, 0, 0, 3381 box, n, 0); 3382 } 3383 if (!ok) { 3384 sna_pixmap_unmap(pixmap, priv); 3385 if (pixmap->devPrivate.ptr == NULL) 3386 return NULL; 3387 3388 assert(pixmap->devKind); 3389 if (n == 1 && !priv->pinned && 3390 box->x1 <= 0 && box->y1 <= 0 && 3391 box->x2 >= pixmap->drawable.width && 3392 box->y2 >= pixmap->drawable.height) { 3393 ok = sna_replace(sna, pixmap, 3394 pixmap->devPrivate.ptr, 3395 pixmap->devKind); 3396 } else { 3397 ok = sna_write_boxes(sna, pixmap, 3398 priv->gpu_bo, 0, 0, 3399 pixmap->devPrivate.ptr, 3400 pixmap->devKind, 3401 0, 0, 3402 box, n); 3403 } 3404 if (!ok) 3405 return NULL; 3406 } 3407 3408 sna_damage_destroy(&priv->cpu_damage); 3409 } else if (DAMAGE_IS_ALL(priv->cpu_damage) || 3410 sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) { 3411 bool ok = false; 3412 3413 assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT); 3414 assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN); 3415 3416 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3417 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3418 ok = sna->render.copy_boxes(sna, GXcopy, 3419 &pixmap->drawable, priv->cpu_bo, 0, 0, 3420 &pixmap->drawable, priv->gpu_bo, 0, 0, 3421 box, 1, 0); 3422 } 3423 if (!ok) { 3424 sna_pixmap_unmap(pixmap, priv); 3425 if (pixmap->devPrivate.ptr != NULL) { 3426 assert(pixmap->devKind); 3427 ok = sna_write_boxes(sna, pixmap, 3428 priv->gpu_bo, 0, 0, 3429 pixmap->devPrivate.ptr, 3430 pixmap->devKind, 3431 0, 0, 3432 box, 1); 3433 } 3434 } 3435 if (!ok) 3436 return NULL; 3437 3438 sna_damage_subtract(&priv->cpu_damage, &r); 3439 } else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) { 3440 int n = region_num_rects(&i); 3441 bool ok; 3442 3443 box = region_rects(&i); 3444 ok = false; 3445 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3446 DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n)); 3447 ok = sna->render.copy_boxes(sna, GXcopy, 3448 &pixmap->drawable, priv->cpu_bo, 0, 0, 3449 &pixmap->drawable, priv->gpu_bo, 0, 0, 3450 box, n, 0); 3451 } 3452 if (!ok) { 3453 sna_pixmap_unmap(pixmap, priv); 3454 if (pixmap->devPrivate.ptr != NULL) { 3455 assert(pixmap->devKind); 3456 ok = sna_write_boxes(sna, pixmap, 3457 priv->gpu_bo, 0, 0, 3458 pixmap->devPrivate.ptr, 3459 pixmap->devKind, 3460 0, 0, 3461 box, n); 3462 } 3463 } 3464 if (!ok) 3465 return NULL; 3466 3467 sna_damage_subtract(&priv->cpu_damage, &r); 3468 RegionUninit(&i); 3469 } 3470 3471done: 3472 if (priv->cpu_damage == NULL && priv->flush) 3473 list_del(&priv->flush_list); 3474 if (flags & MOVE_WRITE) { 3475 priv->clear = false; 3476 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 3477 priv->cpu_damage == NULL && 3478 (box_covers_pixmap(pixmap, &r.extents) || 3479 box_inplace(pixmap, &r.extents))) { 3480 DBG(("%s: large operation on undamaged, discarding CPU shadow\n", 3481 __FUNCTION__)); 3482 assert(priv->gpu_bo); 3483 assert(priv->gpu_bo->proxy == NULL); 3484 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) { 3485 DBG(("%s: large operation on undamaged, promoting to full GPU\n", 3486 __FUNCTION__)); 3487 sna_damage_all(&priv->gpu_damage, pixmap); 3488 } 3489 } 3490 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3491 sna_pixmap_free_cpu(sna, priv, priv->cpu); 3492 sna_damage_destroy(&priv->cpu_damage); 3493 list_del(&priv->flush_list); 3494 } 3495 priv->cpu = false; 3496 } 3497 3498 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3499 return sna_pixmap_mark_active(sna, priv); 3500} 3501 3502struct kgem_bo * 3503sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box, 3504 struct sna_damage ***damage) 3505{ 3506 PixmapPtr pixmap = get_drawable_pixmap(drawable); 3507 struct sna_pixmap *priv = sna_pixmap(pixmap); 3508 struct sna *sna; 3509 RegionRec region; 3510 int16_t dx, dy; 3511 int ret; 3512 3513 DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n", 3514 __FUNCTION__, 3515 pixmap->drawable.serialNumber, 3516 box->x1, box->y1, box->x2, box->y2, 3517 flags)); 3518 3519 assert(box->x2 > box->x1 && box->y2 > box->y1); 3520 assert(pixmap->refcnt); 3521 assert_pixmap_damage(pixmap); 3522 assert_drawable_contains_box(drawable, box); 3523 3524 if (priv == NULL) { 3525 DBG(("%s: not attached\n", __FUNCTION__)); 3526 return NULL; 3527 } 3528 3529 if (priv->cow) { 3530 unsigned cow = MOVE_WRITE | MOVE_READ; 3531 3532 if (flags & IGNORE_DAMAGE) { 3533 if (priv->gpu_damage) { 3534 region.extents = *box; 3535 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3536 region.extents.x1 += dx; 3537 region.extents.x2 += dx; 3538 region.extents.y1 += dy; 3539 region.extents.y2 += dy; 3540 } 3541 region.data = NULL; 3542 if (region_subsumes_damage(®ion, 3543 priv->gpu_damage)) 3544 cow &= ~MOVE_READ; 3545 } else 3546 cow &= ~MOVE_READ; 3547 } 3548 3549 if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow)) 3550 return NULL; 3551 3552 if (priv->gpu_bo == NULL) 3553 sna_damage_destroy(&priv->gpu_damage); 3554 } 3555 3556 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 3557 DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__)); 3558 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3559 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3560 assert(!priv->pinned); 3561 assert(!priv->mapped); 3562 sna_damage_destroy(&priv->gpu_damage); 3563 kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem, 3564 priv->gpu_bo); 3565 priv->gpu_bo = NULL; 3566 goto use_cpu_bo; 3567 } 3568 3569 if (priv->flush) { 3570 DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__)); 3571 flags |= PREFER_GPU; 3572 } 3573 if (priv->shm) { 3574 DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__)); 3575 flags &= ~PREFER_GPU; 3576 } 3577 if (priv->pinned) { 3578 DBG(("%s: pinned, never REPLACES\n", __FUNCTION__)); 3579 flags &= ~REPLACES; 3580 } 3581 if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) { 3582 DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__)); 3583 flags &= ~PREFER_GPU; 3584 } 3585 3586 if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) { 3587 if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) { 3588 DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__)); 3589 flags |= PREFER_GPU; 3590 } 3591 } 3592 3593 DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n", 3594 __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags)); 3595 3596 if ((flags & PREFER_GPU) == 0 && 3597 (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) { 3598 DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__)); 3599 goto use_cpu_bo; 3600 } 3601 3602 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3603 DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__)); 3604 assert(priv->cpu_damage == NULL); 3605 assert(priv->gpu_bo); 3606 assert(priv->gpu_bo->proxy == NULL); 3607 goto use_gpu_bo; 3608 } 3609 3610 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3611 assert(priv->gpu_damage == NULL); 3612 if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) { 3613 DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n", 3614 __FUNCTION__)); 3615 goto use_cpu_bo; 3616 } 3617 } 3618 3619 DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__, 3620 priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL, 3621 priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL)); 3622 if (priv->gpu_bo == NULL) { 3623 unsigned int move; 3624 3625 if ((flags & FORCE_GPU) == 0 && 3626 (priv->create & KGEM_CAN_CREATE_GPU) == 0) { 3627 DBG(("%s: untiled, will not force allocation\n", 3628 __FUNCTION__)); 3629 goto use_cpu_bo; 3630 } 3631 3632 if ((flags & IGNORE_DAMAGE) == 0) { 3633 if (priv->cpu_bo) { 3634 if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) { 3635 if (kgem_bo_is_busy(priv->cpu_bo)) { 3636 DBG(("%s: already using CPU bo, will not force allocation\n", 3637 __FUNCTION__)); 3638 goto use_cpu_bo; 3639 } 3640 3641 if ((flags & RENDER_GPU) == 0) { 3642 DBG(("%s: prefer cpu", __FUNCTION__)); 3643 goto use_cpu_bo; 3644 } 3645 } else { 3646 if (kgem_bo_is_busy(priv->cpu_bo)) { 3647 DBG(("%s: CPU bo active, must force allocation\n", 3648 __FUNCTION__)); 3649 goto create_gpu_bo; 3650 } 3651 } 3652 } 3653 3654 if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) { 3655 if ((flags & PREFER_GPU) == 0) { 3656 DBG(("%s: already damaged and prefer cpu", 3657 __FUNCTION__)); 3658 goto use_cpu_bo; 3659 } 3660 3661 if (!box_inplace(pixmap, box)) { 3662 DBG(("%s: damaged with a small operation, will not force allocation\n", 3663 __FUNCTION__)); 3664 goto use_cpu_bo; 3665 } 3666 } 3667 } else if (priv->cpu_damage) { 3668 region.extents = *box; 3669 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3670 region.extents.x1 += dx; 3671 region.extents.x2 += dx; 3672 region.extents.y1 += dy; 3673 region.extents.y2 += dy; 3674 } 3675 region.data = NULL; 3676 3677 sna_damage_subtract(&priv->cpu_damage, ®ion); 3678 if (priv->cpu_damage == NULL) { 3679 list_del(&priv->flush_list); 3680 priv->cpu = false; 3681 } 3682 } 3683 3684create_gpu_bo: 3685 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3686 if (flags & FORCE_GPU) 3687 move |= __MOVE_FORCE; 3688 if (!sna_pixmap_move_to_gpu(pixmap, move)) 3689 goto use_cpu_bo; 3690 3691 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3692 goto done; 3693 } 3694 3695 3696 region.extents = *box; 3697 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3698 region.extents.x1 += dx; 3699 region.extents.x2 += dx; 3700 region.extents.y1 += dy; 3701 region.extents.y2 += dy; 3702 } 3703 region.data = NULL; 3704 3705 DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__, 3706 region.extents.x1, region.extents.y1, 3707 region.extents.x2, region.extents.y2)); 3708 3709 if (priv->gpu_damage) { 3710 assert(priv->gpu_bo); 3711 if (!priv->cpu_damage || flags & IGNORE_DAMAGE) { 3712 if (flags & REPLACES || box_covers_pixmap(pixmap, ®ion.extents)) { 3713 unsigned int move; 3714 3715 if (flags & IGNORE_DAMAGE) 3716 move = MOVE_WRITE; 3717 else 3718 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3719 3720 if (sna_pixmap_move_to_gpu(pixmap, move)) 3721 goto use_gpu_bo; 3722 } 3723 3724 if (DAMAGE_IS_ALL(priv->gpu_damage) || 3725 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3726 ®ion.extents)) { 3727 DBG(("%s: region wholly contained within GPU damage\n", 3728 __FUNCTION__)); 3729 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3730 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3731 goto use_gpu_bo; 3732 } else { 3733 DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n", 3734 __FUNCTION__)); 3735 goto move_to_gpu; 3736 } 3737 } 3738 3739 ret = sna_damage_contains_box(&priv->gpu_damage, ®ion.extents); 3740 if (ret == PIXMAN_REGION_IN) { 3741 DBG(("%s: region wholly contained within GPU damage\n", 3742 __FUNCTION__)); 3743 goto use_gpu_bo; 3744 } 3745 3746 if (ret != PIXMAN_REGION_OUT) { 3747 DBG(("%s: region partially contained within GPU damage\n", 3748 __FUNCTION__)); 3749 goto move_to_gpu; 3750 } 3751 } 3752 3753 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) { 3754 ret = sna_damage_contains_box(&priv->cpu_damage, ®ion.extents); 3755 if (ret == PIXMAN_REGION_IN) { 3756 DBG(("%s: region wholly contained within CPU damage\n", 3757 __FUNCTION__)); 3758 goto use_cpu_bo; 3759 } 3760 3761 if (box_inplace(pixmap, box)) { 3762 DBG(("%s: forcing inplace\n", __FUNCTION__)); 3763 goto move_to_gpu; 3764 } 3765 3766 if (ret != PIXMAN_REGION_OUT) { 3767 DBG(("%s: region partially contained within CPU damage\n", 3768 __FUNCTION__)); 3769 goto use_cpu_bo; 3770 } 3771 } 3772 3773move_to_gpu: 3774 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion.extents, 3775 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) { 3776 DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__)); 3777 assert(priv->gpu_bo == NULL); 3778 goto use_cpu_bo; 3779 } 3780 3781done: 3782 assert(priv->move_to_gpu == NULL); 3783 assert(priv->gpu_bo != NULL); 3784 assert(priv->gpu_bo->refcnt); 3785 if (sna_damage_is_all(&priv->gpu_damage, 3786 pixmap->drawable.width, 3787 pixmap->drawable.height)) { 3788 sna_damage_destroy(&priv->cpu_damage); 3789 list_del(&priv->flush_list); 3790 *damage = NULL; 3791 } else 3792 *damage = &priv->gpu_damage; 3793 3794 DBG(("%s: using GPU bo with damage? %d\n", 3795 __FUNCTION__, *damage != NULL)); 3796 assert(*damage == NULL || !DAMAGE_IS_ALL(*damage)); 3797 assert(priv->gpu_bo->proxy == NULL); 3798 assert(priv->clear == false); 3799 assert(priv->cpu == false); 3800 assert(!priv->shm); 3801 return priv->gpu_bo; 3802 3803use_gpu_bo: 3804 if (priv->move_to_gpu) { 3805 unsigned hint = MOVE_READ | MOVE_WRITE; 3806 3807 sna = to_sna_from_pixmap(pixmap); 3808 3809 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3810 if (flags & IGNORE_DAMAGE) { 3811 region.extents = *box; 3812 region.data = NULL; 3813 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3814 region.extents.x1 += dx; 3815 region.extents.x2 += dx; 3816 region.extents.y1 += dy; 3817 region.extents.y2 += dy; 3818 } 3819 sna_pixmap_discard_shadow_damage(priv, ®ion); 3820 if (region_subsumes_pixmap(®ion, pixmap)) { 3821 DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__)); 3822 hint = MOVE_WRITE; 3823 } 3824 } 3825 3826 if (!priv->move_to_gpu(sna, priv, hint)) { 3827 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3828 goto use_cpu_bo; 3829 } 3830 } 3831 3832 if (priv->shm) { 3833 assert(!priv->flush); 3834 list_move(&priv->flush_list, &sna->flush_pixmaps); 3835 } 3836 3837 DBG(("%s: using whole GPU bo\n", __FUNCTION__)); 3838 assert(priv->gpu_bo != NULL); 3839 assert(priv->gpu_bo->refcnt); 3840 assert(priv->gpu_bo->proxy == NULL); 3841 assert(priv->gpu_damage); 3842 priv->cpu = false; 3843 priv->clear = false; 3844 *damage = NULL; 3845 return priv->gpu_bo; 3846 3847use_cpu_bo: 3848 if (!USE_CPU_BO || priv->cpu_bo == NULL) { 3849 if ((flags & FORCE_GPU) == 0) { 3850 DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__)); 3851 return NULL; 3852 } 3853 3854 flags &= ~FORCE_GPU; 3855 3856 region.extents = *box; 3857 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3858 region.extents.x1 += dx; 3859 region.extents.x2 += dx; 3860 region.extents.y1 += dy; 3861 region.extents.y2 += dy; 3862 } 3863 region.data = NULL; 3864 3865 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3866 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) || 3867 priv->cpu_bo == NULL) { 3868 DBG(("%s: did not create CPU bo\n", __FUNCTION__)); 3869cpu_fail: 3870 if (priv->gpu_bo) 3871 goto move_to_gpu; 3872 3873 return NULL; 3874 } 3875 } 3876 3877 assert(priv->cpu_bo->refcnt); 3878 3879 sna = to_sna_from_pixmap(pixmap); 3880 if ((flags & FORCE_GPU) == 0 && 3881 !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 3882 DBG(("%s: has CPU bo, but is idle and acceleration not forced\n", 3883 __FUNCTION__)); 3884 return NULL; 3885 } 3886 3887 region.extents = *box; 3888 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3889 region.extents.x1 += dx; 3890 region.extents.x2 += dx; 3891 region.extents.y1 += dy; 3892 region.extents.y2 += dy; 3893 } 3894 region.data = NULL; 3895 3896 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 3897 DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n", 3898 __FUNCTION__)); 3899 goto move_to_gpu; 3900 } 3901 3902 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3903 3904 if (flags & RENDER_GPU) { 3905 flags &= ~RENDER_GPU; 3906 3907 if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) { 3908 DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__)); 3909 3910prefer_gpu_bo: 3911 if (priv->gpu_bo == NULL) { 3912 if ((flags & FORCE_GPU) == 0) { 3913 DBG(("%s: untiled, will not force allocation\n", 3914 __FUNCTION__)); 3915 return NULL; 3916 } 3917 3918 if (flags & IGNORE_DAMAGE) { 3919 sna_damage_subtract(&priv->cpu_damage, ®ion); 3920 if (priv->cpu_damage == NULL) { 3921 list_del(&priv->flush_list); 3922 priv->cpu = false; 3923 } 3924 } 3925 3926 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 3927 return NULL; 3928 3929 sna_damage_all(&priv->gpu_damage, pixmap); 3930 3931 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3932 goto done; 3933 } 3934 goto move_to_gpu; 3935 } 3936 3937 if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) { 3938 if (priv->gpu_bo && priv->gpu_bo->tiling) { 3939 DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__)); 3940 goto prefer_gpu_bo; 3941 } 3942 3943 if (priv->cpu_bo->pitch >= 4096) { 3944 DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__)); 3945 goto prefer_gpu_bo; 3946 } 3947 } 3948 3949 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) { 3950 DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__)); 3951 goto prefer_gpu_bo; 3952 } 3953 3954 if (!sna->kgem.can_blt_cpu) { 3955 DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__)); 3956 goto prefer_gpu_bo; 3957 } 3958 } 3959 3960 if (!sna->kgem.can_blt_cpu) 3961 goto cpu_fail; 3962 3963 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3964 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) { 3965 DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__)); 3966 goto cpu_fail; 3967 } 3968 3969 if (priv->shm) { 3970 assert(!priv->flush); 3971 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3972 3973 /* As we may have flushed and retired,, recheck for busy bo */ 3974 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo)) 3975 return NULL; 3976 } 3977 if (priv->flush) { 3978 assert(!priv->shm); 3979 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3980 } 3981 3982 if (sna_damage_is_all(&priv->cpu_damage, 3983 pixmap->drawable.width, 3984 pixmap->drawable.height)) { 3985 sna_damage_destroy(&priv->gpu_damage); 3986 *damage = NULL; 3987 } else { 3988 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3989 if (priv->cpu_damage && 3990 sna_damage_contains_box__no_reduce(priv->cpu_damage, 3991 ®ion.extents)) { 3992 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3993 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3994 *damage = NULL; 3995 } else 3996 *damage = &priv->cpu_damage; 3997 } 3998 3999 DBG(("%s: using CPU bo with damage? %d\n", 4000 __FUNCTION__, *damage != NULL)); 4001 assert(damage == NULL || !DAMAGE_IS_ALL(*damage)); 4002 assert(priv->clear == false); 4003 priv->cpu = false; 4004 return priv->cpu_bo; 4005} 4006 4007PixmapPtr 4008sna_pixmap_create_upload(ScreenPtr screen, 4009 int width, int height, int depth, 4010 unsigned flags) 4011{ 4012 struct sna *sna = to_sna_from_screen(screen); 4013 PixmapPtr pixmap; 4014 struct sna_pixmap *priv; 4015 void *ptr; 4016 4017 DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__, 4018 width, height, depth, flags)); 4019 assert(width); 4020 assert(height); 4021 4022 if (depth == 1) 4023 return create_pixmap(sna, screen, width, height, depth, 4024 CREATE_PIXMAP_USAGE_SCRATCH); 4025 4026 pixmap = create_pixmap_hdr(sna, screen, 4027 width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, 4028 &priv); 4029 if (!pixmap) 4030 return NullPixmap; 4031 4032 priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem, 4033 width, height, 4034 pixmap->drawable.bitsPerPixel, 4035 flags, &ptr); 4036 if (!priv->gpu_bo) { 4037 free(priv); 4038 FreePixmap(pixmap); 4039 return NullPixmap; 4040 } 4041 4042 /* Marking both the shadow and the GPU bo is a little dubious, 4043 * but will work so long as we always check before doing the 4044 * transfer. 4045 */ 4046 sna_damage_all(&priv->gpu_damage, pixmap); 4047 sna_damage_all(&priv->cpu_damage, pixmap); 4048 4049 pixmap->devKind = priv->gpu_bo->pitch; 4050 pixmap->devPrivate.ptr = ptr; 4051 priv->ptr = MAKE_STATIC_PTR(ptr); 4052 priv->stride = priv->gpu_bo->pitch; 4053 priv->create = 0; 4054 4055 pixmap->usage_hint = 0; 4056 if (!kgem_buffer_is_inplace(priv->gpu_bo)) 4057 pixmap->usage_hint = 1; 4058 4059 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 4060 __FUNCTION__, 4061 pixmap->drawable.serialNumber, 4062 pixmap->drawable.width, 4063 pixmap->drawable.height, 4064 pixmap->usage_hint)); 4065 return pixmap; 4066} 4067 4068static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags) 4069{ 4070 assert(priv->gpu_bo == NULL); 4071 4072 if (priv->cpu_bo == NULL) 4073 return false; 4074 4075 if (priv->shm) 4076 return false; 4077 4078 /* Linear scanout have a restriction that their pitch must be 4079 * 64 byte aligned. Force the creation of a proper GPU bo if 4080 * this CPU bo is not suitable for scanout. 4081 */ 4082 if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT) 4083 if (priv->cpu_bo->pitch & 63) 4084 return false; 4085 4086 if (flags & __MOVE_PRIME) 4087 if (priv->cpu_bo->pitch & 255) 4088 return false; 4089 4090 return true; 4091} 4092 4093struct sna_pixmap * 4094sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags) 4095{ 4096 struct sna *sna = to_sna_from_pixmap(pixmap); 4097 struct sna_pixmap *priv; 4098 const BoxRec *box; 4099 int n; 4100 4101 DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n", 4102 __FUNCTION__, 4103 pixmap->drawable.serialNumber, 4104 pixmap->usage_hint, 4105 flags)); 4106 4107 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 4108 if (priv == NULL) 4109 return NULL; 4110 4111 assert_pixmap_damage(pixmap); 4112 4113 if (priv->move_to_gpu && 4114 !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) { 4115 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 4116 return NULL; 4117 } 4118 4119 if ((flags & MOVE_READ) == 0 && UNDO) 4120 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4121 4122 if (priv->cow) { 4123 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 4124 if (flags & MOVE_READ && priv->cpu_damage) 4125 cow |= MOVE_WRITE; 4126 if (cow) { 4127 if (!sna_pixmap_undo_cow(sna, priv, cow)) 4128 return NULL; 4129 4130 if (priv->gpu_bo == NULL) 4131 sna_damage_destroy(&priv->gpu_damage); 4132 } 4133 } 4134 4135 if (sna_damage_is_all(&priv->gpu_damage, 4136 pixmap->drawable.width, 4137 pixmap->drawable.height)) { 4138 DBG(("%s: already all-damaged\n", __FUNCTION__)); 4139 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 4140 assert(priv->gpu_bo); 4141 assert(priv->gpu_bo->proxy == NULL); 4142 assert_pixmap_map(pixmap, priv); 4143 sna_damage_destroy(&priv->cpu_damage); 4144 list_del(&priv->flush_list); 4145 goto active; 4146 } 4147 4148 if ((flags & MOVE_READ) == 0) 4149 sna_damage_destroy(&priv->cpu_damage); 4150 4151 sna_damage_reduce(&priv->cpu_damage); 4152 assert_pixmap_damage(pixmap); 4153 DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL)); 4154 if (priv->gpu_bo == NULL || 4155 kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 4156 struct kgem_bo *proxy; 4157 4158 proxy = priv->gpu_bo; 4159 priv->gpu_bo = NULL; 4160 4161 DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n", 4162 __FUNCTION__, 4163 pixmap->drawable.width, 4164 pixmap->drawable.height, 4165 pixmap->drawable.bitsPerPixel, 4166 priv->create)); 4167 assert(!priv->mapped); 4168 assert(list_is_empty(&priv->flush_list)); 4169 4170 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) { 4171 bool is_linear; 4172 4173 assert(pixmap->drawable.width > 0); 4174 assert(pixmap->drawable.height > 0); 4175 assert(pixmap->drawable.bitsPerPixel >= 8); 4176 4177 if (flags & __MOVE_PRIME) { 4178 assert((flags & __MOVE_TILED) == 0); 4179 is_linear = true; 4180 } else { 4181 is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE; 4182 if (is_linear && flags & __MOVE_TILED) { 4183 DBG(("%s: not creating linear GPU bo\n", 4184 __FUNCTION__)); 4185 return NULL; 4186 } 4187 } 4188 4189 if (is_linear && 4190 can_convert_to_gpu(priv, flags) && 4191 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4192 assert(!priv->mapped); 4193 assert(!IS_STATIC_PTR(priv->ptr)); 4194#ifdef DEBUG_MEMORY 4195 sna->debug_memory.cpu_bo_allocs--; 4196 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4197#endif 4198 priv->gpu_bo = priv->cpu_bo; 4199 priv->cpu_bo = NULL; 4200 priv->ptr = NULL; 4201 pixmap->devPrivate.ptr = NULL; 4202 sna_damage_all(&priv->gpu_damage, pixmap); 4203 sna_damage_destroy(&priv->cpu_damage); 4204 } else { 4205 unsigned create = 0; 4206 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL)) 4207 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4208 if (flags & __MOVE_PRIME) 4209 create |= CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT; 4210 4211 sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4212 } 4213 } 4214 4215 if (priv->gpu_bo == NULL) { 4216 DBG(("%s: not creating GPU bo\n", __FUNCTION__)); 4217 assert(priv->gpu_damage == NULL); 4218 priv->gpu_bo = proxy; 4219 if (proxy) 4220 sna_damage_all(&priv->cpu_damage, pixmap); 4221 return NULL; 4222 } 4223 4224 if (proxy) { 4225 DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle)); 4226 4227 if (priv->cpu_damage && 4228 sna->render.copy_boxes(sna, GXcopy, 4229 &pixmap->drawable, proxy, 0, 0, 4230 &pixmap->drawable, priv->gpu_bo, 0, 0, 4231 region_rects(DAMAGE_REGION(priv->cpu_damage)), 4232 region_num_rects(DAMAGE_REGION(priv->cpu_damage)), 4233 0)) 4234 sna_damage_destroy(&priv->cpu_damage); 4235 4236 kgem_bo_destroy(&sna->kgem, proxy); 4237 } 4238 4239 if (flags & MOVE_WRITE && priv->cpu_damage == NULL) { 4240 /* Presume that we will only ever write to the GPU 4241 * bo. Readbacks are expensive but fairly constant 4242 * in cost for all sizes i.e. it is the act of 4243 * synchronisation that takes the most time. This is 4244 * mitigated by avoiding fallbacks in the first place. 4245 */ 4246 assert(priv->gpu_bo); 4247 assert(priv->gpu_bo->proxy == NULL); 4248 sna_damage_all(&priv->gpu_damage, pixmap); 4249 DBG(("%s: marking as all-damaged for GPU\n", 4250 __FUNCTION__)); 4251 goto active; 4252 } 4253 } 4254 4255 if (priv->gpu_bo->proxy) { 4256 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 4257 assert((flags & MOVE_WRITE) == 0); 4258 assert(priv->gpu_damage == NULL); 4259 return priv; 4260 } 4261 4262 if (priv->cpu_damage == NULL) 4263 goto done; 4264 4265 if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo && 4266 !priv->pinned && !priv->shm && 4267 priv->gpu_bo->tiling == I915_TILING_NONE && 4268 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4269 assert(!priv->mapped); 4270 assert(!IS_STATIC_PTR(priv->ptr)); 4271#ifdef DEBUG_MEMORY 4272 sna->debug_memory.cpu_bo_allocs--; 4273 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4274#endif 4275 sna_pixmap_free_gpu(sna, priv); 4276 priv->gpu_bo = priv->cpu_bo; 4277 priv->cpu_bo = NULL; 4278 priv->ptr = NULL; 4279 pixmap->devPrivate.ptr = NULL; 4280 sna_damage_all(&priv->gpu_damage, pixmap); 4281 sna_damage_destroy(&priv->cpu_damage); 4282 goto done; 4283 } 4284 4285 if (priv->shm) { 4286 assert(!priv->flush); 4287 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 4288 } 4289 4290 n = sna_damage_get_boxes(priv->cpu_damage, &box); 4291 assert(n); 4292 if (n) { 4293 bool ok; 4294 4295 assert_pixmap_contains_damage(pixmap, priv->cpu_damage); 4296 DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n)); 4297 4298 ok = false; 4299 if (use_cpu_bo_for_upload(sna, priv, flags)) { 4300 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 4301 ok = sna->render.copy_boxes(sna, GXcopy, 4302 &pixmap->drawable, priv->cpu_bo, 0, 0, 4303 &pixmap->drawable, priv->gpu_bo, 0, 0, 4304 box, n, 0); 4305 } 4306 if (!ok) { 4307 sna_pixmap_unmap(pixmap, priv); 4308 if (pixmap->devPrivate.ptr == NULL) 4309 return NULL; 4310 4311 assert(pixmap->devKind); 4312 if (n == 1 && !priv->pinned && 4313 (box->x2 - box->x1) >= pixmap->drawable.width && 4314 (box->y2 - box->y1) >= pixmap->drawable.height) { 4315 ok = sna_replace(sna, pixmap, 4316 pixmap->devPrivate.ptr, 4317 pixmap->devKind); 4318 } else { 4319 ok = sna_write_boxes(sna, pixmap, 4320 priv->gpu_bo, 0, 0, 4321 pixmap->devPrivate.ptr, 4322 pixmap->devKind, 4323 0, 0, 4324 box, n); 4325 } 4326 if (!ok) 4327 return NULL; 4328 } 4329 } 4330 4331 __sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage)); 4332 priv->cpu_damage = NULL; 4333 4334 /* For large bo, try to keep only a single copy around */ 4335 if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) { 4336 DBG(("%s: disposing of system copy for large/source\n", 4337 __FUNCTION__)); 4338 assert(!priv->shm); 4339 assert(priv->gpu_bo); 4340 assert(priv->gpu_bo->proxy == NULL); 4341 sna_damage_all(&priv->gpu_damage, pixmap); 4342 sna_pixmap_free_cpu(sna, priv, 4343 (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu); 4344 } 4345done: 4346 list_del(&priv->flush_list); 4347 4348 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4349 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4350 sna_pixmap_free_cpu(sna, priv, priv->cpu); 4351 4352active: 4353 if (flags & MOVE_WRITE) { 4354 priv->clear = false; 4355 priv->cpu = false; 4356 } 4357 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 4358 return sna_pixmap_mark_active(sna, priv); 4359} 4360 4361static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap) 4362{ 4363 DBG(("%s: target bpp=%d, source bpp=%d\n", 4364 __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel)); 4365 4366 if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel && 4367 FbEvenTile(pixmap->drawable.width * 4368 pixmap->drawable.bitsPerPixel)) { 4369 DBG(("%s: flushing pixmap\n", __FUNCTION__)); 4370 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 4371 return false; 4372 4373 fbPadPixmap(pixmap); 4374 } 4375 4376 return true; 4377} 4378 4379static bool must_check sna_gc_move_to_cpu(GCPtr gc, 4380 DrawablePtr drawable, 4381 RegionPtr region) 4382{ 4383 struct sna_gc *sgc = sna_gc(gc); 4384 long changes = sgc->changes; 4385 4386 DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes)); 4387 assert(drawable); 4388 assert(region); 4389 4390 assert(gc->ops == (GCOps *)&sna_gc_ops); 4391 gc->ops = (GCOps *)&sna_gc_ops__cpu; 4392 4393 assert(gc->funcs); 4394 sgc->old_funcs = gc->funcs; 4395 gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu; 4396 4397 assert(gc->pCompositeClip); 4398 sgc->priv = gc->pCompositeClip; 4399 gc->pCompositeClip = region; 4400 4401#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 4402 if (gc->clientClipType == CT_PIXMAP) { 4403 PixmapPtr clip = gc->clientClip; 4404 gc->clientClip = region_from_bitmap(gc->pScreen, clip); 4405 gc->pScreen->DestroyPixmap(clip); 4406 gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE; 4407 changes |= GCClipMask; 4408 } else 4409 changes &= ~GCClipMask; 4410#else 4411 changes &= ~GCClipMask; 4412#endif 4413 4414 if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) { 4415 long tmp = gc->serialNumber; 4416 gc->serialNumber = sgc->serial; 4417 4418 if (fb_gc(gc)->bpp != drawable->bitsPerPixel) { 4419 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask; 4420 fb_gc(gc)->bpp = drawable->bitsPerPixel; 4421 } 4422 4423 if (changes & GCTile && !gc->tileIsPixel) { 4424 DBG(("%s: flushing tile pixmap\n", __FUNCTION__)); 4425 if (!sna_validate_pixmap(drawable, gc->tile.pixmap)) 4426 return false; 4427 } 4428 4429 if (changes & GCStipple && gc->stipple) { 4430 DBG(("%s: flushing stipple pixmap\n", __FUNCTION__)); 4431 if (!sna_validate_pixmap(drawable, gc->stipple)) 4432 return false; 4433 } 4434 4435 fbValidateGC(gc, changes, drawable); 4436 gc->serialNumber = tmp; 4437 } 4438 sgc->changes = 0; 4439 4440 switch (gc->fillStyle) { 4441 case FillTiled: 4442 DBG(("%s: moving tile to cpu\n", __FUNCTION__)); 4443 return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ); 4444 case FillStippled: 4445 case FillOpaqueStippled: 4446 DBG(("%s: moving stipple to cpu\n", __FUNCTION__)); 4447 return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ); 4448 default: 4449 return true; 4450 } 4451} 4452 4453static void sna_gc_move_to_gpu(GCPtr gc) 4454{ 4455 DBG(("%s(%p)\n", __FUNCTION__, gc)); 4456 4457 assert(gc->ops == (GCOps *)&sna_gc_ops__cpu); 4458 assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu); 4459 4460 gc->ops = (GCOps *)&sna_gc_ops; 4461 gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs; 4462 assert(gc->funcs); 4463 gc->pCompositeClip = sna_gc(gc)->priv; 4464 assert(gc->pCompositeClip); 4465} 4466 4467static inline bool clip_box(BoxPtr box, GCPtr gc) 4468{ 4469 const BoxRec *clip; 4470 bool clipped; 4471 4472 assert(gc->pCompositeClip); 4473 clip = &gc->pCompositeClip->extents; 4474 4475 clipped = !region_is_singular(gc->pCompositeClip); 4476 if (box->x1 < clip->x1) 4477 box->x1 = clip->x1, clipped = true; 4478 if (box->x2 > clip->x2) 4479 box->x2 = clip->x2, clipped = true; 4480 4481 if (box->y1 < clip->y1) 4482 box->y1 = clip->y1, clipped = true; 4483 if (box->y2 > clip->y2) 4484 box->y2 = clip->y2, clipped = true; 4485 4486 return clipped; 4487} 4488 4489static inline void translate_box(BoxPtr box, DrawablePtr d) 4490{ 4491 box->x1 += d->x; 4492 box->x2 += d->x; 4493 4494 box->y1 += d->y; 4495 box->y2 += d->y; 4496} 4497 4498static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc) 4499{ 4500 translate_box(box, d); 4501 return clip_box(box, gc); 4502} 4503 4504static inline bool box32_clip(Box32Rec *box, GCPtr gc) 4505{ 4506 bool clipped = !region_is_singular(gc->pCompositeClip); 4507 const BoxRec *clip = &gc->pCompositeClip->extents; 4508 4509 if (box->x1 < clip->x1) 4510 box->x1 = clip->x1, clipped = true; 4511 if (box->x2 > clip->x2) 4512 box->x2 = clip->x2, clipped = true; 4513 4514 if (box->y1 < clip->y1) 4515 box->y1 = clip->y1, clipped = true; 4516 if (box->y2 > clip->y2) 4517 box->y2 = clip->y2, clipped = true; 4518 4519 return clipped; 4520} 4521 4522static inline void box32_translate(Box32Rec *box, DrawablePtr d) 4523{ 4524 box->x1 += d->x; 4525 box->x2 += d->x; 4526 4527 box->y1 += d->y; 4528 box->y2 += d->y; 4529} 4530 4531static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc) 4532{ 4533 box32_translate(box, d); 4534 return box32_clip(box, gc); 4535} 4536 4537static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y) 4538{ 4539 if (box->x1 > x) 4540 box->x1 = x; 4541 else if (box->x2 < x) 4542 box->x2 = x; 4543 4544 if (box->y1 > y) 4545 box->y1 = y; 4546 else if (box->y2 < y) 4547 box->y2 = y; 4548} 4549 4550static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16) 4551{ 4552 b16->x1 = b32->x1; 4553 b16->y1 = b32->y1; 4554 b16->x2 = b32->x2; 4555 b16->y2 = b32->y2; 4556 4557 return b16->x2 > b16->x1 && b16->y2 > b16->y1; 4558} 4559 4560static inline void box32_add_rect(Box32Rec *box, const xRectangle *r) 4561{ 4562 int32_t v; 4563 4564 v = r->x; 4565 if (box->x1 > v) 4566 box->x1 = v; 4567 v += r->width; 4568 if (box->x2 < v) 4569 box->x2 = v; 4570 4571 v = r->y; 4572 if (box->y1 > v) 4573 box->y1 = v; 4574 v += r->height; 4575 if (box->y2 < v) 4576 box->y2 = v; 4577} 4578 4579static bool 4580can_create_upload_tiled_x(struct sna *sna, 4581 PixmapPtr pixmap, 4582 struct sna_pixmap *priv, 4583 bool replaces) 4584{ 4585 if (priv->shm || (priv->cpu && !replaces)) 4586 return false; 4587 4588 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 4589 return false; 4590 4591 if (sna->kgem.has_llc) 4592 return true; 4593 4594 if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap)) 4595 return false; 4596 4597 return true; 4598} 4599 4600static bool 4601create_upload_tiled_x(struct sna *sna, 4602 PixmapPtr pixmap, 4603 struct sna_pixmap *priv, 4604 bool replaces) 4605{ 4606 unsigned create; 4607 4608 if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces)) 4609 return false; 4610 4611 assert(priv->gpu_bo == NULL); 4612 assert(priv->gpu_damage == NULL); 4613 4614 if (sna->kgem.has_llc) 4615 create = CREATE_CPU_MAP | CREATE_INACTIVE; 4616 else if (sna->kgem.has_wc_mmap) 4617 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4618 else 4619 create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED; 4620 4621 return sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4622} 4623 4624static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo) 4625{ 4626 return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap; 4627} 4628 4629static bool 4630try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region, 4631 int x, int y, int w, int h, char *bits, int stride) 4632{ 4633 struct sna *sna = to_sna_from_pixmap(pixmap); 4634 struct sna_pixmap *priv = sna_pixmap(pixmap); 4635 const BoxRec *box; 4636 uint8_t *dst; 4637 int n; 4638 4639 if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) { 4640 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4641 return false; 4642 } 4643 4644 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4645 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4646 return false; 4647 4648 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4649 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4650 return false; 4651 4652 if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) { 4653 dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 4654 if (dst == NULL) 4655 return false; 4656 4657 kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo); 4658 } else { 4659 dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo); 4660 if (dst == NULL) 4661 return false; 4662 4663 kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo); 4664 } 4665 4666 box = region_rects(region); 4667 n = region_num_rects(region); 4668 4669 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4670 4671 if (sigtrap_get()) 4672 return false; 4673 4674 if (priv->gpu_bo->tiling) { 4675 do { 4676 DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n", 4677 __FUNCTION__, 4678 box->x1 - x, box->y1 - y, 4679 box->x1, box->y1, 4680 box->x2 - box->x1, box->y2 - box->y1)); 4681 4682 assert(box->x2 > box->x1); 4683 assert(box->y2 > box->y1); 4684 4685 assert(box->x1 >= 0); 4686 assert(box->y1 >= 0); 4687 assert(box->x2 <= pixmap->drawable.width); 4688 assert(box->y2 <= pixmap->drawable.height); 4689 4690 assert(box->x1 - x >= 0); 4691 assert(box->y1 - y >= 0); 4692 assert(box->x2 - x <= w); 4693 assert(box->y2 - y <= h); 4694 4695 memcpy_to_tiled_x(&sna->kgem, bits, dst, 4696 pixmap->drawable.bitsPerPixel, 4697 stride, priv->gpu_bo->pitch, 4698 box->x1 - x, box->y1 - y, 4699 box->x1, box->y1, 4700 box->x2 - box->x1, box->y2 - box->y1); 4701 box++; 4702 } while (--n); 4703 } else { 4704 do { 4705 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4706 __FUNCTION__, 4707 box->x1 - x, box->y1 - y, 4708 box->x1, box->y1, 4709 box->x2 - box->x1, box->y2 - box->y1)); 4710 4711 assert(box->x2 > box->x1); 4712 assert(box->y2 > box->y1); 4713 4714 assert(box->x1 >= 0); 4715 assert(box->y1 >= 0); 4716 assert(box->x2 <= pixmap->drawable.width); 4717 assert(box->y2 <= pixmap->drawable.height); 4718 4719 assert(box->x1 - x >= 0); 4720 assert(box->y1 - y >= 0); 4721 assert(box->x2 - x <= w); 4722 assert(box->y2 - y <= h); 4723 4724 memcpy_blt(bits, dst, 4725 pixmap->drawable.bitsPerPixel, 4726 stride, priv->gpu_bo->pitch, 4727 box->x1 - x, box->y1 - y, 4728 box->x1, box->y1, 4729 box->x2 - box->x1, box->y2 - box->y1); 4730 box++; 4731 } while (--n); 4732 4733 if (!priv->shm) { 4734 pixmap->devPrivate.ptr = dst; 4735 pixmap->devKind = priv->gpu_bo->pitch; 4736 if (dst == MAP(priv->gpu_bo->map__cpu)) { 4737 priv->mapped = MAPPED_CPU; 4738 priv->cpu = true; 4739 } else 4740 priv->mapped = MAPPED_GTT; 4741 assert_pixmap_map(pixmap, priv); 4742 } 4743 } 4744 4745 sigtrap_put(); 4746 return true; 4747} 4748 4749static bool 4750try_upload__inplace(PixmapPtr pixmap, RegionRec *region, 4751 int x, int y, int w, int h, char *bits, int stride) 4752{ 4753 struct sna *sna = to_sna_from_pixmap(pixmap); 4754 struct sna_pixmap *priv = sna_pixmap(pixmap); 4755 bool ignore_cpu = false; 4756 bool replaces; 4757 const BoxRec *box; 4758 uint8_t *dst; 4759 int n; 4760 4761 if (!USE_INPLACE) 4762 return false; 4763 4764 assert(priv); 4765 4766 if (priv->shm && priv->gpu_damage == NULL) 4767 return false; 4768 4769 replaces = region_subsumes_pixmap(region, pixmap); 4770 4771 DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__, 4772 priv->gpu_bo != NULL, 4773 priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0, 4774 replaces)); 4775 4776 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 4777 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 4778 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 4779 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 4780 assert(!priv->pinned); 4781 assert(!priv->mapped); 4782 sna_damage_destroy(&priv->gpu_damage); 4783 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 4784 priv->gpu_bo = NULL; 4785 } 4786 4787 if (priv->gpu_bo && replaces) { 4788 if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4789 if (can_create_upload_tiled_x(sna, pixmap, priv, true) && 4790 (priv->cow || 4791 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4792 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4793 DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4794 kgem_bo_is_busy(priv->gpu_bo), 4795 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4796 sna_pixmap_free_gpu(sna, priv); 4797 ignore_cpu = true; 4798 } 4799 } 4800 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4801 4802 if (priv->cow || 4803 (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) { 4804 DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n", 4805 __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL)); 4806 return false; 4807 } 4808 4809 if (priv->gpu_damage && 4810 region_subsumes_damage(region, priv->gpu_damage)) { 4811 if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo); 4812 if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) && 4813 (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4814 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4815 DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4816 kgem_bo_is_busy(priv->gpu_bo), 4817 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4818 sna_pixmap_free_gpu(sna, priv); 4819 ignore_cpu = priv->cpu_damage == NULL; 4820 if (priv->ptr) 4821 sna_damage_all(&priv->cpu_damage, pixmap); 4822 } 4823 } 4824 4825 if (priv->gpu_bo == NULL && 4826 !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu)) 4827 return false; 4828 4829 DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling)); 4830 switch (priv->gpu_bo->tiling) { 4831 case I915_TILING_Y: 4832 break; 4833 case I915_TILING_X: 4834 if (!sna->kgem.memcpy_to_tiled_x) 4835 break; 4836 default: 4837 if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride)) 4838 goto done; 4839 break; 4840 } 4841 4842 if (priv->gpu_damage == NULL && !box_inplace(pixmap, ®ion->extents)) { 4843 DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__)); 4844 return false; 4845 } 4846 4847 if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 4848 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4849 return false; 4850 } 4851 4852 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4853 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4854 return false; 4855 4856 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4857 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4858 return false; 4859 4860 dst = kgem_bo_map(&sna->kgem, priv->gpu_bo); 4861 if (dst == NULL) 4862 return false; 4863 4864 pixmap->devPrivate.ptr = dst; 4865 pixmap->devKind = priv->gpu_bo->pitch; 4866 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 4867 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 4868 4869 box = region_rects(region); 4870 n = region_num_rects(region); 4871 4872 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4873 4874 if (sigtrap_get()) 4875 return false; 4876 4877 do { 4878 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4879 __FUNCTION__, 4880 box->x1 - x, box->y1 - y, 4881 box->x1, box->y1, 4882 box->x2 - box->x1, box->y2 - box->y1)); 4883 4884 assert(box->x2 > box->x1); 4885 assert(box->y2 > box->y1); 4886 4887 assert(box->x1 >= 0); 4888 assert(box->y1 >= 0); 4889 assert(box->x2 <= pixmap->drawable.width); 4890 assert(box->y2 <= pixmap->drawable.height); 4891 4892 assert(box->x1 - x >= 0); 4893 assert(box->y1 - y >= 0); 4894 assert(box->x2 - x <= w); 4895 assert(box->y2 - y <= h); 4896 4897 memcpy_blt(bits, dst, 4898 pixmap->drawable.bitsPerPixel, 4899 stride, priv->gpu_bo->pitch, 4900 box->x1 - x, box->y1 - y, 4901 box->x1, box->y1, 4902 box->x2 - box->x1, box->y2 - box->y1); 4903 box++; 4904 } while (--n); 4905 4906 sigtrap_put(); 4907 4908done: 4909 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4910 if (replaces) { 4911 sna_damage_all(&priv->gpu_damage, pixmap); 4912 } else { 4913 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 4914 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4915 } 4916 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4917 sna_damage_destroy(&priv->cpu_damage); 4918 else 4919 sna_damage_subtract(&priv->cpu_damage, region); 4920 4921 if (priv->cpu_damage == NULL) { 4922 list_del(&priv->flush_list); 4923 sna_damage_all(&priv->gpu_damage, pixmap); 4924 } 4925 4926 if (priv->shm) 4927 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 4928 } 4929 4930 assert(!priv->clear); 4931 return true; 4932} 4933 4934static bool 4935try_upload__blt(PixmapPtr pixmap, RegionRec *region, 4936 int x, int y, int w, int h, char *bits, int stride) 4937{ 4938 struct sna *sna = to_sna_from_pixmap(pixmap); 4939 struct sna_pixmap *priv; 4940 struct kgem_bo *src_bo; 4941 bool ok; 4942 4943 if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS) 4944 return false; 4945 4946 priv = sna_pixmap(pixmap); 4947 assert(priv); 4948 assert(priv->gpu_bo); 4949 assert(priv->gpu_bo->proxy == NULL); 4950 4951 if (priv->cpu_damage && 4952 (DAMAGE_IS_ALL(priv->cpu_damage) || 4953 sna_damage_contains_box__no_reduce(priv->cpu_damage, 4954 ®ion->extents)) && 4955 !box_inplace(pixmap, ®ion->extents)) { 4956 DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__)); 4957 return false; 4958 } 4959 4960 src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true); 4961 if (src_bo == NULL) 4962 return false; 4963 4964 src_bo->pitch = stride; 4965 kgem_bo_mark_unreusable(src_bo); 4966 4967 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4968 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) { 4969 kgem_bo_destroy(&sna->kgem, src_bo); 4970 return false; 4971 } 4972 4973 DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n", 4974 __FUNCTION__, x, y, w, h, region_num_rects(region))); 4975 4976 if (sigtrap_get() == 0) { 4977 ok = sna->render.copy_boxes(sna, GXcopy, 4978 &pixmap->drawable, src_bo, -x, -y, 4979 &pixmap->drawable, priv->gpu_bo, 0, 0, 4980 region_rects(region), 4981 region_num_rects(region), 4982 COPY_LAST); 4983 sigtrap_put(); 4984 } else 4985 ok = false; 4986 4987 kgem_bo_sync__cpu(&sna->kgem, src_bo); 4988 assert(src_bo->rq == NULL); 4989 kgem_bo_destroy(&sna->kgem, src_bo); 4990 4991 if (!ok) { 4992 DBG(("%s: copy failed!\n", __FUNCTION__)); 4993 return false; 4994 } 4995 4996 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4997 assert(!priv->clear); 4998 if (region_subsumes_drawable(region, &pixmap->drawable)) { 4999 sna_damage_all(&priv->gpu_damage, pixmap); 5000 } else { 5001 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5002 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 5003 } 5004 if (DAMAGE_IS_ALL(priv->gpu_damage)) 5005 sna_damage_destroy(&priv->cpu_damage); 5006 else 5007 sna_damage_subtract(&priv->cpu_damage, region); 5008 if (priv->cpu_damage == NULL) { 5009 list_del(&priv->flush_list); 5010 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) 5011 sna_damage_all(&priv->gpu_damage, pixmap); 5012 } 5013 } 5014 priv->cpu = false; 5015 priv->clear = false; 5016 5017 return true; 5018} 5019 5020static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region) 5021{ 5022 if (region_subsumes_pixmap(region, priv->pixmap)) 5023 return true; 5024 5025 if (priv->cpu_damage != NULL) { 5026 if (DAMAGE_IS_ALL(priv->cpu_damage)) 5027 return false; 5028 5029 if (!box_inplace(priv->pixmap, ®ion->extents)) 5030 return false; 5031 5032 if (sna_damage_contains_box__no_reduce(priv->cpu_damage, ®ion->extents)) 5033 return false; 5034 } 5035 5036 return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo); 5037 5038} 5039 5040static bool 5041try_upload__fast(PixmapPtr pixmap, RegionRec *region, 5042 int x, int y, int w, int h, char *bits, int stride) 5043{ 5044 struct sna *sna = to_sna_from_pixmap(pixmap); 5045 struct sna_pixmap *priv; 5046 5047 if (wedged(sna)) 5048 return false; 5049 5050 priv = sna_pixmap(pixmap); 5051 if (priv == NULL) 5052 return false; 5053 5054 if (ignore_cpu_damage(sna, priv, region)) { 5055 DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__)); 5056 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5057 return true; 5058 } 5059 5060 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) { 5061 DBG(("%s: no, no gpu damage\n", __FUNCTION__)); 5062 return false; 5063 } 5064 5065 assert(priv->gpu_bo); 5066 assert(priv->gpu_bo->proxy == NULL); 5067 5068 if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride)) 5069 return true; 5070 5071 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5072 return true; 5073 5074 return false; 5075} 5076 5077static bool 5078sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5079 int x, int y, int w, int h, char *bits, int stride) 5080{ 5081 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5082 unsigned int hint; 5083 const BoxRec *box; 5084 int16_t dx, dy; 5085 int n; 5086 5087 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5088 5089 if (gc->alu != GXcopy) 5090 return false; 5091 5092 if (drawable->depth < 8) 5093 return false; 5094 5095 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5096 x += dx + drawable->x; 5097 y += dy + drawable->y; 5098 assert(region->extents.x1 >= x); 5099 assert(region->extents.y1 >= y); 5100 assert(region->extents.x2 <= x + w); 5101 assert(region->extents.y2 <= y + h); 5102 5103 if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride)) 5104 return true; 5105 5106 hint = MOVE_WRITE; 5107 if (region_is_unclipped(region, pixmap->drawable.width, h) && 5108 (h+1)*stride > 65536) { 5109 DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n", 5110 __FUNCTION__, h*stride)); 5111 hint |= MOVE_WHOLE_HINT; 5112 } 5113 5114 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint)) 5115 return false; 5116 5117 if (sigtrap_get()) 5118 return false; 5119 5120 /* Region is pre-clipped and translated into pixmap space */ 5121 box = region_rects(region); 5122 n = region_num_rects(region); 5123 DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n)); 5124 do { 5125 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 5126 __FUNCTION__, 5127 box->x1 - x, box->y1 - y, 5128 box->x1, box->y1, 5129 box->x2 - box->x1, box->y2 - box->y1)); 5130 5131 assert(box->x2 > box->x1); 5132 assert(box->y2 > box->y1); 5133 5134 assert(box->x1 >= 0); 5135 assert(box->y1 >= 0); 5136 assert(box->x2 <= pixmap->drawable.width); 5137 assert(box->y2 <= pixmap->drawable.height); 5138 5139 assert(box->x1 - x >= 0); 5140 assert(box->y1 - y >= 0); 5141 assert(box->x2 - x <= w); 5142 assert(box->y2 - y <= h); 5143 5144 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE)); 5145 assert(pixmap->devKind); 5146 memcpy_blt(bits, pixmap->devPrivate.ptr, 5147 pixmap->drawable.bitsPerPixel, 5148 stride, pixmap->devKind, 5149 box->x1 - x, box->y1 - y, 5150 box->x1, box->y1, 5151 box->x2 - box->x1, box->y2 - box->y1); 5152 box++; 5153 } while (--n); 5154 5155 sigtrap_put(); 5156 assert_pixmap_damage(pixmap); 5157 return true; 5158} 5159 5160static inline uint8_t byte_reverse(uint8_t b) 5161{ 5162 return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; 5163} 5164 5165static inline uint8_t blt_depth(int depth) 5166{ 5167 switch (depth) { 5168 case 8: return 0; 5169 case 15: return 0x2; 5170 case 16: return 0x1; 5171 default: return 0x3; 5172 } 5173} 5174 5175static bool 5176sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5177 int x, int y, int w, int h, char *bits) 5178{ 5179 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5180 struct sna *sna = to_sna_from_pixmap(pixmap); 5181 struct sna_damage **damage; 5182 struct kgem_bo *bo; 5183 const BoxRec *box; 5184 int16_t dx, dy; 5185 int n; 5186 uint8_t rop = copy_ROP[gc->alu]; 5187 5188 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5189 ®ion->extents, &damage); 5190 if (bo == NULL) 5191 return false; 5192 5193 if (bo->tiling == I915_TILING_Y) { 5194 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5195 assert(bo == __sna_pixmap_get_bo(pixmap)); 5196 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5197 if (bo == NULL) { 5198 DBG(("%s: fallback -- unable to change tiling\n", 5199 __FUNCTION__)); 5200 return false; 5201 } 5202 } 5203 5204 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5205 return false; 5206 5207 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5208 if (damage) 5209 sna_damage_add_to_pixmap(damage, region, pixmap); 5210 assert_pixmap_damage(pixmap); 5211 5212 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5213 5214 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5215 x += dx + drawable->x; 5216 y += dy + drawable->y; 5217 5218 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5219 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5220 5221 /* Region is pre-clipped and translated into pixmap space */ 5222 box = region_rects(region); 5223 n = region_num_rects(region); 5224 do { 5225 int bx1 = (box->x1 - x) & ~7; 5226 int bx2 = (box->x2 - x + 7) & ~7; 5227 int bw = (bx2 - bx1)/8; 5228 int bh = box->y2 - box->y1; 5229 int bstride = ALIGN(bw, 2); 5230 struct kgem_bo *upload; 5231 void *ptr; 5232 5233 if (!kgem_check_batch(&sna->kgem, 10) || 5234 !kgem_check_bo_fenced(&sna->kgem, bo) || 5235 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5236 kgem_submit(&sna->kgem); 5237 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5238 return false; 5239 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5240 } 5241 5242 upload = kgem_create_buffer(&sna->kgem, 5243 bstride*bh, 5244 KGEM_BUFFER_WRITE_INPLACE, 5245 &ptr); 5246 if (!upload) 5247 break; 5248 5249 5250 if (sigtrap_get() == 0) { 5251 int src_stride = BitmapBytePad(w); 5252 uint8_t *dst = ptr; 5253 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5254 uint32_t *b; 5255 5256 bstride -= bw; 5257 src_stride -= bw; 5258 5259 do { 5260 int i = bw; 5261 assert(src >= (uint8_t *)bits); 5262 do { 5263 *dst++ = byte_reverse(*src++); 5264 } while (--i); 5265 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5266 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5267 dst += bstride; 5268 src += src_stride; 5269 } while (--bh); 5270 5271 assert(sna->kgem.mode == KGEM_BLT); 5272 if (sna->kgem.gen >= 0100) { 5273 b = sna->kgem.batch + sna->kgem.nbatch; 5274 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 5275 b[0] |= ((box->x1 - x) & 7) << 17; 5276 b[1] = bo->pitch; 5277 if (bo->tiling) { 5278 b[0] |= BLT_DST_TILED; 5279 b[1] >>= 2; 5280 } 5281 b[1] |= blt_depth(drawable->depth) << 24; 5282 b[1] |= rop << 16; 5283 b[2] = box->y1 << 16 | box->x1; 5284 b[3] = box->y2 << 16 | box->x2; 5285 *(uint64_t *)(b+4) = 5286 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5287 I915_GEM_DOMAIN_RENDER << 16 | 5288 I915_GEM_DOMAIN_RENDER | 5289 KGEM_RELOC_FENCED, 5290 0); 5291 *(uint64_t *)(b+6) = 5292 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5293 I915_GEM_DOMAIN_RENDER << 16 | 5294 KGEM_RELOC_FENCED, 5295 0); 5296 b[8] = gc->bgPixel; 5297 b[9] = gc->fgPixel; 5298 5299 sna->kgem.nbatch += 10; 5300 } else { 5301 b = sna->kgem.batch + sna->kgem.nbatch; 5302 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 5303 b[0] |= ((box->x1 - x) & 7) << 17; 5304 b[1] = bo->pitch; 5305 if (sna->kgem.gen >= 040 && bo->tiling) { 5306 b[0] |= BLT_DST_TILED; 5307 b[1] >>= 2; 5308 } 5309 b[1] |= blt_depth(drawable->depth) << 24; 5310 b[1] |= rop << 16; 5311 b[2] = box->y1 << 16 | box->x1; 5312 b[3] = box->y2 << 16 | box->x2; 5313 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5314 I915_GEM_DOMAIN_RENDER << 16 | 5315 I915_GEM_DOMAIN_RENDER | 5316 KGEM_RELOC_FENCED, 5317 0); 5318 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5319 I915_GEM_DOMAIN_RENDER << 16 | 5320 KGEM_RELOC_FENCED, 5321 0); 5322 b[6] = gc->bgPixel; 5323 b[7] = gc->fgPixel; 5324 5325 sna->kgem.nbatch += 8; 5326 } 5327 sigtrap_put(); 5328 } 5329 kgem_bo_destroy(&sna->kgem, upload); 5330 5331 box++; 5332 } while (--n); 5333 5334 sna->blt_state.fill_bo = 0; 5335 return true; 5336} 5337 5338static bool 5339sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5340 int x, int y, int w, int h, int left,char *bits) 5341{ 5342 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5343 struct sna *sna = to_sna_from_pixmap(pixmap); 5344 struct sna_damage **damage; 5345 struct kgem_bo *bo; 5346 int16_t dx, dy; 5347 unsigned i, skip; 5348 5349 if (gc->alu != GXcopy) 5350 return false; 5351 5352 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5353 ®ion->extents, &damage); 5354 if (bo == NULL) 5355 return false; 5356 5357 if (bo->tiling == I915_TILING_Y) { 5358 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5359 assert(bo == __sna_pixmap_get_bo(pixmap)); 5360 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5361 if (bo == NULL) { 5362 DBG(("%s: fallback -- unable to change tiling\n", 5363 __FUNCTION__)); 5364 return false; 5365 } 5366 } 5367 5368 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5369 return false; 5370 5371 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5372 if (damage) 5373 sna_damage_add_to_pixmap(damage, region, pixmap); 5374 assert_pixmap_damage(pixmap); 5375 5376 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5377 5378 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5379 x += dx + drawable->x; 5380 y += dy + drawable->y; 5381 5382 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5383 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5384 5385 skip = h * BitmapBytePad(w + left); 5386 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { 5387 const BoxRec *box = region_rects(region); 5388 int n = region_num_rects(region); 5389 5390 if ((gc->planemask & i) == 0) 5391 continue; 5392 5393 /* Region is pre-clipped and translated into pixmap space */ 5394 do { 5395 int bx1 = (box->x1 - x) & ~7; 5396 int bx2 = (box->x2 - x + 7) & ~7; 5397 int bw = (bx2 - bx1)/8; 5398 int bh = box->y2 - box->y1; 5399 int bstride = ALIGN(bw, 2); 5400 struct kgem_bo *upload; 5401 void *ptr; 5402 5403 if (!kgem_check_batch(&sna->kgem, 14) || 5404 !kgem_check_bo_fenced(&sna->kgem, bo) || 5405 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5406 kgem_submit(&sna->kgem); 5407 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5408 return false; 5409 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5410 } 5411 5412 upload = kgem_create_buffer(&sna->kgem, 5413 bstride*bh, 5414 KGEM_BUFFER_WRITE_INPLACE, 5415 &ptr); 5416 if (!upload) 5417 break; 5418 5419 if (sigtrap_get() == 0) { 5420 int src_stride = BitmapBytePad(w); 5421 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5422 uint8_t *dst = ptr; 5423 uint32_t *b; 5424 5425 bstride -= bw; 5426 src_stride -= bw; 5427 do { 5428 int j = bw; 5429 assert(src >= (uint8_t *)bits); 5430 do { 5431 *dst++ = byte_reverse(*src++); 5432 } while (--j); 5433 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5434 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5435 dst += bstride; 5436 src += src_stride; 5437 } while (--bh); 5438 5439 assert(sna->kgem.mode == KGEM_BLT); 5440 if (sna->kgem.gen >= 0100) { 5441 assert(sna->kgem.mode == KGEM_BLT); 5442 b = sna->kgem.batch + sna->kgem.nbatch; 5443 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12; 5444 b[0] |= ((box->x1 - x) & 7) << 17; 5445 b[1] = bo->pitch; 5446 if (bo->tiling) { 5447 b[0] |= BLT_DST_TILED; 5448 b[1] >>= 2; 5449 } 5450 b[1] |= 1 << 31; /* solid pattern */ 5451 b[1] |= blt_depth(drawable->depth) << 24; 5452 b[1] |= 0xce << 16; /* S or (D and !P) */ 5453 b[2] = box->y1 << 16 | box->x1; 5454 b[3] = box->y2 << 16 | box->x2; 5455 *(uint64_t *)(b+4) = 5456 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5457 I915_GEM_DOMAIN_RENDER << 16 | 5458 I915_GEM_DOMAIN_RENDER | 5459 KGEM_RELOC_FENCED, 5460 0); 5461 *(uint64_t *)(b+6) = 5462 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5463 I915_GEM_DOMAIN_RENDER << 16 | 5464 KGEM_RELOC_FENCED, 5465 0); 5466 b[8] = 0; 5467 b[9] = i; 5468 b[10] = i; 5469 b[11] = i; 5470 b[12] = -1; 5471 b[13] = -1; 5472 sna->kgem.nbatch += 14; 5473 } else { 5474 b = sna->kgem.batch + sna->kgem.nbatch; 5475 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10; 5476 b[0] |= ((box->x1 - x) & 7) << 17; 5477 b[1] = bo->pitch; 5478 if (sna->kgem.gen >= 040 && bo->tiling) { 5479 b[0] |= BLT_DST_TILED; 5480 b[1] >>= 2; 5481 } 5482 b[1] |= 1 << 31; /* solid pattern */ 5483 b[1] |= blt_depth(drawable->depth) << 24; 5484 b[1] |= 0xce << 16; /* S or (D and !P) */ 5485 b[2] = box->y1 << 16 | box->x1; 5486 b[3] = box->y2 << 16 | box->x2; 5487 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5488 I915_GEM_DOMAIN_RENDER << 16 | 5489 I915_GEM_DOMAIN_RENDER | 5490 KGEM_RELOC_FENCED, 5491 0); 5492 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5493 I915_GEM_DOMAIN_RENDER << 16 | 5494 KGEM_RELOC_FENCED, 5495 0); 5496 b[6] = 0; 5497 b[7] = i; 5498 b[8] = i; 5499 b[9] = i; 5500 b[10] = -1; 5501 b[11] = -1; 5502 sna->kgem.nbatch += 12; 5503 } 5504 sigtrap_put(); 5505 } 5506 kgem_bo_destroy(&sna->kgem, upload); 5507 5508 box++; 5509 } while (--n); 5510 } 5511 5512 sna->blt_state.fill_bo = 0; 5513 return true; 5514} 5515 5516static void 5517sna_put_image(DrawablePtr drawable, GCPtr gc, int depth, 5518 int x, int y, int w, int h, int left, int format, 5519 char *bits) 5520{ 5521 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5522 struct sna *sna = to_sna_from_pixmap(pixmap); 5523 struct sna_pixmap *priv = sna_pixmap(pixmap); 5524 RegionRec region; 5525 int16_t dx, dy; 5526 5527 DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n", 5528 __FUNCTION__, x, y, w, h, depth, format)); 5529 5530 if (w == 0 || h == 0) 5531 return; 5532 5533 region.extents.x1 = x + drawable->x; 5534 region.extents.y1 = y + drawable->y; 5535 region.extents.x2 = region.extents.x1 + w; 5536 region.extents.y2 = region.extents.y1 + h; 5537 region.data = NULL; 5538 5539 if (!region_is_singular(gc->pCompositeClip) || 5540 gc->pCompositeClip->extents.x1 > region.extents.x1 || 5541 gc->pCompositeClip->extents.y1 > region.extents.y1 || 5542 gc->pCompositeClip->extents.x2 < region.extents.x2 || 5543 gc->pCompositeClip->extents.y2 < region.extents.y2) { 5544 if (!RegionIntersect(®ion, ®ion, gc->pCompositeClip) || 5545 box_empty(®ion.extents)) 5546 return; 5547 } 5548 5549 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 5550 RegionTranslate(®ion, dx, dy); 5551 5552 if (priv == NULL) { 5553 DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n", 5554 __FUNCTION__, x, y, w, h)); 5555 goto fallback; 5556 } 5557 5558 if (FORCE_FALLBACK) 5559 goto fallback; 5560 5561 if (wedged(sna)) 5562 goto fallback; 5563 5564 if (!ACCEL_PUT_IMAGE) 5565 goto fallback; 5566 5567 switch (format) { 5568 case ZPixmap: 5569 if (!PM_IS_SOLID(drawable, gc->planemask)) 5570 goto fallback; 5571 5572 if (sna_put_zpixmap_blt(drawable, gc, ®ion, 5573 x, y, w, h, 5574 bits, PixmapBytePad(w, depth))) 5575 return; 5576 break; 5577 5578 case XYBitmap: 5579 if (!PM_IS_SOLID(drawable, gc->planemask)) 5580 goto fallback; 5581 5582 if (sna_put_xybitmap_blt(drawable, gc, ®ion, 5583 x, y, w, h, 5584 bits)) 5585 return; 5586 break; 5587 5588 case XYPixmap: 5589 if (sna_put_xypixmap_blt(drawable, gc, ®ion, 5590 x, y, w, h, left, 5591 bits)) 5592 return; 5593 break; 5594 5595 default: 5596 return; 5597 } 5598 5599fallback: 5600 DBG(("%s: fallback\n", __FUNCTION__)); 5601 RegionTranslate(®ion, -dx, -dy); 5602 5603 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 5604 goto out; 5605 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 5606 format == XYPixmap ? 5607 MOVE_READ | MOVE_WRITE : 5608 drawable_gc_flags(drawable, gc, false))) 5609 goto out; 5610 5611 if (sigtrap_get() == 0) { 5612 DBG(("%s: fbPutImage(%d, %d, %d, %d)\n", 5613 __FUNCTION__, x, y, w, h)); 5614 fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits); 5615 FALLBACK_FLUSH(drawable); 5616 sigtrap_put(); 5617 } 5618out: 5619 sna_gc_move_to_gpu(gc); 5620 RegionUninit(®ion); 5621} 5622 5623static bool 5624source_contains_region(struct sna_damage *damage, 5625 const RegionRec *region, int16_t dx, int16_t dy) 5626{ 5627 BoxRec box; 5628 5629 if (DAMAGE_IS_ALL(damage)) 5630 return true; 5631 5632 if (damage == NULL) 5633 return false; 5634 5635 box = region->extents; 5636 box.x1 += dx; 5637 box.x2 += dx; 5638 box.y1 += dy; 5639 box.y2 += dy; 5640 return sna_damage_contains_box__no_reduce(damage, &box); 5641} 5642 5643static bool 5644move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv, 5645 RegionRec *region, int16_t dx, int16_t dy, 5646 uint8_t alu, bool dst_is_gpu) 5647{ 5648 int w = region->extents.x2 - region->extents.x1; 5649 int h = region->extents.y2 - region->extents.y1; 5650 int count; 5651 5652 assert_pixmap_map(pixmap, priv); 5653 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 5654 assert(priv->gpu_bo); 5655 return true; 5656 } 5657 5658 if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) { 5659 DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n", 5660 __FUNCTION__, 5661 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5662 priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0, 5663 priv->cpu)); 5664 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 5665 return false; 5666 5667 if (priv->cpu && 5668 source_contains_region(priv->cpu_damage, region, dx, dy)) 5669 return false; 5670 } 5671 5672 if (priv->gpu_bo) { 5673 DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n", 5674 __FUNCTION__, 5675 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5676 priv->cpu, priv->gpu_bo->tiling)); 5677 5678 if (priv->cpu_damage == NULL) 5679 return true; 5680 5681 if (alu != GXcopy) 5682 return true; 5683 5684 if (!priv->cpu) 5685 return true; 5686 5687 if (priv->gpu_bo->tiling) 5688 return true; 5689 5690 RegionTranslate(region, dx, dy); 5691 count = region_subsumes_damage(region, priv->cpu_damage); 5692 RegionTranslate(region, -dx, -dy); 5693 if (count) 5694 return true; 5695 } else { 5696 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 5697 return false; 5698 if (priv->shm) 5699 return false; 5700 } 5701 5702 count = priv->source_count++; 5703 if (priv->cpu_bo) { 5704 if (priv->cpu_bo->flush && count > SOURCE_BIAS) 5705 return true; 5706 5707 if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE) 5708 return false; 5709 5710 if (priv->cpu) 5711 return false; 5712 5713 return count > SOURCE_BIAS; 5714 } else { 5715 if (w == pixmap->drawable.width && h == pixmap->drawable.height) 5716 return count > SOURCE_BIAS; 5717 5718 return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height; 5719 } 5720} 5721 5722static const BoxRec * 5723reorder_boxes(const BoxRec *box, int n, int dx, int dy) 5724{ 5725 const BoxRec *next, *base; 5726 BoxRec *new; 5727 5728 DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy)); 5729 5730 if (dy <= 0 && dx <= 0) { 5731 BoxRec *tmp; 5732 5733 new = malloc(sizeof(BoxRec) * n); 5734 if (new == NULL) 5735 return NULL; 5736 5737 tmp = new; 5738 next = box + n; 5739 do { 5740 *tmp++ = *--next; 5741 } while (next != box); 5742 } else if (dy < 0) { 5743 new = malloc(sizeof(BoxRec) * n); 5744 if (new == NULL) 5745 return NULL; 5746 5747 base = next = box + n - 1; 5748 while (base >= box) { 5749 const BoxRec *tmp; 5750 5751 while (next >= box && base->y1 == next->y1) 5752 next--; 5753 tmp = next + 1; 5754 while (tmp <= base) 5755 *new++ = *tmp++; 5756 base = next; 5757 } 5758 new -= n; 5759 } else { 5760 new = malloc(sizeof(BoxRec) * n); 5761 if (!new) 5762 return NULL; 5763 5764 base = next = box; 5765 while (base < box + n) { 5766 const BoxRec *tmp; 5767 5768 while (next < box + n && next->y1 == base->y1) 5769 next++; 5770 tmp = next; 5771 while (tmp != base) 5772 *new++ = *--tmp; 5773 base = next; 5774 } 5775 new -= n; 5776 } 5777 5778 return new; 5779} 5780 5781static void 5782sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5783 RegionPtr region,int dx, int dy, 5784 Pixel bitplane, void *closure) 5785{ 5786 PixmapPtr pixmap = get_drawable_pixmap(src); 5787 struct sna *sna = to_sna_from_pixmap(pixmap); 5788 struct sna_pixmap *priv = sna_pixmap(pixmap); 5789 const BoxRec *box = region_rects(region); 5790 int n = region_num_rects(region); 5791 int alu = gc ? gc->alu : GXcopy; 5792 int16_t tx, ty, sx, sy; 5793 5794 assert(pixmap == get_drawable_pixmap(dst)); 5795 5796 assert(region_num_rects(region)); 5797 if (((dx | dy) == 0 && alu == GXcopy)) 5798 return; 5799 5800 if (n > 1 && (dx | dy) < 0) { 5801 box = reorder_boxes(box, n, dx, dy); 5802 if (box == NULL) 5803 return; 5804 } 5805 5806 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n", 5807 __FUNCTION__, n, 5808 region->extents.x1, region->extents.y1, 5809 region->extents.x2, region->extents.y2, 5810 dx, dy, alu, 5811 pixmap->drawable.width, pixmap->drawable.height)); 5812 5813 get_drawable_deltas(dst, pixmap, &tx, &ty); 5814 get_drawable_deltas(src, pixmap, &sx, &sy); 5815 sx += dx; 5816 sy += dy; 5817 5818 if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) { 5819 DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__)); 5820 goto fallback; 5821 } 5822 5823 if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) { 5824 assert(priv->gpu_bo); 5825 5826 if (alu == GXcopy && priv->clear) 5827 goto free_boxes; 5828 5829 assert(priv->gpu_bo->proxy == NULL); 5830 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) { 5831 DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n", 5832 __FUNCTION__)); 5833 goto fallback; 5834 } 5835 assert(priv->cpu_damage == NULL); 5836 5837 if (!sna->render.copy_boxes(sna, alu, 5838 &pixmap->drawable, priv->gpu_bo, sx, sy, 5839 &pixmap->drawable, priv->gpu_bo, tx, ty, 5840 box, n, 0)) { 5841 DBG(("%s: fallback - accelerated copy boxes failed\n", 5842 __FUNCTION__)); 5843 goto fallback; 5844 } 5845 5846 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5847 assert(!priv->clear); 5848 if (sna_pixmap_free_cpu(sna, priv, false)) { 5849 sna_damage_all(&priv->gpu_damage, pixmap); 5850 } else { 5851 RegionTranslate(region, tx, ty); 5852 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5853 } 5854 } 5855 assert_pixmap_damage(pixmap); 5856 } else { 5857fallback: 5858 DBG(("%s: fallback\n", __FUNCTION__)); 5859 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 5860 goto free_boxes; 5861 5862 if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) { 5863 assert(pixmap->devKind); 5864 if (sigtrap_get() == 0) { 5865 FbBits *dst_bits, *src_bits; 5866 int stride = pixmap->devKind; 5867 int bpp = pixmap->drawable.bitsPerPixel; 5868 int i; 5869 5870 dst_bits = (FbBits *) 5871 ((char *)pixmap->devPrivate.ptr + 5872 ty * stride + tx * bpp / 8); 5873 src_bits = (FbBits *) 5874 ((char *)pixmap->devPrivate.ptr + 5875 sy * stride + sx * bpp / 8); 5876 5877 for (i = 0; i < n; i++) 5878 memmove_box(src_bits, dst_bits, 5879 bpp, stride, box+i, 5880 dx, dy); 5881 sigtrap_put(); 5882 } 5883 } else { 5884 if (gc && !sna_gc_move_to_cpu(gc, dst, region)) 5885 goto out; 5886 5887 if (sigtrap_get() == 0) { 5888 miCopyRegion(src, dst, gc, 5889 region, dx, dy, 5890 fbCopyNtoN, 0, NULL); 5891 sigtrap_put(); 5892 } 5893 5894 if (gc) 5895out: 5896 sna_gc_move_to_gpu(gc); 5897 } 5898 } 5899 5900free_boxes: 5901 if (box != region_rects(region)) 5902 free((void *)box); 5903} 5904 5905static inline bool 5906sna_pixmap_is_gpu(PixmapPtr pixmap) 5907{ 5908 struct sna_pixmap *priv = sna_pixmap(pixmap); 5909 5910 if (priv == NULL || priv->clear) 5911 return false; 5912 5913 if (DAMAGE_IS_ALL(priv->gpu_damage) || 5914 (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy)) 5915 return true; 5916 5917 return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo); 5918} 5919 5920static int 5921copy_prefer_gpu(struct sna *sna, 5922 struct sna_pixmap *dst_priv, 5923 struct sna_pixmap *src_priv, 5924 RegionRec *region, 5925 int16_t dx, int16_t dy) 5926{ 5927 assert(dst_priv); 5928 5929 if (wedged(sna) && !dst_priv->pinned) 5930 return 0; 5931 5932 if (src_priv == NULL) { 5933 DBG(("%s: source unattached, use cpu\n", __FUNCTION__)); 5934 return 0; 5935 } 5936 5937 if (src_priv->clear) { 5938 DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__)); 5939 return 0; 5940 } 5941 5942 if (src_priv->gpu_damage && 5943 !source_contains_region(src_priv->cpu_damage, region, dx, dy)) { 5944 DBG(("%s: source has gpu damage, force gpu? %d\n", 5945 __FUNCTION__, src_priv->cpu_damage == NULL)); 5946 assert(src_priv->gpu_bo); 5947 return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU; 5948 } 5949 5950 if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) { 5951 DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__)); 5952 return PREFER_GPU | FORCE_GPU; 5953 } 5954 5955 if (source_contains_region(src_priv->cpu_damage, region, dx, dy)) 5956 return src_priv->cpu_bo && kgem_is_idle(&sna->kgem); 5957 5958 DBG(("%s: source has GPU bo? %d\n", 5959 __FUNCTION__, src_priv->gpu_bo != NULL)); 5960 return src_priv->gpu_bo != NULL; 5961} 5962 5963static bool use_shm_bo(struct sna *sna, 5964 struct kgem_bo *bo, 5965 struct sna_pixmap *priv, 5966 int alu, bool replaces) 5967{ 5968 if (priv == NULL || priv->cpu_bo == NULL) { 5969 DBG(("%s: no, not attached\n", __FUNCTION__)); 5970 return false; 5971 } 5972 5973 if (!priv->shm && !priv->cpu) { 5974 DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__)); 5975 return true; 5976 } 5977 5978 if (alu != GXcopy) { 5979 DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu)); 5980 return true; 5981 } 5982 5983 if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) { 5984 DBG(("%s: yes, dst is busy\n", __FUNCTION__)); 5985 return true; 5986 } 5987 5988 if (priv->cpu_bo->needs_flush && 5989 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 5990 DBG(("%s: yes, src is busy\n", __FUNCTION__)); 5991 return true; 5992 } 5993 5994 return false; 5995} 5996 5997static bool 5998sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage, 5999 const BoxRec *extents, 6000 int16_t dx, int16_t dy) 6001{ 6002 BoxRec _extents; 6003 6004 if (dx | dy) { 6005 _extents.x1 = extents->x1 + dx; 6006 _extents.x2 = extents->x2 + dx; 6007 _extents.y1 = extents->y1 + dy; 6008 _extents.y2 = extents->y2 + dy; 6009 extents = &_extents; 6010 } 6011 6012 return sna_damage_contains_box__no_reduce(damage, extents); 6013} 6014 6015static bool 6016sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu, 6017 PixmapPtr src_pixmap, struct sna_pixmap *src_priv, 6018 int dx, int dy, 6019 PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv, 6020 bool replaces) 6021{ 6022 const BoxRec *box; 6023 char *ptr; 6024 int n; 6025 6026 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6027 6028 if (alu != GXcopy) { 6029 DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu)); 6030 return false; 6031 } 6032 6033 if (!USE_INPLACE) { 6034 DBG(("%s - no, compile time disabled\n", __FUNCTION__)); 6035 return false; 6036 } 6037 6038 if (dst_priv == src_priv) { 6039 DBG(("%s - no, dst == src\n", __FUNCTION__)); 6040 return false; 6041 } 6042 6043 if (src_priv == NULL || src_priv->gpu_bo == NULL) { 6044 if (dst_priv && dst_priv->gpu_bo) 6045 goto upload_inplace; 6046 6047 DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__)); 6048 return false; 6049 } 6050 6051 switch (src_priv->gpu_bo->tiling) { 6052 case I915_TILING_Y: 6053 DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__)); 6054 return false; 6055 case I915_TILING_X: 6056 if (!sna->kgem.memcpy_from_tiled_x) { 6057 DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__)); 6058 return false; 6059 } 6060 default: 6061 break; 6062 } 6063 6064 if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) { 6065 DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__)); 6066 return false; 6067 } 6068 6069 if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) { 6070 DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__)); 6071 return false; 6072 } 6073 6074 if (src_priv->gpu_damage == NULL || 6075 !(DAMAGE_IS_ALL(src_priv->gpu_damage) || 6076 sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage, 6077 ®ion->extents, 6078 dx, dy))) { 6079 DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__)); 6080 return false; 6081 } 6082 6083 assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_IN); 6084 assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_OUT); 6085 6086 ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo); 6087 if (ptr == NULL) { 6088 DBG(("%s - no, map failed\n", __FUNCTION__)); 6089 return false; 6090 } 6091 6092 if (dst_priv && 6093 !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6094 region, MOVE_WRITE | MOVE_INPLACE_HINT)) { 6095 DBG(("%s - no, dst sync failed\n", __FUNCTION__)); 6096 return false; 6097 } 6098 6099 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC); 6100 6101 box = region_rects(region); 6102 n = region_num_rects(region); 6103 if (src_priv->gpu_bo->tiling) { 6104 DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__)); 6105 assert(dst_pixmap->devKind); 6106 do { 6107 memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr, 6108 src_pixmap->drawable.bitsPerPixel, 6109 src_priv->gpu_bo->pitch, 6110 dst_pixmap->devKind, 6111 box->x1 + dx, box->y1 + dy, 6112 box->x1, box->y1, 6113 box->x2 - box->x1, box->y2 - box->y1); 6114 box++; 6115 } while (--n); 6116 } else { 6117 DBG(("%s: copy from a linear CPU map\n", __FUNCTION__)); 6118 assert(dst_pixmap->devKind); 6119 do { 6120 memcpy_blt(ptr, dst_pixmap->devPrivate.ptr, 6121 src_pixmap->drawable.bitsPerPixel, 6122 src_priv->gpu_bo->pitch, 6123 dst_pixmap->devKind, 6124 box->x1 + dx, box->y1 + dy, 6125 box->x1, box->y1, 6126 box->x2 - box->x1, box->y2 - box->y1); 6127 box++; 6128 } while (--n); 6129 6130 if (!src_priv->shm) { 6131 assert(ptr == MAP(src_priv->gpu_bo->map__cpu)); 6132 src_pixmap->devPrivate.ptr = ptr; 6133 src_pixmap->devKind = src_priv->gpu_bo->pitch; 6134 src_priv->mapped = MAPPED_CPU; 6135 assert_pixmap_map(src_pixmap, src_priv); 6136 src_priv->cpu = true; 6137 } 6138 } 6139 6140 return true; 6141 6142upload_inplace: 6143 switch (dst_priv->gpu_bo->tiling) { 6144 case I915_TILING_Y: 6145 DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__)); 6146 return false; 6147 case I915_TILING_X: 6148 if (!sna->kgem.memcpy_to_tiled_x) { 6149 DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__)); 6150 return false; 6151 } 6152 default: 6153 break; 6154 } 6155 6156 if (dst_priv->move_to_gpu) { 6157 DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__)); 6158 return false; 6159 } 6160 6161 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) || 6162 __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) { 6163 if (replaces && !dst_priv->pinned) { 6164 unsigned create; 6165 struct kgem_bo *bo; 6166 6167 create = CREATE_CPU_MAP | CREATE_INACTIVE; 6168 if (dst_priv->gpu_bo->scanout) 6169 create |= CREATE_SCANOUT; 6170 6171 bo = kgem_create_2d(&sna->kgem, 6172 dst_pixmap->drawable.width, 6173 dst_pixmap->drawable.height, 6174 dst_pixmap->drawable.bitsPerPixel, 6175 dst_priv->gpu_bo->tiling, 6176 create); 6177 if (bo == NULL) 6178 return false; 6179 6180 sna_pixmap_unmap(dst_pixmap, dst_priv); 6181 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 6182 dst_priv->gpu_bo = bo; 6183 } else { 6184 DBG(("%s - no, dst is busy\n", __FUNCTION__)); 6185 return false; 6186 } 6187 6188 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) { 6189 DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__)); 6190 return false; 6191 } 6192 } 6193 6194 if (src_priv && 6195 !sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6196 region, MOVE_READ)) { 6197 DBG(("%s - no, src sync failed\n", __FUNCTION__)); 6198 return false; 6199 } 6200 6201 if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) { 6202 ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo); 6203 if (ptr == NULL) { 6204 DBG(("%s - no, map failed\n", __FUNCTION__)); 6205 return false; 6206 } 6207 6208 kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo); 6209 } else { 6210 ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo); 6211 if (ptr == NULL) { 6212 DBG(("%s - no, map failed\n", __FUNCTION__)); 6213 return false; 6214 } 6215 6216 kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo); 6217 } 6218 6219 if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) { 6220 assert(!dst_priv->clear); 6221 sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap); 6222 if (sna_damage_is_all(&dst_priv->gpu_damage, 6223 dst_pixmap->drawable.width, 6224 dst_pixmap->drawable.height)) { 6225 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 6226 __FUNCTION__)); 6227 sna_damage_destroy(&dst_priv->cpu_damage); 6228 list_del(&dst_priv->flush_list); 6229 } else 6230 sna_damage_subtract(&dst_priv->cpu_damage, 6231 region); 6232 } 6233 dst_priv->clear = false; 6234 6235 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6236 6237 box = region_rects(region); 6238 n = region_num_rects(region); 6239 if (dst_priv->gpu_bo->tiling) { 6240 DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__)); 6241 assert(dst_priv->gpu_bo->tiling == I915_TILING_X); 6242 assert(src_pixmap->devKind); 6243 do { 6244 memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr, 6245 src_pixmap->drawable.bitsPerPixel, 6246 src_pixmap->devKind, 6247 dst_priv->gpu_bo->pitch, 6248 box->x1 + dx, box->y1 + dy, 6249 box->x1, box->y1, 6250 box->x2 - box->x1, box->y2 - box->y1); 6251 box++; 6252 } while (--n); 6253 } else { 6254 DBG(("%s: copy to a linear CPU map\n", __FUNCTION__)); 6255 assert(src_pixmap->devKind); 6256 do { 6257 memcpy_blt(src_pixmap->devPrivate.ptr, ptr, 6258 src_pixmap->drawable.bitsPerPixel, 6259 src_pixmap->devKind, 6260 dst_priv->gpu_bo->pitch, 6261 box->x1 + dx, box->y1 + dy, 6262 box->x1, box->y1, 6263 box->x2 - box->x1, box->y2 - box->y1); 6264 box++; 6265 } while (--n); 6266 6267 if (!dst_priv->shm) { 6268 assert(ptr == MAP(dst_priv->gpu_bo->map__cpu)); 6269 dst_pixmap->devPrivate.ptr = ptr; 6270 dst_pixmap->devKind = dst_priv->gpu_bo->pitch; 6271 dst_priv->mapped = MAPPED_CPU; 6272 assert_pixmap_map(dst_pixmap, dst_priv); 6273 dst_priv->cpu = true; 6274 } 6275 } 6276 6277 return true; 6278} 6279 6280static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv) 6281{ 6282 if (priv->cpu_damage == NULL && !priv->shm) 6283 return; 6284 6285 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 6286 6287 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 6288 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 6289 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 6290 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 6291 assert(!priv->pinned); 6292 assert(!priv->mapped); 6293 sna_damage_destroy(&priv->gpu_damage); 6294 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 6295 priv->gpu_bo = NULL; 6296 } 6297 6298 sna_damage_destroy(&priv->cpu_damage); 6299 list_del(&priv->flush_list); 6300 6301 if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu)) 6302 sna_damage_all(&priv->gpu_damage, priv->pixmap); 6303 priv->cpu = false; 6304} 6305 6306static void 6307sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6308 RegionPtr region, int dx, int dy, 6309 Pixel bitplane, void *closure) 6310{ 6311 PixmapPtr src_pixmap = get_drawable_pixmap(src); 6312 struct sna_pixmap *src_priv = sna_pixmap(src_pixmap); 6313 PixmapPtr dst_pixmap = get_drawable_pixmap(dst); 6314 struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap); 6315 struct sna *sna = to_sna_from_pixmap(src_pixmap); 6316 struct sna_damage **damage; 6317 struct kgem_bo *bo; 6318 int16_t src_dx, src_dy; 6319 int16_t dst_dx, dst_dy; 6320 const BoxRec *box = region_rects(region); 6321 int n = region_num_rects(region); 6322 int alu = gc->alu; 6323 int stride, bpp; 6324 char *bits; 6325 bool replaces; 6326 6327 assert(region_num_rects(region)); 6328 6329 if (src_pixmap == dst_pixmap) 6330 return sna_self_copy_boxes(src, dst, gc, 6331 region, dx, dy, 6332 bitplane, closure); 6333 6334 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", 6335 __FUNCTION__, n, 6336 box[0].x1, box[0].y1, box[0].x2, box[0].y2, 6337 src_pixmap->drawable.serialNumber, dx, dy, 6338 dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst), 6339 alu, 6340 src_pixmap->drawable.width, src_pixmap->drawable.height, 6341 dst_pixmap->drawable.width, dst_pixmap->drawable.height)); 6342 6343 assert_pixmap_damage(dst_pixmap); 6344 assert_pixmap_damage(src_pixmap); 6345 6346 bpp = dst_pixmap->drawable.bitsPerPixel; 6347 6348 if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy)) 6349 RegionTranslate(region, dst_dx, dst_dy); 6350 get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy); 6351 src_dx += dx - dst_dx; 6352 src_dy += dy - dst_dy; 6353 6354 assert_pixmap_contains_box(dst_pixmap, RegionExtents(region)); 6355 assert_pixmap_contains_box_with_offset(src_pixmap, 6356 RegionExtents(region), 6357 src_dx, src_dy); 6358 6359 replaces = n == 1 && 6360 alu_overwrites(alu) && 6361 box->x1 <= 0 && 6362 box->y1 <= 0 && 6363 box->x2 >= dst_pixmap->drawable.width && 6364 box->y2 >= dst_pixmap->drawable.height; 6365 6366 DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n", 6367 __FUNCTION__, 6368 dst_priv, 6369 dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0, 6370 dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0, 6371 src_priv, 6372 src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0, 6373 src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0, 6374 replaces)); 6375 6376 if (dst_priv == NULL) { 6377 DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__)); 6378 goto fallback; 6379 } 6380 6381 if (alu == GXcopy && 6382 src_priv && src_priv->cow && 6383 COW(src_priv->cow) == COW(dst_priv->cow)) { 6384 if ((dx | dy) == 0) { 6385 DBG(("%s: ignoring cow for no op\n", 6386 __FUNCTION__)); 6387 return; 6388 } else if (IS_COW_OWNER(dst_priv->cow)) { 6389 /* XXX hack for firefox -- subsequent uses of src will be corrupt! */ 6390 DBG(("%s: ignoring cow reference for cousin copy\n", 6391 __FUNCTION__)); 6392 assert(src_priv->cpu_damage == NULL); 6393 assert(dst_priv->move_to_gpu == NULL); 6394 bo = dst_priv->gpu_bo; 6395 damage = NULL; 6396 } else 6397 goto discard_cow; 6398 } else { 6399 unsigned hint; 6400discard_cow: 6401 hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy); 6402 if (replaces) { 6403 discard_cpu_damage(sna, dst_priv); 6404 hint |= REPLACES | IGNORE_DAMAGE; 6405 } else if (alu_overwrites(alu)) { 6406 if (region->data == NULL) 6407 hint |= IGNORE_DAMAGE; 6408 if (dst_priv->cpu_damage && 6409 region_subsumes_damage(region, 6410 dst_priv->cpu_damage)) 6411 discard_cpu_damage(sna, dst_priv); 6412 } 6413 bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint, 6414 ®ion->extents, &damage); 6415 } 6416 if (bo) { 6417 if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) { 6418 uint32_t color; 6419 6420 if (alu == GXset) 6421 color = (1 << dst_pixmap->drawable.depth) - 1; 6422 else if (alu == GXclear) 6423 color = 0; 6424 else 6425 color = src_priv->clear_color; 6426 DBG(("%s: applying src clear [%08x] to dst\n", 6427 __FUNCTION__, src_priv->clear_color)); 6428 6429 if (n == 1) { 6430 if (replaces && UNDO) 6431 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6432 6433 if (!sna->render.fill_one(sna, 6434 dst_pixmap, bo, color, 6435 box->x1, box->y1, 6436 box->x2, box->y2, 6437 alu)) { 6438 DBG(("%s: unsupported fill\n", 6439 __FUNCTION__)); 6440 goto fallback; 6441 } 6442 6443 if (replaces && bo == dst_priv->gpu_bo) { 6444 DBG(("%s: marking dst handle=%d as all clear [%08x]\n", 6445 __FUNCTION__, 6446 dst_priv->gpu_bo->handle, 6447 src_priv->clear_color)); 6448 dst_priv->clear = true; 6449 dst_priv->clear_color = color; 6450 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6451 sna_damage_destroy(&dst_priv->cpu_damage); 6452 list_del(&dst_priv->flush_list); 6453 return; 6454 } 6455 } else { 6456 struct sna_fill_op fill; 6457 6458 if (!sna_fill_init_blt(&fill, sna, 6459 dst_pixmap, bo, 6460 alu, color, 6461 FILL_BOXES)) { 6462 DBG(("%s: unsupported fill\n", 6463 __FUNCTION__)); 6464 goto fallback; 6465 } 6466 6467 fill.boxes(sna, &fill, box, n); 6468 fill.done(sna, &fill); 6469 } 6470 6471 if (damage) 6472 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6473 return; 6474 } 6475 6476 if (src_priv && 6477 move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) && 6478 sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 6479 DBG(("%s: move whole src_pixmap to GPU and copy\n", 6480 __FUNCTION__)); 6481 if (replaces && UNDO) 6482 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6483 6484 if (replaces && 6485 src_pixmap->drawable.width == dst_pixmap->drawable.width && 6486 src_pixmap->drawable.height == dst_pixmap->drawable.height) { 6487 assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth); 6488 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6489 if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) { 6490 assert(dst_priv->gpu_bo == src_priv->gpu_bo); 6491 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6492 sna_damage_destroy(&dst_priv->cpu_damage); 6493 list_del(&dst_priv->flush_list); 6494 if (dst_priv->shm) 6495 sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo); 6496 return; 6497 } 6498 } 6499 if (!sna->render.copy_boxes(sna, alu, 6500 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6501 &dst_pixmap->drawable, bo, 0, 0, 6502 box, n, 0)) { 6503 DBG(("%s: fallback - accelerated copy boxes failed\n", 6504 __FUNCTION__)); 6505 goto fallback; 6506 } 6507 6508 if (damage) 6509 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6510 return; 6511 } 6512 6513 if (src_priv && 6514 region_overlaps_damage(region, src_priv->gpu_damage, 6515 src_dx, src_dy)) { 6516 BoxRec area; 6517 6518 DBG(("%s: region overlaps GPU damage, upload and copy\n", 6519 __FUNCTION__)); 6520 6521 area = region->extents; 6522 area.x1 += src_dx; 6523 area.x2 += src_dx; 6524 area.y1 += src_dy; 6525 area.y2 += src_dy; 6526 6527 if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area, 6528 MOVE_READ | MOVE_ASYNC_HINT)) { 6529 DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__)); 6530 goto fallback; 6531 } 6532 6533 if (replaces && UNDO) 6534 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6535 6536 if (!sna->render.copy_boxes(sna, alu, 6537 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6538 &dst_pixmap->drawable, bo, 0, 0, 6539 box, n, 0)) { 6540 DBG(("%s: fallback - accelerated copy boxes failed\n", 6541 __FUNCTION__)); 6542 goto fallback; 6543 } 6544 6545 if (damage) 6546 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6547 return; 6548 } 6549 6550 if (bo != dst_priv->gpu_bo) 6551 goto fallback; 6552 6553 if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) { 6554 bool ret; 6555 6556 DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n", 6557 __FUNCTION__, src_priv->shm)); 6558 6559 assert(bo != dst_priv->cpu_bo); 6560 6561 RegionTranslate(region, src_dx, src_dy); 6562 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6563 region, 6564 MOVE_READ | MOVE_ASYNC_HINT); 6565 RegionTranslate(region, -src_dx, -src_dy); 6566 if (!ret) { 6567 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6568 goto fallback; 6569 } 6570 6571 if (replaces && UNDO) 6572 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6573 6574 if (src_priv->shm) { 6575 assert(!src_priv->flush); 6576 sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo); 6577 } 6578 6579 if (!sna->render.copy_boxes(sna, alu, 6580 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy, 6581 &dst_pixmap->drawable, bo, 0, 0, 6582 box, n, src_priv->shm ? COPY_LAST : 0)) { 6583 DBG(("%s: fallback - accelerated copy boxes failed\n", 6584 __FUNCTION__)); 6585 goto fallback; 6586 } 6587 6588 if (damage) 6589 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6590 return; 6591 } 6592 6593 if (src_priv) { 6594 bool ret; 6595 6596 RegionTranslate(region, src_dx, src_dy); 6597 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6598 region, MOVE_READ); 6599 RegionTranslate(region, -src_dx, -src_dy); 6600 if (!ret) { 6601 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6602 goto fallback; 6603 } 6604 6605 assert(!src_priv->mapped); 6606 if (src_pixmap->devPrivate.ptr == NULL) 6607 /* uninitialised!*/ 6608 return; 6609 } 6610 6611 if (USE_USERPTR_UPLOADS && 6612 sna->kgem.has_userptr && 6613 (alu != GXcopy || 6614 (box_inplace(src_pixmap, ®ion->extents) && 6615 __kgem_bo_is_busy(&sna->kgem, bo)))) { 6616 struct kgem_bo *src_bo; 6617 bool ok = false; 6618 6619 DBG(("%s: upload through a temporary map\n", 6620 __FUNCTION__)); 6621 6622 assert(src_pixmap->devKind); 6623 src_bo = kgem_create_map(&sna->kgem, 6624 src_pixmap->devPrivate.ptr, 6625 src_pixmap->devKind * src_pixmap->drawable.height, 6626 true); 6627 if (src_bo) { 6628 src_bo->pitch = src_pixmap->devKind; 6629 kgem_bo_mark_unreusable(src_bo); 6630 6631 ok = sna->render.copy_boxes(sna, alu, 6632 &src_pixmap->drawable, src_bo, src_dx, src_dy, 6633 &dst_pixmap->drawable, bo, 0, 0, 6634 box, n, COPY_LAST); 6635 6636 kgem_bo_sync__cpu(&sna->kgem, src_bo); 6637 assert(src_bo->rq == NULL); 6638 kgem_bo_destroy(&sna->kgem, src_bo); 6639 } 6640 6641 if (ok) { 6642 if (damage) 6643 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6644 return; 6645 } 6646 } 6647 6648 if (alu != GXcopy) { 6649 PixmapPtr tmp; 6650 struct kgem_bo *src_bo; 6651 int i; 6652 6653 assert(src_pixmap->drawable.depth != 1); 6654 6655 DBG(("%s: creating temporary source upload for non-copy alu [%d]\n", 6656 __FUNCTION__, alu)); 6657 6658 tmp = sna_pixmap_create_upload(src->pScreen, 6659 region->extents.x2 - region->extents.x1, 6660 region->extents.y2 - region->extents.y1, 6661 src->depth, 6662 KGEM_BUFFER_WRITE_INPLACE); 6663 if (tmp == NullPixmap) 6664 return; 6665 6666 src_bo = __sna_pixmap_get_bo(tmp); 6667 assert(src_bo != NULL); 6668 6669 dx = -region->extents.x1; 6670 dy = -region->extents.y1; 6671 for (i = 0; i < n; i++) { 6672 assert(box[i].x1 + src_dx >= 0); 6673 assert(box[i].y1 + src_dy >= 0); 6674 assert(box[i].x2 + src_dx <= src_pixmap->drawable.width); 6675 assert(box[i].y2 + src_dy <= src_pixmap->drawable.height); 6676 6677 assert(box[i].x1 + dx >= 0); 6678 assert(box[i].y1 + dy >= 0); 6679 assert(box[i].x2 + dx <= tmp->drawable.width); 6680 assert(box[i].y2 + dy <= tmp->drawable.height); 6681 6682 assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ)); 6683 assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE)); 6684 assert(src_pixmap->devKind); 6685 assert(tmp->devKind); 6686 memcpy_blt(src_pixmap->devPrivate.ptr, 6687 tmp->devPrivate.ptr, 6688 src_pixmap->drawable.bitsPerPixel, 6689 src_pixmap->devKind, 6690 tmp->devKind, 6691 box[i].x1 + src_dx, 6692 box[i].y1 + src_dy, 6693 box[i].x1 + dx, 6694 box[i].y1 + dy, 6695 box[i].x2 - box[i].x1, 6696 box[i].y2 - box[i].y1); 6697 } 6698 6699 if (n == 1 && 6700 tmp->drawable.width == src_pixmap->drawable.width && 6701 tmp->drawable.height == src_pixmap->drawable.height) { 6702 DBG(("%s: caching upload for src bo\n", 6703 __FUNCTION__)); 6704 assert(src_priv->gpu_damage == NULL); 6705 assert(src_priv->gpu_bo == NULL); 6706 kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo); 6707 } 6708 6709 if (!sna->render.copy_boxes(sna, alu, 6710 &tmp->drawable, src_bo, dx, dy, 6711 &dst_pixmap->drawable, bo, 0, 0, 6712 box, n, 0)) { 6713 DBG(("%s: fallback - accelerated copy boxes failed\n", 6714 __FUNCTION__)); 6715 tmp->drawable.pScreen->DestroyPixmap(tmp); 6716 goto fallback; 6717 } 6718 tmp->drawable.pScreen->DestroyPixmap(tmp); 6719 6720 if (damage) 6721 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6722 return; 6723 } else { 6724 DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n", 6725 __FUNCTION__)); 6726 6727 assert(src_pixmap->devKind); 6728 if (!dst_priv->pinned && replaces) { 6729 stride = src_pixmap->devKind; 6730 bits = src_pixmap->devPrivate.ptr; 6731 bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8; 6732 6733 if (!sna_replace(sna, dst_pixmap, bits, stride)) { 6734 DBG(("%s: replace failed, fallback\n", __FUNCTION__)); 6735 goto fallback; 6736 } 6737 } else { 6738 assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage)); 6739 if (!sna_write_boxes(sna, dst_pixmap, 6740 dst_priv->gpu_bo, 0, 0, 6741 src_pixmap->devPrivate.ptr, 6742 src_pixmap->devKind, 6743 src_dx, src_dy, 6744 box, n)) { 6745 DBG(("%s: write failed, fallback\n", __FUNCTION__)); 6746 goto fallback; 6747 } 6748 } 6749 6750 assert(dst_priv->clear == false); 6751 dst_priv->cpu = false; 6752 if (damage) { 6753 assert(!dst_priv->clear); 6754 assert(dst_priv->gpu_bo); 6755 assert(dst_priv->gpu_bo->proxy == NULL); 6756 assert(*damage == dst_priv->gpu_damage); 6757 if (replaces) { 6758 sna_damage_destroy(&dst_priv->cpu_damage); 6759 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6760 list_del(&dst_priv->flush_list); 6761 } else 6762 sna_damage_add(&dst_priv->gpu_damage, 6763 region); 6764 assert_pixmap_damage(dst_pixmap); 6765 } 6766 } 6767 6768 return; 6769 } 6770 6771fallback: 6772 if (alu == GXcopy && src_priv && src_priv->clear) { 6773 DBG(("%s: copying clear [%08x]\n", 6774 __FUNCTION__, src_priv->clear_color)); 6775 6776 if (dst_priv) { 6777 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6778 region, 6779 MOVE_WRITE | MOVE_INPLACE_HINT)) 6780 return; 6781 } 6782 6783 assert(dst_pixmap->devPrivate.ptr); 6784 assert(dst_pixmap->devKind); 6785 do { 6786 pixman_fill(dst_pixmap->devPrivate.ptr, 6787 dst_pixmap->devKind/sizeof(uint32_t), 6788 dst_pixmap->drawable.bitsPerPixel, 6789 box->x1, box->y1, 6790 box->x2 - box->x1, 6791 box->y2 - box->y1, 6792 src_priv->clear_color); 6793 box++; 6794 } while (--n); 6795 } else if (!sna_copy_boxes__inplace(sna, region, alu, 6796 src_pixmap, src_priv, 6797 src_dx, src_dy, 6798 dst_pixmap, dst_priv, 6799 replaces)) { 6800 FbBits *dst_bits, *src_bits; 6801 int dst_stride, src_stride; 6802 6803 DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", 6804 __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); 6805 if (src_priv) { 6806 unsigned mode; 6807 6808 RegionTranslate(region, src_dx, src_dy); 6809 6810 assert_pixmap_contains_box(src_pixmap, 6811 RegionExtents(region)); 6812 6813 mode = MOVE_READ; 6814 if (!sna->kgem.can_blt_cpu || 6815 (src_priv->cpu_bo == NULL && 6816 (src_priv->create & KGEM_CAN_CREATE_CPU) == 0)) 6817 mode |= MOVE_INPLACE_HINT; 6818 6819 if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6820 region, mode)) 6821 return; 6822 6823 RegionTranslate(region, -src_dx, -src_dy); 6824 } 6825 assert(src_priv == sna_pixmap(src_pixmap)); 6826 6827 if (dst_priv) { 6828 unsigned mode; 6829 6830 if (alu_overwrites(alu)) 6831 mode = MOVE_WRITE | MOVE_INPLACE_HINT; 6832 else 6833 mode = MOVE_WRITE | MOVE_READ; 6834 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6835 region, mode)) 6836 return; 6837 } 6838 assert(dst_priv == sna_pixmap(dst_pixmap)); 6839 6840 assert(dst_pixmap->devKind); 6841 assert(src_pixmap->devKind); 6842 dst_stride = dst_pixmap->devKind; 6843 src_stride = src_pixmap->devKind; 6844 6845 if (alu == GXcopy && bpp >= 8) { 6846 dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr; 6847 src_bits = (FbBits *) 6848 ((char *)src_pixmap->devPrivate.ptr + 6849 src_dy * src_stride + src_dx * bpp / 8); 6850 6851 do { 6852 DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", 6853 __FUNCTION__, 6854 box->x1, box->y1, 6855 box->x2 - box->x1, 6856 box->y2 - box->y1, 6857 src_dx, src_dy, 6858 src_stride, dst_stride)); 6859 6860 assert(box->x1 >= 0); 6861 assert(box->y1 >= 0); 6862 assert(box->x2 <= dst_pixmap->drawable.width); 6863 assert(box->y2 <= dst_pixmap->drawable.height); 6864 6865 assert(box->x1 + src_dx >= 0); 6866 assert(box->y1 + src_dy >= 0); 6867 assert(box->x2 + src_dx <= src_pixmap->drawable.width); 6868 assert(box->y2 + src_dy <= src_pixmap->drawable.height); 6869 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6870 assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); 6871 assert(src_stride); 6872 assert(dst_stride); 6873 memcpy_blt(src_bits, dst_bits, bpp, 6874 src_stride, dst_stride, 6875 box->x1, box->y1, 6876 box->x1, box->y1, 6877 box->x2 - box->x1, 6878 box->y2 - box->y1); 6879 box++; 6880 } while (--n); 6881 } else { 6882 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); 6883 6884 RegionTranslate(region, -dst_dx, -dst_dy); 6885 6886 if (sna_gc_move_to_cpu(gc, dst, region) && 6887 sigtrap_get() == 0) { 6888 miCopyRegion(src, dst, gc, 6889 region, dx, dy, 6890 fbCopyNtoN, 0, NULL); 6891 sigtrap_put(); 6892 } 6893 6894 sna_gc_move_to_gpu(gc); 6895 } 6896 } 6897} 6898 6899typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6900 RegionPtr region, int dx, int dy, 6901 Pixel bitPlane, void *closure); 6902 6903static inline bool box_equal(const BoxRec *a, const BoxRec *b) 6904{ 6905 return *(const uint64_t *)a == *(const uint64_t *)b; 6906} 6907 6908static inline bool has_clip(GCPtr gc) 6909{ 6910#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 6911 return gc->clientClipType != CT_NONE; 6912#else 6913 return gc->clientClip != NULL; 6914#endif 6915} 6916 6917static RegionPtr 6918sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6919 int sx, int sy, 6920 int width, int height, 6921 int dx, int dy, 6922 sna_copy_func copy, Pixel bitPlane, void *closure) 6923{ 6924 RegionPtr clip; 6925 RegionRec region; 6926 BoxRec src_extents; 6927 bool expose; 6928 6929 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 6930 __FUNCTION__, sx, sy, dx, dy, width, height)); 6931 6932 /* Short cut for unmapped windows */ 6933 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) { 6934 DBG(("%s: unmapped\n", __FUNCTION__)); 6935 return NULL; 6936 } 6937 6938 SourceValidate(src, sx, sy, width, height, gc->subWindowMode); 6939 6940 sx += src->x; 6941 sy += src->y; 6942 6943 dx += dst->x; 6944 dy += dst->y; 6945 6946 DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 6947 __FUNCTION__, sx, sy, dx, dy, width, height)); 6948 6949 region.extents.x1 = dx; 6950 region.extents.y1 = dy; 6951 region.extents.x2 = bound(dx, width); 6952 region.extents.y2 = bound(dy, height); 6953 region.data = NULL; 6954 6955 DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__, 6956 region.extents.x1, region.extents.y1, 6957 region.extents.x2, region.extents.y2, 6958 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 6959 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2, 6960 dst->width, dst->height)); 6961 6962 if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) { 6963 DBG(("%s: dst clipped out\n", __FUNCTION__)); 6964 return NULL; 6965 } 6966 6967 DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6968 region.extents.x1, region.extents.y1, 6969 region.extents.x2, region.extents.y2)); 6970 assert_drawable_contains_box(dst, ®ion.extents); 6971 6972 region.extents.x1 = clamp(region.extents.x1, sx - dx); 6973 region.extents.x2 = clamp(region.extents.x2, sx - dx); 6974 region.extents.y1 = clamp(region.extents.y1, sy - dy); 6975 region.extents.y2 = clamp(region.extents.y2, sy - dy); 6976 6977 src_extents = region.extents; 6978 expose = true; 6979 6980 DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6981 region.extents.x1, region.extents.y1, 6982 region.extents.x2, region.extents.y2)); 6983 6984 if (region.extents.x1 < src->x) 6985 region.extents.x1 = src->x; 6986 if (region.extents.y1 < src->y) 6987 region.extents.y1 = src->y; 6988 if (region.extents.x2 > src->x + (int) src->width) 6989 region.extents.x2 = src->x + (int) src->width; 6990 if (region.extents.y2 > src->y + (int) src->height) 6991 region.extents.y2 = src->y + (int) src->height; 6992 6993 DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6994 region.extents.x1, region.extents.y1, 6995 region.extents.x2, region.extents.y2)); 6996 if (box_empty(®ion.extents)) { 6997 DBG(("%s: src clipped out\n", __FUNCTION__)); 6998 return NULL; 6999 } 7000 7001 /* Compute source clip region */ 7002 if (src->type == DRAWABLE_PIXMAP) { 7003 if (src == dst && !has_clip(gc)) { 7004 DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__)); 7005 clip = gc->pCompositeClip; 7006 } else { 7007 DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__)); 7008 expose = false; 7009 clip = NULL; 7010 } 7011 } else { 7012 WindowPtr w = (WindowPtr)src; 7013 if (gc->subWindowMode == IncludeInferiors) { 7014 DBG(("%s: window -- include inferiors\n", __FUNCTION__)); 7015 7016 if (w->winSize.data) 7017 RegionIntersect(®ion, ®ion, &w->winSize); 7018 else 7019 box_intersect(®ion.extents, &w->winSize.extents); 7020 clip = &w->borderClip; 7021 } else { 7022 DBG(("%s: window -- clip by children\n", __FUNCTION__)); 7023 clip = &w->clipList; 7024 } 7025 } 7026 if (clip != NULL) { 7027 if (clip->data == NULL) { 7028 box_intersect(®ion.extents, &clip->extents); 7029 if (box_equal(&src_extents, ®ion.extents)) 7030 expose = false; 7031 } else 7032 RegionIntersect(®ion, ®ion, clip); 7033 } 7034 DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__, 7035 region.extents.x1, region.extents.y1, 7036 region.extents.x2, region.extents.y2, 7037 region_num_rects(®ion))); 7038 7039 RegionTranslate(®ion, dx-sx, dy-sy); 7040 if (gc->pCompositeClip->data) 7041 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 7042 DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n", 7043 __FUNCTION__, 7044 region.extents.x1, region.extents.y1, 7045 region.extents.x2, region.extents.y2, 7046 region_num_rects(®ion), 7047 sx-dx, sy-dy)); 7048 7049 if (!box_empty(®ion.extents)) 7050 copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure); 7051 assert(gc->pCompositeClip != ®ion); 7052 RegionUninit(®ion); 7053 7054 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 7055 clip = NULL; 7056 if (expose && gc->fExpose) 7057 clip = miHandleExposures(src, dst, gc, 7058 sx - src->x, sy - src->y, 7059 width, height, 7060 dx - dst->x, dy - dst->y, 7061 (unsigned long) bitPlane); 7062 return clip; 7063} 7064 7065static void 7066sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7067 RegionPtr region, int dx, int dy, 7068 Pixel bitplane, void *closure) 7069{ 7070 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n", 7071 __FUNCTION__, region_num_rects(region), 7072 region->extents.x1, region->extents.y1, 7073 region->extents.x2, region->extents.y2, 7074 dx, dy, gc->alu)); 7075 7076 if (!sna_gc_move_to_cpu(gc, dst, region)) 7077 goto out; 7078 7079 RegionTranslate(region, dx, dy); 7080 if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ)) 7081 goto out; 7082 RegionTranslate(region, -dx, -dy); 7083 7084 if (src == dst || 7085 get_drawable_pixmap(src) == get_drawable_pixmap(dst)) { 7086 DBG(("%s: self-copy\n", __FUNCTION__)); 7087 if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ)) 7088 goto out; 7089 } else { 7090 if (!sna_drawable_move_region_to_cpu(dst, region, 7091 drawable_gc_flags(dst, gc, false))) 7092 goto out; 7093 } 7094 7095 if (sigtrap_get() == 0) { 7096 miCopyRegion(src, dst, gc, 7097 region, dx, dy, 7098 fbCopyNtoN, 0, NULL); 7099 FALLBACK_FLUSH(dst); 7100 sigtrap_put(); 7101 } 7102out: 7103 sna_gc_move_to_gpu(gc); 7104} 7105 7106static RegionPtr 7107sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7108 int src_x, int src_y, 7109 int width, int height, 7110 int dst_x, int dst_y) 7111{ 7112 struct sna *sna = to_sna_from_drawable(dst); 7113 sna_copy_func copy; 7114 7115 if (gc->planemask == 0) 7116 return NULL; 7117 7118 DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n", 7119 __FUNCTION__, 7120 src_x, src_y, width, height, src->x, src->y, 7121 dst_x, dst_y, dst->x, dst->y, 7122 gc->alu, gc->planemask, gc->depth)); 7123 7124 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) || 7125 !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) 7126 copy = sna_fallback_copy_boxes; 7127 else if (src == dst) 7128 copy = sna_self_copy_boxes; 7129 else 7130 copy = sna_copy_boxes; 7131 7132 return sna_do_copy(src, dst, gc, 7133 src_x, src_y, 7134 width, height, 7135 dst_x, dst_y, 7136 copy, 0, NULL); 7137} 7138 7139static const BoxRec * 7140find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) 7141{ 7142 const BoxRec *mid; 7143 7144 if (end == begin) 7145 return end; 7146 7147 if (end - begin == 1) { 7148 if (begin->y2 > y) 7149 return begin; 7150 else 7151 return end; 7152 } 7153 7154 mid = begin + (end - begin) / 2; 7155 if (mid->y2 > y) 7156 /* If no box is found in [begin, mid], the function 7157 * will return @mid, which is then known to be the 7158 * correct answer. 7159 */ 7160 return find_clip_box_for_y(begin, mid, y); 7161 else 7162 return find_clip_box_for_y(mid, end, y); 7163} 7164 7165struct sna_fill_spans { 7166 struct sna *sna; 7167 PixmapPtr pixmap; 7168 RegionRec region; 7169 unsigned flags; 7170 uint32_t phase; 7171 struct kgem_bo *bo; 7172 struct sna_damage **damage; 7173 int16_t dx, dy; 7174 void *op; 7175}; 7176 7177static void 7178sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc, 7179 int mode, int n, DDXPointPtr pt) 7180{ 7181 fbPolyPoint(drawable, gc, mode, n, pt, -1); 7182} 7183 7184static void 7185sna_poly_point__fill(DrawablePtr drawable, GCPtr gc, 7186 int mode, int n, DDXPointPtr pt) 7187{ 7188 struct sna_fill_spans *data = sna_gc(gc)->priv; 7189 struct sna_fill_op *op = data->op; 7190 BoxRec box[512]; 7191 DDXPointRec last; 7192 7193 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7194 if (n == 0) 7195 return; 7196 7197 last.x = drawable->x + data->dx; 7198 last.y = drawable->y + data->dy; 7199 if (op->points && mode != CoordModePrevious) { 7200 op->points(data->sna, op, last.x, last.y, pt, n); 7201 } else do { 7202 BoxRec *b = box; 7203 unsigned nbox = n; 7204 if (nbox > ARRAY_SIZE(box)) 7205 nbox = ARRAY_SIZE(box); 7206 n -= nbox; 7207 do { 7208 *(DDXPointRec *)b = *pt++; 7209 7210 b->x1 += last.x; 7211 b->y1 += last.y; 7212 if (mode == CoordModePrevious) 7213 last = *(DDXPointRec *)b; 7214 7215 b->x2 = b->x1 + 1; 7216 b->y2 = b->y1 + 1; 7217 b++; 7218 } while (--nbox); 7219 op->boxes(data->sna, op, box, b - box); 7220 } while (n); 7221} 7222 7223static void 7224sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc, 7225 int mode, int n, DDXPointPtr pt) 7226{ 7227 struct sna_fill_spans *data = sna_gc(gc)->priv; 7228 struct sna_fill_op fill; 7229 BoxRec box[512]; 7230 DDXPointRec last; 7231 7232 if (!sna_fill_init_blt(&fill, 7233 data->sna, data->pixmap, 7234 data->bo, gc->alu, gc->fgPixel, 7235 FILL_POINTS)) 7236 return; 7237 7238 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7239 7240 last.x = drawable->x; 7241 last.y = drawable->y; 7242 while (n) { 7243 BoxRec *b = box; 7244 unsigned nbox = n; 7245 if (nbox > ARRAY_SIZE(box)) 7246 nbox = ARRAY_SIZE(box); 7247 n -= nbox; 7248 do { 7249 *(DDXPointRec *)b = *pt++; 7250 7251 b->x1 += last.x; 7252 b->y1 += last.y; 7253 if (mode == CoordModePrevious) 7254 last = *(DDXPointRec *)b; 7255 7256 if (RegionContainsPoint(&data->region, 7257 b->x1, b->y1, NULL)) { 7258 b->x1 += data->dx; 7259 b->y1 += data->dy; 7260 b->x2 = b->x1 + 1; 7261 b->y2 = b->y1 + 1; 7262 b++; 7263 } 7264 } while (--nbox); 7265 if (b != box) 7266 fill.boxes(data->sna, &fill, box, b - box); 7267 } 7268 fill.done(data->sna, &fill); 7269} 7270 7271static void 7272sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc, 7273 int mode, int n, DDXPointPtr pt) 7274{ 7275 struct sna_fill_spans *data = sna_gc(gc)->priv; 7276 struct sna_fill_op *op = data->op; 7277 const BoxRec *extents = &data->region.extents; 7278 BoxRec box[512], *b = box; 7279 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7280 DDXPointRec last; 7281 7282 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7283 7284 last.x = drawable->x + data->dx; 7285 last.y = drawable->y + data->dy; 7286 while (n--) { 7287 *(DDXPointRec *)b = *pt++; 7288 7289 b->x1 += last.x; 7290 b->y1 += last.y; 7291 if (mode == CoordModePrevious) 7292 last = *(DDXPointRec *)b; 7293 7294 if (b->x1 >= extents->x1 && b->x1 < extents->x2 && 7295 b->y1 >= extents->y1 && b->y1 < extents->y2) { 7296 b->x2 = b->x1 + 1; 7297 b->y2 = b->y1 + 1; 7298 if (++b == last_box) { 7299 op->boxes(data->sna, op, box, last_box - box); 7300 b = box; 7301 } 7302 } 7303 } 7304 if (b != box) 7305 op->boxes(data->sna, op, box, b - box); 7306} 7307 7308static void 7309sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc, 7310 int mode, int n, DDXPointPtr pt) 7311{ 7312 struct sna_fill_spans *data = sna_gc(gc)->priv; 7313 struct sna_fill_op *op = data->op; 7314 RegionRec *clip = &data->region; 7315 BoxRec box[512], *b = box; 7316 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7317 DDXPointRec last; 7318 7319 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7320 7321 last.x = drawable->x + data->dx; 7322 last.y = drawable->y + data->dy; 7323 while (n--) { 7324 *(DDXPointRec *)b = *pt++; 7325 7326 b->x1 += last.x; 7327 b->y1 += last.y; 7328 if (mode == CoordModePrevious) 7329 last = *(DDXPointRec *)b; 7330 7331 if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) { 7332 b->x2 = b->x1 + 1; 7333 b->y2 = b->y1 + 1; 7334 if (++b == last_box) { 7335 op->boxes(data->sna, op, box, last_box - box); 7336 b = box; 7337 } 7338 } 7339 } 7340 if (b != box) 7341 op->boxes(data->sna, op, box, b - box); 7342} 7343 7344static void 7345sna_poly_point__dash(DrawablePtr drawable, GCPtr gc, 7346 int mode, int n, DDXPointPtr pt) 7347{ 7348 struct sna_fill_spans *data = sna_gc(gc)->priv; 7349 if (data->phase == gc->fgPixel) 7350 sna_poly_point__fill(drawable, gc, mode, n, pt); 7351} 7352 7353static void 7354sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc, 7355 int mode, int n, DDXPointPtr pt) 7356{ 7357 struct sna_fill_spans *data = sna_gc(gc)->priv; 7358 if (data->phase == gc->fgPixel) 7359 sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt); 7360} 7361 7362static void 7363sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc, 7364 int mode, int n, DDXPointPtr pt) 7365{ 7366 struct sna_fill_spans *data = sna_gc(gc)->priv; 7367 if (data->phase == gc->fgPixel) 7368 sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt); 7369} 7370 7371static void 7372sna_fill_spans__fill(DrawablePtr drawable, 7373 GCPtr gc, int n, 7374 DDXPointPtr pt, int *width, int sorted) 7375{ 7376 struct sna_fill_spans *data = sna_gc(gc)->priv; 7377 struct sna_fill_op *op = data->op; 7378 BoxRec box[512]; 7379 7380 DBG(("%s: alu=%d, fg=%08lx, count=%d\n", 7381 __FUNCTION__, gc->alu, gc->fgPixel, n)); 7382 7383 while (n) { 7384 BoxRec *b = box; 7385 int nbox = n; 7386 if (nbox > ARRAY_SIZE(box)) 7387 nbox = ARRAY_SIZE(box); 7388 n -= nbox; 7389 do { 7390 *(DDXPointRec *)b = *pt++; 7391 b->x2 = b->x1 + (int)*width++; 7392 b->y2 = b->y1 + 1; 7393 DBG(("%s: (%d, %d), (%d, %d)\n", 7394 __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); 7395 assert(b->x1 >= drawable->x); 7396 assert(b->x2 <= drawable->x + drawable->width); 7397 assert(b->y1 >= drawable->y); 7398 assert(b->y2 <= drawable->y + drawable->height); 7399 if (b->x2 > b->x1) { 7400 if (b != box && 7401 b->y1 == b[-1].y2 && 7402 b->x1 == b[-1].x1 && 7403 b->x2 == b[-1].x2) 7404 b[-1].y2 = b->y2; 7405 else 7406 b++; 7407 } 7408 } while (--nbox); 7409 if (b != box) 7410 op->boxes(data->sna, op, box, b - box); 7411 } 7412} 7413 7414static void 7415sna_fill_spans__dash(DrawablePtr drawable, 7416 GCPtr gc, int n, 7417 DDXPointPtr pt, int *width, int sorted) 7418{ 7419 struct sna_fill_spans *data = sna_gc(gc)->priv; 7420 if (data->phase == gc->fgPixel) 7421 sna_fill_spans__fill(drawable, gc, n, pt, width, sorted); 7422} 7423 7424static void 7425sna_fill_spans__fill_offset(DrawablePtr drawable, 7426 GCPtr gc, int n, 7427 DDXPointPtr pt, int *width, int sorted) 7428{ 7429 struct sna_fill_spans *data = sna_gc(gc)->priv; 7430 struct sna_fill_op *op = data->op; 7431 BoxRec box[512]; 7432 7433 DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); 7434 7435 while (n) { 7436 BoxRec *b = box; 7437 int nbox = n; 7438 if (nbox > ARRAY_SIZE(box)) 7439 nbox = ARRAY_SIZE(box); 7440 n -= nbox; 7441 do { 7442 *(DDXPointRec *)b = *pt++; 7443 b->x1 += data->dx; 7444 b->y1 += data->dy; 7445 b->x2 = b->x1 + (int)*width++; 7446 b->y2 = b->y1 + 1; 7447 if (b->x2 > b->x1) 7448 b++; 7449 } while (--nbox); 7450 if (b != box) 7451 op->boxes(data->sna, op, box, b - box); 7452 } 7453} 7454 7455static void 7456sna_fill_spans__dash_offset(DrawablePtr drawable, 7457 GCPtr gc, int n, 7458 DDXPointPtr pt, int *width, int sorted) 7459{ 7460 struct sna_fill_spans *data = sna_gc(gc)->priv; 7461 if (data->phase == gc->fgPixel) 7462 sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted); 7463} 7464 7465static void 7466sna_fill_spans__fill_clip_extents(DrawablePtr drawable, 7467 GCPtr gc, int n, 7468 DDXPointPtr pt, int *width, int sorted) 7469{ 7470 struct sna_fill_spans *data = sna_gc(gc)->priv; 7471 struct sna_fill_op *op = data->op; 7472 const BoxRec *extents = &data->region.extents; 7473 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7474 7475 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7476 __FUNCTION__, gc->alu, gc->fgPixel, n, 7477 extents->x1, extents->y1, 7478 extents->x2, extents->y2)); 7479 7480 while (n--) { 7481 DBG(("%s: [%d] pt=(%d, %d), width=%d\n", 7482 __FUNCTION__, n, pt->x, pt->y, *width)); 7483 *(DDXPointRec *)b = *pt++; 7484 b->x2 = b->x1 + (int)*width++; 7485 b->y2 = b->y1 + 1; 7486 if (box_intersect(b, extents)) { 7487 DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n", 7488 __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2)); 7489 if (data->dx|data->dy) { 7490 b->x1 += data->dx; b->x2 += data->dx; 7491 b->y1 += data->dy; b->y2 += data->dy; 7492 } 7493 if (b != box && 7494 b->y1 == b[-1].y2 && 7495 b->x1 == b[-1].x1 && 7496 b->x2 == b[-1].x2) { 7497 b[-1].y2 = b->y2; 7498 } else if (++b == last_box) { 7499 op->boxes(data->sna, op, box, last_box - box); 7500 b = box; 7501 } 7502 } 7503 } 7504 if (b != box) 7505 op->boxes(data->sna, op, box, b - box); 7506} 7507 7508static void 7509sna_fill_spans__dash_clip_extents(DrawablePtr drawable, 7510 GCPtr gc, int n, 7511 DDXPointPtr pt, int *width, int sorted) 7512{ 7513 struct sna_fill_spans *data = sna_gc(gc)->priv; 7514 if (data->phase == gc->fgPixel) 7515 sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted); 7516} 7517 7518static void 7519sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, 7520 GCPtr gc, int n, 7521 DDXPointPtr pt, int *width, int sorted) 7522{ 7523 struct sna_fill_spans *data = sna_gc(gc)->priv; 7524 struct sna_fill_op *op = data->op; 7525 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7526 const BoxRec * const clip_start = RegionBoxptr(&data->region); 7527 const BoxRec * const clip_end = clip_start + data->region.data->numRects; 7528 7529 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7530 __FUNCTION__, gc->alu, gc->fgPixel, n, 7531 data->region.extents.x1, data->region.extents.y1, 7532 data->region.extents.x2, data->region.extents.y2)); 7533 7534 while (n--) { 7535 int16_t X1 = pt->x; 7536 int16_t y = pt->y; 7537 int16_t X2 = X1 + (int)*width; 7538 const BoxRec *c; 7539 7540 pt++; 7541 width++; 7542 7543 if (y < data->region.extents.y1 || data->region.extents.y2 <= y) 7544 continue; 7545 7546 if (X1 < data->region.extents.x1) 7547 X1 = data->region.extents.x1; 7548 7549 if (X2 > data->region.extents.x2) 7550 X2 = data->region.extents.x2; 7551 7552 if (X1 >= X2) 7553 continue; 7554 7555 c = find_clip_box_for_y(clip_start, clip_end, y); 7556 while (c != clip_end) { 7557 if (y + 1 <= c->y1 || X2 <= c->x1) 7558 break; 7559 7560 if (X1 >= c->x2) { 7561 c++; 7562 continue; 7563 } 7564 7565 b->x1 = c->x1; 7566 b->x2 = c->x2; 7567 c++; 7568 7569 if (b->x1 < X1) 7570 b->x1 = X1; 7571 if (b->x2 > X2) 7572 b->x2 = X2; 7573 if (b->x2 <= b->x1) 7574 continue; 7575 7576 b->x1 += data->dx; 7577 b->x2 += data->dx; 7578 b->y1 = y + data->dy; 7579 b->y2 = b->y1 + 1; 7580 if (++b == last_box) { 7581 op->boxes(data->sna, op, box, last_box - box); 7582 b = box; 7583 } 7584 } 7585 } 7586 if (b != box) 7587 op->boxes(data->sna, op, box, b - box); 7588} 7589 7590static void 7591sna_fill_spans__dash_clip_boxes(DrawablePtr drawable, 7592 GCPtr gc, int n, 7593 DDXPointPtr pt, int *width, int sorted) 7594{ 7595 struct sna_fill_spans *data = sna_gc(gc)->priv; 7596 if (data->phase == gc->fgPixel) 7597 sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted); 7598} 7599 7600static bool 7601sna_fill_spans_blt(DrawablePtr drawable, 7602 struct kgem_bo *bo, struct sna_damage **damage, 7603 GCPtr gc, uint32_t pixel, 7604 int n, DDXPointPtr pt, int *width, int sorted, 7605 const BoxRec *extents, unsigned clipped) 7606{ 7607 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7608 struct sna *sna = to_sna_from_pixmap(pixmap); 7609 int16_t dx, dy; 7610 struct sna_fill_op fill; 7611 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7612 static void * const jump[] = { 7613 &&no_damage, 7614 &&damage, 7615 &&no_damage_clipped, 7616 &&damage_clipped, 7617 }; 7618 unsigned v; 7619 7620 DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n", 7621 __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped)); 7622 7623 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 7624 return false; 7625 7626 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7627 7628 v = (damage != NULL) | clipped; 7629 goto *jump[v]; 7630 7631no_damage: 7632 if (dx|dy) { 7633 do { 7634 int nbox = n; 7635 if (nbox > last_box - box) 7636 nbox = last_box - box; 7637 n -= nbox; 7638 do { 7639 *(DDXPointRec *)b = *pt++; 7640 b->x1 += dx; 7641 b->y1 += dy; 7642 b->x2 = b->x1 + (int)*width++; 7643 b->y2 = b->y1 + 1; 7644 b++; 7645 } while (--nbox); 7646 fill.boxes(sna, &fill, box, b - box); 7647 b = box; 7648 } while (n); 7649 } else { 7650 do { 7651 int nbox = n; 7652 if (nbox > last_box - box) 7653 nbox = last_box - box; 7654 n -= nbox; 7655 do { 7656 *(DDXPointRec *)b = *pt++; 7657 b->x2 = b->x1 + (int)*width++; 7658 b->y2 = b->y1 + 1; 7659 b++; 7660 } while (--nbox); 7661 fill.boxes(sna, &fill, box, b - box); 7662 b = box; 7663 } while (n); 7664 } 7665 goto done; 7666 7667damage: 7668 do { 7669 *(DDXPointRec *)b = *pt++; 7670 b->x1 += dx; 7671 b->y1 += dy; 7672 b->x2 = b->x1 + (int)*width++; 7673 b->y2 = b->y1 + 1; 7674 7675 if (++b == last_box) { 7676 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7677 fill.boxes(sna, &fill, box, last_box - box); 7678 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7679 b = box; 7680 } 7681 } while (--n); 7682 if (b != box) { 7683 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7684 fill.boxes(sna, &fill, box, b - box); 7685 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7686 } 7687 goto done; 7688 7689no_damage_clipped: 7690 { 7691 RegionRec clip; 7692 7693 region_set(&clip, extents); 7694 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7695 return true; 7696 7697 assert(dx + clip.extents.x1 >= 0); 7698 assert(dy + clip.extents.y1 >= 0); 7699 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7700 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7701 7702 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7703 __FUNCTION__, 7704 region_num_rects(&clip), 7705 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7706 n, pt->x, pt->y)); 7707 7708 if (clip.data == NULL) { 7709 do { 7710 *(DDXPointRec *)b = *pt++; 7711 b->x2 = b->x1 + (int)*width++; 7712 b->y2 = b->y1 + 1; 7713 7714 if (box_intersect(b, &clip.extents)) { 7715 if (dx|dy) { 7716 b->x1 += dx; b->x2 += dx; 7717 b->y1 += dy; b->y2 += dy; 7718 } 7719 if (++b == last_box) { 7720 fill.boxes(sna, &fill, box, last_box - box); 7721 b = box; 7722 } 7723 } 7724 } while (--n); 7725 } else { 7726 const BoxRec * const clip_start = RegionBoxptr(&clip); 7727 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7728 do { 7729 int16_t X1 = pt->x; 7730 int16_t y = pt->y; 7731 int16_t X2 = X1 + (int)*width; 7732 const BoxRec *c; 7733 7734 pt++; 7735 width++; 7736 7737 if (y < extents->y1 || extents->y2 <= y) 7738 continue; 7739 7740 if (X1 < extents->x1) 7741 X1 = extents->x1; 7742 7743 if (X2 > extents->x2) 7744 X2 = extents->x2; 7745 7746 if (X1 >= X2) 7747 continue; 7748 7749 c = find_clip_box_for_y(clip_start, 7750 clip_end, 7751 y); 7752 while (c != clip_end) { 7753 if (y + 1 <= c->y1 || X2 <= c->x1) 7754 break; 7755 7756 if (X1 >= c->x2) { 7757 c++; 7758 continue; 7759 } 7760 7761 b->x1 = c->x1; 7762 b->x2 = c->x2; 7763 c++; 7764 7765 if (b->x1 < X1) 7766 b->x1 = X1; 7767 if (b->x2 > X2) 7768 b->x2 = X2; 7769 if (b->x2 <= b->x1) 7770 continue; 7771 7772 b->x1 += dx; 7773 b->x2 += dx; 7774 b->y1 = y + dy; 7775 b->y2 = b->y1 + 1; 7776 if (++b == last_box) { 7777 fill.boxes(sna, &fill, box, last_box - box); 7778 b = box; 7779 } 7780 } 7781 } while (--n); 7782 RegionUninit(&clip); 7783 } 7784 if (b != box) 7785 fill.boxes(sna, &fill, box, b - box); 7786 goto done; 7787 } 7788 7789damage_clipped: 7790 { 7791 RegionRec clip; 7792 7793 region_set(&clip, extents); 7794 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7795 return true; 7796 7797 assert(dx + clip.extents.x1 >= 0); 7798 assert(dy + clip.extents.y1 >= 0); 7799 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7800 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7801 7802 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7803 __FUNCTION__, 7804 region_num_rects(&clip), 7805 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7806 n, pt->x, pt->y)); 7807 7808 if (clip.data == NULL) { 7809 do { 7810 *(DDXPointRec *)b = *pt++; 7811 b->x2 = b->x1 + (int)*width++; 7812 b->y2 = b->y1 + 1; 7813 7814 if (box_intersect(b, &clip.extents)) { 7815 b->x1 += dx; 7816 b->x2 += dx; 7817 b->y1 += dy; 7818 b->y2 += dy; 7819 if (++b == last_box) { 7820 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7821 fill.boxes(sna, &fill, box, last_box - box); 7822 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7823 b = box; 7824 } 7825 } 7826 } while (--n); 7827 } else { 7828 const BoxRec * const clip_start = RegionBoxptr(&clip); 7829 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7830 do { 7831 int16_t X1 = pt->x; 7832 int16_t y = pt->y; 7833 int16_t X2 = X1 + (int)*width; 7834 const BoxRec *c; 7835 7836 pt++; 7837 width++; 7838 7839 if (y < extents->y1 || extents->y2 <= y) 7840 continue; 7841 7842 if (X1 < extents->x1) 7843 X1 = extents->x1; 7844 7845 if (X2 > extents->x2) 7846 X2 = extents->x2; 7847 7848 if (X1 >= X2) 7849 continue; 7850 7851 c = find_clip_box_for_y(clip_start, 7852 clip_end, 7853 y); 7854 while (c != clip_end) { 7855 if (y + 1 <= c->y1 || X2 <= c->x1) 7856 break; 7857 7858 if (X1 >= c->x2) { 7859 c++; 7860 continue; 7861 } 7862 7863 b->x1 = c->x1; 7864 b->x2 = c->x2; 7865 c++; 7866 7867 if (b->x1 < X1) 7868 b->x1 = X1; 7869 if (b->x2 > X2) 7870 b->x2 = X2; 7871 if (b->x2 <= b->x1) 7872 continue; 7873 7874 b->x1 += dx; 7875 b->x2 += dx; 7876 b->y1 = y + dy; 7877 b->y2 = b->y1 + 1; 7878 if (++b == last_box) { 7879 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7880 fill.boxes(sna, &fill, box, last_box - box); 7881 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7882 b = box; 7883 } 7884 } 7885 } while (--n); 7886 RegionUninit(&clip); 7887 } 7888 if (b != box) { 7889 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7890 fill.boxes(sna, &fill, box, b - box); 7891 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7892 } 7893 goto done; 7894 } 7895 7896done: 7897 fill.done(sna, &fill); 7898 assert_pixmap_damage(pixmap); 7899 return true; 7900} 7901 7902static bool 7903sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 7904 struct kgem_bo *bo, 7905 struct sna_damage **damage, 7906 GCPtr gc, int n, xRectangle *rect, 7907 const BoxRec *extents, unsigned clipped); 7908 7909static bool 7910sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 7911 struct kgem_bo *bo, 7912 struct sna_damage **damage, 7913 GCPtr gc, int n, xRectangle *rect, 7914 const BoxRec *extents, unsigned clipped); 7915 7916static inline bool 7917gc_is_solid(GCPtr gc, uint32_t *color) 7918{ 7919 assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask)); 7920 7921 if (gc->alu == GXclear) { 7922 *color = 0; 7923 return true; 7924 } 7925 if (gc->alu == GXset) { 7926 *color = (1 << gc->depth) - 1; 7927 return true; 7928 } 7929 7930 if (gc->fillStyle == FillSolid || 7931 (gc->fillStyle == FillTiled && gc->tileIsPixel) || 7932 (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { 7933 *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; 7934 return true; 7935 } 7936 7937 return false; 7938} 7939 7940static void 7941sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n, 7942 DDXPointPtr pt, int *width, int sorted) 7943{ 7944 struct sna_fill_spans *data = sna_gc(gc)->priv; 7945 uint32_t color; 7946 7947 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 7948 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 7949 7950 assert(PM_IS_SOLID(drawable, gc->planemask)); 7951 if (n == 0) 7952 return; 7953 7954 /* The mi routines do not attempt to keep the spans it generates 7955 * within the clip, so we must run them through the clipper. 7956 */ 7957 7958 if (gc_is_solid(gc, &color)) { 7959 sna_fill_spans_blt(drawable, 7960 data->bo, NULL, 7961 gc, color, n, pt, width, sorted, 7962 &data->region.extents, 2); 7963 } else { 7964 /* Try converting these to a set of rectangles instead */ 7965 xRectangle *rect; 7966 int i; 7967 7968 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 7969 7970 rect = malloc (n * sizeof (xRectangle)); 7971 if (rect == NULL) 7972 return; 7973 7974 for (i = 0; i < n; i++) { 7975 rect[i].x = pt[i].x - drawable->x; 7976 rect[i].width = width[i]; 7977 rect[i].y = pt[i].y - drawable->y; 7978 rect[i].height = 1; 7979 } 7980 7981 if (gc->fillStyle == FillTiled) { 7982 (void)sna_poly_fill_rect_tiled_blt(drawable, 7983 data->bo, NULL, 7984 gc, n, rect, 7985 &data->region.extents, 2); 7986 } else { 7987 (void)sna_poly_fill_rect_stippled_blt(drawable, 7988 data->bo, NULL, 7989 gc, n, rect, 7990 &data->region.extents, 2); 7991 } 7992 free (rect); 7993 } 7994} 7995 7996static unsigned 7997sna_spans_extents(DrawablePtr drawable, GCPtr gc, 7998 int n, DDXPointPtr pt, int *width, 7999 BoxPtr out) 8000{ 8001 BoxRec box; 8002 bool clipped = false; 8003 8004 if (n == 0) 8005 return 0; 8006 8007 box.x1 = pt->x; 8008 box.x2 = box.x1 + *width; 8009 box.y2 = box.y1 = pt->y; 8010 8011 while (--n) { 8012 pt++; 8013 width++; 8014 if (box.x1 > pt->x) 8015 box.x1 = pt->x; 8016 if (box.x2 < pt->x + *width) 8017 box.x2 = pt->x + *width; 8018 8019 if (box.y1 > pt->y) 8020 box.y1 = pt->y; 8021 else if (box.y2 < pt->y) 8022 box.y2 = pt->y; 8023 } 8024 box.y2++; 8025 8026 if (gc) 8027 clipped = clip_box(&box, gc); 8028 if (box_empty(&box)) 8029 return 0; 8030 8031 *out = box; 8032 return 1 | clipped << 1; 8033} 8034 8035static void 8036sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n, 8037 DDXPointPtr pt, int *width, int sorted) 8038{ 8039 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8040 struct sna *sna = to_sna_from_pixmap(pixmap); 8041 struct sna_damage **damage; 8042 struct kgem_bo *bo; 8043 RegionRec region; 8044 unsigned flags; 8045 uint32_t color; 8046 8047 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 8048 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 8049 8050 flags = sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents); 8051 if (flags == 0) 8052 return; 8053 8054 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 8055 region.extents.x1, region.extents.y1, 8056 region.extents.x2, region.extents.y2)); 8057 8058 if (FORCE_FALLBACK) 8059 goto fallback; 8060 8061 if (!ACCEL_FILL_SPANS) 8062 goto fallback; 8063 8064 if (wedged(sna)) { 8065 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8066 goto fallback; 8067 } 8068 8069 DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__, 8070 gc->fillStyle, gc->fillStyle == FillSolid, 8071 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 8072 if (!PM_IS_SOLID(drawable, gc->planemask)) 8073 goto fallback; 8074 8075 bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8076 ®ion.extents, &damage); 8077 if (bo) { 8078 if (gc_is_solid(gc, &color)) { 8079 DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n", 8080 __FUNCTION__, gc->alu, gc->fgPixel)); 8081 8082 sna_fill_spans_blt(drawable, 8083 bo, damage, 8084 gc, color, n, pt, width, sorted, 8085 ®ion.extents, flags & IS_CLIPPED); 8086 } else { 8087 /* Try converting these to a set of rectangles instead */ 8088 xRectangle *rect; 8089 int i; 8090 8091 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8092 8093 rect = malloc (n * sizeof (xRectangle)); 8094 if (rect == NULL) 8095 return; 8096 8097 for (i = 0; i < n; i++) { 8098 rect[i].x = pt[i].x - drawable->x; 8099 rect[i].width = width[i]; 8100 rect[i].y = pt[i].y - drawable->y; 8101 rect[i].height = 1; 8102 } 8103 8104 if (gc->fillStyle == FillTiled) { 8105 i = sna_poly_fill_rect_tiled_blt(drawable, 8106 bo, damage, 8107 gc, n, rect, 8108 ®ion.extents, flags & IS_CLIPPED); 8109 } else { 8110 i = sna_poly_fill_rect_stippled_blt(drawable, 8111 bo, damage, 8112 gc, n, rect, 8113 ®ion.extents, flags & IS_CLIPPED); 8114 } 8115 free (rect); 8116 8117 if (i) 8118 return; 8119 } 8120 } 8121 8122fallback: 8123 DBG(("%s: fallback\n", __FUNCTION__)); 8124 region.data = NULL; 8125 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8126 return; 8127 8128 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8129 goto out; 8130 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8131 drawable_gc_flags(drawable, gc, n > 1))) 8132 goto out; 8133 8134 if (sigtrap_get() == 0) { 8135 DBG(("%s: fbFillSpans\n", __FUNCTION__)); 8136 fbFillSpans(drawable, gc, n, pt, width, sorted); 8137 FALLBACK_FLUSH(drawable); 8138 sigtrap_put(); 8139 } 8140out: 8141 sna_gc_move_to_gpu(gc); 8142 RegionUninit(®ion); 8143} 8144 8145static void 8146sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 8147 DDXPointPtr pt, int *width, int n, int sorted) 8148{ 8149 RegionRec region; 8150 8151 if (sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents) == 0) 8152 return; 8153 8154 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 8155 region.extents.x1, region.extents.y1, 8156 region.extents.x2, region.extents.y2)); 8157 8158 if (FORCE_FALLBACK) 8159 goto fallback; 8160 8161 if (!ACCEL_SET_SPANS) 8162 goto fallback; 8163 8164fallback: 8165 region.data = NULL; 8166 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8167 return; 8168 8169 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8170 goto out; 8171 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8172 drawable_gc_flags(drawable, gc, n > 1))) 8173 goto out; 8174 8175 if (sigtrap_get() == 0) { 8176 DBG(("%s: fbSetSpans\n", __FUNCTION__)); 8177 fbSetSpans(drawable, gc, src, pt, width, n, sorted); 8178 FALLBACK_FLUSH(drawable); 8179 sigtrap_put(); 8180 } 8181out: 8182 sna_gc_move_to_gpu(gc); 8183 RegionUninit(®ion); 8184} 8185 8186struct sna_copy_plane { 8187 struct sna_damage **damage; 8188 struct kgem_bo *bo; 8189}; 8190 8191static void 8192sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, 8193 RegionRec *region, int sx, int sy, 8194 Pixel bitplane, void *closure) 8195{ 8196 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8197 struct sna *sna = to_sna_from_pixmap(pixmap); 8198 struct sna_copy_plane *arg = closure; 8199 PixmapPtr bitmap = (PixmapPtr)_bitmap; 8200 uint32_t br00, br13; 8201 int16_t dx, dy; 8202 const BoxRec *box; 8203 int n; 8204 8205 DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n", 8206 __FUNCTION__, (unsigned)bitplane, 8207 region->extents.x1, region->extents.y1, 8208 region->extents.x2, region->extents.y2, 8209 region_num_rects(region))); 8210 8211 box = region_rects(region); 8212 n = region_num_rects(region); 8213 assert(n); 8214 8215 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8216 assert_pixmap_contains_boxes(pixmap, box, n, dx, dy); 8217 8218 br00 = 3 << 20; 8219 br13 = arg->bo->pitch; 8220 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8221 br00 |= BLT_DST_TILED; 8222 br13 >>= 2; 8223 } 8224 br13 |= blt_depth(drawable->depth) << 24; 8225 br13 |= copy_ROP[gc->alu] << 16; 8226 8227 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8228 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8229 do { 8230 int bx1 = (box->x1 + sx) & ~7; 8231 int bx2 = (box->x2 + sx + 7) & ~7; 8232 int bw = (bx2 - bx1)/8; 8233 int bh = box->y2 - box->y1; 8234 int bstride = ALIGN(bw, 2); 8235 int src_stride; 8236 uint8_t *dst, *src; 8237 uint32_t *b; 8238 8239 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8240 __FUNCTION__, 8241 box->x1, box->y1, 8242 box->x2, box->y2, 8243 sx, sy, bx1, bx2)); 8244 8245 src_stride = bstride*bh; 8246 assert(src_stride > 0); 8247 if (src_stride <= 128) { 8248 src_stride = ALIGN(src_stride, 8) / 4; 8249 assert(src_stride <= 32); 8250 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 8251 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8252 !kgem_check_reloc(&sna->kgem, 1)) { 8253 kgem_submit(&sna->kgem); 8254 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8255 return; /* XXX fallback? */ 8256 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8257 } 8258 8259 assert(sna->kgem.mode == KGEM_BLT); 8260 if (sna->kgem.gen >= 0100) { 8261 b = sna->kgem.batch + sna->kgem.nbatch; 8262 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 8263 b[0] |= ((box->x1 + sx) & 7) << 17; 8264 b[1] = br13; 8265 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8266 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8267 *(uint64_t *)(b+4) = 8268 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8269 I915_GEM_DOMAIN_RENDER << 16 | 8270 I915_GEM_DOMAIN_RENDER | 8271 KGEM_RELOC_FENCED, 8272 0); 8273 b[5] = gc->bgPixel; 8274 b[6] = gc->fgPixel; 8275 8276 dst = (uint8_t *)&b[8]; 8277 sna->kgem.nbatch += 8 + src_stride; 8278 } else { 8279 b = sna->kgem.batch + sna->kgem.nbatch; 8280 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 8281 b[0] |= ((box->x1 + sx) & 7) << 17; 8282 b[1] = br13; 8283 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8284 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8285 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8286 I915_GEM_DOMAIN_RENDER << 16 | 8287 I915_GEM_DOMAIN_RENDER | 8288 KGEM_RELOC_FENCED, 8289 0); 8290 b[5] = gc->bgPixel; 8291 b[6] = gc->fgPixel; 8292 8293 dst = (uint8_t *)&b[7]; 8294 sna->kgem.nbatch += 7 + src_stride; 8295 } 8296 8297 assert(bitmap->devKind); 8298 src_stride = bitmap->devKind; 8299 src = bitmap->devPrivate.ptr; 8300 src += (box->y1 + sy) * src_stride + bx1/8; 8301 src_stride -= bstride; 8302 do { 8303 int i = bstride; 8304 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8305 do { 8306 *dst++ = byte_reverse(*src++); 8307 *dst++ = byte_reverse(*src++); 8308 i -= 2; 8309 } while (i); 8310 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8311 src += src_stride; 8312 } while (--bh); 8313 } else { 8314 struct kgem_bo *upload; 8315 void *ptr; 8316 8317 if (!kgem_check_batch(&sna->kgem, 10) || 8318 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8319 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8320 kgem_submit(&sna->kgem); 8321 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8322 return; /* XXX fallback? */ 8323 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8324 } 8325 8326 upload = kgem_create_buffer(&sna->kgem, 8327 bstride*bh, 8328 KGEM_BUFFER_WRITE_INPLACE, 8329 &ptr); 8330 if (!upload) 8331 break; 8332 8333 if (sigtrap_get() == 0) { 8334 assert(sna->kgem.mode == KGEM_BLT); 8335 b = sna->kgem.batch + sna->kgem.nbatch; 8336 if (sna->kgem.gen >= 0100) { 8337 b[0] = XY_MONO_SRC_COPY | br00 | 8; 8338 b[0] |= ((box->x1 + sx) & 7) << 17; 8339 b[1] = br13; 8340 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8341 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8342 *(uint64_t *)(b+4) = 8343 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8344 I915_GEM_DOMAIN_RENDER << 16 | 8345 I915_GEM_DOMAIN_RENDER | 8346 KGEM_RELOC_FENCED, 8347 0); 8348 *(uint64_t *)(b+6) = 8349 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8350 I915_GEM_DOMAIN_RENDER << 16 | 8351 KGEM_RELOC_FENCED, 8352 0); 8353 b[8] = gc->bgPixel; 8354 b[9] = gc->fgPixel; 8355 8356 sna->kgem.nbatch += 10; 8357 } else { 8358 b[0] = XY_MONO_SRC_COPY | br00 | 6; 8359 b[0] |= ((box->x1 + sx) & 7) << 17; 8360 b[1] = br13; 8361 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8362 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8363 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8364 I915_GEM_DOMAIN_RENDER << 16 | 8365 I915_GEM_DOMAIN_RENDER | 8366 KGEM_RELOC_FENCED, 8367 0); 8368 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8369 I915_GEM_DOMAIN_RENDER << 16 | 8370 KGEM_RELOC_FENCED, 8371 0); 8372 b[6] = gc->bgPixel; 8373 b[7] = gc->fgPixel; 8374 8375 sna->kgem.nbatch += 8; 8376 } 8377 8378 dst = ptr; 8379 assert(bitmap->devKind); 8380 src_stride = bitmap->devKind; 8381 src = bitmap->devPrivate.ptr; 8382 src += (box->y1 + sy) * src_stride + bx1/8; 8383 src_stride -= bstride; 8384 do { 8385 int i = bstride; 8386 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8387 do { 8388 *dst++ = byte_reverse(*src++); 8389 *dst++ = byte_reverse(*src++); 8390 i -= 2; 8391 } while (i); 8392 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8393 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 8394 src += src_stride; 8395 } while (--bh); 8396 8397 sigtrap_put(); 8398 } 8399 8400 kgem_bo_destroy(&sna->kgem, upload); 8401 } 8402 8403 box++; 8404 } while (--n); 8405 8406 if (arg->damage) { 8407 RegionTranslate(region, dx, dy); 8408 sna_damage_add_to_pixmap(arg->damage, region, pixmap); 8409 } 8410 assert_pixmap_damage(pixmap); 8411 sna->blt_state.fill_bo = 0; 8412} 8413 8414static void 8415sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, 8416 RegionPtr region, int sx, int sy, 8417 Pixel bitplane, void *closure) 8418{ 8419 PixmapPtr dst_pixmap = get_drawable_pixmap(drawable); 8420 PixmapPtr src_pixmap = get_drawable_pixmap(source); 8421 struct sna *sna = to_sna_from_pixmap(dst_pixmap); 8422 struct sna_copy_plane *arg = closure; 8423 int16_t dx, dy; 8424 int bit = ffs(bitplane) - 1; 8425 uint32_t br00, br13; 8426 const BoxRec *box = region_rects(region); 8427 int n = region_num_rects(region); 8428 8429 DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__, 8430 (unsigned)bitplane, bit, n)); 8431 8432 if (n == 0) 8433 return; 8434 8435 if (get_drawable_deltas(source, src_pixmap, &dx, &dy)) 8436 sx += dx, sy += dy; 8437 8438 get_drawable_deltas(drawable, dst_pixmap, &dx, &dy); 8439 assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy); 8440 8441 br00 = XY_MONO_SRC_COPY | 3 << 20; 8442 br13 = arg->bo->pitch; 8443 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8444 br00 |= BLT_DST_TILED; 8445 br13 >>= 2; 8446 } 8447 br13 |= blt_depth(drawable->depth) << 24; 8448 br13 |= copy_ROP[gc->alu] << 16; 8449 8450 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8451 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8452 do { 8453 int bx1 = (box->x1 + sx) & ~7; 8454 int bx2 = (box->x2 + sx + 7) & ~7; 8455 int bw = (bx2 - bx1)/8; 8456 int bh = box->y2 - box->y1; 8457 int bstride = ALIGN(bw, 2); 8458 struct kgem_bo *upload; 8459 void *ptr; 8460 8461 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8462 __FUNCTION__, 8463 box->x1, box->y1, 8464 box->x2, box->y2, 8465 sx, sy, bx1, bx2)); 8466 8467 if (!kgem_check_batch(&sna->kgem, 10) || 8468 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8469 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8470 kgem_submit(&sna->kgem); 8471 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8472 return; /* XXX fallback? */ 8473 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8474 } 8475 8476 upload = kgem_create_buffer(&sna->kgem, 8477 bstride*bh, 8478 KGEM_BUFFER_WRITE_INPLACE, 8479 &ptr); 8480 if (!upload) 8481 break; 8482 8483 if (sigtrap_get() == 0) { 8484 uint32_t *b; 8485 8486 assert(src_pixmap->devKind); 8487 switch (source->bitsPerPixel) { 8488 case 32: 8489 { 8490 uint32_t *src = src_pixmap->devPrivate.ptr; 8491 int src_stride = src_pixmap->devKind/sizeof(uint32_t); 8492 uint8_t *dst = ptr; 8493 8494 src += (box->y1 + sy) * src_stride; 8495 src += bx1; 8496 8497 src_stride -= bw * 8; 8498 bstride -= bw; 8499 8500 do { 8501 int i = bw; 8502 do { 8503 uint8_t v = 0; 8504 8505 v |= ((*src++ >> bit) & 1) << 7; 8506 v |= ((*src++ >> bit) & 1) << 6; 8507 v |= ((*src++ >> bit) & 1) << 5; 8508 v |= ((*src++ >> bit) & 1) << 4; 8509 v |= ((*src++ >> bit) & 1) << 3; 8510 v |= ((*src++ >> bit) & 1) << 2; 8511 v |= ((*src++ >> bit) & 1) << 1; 8512 v |= ((*src++ >> bit) & 1) << 0; 8513 8514 *dst++ = v; 8515 } while (--i); 8516 dst += bstride; 8517 src += src_stride; 8518 } while (--bh); 8519 break; 8520 } 8521 case 16: 8522 { 8523 uint16_t *src = src_pixmap->devPrivate.ptr; 8524 int src_stride = src_pixmap->devKind/sizeof(uint16_t); 8525 uint8_t *dst = ptr; 8526 8527 src += (box->y1 + sy) * src_stride; 8528 src += bx1; 8529 8530 src_stride -= bw * 8; 8531 bstride -= bw; 8532 8533 do { 8534 int i = bw; 8535 do { 8536 uint8_t v = 0; 8537 8538 v |= ((*src++ >> bit) & 1) << 7; 8539 v |= ((*src++ >> bit) & 1) << 6; 8540 v |= ((*src++ >> bit) & 1) << 5; 8541 v |= ((*src++ >> bit) & 1) << 4; 8542 v |= ((*src++ >> bit) & 1) << 3; 8543 v |= ((*src++ >> bit) & 1) << 2; 8544 v |= ((*src++ >> bit) & 1) << 1; 8545 v |= ((*src++ >> bit) & 1) << 0; 8546 8547 *dst++ = v; 8548 } while (--i); 8549 dst += bstride; 8550 src += src_stride; 8551 } while (--bh); 8552 break; 8553 } 8554 default: 8555 assert(0); 8556 case 8: 8557 { 8558 uint8_t *src = src_pixmap->devPrivate.ptr; 8559 int src_stride = src_pixmap->devKind/sizeof(uint8_t); 8560 uint8_t *dst = ptr; 8561 8562 src += (box->y1 + sy) * src_stride; 8563 src += bx1; 8564 8565 src_stride -= bw * 8; 8566 bstride -= bw; 8567 8568 do { 8569 int i = bw; 8570 do { 8571 uint8_t v = 0; 8572 8573 v |= ((*src++ >> bit) & 1) << 7; 8574 v |= ((*src++ >> bit) & 1) << 6; 8575 v |= ((*src++ >> bit) & 1) << 5; 8576 v |= ((*src++ >> bit) & 1) << 4; 8577 v |= ((*src++ >> bit) & 1) << 3; 8578 v |= ((*src++ >> bit) & 1) << 2; 8579 v |= ((*src++ >> bit) & 1) << 1; 8580 v |= ((*src++ >> bit) & 1) << 0; 8581 8582 *dst++ = v; 8583 } while (--i); 8584 dst += bstride; 8585 src += src_stride; 8586 } while (--bh); 8587 break; 8588 } 8589 } 8590 8591 assert(sna->kgem.mode == KGEM_BLT); 8592 b = sna->kgem.batch + sna->kgem.nbatch; 8593 if (sna->kgem.gen >= 0100) { 8594 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8; 8595 b[1] = br13; 8596 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8597 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8598 *(uint64_t *)(b+4) = 8599 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8600 I915_GEM_DOMAIN_RENDER << 16 | 8601 I915_GEM_DOMAIN_RENDER | 8602 KGEM_RELOC_FENCED, 8603 0); 8604 *(uint64_t *)(b+6) = 8605 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8606 I915_GEM_DOMAIN_RENDER << 16 | 8607 KGEM_RELOC_FENCED, 8608 0); 8609 b[8] = gc->bgPixel; 8610 b[9] = gc->fgPixel; 8611 8612 sna->kgem.nbatch += 10; 8613 } else { 8614 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6; 8615 b[1] = br13; 8616 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8617 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8618 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8619 I915_GEM_DOMAIN_RENDER << 16 | 8620 I915_GEM_DOMAIN_RENDER | 8621 KGEM_RELOC_FENCED, 8622 0); 8623 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8624 I915_GEM_DOMAIN_RENDER << 16 | 8625 KGEM_RELOC_FENCED, 8626 0); 8627 b[6] = gc->bgPixel; 8628 b[7] = gc->fgPixel; 8629 8630 sna->kgem.nbatch += 8; 8631 } 8632 sigtrap_put(); 8633 } 8634 kgem_bo_destroy(&sna->kgem, upload); 8635 8636 box++; 8637 } while (--n); 8638 8639 if (arg->damage) { 8640 RegionTranslate(region, dx, dy); 8641 sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap); 8642 } 8643 assert_pixmap_damage(dst_pixmap); 8644 sna->blt_state.fill_bo = 0; 8645} 8646 8647static RegionPtr 8648sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 8649 int src_x, int src_y, 8650 int w, int h, 8651 int dst_x, int dst_y, 8652 unsigned long bit) 8653{ 8654 PixmapPtr pixmap = get_drawable_pixmap(dst); 8655 struct sna *sna = to_sna_from_pixmap(pixmap); 8656 RegionRec region, *ret = NULL; 8657 struct sna_copy_plane arg; 8658 8659 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__, 8660 src_x, src_y, dst_x, dst_y, w, h)); 8661 8662 if (gc->planemask == 0) 8663 goto empty; 8664 8665 if (src->bitsPerPixel == 1 && (bit&1) == 0) 8666 goto empty; 8667 8668 region.extents.x1 = dst_x + dst->x; 8669 region.extents.y1 = dst_y + dst->y; 8670 region.extents.x2 = region.extents.x1 + w; 8671 region.extents.y2 = region.extents.y1 + h; 8672 region.data = NULL; 8673 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 8674 8675 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", 8676 __FUNCTION__, 8677 region.extents.x1, region.extents.y1, 8678 region.extents.x2, region.extents.y2)); 8679 8680 { 8681 RegionRec clip; 8682 8683 clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x); 8684 clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y); 8685 clip.extents.x2 = clip.extents.x1 + src->width; 8686 clip.extents.y2 = clip.extents.y1 + src->height; 8687 clip.data = NULL; 8688 8689 DBG(("%s: src extents (%d, %d), (%d, %d)\n", 8690 __FUNCTION__, 8691 clip.extents.x1, clip.extents.y1, 8692 clip.extents.x2, clip.extents.y2)); 8693 8694 RegionIntersect(®ion, ®ion, &clip); 8695 } 8696 DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n", 8697 __FUNCTION__, 8698 region.extents.x1, region.extents.y1, 8699 region.extents.x2, region.extents.y2)); 8700 if (box_empty(®ion.extents)) 8701 goto empty; 8702 8703 RegionTranslate(®ion, 8704 src_x - dst_x - dst->x + src->x, 8705 src_y - dst_y - dst->y + src->y); 8706 8707 if (!sna_drawable_move_region_to_cpu(src, ®ion, MOVE_READ)) 8708 goto out; 8709 8710 RegionTranslate(®ion, 8711 -(src_x - dst_x - dst->x + src->x), 8712 -(src_y - dst_y - dst->y + src->y)); 8713 8714 if (FORCE_FALLBACK) 8715 goto fallback; 8716 8717 if (!ACCEL_COPY_PLANE) 8718 goto fallback; 8719 8720 if (wedged(sna)) 8721 goto fallback; 8722 8723 if (!PM_IS_SOLID(dst, gc->planemask)) 8724 goto fallback; 8725 8726 arg.bo = sna_drawable_use_bo(dst, PREFER_GPU, 8727 ®ion.extents, &arg.damage); 8728 if (arg.bo) { 8729 if (arg.bo->tiling == I915_TILING_Y) { 8730 assert(arg.bo == __sna_pixmap_get_bo(pixmap)); 8731 arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 8732 if (arg.bo == NULL) { 8733 DBG(("%s: fallback -- unable to change tiling\n", 8734 __FUNCTION__)); 8735 goto fallback; 8736 } 8737 } 8738 8739 if (!kgem_bo_can_blt(&sna->kgem, arg.bo)) 8740 return false; 8741 8742 RegionUninit(®ion); 8743 return sna_do_copy(src, dst, gc, 8744 src_x, src_y, 8745 w, h, 8746 dst_x, dst_y, 8747 src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt, 8748 (Pixel)bit, &arg); 8749 } 8750 8751fallback: 8752 DBG(("%s: fallback\n", __FUNCTION__)); 8753 if (!sna_gc_move_to_cpu(gc, dst, ®ion)) 8754 goto out; 8755 if (!sna_drawable_move_region_to_cpu(dst, ®ion, 8756 drawable_gc_flags(dst, gc, false))) 8757 goto out; 8758 8759 if (sigtrap_get() == 0) { 8760 DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n", 8761 __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit)); 8762 ret = miDoCopy(src, dst, gc, 8763 src_x, src_y, w, h, dst_x, dst_y, 8764 src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN, 8765 bit, 0); 8766 FALLBACK_FLUSH(dst); 8767 sigtrap_put(); 8768 } 8769out: 8770 sna_gc_move_to_gpu(gc); 8771 RegionUninit(®ion); 8772 return ret; 8773empty: 8774 return miHandleExposures(src, dst, gc, 8775 src_x, src_y, 8776 w, h, 8777 dst_x, dst_y, bit); 8778} 8779 8780static bool 8781sna_poly_point_blt(DrawablePtr drawable, 8782 struct kgem_bo *bo, 8783 struct sna_damage **damage, 8784 GCPtr gc, int mode, int n, DDXPointPtr pt, 8785 bool clipped) 8786{ 8787 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8788 struct sna *sna = to_sna_from_pixmap(pixmap); 8789 BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box); 8790 struct sna_fill_op fill; 8791 DDXPointRec last; 8792 int16_t dx, dy; 8793 8794 DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n", 8795 __FUNCTION__, gc->alu, gc->fgPixel, clipped)); 8796 8797 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS)) 8798 return false; 8799 8800 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8801 8802 last.x = drawable->x; 8803 last.y = drawable->y; 8804 8805 if (!clipped) { 8806 last.x += dx; 8807 last.y += dy; 8808 8809 assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y); 8810 sna_damage_add_points(damage, pt, n, last.x, last.y); 8811 if (fill.points && mode != CoordModePrevious) { 8812 fill.points(sna, &fill, last.x, last.y, pt, n); 8813 } else { 8814 do { 8815 unsigned nbox = n; 8816 if (nbox > ARRAY_SIZE(box)) 8817 nbox = ARRAY_SIZE(box); 8818 n -= nbox; 8819 do { 8820 *(DDXPointRec *)b = *pt++; 8821 8822 b->x1 += last.x; 8823 b->y1 += last.y; 8824 if (mode == CoordModePrevious) 8825 last = *(DDXPointRec *)b; 8826 8827 b->x2 = b->x1 + 1; 8828 b->y2 = b->y1 + 1; 8829 b++; 8830 } while (--nbox); 8831 fill.boxes(sna, &fill, box, b - box); 8832 b = box; 8833 } while (n); 8834 } 8835 } else { 8836 RegionPtr clip = gc->pCompositeClip; 8837 8838 while (n--) { 8839 int x, y; 8840 8841 x = pt->x; 8842 y = pt->y; 8843 pt++; 8844 if (mode == CoordModePrevious) { 8845 x += last.x; 8846 y += last.y; 8847 last.x = x; 8848 last.y = y; 8849 } else { 8850 x += drawable->x; 8851 y += drawable->y; 8852 } 8853 8854 if (RegionContainsPoint(clip, x, y, NULL)) { 8855 b->x1 = x + dx; 8856 b->y1 = y + dy; 8857 b->x2 = b->x1 + 1; 8858 b->y2 = b->y1 + 1; 8859 if (++b == last_box){ 8860 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 8861 fill.boxes(sna, &fill, box, last_box - box); 8862 if (damage) 8863 sna_damage_add_boxes(damage, box, last_box-box, 0, 0); 8864 b = box; 8865 } 8866 } 8867 } 8868 if (b != box){ 8869 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 8870 fill.boxes(sna, &fill, box, b - box); 8871 if (damage) 8872 sna_damage_add_boxes(damage, box, b-box, 0, 0); 8873 } 8874 } 8875 fill.done(sna, &fill); 8876 assert_pixmap_damage(pixmap); 8877 return true; 8878} 8879 8880static unsigned 8881sna_poly_point_extents(DrawablePtr drawable, GCPtr gc, 8882 int mode, int n, DDXPointPtr pt, BoxPtr out) 8883{ 8884 BoxRec box; 8885 bool clipped; 8886 8887 if (n == 0) 8888 return 0; 8889 8890 box.x2 = box.x1 = pt->x; 8891 box.y2 = box.y1 = pt->y; 8892 if (mode == CoordModePrevious) { 8893 DDXPointRec last = *pt++; 8894 while (--n) { 8895 last.x += pt->x; 8896 last.y += pt->y; 8897 pt++; 8898 box_add_pt(&box, last.x, last.y); 8899 } 8900 } else { 8901 --n; ++pt; 8902 while (n >= 8) { 8903 box_add_pt(&box, pt[0].x, pt[0].y); 8904 box_add_pt(&box, pt[1].x, pt[1].y); 8905 box_add_pt(&box, pt[2].x, pt[2].y); 8906 box_add_pt(&box, pt[3].x, pt[3].y); 8907 box_add_pt(&box, pt[4].x, pt[4].y); 8908 box_add_pt(&box, pt[5].x, pt[5].y); 8909 box_add_pt(&box, pt[6].x, pt[6].y); 8910 box_add_pt(&box, pt[7].x, pt[7].y); 8911 pt += 8; 8912 n -= 8; 8913 } 8914 if (n & 4) { 8915 box_add_pt(&box, pt[0].x, pt[0].y); 8916 box_add_pt(&box, pt[1].x, pt[1].y); 8917 box_add_pt(&box, pt[2].x, pt[2].y); 8918 box_add_pt(&box, pt[3].x, pt[3].y); 8919 pt += 4; 8920 } 8921 if (n & 2) { 8922 box_add_pt(&box, pt[0].x, pt[0].y); 8923 box_add_pt(&box, pt[1].x, pt[1].y); 8924 pt += 2; 8925 } 8926 if (n & 1) 8927 box_add_pt(&box, pt[0].x, pt[0].y); 8928 } 8929 box.x2++; 8930 box.y2++; 8931 8932 clipped = trim_and_translate_box(&box, drawable, gc); 8933 if (box_empty(&box)) 8934 return 0; 8935 8936 *out = box; 8937 return 1 | clipped << 1; 8938} 8939 8940static void 8941sna_poly_point(DrawablePtr drawable, GCPtr gc, 8942 int mode, int n, DDXPointPtr pt) 8943{ 8944 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8945 struct sna *sna = to_sna_from_pixmap(pixmap); 8946 RegionRec region; 8947 unsigned flags; 8948 8949 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n", 8950 __FUNCTION__, mode, n, pt[0].x, pt[0].y)); 8951 8952 flags = sna_poly_point_extents(drawable, gc, mode, n, pt, ®ion.extents); 8953 if (flags == 0) 8954 return; 8955 8956 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 8957 region.extents.x1, region.extents.y1, 8958 region.extents.x2, region.extents.y2, 8959 flags)); 8960 8961 if (FORCE_FALLBACK) 8962 goto fallback; 8963 8964 if (!ACCEL_POLY_POINT) 8965 goto fallback; 8966 8967 if (wedged(sna)) { 8968 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8969 goto fallback; 8970 } 8971 8972 if (PM_IS_SOLID(drawable, gc->planemask)) { 8973 struct sna_damage **damage; 8974 struct kgem_bo *bo; 8975 8976 DBG(("%s: trying solid fill [%08lx] blt paths\n", 8977 __FUNCTION__, gc->fgPixel)); 8978 8979 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8980 ®ion.extents, &damage)) && 8981 sna_poly_point_blt(drawable, bo, damage, 8982 gc, mode, n, pt, flags & IS_CLIPPED)) 8983 return; 8984 } 8985 8986fallback: 8987 DBG(("%s: fallback\n", __FUNCTION__)); 8988 region.data = NULL; 8989 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8990 return; 8991 8992 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8993 goto out; 8994 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8995 MOVE_READ | MOVE_WRITE)) 8996 goto out; 8997 8998 if (sigtrap_get() == 0) { 8999 DBG(("%s: fbPolyPoint\n", __FUNCTION__)); 9000 fbPolyPoint(drawable, gc, mode, n, pt, flags); 9001 FALLBACK_FLUSH(drawable); 9002 sigtrap_put(); 9003 } 9004out: 9005 sna_gc_move_to_gpu(gc); 9006 RegionUninit(®ion); 9007} 9008 9009static bool 9010sna_poly_zero_line_blt(DrawablePtr drawable, 9011 struct kgem_bo *bo, 9012 struct sna_damage **damage, 9013 GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt, 9014 const BoxRec *extents, unsigned clipped) 9015{ 9016 static void * const _jump[] = { 9017 &&no_damage, 9018 &&damage, 9019 9020 &&no_damage_offset, 9021 &&damage_offset, 9022 }; 9023 9024 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9025 struct sna *sna = to_sna_from_pixmap(pixmap); 9026 int x2, y2, xstart, ystart, oc2; 9027 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 9028 bool degenerate = true; 9029 struct sna_fill_op fill; 9030 RegionRec clip; 9031 BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box); 9032 const BoxRec *last_extents; 9033 int16_t dx, dy; 9034 void *jump, *ret; 9035 9036 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 9037 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 9038 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS)) 9039 return false; 9040 9041 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9042 9043 region_set(&clip, extents); 9044 if (clipped) { 9045 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9046 return true; 9047 } 9048 9049 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 9050 DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n", 9051 __FUNCTION__, clipped, 9052 clip.extents.x1, clip.extents.y1, 9053 clip.extents.x2, clip.extents.y2, 9054 dx, dy, damage)); 9055 9056 extents = region_rects(&clip); 9057 last_extents = extents + region_num_rects(&clip); 9058 9059 b = box; 9060 do { 9061 int n = _n; 9062 const DDXPointRec *pt = _pt; 9063 9064 xstart = pt->x + drawable->x; 9065 ystart = pt->y + drawable->y; 9066 9067 x2 = xstart; 9068 y2 = ystart; 9069 oc2 = 0; 9070 OUTCODES(oc2, x2, y2, extents); 9071 9072 while (--n) { 9073 int16_t sdx, sdy; 9074 int adx, ady, length; 9075 int e, e1, e2, e3; 9076 int x1 = x2, x; 9077 int y1 = y2, y; 9078 int oc1 = oc2; 9079 int octant; 9080 9081 ++pt; 9082 9083 x2 = pt->x; 9084 y2 = pt->y; 9085 if (mode == CoordModePrevious) { 9086 x2 += x1; 9087 y2 += y1; 9088 } else { 9089 x2 += drawable->x; 9090 y2 += drawable->y; 9091 } 9092 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 9093 __FUNCTION__, x1, y1, x2, y2)); 9094 if (x2 == x1 && y2 == y1) 9095 continue; 9096 9097 degenerate = false; 9098 9099 oc2 = 0; 9100 OUTCODES(oc2, x2, y2, extents); 9101 if (oc1 & oc2) 9102 continue; 9103 9104 CalcLineDeltas(x1, y1, x2, y2, 9105 adx, ady, sdx, sdy, 9106 1, 1, octant); 9107 9108 DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n", 9109 __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2)); 9110 if (adx == 0 || ady == 0) { 9111 if (x1 <= x2) { 9112 b->x1 = x1; 9113 b->x2 = x2; 9114 } else { 9115 b->x1 = x2; 9116 b->x2 = x1; 9117 } 9118 if (y1 <= y2) { 9119 b->y1 = y1; 9120 b->y2 = y2; 9121 } else { 9122 b->y1 = y2; 9123 b->y2 = y1; 9124 } 9125 b->x2++; 9126 b->y2++; 9127 if (oc1 | oc2) { 9128 bool intersects; 9129 9130 intersects = box_intersect(b, extents); 9131 assert(intersects); 9132 } 9133 if (++b == last_box) { 9134 ret = &&rectangle_continue; 9135 goto *jump; 9136rectangle_continue: 9137 b = box; 9138 } 9139 } else if (adx >= ady) { 9140 int x2_clipped = x2, y2_clipped = y2; 9141 bool dirty; 9142 9143 /* X-major segment */ 9144 e1 = ady << 1; 9145 e2 = e1 - (adx << 1); 9146 e = e1 - adx; 9147 length = adx; 9148 9149 FIXUP_ERROR(e, octant, bias); 9150 9151 x = x1; 9152 y = y1; 9153 9154 if (oc1 | oc2) { 9155 int pt1_clipped, pt2_clipped; 9156 9157 if (miZeroClipLine(extents->x1, extents->y1, 9158 extents->x2-1, extents->y2-1, 9159 &x, &y, &x2_clipped, &y2_clipped, 9160 adx, ady, 9161 &pt1_clipped, &pt2_clipped, 9162 octant, bias, oc1, oc2) == -1) 9163 continue; 9164 9165 length = abs(x2_clipped - x); 9166 if (length == 0) 9167 continue; 9168 9169 if (pt1_clipped) { 9170 int clipdx = abs(x - x1); 9171 int clipdy = abs(y - y1); 9172 e += clipdy * e2 + (clipdx - clipdy) * e1; 9173 } 9174 } 9175 9176 e3 = e2 - e1; 9177 e = e - e1; 9178 9179 b->x1 = x; 9180 b->y1 = y; 9181 dirty = false; 9182 while (length--) { 9183 e += e1; 9184 dirty = true; 9185 if (e >= 0) { 9186 e += e3; 9187 9188 if (sdx < 0) { 9189 b->x2 = b->x1 + 1; 9190 b->x1 = x; 9191 } else 9192 b->x2 = x + 1; 9193 b->y2 = b->y1 + 1; 9194 9195 if (++b == last_box) { 9196 ret = &&X_continue; 9197 goto *jump; 9198X_continue: 9199 b = box; 9200 } 9201 9202 b->x1 = x + sdx; 9203 b->y1 = y += sdy; 9204 dirty = false; 9205 } 9206 x += sdx; 9207 } 9208 if (dirty) { 9209 x -= sdx; 9210 if (sdx < 0) { 9211 b->x2 = b->x1 + 1; 9212 b->x1 = x; 9213 } else 9214 b->x2 = x + 1; 9215 b->y2 = b->y1 + 1; 9216 9217 if (++b == last_box) { 9218 ret = &&X2_continue; 9219 goto *jump; 9220X2_continue: 9221 b = box; 9222 } 9223 } 9224 } else { 9225 int x2_clipped = x2, y2_clipped = y2; 9226 bool dirty; 9227 9228 /* Y-major segment */ 9229 e1 = adx << 1; 9230 e2 = e1 - (ady << 1); 9231 e = e1 - ady; 9232 length = ady; 9233 9234 SetYMajorOctant(octant); 9235 FIXUP_ERROR(e, octant, bias); 9236 9237 x = x1; 9238 y = y1; 9239 9240 if (oc1 | oc2) { 9241 int pt1_clipped, pt2_clipped; 9242 9243 if (miZeroClipLine(extents->x1, extents->y1, 9244 extents->x2-1, extents->y2-1, 9245 &x, &y, &x2_clipped, &y2_clipped, 9246 adx, ady, 9247 &pt1_clipped, &pt2_clipped, 9248 octant, bias, oc1, oc2) == -1) 9249 continue; 9250 9251 length = abs(y2_clipped - y); 9252 if (length == 0) 9253 continue; 9254 9255 if (pt1_clipped) { 9256 int clipdx = abs(x - x1); 9257 int clipdy = abs(y - y1); 9258 e += clipdx * e2 + (clipdy - clipdx) * e1; 9259 } 9260 } 9261 9262 e3 = e2 - e1; 9263 e = e - e1; 9264 9265 b->x1 = x; 9266 b->y1 = y; 9267 dirty = false; 9268 while (length--) { 9269 e += e1; 9270 dirty = true; 9271 if (e >= 0) { 9272 e += e3; 9273 9274 if (sdy < 0) { 9275 b->y2 = b->y1 + 1; 9276 b->y1 = y; 9277 } else 9278 b->y2 = y + 1; 9279 b->x2 = x + 1; 9280 9281 if (++b == last_box) { 9282 ret = &&Y_continue; 9283 goto *jump; 9284Y_continue: 9285 b = box; 9286 } 9287 9288 b->x1 = x += sdx; 9289 b->y1 = y + sdy; 9290 dirty = false; 9291 } 9292 y += sdy; 9293 } 9294 9295 if (dirty) { 9296 y -= sdy; 9297 if (sdy < 0) { 9298 b->y2 = b->y1 + 1; 9299 b->y1 = y; 9300 } else 9301 b->y2 = y + 1; 9302 b->x2 = x + 1; 9303 9304 if (++b == last_box) { 9305 ret = &&Y2_continue; 9306 goto *jump; 9307Y2_continue: 9308 b = box; 9309 } 9310 } 9311 } 9312 } 9313 9314#if 0 9315 /* Only do the CapNotLast check on the last segment 9316 * and only if the endpoint wasn't clipped. And then, if the last 9317 * point is the same as the first point, do not draw it, unless the 9318 * line is degenerate 9319 */ 9320 if (!pt2_clipped && 9321 gc->capStyle != CapNotLast && 9322 !(xstart == x2 && ystart == y2 && !degenerate)) 9323 { 9324 b->x2 = x2; 9325 b->y2 = y2; 9326 if (b->x2 < b->x1) { 9327 int16_t t = b->x1; 9328 b->x1 = b->x2; 9329 b->x2 = t; 9330 } 9331 if (b->y2 < b->y1) { 9332 int16_t t = b->y1; 9333 b->y1 = b->y2; 9334 b->y2 = t; 9335 } 9336 b->x2++; 9337 b->y2++; 9338 b++; 9339 } 9340#endif 9341 } while (++extents != last_extents); 9342 9343 if (b != box) { 9344 ret = &&done; 9345 goto *jump; 9346 } 9347 9348done: 9349 fill.done(sna, &fill); 9350 assert_pixmap_damage(pixmap); 9351 RegionUninit(&clip); 9352 return true; 9353 9354damage: 9355 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9356 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9357no_damage: 9358 fill.boxes(sna, &fill, box, b-box); 9359 goto *ret; 9360 9361no_damage_offset: 9362 { 9363 BoxRec *bb = box; 9364 do { 9365 bb->x1 += dx; 9366 bb->x2 += dx; 9367 bb->y1 += dy; 9368 bb->y2 += dy; 9369 } while (++bb != b); 9370 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9371 fill.boxes(sna, &fill, box, b - box); 9372 } 9373 goto *ret; 9374 9375damage_offset: 9376 { 9377 BoxRec *bb = box; 9378 do { 9379 bb->x1 += dx; 9380 bb->x2 += dx; 9381 bb->y1 += dy; 9382 bb->y2 += dy; 9383 } while (++bb != b); 9384 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9385 fill.boxes(sna, &fill, box, b - box); 9386 sna_damage_add_boxes(damage, box, b - box, 0, 0); 9387 } 9388 goto *ret; 9389} 9390 9391static bool 9392sna_poly_line_blt(DrawablePtr drawable, 9393 struct kgem_bo *bo, 9394 struct sna_damage **damage, 9395 GCPtr gc, uint32_t pixel, 9396 int mode, int n, DDXPointPtr pt, 9397 const BoxRec *extents, bool clipped) 9398{ 9399 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9400 struct sna *sna = to_sna_from_pixmap(pixmap); 9401 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 9402 struct sna_fill_op fill; 9403 DDXPointRec last; 9404 int16_t dx, dy; 9405 9406 DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped)); 9407 9408 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) 9409 return false; 9410 9411 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9412 9413 if (!clipped) { 9414 dx += drawable->x; 9415 dy += drawable->y; 9416 9417 last.x = pt->x + dx; 9418 last.y = pt->y + dy; 9419 pt++; 9420 9421 while (--n) { 9422 DDXPointRec p; 9423 9424 p = *pt++; 9425 if (mode == CoordModePrevious) { 9426 p.x += last.x; 9427 p.y += last.y; 9428 } else { 9429 p.x += dx; 9430 p.y += dy; 9431 } 9432 DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y)); 9433 9434 if (last.x == p.x) { 9435 b->x1 = last.x; 9436 b->x2 = last.x + 1; 9437 } else if (last.x < p.x) { 9438 b->x1 = last.x; 9439 b->x2 = p.x; 9440 } else { 9441 b->x1 = p.x; 9442 b->x2 = last.x; 9443 } 9444 9445 if (last.y == p.y) { 9446 b->y1 = last.y; 9447 b->y2 = last.y + 1; 9448 } else if (last.y < p.y) { 9449 b->y1 = last.y; 9450 b->y2 = p.y; 9451 } else { 9452 b->y1 = p.y; 9453 b->y2 = last.y; 9454 } 9455 b->y2 += last.x == p.x && last.y != p.y; 9456 b->x2 += last.y == p.y && last.x != p.x; 9457 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9458 __FUNCTION__, 9459 b->x1, b->y1, b->x2, b->y2)); 9460 9461 if (++b == last_box) { 9462 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9463 fill.boxes(sna, &fill, boxes, last_box - boxes); 9464 if (damage) 9465 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9466 b = boxes; 9467 } 9468 9469 last = p; 9470 } 9471 } else { 9472 RegionRec clip; 9473 9474 region_set(&clip, extents); 9475 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9476 return true; 9477 9478 last.x = pt->x + drawable->x; 9479 last.y = pt->y + drawable->y; 9480 pt++; 9481 9482 if (clip.data == NULL) { 9483 while (--n) { 9484 DDXPointRec p; 9485 9486 p = *pt++; 9487 if (mode == CoordModePrevious) { 9488 p.x += last.x; 9489 p.y += last.y; 9490 } else { 9491 p.x += drawable->x; 9492 p.y += drawable->y; 9493 } 9494 if (last.x == p.x) { 9495 b->x1 = last.x; 9496 b->x2 = last.x + 1; 9497 } else if (last.x < p.x) { 9498 b->x1 = last.x; 9499 b->x2 = p.x; 9500 } else { 9501 b->x1 = p.x; 9502 b->x2 = last.x; 9503 } 9504 if (last.y == p.y) { 9505 b->y1 = last.y; 9506 b->y2 = last.y + 1; 9507 } else if (last.y < p.y) { 9508 b->y1 = last.y; 9509 b->y2 = p.y; 9510 } else { 9511 b->y1 = p.y; 9512 b->y2 = last.y; 9513 } 9514 b->y2 += last.x == p.x && last.y != p.y; 9515 b->x2 += last.y == p.y && last.x != p.x; 9516 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9517 __FUNCTION__, 9518 b->x1, b->y1, b->x2, b->y2)); 9519 if (box_intersect(b, &clip.extents)) { 9520 b->x1 += dx; 9521 b->x2 += dx; 9522 b->y1 += dy; 9523 b->y2 += dy; 9524 if (++b == last_box) { 9525 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9526 fill.boxes(sna, &fill, boxes, last_box - boxes); 9527 if (damage) 9528 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9529 b = boxes; 9530 } 9531 } 9532 9533 last = p; 9534 } 9535 } else { 9536 const BoxRec * const clip_start = RegionBoxptr(&clip); 9537 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9538 const BoxRec *c; 9539 9540 while (--n) { 9541 DDXPointRec p; 9542 BoxRec box; 9543 9544 p = *pt++; 9545 if (mode == CoordModePrevious) { 9546 p.x += last.x; 9547 p.y += last.y; 9548 } else { 9549 p.x += drawable->x; 9550 p.y += drawable->y; 9551 } 9552 if (last.x == p.x) { 9553 box.x1 = last.x; 9554 box.x2 = last.x + 1; 9555 } else if (last.x < p.x) { 9556 box.x1 = last.x; 9557 box.x2 = p.x; 9558 } else { 9559 box.x1 = p.x; 9560 box.x2 = last.x; 9561 } 9562 if (last.y == p.y) { 9563 box.y1 = last.y; 9564 box.y2 = last.y + 1; 9565 } else if (last.y < p.y) { 9566 box.y1 = last.y; 9567 box.y2 = p.y; 9568 } else { 9569 box.y1 = p.y; 9570 box.y2 = last.y; 9571 } 9572 b->y2 += last.x == p.x && last.y != p.y; 9573 b->x2 += last.y == p.y && last.x != p.x; 9574 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9575 __FUNCTION__, 9576 box.x1, box.y1, box.x2, box.y2)); 9577 9578 c = find_clip_box_for_y(clip_start, 9579 clip_end, 9580 box.y1); 9581 while (c != clip_end) { 9582 if (box.y2 <= c->y1) 9583 break; 9584 9585 *b = box; 9586 if (box_intersect(b, c++)) { 9587 b->x1 += dx; 9588 b->x2 += dx; 9589 b->y1 += dy; 9590 b->y2 += dy; 9591 if (++b == last_box) { 9592 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9593 fill.boxes(sna, &fill, boxes, last_box-boxes); 9594 if (damage) 9595 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9596 b = boxes; 9597 } 9598 } 9599 } 9600 9601 last = p; 9602 } 9603 } 9604 RegionUninit(&clip); 9605 } 9606 if (b != boxes) { 9607 assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0); 9608 fill.boxes(sna, &fill, boxes, b - boxes); 9609 if (damage) 9610 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 9611 } 9612 fill.done(sna, &fill); 9613 assert_pixmap_damage(pixmap); 9614 return true; 9615} 9616 9617static unsigned 9618sna_poly_line_extents(DrawablePtr drawable, GCPtr gc, 9619 int mode, int n, DDXPointPtr pt, 9620 BoxPtr out) 9621{ 9622 BoxRec box; 9623 bool clip, blt = true; 9624 9625 if (n == 0) 9626 return 0; 9627 9628 box.x2 = box.x1 = pt->x; 9629 box.y2 = box.y1 = pt->y; 9630 if (mode == CoordModePrevious) { 9631 int x = box.x1; 9632 int y = box.y1; 9633 while (--n) { 9634 pt++; 9635 x += pt->x; 9636 y += pt->y; 9637 if (blt) 9638 blt &= pt->x == 0 || pt->y == 0; 9639 box_add_pt(&box, x, y); 9640 } 9641 } else { 9642 int x = box.x1; 9643 int y = box.y1; 9644 while (--n) { 9645 pt++; 9646 if (blt) { 9647 blt &= pt->x == x || pt->y == y; 9648 x = pt->x; 9649 y = pt->y; 9650 } 9651 box_add_pt(&box, pt->x, pt->y); 9652 } 9653 } 9654 box.x2++; 9655 box.y2++; 9656 9657 if (gc->lineWidth) { 9658 int extra = gc->lineWidth >> 1; 9659 if (n > 1) { 9660 if (gc->joinStyle == JoinMiter) 9661 extra = 6 * gc->lineWidth; 9662 else if (gc->capStyle == CapProjecting) 9663 extra = gc->lineWidth; 9664 } 9665 if (extra) { 9666 box.x1 -= extra; 9667 box.x2 += extra; 9668 box.y1 -= extra; 9669 box.y2 += extra; 9670 } 9671 } 9672 9673 clip = trim_and_translate_box(&box, drawable, gc); 9674 if (box_empty(&box)) 9675 return 0; 9676 9677 *out = box; 9678 return 1 | blt << 2 | clip << 1; 9679} 9680 9681inline static int 9682_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9683{ 9684 uint32_t ignored; 9685 9686 if (USE_SPANS) 9687 return USE_SPANS > 0; 9688 9689 if (flags & RECTILINEAR) 9690 return PREFER_GPU; 9691 9692 if (gc->lineStyle != LineSolid && gc->lineWidth == 0) 9693 return 0; 9694 9695 if (gc_is_solid(gc, &ignored)) 9696 return PREFER_GPU; 9697 9698 return !drawable_gc_inplace_hint(drawable, gc); 9699} 9700 9701inline static int 9702use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9703{ 9704 int ret = _use_line_spans(drawable, gc, extents, flags); 9705 DBG(("%s? %d\n", __FUNCTION__, ret)); 9706 return ret; 9707} 9708 9709static void 9710sna_poly_line(DrawablePtr drawable, GCPtr gc, 9711 int mode, int n, DDXPointPtr pt) 9712{ 9713 struct sna_pixmap *priv; 9714 struct sna_fill_spans data; 9715 uint32_t color; 9716 9717 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n", 9718 __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth)); 9719 9720 data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt, 9721 &data.region.extents); 9722 if (data.flags == 0) 9723 return; 9724 9725 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9726 data.region.extents.x1, data.region.extents.y1, 9727 data.region.extents.x2, data.region.extents.y2, 9728 data.flags)); 9729 9730 data.region.data = NULL; 9731 9732 if (FORCE_FALLBACK) 9733 goto fallback; 9734 9735 if (!ACCEL_POLY_LINE) 9736 goto fallback; 9737 9738 data.pixmap = get_drawable_pixmap(drawable); 9739 data.sna = to_sna_from_pixmap(data.pixmap); 9740 if (wedged(data.sna)) { 9741 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9742 goto fallback; 9743 } 9744 9745 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n", 9746 __FUNCTION__, 9747 gc->fillStyle, gc->fillStyle == FillSolid, 9748 gc->lineStyle, gc->lineStyle == LineSolid, 9749 gc->lineWidth, 9750 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 9751 data.flags & RECTILINEAR)); 9752 9753 if (!PM_IS_SOLID(drawable, gc->planemask)) 9754 goto fallback; 9755 9756 priv = sna_pixmap(data.pixmap); 9757 if (!priv) { 9758 DBG(("%s: not attached to pixmap %ld\n", 9759 __FUNCTION__, data.pixmap->drawable.serialNumber)); 9760 goto fallback; 9761 } 9762 9763 if (gc->lineStyle != LineSolid) { 9764 DBG(("%s: lineStyle, %d, is not solid\n", 9765 __FUNCTION__, gc->lineStyle)); 9766 goto spans_fallback; 9767 } 9768 if (!(gc->lineWidth == 0 || 9769 (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) { 9770 DBG(("%s: non-zero lineWidth %d\n", 9771 __FUNCTION__, gc->lineWidth)); 9772 goto spans_fallback; 9773 } 9774 9775 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9776 &data.region.extents, 9777 &data.damage); 9778 if (data.bo == NULL) 9779 goto fallback; 9780 9781 if (gc_is_solid(gc, &color)) { 9782 DBG(("%s: trying solid fill [%08x]\n", 9783 __FUNCTION__, (unsigned)color)); 9784 if (data.flags & RECTILINEAR) { 9785 if (sna_poly_line_blt(drawable, 9786 data.bo, data.damage, 9787 gc, color, mode, n, pt, 9788 &data.region.extents, 9789 data.flags & IS_CLIPPED)) 9790 return; 9791 } else { /* !rectilinear */ 9792 if (sna_poly_zero_line_blt(drawable, 9793 data.bo, data.damage, 9794 gc, mode, n, pt, 9795 &data.region.extents, 9796 data.flags & IS_CLIPPED)) 9797 return; 9798 9799 } 9800 } else if (data.flags & RECTILINEAR) { 9801 /* Try converting these to a set of rectangles instead */ 9802 DDXPointRec p1, p2; 9803 xRectangle *rect; 9804 int i; 9805 9806 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 9807 9808 rect = malloc (n * sizeof (xRectangle)); 9809 if (rect == NULL) 9810 return; 9811 9812 p1 = pt[0]; 9813 for (i = 1; i < n; i++) { 9814 if (mode == CoordModePrevious) { 9815 p2.x = p1.x + pt[i].x; 9816 p2.y = p1.y + pt[i].y; 9817 } else 9818 p2 = pt[i]; 9819 if (p1.x < p2.x) { 9820 rect[i].x = p1.x; 9821 rect[i].width = p2.x - p1.x + 1; 9822 } else if (p1.x > p2.x) { 9823 rect[i].x = p2.x; 9824 rect[i].width = p1.x - p2.x + 1; 9825 } else { 9826 rect[i].x = p1.x; 9827 rect[i].width = 1; 9828 } 9829 if (p1.y < p2.y) { 9830 rect[i].y = p1.y; 9831 rect[i].height = p2.y - p1.y + 1; 9832 } else if (p1.y > p2.y) { 9833 rect[i].y = p2.y; 9834 rect[i].height = p1.y - p2.y + 1; 9835 } else { 9836 rect[i].y = p1.y; 9837 rect[i].height = 1; 9838 } 9839 9840 /* don't paint last pixel */ 9841 if (gc->capStyle == CapNotLast) { 9842 if (p1.x == p2.x) 9843 rect[i].height--; 9844 else 9845 rect[i].width--; 9846 } 9847 p1 = p2; 9848 } 9849 9850 if (gc->fillStyle == FillTiled) { 9851 i = sna_poly_fill_rect_tiled_blt(drawable, 9852 data.bo, data.damage, 9853 gc, n - 1, rect + 1, 9854 &data.region.extents, 9855 data.flags & IS_CLIPPED); 9856 } else { 9857 i = sna_poly_fill_rect_stippled_blt(drawable, 9858 data.bo, data.damage, 9859 gc, n - 1, rect + 1, 9860 &data.region.extents, 9861 data.flags & IS_CLIPPED); 9862 } 9863 free (rect); 9864 9865 if (i) 9866 return; 9867 } 9868 9869spans_fallback: 9870 if ((data.bo = sna_drawable_use_bo(drawable, 9871 use_line_spans(drawable, gc, &data.region.extents, data.flags), 9872 &data.region.extents, &data.damage))) { 9873 DBG(("%s: converting line into spans\n", __FUNCTION__)); 9874 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 9875 sna_gc(gc)->priv = &data; 9876 9877 if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) { 9878 struct sna_fill_op fill; 9879 9880 if (gc->lineStyle == LineSolid) { 9881 if (!sna_fill_init_blt(&fill, 9882 data.sna, data.pixmap, 9883 data.bo, gc->alu, color, 9884 FILL_POINTS | FILL_SPANS)) 9885 goto fallback; 9886 9887 data.op = &fill; 9888 9889 if ((data.flags & IS_CLIPPED) == 0) { 9890 if (data.dx | data.dy) 9891 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 9892 else 9893 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 9894 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 9895 } else { 9896 if (!region_maybe_clip(&data.region, 9897 gc->pCompositeClip)) 9898 return; 9899 9900 if (region_is_singular(&data.region)) { 9901 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 9902 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 9903 } else { 9904 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 9905 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 9906 } 9907 } 9908 assert(gc->miTranslate); 9909 9910 gc->ops = &sna_gc_ops__tmp; 9911 DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__)); 9912 miZeroLine(drawable, gc, mode, n, pt); 9913 fill.done(data.sna, &fill); 9914 } else { 9915 data.op = &fill; 9916 9917 if ((data.flags & IS_CLIPPED) == 0) { 9918 if (data.dx | data.dy) 9919 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset; 9920 else 9921 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash; 9922 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash; 9923 } else { 9924 if (!region_maybe_clip(&data.region, 9925 gc->pCompositeClip)) 9926 return; 9927 9928 if (region_is_singular(&data.region)) { 9929 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents; 9930 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents; 9931 } else { 9932 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes; 9933 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes; 9934 } 9935 } 9936 assert(gc->miTranslate); 9937 9938 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n", 9939 __FUNCTION__, 9940 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 9941 gc->fgPixel)); 9942 9943 if (!sna_fill_init_blt(&fill, 9944 data.sna, data.pixmap, 9945 data.bo, gc->alu, color, 9946 FILL_POINTS | FILL_SPANS)) 9947 goto fallback; 9948 9949 gc->ops = &sna_gc_ops__tmp; 9950 data.phase = gc->fgPixel; 9951 miZeroDashLine(drawable, gc, mode, n, pt); 9952 fill.done(data.sna, &fill); 9953 9954 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n", 9955 __FUNCTION__, 9956 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 9957 gc->bgPixel)); 9958 9959 if (sna_fill_init_blt(&fill, 9960 data.sna, data.pixmap, 9961 data.bo, gc->alu, 9962 gc->bgPixel, 9963 FILL_POINTS | FILL_SPANS)) { 9964 data.phase = gc->bgPixel; 9965 miZeroDashLine(drawable, gc, mode, n, pt); 9966 fill.done(data.sna, &fill); 9967 } 9968 } 9969 } else { 9970 /* Note that the WideDash functions alternate 9971 * between filling using fgPixel and bgPixel 9972 * so we need to reset state between FillSpans and 9973 * cannot use the fill fast paths. 9974 */ 9975 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 9976 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 9977 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 9978 gc->ops = &sna_gc_ops__tmp; 9979 9980 switch (gc->lineStyle) { 9981 default: 9982 assert(0); 9983 case LineSolid: 9984 if (gc->lineWidth == 0) { 9985 DBG(("%s: miZeroLine\n", __FUNCTION__)); 9986 miZeroLine(drawable, gc, mode, n, pt); 9987 } else { 9988 DBG(("%s: miWideLine\n", __FUNCTION__)); 9989 miWideLine(drawable, gc, mode, n, pt); 9990 } 9991 break; 9992 case LineOnOffDash: 9993 case LineDoubleDash: 9994 if (gc->lineWidth == 0) { 9995 DBG(("%s: miZeroDashLine\n", __FUNCTION__)); 9996 miZeroDashLine(drawable, gc, mode, n, pt); 9997 } else { 9998 DBG(("%s: miWideDash\n", __FUNCTION__)); 9999 miWideDash(drawable, gc, mode, n, pt); 10000 } 10001 break; 10002 } 10003 } 10004 10005 gc->ops = (GCOps *)&sna_gc_ops; 10006 if (data.damage) { 10007 if (data.dx | data.dy) 10008 pixman_region_translate(&data.region, data.dx, data.dy); 10009 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10010 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 10011 assert_pixmap_damage(data.pixmap); 10012 } 10013 RegionUninit(&data.region); 10014 return; 10015 } 10016 10017fallback: 10018 DBG(("%s: fallback\n", __FUNCTION__)); 10019 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 10020 return; 10021 10022 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10023 goto out; 10024 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10025 drawable_gc_flags(drawable, gc, 10026 !(data.flags & RECTILINEAR && n == 2)))) 10027 goto out; 10028 10029 if (sigtrap_get() == 0) { 10030 DBG(("%s: fbPolyLine\n", __FUNCTION__)); 10031 fbPolyLine(drawable, gc, mode, n, pt); 10032 FALLBACK_FLUSH(drawable); 10033 sigtrap_put(); 10034 } 10035out: 10036 sna_gc_move_to_gpu(gc); 10037 RegionUninit(&data.region); 10038} 10039 10040static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc) 10041{ 10042 if (seg->x1 == seg->x2) { 10043 if (seg->y1 > seg->y2) { 10044 b->y2 = seg->y1 + 1; 10045 b->y1 = seg->y2 + 1; 10046 if (gc->capStyle != CapNotLast) 10047 b->y1--; 10048 } else { 10049 b->y1 = seg->y1; 10050 b->y2 = seg->y2; 10051 if (gc->capStyle != CapNotLast) 10052 b->y2++; 10053 } 10054 b->x1 = seg->x1; 10055 b->x2 = seg->x1 + 1; 10056 } else { 10057 if (seg->x1 > seg->x2) { 10058 b->x2 = seg->x1 + 1; 10059 b->x1 = seg->x2 + 1; 10060 if (gc->capStyle != CapNotLast) 10061 b->x1--; 10062 } else { 10063 b->x1 = seg->x1; 10064 b->x2 = seg->x2; 10065 if (gc->capStyle != CapNotLast) 10066 b->x2++; 10067 } 10068 b->y1 = seg->y1; 10069 b->y2 = seg->y1 + 1; 10070 } 10071 10072 DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n", 10073 __FUNCTION__, 10074 seg->x1, seg->y1, seg->x2, seg->y2, 10075 b->x1, b->y1, b->x2, b->y2)); 10076} 10077 10078static bool 10079sna_poly_segment_blt(DrawablePtr drawable, 10080 struct kgem_bo *bo, 10081 struct sna_damage **damage, 10082 GCPtr gc, uint32_t pixel, 10083 int n, xSegment *seg, 10084 const BoxRec *extents, unsigned clipped) 10085{ 10086 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10087 struct sna *sna = to_sna_from_pixmap(pixmap); 10088 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 10089 struct sna_fill_op fill; 10090 int16_t dx, dy; 10091 10092 DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n", 10093 __FUNCTION__, n, gc->alu, gc->fgPixel, clipped)); 10094 10095 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 10096 return false; 10097 10098 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10099 10100 if (!clipped) { 10101 dx += drawable->x; 10102 dy += drawable->y; 10103 if (dx|dy) { 10104 do { 10105 unsigned nbox = n; 10106 if (nbox > ARRAY_SIZE(boxes)) 10107 nbox = ARRAY_SIZE(boxes); 10108 n -= nbox; 10109 do { 10110 box_from_seg(b, seg++, gc); 10111 if (b->y2 > b->y1 && b->x2 > b->x1) { 10112 b->x1 += dx; 10113 b->x2 += dx; 10114 b->y1 += dy; 10115 b->y2 += dy; 10116 b++; 10117 } 10118 } while (--nbox); 10119 10120 if (b != boxes) { 10121 fill.boxes(sna, &fill, boxes, b-boxes); 10122 if (damage) 10123 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10124 b = boxes; 10125 } 10126 } while (n); 10127 } else { 10128 do { 10129 unsigned nbox = n; 10130 if (nbox > ARRAY_SIZE(boxes)) 10131 nbox = ARRAY_SIZE(boxes); 10132 n -= nbox; 10133 do { 10134 box_from_seg(b++, seg++, gc); 10135 } while (--nbox); 10136 10137 if (b != boxes) { 10138 fill.boxes(sna, &fill, boxes, b-boxes); 10139 if (damage) 10140 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10141 b = boxes; 10142 } 10143 } while (n); 10144 } 10145 } else { 10146 RegionRec clip; 10147 10148 region_set(&clip, extents); 10149 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10150 goto done; 10151 10152 if (clip.data) { 10153 const BoxRec * const clip_start = RegionBoxptr(&clip); 10154 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10155 const BoxRec *c; 10156 do { 10157 BoxRec box; 10158 10159 box_from_seg(&box, seg++, gc); 10160 box.x1 += drawable->x; 10161 box.x2 += drawable->x; 10162 box.y1 += drawable->y; 10163 box.y2 += drawable->y; 10164 c = find_clip_box_for_y(clip_start, 10165 clip_end, 10166 box.y1); 10167 while (c != clip_end) { 10168 if (box.y2 <= c->y1) 10169 break; 10170 10171 *b = box; 10172 if (box_intersect(b, c++)) { 10173 b->x1 += dx; 10174 b->x2 += dx; 10175 b->y1 += dy; 10176 b->y2 += dy; 10177 if (++b == last_box) { 10178 fill.boxes(sna, &fill, boxes, last_box-boxes); 10179 if (damage) 10180 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10181 b = boxes; 10182 } 10183 } 10184 } 10185 } while (--n); 10186 } else { 10187 do { 10188 box_from_seg(b, seg++, gc); 10189 b->x1 += drawable->x; 10190 b->x2 += drawable->x; 10191 b->y1 += drawable->y; 10192 b->y2 += drawable->y; 10193 if (box_intersect(b, &clip.extents)) { 10194 b->x1 += dx; 10195 b->x2 += dx; 10196 b->y1 += dy; 10197 b->y2 += dy; 10198 if (++b == last_box) { 10199 fill.boxes(sna, &fill, boxes, last_box-boxes); 10200 if (damage) 10201 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10202 b = boxes; 10203 } 10204 } 10205 } while (--n); 10206 } 10207 RegionUninit(&clip); 10208 } 10209 if (b != boxes) { 10210 fill.boxes(sna, &fill, boxes, b - boxes); 10211 if (damage) 10212 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 10213 } 10214done: 10215 fill.done(sna, &fill); 10216 assert_pixmap_damage(pixmap); 10217 return true; 10218} 10219 10220static bool 10221sna_poly_zero_segment_blt(DrawablePtr drawable, 10222 struct kgem_bo *bo, 10223 struct sna_damage **damage, 10224 GCPtr gc, const int _n, const xSegment *_s, 10225 const BoxRec *extents, unsigned clipped) 10226{ 10227 static void * const _jump[] = { 10228 &&no_damage, 10229 &&damage, 10230 10231 &&no_damage_offset, 10232 &&damage_offset, 10233 }; 10234 10235 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10236 struct sna *sna = to_sna_from_pixmap(pixmap); 10237 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 10238 struct sna_fill_op fill; 10239 RegionRec clip; 10240 const BoxRec *last_extents; 10241 BoxRec box[512], *b; 10242 BoxRec *const last_box = box + ARRAY_SIZE(box); 10243 int16_t dx, dy; 10244 void *jump, *ret; 10245 10246 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 10247 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 10248 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10249 return false; 10250 10251 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10252 10253 region_set(&clip, extents); 10254 if (clipped) { 10255 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10256 return true; 10257 } 10258 DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n", 10259 __FUNCTION__, 10260 clip.extents.x1, clip.extents.y1, 10261 clip.extents.x2, clip.extents.y2, 10262 dx, dy)); 10263 10264 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 10265 10266 b = box; 10267 extents = region_rects(&clip); 10268 last_extents = extents + region_num_rects(&clip); 10269 do { 10270 int n = _n; 10271 const xSegment *s = _s; 10272 do { 10273 int16_t sdx, sdy; 10274 int adx, ady, length; 10275 int e, e1, e2, e3; 10276 int x1, x2; 10277 int y1, y2; 10278 int oc1, oc2; 10279 int octant; 10280 10281 x1 = s->x1 + drawable->x; 10282 y1 = s->y1 + drawable->y; 10283 x2 = s->x2 + drawable->x; 10284 y2 = s->y2 + drawable->y; 10285 s++; 10286 10287 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 10288 __FUNCTION__, x1, y1, x2, y2)); 10289 if (x2 == x1 && y2 == y1) 10290 continue; 10291 10292 oc1 = 0; 10293 OUTCODES(oc1, x1, y1, extents); 10294 oc2 = 0; 10295 OUTCODES(oc2, x2, y2, extents); 10296 if (oc1 & oc2) 10297 continue; 10298 10299 CalcLineDeltas(x1, y1, x2, y2, 10300 adx, ady, sdx, sdy, 10301 1, 1, octant); 10302 10303 DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n", 10304 __FUNCTION__, adx, ady, sdx, sdy)); 10305 if (adx == 0 || ady == 0) { 10306 if (x1 <= x2) { 10307 b->x1 = x1; 10308 b->x2 = x2; 10309 } else { 10310 b->x1 = x2; 10311 b->x2 = x1; 10312 } 10313 if (y1 <= y2) { 10314 b->y1 = y1; 10315 b->y2 = y2; 10316 } else { 10317 b->y1 = y2; 10318 b->y2 = y1; 10319 } 10320 b->x2++; 10321 b->y2++; 10322 if (oc1 | oc2) 10323 box_intersect(b, extents); 10324 if (++b == last_box) { 10325 ret = &&rectangle_continue; 10326 goto *jump; 10327rectangle_continue: 10328 b = box; 10329 } 10330 } else if (adx >= ady) { 10331 bool dirty; 10332 10333 /* X-major segment */ 10334 e1 = ady << 1; 10335 e2 = e1 - (adx << 1); 10336 e = e1 - adx; 10337 length = adx; /* don't draw endpoint in main loop */ 10338 10339 FIXUP_ERROR(e, octant, bias); 10340 10341 if (oc1 | oc2) { 10342 int pt1_clipped, pt2_clipped; 10343 int x = x1, y = y1; 10344 10345 if (miZeroClipLine(extents->x1, extents->y1, 10346 extents->x2-1, extents->y2-1, 10347 &x1, &y1, &x2, &y2, 10348 adx, ady, 10349 &pt1_clipped, &pt2_clipped, 10350 octant, bias, oc1, oc2) == -1) 10351 continue; 10352 10353 length = abs(x2 - x1); 10354 if (length == 0) 10355 continue; 10356 10357 if (pt1_clipped) { 10358 int clipdx = abs(x1 - x); 10359 int clipdy = abs(y1 - y); 10360 e += clipdy * e2 + (clipdx - clipdy) * e1; 10361 } 10362 } 10363 e3 = e2 - e1; 10364 e = e - e1; 10365 10366 b->x1 = x1; 10367 b->y1 = y1; 10368 dirty = false; 10369 while (length--) { 10370 dirty = true; 10371 e += e1; 10372 if (e >= 0) { 10373 e += e3; 10374 10375 if (sdx < 0) { 10376 b->x2 = b->x1 + 1; 10377 b->x1 = x1; 10378 } else 10379 b->x2 = x1 + 1; 10380 b->y2 = b->y1 + 1; 10381 10382 DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n", 10383 __FUNCTION__, x1, y1, 10384 b->x1, b->y1, b->x2, b->y2)); 10385 10386 if (++b == last_box) { 10387 ret = &&X_continue; 10388 goto *jump; 10389X_continue: 10390 b = box; 10391 } 10392 10393 b->x1 = x1 + sdx; 10394 b->y1 = y1 += sdy; 10395 dirty = false; 10396 } 10397 x1 += sdx; 10398 } 10399 if (dirty) { 10400 x1 -= sdx; 10401 DBG(("%s: horizontal tail: (%d, %d)\n", 10402 __FUNCTION__, x1, y1)); 10403 if (sdx < 0) { 10404 b->x2 = b->x1 + 1; 10405 b->x1 = x1; 10406 } else 10407 b->x2 = x1 + 1; 10408 b->y2 = b->y1 + 1; 10409 10410 if (++b == last_box) { 10411 ret = &&X2_continue; 10412 goto *jump; 10413X2_continue: 10414 b = box; 10415 } 10416 } 10417 } else { 10418 bool dirty; 10419 10420 /* Y-major segment */ 10421 e1 = adx << 1; 10422 e2 = e1 - (ady << 1); 10423 e = e1 - ady; 10424 length = ady; /* don't draw endpoint in main loop */ 10425 10426 SetYMajorOctant(octant); 10427 FIXUP_ERROR(e, octant, bias); 10428 10429 if (oc1 | oc2) { 10430 int pt1_clipped, pt2_clipped; 10431 int x = x1, y = y1; 10432 10433 if (miZeroClipLine(extents->x1, extents->y1, 10434 extents->x2-1, extents->y2-1, 10435 &x1, &y1, &x2, &y2, 10436 adx, ady, 10437 &pt1_clipped, &pt2_clipped, 10438 octant, bias, oc1, oc2) == -1) 10439 continue; 10440 10441 length = abs(y2 - y1); 10442 if (length == 0) 10443 continue; 10444 10445 if (pt1_clipped) { 10446 int clipdx = abs(x1 - x); 10447 int clipdy = abs(y1 - y); 10448 e += clipdx * e2 + (clipdy - clipdx) * e1; 10449 } 10450 } 10451 10452 e3 = e2 - e1; 10453 e = e - e1; 10454 10455 b->x1 = x1; 10456 b->y1 = y1; 10457 dirty = false; 10458 while (length--) { 10459 e += e1; 10460 dirty = true; 10461 if (e >= 0) { 10462 e += e3; 10463 10464 if (sdy < 0) { 10465 b->y2 = b->y1 + 1; 10466 b->y1 = y1; 10467 } else 10468 b->y2 = y1 + 1; 10469 b->x2 = x1 + 1; 10470 10471 if (++b == last_box) { 10472 ret = &&Y_continue; 10473 goto *jump; 10474Y_continue: 10475 b = box; 10476 } 10477 10478 b->x1 = x1 += sdx; 10479 b->y1 = y1 + sdy; 10480 dirty = false; 10481 } 10482 y1 += sdy; 10483 } 10484 10485 if (dirty) { 10486 y1 -= sdy; 10487 if (sdy < 0) { 10488 b->y2 = b->y1 + 1; 10489 b->y1 = y1; 10490 } else 10491 b->y2 = y1 + 1; 10492 b->x2 = x1 + 1; 10493 10494 if (++b == last_box) { 10495 ret = &&Y2_continue; 10496 goto *jump; 10497Y2_continue: 10498 b = box; 10499 } 10500 } 10501 } 10502 } while (--n); 10503 } while (++extents != last_extents); 10504 10505 if (b != box) { 10506 ret = &&done; 10507 goto *jump; 10508 } 10509 10510done: 10511 fill.done(sna, &fill); 10512 assert_pixmap_damage(pixmap); 10513 RegionUninit(&clip); 10514 return true; 10515 10516damage: 10517 sna_damage_add_boxes(damage, box, b-box, 0, 0); 10518no_damage: 10519 fill.boxes(sna, &fill, box, b-box); 10520 goto *ret; 10521 10522no_damage_offset: 10523 { 10524 BoxRec *bb = box; 10525 do { 10526 bb->x1 += dx; 10527 bb->x2 += dx; 10528 bb->y1 += dy; 10529 bb->y2 += dy; 10530 } while (++bb != b); 10531 fill.boxes(sna, &fill, box, b - box); 10532 } 10533 goto *ret; 10534 10535damage_offset: 10536 { 10537 BoxRec *bb = box; 10538 do { 10539 bb->x1 += dx; 10540 bb->x2 += dx; 10541 bb->y1 += dy; 10542 bb->y2 += dy; 10543 } while (++bb != b); 10544 fill.boxes(sna, &fill, box, b - box); 10545 sna_damage_add_boxes(damage, box, b - box, 0, 0); 10546 } 10547 goto *ret; 10548} 10549 10550static unsigned 10551sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc, 10552 int n, xSegment *seg, 10553 BoxPtr out) 10554{ 10555 BoxRec box; 10556 bool clipped, can_blit; 10557 10558 if (n == 0) 10559 return 0; 10560 10561 if (seg->x2 >= seg->x1) { 10562 box.x1 = seg->x1; 10563 box.x2 = seg->x2; 10564 } else { 10565 box.x2 = seg->x1; 10566 box.x1 = seg->x2; 10567 } 10568 10569 if (seg->y2 >= seg->y1) { 10570 box.y1 = seg->y1; 10571 box.y2 = seg->y2; 10572 } else { 10573 box.y2 = seg->y1; 10574 box.y1 = seg->y2; 10575 } 10576 10577 can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2; 10578 while (--n) { 10579 seg++; 10580 if (seg->x2 > seg->x1) { 10581 if (seg->x1 < box.x1) box.x1 = seg->x1; 10582 if (seg->x2 > box.x2) box.x2 = seg->x2; 10583 } else { 10584 if (seg->x2 < box.x1) box.x1 = seg->x2; 10585 if (seg->x1 > box.x2) box.x2 = seg->x1; 10586 } 10587 10588 if (seg->y2 > seg->y1) { 10589 if (seg->y1 < box.y1) box.y1 = seg->y1; 10590 if (seg->y2 > box.y2) box.y2 = seg->y2; 10591 } else { 10592 if (seg->y2 < box.y1) box.y1 = seg->y2; 10593 if (seg->y1 > box.y2) box.y2 = seg->y1; 10594 } 10595 10596 if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2)) 10597 can_blit = false; 10598 } 10599 10600 box.x2++; 10601 box.y2++; 10602 10603 if (gc->lineWidth) { 10604 int extra = gc->lineWidth; 10605 if (gc->capStyle != CapProjecting) 10606 extra >>= 1; 10607 if (extra) { 10608 box.x1 -= extra; 10609 box.x2 += extra; 10610 box.y1 -= extra; 10611 box.y2 += extra; 10612 } 10613 } 10614 10615 DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n", 10616 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10617 10618 clipped = trim_and_translate_box(&box, drawable, gc); 10619 if (box_empty(&box)) 10620 return 0; 10621 10622 *out = box; 10623 return 1 | clipped << 1 | can_blit << 2; 10624} 10625 10626static void 10627sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg) 10628{ 10629 struct sna_pixmap *priv; 10630 struct sna_fill_spans data; 10631 uint32_t color; 10632 10633 DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n", 10634 __FUNCTION__, 10635 n, seg->x1, seg->y1, seg->x2, seg->y2, 10636 gc->lineWidth)); 10637 10638 data.flags = sna_poly_segment_extents(drawable, gc, n, seg, 10639 &data.region.extents); 10640 if (data.flags == 0) 10641 return; 10642 10643 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 10644 data.region.extents.x1, data.region.extents.y1, 10645 data.region.extents.x2, data.region.extents.y2)); 10646 10647 data.region.data = NULL; 10648 10649 if (FORCE_FALLBACK) 10650 goto fallback; 10651 10652 if (!ACCEL_POLY_SEGMENT) 10653 goto fallback; 10654 10655 data.pixmap = get_drawable_pixmap(drawable); 10656 data.sna = to_sna_from_pixmap(data.pixmap); 10657 priv = sna_pixmap(data.pixmap); 10658 if (priv == NULL) { 10659 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10660 goto fallback; 10661 } 10662 10663 if (wedged(data.sna)) { 10664 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10665 goto fallback; 10666 } 10667 10668 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 10669 __FUNCTION__, 10670 gc->fillStyle, gc->fillStyle == FillSolid, 10671 gc->lineStyle, gc->lineStyle == LineSolid, 10672 gc->lineWidth, 10673 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 10674 data.flags & RECTILINEAR)); 10675 if (!PM_IS_SOLID(drawable, gc->planemask)) 10676 goto fallback; 10677 10678 if (gc->lineStyle != LineSolid || gc->lineWidth > 1) 10679 goto spans_fallback; 10680 10681 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 10682 &data.region.extents, 10683 &data.damage); 10684 if (data.bo == NULL) 10685 goto fallback; 10686 10687 if (gc_is_solid(gc, &color)) { 10688 DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n", 10689 __FUNCTION__, (unsigned)color, data.flags)); 10690 10691 if (data.flags & RECTILINEAR) { 10692 if (sna_poly_segment_blt(drawable, 10693 data.bo, data.damage, 10694 gc, color, n, seg, 10695 &data.region.extents, 10696 data.flags & IS_CLIPPED)) 10697 return; 10698 } else { 10699 if (sna_poly_zero_segment_blt(drawable, 10700 data.bo, data.damage, 10701 gc, n, seg, 10702 &data.region.extents, 10703 data.flags & IS_CLIPPED)) 10704 return; 10705 } 10706 } else if (data.flags & RECTILINEAR) { 10707 /* Try converting these to a set of rectangles instead */ 10708 xRectangle *rect; 10709 int i; 10710 10711 DBG(("%s: converting to rectangles\n", __FUNCTION__)); 10712 10713 rect = malloc (n * sizeof (xRectangle)); 10714 if (rect == NULL) 10715 return; 10716 10717 for (i = 0; i < n; i++) { 10718 if (seg[i].x1 < seg[i].x2) { 10719 rect[i].x = seg[i].x1; 10720 rect[i].width = seg[i].x2 - seg[i].x1 + 1; 10721 } else if (seg[i].x1 > seg[i].x2) { 10722 rect[i].x = seg[i].x2; 10723 rect[i].width = seg[i].x1 - seg[i].x2 + 1; 10724 } else { 10725 rect[i].x = seg[i].x1; 10726 rect[i].width = 1; 10727 } 10728 if (seg[i].y1 < seg[i].y2) { 10729 rect[i].y = seg[i].y1; 10730 rect[i].height = seg[i].y2 - seg[i].y1 + 1; 10731 } else if (seg[i].y1 > seg[i].y2) { 10732 rect[i].y = seg[i].y2; 10733 rect[i].height = seg[i].y1 - seg[i].y2 + 1; 10734 } else { 10735 rect[i].y = seg[i].y1; 10736 rect[i].height = 1; 10737 } 10738 10739 /* don't paint last pixel */ 10740 if (gc->capStyle == CapNotLast) { 10741 if (seg[i].x1 == seg[i].x2) 10742 rect[i].height--; 10743 else 10744 rect[i].width--; 10745 } 10746 } 10747 10748 if (gc->fillStyle == FillTiled) { 10749 i = sna_poly_fill_rect_tiled_blt(drawable, 10750 data.bo, data.damage, 10751 gc, n, rect, 10752 &data.region.extents, 10753 data.flags); 10754 } else { 10755 i = sna_poly_fill_rect_stippled_blt(drawable, 10756 data.bo, data.damage, 10757 gc, n, rect, 10758 &data.region.extents, 10759 data.flags); 10760 } 10761 free (rect); 10762 10763 if (i) 10764 return; 10765 } 10766 10767spans_fallback: 10768 if ((data.bo = sna_drawable_use_bo(drawable, 10769 use_line_spans(drawable, gc, &data.region.extents, data.flags), 10770 &data.region.extents, 10771 &data.damage))) { 10772 void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr); 10773 int i; 10774 10775 DBG(("%s: converting segments into spans\n", __FUNCTION__)); 10776 10777 switch (gc->lineStyle) { 10778 default: 10779 case LineSolid: 10780 if (gc->lineWidth == 0) 10781 line = miZeroLine; 10782 else 10783 line = miWideLine; 10784 break; 10785 case LineOnOffDash: 10786 case LineDoubleDash: 10787 if (gc->lineWidth == 0) 10788 line = miZeroDashLine; 10789 else 10790 line = miWideDash; 10791 break; 10792 } 10793 10794 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10795 sna_gc(gc)->priv = &data; 10796 10797 if (gc->lineWidth == 0 && 10798 gc->lineStyle == LineSolid && 10799 gc_is_solid(gc, &color)) { 10800 struct sna_fill_op fill; 10801 10802 if (!sna_fill_init_blt(&fill, 10803 data.sna, data.pixmap, 10804 data.bo, gc->alu, color, 10805 FILL_POINTS | FILL_SPANS)) 10806 goto fallback; 10807 10808 data.op = &fill; 10809 10810 if ((data.flags & IS_CLIPPED) == 0) { 10811 if (data.dx | data.dy) 10812 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10813 else 10814 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10815 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10816 } else { 10817 if (!region_maybe_clip(&data.region, 10818 gc->pCompositeClip)) 10819 return; 10820 10821 if (region_is_singular(&data.region)) { 10822 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10823 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10824 } else { 10825 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10826 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10827 } 10828 } 10829 assert(gc->miTranslate); 10830 gc->ops = &sna_gc_ops__tmp; 10831 for (i = 0; i < n; i++) 10832 line(drawable, gc, CoordModeOrigin, 2, 10833 (DDXPointPtr)&seg[i]); 10834 10835 fill.done(data.sna, &fill); 10836 } else { 10837 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10838 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 10839 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 10840 gc->ops = &sna_gc_ops__tmp; 10841 10842 for (i = 0; i < n; i++) 10843 line(drawable, gc, CoordModeOrigin, 2, 10844 (DDXPointPtr)&seg[i]); 10845 } 10846 10847 gc->ops = (GCOps *)&sna_gc_ops; 10848 if (data.damage) { 10849 if (data.dx | data.dy) 10850 pixman_region_translate(&data.region, data.dx, data.dy); 10851 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10852 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 10853 } 10854 assert_pixmap_damage(data.pixmap); 10855 RegionUninit(&data.region); 10856 return; 10857 } 10858 10859fallback: 10860 DBG(("%s: fallback\n", __FUNCTION__)); 10861 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 10862 return; 10863 10864 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10865 goto out; 10866 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10867 drawable_gc_flags(drawable, gc, 10868 !(data.flags & RECTILINEAR && n == 1)))) 10869 goto out; 10870 10871 if (sigtrap_get() == 0) { 10872 DBG(("%s: fbPolySegment\n", __FUNCTION__)); 10873 fbPolySegment(drawable, gc, n, seg); 10874 FALLBACK_FLUSH(drawable); 10875 sigtrap_put(); 10876 } 10877out: 10878 sna_gc_move_to_gpu(gc); 10879 RegionUninit(&data.region); 10880} 10881 10882static unsigned 10883sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, 10884 int n, xRectangle *r, 10885 BoxPtr out) 10886{ 10887 Box32Rec box; 10888 int extra = gc->lineWidth >> 1; 10889 bool clipped; 10890 bool zero = false; 10891 10892 if (n == 0) 10893 return 0; 10894 10895 box.x1 = r->x; 10896 box.y1 = r->y; 10897 box.x2 = box.x1 + r->width; 10898 box.y2 = box.y1 + r->height; 10899 zero |= (r->width | r->height) == 0; 10900 10901 while (--n) { 10902 r++; 10903 zero |= (r->width | r->height) == 0; 10904 box32_add_rect(&box, r); 10905 } 10906 10907 box.x2++; 10908 box.y2++; 10909 10910 if (extra) { 10911 box.x1 -= extra; 10912 box.x2 += extra; 10913 box.y1 -= extra; 10914 box.y2 += extra; 10915 zero = !zero; 10916 } else 10917 zero = true; 10918 10919 DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n", 10920 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10921 clipped = box32_trim_and_translate(&box, drawable, gc); 10922 if (!box32_to_box16(&box, out)) 10923 return 0; 10924 10925 DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n", 10926 __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped)); 10927 return 1 | clipped << 1 | zero << 2; 10928} 10929 10930static bool 10931sna_poly_rectangle_blt(DrawablePtr drawable, 10932 struct kgem_bo *bo, 10933 struct sna_damage **damage, 10934 GCPtr gc, int n, xRectangle *r, 10935 const BoxRec *extents, unsigned clipped) 10936{ 10937 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10938 struct sna *sna = to_sna_from_pixmap(pixmap); 10939 struct sna_fill_op fill; 10940 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 10941 int16_t dx, dy; 10942 static void * const jump[] = { 10943 &&wide, 10944 &&zero, 10945 &&wide_clipped, 10946 &&zero_clipped, 10947 }; 10948 10949 DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", 10950 __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); 10951 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10952 return false; 10953 10954 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10955 10956 goto *jump[(gc->lineWidth <= 1) | clipped]; 10957 10958zero: 10959 dx += drawable->x; 10960 dy += drawable->y; 10961 10962 do { 10963 xRectangle rr = *r++; 10964 10965 if ((rr.width | rr.height) == 0) 10966 continue; /* XXX -> PolyLine */ 10967 10968 DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 10969 n, rr.x, rr.y, rr.width, rr.height)); 10970 rr.x += dx; 10971 rr.y += dy; 10972 10973 if (b+4 > last_box) { 10974 fill.boxes(sna, &fill, boxes, b-boxes); 10975 if (damage) 10976 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10977 b = boxes; 10978 } 10979 10980 if (rr.width <= 1 || rr.height <= 1) { 10981 b->x1 = rr.x; 10982 b->y1 = rr.y; 10983 b->x2 = rr.x + rr.width + (rr.height != 0); 10984 b->y2 = rr.y + rr.height + (rr.width != 0); 10985 DBG(("%s: blt (%d, %d), (%d, %d)\n", 10986 __FUNCTION__, 10987 b->x1, b->y1, b->x2,b->y2)); 10988 b++; 10989 } else { 10990 b[0].x1 = rr.x; 10991 b[0].y1 = rr.y; 10992 b[0].x2 = rr.x + rr.width + 1; 10993 b[0].y2 = rr.y + 1; 10994 10995 b[1] = b[0]; 10996 b[1].y1 += rr.height; 10997 b[1].y2 += rr.height; 10998 10999 b[2].y1 = rr.y + 1; 11000 b[2].y2 = rr.y + rr.height; 11001 b[2].x1 = rr.x; 11002 b[2].x2 = rr.x + 1; 11003 11004 b[3] = b[2]; 11005 b[3].x1 += rr.width; 11006 b[3].x2 += rr.width; 11007 11008 b += 4; 11009 } 11010 } while (--n); 11011 goto done; 11012 11013zero_clipped: 11014 { 11015 RegionRec clip; 11016 BoxRec box[4]; 11017 int count; 11018 11019 region_set(&clip, extents); 11020 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11021 goto done; 11022 11023 if (clip.data) { 11024 const BoxRec * const clip_start = RegionBoxptr(&clip); 11025 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11026 const BoxRec *c; 11027 do { 11028 xRectangle rr = *r++; 11029 11030 DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11031 n, rr.x, rr.y, rr.width, rr.height)); 11032 11033 if ((rr.width | rr.height) == 0) 11034 continue; /* XXX -> PolyLine */ 11035 11036 rr.x += drawable->x; 11037 rr.y += drawable->y; 11038 11039 if (rr.width <= 1 || rr.height <= 1) { 11040 box[0].x1 = rr.x; 11041 box[0].y1 = rr.y; 11042 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11043 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11044 count = 1; 11045 } else { 11046 box[0].x1 = rr.x; 11047 box[0].y1 = rr.y; 11048 box[0].x2 = rr.x + rr.width + 1; 11049 box[0].y2 = rr.y + 1; 11050 11051 box[1] = box[0]; 11052 box[1].y1 += rr.height; 11053 box[1].y2 += rr.height; 11054 11055 box[2].y1 = rr.y + 1; 11056 box[2].y2 = rr.y + rr.height; 11057 box[2].x1 = rr.x; 11058 box[2].x2 = rr.x + 1; 11059 11060 box[3] = box[2]; 11061 box[3].x1 += rr.width; 11062 box[3].x2 += rr.width; 11063 count = 4; 11064 } 11065 11066 while (count--) { 11067 c = find_clip_box_for_y(clip_start, 11068 clip_end, 11069 box[count].y1); 11070 while (c != clip_end) { 11071 if (box[count].y2 <= c->y1) 11072 break; 11073 11074 *b = box[count]; 11075 if (box_intersect(b, c++)) { 11076 b->x1 += dx; 11077 b->x2 += dx; 11078 b->y1 += dy; 11079 b->y2 += dy; 11080 if (++b == last_box) { 11081 fill.boxes(sna, &fill, boxes, last_box-boxes); 11082 if (damage) 11083 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11084 b = boxes; 11085 } 11086 } 11087 11088 } 11089 } 11090 } while (--n); 11091 } else { 11092 do { 11093 xRectangle rr = *r++; 11094 DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11095 n, rr.x, rr.y, rr.width, rr.height)); 11096 11097 if ((rr.width | rr.height) == 0) 11098 continue; /* XXX -> PolyLine */ 11099 11100 rr.x += drawable->x; 11101 rr.y += drawable->y; 11102 11103 if (rr.width <= 1 || rr.height <= 1) { 11104 box[0].x1 = rr.x; 11105 box[0].y1 = rr.y; 11106 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11107 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11108 count = 1; 11109 } else { 11110 box[0].x1 = rr.x; 11111 box[0].y1 = rr.y; 11112 box[0].x2 = rr.x + rr.width + 1; 11113 box[0].y2 = rr.y + 1; 11114 11115 box[1] = box[0]; 11116 box[1].y1 += rr.height; 11117 box[1].y2 += rr.height; 11118 11119 box[2].y1 = rr.y + 1; 11120 box[2].y2 = rr.y + rr.height; 11121 box[2].x1 = rr.x; 11122 box[2].x2 = rr.x + 1; 11123 11124 box[3] = box[2]; 11125 box[3].x1 += rr.width; 11126 box[3].x2 += rr.width; 11127 count = 4; 11128 } 11129 11130 while (count--) { 11131 *b = box[count]; 11132 if (box_intersect(b, &clip.extents)) { 11133 b->x1 += dx; 11134 b->x2 += dx; 11135 b->y1 += dy; 11136 b->y2 += dy; 11137 if (++b == last_box) { 11138 fill.boxes(sna, &fill, boxes, last_box-boxes); 11139 if (damage) 11140 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11141 b = boxes; 11142 } 11143 } 11144 11145 } 11146 } while (--n); 11147 } 11148 RegionUninit(&clip); 11149 } 11150 goto done; 11151 11152wide_clipped: 11153 { 11154 RegionRec clip; 11155 BoxRec box[4]; 11156 int16_t offset2 = gc->lineWidth; 11157 int16_t offset1 = offset2 >> 1; 11158 int16_t offset3 = offset2 - offset1; 11159 11160 region_set(&clip, extents); 11161 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11162 goto done; 11163 11164 DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n", 11165 __FUNCTION__, 11166 clip.extents.x1, clip.extents.y1, 11167 clip.extents.x2, clip.extents.y2)); 11168 11169 if (clip.data) { 11170 const BoxRec * const clip_start = RegionBoxptr(&clip); 11171 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11172 const BoxRec *c; 11173 do { 11174 xRectangle rr = *r++; 11175 int count; 11176 11177 if ((rr.width | rr.height) == 0) 11178 continue; /* XXX -> PolyLine */ 11179 11180 rr.x += drawable->x; 11181 rr.y += drawable->y; 11182 11183 if (rr.height <= offset2 || rr.width <= offset2) { 11184 if (rr.height == 0) { 11185 box[0].x1 = rr.x; 11186 box[0].x2 = rr.x + rr.width; 11187 } else { 11188 box[0].x1 = rr.x - offset1; 11189 box[0].x2 = rr.x + rr.width + offset3; 11190 } 11191 if (rr.width == 0) { 11192 box[0].y1 = rr.y; 11193 box[0].y2 = rr.y + rr.height; 11194 } else { 11195 box[0].y1 = rr.y - offset1; 11196 box[0].y2 = rr.y + rr.height + offset3; 11197 } 11198 count = 1; 11199 } else { 11200 box[0].x1 = rr.x - offset1; 11201 box[0].x2 = box[0].x1 + rr.width + offset2; 11202 box[0].y1 = rr.y - offset1; 11203 box[0].y2 = box[0].y1 + offset2; 11204 11205 box[1].x1 = rr.x - offset1; 11206 box[1].x2 = box[1].x1 + offset2; 11207 box[1].y1 = rr.y + offset3; 11208 box[1].y2 = rr.y + rr.height - offset1; 11209 11210 box[2] = box[1]; 11211 box[2].x1 += rr.width; 11212 box[2].x2 += rr.width; 11213 11214 box[3] = box[0]; 11215 box[3].y1 += rr.height; 11216 box[3].y2 += rr.height; 11217 count = 4; 11218 } 11219 11220 while (count--) { 11221 c = find_clip_box_for_y(clip_start, 11222 clip_end, 11223 box[count].y1); 11224 while (c != clip_end) { 11225 if (box[count].y2 <= c->y1) 11226 break; 11227 11228 *b = box[count]; 11229 if (box_intersect(b, c++)) { 11230 b->x1 += dx; 11231 b->x2 += dx; 11232 b->y1 += dy; 11233 b->y2 += dy; 11234 if (++b == last_box) { 11235 fill.boxes(sna, &fill, boxes, last_box-boxes); 11236 if (damage) 11237 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11238 b = boxes; 11239 } 11240 } 11241 } 11242 } 11243 } while (--n); 11244 } else { 11245 DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n", 11246 __FUNCTION__, offset1, offset2, offset3)); 11247 do { 11248 xRectangle rr = *r++; 11249 int count; 11250 rr.x += drawable->x; 11251 rr.y += drawable->y; 11252 11253 DBG(("%s: r=(%d, %d)x(%d, %d)\n", 11254 __FUNCTION__, rr.x, rr.y, rr.width, rr.height)); 11255 if (rr.height <= offset2 || rr.width <= offset2) { 11256 if (rr.height == 0) { 11257 box[0].x1 = rr.x; 11258 box[0].x2 = rr.x + rr.width; 11259 } else { 11260 box[0].x1 = rr.x - offset1; 11261 box[0].x2 = box[0].x1 + rr.width + offset2; 11262 } 11263 if (rr.width == 0) { 11264 box[0].y1 = rr.y; 11265 box[0].y2 = rr.y + rr.height; 11266 } else { 11267 box[0].y1 = rr.y - offset1; 11268 box[0].y2 = box[0].y1 + rr.height + offset2; 11269 } 11270 count = 1; 11271 } else { 11272 box[0].x1 = rr.x - offset1; 11273 box[0].x2 = box[0].x1 + rr.width + offset2; 11274 box[0].y1 = rr.y - offset1; 11275 box[0].y2 = box[0].y1 + offset2; 11276 DBG(("%s: box[0]=(%d, %d), (%d, %d)\n", 11277 __FUNCTION__, 11278 box[0].x1, box[0].y1, 11279 box[0].x2, box[0].y2)); 11280 11281 box[1].x1 = rr.x - offset1; 11282 box[1].x2 = box[1].x1 + offset2; 11283 box[1].y1 = rr.y + offset3; 11284 box[1].y2 = rr.y + rr.height - offset1; 11285 DBG(("%s: box[1]=(%d, %d), (%d, %d)\n", 11286 __FUNCTION__, 11287 box[1].x1, box[1].y1, 11288 box[1].x2, box[1].y2)); 11289 11290 box[2] = box[1]; 11291 box[2].x1 += rr.width; 11292 box[2].x2 += rr.width; 11293 DBG(("%s: box[2]=(%d, %d), (%d, %d)\n", 11294 __FUNCTION__, 11295 box[2].x1, box[2].y1, 11296 box[2].x2, box[2].y2)); 11297 11298 box[3] = box[0]; 11299 box[3].y1 += rr.height; 11300 box[3].y2 += rr.height; 11301 DBG(("%s: box[3]=(%d, %d), (%d, %d)\n", 11302 __FUNCTION__, 11303 box[3].x1, box[3].y1, 11304 box[3].x2, box[3].y2)); 11305 11306 count = 4; 11307 } 11308 11309 while (count--) { 11310 *b = box[count]; 11311 if (box_intersect(b, &clip.extents)) { 11312 b->x1 += dx; 11313 b->x2 += dx; 11314 b->y1 += dy; 11315 b->y2 += dy; 11316 if (++b == last_box) { 11317 fill.boxes(sna, &fill, boxes, last_box-boxes); 11318 if (damage) 11319 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11320 b = boxes; 11321 } 11322 } 11323 } 11324 } while (--n); 11325 } 11326 RegionUninit(&clip); 11327 } 11328 goto done; 11329 11330wide: 11331 { 11332 int offset2 = gc->lineWidth; 11333 int offset1 = offset2 >> 1; 11334 int offset3 = offset2 - offset1; 11335 11336 dx += drawable->x; 11337 dy += drawable->y; 11338 11339 do { 11340 xRectangle rr = *r++; 11341 11342 if ((rr.width | rr.height) == 0) 11343 continue; /* XXX -> PolyLine */ 11344 11345 rr.x += dx; 11346 rr.y += dy; 11347 11348 if (b+4 > last_box) { 11349 fill.boxes(sna, &fill, boxes, last_box-boxes); 11350 if (damage) 11351 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11352 b = boxes; 11353 } 11354 11355 if (rr.height <= offset2 || rr.width <= offset2) { 11356 if (rr.height == 0) { 11357 b->x1 = rr.x; 11358 b->x2 = rr.x + rr.width; 11359 } else { 11360 b->x1 = rr.x - offset1; 11361 b->x2 = rr.x + rr.width + offset3; 11362 } 11363 if (rr.width == 0) { 11364 b->y1 = rr.y; 11365 b->y2 = rr.y + rr.height; 11366 } else { 11367 b->y1 = rr.y - offset1; 11368 b->y2 = rr.y + rr.height + offset3; 11369 } 11370 b++; 11371 } else { 11372 b[0].x1 = rr.x - offset1; 11373 b[0].x2 = b[0].x1 + rr.width + offset2; 11374 b[0].y1 = rr.y - offset1; 11375 b[0].y2 = b[0].y1 + offset2; 11376 11377 b[1].x1 = rr.x - offset1; 11378 b[1].x2 = b[1].x1 + offset2; 11379 b[1].y1 = rr.y + offset3; 11380 b[1].y2 = rr.y + rr.height - offset1; 11381 11382 b[2] = b[1]; 11383 b[2].x1 += rr.width; 11384 b[2].x2 += rr.width; 11385 11386 b[3] = b[0]; 11387 b[3].y1 += rr.height; 11388 b[3].y2 += rr.height; 11389 b += 4; 11390 } 11391 } while (--n); 11392 } 11393 goto done; 11394 11395done: 11396 if (b != boxes) { 11397 fill.boxes(sna, &fill, boxes, b-boxes); 11398 if (damage) 11399 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11400 } 11401 fill.done(sna, &fill); 11402 assert_pixmap_damage(pixmap); 11403 return true; 11404} 11405 11406static void 11407sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) 11408{ 11409 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11410 struct sna *sna = to_sna_from_pixmap(pixmap); 11411 struct sna_damage **damage; 11412 struct kgem_bo *bo; 11413 RegionRec region; 11414 unsigned flags; 11415 11416 DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", 11417 __FUNCTION__, 11418 n, r->x, r->y, r->width, r->height, 11419 gc->lineWidth)); 11420 11421 flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); 11422 if (flags == 0) 11423 return; 11424 11425 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11426 region.extents.x1, region.extents.y1, 11427 region.extents.x2, region.extents.y2, 11428 flags)); 11429 11430 if (FORCE_FALLBACK) 11431 goto fallback; 11432 11433 if (!ACCEL_POLY_RECTANGLE) 11434 goto fallback; 11435 11436 if (wedged(sna)) { 11437 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11438 goto fallback; 11439 } 11440 11441 DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n", 11442 __FUNCTION__, 11443 gc->fillStyle, gc->fillStyle == FillSolid, 11444 gc->lineStyle, gc->lineStyle == LineSolid, 11445 gc->joinStyle, gc->joinStyle == JoinMiter, 11446 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 11447 11448 if (!PM_IS_SOLID(drawable, gc->planemask)) 11449 goto fallback; 11450 11451 if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) { 11452 DBG(("%s: trying blt solid fill [%08lx] paths\n", 11453 __FUNCTION__, gc->fgPixel)); 11454 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11455 ®ion.extents, &damage)) && 11456 sna_poly_rectangle_blt(drawable, bo, damage, 11457 gc, n, r, ®ion.extents, flags&2)) 11458 return; 11459 } else { 11460 /* Not a trivial outline, but we still maybe able to break it 11461 * down into simpler operations that we can accelerate. 11462 */ 11463 if (sna_drawable_use_bo(drawable, PREFER_GPU, 11464 ®ion.extents, &damage)) { 11465 miPolyRectangle(drawable, gc, n, r); 11466 return; 11467 } 11468 } 11469 11470fallback: 11471 DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11472 region_num_rects(gc->pCompositeClip), 11473 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 11474 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2)); 11475 11476 region.data = NULL; 11477 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 11478 return; 11479 11480 DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11481 region_num_rects(®ion), 11482 region.extents.x1, region.extents.y1, 11483 region.extents.x2, region.extents.y2)); 11484 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 11485 goto out; 11486 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 11487 drawable_gc_flags(drawable, gc, true))) 11488 goto out; 11489 11490 if (sigtrap_get() == 0) { 11491 DBG(("%s: miPolyRectangle\n", __FUNCTION__)); 11492 miPolyRectangle(drawable, gc, n, r); 11493 FALLBACK_FLUSH(drawable); 11494 sigtrap_put(); 11495 } 11496out: 11497 sna_gc_move_to_gpu(gc); 11498 RegionUninit(®ion); 11499} 11500 11501static unsigned 11502sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, 11503 int n, xArc *arc, 11504 BoxPtr out) 11505{ 11506 BoxRec box; 11507 bool clipped; 11508 int v; 11509 11510 if (n == 0) 11511 return 0; 11512 11513 box.x1 = arc->x; 11514 box.x2 = bound(box.x1, arc->width); 11515 box.y1 = arc->y; 11516 box.y2 = bound(box.y1, arc->height); 11517 11518 while (--n) { 11519 arc++; 11520 if (box.x1 > arc->x) 11521 box.x1 = arc->x; 11522 v = bound(arc->x, arc->width); 11523 if (box.x2 < v) 11524 box.x2 = v; 11525 if (box.y1 > arc->y) 11526 box.y1 = arc->y; 11527 v = bound(arc->y, arc->height); 11528 if (box.y2 < v) 11529 box.y2 = v; 11530 } 11531 11532 v = gc->lineWidth >> 1; 11533 if (v) { 11534 box.x1 -= v; 11535 box.x2 += v; 11536 box.y1 -= v; 11537 box.y2 += v; 11538 } 11539 11540 box.x2++; 11541 box.y2++; 11542 11543 clipped = trim_and_translate_box(&box, drawable, gc); 11544 if (box_empty(&box)) 11545 return 0; 11546 11547 *out = box; 11548 return 1 | clipped << 1; 11549} 11550 11551static void 11552sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc) 11553{ 11554 struct sna_fill_spans data; 11555 struct sna_pixmap *priv; 11556 11557 DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth)); 11558 11559 data.flags = sna_poly_arc_extents(drawable, gc, n, arc, 11560 &data.region.extents); 11561 if (data.flags == 0) 11562 return; 11563 11564 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11565 data.region.extents.x1, data.region.extents.y1, 11566 data.region.extents.x2, data.region.extents.y2, 11567 data.flags)); 11568 11569 data.region.data = NULL; 11570 11571 if (FORCE_FALLBACK) 11572 goto fallback; 11573 11574 if (!ACCEL_POLY_ARC) 11575 goto fallback; 11576 11577 data.pixmap = get_drawable_pixmap(drawable); 11578 data.sna = to_sna_from_pixmap(data.pixmap); 11579 priv = sna_pixmap(data.pixmap); 11580 if (priv == NULL) { 11581 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11582 goto fallback; 11583 } 11584 11585 if (wedged(data.sna)) { 11586 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11587 goto fallback; 11588 } 11589 11590 if (!PM_IS_SOLID(drawable, gc->planemask)) 11591 goto fallback; 11592 11593 if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11594 &data.region.extents, &data.damage))) { 11595 uint32_t color; 11596 11597 DBG(("%s: converting arcs into spans\n", __FUNCTION__)); 11598 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 11599 11600 if (gc_is_solid(gc, &color)) { 11601 sna_gc(gc)->priv = &data; 11602 11603 assert(gc->miTranslate); 11604 if (gc->lineStyle == LineSolid) { 11605 struct sna_fill_op fill; 11606 11607 if (!sna_fill_init_blt(&fill, 11608 data.sna, data.pixmap, 11609 data.bo, gc->alu, color, 11610 FILL_POINTS | FILL_SPANS)) 11611 goto fallback; 11612 11613 if ((data.flags & IS_CLIPPED) == 0) { 11614 if (data.dx | data.dy) 11615 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 11616 else 11617 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 11618 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 11619 } else { 11620 if (!region_maybe_clip(&data.region, 11621 gc->pCompositeClip)) 11622 return; 11623 11624 if (region_is_singular(&data.region)) { 11625 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 11626 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 11627 } else { 11628 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 11629 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 11630 } 11631 } 11632 11633 data.op = &fill; 11634 gc->ops = &sna_gc_ops__tmp; 11635 if (gc->lineWidth == 0) 11636 miZeroPolyArc(drawable, gc, n, arc); 11637 else 11638 miPolyArc(drawable, gc, n, arc); 11639 gc->ops = (GCOps *)&sna_gc_ops; 11640 11641 fill.done(data.sna, &fill); 11642 } else { 11643 if (!region_maybe_clip(&data.region, 11644 gc->pCompositeClip)) 11645 return; 11646 11647 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11648 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11649 11650 gc->ops = &sna_gc_ops__tmp; 11651 if (gc->lineWidth == 0) 11652 miZeroPolyArc(drawable, gc, n, arc); 11653 else 11654 miPolyArc(drawable, gc, n, arc); 11655 gc->ops = (GCOps *)&sna_gc_ops; 11656 } 11657 11658 if (data.damage) { 11659 if (data.dx | data.dy) 11660 pixman_region_translate(&data.region, data.dx, data.dy); 11661 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11662 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 11663 } 11664 assert_pixmap_damage(data.pixmap); 11665 RegionUninit(&data.region); 11666 return; 11667 } 11668 11669 /* XXX still around 10x slower for x11perf -ellipse */ 11670 if (gc->lineWidth == 0) 11671 miZeroPolyArc(drawable, gc, n, arc); 11672 else 11673 miPolyArc(drawable, gc, n, arc); 11674 return; 11675 } 11676 11677fallback: 11678 DBG(("%s -- fallback\n", __FUNCTION__)); 11679 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11680 return; 11681 11682 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11683 goto out; 11684 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11685 drawable_gc_flags(drawable, gc, true))) 11686 goto out; 11687 11688 if (sigtrap_get() == 0) { 11689 DBG(("%s -- fbPolyArc\n", __FUNCTION__)); 11690 fbPolyArc(drawable, gc, n, arc); 11691 FALLBACK_FLUSH(drawable); 11692 sigtrap_put(); 11693 } 11694out: 11695 sna_gc_move_to_gpu(gc); 11696 RegionUninit(&data.region); 11697} 11698 11699static bool 11700sna_poly_fill_rect_blt(DrawablePtr drawable, 11701 struct kgem_bo *bo, 11702 struct sna_damage **damage, 11703 GCPtr gc, uint32_t pixel, 11704 int n, const xRectangle *rect, 11705 const BoxRec *extents, 11706 unsigned flags) 11707{ 11708 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11709 struct sna *sna = to_sna_from_pixmap(pixmap); 11710 struct sna_fill_op fill; 11711 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11712 int16_t dx, dy; 11713 11714 DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n", 11715 __FUNCTION__, pixmap->drawable.serialNumber, n, 11716 rect->x, rect->y, rect->width, rect->height, 11717 drawable->x, drawable->y, 11718 flags&2)); 11719 11720 if (n == 1 && region_is_singular(gc->pCompositeClip)) { 11721 BoxRec r; 11722 bool success = true; 11723 11724 r.x1 = rect->x + drawable->x; 11725 r.y1 = rect->y + drawable->y; 11726 r.x2 = bound(r.x1, rect->width); 11727 r.y2 = bound(r.y1, rect->height); 11728 if (box_intersect(&r, &gc->pCompositeClip->extents)) { 11729 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 11730 r.x1 += dx; r.y1 += dy; 11731 r.x2 += dx; r.y2 += dy; 11732 } 11733 DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n", 11734 __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL)); 11735 11736 assert_pixmap_contains_box(pixmap, &r); 11737 if (sna->render.fill_one(sna, pixmap, bo, pixel, 11738 r.x1, r.y1, r.x2, r.y2, 11739 gc->alu)) { 11740 if (r.x2 - r.x1 == pixmap->drawable.width && 11741 r.y2 - r.y1 == pixmap->drawable.height) { 11742 if (damage) { 11743 sna_damage_all(damage, pixmap); 11744 damage = NULL; 11745 } 11746 if (flags & OVERWRITES) { 11747 struct sna_pixmap *priv = sna_pixmap(pixmap); 11748 if (bo == priv->gpu_bo) { 11749 assert(damage == NULL || damage == &priv->gpu_damage); 11750 assert(priv->gpu_bo->proxy == NULL); 11751 sna_damage_destroy(&priv->cpu_damage); 11752 list_del(&priv->flush_list); 11753 priv->clear = true; 11754 priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel; 11755 11756 DBG(("%s: pixmap=%ld, marking clear [%08x]\n", 11757 __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); 11758 } 11759 } 11760 } 11761 if (damage) 11762 sna_damage_add_box(damage, &r); 11763 assert_pixmap_damage(pixmap); 11764 } else 11765 success = false; 11766 } 11767 11768 return success; 11769 } 11770 11771 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) { 11772 DBG(("%s: unsupported blt\n", __FUNCTION__)); 11773 return false; 11774 } 11775 11776 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11777 if ((flags & IS_CLIPPED) == 0) { 11778 dx += drawable->x; 11779 dy += drawable->y; 11780 11781 sna_damage_add_rectangles(damage, rect, n, dx, dy); 11782 if (dx|dy) { 11783 do { 11784 unsigned nbox = n; 11785 if (nbox > ARRAY_SIZE(boxes)) 11786 nbox = ARRAY_SIZE(boxes); 11787 n -= nbox; 11788 do { 11789 b->x1 = rect->x + dx; 11790 b->y1 = rect->y + dy; 11791 b->x2 = b->x1 + rect->width; 11792 b->y2 = b->y1 + rect->height; 11793 b++; 11794 rect++; 11795 } while (--nbox); 11796 fill.boxes(sna, &fill, boxes, b-boxes); 11797 b = boxes; 11798 } while (n); 11799 } else { 11800 do { 11801 unsigned nbox = n; 11802 if (nbox > ARRAY_SIZE(boxes)) 11803 nbox = ARRAY_SIZE(boxes); 11804 n -= nbox; 11805 do { 11806 b->x1 = rect->x; 11807 b->y1 = rect->y; 11808 b->x2 = b->x1 + rect->width; 11809 b->y2 = b->y1 + rect->height; 11810 b++; 11811 rect++; 11812 } while (--nbox); 11813 fill.boxes(sna, &fill, boxes, b-boxes); 11814 b = boxes; 11815 } while (n); 11816 } 11817 } else { 11818 RegionRec clip; 11819 11820 region_set(&clip, extents); 11821 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11822 goto done; 11823 11824 if (clip.data == NULL) { 11825 do { 11826 b->x1 = rect->x + drawable->x; 11827 b->y1 = rect->y + drawable->y; 11828 b->x2 = bound(b->x1, rect->width); 11829 b->y2 = bound(b->y1, rect->height); 11830 rect++; 11831 11832 if (box_intersect(b, &clip.extents)) { 11833 b->x1 += dx; 11834 b->x2 += dx; 11835 b->y1 += dy; 11836 b->y2 += dy; 11837 if (++b == last_box) { 11838 fill.boxes(sna, &fill, boxes, last_box-boxes); 11839 if (damage) 11840 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11841 b = boxes; 11842 } 11843 } 11844 } while (--n); 11845 } else { 11846 const BoxRec * const clip_start = RegionBoxptr(&clip); 11847 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11848 const BoxRec *c; 11849 11850 do { 11851 BoxRec box; 11852 11853 box.x1 = rect->x + drawable->x; 11854 box.y1 = rect->y + drawable->y; 11855 box.x2 = bound(box.x1, rect->width); 11856 box.y2 = bound(box.y1, rect->height); 11857 rect++; 11858 11859 c = find_clip_box_for_y(clip_start, 11860 clip_end, 11861 box.y1); 11862 while (c != clip_end) { 11863 if (box.y2 <= c->y1) 11864 break; 11865 11866 *b = box; 11867 if (box_intersect(b, c++)) { 11868 b->x1 += dx; 11869 b->x2 += dx; 11870 b->y1 += dy; 11871 b->y2 += dy; 11872 if (++b == last_box) { 11873 fill.boxes(sna, &fill, boxes, last_box-boxes); 11874 if (damage) 11875 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11876 b = boxes; 11877 } 11878 } 11879 11880 } 11881 } while (--n); 11882 } 11883 11884 RegionUninit(&clip); 11885 if (b != boxes) { 11886 fill.boxes(sna, &fill, boxes, b-boxes); 11887 if (damage) 11888 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11889 } 11890 } 11891done: 11892 fill.done(sna, &fill); 11893 assert_pixmap_damage(pixmap); 11894 return true; 11895} 11896 11897static uint32_t 11898get_pixel(PixmapPtr pixmap) 11899{ 11900 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 11901 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 11902 return 0; 11903 11904 switch (pixmap->drawable.bitsPerPixel) { 11905 case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 11906 case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 11907 default: return *(uint8_t *)pixmap->devPrivate.ptr; 11908 } 11909} 11910 11911inline static int 11912_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 11913{ 11914 if (USE_SPANS) 11915 return USE_SPANS > 0; 11916 11917 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 11918 sna_pixmap_is_gpu(gc->tile.pixmap)) { 11919 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 11920 return PREFER_GPU | FORCE_GPU; 11921 } 11922 11923 return PREFER_GPU; 11924} 11925 11926static int 11927use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 11928{ 11929 int ret = _use_fill_spans(drawable, gc, extents, flags); 11930 DBG(("%s? %d\n", __FUNCTION__, ret)); 11931 return ret; 11932} 11933 11934static void 11935sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, 11936 int shape, int mode, 11937 int n, DDXPointPtr pt) 11938{ 11939 struct sna_fill_spans data; 11940 struct sna_pixmap *priv; 11941 11942 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 11943 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 11944 (gc->fillStyle == FillSolid || 11945 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 11946 gc->fillStyle, gc->tileIsPixel, 11947 gc->alu)); 11948 DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n", 11949 __FUNCTION__, draw->serialNumber, 11950 draw->x, draw->y, draw->width, draw->height)); 11951 11952 data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, 11953 &data.region.extents); 11954 if (data.flags == 0) { 11955 DBG(("%s, nothing to do\n", __FUNCTION__)); 11956 return; 11957 } 11958 11959 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11960 data.region.extents.x1, data.region.extents.y1, 11961 data.region.extents.x2, data.region.extents.y2, 11962 data.flags)); 11963 11964 data.region.data = NULL; 11965 11966 if (FORCE_FALLBACK) 11967 goto fallback; 11968 11969 if (!ACCEL_POLY_FILL_POLYGON) 11970 goto fallback; 11971 11972 data.pixmap = get_drawable_pixmap(draw); 11973 data.sna = to_sna_from_pixmap(data.pixmap); 11974 priv = sna_pixmap(data.pixmap); 11975 if (priv == NULL) { 11976 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11977 goto fallback; 11978 } 11979 11980 if (wedged(data.sna)) { 11981 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11982 goto fallback; 11983 } 11984 11985 if (!PM_IS_SOLID(draw, gc->planemask)) 11986 goto fallback; 11987 11988 if ((data.bo = sna_drawable_use_bo(draw, 11989 use_fill_spans(draw, gc, &data.region.extents, data.flags), 11990 &data.region.extents, 11991 &data.damage))) { 11992 uint32_t color; 11993 11994 sna_gc(gc)->priv = &data; 11995 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 11996 11997 if (gc_is_solid(gc, &color)) { 11998 struct sna_fill_op fill; 11999 12000 if (!sna_fill_init_blt(&fill, 12001 data.sna, data.pixmap, 12002 data.bo, gc->alu, color, 12003 FILL_SPANS)) 12004 goto fallback; 12005 12006 data.op = &fill; 12007 12008 if ((data.flags & IS_CLIPPED) == 0) { 12009 if (data.dx | data.dy) 12010 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 12011 else 12012 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 12013 } else { 12014 if (!region_maybe_clip(&data.region, 12015 gc->pCompositeClip)) 12016 return; 12017 12018 if (region_is_singular(&data.region)) 12019 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 12020 else 12021 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 12022 } 12023 assert(gc->miTranslate); 12024 gc->ops = &sna_gc_ops__tmp; 12025 12026 miFillPolygon(draw, gc, shape, mode, n, pt); 12027 fill.done(data.sna, &fill); 12028 } else { 12029 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 12030 gc->ops = &sna_gc_ops__tmp; 12031 12032 miFillPolygon(draw, gc, shape, mode, n, pt); 12033 } 12034 12035 gc->ops = (GCOps *)&sna_gc_ops; 12036 if (data.damage) { 12037 if (data.dx | data.dy) 12038 pixman_region_translate(&data.region, data.dx, data.dy); 12039 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 12040 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 12041 } 12042 assert_pixmap_damage(data.pixmap); 12043 RegionUninit(&data.region); 12044 return; 12045 } 12046 12047fallback: 12048 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 12049 data.region.extents.x1, data.region.extents.y1, 12050 data.region.extents.x2, data.region.extents.y2)); 12051 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 12052 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 12053 return; 12054 } 12055 12056 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 12057 goto out; 12058 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 12059 drawable_gc_flags(draw, gc, true))) 12060 goto out; 12061 12062 if (sigtrap_get() == 0) { 12063 DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", 12064 __FUNCTION__)); 12065 miFillPolygon(draw, gc, shape, mode, n, pt); 12066 sigtrap_put(); 12067 } 12068out: 12069 sna_gc_move_to_gpu(gc); 12070 RegionUninit(&data.region); 12071} 12072 12073static struct kgem_bo * 12074sna_pixmap_get_source_bo(PixmapPtr pixmap) 12075{ 12076 struct sna_pixmap *priv = sna_pixmap(pixmap); 12077 unsigned flags; 12078 BoxRec box; 12079 12080 box.x1 = box.y1 = 0; 12081 box.x2 = pixmap->drawable.width; 12082 box.y2 = pixmap->drawable.height; 12083 12084 DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__, 12085 pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 12086 12087 if (priv == NULL) { 12088 DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__)); 12089 return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12090 pixmap->devPrivate.ptr, &box, 12091 pixmap->devKind, 12092 pixmap->drawable.bitsPerPixel); 12093 } 12094 12095 if (priv->gpu_damage) { 12096 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) 12097 return kgem_bo_reference(priv->gpu_bo); 12098 } else if (priv->cpu_damage) { 12099 if (priv->cpu_bo) 12100 return kgem_bo_reference(priv->cpu_bo); 12101 } else { 12102 if (priv->gpu_bo) 12103 return kgem_bo_reference(priv->gpu_bo); 12104 if (priv->cpu_bo) 12105 return kgem_bo_reference(priv->cpu_bo); 12106 } 12107 12108 flags = MOVE_READ | MOVE_ASYNC_HINT; 12109 if (priv->gpu_bo && priv->gpu_bo->proxy) { 12110 struct kgem_bo *bo = priv->gpu_bo; 12111 if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096)) 12112 flags |= __MOVE_FORCE; 12113 } 12114 if (priv->gpu_bo == NULL) { 12115 if (++priv->source_count > SOURCE_BIAS) 12116 flags |= __MOVE_FORCE; 12117 } 12118 12119 if (!sna_pixmap_move_to_gpu(pixmap, flags)) { 12120 struct kgem_bo *upload; 12121 12122 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12123 return NULL; 12124 12125 upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12126 pixmap->devPrivate.ptr, &box, 12127 pixmap->devKind, 12128 pixmap->drawable.bitsPerPixel); 12129 if (upload == NULL) 12130 return NULL; 12131 12132 if (priv->gpu_bo == NULL) { 12133 DBG(("%s: adding upload cache to pixmap=%ld\n", 12134 __FUNCTION__, pixmap->drawable.serialNumber)); 12135 assert(upload->proxy != NULL); 12136 kgem_proxy_bo_attach(upload, &priv->gpu_bo); 12137 } 12138 12139 return upload; 12140 } 12141 12142 return kgem_bo_reference(priv->gpu_bo); 12143} 12144 12145/* 12146static bool 12147tile(DrawablePtr drawable, 12148 struct kgem_bo *bo, struct sna_damage **damage, 12149 PixmapPtr tile, const DDXPointRec * const origin, int alu, 12150 int n, xRectangle *rect, 12151 const BoxRec *extents, unsigned clipped) 12152 */ 12153 12154static bool 12155sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, 12156 struct kgem_bo *bo, struct sna_damage **damage, 12157 struct kgem_bo *tile_bo, GCPtr gc, 12158 int n, const xRectangle *r, 12159 const BoxRec *extents, unsigned clipped) 12160{ 12161 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12162 struct sna *sna = to_sna_from_pixmap(pixmap); 12163 const DDXPointRec * const origin = &gc->patOrg; 12164 uint32_t br00, br13; 12165 int tx, ty; 12166 int16_t dx, dy; 12167 uint32_t *b; 12168 12169 if (NO_TILE_8x8) 12170 return false; 12171 12172 DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n", 12173 __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y)); 12174 12175 DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch)); 12176 if (tile_bo->tiling) 12177 return false; 12178 12179 if (!kgem_bo_can_blt(&sna->kgem, bo) || 12180 !kgem_bo_can_blt(&sna->kgem, tile_bo)) 12181 return false; 12182 12183 assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3); 12184 12185 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12186 assert(kgem_bo_can_blt(&sna->kgem, bo)); 12187 if (!kgem_check_batch(&sna->kgem, 10+2*3) || 12188 !kgem_check_reloc(&sna->kgem, 2) || 12189 !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) { 12190 kgem_submit(&sna->kgem); 12191 if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) 12192 return false; 12193 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12194 } 12195 12196 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12197 assert(extents->x1 + dx >= 0); 12198 assert(extents->y1 + dy >= 0); 12199 assert(extents->x2 + dx <= pixmap->drawable.width); 12200 assert(extents->y2 + dy <= pixmap->drawable.height); 12201 12202 br00 = XY_SCANLINE_BLT; 12203 tx = (-drawable->x - dx - origin->x) % 8; 12204 if (tx < 0) 12205 tx += 8; 12206 ty = (-drawable->y - dy - origin->y) % 8; 12207 if (ty < 0) 12208 ty += 8; 12209 br00 |= tx << 12 | ty << 8; 12210 12211 br13 = bo->pitch; 12212 if (sna->kgem.gen >= 040 && bo->tiling) { 12213 br00 |= BLT_DST_TILED; 12214 br13 >>= 2; 12215 } 12216 br13 |= blt_depth(drawable->depth) << 24; 12217 br13 |= fill_ROP[gc->alu] << 16; 12218 12219 if (!clipped) { 12220 dx += drawable->x; 12221 dy += drawable->y; 12222 12223 sna_damage_add_rectangles(damage, r, n, dx, dy); 12224 if (n == 1) { 12225 DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12226 __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty)); 12227 12228 assert(r->x + dx >= 0); 12229 assert(r->y + dy >= 0); 12230 assert(r->x + dx + r->width <= pixmap->drawable.width); 12231 assert(r->y + dy + r->height <= pixmap->drawable.height); 12232 12233 assert(sna->kgem.mode == KGEM_BLT); 12234 b = sna->kgem.batch + sna->kgem.nbatch; 12235 if (sna->kgem.gen >= 0100) { 12236 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6; 12237 b[1] = br13; 12238 b[2] = (r->y + dy) << 16 | (r->x + dx); 12239 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12240 *(uint64_t *)(b+4) = 12241 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12242 I915_GEM_DOMAIN_RENDER << 16 | 12243 I915_GEM_DOMAIN_RENDER | 12244 KGEM_RELOC_FENCED, 12245 0); 12246 *(uint64_t *)(b+6) = 12247 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo, 12248 I915_GEM_DOMAIN_RENDER << 16 | 12249 KGEM_RELOC_FENCED, 12250 0); 12251 sna->kgem.nbatch += 8; 12252 } else { 12253 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4; 12254 b[1] = br13; 12255 b[2] = (r->y + dy) << 16 | (r->x + dx); 12256 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12257 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12258 I915_GEM_DOMAIN_RENDER << 16 | 12259 I915_GEM_DOMAIN_RENDER | 12260 KGEM_RELOC_FENCED, 12261 0); 12262 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo, 12263 I915_GEM_DOMAIN_RENDER << 16 | 12264 KGEM_RELOC_FENCED, 12265 0); 12266 sna->kgem.nbatch += 6; 12267 } 12268 } else do { 12269 int n_this_time, rem; 12270 12271 assert(sna->kgem.mode == KGEM_BLT); 12272 b = sna->kgem.batch + sna->kgem.nbatch; 12273 if (sna->kgem.gen >= 0100) { 12274 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12275 b[1] = br13; 12276 b[2] = 0; 12277 b[3] = 0; 12278 *(uint64_t *)(b+4) = 12279 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12280 I915_GEM_DOMAIN_RENDER << 16 | 12281 I915_GEM_DOMAIN_RENDER | 12282 KGEM_RELOC_FENCED, 12283 0); 12284 b[6] = gc->bgPixel; 12285 b[7] = gc->fgPixel; 12286 *(uint64_t *)(b+8) = 12287 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12288 I915_GEM_DOMAIN_RENDER << 16 | 12289 KGEM_RELOC_FENCED, 12290 0); 12291 sna->kgem.nbatch += 10; 12292 } else { 12293 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12294 b[1] = br13; 12295 b[2] = 0; 12296 b[3] = 0; 12297 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12298 I915_GEM_DOMAIN_RENDER << 16 | 12299 I915_GEM_DOMAIN_RENDER | 12300 KGEM_RELOC_FENCED, 12301 0); 12302 b[5] = gc->bgPixel; 12303 b[6] = gc->fgPixel; 12304 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12305 I915_GEM_DOMAIN_RENDER << 16 | 12306 KGEM_RELOC_FENCED, 12307 0); 12308 sna->kgem.nbatch += 8; 12309 } 12310 12311 n_this_time = n; 12312 rem = kgem_batch_space(&sna->kgem); 12313 if (3*n_this_time > rem) 12314 n_this_time = rem / 3; 12315 assert(n_this_time); 12316 n -= n_this_time; 12317 12318 assert(sna->kgem.mode == KGEM_BLT); 12319 b = sna->kgem.batch + sna->kgem.nbatch; 12320 sna->kgem.nbatch += 3*n_this_time; 12321 do { 12322 assert(r->x + dx >= 0); 12323 assert(r->y + dy >= 0); 12324 assert(r->x + dx + r->width <= pixmap->drawable.width); 12325 assert(r->y + dy + r->height <= pixmap->drawable.height); 12326 12327 b[0] = br00; 12328 b[1] = (r->y + dy) << 16 | (r->x + dx); 12329 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12330 b += 3; r++; 12331 } while (--n_this_time); 12332 12333 if (!n) 12334 break; 12335 12336 _kgem_submit(&sna->kgem); 12337 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12338 } while (1); 12339 } else { 12340 RegionRec clip; 12341 uint16_t unwind_batch, unwind_reloc; 12342 12343 region_set(&clip, extents); 12344 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12345 goto done; 12346 12347 unwind_batch = sna->kgem.nbatch; 12348 unwind_reloc = sna->kgem.nreloc; 12349 12350 assert(sna->kgem.mode == KGEM_BLT); 12351 b = sna->kgem.batch + sna->kgem.nbatch; 12352 if (sna->kgem.gen >= 0100) { 12353 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12354 b[1] = br13; 12355 b[2] = 0; 12356 b[3] = 0; 12357 *(uint64_t *)(b+4) = 12358 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12359 I915_GEM_DOMAIN_RENDER << 16 | 12360 I915_GEM_DOMAIN_RENDER | 12361 KGEM_RELOC_FENCED, 12362 0); 12363 b[6] = gc->bgPixel; 12364 b[7] = gc->fgPixel; 12365 *(uint64_t *)(b+8) = 12366 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12367 I915_GEM_DOMAIN_RENDER << 16 | 12368 KGEM_RELOC_FENCED, 12369 0); 12370 sna->kgem.nbatch += 10; 12371 } else { 12372 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12373 b[1] = br13; 12374 b[2] = 0; 12375 b[3] = 0; 12376 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12377 I915_GEM_DOMAIN_RENDER << 16 | 12378 I915_GEM_DOMAIN_RENDER | 12379 KGEM_RELOC_FENCED, 12380 0); 12381 b[5] = gc->bgPixel; 12382 b[6] = gc->fgPixel; 12383 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12384 I915_GEM_DOMAIN_RENDER << 16 | 12385 KGEM_RELOC_FENCED, 12386 0); 12387 sna->kgem.nbatch += 8; 12388 } 12389 12390 if (clip.data == NULL) { 12391 const BoxRec *c = &clip.extents; 12392 DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n)); 12393 while (n--) { 12394 BoxRec box; 12395 12396 box.x1 = r->x + drawable->x; 12397 box.y1 = r->y + drawable->y; 12398 box.x2 = bound(box.x1, r->width); 12399 box.y2 = bound(box.y1, r->height); 12400 r++; 12401 12402 if (box_intersect(&box, c)) { 12403 if (!kgem_check_batch(&sna->kgem, 3)) { 12404 _kgem_submit(&sna->kgem); 12405 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12406 12407 unwind_batch = sna->kgem.nbatch; 12408 unwind_reloc = sna->kgem.nreloc; 12409 12410 assert(sna->kgem.mode == KGEM_BLT); 12411 b = sna->kgem.batch + sna->kgem.nbatch; 12412 if (sna->kgem.gen >= 0100) { 12413 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12414 b[1] = br13; 12415 b[2] = 0; 12416 b[3] = 0; 12417 *(uint64_t *)(b+4) = 12418 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12419 I915_GEM_DOMAIN_RENDER << 16 | 12420 I915_GEM_DOMAIN_RENDER | 12421 KGEM_RELOC_FENCED, 12422 0); 12423 b[6] = gc->bgPixel; 12424 b[7] = gc->fgPixel; 12425 *(uint64_t *)(b+8) = 12426 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12427 I915_GEM_DOMAIN_RENDER << 16 | 12428 KGEM_RELOC_FENCED, 12429 0); 12430 sna->kgem.nbatch += 10; 12431 } else { 12432 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12433 b[1] = br13; 12434 b[2] = 0; 12435 b[3] = 0; 12436 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12437 I915_GEM_DOMAIN_RENDER << 16 | 12438 I915_GEM_DOMAIN_RENDER | 12439 KGEM_RELOC_FENCED, 12440 0); 12441 b[5] = gc->bgPixel; 12442 b[6] = gc->fgPixel; 12443 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12444 I915_GEM_DOMAIN_RENDER << 16 | 12445 KGEM_RELOC_FENCED, 12446 0); 12447 sna->kgem.nbatch += 8; 12448 } 12449 } 12450 12451 assert(box.x1 + dx >= 0); 12452 assert(box.y1 + dy >= 0); 12453 assert(box.x2 + dx <= pixmap->drawable.width); 12454 assert(box.y2 + dy <= pixmap->drawable.height); 12455 12456 DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12457 __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty)); 12458 12459 assert(sna->kgem.mode == KGEM_BLT); 12460 b = sna->kgem.batch + sna->kgem.nbatch; 12461 b[0] = br00; 12462 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 12463 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 12464 sna->kgem.nbatch += 3; 12465 } 12466 } 12467 } else { 12468 const BoxRec * const clip_start = RegionBoxptr(&clip); 12469 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12470 const BoxRec *c; 12471 12472 DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n)); 12473 do { 12474 BoxRec box; 12475 12476 box.x1 = r->x + drawable->x; 12477 box.y1 = r->y + drawable->y; 12478 box.x2 = bound(box.x1, r->width); 12479 box.y2 = bound(box.y1, r->height); 12480 DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__, 12481 r->x, r->y, r->width, r->height, 12482 box.x1, box.y1, box.x2, box.y2)); 12483 r++; 12484 12485 c = find_clip_box_for_y(clip_start, 12486 clip_end, 12487 box.y1); 12488 while (c != clip_end) { 12489 BoxRec bb; 12490 12491 DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2)); 12492 12493 if (box.y2 <= c->y1) 12494 break; 12495 12496 bb = box; 12497 if (box_intersect(&bb, c++)) { 12498 if (!kgem_check_batch(&sna->kgem, 3)) { 12499 DBG(("%s: emitting split batch\n", __FUNCTION__)); 12500 _kgem_submit(&sna->kgem); 12501 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12502 12503 unwind_batch = sna->kgem.nbatch; 12504 unwind_reloc = sna->kgem.nreloc; 12505 12506 assert(sna->kgem.mode == KGEM_BLT); 12507 b = sna->kgem.batch + sna->kgem.nbatch; 12508 if (sna->kgem.gen >= 0100) { 12509 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12510 b[1] = br13; 12511 b[2] = 0; 12512 b[3] = 0; 12513 *(uint64_t *)(b+4) = 12514 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12515 I915_GEM_DOMAIN_RENDER << 16 | 12516 I915_GEM_DOMAIN_RENDER | 12517 KGEM_RELOC_FENCED, 12518 0); 12519 b[6] = gc->bgPixel; 12520 b[7] = gc->fgPixel; 12521 *(uint64_t *)(b+8) = 12522 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12523 I915_GEM_DOMAIN_RENDER << 16 | 12524 KGEM_RELOC_FENCED, 12525 0); 12526 sna->kgem.nbatch += 10; 12527 } else { 12528 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12529 b[1] = br13; 12530 b[2] = 0; 12531 b[3] = 0; 12532 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12533 I915_GEM_DOMAIN_RENDER << 16 | 12534 I915_GEM_DOMAIN_RENDER | 12535 KGEM_RELOC_FENCED, 12536 0); 12537 b[5] = gc->bgPixel; 12538 b[6] = gc->fgPixel; 12539 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12540 I915_GEM_DOMAIN_RENDER << 16 | 12541 KGEM_RELOC_FENCED, 12542 0); 12543 sna->kgem.nbatch += 8; 12544 } 12545 } 12546 12547 assert(bb.x1 + dx >= 0); 12548 assert(bb.y1 + dy >= 0); 12549 assert(bb.x2 + dx <= pixmap->drawable.width); 12550 assert(bb.y2 + dy <= pixmap->drawable.height); 12551 12552 DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n", 12553 __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y)); 12554 12555 assert(sna->kgem.mode == KGEM_BLT); 12556 b = sna->kgem.batch + sna->kgem.nbatch; 12557 b[0] = br00; 12558 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 12559 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 12560 sna->kgem.nbatch += 3; 12561 } 12562 } 12563 } while (--n); 12564 } 12565 12566 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 12567 sna->kgem.nbatch = unwind_batch; 12568 sna->kgem.nreloc = unwind_reloc; 12569 if (sna->kgem.nbatch == 0) 12570 kgem_bo_pair_undo(&sna->kgem, bo, tile_bo); 12571 } 12572 } 12573done: 12574 assert_pixmap_damage(pixmap); 12575 sna->blt_state.fill_bo = 0; 12576 return true; 12577} 12578 12579static bool tile8(int x) 12580{ 12581 switch(x) { 12582 case 1: 12583 case 2: 12584 case 4: 12585 case 8: 12586 return true; 12587 default: 12588 return false; 12589 } 12590} 12591 12592static int next8(int x, int max) 12593{ 12594 if (x > 2 && x <= 4) 12595 x = 4; 12596 else if (x < 8) 12597 x = 8; 12598 return MIN(x, max); 12599} 12600 12601static bool 12602sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable, 12603 struct kgem_bo *bo, 12604 struct sna_damage **damage, 12605 GCPtr gc, int n, const xRectangle *rect, 12606 const BoxRec *extents, unsigned clipped) 12607{ 12608 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12609 struct sna *sna = to_sna_from_pixmap(pixmap); 12610 PixmapPtr tile = gc->tile.pixmap; 12611 int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel; 12612 const DDXPointRec origin = gc->patOrg; 12613 struct kgem_bo *upload; 12614 bool ret = false; 12615 uint8_t *src; 12616 void *ptr; 12617 12618 tx = 0, tw = tile->drawable.width; 12619 if (!tile8(tw) && tw > extents->x2 - extents->x1) { 12620 tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw; 12621 if (tx < 0) 12622 tx += tw; 12623 tw = next8(extents->x2 - extents->x1, tw); 12624 gc->patOrg.x = extents->x1 - drawable->x; 12625 } 12626 12627 ty = 0, th = tile->drawable.height; 12628 if (!tile8(th) && th > extents->y2 - extents->y1) { 12629 ty = (extents->y1 - gc->patOrg.y - drawable->y) % th; 12630 if (ty < 0) 12631 ty += th; 12632 th = next8(extents->y2 - extents->y1, th); 12633 gc->patOrg.y = extents->y1 - drawable->y; 12634 } 12635 12636 DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__, 12637 tw, th, tx, ty, tile->drawable.width, tile->drawable.height)); 12638 assert(tx < tile->drawable.width && tx >= 0); 12639 assert(ty < tile->drawable.height && ty >= 0); 12640 assert(tw && tw <= 8 && tw <= tile->drawable.width); 12641 assert(is_power_of_two(tw)); 12642 assert(th && th <= 8 && th <= tile->drawable.height); 12643 assert(is_power_of_two(th)); 12644 12645 if (!sna_pixmap_move_to_cpu(tile, MOVE_READ)) 12646 goto out_gc; 12647 12648 assert(tile->devKind); 12649 assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ)); 12650 12651 src = tile->devPrivate.ptr; 12652 src += tile->devKind * ty; 12653 src += tx * bpp/8; 12654 12655 if ((tw | th) == 1) { 12656 uint32_t pixel; 12657 switch (bpp) { 12658 case 32: pixel = *(uint32_t *)src; break; 12659 case 16: pixel = *(uint16_t *)src; break; 12660 default: pixel = *(uint8_t *)src; break; 12661 } 12662 return sna_poly_fill_rect_blt(drawable, bo, damage, 12663 gc, pixel, n, rect, 12664 extents, clipped); 12665 } 12666 12667 upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr); 12668 if (upload == NULL) 12669 goto out_gc; 12670 12671 upload->pitch = bpp; /* for sanity checks */ 12672 12673 if (sigtrap_get() == 0) { 12674 uint8_t *dst = ptr; 12675 if (tx + tw > tile->drawable.width || 12676 ty + th > tile->drawable.height) { 12677 int sy = ty; 12678 src = tile->devPrivate.ptr; 12679 for (h = 0; h < th; h++) { 12680 int sx = tx; 12681 for (w = 0; w < tw; w++) { 12682 memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8); 12683 if (++sx == tile->drawable.width) 12684 sx = 0; 12685 } 12686 w *= bpp/8; 12687 while (w < bpp) { 12688 memcpy(dst+w, dst, w); 12689 w *= 2; 12690 } 12691 if (++sy == tile->drawable.height) 12692 sy = 0; 12693 dst += bpp; 12694 } 12695 while (h < 8) { 12696 memcpy(dst, ptr, bpp*h); 12697 dst += bpp * h; 12698 h *= 2; 12699 } 12700 } else { 12701 for (h = 0; h < th; h++) { 12702 w = tw*bpp/8; 12703 memcpy(dst, src, w); 12704 while (w < bpp) { 12705 memcpy(dst+w, dst, w); 12706 w *= 2; 12707 } 12708 assert(w == bpp); 12709 12710 src += tile->devKind; 12711 dst += bpp; 12712 } 12713 while (h < 8) { 12714 memcpy(dst, ptr, bpp*h); 12715 dst += bpp * h; 12716 h *= 2; 12717 } 12718 assert(h == 8); 12719 } 12720 12721 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12722 upload, gc, n, rect, 12723 extents, clipped); 12724 sigtrap_put(); 12725 } 12726 12727 kgem_bo_destroy(&sna->kgem, upload); 12728out_gc: 12729 gc->patOrg = origin; 12730 return ret; 12731} 12732 12733inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel) 12734{ 12735 PixmapPtr tile = gc->tile.pixmap; 12736 struct sna_pixmap *priv; 12737 12738 if ((tile->drawable.width | tile->drawable.height) == 1) { 12739 DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__)); 12740 *pixel = get_pixel(tile); 12741 return true; 12742 } 12743 12744 priv = sna_pixmap(tile); 12745 if (priv == NULL || !priv->clear) 12746 return false; 12747 12748 DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__)); 12749 *pixel = priv->clear_color; 12750 return true; 12751} 12752 12753static bool 12754sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 12755 struct kgem_bo *bo, 12756 struct sna_damage **damage, 12757 GCPtr gc, int n, xRectangle *rect, 12758 const BoxRec *extents, unsigned clipped) 12759{ 12760 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12761 struct sna *sna = to_sna_from_pixmap(pixmap); 12762 PixmapPtr tile = gc->tile.pixmap; 12763 struct kgem_bo *tile_bo; 12764 const DDXPointRec * const origin = &gc->patOrg; 12765 struct sna_copy_op copy; 12766 CARD32 alu = gc->alu; 12767 int tile_width, tile_height; 12768 int16_t dx, dy; 12769 uint32_t pixel; 12770 12771 DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n", 12772 __FUNCTION__, pixmap->drawable.serialNumber, 12773 n, rect->x, rect->y, rect->width, rect->height, 12774 clipped)); 12775 12776 assert(tile->drawable.depth == drawable->depth); 12777 assert(bo); 12778 12779 if (tile_is_solid(gc, &pixel)) 12780 return sna_poly_fill_rect_blt(drawable, bo, damage, 12781 gc, pixel, 12782 n, rect, 12783 extents, clipped); 12784 12785 /* XXX [248]x[238] tiling can be reduced to a pattern fill. 12786 * Also we can do the lg2 reduction for BLT and use repeat modes for 12787 * RENDER. 12788 */ 12789 12790 tile_width = tile->drawable.width; 12791 tile_height = tile->drawable.height; 12792 if ((tile_width | tile_height) == 8) { 12793 bool ret; 12794 12795 DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__)); 12796 12797 tile_bo = sna_pixmap_get_source_bo(tile); 12798 if (tile_bo == NULL) { 12799 DBG(("%s: unable to move tile go GPU, fallback\n", 12800 __FUNCTION__)); 12801 return false; 12802 } 12803 12804 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12805 tile_bo, gc, n, rect, 12806 extents, clipped); 12807 if (ret) { 12808 kgem_bo_destroy(&sna->kgem, tile_bo); 12809 return true; 12810 } 12811 } else { 12812 int w = tile_width, h = tile_height; 12813 struct sna_pixmap *priv = sna_pixmap(tile); 12814 12815 if (priv == NULL || priv->gpu_damage == NULL) { 12816 w = next8(extents->x2 - extents->x1, w); 12817 h = next8(extents->y2 - extents->y1, h); 12818 } 12819 12820 DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n", 12821 __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1)); 12822 12823 if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) && 12824 sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage, 12825 gc, n, rect, 12826 extents, clipped)) 12827 return true; 12828 12829 tile_bo = sna_pixmap_get_source_bo(tile); 12830 if (tile_bo == NULL) { 12831 DBG(("%s: unable to move tile go GPU, fallback\n", 12832 __FUNCTION__)); 12833 return false; 12834 } 12835 } 12836 12837 if (!sna_copy_init_blt(©, sna, tile, tile_bo, pixmap, bo, alu)) { 12838 DBG(("%s: unsupported blt\n", __FUNCTION__)); 12839 kgem_bo_destroy(&sna->kgem, tile_bo); 12840 return false; 12841 } 12842 12843 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12844 DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n", 12845 __FUNCTION__, pixmap->drawable.serialNumber, dx, dy)); 12846 if (!clipped) { 12847 dx += drawable->x; 12848 dy += drawable->y; 12849 12850 sna_damage_add_rectangles(damage, rect, n, dx, dy); 12851 do { 12852 xRectangle r = *rect++; 12853 int16_t tile_y = (r.y - origin->y) % tile_height; 12854 if (tile_y < 0) 12855 tile_y += tile_height; 12856 12857 assert(r.x + dx >= 0); 12858 assert(r.y + dy >= 0); 12859 assert(r.x + dx + r.width <= pixmap->drawable.width); 12860 assert(r.y + dy + r.height <= pixmap->drawable.height); 12861 12862 r.y += dy; 12863 do { 12864 int16_t width = r.width; 12865 int16_t x = r.x + dx, tile_x; 12866 int16_t h = tile_height - tile_y; 12867 if (h > r.height) 12868 h = r.height; 12869 r.height -= h; 12870 12871 tile_x = (r.x - origin->x) % tile_width; 12872 if (tile_x < 0) 12873 tile_x += tile_width; 12874 12875 do { 12876 int16_t w = tile_width - tile_x; 12877 if (w > width) 12878 w = width; 12879 width -= w; 12880 12881 copy.blt(sna, ©, 12882 tile_x, tile_y, 12883 w, h, 12884 x, r.y); 12885 12886 x += w; 12887 tile_x = 0; 12888 } while (width); 12889 r.y += h; 12890 tile_y = 0; 12891 } while (r.height); 12892 } while (--n); 12893 } else { 12894 RegionRec clip; 12895 12896 region_set(&clip, extents); 12897 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12898 goto done; 12899 12900 if (clip.data == NULL) { 12901 const BoxRec *box = &clip.extents; 12902 DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n", 12903 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 12904 while (n--) { 12905 BoxRec r; 12906 12907 r.x1 = rect->x + drawable->x; 12908 r.y1 = rect->y + drawable->y; 12909 r.x2 = bound(r.x1, rect->width); 12910 r.y2 = bound(r.y1, rect->height); 12911 rect++; 12912 12913 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 12914 __FUNCTION__, r.x1, r.y1, r.x2, r.y2)); 12915 12916 if (box_intersect(&r, box)) { 12917 int height = r.y2 - r.y1; 12918 int dst_y = r.y1; 12919 int tile_y = (r.y1 - drawable->y - origin->y) % tile_height; 12920 if (tile_y < 0) 12921 tile_y += tile_height; 12922 12923 assert(r.x1 + dx >= 0); 12924 assert(r.y1 + dy >= 0); 12925 assert(r.x2 + dx <= pixmap->drawable.width); 12926 assert(r.y2 + dy <= pixmap->drawable.height); 12927 12928 while (height) { 12929 int width = r.x2 - r.x1; 12930 int dst_x = r.x1, tile_x; 12931 int h = tile_height - tile_y; 12932 if (h > height) 12933 h = height; 12934 height -= h; 12935 12936 tile_x = (r.x1 - drawable->x - origin->x) % tile_width; 12937 if (tile_x < 0) 12938 tile_x += tile_width; 12939 12940 while (width > 0) { 12941 int w = tile_width - tile_x; 12942 if (w > width) 12943 w = width; 12944 width -= w; 12945 12946 copy.blt(sna, ©, 12947 tile_x, tile_y, 12948 w, h, 12949 dst_x + dx, dst_y + dy); 12950 if (damage) { 12951 BoxRec b; 12952 12953 b.x1 = dst_x + dx; 12954 b.y1 = dst_y + dy; 12955 b.x2 = b.x1 + w; 12956 b.y2 = b.y1 + h; 12957 12958 assert_pixmap_contains_box(pixmap, &b); 12959 sna_damage_add_box(damage, &b); 12960 } 12961 12962 dst_x += w; 12963 tile_x = 0; 12964 } 12965 dst_y += h; 12966 tile_y = 0; 12967 } 12968 } 12969 } 12970 } else { 12971 while (n--) { 12972 RegionRec region; 12973 const BoxRec *box; 12974 int nbox; 12975 12976 region.extents.x1 = rect->x + drawable->x; 12977 region.extents.y1 = rect->y + drawable->y; 12978 region.extents.x2 = bound(region.extents.x1, rect->width); 12979 region.extents.y2 = bound(region.extents.y1, rect->height); 12980 rect++; 12981 12982 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 12983 __FUNCTION__, 12984 region.extents.x1, 12985 region.extents.y1, 12986 region.extents.x2, 12987 region.extents.y2)); 12988 12989 region.data = NULL; 12990 RegionIntersect(®ion, ®ion, &clip); 12991 12992 assert(region.extents.x1 + dx >= 0); 12993 assert(region.extents.y1 + dy >= 0); 12994 assert(region.extents.x2 + dx <= pixmap->drawable.width); 12995 assert(region.extents.y2 + dy <= pixmap->drawable.height); 12996 12997 nbox = region_num_rects(®ion); 12998 box = region_rects(®ion); 12999 DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox)); 13000 while (nbox--) { 13001 int height = box->y2 - box->y1; 13002 int dst_y = box->y1; 13003 int tile_y = (box->y1 - drawable->y - origin->y) % tile_height; 13004 if (tile_y < 0) 13005 tile_y += tile_height; 13006 13007 while (height) { 13008 int width = box->x2 - box->x1; 13009 int dst_x = box->x1, tile_x; 13010 int h = tile_height - tile_y; 13011 if (h > height) 13012 h = height; 13013 height -= h; 13014 13015 tile_x = (box->x1 - drawable->x - origin->x) % tile_width; 13016 if (tile_x < 0) 13017 tile_x += tile_width; 13018 13019 while (width > 0) { 13020 int w = tile_width - tile_x; 13021 if (w > width) 13022 w = width; 13023 width -= w; 13024 13025 copy.blt(sna, ©, 13026 tile_x, tile_y, 13027 w, h, 13028 dst_x + dx, dst_y + dy); 13029 if (damage) { 13030 BoxRec b; 13031 13032 b.x1 = dst_x + dx; 13033 b.y1 = dst_y + dy; 13034 b.x2 = b.x1 + w; 13035 b.y2 = b.y1 + h; 13036 13037 assert_pixmap_contains_box(pixmap, &b); 13038 sna_damage_add_box(damage, &b); 13039 } 13040 13041 dst_x += w; 13042 tile_x = 0; 13043 } 13044 dst_y += h; 13045 tile_y = 0; 13046 } 13047 box++; 13048 } 13049 13050 RegionUninit(®ion); 13051 } 13052 } 13053 13054 RegionUninit(&clip); 13055 } 13056done: 13057 copy.done(sna, ©); 13058 assert_pixmap_damage(pixmap); 13059 kgem_bo_destroy(&sna->kgem, tile_bo); 13060 return true; 13061} 13062 13063static bool 13064sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, 13065 struct kgem_bo *bo, 13066 struct sna_damage **damage, 13067 GCPtr gc, int n, xRectangle *r, 13068 const BoxRec *extents, unsigned clipped) 13069{ 13070 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13071 struct sna *sna = to_sna_from_pixmap(pixmap); 13072 uint32_t pat[2] = {0, 0}, br00, br13; 13073 int16_t dx, dy; 13074 uint32_t *b; 13075 13076 if (NO_STIPPLE_8x8) 13077 return false; 13078 13079 DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n", 13080 __FUNCTION__, gc->alu, 13081 extents->x1, extents->y1, 13082 extents->x2, extents->y2, 13083 gc->patOrg.x, gc->patOrg.y)); 13084 13085 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13086 { 13087 int px, py; 13088 13089 px = (0 - gc->patOrg.x - drawable->x - dx) % 8; 13090 if (px < 0) 13091 px += 8; 13092 13093 py = (0 - gc->patOrg.y - drawable->y - dy) % 8; 13094 if (py < 0) 13095 py += 8; 13096 DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py)); 13097 13098 br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20; 13099 br13 = bo->pitch; 13100 if (sna->kgem.gen >= 040 && bo->tiling) { 13101 br00 |= BLT_DST_TILED; 13102 br13 >>= 2; 13103 } 13104 br13 |= (gc->fillStyle == FillStippled) << 28; 13105 br13 |= blt_depth(drawable->depth) << 24; 13106 br13 |= fill_ROP[gc->alu] << 16; 13107 } 13108 13109 assert(gc->stipple->devKind); 13110 { 13111 uint8_t *dst = (uint8_t *)pat; 13112 const uint8_t *src = gc->stipple->devPrivate.ptr; 13113 int stride = gc->stipple->devKind; 13114 int j = gc->stipple->drawable.height; 13115 do { 13116 *dst++ = byte_reverse(*src); 13117 src += stride; 13118 } while (--j); 13119 } 13120 13121 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13122 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13123 if (!kgem_check_batch(&sna->kgem, 10 + 2*3) || 13124 !kgem_check_bo_fenced(&sna->kgem, bo) || 13125 !kgem_check_reloc(&sna->kgem, 1)) { 13126 kgem_submit(&sna->kgem); 13127 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13128 return false; 13129 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13130 } 13131 13132 if (!clipped) { 13133 dx += drawable->x; 13134 dy += drawable->y; 13135 13136 sna_damage_add_rectangles(damage, r, n, dx, dy); 13137 if (n == 1) { 13138 DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n", 13139 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13140 13141 assert(sna->kgem.mode == KGEM_BLT); 13142 b = sna->kgem.batch + sna->kgem.nbatch; 13143 if (sna->kgem.gen >= 0100) { 13144 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8; 13145 b[1] = br13; 13146 b[2] = (r->y + dy) << 16 | (r->x + dx); 13147 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13148 *(uint64_t *)(b+4) = 13149 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13150 I915_GEM_DOMAIN_RENDER << 16 | 13151 I915_GEM_DOMAIN_RENDER | 13152 KGEM_RELOC_FENCED, 13153 0); 13154 b[6] = gc->bgPixel; 13155 b[7] = gc->fgPixel; 13156 b[8] = pat[0]; 13157 b[9] = pat[1]; 13158 sna->kgem.nbatch += 10; 13159 } else { 13160 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7; 13161 b[1] = br13; 13162 b[2] = (r->y + dy) << 16 | (r->x + dx); 13163 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13164 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13165 I915_GEM_DOMAIN_RENDER << 16 | 13166 I915_GEM_DOMAIN_RENDER | 13167 KGEM_RELOC_FENCED, 13168 0); 13169 b[5] = gc->bgPixel; 13170 b[6] = gc->fgPixel; 13171 b[7] = pat[0]; 13172 b[8] = pat[1]; 13173 sna->kgem.nbatch += 9; 13174 } 13175 } else do { 13176 int n_this_time, rem; 13177 13178 assert(sna->kgem.mode == KGEM_BLT); 13179 b = sna->kgem.batch + sna->kgem.nbatch; 13180 if (sna->kgem.gen >= 0100) { 13181 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13182 b[1] = br13; 13183 b[2] = 0; 13184 b[3] = 0; 13185 *(uint64_t *)(b+4) = 13186 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13187 I915_GEM_DOMAIN_RENDER << 16 | 13188 I915_GEM_DOMAIN_RENDER | 13189 KGEM_RELOC_FENCED, 13190 0); 13191 b[6] = gc->bgPixel; 13192 b[7] = gc->fgPixel; 13193 b[8] = pat[0]; 13194 b[9] = pat[1]; 13195 sna->kgem.nbatch += 10; 13196 } else { 13197 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13198 b[1] = br13; 13199 b[2] = 0; 13200 b[3] = 0; 13201 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13202 I915_GEM_DOMAIN_RENDER << 16 | 13203 I915_GEM_DOMAIN_RENDER | 13204 KGEM_RELOC_FENCED, 13205 0); 13206 b[5] = gc->bgPixel; 13207 b[6] = gc->fgPixel; 13208 b[7] = pat[0]; 13209 b[8] = pat[1]; 13210 sna->kgem.nbatch += 9; 13211 } 13212 13213 n_this_time = n; 13214 rem = kgem_batch_space(&sna->kgem); 13215 if (3*n_this_time > rem) 13216 n_this_time = rem / 3; 13217 assert(n_this_time); 13218 n -= n_this_time; 13219 13220 assert(sna->kgem.mode == KGEM_BLT); 13221 b = sna->kgem.batch + sna->kgem.nbatch; 13222 sna->kgem.nbatch += 3 * n_this_time; 13223 do { 13224 DBG(("%s: rect (%d, %d)x(%d, %d)\n", 13225 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13226 assert(r->x + dx >= 0); 13227 assert(r->y + dy >= 0); 13228 assert(r->x + dx + r->width <= pixmap->drawable.width); 13229 assert(r->y + dy + r->height <= pixmap->drawable.height); 13230 13231 b[0] = br00; 13232 b[1] = (r->y + dy) << 16 | (r->x + dx); 13233 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13234 13235 b += 3; r++; 13236 } while(--n_this_time); 13237 13238 if (!n) 13239 break; 13240 13241 _kgem_submit(&sna->kgem); 13242 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13243 } while (1); 13244 } else { 13245 RegionRec clip; 13246 13247 region_set(&clip, extents); 13248 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13249 return true; 13250 13251 assert(sna->kgem.mode == KGEM_BLT); 13252 b = sna->kgem.batch + sna->kgem.nbatch; 13253 if (sna->kgem.gen >= 0100) { 13254 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13255 b[1] = br13; 13256 b[2] = 0; 13257 b[3] = 0; 13258 *(uint64_t *)(b+4) = 13259 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13260 I915_GEM_DOMAIN_RENDER << 16 | 13261 I915_GEM_DOMAIN_RENDER | 13262 KGEM_RELOC_FENCED, 13263 0); 13264 b[6] = gc->bgPixel; 13265 b[7] = gc->fgPixel; 13266 b[8] = pat[0]; 13267 b[9] = pat[1]; 13268 sna->kgem.nbatch += 10; 13269 } else { 13270 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13271 b[1] = br13; 13272 b[2] = 0; 13273 b[3] = 0; 13274 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13275 I915_GEM_DOMAIN_RENDER << 16 | 13276 I915_GEM_DOMAIN_RENDER | 13277 KGEM_RELOC_FENCED, 13278 0); 13279 b[5] = gc->bgPixel; 13280 b[6] = gc->fgPixel; 13281 b[7] = pat[0]; 13282 b[8] = pat[1]; 13283 sna->kgem.nbatch += 9; 13284 } 13285 13286 if (clip.data == NULL) { 13287 do { 13288 BoxRec box; 13289 13290 box.x1 = r->x + drawable->x; 13291 box.y1 = r->y + drawable->y; 13292 box.x2 = bound(box.x1, r->width); 13293 box.y2 = bound(box.y1, r->height); 13294 r++; 13295 13296 if (box_intersect(&box, &clip.extents)) { 13297 if (!kgem_check_batch(&sna->kgem, 3)) { 13298 _kgem_submit(&sna->kgem); 13299 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13300 13301 assert(sna->kgem.mode == KGEM_BLT); 13302 b = sna->kgem.batch + sna->kgem.nbatch; 13303 if (sna->kgem.gen >= 0100) { 13304 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13305 b[1] = br13; 13306 b[2] = 0; 13307 b[3] = 0; 13308 *(uint64_t *)(b+4) = 13309 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13310 I915_GEM_DOMAIN_RENDER << 16 | 13311 I915_GEM_DOMAIN_RENDER | 13312 KGEM_RELOC_FENCED, 13313 0); 13314 b[6] = gc->bgPixel; 13315 b[7] = gc->fgPixel; 13316 b[8] = pat[0]; 13317 b[9] = pat[1]; 13318 sna->kgem.nbatch += 10; 13319 } else { 13320 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13321 b[1] = br13; 13322 b[2] = 0; 13323 b[3] = 0; 13324 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13325 I915_GEM_DOMAIN_RENDER << 16 | 13326 I915_GEM_DOMAIN_RENDER | 13327 KGEM_RELOC_FENCED, 13328 0); 13329 b[5] = gc->bgPixel; 13330 b[6] = gc->fgPixel; 13331 b[7] = pat[0]; 13332 b[8] = pat[1]; 13333 sna->kgem.nbatch += 9; 13334 } 13335 } 13336 13337 assert(sna->kgem.mode == KGEM_BLT); 13338 b = sna->kgem.batch + sna->kgem.nbatch; 13339 sna->kgem.nbatch += 3; 13340 b[0] = br00; 13341 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 13342 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 13343 } 13344 } while (--n); 13345 } else { 13346 const BoxRec * const clip_start = RegionBoxptr(&clip); 13347 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13348 const BoxRec *c; 13349 13350 do { 13351 BoxRec box; 13352 13353 box.x1 = r->x + drawable->x; 13354 box.y1 = r->y + drawable->y; 13355 box.x2 = bound(box.x1, r->width); 13356 box.y2 = bound(box.y1, r->height); 13357 r++; 13358 13359 c = find_clip_box_for_y(clip_start, 13360 clip_end, 13361 box.y1); 13362 while (c != clip_end) { 13363 BoxRec bb; 13364 if (box.y2 <= c->y1) 13365 break; 13366 13367 bb = box; 13368 if (box_intersect(&bb, c++)) { 13369 if (!kgem_check_batch(&sna->kgem, 3)) { 13370 _kgem_submit(&sna->kgem); 13371 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13372 13373 assert(sna->kgem.mode == KGEM_BLT); 13374 b = sna->kgem.batch + sna->kgem.nbatch; 13375 if (sna->kgem.gen >= 0100) { 13376 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13377 b[1] = br13; 13378 b[2] = 0; 13379 b[3] = 0; 13380 *(uint64_t *)(b+4) = 13381 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13382 I915_GEM_DOMAIN_RENDER << 16 | 13383 I915_GEM_DOMAIN_RENDER | 13384 KGEM_RELOC_FENCED, 13385 0); 13386 b[6] = gc->bgPixel; 13387 b[7] = gc->fgPixel; 13388 b[8] = pat[0]; 13389 b[9] = pat[1]; 13390 sna->kgem.nbatch += 10; 13391 } else { 13392 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13393 b[1] = br13; 13394 b[2] = 0; 13395 b[3] = 0; 13396 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13397 I915_GEM_DOMAIN_RENDER << 16 | 13398 I915_GEM_DOMAIN_RENDER | 13399 KGEM_RELOC_FENCED, 13400 0); 13401 b[5] = gc->bgPixel; 13402 b[6] = gc->fgPixel; 13403 b[7] = pat[0]; 13404 b[8] = pat[1]; 13405 sna->kgem.nbatch += 9; 13406 } 13407 } 13408 13409 assert(sna->kgem.mode == KGEM_BLT); 13410 b = sna->kgem.batch + sna->kgem.nbatch; 13411 sna->kgem.nbatch += 3; 13412 b[0] = br00; 13413 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 13414 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 13415 } 13416 } 13417 } while (--n); 13418 } 13419 } 13420 13421 assert_pixmap_damage(pixmap); 13422 sna->blt_state.fill_bo = 0; 13423 return true; 13424} 13425 13426static bool 13427sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable, 13428 struct kgem_bo *bo, 13429 struct sna_damage **damage, 13430 GCPtr gc, int n, xRectangle *r, 13431 const BoxRec *extents, unsigned clipped) 13432{ 13433 PixmapPtr scratch, stipple; 13434 uint8_t bytes[8], *dst = bytes; 13435 const uint8_t *src, *end; 13436 int j, stride; 13437 bool ret; 13438 13439 DBG(("%s: expanding %dx%d stipple to 8x8\n", 13440 __FUNCTION__, 13441 gc->stipple->drawable.width, 13442 gc->stipple->drawable.height)); 13443 13444 scratch = GetScratchPixmapHeader(drawable->pScreen, 13445 8, 8, 1, 1, 1, bytes); 13446 if (scratch == NullPixmap) 13447 return false; 13448 13449 stipple = gc->stipple; 13450 gc->stipple = scratch; 13451 13452 assert(stipple->devKind); 13453 stride = stipple->devKind; 13454 src = stipple->devPrivate.ptr; 13455 end = src + stride * stipple->drawable.height; 13456 for(j = 0; j < 8; j++) { 13457 switch (stipple->drawable.width) { 13458 case 1: *dst = (*src & 1) * 0xff; break; 13459 case 2: *dst = (*src & 3) * 0x55; break; 13460 case 4: *dst = (*src & 15) * 0x11; break; 13461 case 8: *dst = *src; break; 13462 default: assert(0); break; 13463 } 13464 dst++; 13465 src += stride; 13466 if (src == end) 13467 src = stipple->devPrivate.ptr; 13468 } 13469 13470 ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 13471 gc, n, r, extents, clipped); 13472 13473 gc->stipple = stipple; 13474 FreeScratchPixmapHeader(scratch); 13475 13476 return ret; 13477} 13478 13479static bool 13480sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, 13481 struct kgem_bo *bo, 13482 struct sna_damage **damage, 13483 GCPtr gc, int n, xRectangle *r, 13484 const BoxRec *extents, unsigned clipped) 13485{ 13486 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13487 struct sna *sna = to_sna_from_pixmap(pixmap); 13488 PixmapPtr stipple = gc->stipple; 13489 const DDXPointRec *origin = &gc->patOrg; 13490 int16_t dx, dy; 13491 uint32_t br00, br13; 13492 13493 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__, 13494 extents->x1, extents->y1, 13495 extents->x2, extents->y2, 13496 origin->x, origin->y, 13497 clipped)); 13498 13499 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13500 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13501 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13502 13503 br00 = 3 << 20; 13504 br13 = bo->pitch; 13505 if (sna->kgem.gen >= 040 && bo->tiling) { 13506 br00 |= BLT_DST_TILED; 13507 br13 >>= 2; 13508 } 13509 br13 |= (gc->fillStyle == FillStippled) << 29; 13510 br13 |= blt_depth(drawable->depth) << 24; 13511 br13 |= copy_ROP[gc->alu] << 16; 13512 13513 if (!clipped) { 13514 dx += drawable->x; 13515 dy += drawable->y; 13516 13517 sna_damage_add_rectangles(damage, r, n, dx, dy); 13518 do { 13519 int bx1 = (r->x - origin->x) & ~7; 13520 int bx2 = (r->x + r->width - origin->x + 7) & ~7; 13521 int bw = (bx2 - bx1)/8; 13522 int bh = r->height; 13523 int bstride = ALIGN(bw, 2); 13524 int src_stride; 13525 uint8_t *dst, *src; 13526 uint32_t *b; 13527 13528 DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n", 13529 __FUNCTION__, 13530 r->x, r->y, r->width, r->height, 13531 bx1, bx2)); 13532 13533 src_stride = bstride*bh; 13534 assert(src_stride > 0); 13535 if (src_stride <= 128) { 13536 src_stride = ALIGN(src_stride, 8) / 4; 13537 assert(src_stride <= 32); 13538 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13539 !kgem_check_bo_fenced(&sna->kgem, bo) || 13540 !kgem_check_reloc(&sna->kgem, 1)) { 13541 kgem_submit(&sna->kgem); 13542 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13543 return false; 13544 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13545 } 13546 13547 assert(sna->kgem.mode == KGEM_BLT); 13548 b = sna->kgem.batch + sna->kgem.nbatch; 13549 if (sna->kgem.gen >= 0100) { 13550 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13551 b[0] |= ((r->x - origin->x) & 7) << 17; 13552 b[1] = br13; 13553 b[2] = (r->y + dy) << 16 | (r->x + dx); 13554 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13555 *(uint64_t *)(b+4) = 13556 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13557 I915_GEM_DOMAIN_RENDER << 16 | 13558 I915_GEM_DOMAIN_RENDER | 13559 KGEM_RELOC_FENCED, 13560 0); 13561 b[6] = gc->bgPixel; 13562 b[7] = gc->fgPixel; 13563 13564 dst = (uint8_t *)&b[8]; 13565 sna->kgem.nbatch += 8 + src_stride; 13566 } else { 13567 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13568 b[0] |= ((r->x - origin->x) & 7) << 17; 13569 b[1] = br13; 13570 b[2] = (r->y + dy) << 16 | (r->x + dx); 13571 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13572 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13573 I915_GEM_DOMAIN_RENDER << 16 | 13574 I915_GEM_DOMAIN_RENDER | 13575 KGEM_RELOC_FENCED, 13576 0); 13577 b[5] = gc->bgPixel; 13578 b[6] = gc->fgPixel; 13579 13580 dst = (uint8_t *)&b[7]; 13581 sna->kgem.nbatch += 7 + src_stride; 13582 } 13583 assert(stipple->devKind); 13584 src_stride = stipple->devKind; 13585 src = stipple->devPrivate.ptr; 13586 src += (r->y - origin->y) * src_stride + bx1/8; 13587 src_stride -= bstride; 13588 do { 13589 int i = bstride; 13590 do { 13591 *dst++ = byte_reverse(*src++); 13592 *dst++ = byte_reverse(*src++); 13593 i -= 2; 13594 } while (i); 13595 src += src_stride; 13596 } while (--bh); 13597 } else { 13598 struct kgem_bo *upload; 13599 void *ptr; 13600 13601 if (!kgem_check_batch(&sna->kgem, 10) || 13602 !kgem_check_bo_fenced(&sna->kgem, bo) || 13603 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13604 kgem_submit(&sna->kgem); 13605 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13606 return false; 13607 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13608 } 13609 13610 upload = kgem_create_buffer(&sna->kgem, 13611 bstride*bh, 13612 KGEM_BUFFER_WRITE_INPLACE, 13613 &ptr); 13614 if (!upload) 13615 break; 13616 13617 if (sigtrap_get() == 0) { 13618 dst = ptr; 13619 assert(stipple->devKind); 13620 src_stride = stipple->devKind; 13621 src = stipple->devPrivate.ptr; 13622 src += (r->y - origin->y) * src_stride + bx1/8; 13623 src_stride -= bstride; 13624 do { 13625 int i = bstride; 13626 do { 13627 *dst++ = byte_reverse(*src++); 13628 *dst++ = byte_reverse(*src++); 13629 i -= 2; 13630 } while (i); 13631 src += src_stride; 13632 } while (--bh); 13633 13634 assert(sna->kgem.mode == KGEM_BLT); 13635 b = sna->kgem.batch + sna->kgem.nbatch; 13636 if (sna->kgem.gen >= 0100) { 13637 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13638 b[0] |= ((r->x - origin->x) & 7) << 17; 13639 b[1] = br13; 13640 b[2] = (r->y + dy) << 16 | (r->x + dx); 13641 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13642 *(uint64_t *)(b+4) = 13643 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13644 I915_GEM_DOMAIN_RENDER << 16 | 13645 I915_GEM_DOMAIN_RENDER | 13646 KGEM_RELOC_FENCED, 13647 0); 13648 *(uint64_t *)(b+6) = 13649 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13650 I915_GEM_DOMAIN_RENDER << 16 | 13651 KGEM_RELOC_FENCED, 13652 0); 13653 b[8] = gc->bgPixel; 13654 b[9] = gc->fgPixel; 13655 sna->kgem.nbatch += 10; 13656 } else { 13657 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13658 b[0] |= ((r->x - origin->x) & 7) << 17; 13659 b[1] = br13; 13660 b[2] = (r->y + dy) << 16 | (r->x + dx); 13661 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13662 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13663 I915_GEM_DOMAIN_RENDER << 16 | 13664 I915_GEM_DOMAIN_RENDER | 13665 KGEM_RELOC_FENCED, 13666 0); 13667 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13668 I915_GEM_DOMAIN_RENDER << 16 | 13669 KGEM_RELOC_FENCED, 13670 0); 13671 b[6] = gc->bgPixel; 13672 b[7] = gc->fgPixel; 13673 13674 sna->kgem.nbatch += 8; 13675 } 13676 sigtrap_put(); 13677 } 13678 13679 kgem_bo_destroy(&sna->kgem, upload); 13680 } 13681 13682 r++; 13683 } while (--n); 13684 } else { 13685 RegionRec clip; 13686 DDXPointRec pat; 13687 13688 region_set(&clip, extents); 13689 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13690 return true; 13691 13692 pat.x = origin->x + drawable->x; 13693 pat.y = origin->y + drawable->y; 13694 13695 if (clip.data == NULL) { 13696 do { 13697 BoxRec box; 13698 int bx1, bx2, bw, bh, bstride; 13699 int src_stride; 13700 uint8_t *dst, *src; 13701 uint32_t *b; 13702 struct kgem_bo *upload; 13703 void *ptr; 13704 13705 box.x1 = r->x + drawable->x; 13706 box.x2 = bound(box.x1, r->width); 13707 box.y1 = r->y + drawable->y; 13708 box.y2 = bound(box.y1, r->height); 13709 r++; 13710 13711 if (!box_intersect(&box, &clip.extents)) 13712 continue; 13713 13714 bx1 = (box.x1 - pat.x) & ~7; 13715 bx2 = (box.x2 - pat.x + 7) & ~7; 13716 bw = (bx2 - bx1)/8; 13717 bh = box.y2 - box.y1; 13718 bstride = ALIGN(bw, 2); 13719 13720 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n", 13721 __FUNCTION__, 13722 r->x, r->y, r->width, r->height, 13723 box.x1, box.y1, box.x2, box.y2, 13724 bx1, bx2, bw, bstride)); 13725 13726 src_stride = bstride*bh; 13727 assert(src_stride > 0); 13728 if (src_stride <= 128) { 13729 src_stride = ALIGN(src_stride, 8) / 4; 13730 assert(src_stride <= 32); 13731 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13732 !kgem_check_bo_fenced(&sna->kgem, bo) || 13733 !kgem_check_reloc(&sna->kgem, 1)) { 13734 kgem_submit(&sna->kgem); 13735 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13736 return false; 13737 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13738 } 13739 13740 assert(sna->kgem.mode == KGEM_BLT); 13741 b = sna->kgem.batch + sna->kgem.nbatch; 13742 if (sna->kgem.gen >= 0100) { 13743 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13744 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13745 b[1] = br13; 13746 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13747 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13748 *(uint64_t *)(b+4) = 13749 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13750 I915_GEM_DOMAIN_RENDER << 16 | 13751 I915_GEM_DOMAIN_RENDER | 13752 KGEM_RELOC_FENCED, 13753 0); 13754 b[6] = gc->bgPixel; 13755 b[7] = gc->fgPixel; 13756 13757 dst = (uint8_t *)&b[8]; 13758 sna->kgem.nbatch += 8 + src_stride; 13759 } else { 13760 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13761 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13762 b[1] = br13; 13763 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13764 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13765 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13766 I915_GEM_DOMAIN_RENDER << 16 | 13767 I915_GEM_DOMAIN_RENDER | 13768 KGEM_RELOC_FENCED, 13769 0); 13770 b[5] = gc->bgPixel; 13771 b[6] = gc->fgPixel; 13772 13773 dst = (uint8_t *)&b[7]; 13774 sna->kgem.nbatch += 7 + src_stride; 13775 } 13776 13777 assert(stipple->devKind); 13778 src_stride = stipple->devKind; 13779 src = stipple->devPrivate.ptr; 13780 src += (box.y1 - pat.y) * src_stride + bx1/8; 13781 src_stride -= bstride; 13782 do { 13783 int i = bstride; 13784 do { 13785 *dst++ = byte_reverse(*src++); 13786 *dst++ = byte_reverse(*src++); 13787 i -= 2; 13788 } while (i); 13789 src += src_stride; 13790 } while (--bh); 13791 } else { 13792 if (!kgem_check_batch(&sna->kgem, 10) || 13793 !kgem_check_bo_fenced(&sna->kgem, bo) || 13794 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13795 kgem_submit(&sna->kgem); 13796 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13797 return false; 13798 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13799 } 13800 13801 upload = kgem_create_buffer(&sna->kgem, 13802 bstride*bh, 13803 KGEM_BUFFER_WRITE_INPLACE, 13804 &ptr); 13805 if (!upload) 13806 break; 13807 13808 if (sigtrap_get() == 0) { 13809 dst = ptr; 13810 assert(stipple->devKind); 13811 src_stride = stipple->devKind; 13812 src = stipple->devPrivate.ptr; 13813 src += (box.y1 - pat.y) * src_stride + bx1/8; 13814 src_stride -= bstride; 13815 do { 13816 int i = bstride; 13817 do { 13818 *dst++ = byte_reverse(*src++); 13819 *dst++ = byte_reverse(*src++); 13820 i -= 2; 13821 } while (i); 13822 src += src_stride; 13823 } while (--bh); 13824 13825 assert(sna->kgem.mode == KGEM_BLT); 13826 b = sna->kgem.batch + sna->kgem.nbatch; 13827 if (sna->kgem.gen >= 0100) { 13828 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13829 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13830 b[1] = br13; 13831 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13832 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13833 *(uint64_t *)(b+4) = 13834 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13835 I915_GEM_DOMAIN_RENDER << 16 | 13836 I915_GEM_DOMAIN_RENDER | 13837 KGEM_RELOC_FENCED, 13838 0); 13839 *(uint64_t *)(b+5) = 13840 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13841 I915_GEM_DOMAIN_RENDER << 16 | 13842 KGEM_RELOC_FENCED, 13843 0); 13844 b[8] = gc->bgPixel; 13845 b[9] = gc->fgPixel; 13846 sna->kgem.nbatch += 10; 13847 } else { 13848 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13849 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13850 b[1] = br13; 13851 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13852 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13853 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13854 I915_GEM_DOMAIN_RENDER << 16 | 13855 I915_GEM_DOMAIN_RENDER | 13856 KGEM_RELOC_FENCED, 13857 0); 13858 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13859 I915_GEM_DOMAIN_RENDER << 16 | 13860 KGEM_RELOC_FENCED, 13861 0); 13862 b[6] = gc->bgPixel; 13863 b[7] = gc->fgPixel; 13864 13865 sna->kgem.nbatch += 8; 13866 } 13867 sigtrap_put(); 13868 } 13869 kgem_bo_destroy(&sna->kgem, upload); 13870 } 13871 } while (--n); 13872 } else { 13873 const BoxRec * const clip_start = RegionBoxptr(&clip); 13874 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13875 const BoxRec *c; 13876 13877 do { 13878 BoxRec unclipped; 13879 int bx1, bx2, bw, bh, bstride; 13880 int src_stride; 13881 uint8_t *dst, *src; 13882 uint32_t *b; 13883 struct kgem_bo *upload; 13884 void *ptr; 13885 13886 unclipped.x1 = r->x + drawable->x; 13887 unclipped.x2 = bound(unclipped.x1, r->width); 13888 unclipped.y1 = r->y + drawable->y; 13889 unclipped.y2 = bound(unclipped.y1, r->height); 13890 r++; 13891 13892 c = find_clip_box_for_y(clip_start, 13893 clip_end, 13894 unclipped.y1); 13895 while (c != clip_end) { 13896 BoxRec box; 13897 13898 if (unclipped.y2 <= c->y1) 13899 break; 13900 13901 box = unclipped; 13902 if (!box_intersect(&box, c++)) 13903 continue; 13904 13905 bx1 = (box.x1 - pat.x) & ~7; 13906 bx2 = (box.x2 - pat.x + 7) & ~7; 13907 bw = (bx2 - bx1)/8; 13908 bh = box.y2 - box.y1; 13909 bstride = ALIGN(bw, 2); 13910 13911 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n", 13912 __FUNCTION__, 13913 r->x, r->y, r->width, r->height, 13914 box.x1, box.y1, box.x2, box.y2, 13915 bx1, bx2)); 13916 13917 src_stride = bstride*bh; 13918 assert(src_stride > 0); 13919 if (src_stride <= 128) { 13920 src_stride = ALIGN(src_stride, 8) / 4; 13921 assert(src_stride <= 32); 13922 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13923 !kgem_check_bo_fenced(&sna->kgem, bo) || 13924 !kgem_check_reloc(&sna->kgem, 1)) { 13925 kgem_submit(&sna->kgem); 13926 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13927 return false; 13928 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13929 } 13930 13931 assert(sna->kgem.mode == KGEM_BLT); 13932 b = sna->kgem.batch + sna->kgem.nbatch; 13933 if (sna->kgem.gen >= 0100) { 13934 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13935 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13936 b[1] = br13; 13937 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13938 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13939 *(uint64_t *)(b+4) = 13940 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13941 I915_GEM_DOMAIN_RENDER << 16 | 13942 I915_GEM_DOMAIN_RENDER | 13943 KGEM_RELOC_FENCED, 13944 0); 13945 b[6] = gc->bgPixel; 13946 b[7] = gc->fgPixel; 13947 13948 dst = (uint8_t *)&b[8]; 13949 sna->kgem.nbatch += 8 + src_stride; 13950 } else { 13951 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13952 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13953 b[1] = br13; 13954 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13955 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13956 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13957 I915_GEM_DOMAIN_RENDER << 16 | 13958 I915_GEM_DOMAIN_RENDER | 13959 KGEM_RELOC_FENCED, 13960 0); 13961 b[5] = gc->bgPixel; 13962 b[6] = gc->fgPixel; 13963 13964 dst = (uint8_t *)&b[7]; 13965 sna->kgem.nbatch += 7 + src_stride; 13966 } 13967 assert(stipple->devKind); 13968 src_stride = stipple->devKind; 13969 src = stipple->devPrivate.ptr; 13970 src += (box.y1 - pat.y) * src_stride + bx1/8; 13971 src_stride -= bstride; 13972 do { 13973 int i = bstride; 13974 do { 13975 *dst++ = byte_reverse(*src++); 13976 *dst++ = byte_reverse(*src++); 13977 i -= 2; 13978 } while (i); 13979 src += src_stride; 13980 } while (--bh); 13981 } else { 13982 if (!kgem_check_batch(&sna->kgem, 10) || 13983 !kgem_check_bo_fenced(&sna->kgem, bo) || 13984 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13985 kgem_submit(&sna->kgem); 13986 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13987 return false; 13988 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13989 } 13990 13991 upload = kgem_create_buffer(&sna->kgem, 13992 bstride*bh, 13993 KGEM_BUFFER_WRITE_INPLACE, 13994 &ptr); 13995 if (!upload) 13996 break; 13997 13998 if (sigtrap_get() == 0) { 13999 dst = ptr; 14000 assert(stipple->devKind); 14001 src_stride = stipple->devKind; 14002 src = stipple->devPrivate.ptr; 14003 src += (box.y1 - pat.y) * src_stride + bx1/8; 14004 src_stride -= bstride; 14005 do { 14006 int i = bstride; 14007 do { 14008 *dst++ = byte_reverse(*src++); 14009 *dst++ = byte_reverse(*src++); 14010 i -= 2; 14011 } while (i); 14012 src += src_stride; 14013 } while (--bh); 14014 14015 assert(sna->kgem.mode == KGEM_BLT); 14016 b = sna->kgem.batch + sna->kgem.nbatch; 14017 if (sna->kgem.gen >= 0100) { 14018 b[0] = XY_MONO_SRC_COPY | br00 | 8; 14019 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14020 b[1] = br13; 14021 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14022 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 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 *(uint64_t *)(b+6) = 14030 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14031 I915_GEM_DOMAIN_RENDER << 16 | 14032 KGEM_RELOC_FENCED, 14033 0); 14034 b[8] = gc->bgPixel; 14035 b[9] = gc->fgPixel; 14036 sna->kgem.nbatch += 10; 14037 } else { 14038 b[0] = XY_MONO_SRC_COPY | br00 | 6; 14039 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14040 b[1] = br13; 14041 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14042 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14043 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14044 I915_GEM_DOMAIN_RENDER << 16 | 14045 I915_GEM_DOMAIN_RENDER | 14046 KGEM_RELOC_FENCED, 14047 0); 14048 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14049 I915_GEM_DOMAIN_RENDER << 16 | 14050 KGEM_RELOC_FENCED, 14051 0); 14052 b[6] = gc->bgPixel; 14053 b[7] = gc->fgPixel; 14054 14055 sna->kgem.nbatch += 8; 14056 } 14057 sigtrap_put(); 14058 } 14059 kgem_bo_destroy(&sna->kgem, upload); 14060 } 14061 } 14062 } while (--n); 14063 14064 } 14065 } 14066 14067 sna->blt_state.fill_bo = 0; 14068 return true; 14069} 14070 14071static void 14072sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, 14073 struct kgem_bo *bo, 14074 uint32_t br00, uint32_t br13, 14075 const GC *gc, 14076 const BoxRec *box, 14077 const DDXPointRec *origin) 14078{ 14079 int x1, x2, y1, y2; 14080 uint32_t *b; 14081 14082 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14083 int oy = (y1 - origin->y) % gc->stipple->drawable.height; 14084 if (oy < 0) 14085 oy += gc->stipple->drawable.height; 14086 14087 y2 = box->y2; 14088 if (y2 - y1 > gc->stipple->drawable.height - oy) 14089 y2 = y1 + gc->stipple->drawable.height - oy; 14090 14091 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14092 int bx1, bx2, bw, bh, len, ox; 14093 uint8_t *dst, *src; 14094 14095 x2 = box->x2; 14096 ox = (x1 - origin->x) % gc->stipple->drawable.width; 14097 if (ox < 0) 14098 ox += gc->stipple->drawable.width; 14099 bx1 = ox & ~7; 14100 bx2 = ox + (x2 - x1); 14101 if (bx2 > gc->stipple->drawable.width) { 14102 bx2 = gc->stipple->drawable.width; 14103 x2 = x1 + bx2-ox; 14104 } 14105 bw = (bx2 - bx1 + 7)/8; 14106 bw = ALIGN(bw, 2); 14107 bh = y2 - y1; 14108 14109 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n", 14110 __FUNCTION__, 14111 x1, y1, x2-x1, y2-y1, 14112 origin->x, origin->y, 14113 ox, oy, bx1, bx2, 14114 gc->stipple->drawable.width, 14115 gc->stipple->drawable.height)); 14116 14117 len = bw*bh; 14118 len = ALIGN(len, 8) / 4; 14119 assert(len > 0); 14120 assert(len <= 32); 14121 if (!kgem_check_batch(&sna->kgem, 8+len) || 14122 !kgem_check_bo_fenced(&sna->kgem, bo) || 14123 !kgem_check_reloc(&sna->kgem, 1)) { 14124 kgem_submit(&sna->kgem); 14125 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14126 return; /* XXX fallback? */ 14127 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14128 } 14129 14130 assert(sna->kgem.mode == KGEM_BLT); 14131 b = sna->kgem.batch + sna->kgem.nbatch; 14132 if (sna->kgem.gen >= 0100) { 14133 b[0] = br00 | (6 + len) | (ox & 7) << 17; 14134 b[1] = br13; 14135 b[2] = y1 << 16 | x1; 14136 b[3] = y2 << 16 | x2; 14137 *(uint64_t *)(b+4) = 14138 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14139 I915_GEM_DOMAIN_RENDER << 16 | 14140 I915_GEM_DOMAIN_RENDER | 14141 KGEM_RELOC_FENCED, 14142 0); 14143 b[6] = gc->bgPixel; 14144 b[7] = gc->fgPixel; 14145 dst = (uint8_t *)&b[8]; 14146 sna->kgem.nbatch += 8 + len; 14147 } else { 14148 b[0] = br00 | (5 + len) | (ox & 7) << 17; 14149 b[1] = br13; 14150 b[2] = y1 << 16 | x1; 14151 b[3] = y2 << 16 | x2; 14152 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14153 I915_GEM_DOMAIN_RENDER << 16 | 14154 I915_GEM_DOMAIN_RENDER | 14155 KGEM_RELOC_FENCED, 14156 0); 14157 b[5] = gc->bgPixel; 14158 b[6] = gc->fgPixel; 14159 dst = (uint8_t *)&b[7]; 14160 sna->kgem.nbatch += 7 + len; 14161 } 14162 14163 assert(gc->stipple->devKind); 14164 len = gc->stipple->devKind; 14165 src = gc->stipple->devPrivate.ptr; 14166 src += oy*len + ox/8; 14167 len -= bw; 14168 do { 14169 int i = bw; 14170 do { 14171 *dst++ = byte_reverse(*src++); 14172 *dst++ = byte_reverse(*src++); 14173 i -= 2; 14174 } while (i); 14175 src += len; 14176 } while (--bh); 14177 } 14178 } 14179} 14180 14181static void 14182sna_poly_fill_rect_stippled_n_box(struct sna *sna, 14183 struct kgem_bo *bo, 14184 struct kgem_bo **tile, 14185 uint32_t br00, uint32_t br13, 14186 const GC *gc, 14187 const BoxRec *box, 14188 const DDXPointRec *origin) 14189{ 14190 int x1, x2, y1, y2; 14191 int w = gc->stipple->drawable.width; 14192 int h = gc->stipple->drawable.height; 14193 int stride = gc->stipple->devKind; 14194 uint32_t *b; 14195 14196 assert(stride); 14197 if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) { 14198 br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20)); 14199 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14200 br00, br13, gc, 14201 box, origin); 14202 return; 14203 } 14204 14205 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14206 int row, oy = (y1 - origin->y) % gc->stipple->drawable.height; 14207 if (oy < 0) 14208 oy += h; 14209 14210 y2 = box->y2; 14211 if (y2 - y1 > h - oy) 14212 y2 = y1 + h - oy; 14213 14214 row = oy * stride; 14215 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14216 int bx1, bx2, bw, bh, len, ox; 14217 bool use_tile; 14218 14219 x2 = box->x2; 14220 ox = (x1 - origin->x) % w; 14221 if (ox < 0) 14222 ox += w; 14223 bx1 = ox & ~7; 14224 bx2 = ox + (x2 - x1); 14225 if (bx2 > w) { 14226 bx2 = w; 14227 x2 = x1 + bx2-ox; 14228 } 14229 14230 use_tile = y2-y1 == h && x2-x1 == w; 14231 14232 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n", 14233 __FUNCTION__, 14234 x1, y1, x2-x1, y2-y1, 14235 origin->x, origin->y, 14236 ox, oy, bx1, bx2, w, h, 14237 use_tile)); 14238 14239 bw = (bx2 - bx1 + 7)/8; 14240 bw = ALIGN(bw, 2); 14241 bh = y2 - y1; 14242 14243 len = bw*bh; 14244 len = ALIGN(len, 8) / 4; 14245 assert(len > 0); 14246 if (!kgem_check_batch(&sna->kgem, 8+len) || 14247 !kgem_check_bo_fenced(&sna->kgem, bo) || 14248 !kgem_check_reloc(&sna->kgem, 2)) { 14249 kgem_submit(&sna->kgem); 14250 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14251 return; /* XXX fallback? */ 14252 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14253 } 14254 14255 assert(sna->kgem.mode == KGEM_BLT); 14256 b = sna->kgem.batch + sna->kgem.nbatch; 14257 14258 if (!use_tile && len <= 32) { 14259 uint8_t *dst, *src; 14260 14261 if (sna->kgem.gen >= 0100) { 14262 b[0] = XY_MONO_SRC_COPY_IMM; 14263 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14264 b[0] |= (ox & 7) << 17; 14265 b[0] |= (6 + len); 14266 b[1] = br13; 14267 b[2] = y1 << 16 | x1; 14268 b[3] = y2 << 16 | x2; 14269 *(uint64_t *)(b+4) = 14270 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14271 I915_GEM_DOMAIN_RENDER << 16 | 14272 I915_GEM_DOMAIN_RENDER | 14273 KGEM_RELOC_FENCED, 14274 0); 14275 b[6] = gc->bgPixel; 14276 b[7] = gc->fgPixel; 14277 14278 dst = (uint8_t *)&b[8]; 14279 sna->kgem.nbatch += 8 + len; 14280 } else { 14281 b[0] = XY_MONO_SRC_COPY_IMM; 14282 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14283 b[0] |= (ox & 7) << 17; 14284 b[0] |= (5 + len); 14285 b[1] = br13; 14286 b[2] = y1 << 16 | x1; 14287 b[3] = y2 << 16 | x2; 14288 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14289 I915_GEM_DOMAIN_RENDER << 16 | 14290 I915_GEM_DOMAIN_RENDER | 14291 KGEM_RELOC_FENCED, 14292 0); 14293 b[5] = gc->bgPixel; 14294 b[6] = gc->fgPixel; 14295 14296 dst = (uint8_t *)&b[7]; 14297 sna->kgem.nbatch += 7 + len; 14298 } 14299 14300 assert(gc->stipple->devKind); 14301 len = gc->stipple->devKind; 14302 src = gc->stipple->devPrivate.ptr; 14303 src += oy*len + ox/8; 14304 len -= bw; 14305 do { 14306 int i = bw; 14307 do { 14308 *dst++ = byte_reverse(*src++); 14309 *dst++ = byte_reverse(*src++); 14310 i -= 2; 14311 } while (i); 14312 src += len; 14313 } while (--bh); 14314 } else { 14315 bool has_tile = use_tile && *tile; 14316 struct kgem_bo *upload; 14317 uint8_t *dst, *src; 14318 void *ptr; 14319 14320 if (has_tile) { 14321 upload = kgem_bo_reference(*tile); 14322 } else { 14323 upload = kgem_create_buffer(&sna->kgem, bw*bh, 14324 KGEM_BUFFER_WRITE_INPLACE, 14325 &ptr); 14326 if (!upload) 14327 return; 14328 } 14329 14330 assert(sna->kgem.mode == KGEM_BLT); 14331 b = sna->kgem.batch + sna->kgem.nbatch; 14332 if (sna->kgem.gen >= 0100) { 14333 b[0] = br00 | (ox & 7) << 17 | 8; 14334 b[1] = br13; 14335 b[2] = y1 << 16 | x1; 14336 b[3] = y2 << 16 | x2; 14337 *(uint64_t *)(b+4) = 14338 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14339 I915_GEM_DOMAIN_RENDER << 16 | 14340 I915_GEM_DOMAIN_RENDER | 14341 KGEM_RELOC_FENCED, 14342 0); 14343 *(uint64_t *)(b+6) = 14344 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14345 I915_GEM_DOMAIN_RENDER << 16 | 14346 KGEM_RELOC_FENCED, 14347 0); 14348 b[8] = gc->bgPixel; 14349 b[9] = gc->fgPixel; 14350 sna->kgem.nbatch += 10; 14351 } else { 14352 b[0] = br00 | (ox & 7) << 17 | 6; 14353 b[1] = br13; 14354 b[2] = y1 << 16 | x1; 14355 b[3] = y2 << 16 | x2; 14356 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14357 I915_GEM_DOMAIN_RENDER << 16 | 14358 I915_GEM_DOMAIN_RENDER | 14359 KGEM_RELOC_FENCED, 14360 0); 14361 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14362 I915_GEM_DOMAIN_RENDER << 16 | 14363 KGEM_RELOC_FENCED, 14364 0); 14365 b[6] = gc->bgPixel; 14366 b[7] = gc->fgPixel; 14367 sna->kgem.nbatch += 8; 14368 } 14369 14370 if (!has_tile) { 14371 dst = ptr; 14372 len = stride; 14373 src = gc->stipple->devPrivate.ptr; 14374 src += row + (ox >> 3); 14375 len -= bw; 14376 do { 14377 int i = bw; 14378 do { 14379 *dst++ = byte_reverse(*src++); 14380 *dst++ = byte_reverse(*src++); 14381 i -= 2; 14382 } while (i); 14383 src += len; 14384 } while (--bh); 14385 if (use_tile) 14386 *tile = kgem_bo_reference(upload); 14387 } 14388 14389 kgem_bo_destroy(&sna->kgem, upload); 14390 } 14391 } 14392 } 14393} 14394 14395static bool 14396sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, 14397 struct kgem_bo *bo, 14398 struct sna_damage **damage, 14399 GCPtr gc, int n, xRectangle *r, 14400 const BoxRec *extents, unsigned clipped) 14401{ 14402 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14403 struct sna *sna = to_sna_from_pixmap(pixmap); 14404 DDXPointRec origin = gc->patOrg; 14405 int16_t dx, dy; 14406 uint32_t br00, br13; 14407 14408 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14409 extents->x1, extents->y1, 14410 extents->x2, extents->y2, 14411 origin.x, origin.y, 14412 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14413 14414 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14415 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14416 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14417 14418 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; 14419 br13 = bo->pitch; 14420 if (sna->kgem.gen >= 040 && bo->tiling) { 14421 br00 |= BLT_DST_TILED; 14422 br13 >>= 2; 14423 } 14424 br13 |= (gc->fillStyle == FillStippled) << 29; 14425 br13 |= blt_depth(drawable->depth) << 24; 14426 br13 |= copy_ROP[gc->alu] << 16; 14427 14428 origin.x += dx + drawable->x; 14429 origin.y += dy + drawable->y; 14430 14431 if (!clipped) { 14432 dx += drawable->x; 14433 dy += drawable->y; 14434 14435 sna_damage_add_rectangles(damage, r, n, dx, dy); 14436 do { 14437 BoxRec box; 14438 14439 box.x1 = r->x + dx; 14440 box.y1 = r->y + dy; 14441 box.x2 = box.x1 + r->width; 14442 box.y2 = box.y1 + r->height; 14443 14444 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14445 br00, br13, gc, 14446 &box, &origin); 14447 r++; 14448 } while (--n); 14449 } else { 14450 RegionRec clip; 14451 14452 region_set(&clip, extents); 14453 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14454 DBG(("%s: all clipped\n", __FUNCTION__)); 14455 return true; 14456 } 14457 14458 if (clip.data == NULL) { 14459 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14460 __FUNCTION__, 14461 clip.extents.x1, clip.extents.y1, 14462 clip.extents.x2, clip.extents.y2)); 14463 do { 14464 BoxRec box; 14465 14466 box.x1 = r->x + drawable->x; 14467 box.x2 = bound(box.x1, r->width); 14468 box.y1 = r->y + drawable->y; 14469 box.y2 = bound(box.y1, r->height); 14470 r++; 14471 14472 DBG(("%s: box (%d, %d), (%d, %d)\n", 14473 __FUNCTION__, 14474 box.x1, box.y1, box.x2, box.y2)); 14475 if (!box_intersect(&box, &clip.extents)) 14476 continue; 14477 14478 box.x1 += dx; box.x2 += dx; 14479 box.y1 += dy; box.y2 += dy; 14480 14481 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14482 br00, br13, gc, 14483 &box, &origin); 14484 } while (--n); 14485 } else { 14486 const BoxRec * const clip_start = RegionBoxptr(&clip); 14487 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14488 const BoxRec *c; 14489 14490 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14491 clip_start->x1, clip_start->y1, 14492 clip_start->x2, clip_start->y2, 14493 clip_end->x1, clip_end->y1, 14494 clip_end->x2, clip_end->y2)); 14495 do { 14496 BoxRec unclipped; 14497 14498 unclipped.x1 = r->x + drawable->x; 14499 unclipped.x2 = bound(unclipped.x1, r->width); 14500 unclipped.y1 = r->y + drawable->y; 14501 unclipped.y2 = bound(unclipped.y1, r->height); 14502 r++; 14503 14504 c = find_clip_box_for_y(clip_start, 14505 clip_end, 14506 unclipped.y1); 14507 while (c != clip_end) { 14508 BoxRec box; 14509 14510 if (unclipped.y2 <= c->y1) 14511 break; 14512 14513 box = unclipped; 14514 if (!box_intersect(&box, c++)) 14515 continue; 14516 14517 box.x1 += dx; box.x2 += dx; 14518 box.y1 += dy; box.y2 += dy; 14519 14520 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14521 br00, br13, gc, 14522 &box, &origin); 14523 } 14524 } while (--n); 14525 } 14526 } 14527 14528 assert_pixmap_damage(pixmap); 14529 sna->blt_state.fill_bo = 0; 14530 return true; 14531} 14532 14533static bool 14534sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, 14535 struct kgem_bo *bo, 14536 struct sna_damage **damage, 14537 GCPtr gc, int n, xRectangle *r, 14538 const BoxRec *extents, unsigned clipped) 14539{ 14540 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14541 struct sna *sna = to_sna_from_pixmap(pixmap); 14542 DDXPointRec origin = gc->patOrg; 14543 struct kgem_bo *tile = NULL; 14544 int16_t dx, dy; 14545 uint32_t br00, br13; 14546 14547 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14548 extents->x1, extents->y1, 14549 extents->x2, extents->y2, 14550 origin.x, origin.y, 14551 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14552 14553 if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0) 14554 return sna_poly_fill_rect_stippled_n_blt__imm(drawable, 14555 bo, damage, 14556 gc, n, r, 14557 extents, clipped); 14558 14559 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14560 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14561 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14562 14563 br00 = XY_MONO_SRC_COPY | 3 << 20; 14564 br13 = bo->pitch; 14565 if (sna->kgem.gen >= 040 && bo->tiling) { 14566 br00 |= BLT_DST_TILED; 14567 br13 >>= 2; 14568 } 14569 br13 |= (gc->fillStyle == FillStippled) << 29; 14570 br13 |= blt_depth(drawable->depth) << 24; 14571 br13 |= copy_ROP[gc->alu] << 16; 14572 14573 origin.x += dx + drawable->x; 14574 origin.y += dy + drawable->y; 14575 14576 if (!clipped) { 14577 dx += drawable->x; 14578 dy += drawable->y; 14579 14580 sna_damage_add_rectangles(damage, r, n, dx, dy); 14581 do { 14582 BoxRec box; 14583 14584 box.x1 = r->x + dx; 14585 box.y1 = r->y + dy; 14586 box.x2 = box.x1 + r->width; 14587 box.y2 = box.y1 + r->height; 14588 14589 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14590 br00, br13, gc, 14591 &box, &origin); 14592 r++; 14593 } while (--n); 14594 } else { 14595 RegionRec clip; 14596 14597 region_set(&clip, extents); 14598 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14599 DBG(("%s: all clipped\n", __FUNCTION__)); 14600 return true; 14601 } 14602 14603 if (clip.data == NULL) { 14604 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14605 __FUNCTION__, 14606 clip.extents.x1, clip.extents.y1, 14607 clip.extents.x2, clip.extents.y2)); 14608 do { 14609 BoxRec box; 14610 14611 box.x1 = r->x + drawable->x; 14612 box.x2 = bound(box.x1, r->width); 14613 box.y1 = r->y + drawable->y; 14614 box.y2 = bound(box.y1, r->height); 14615 r++; 14616 14617 DBG(("%s: box (%d, %d), (%d, %d)\n", 14618 __FUNCTION__, 14619 box.x1, box.y1, box.x2, box.y2)); 14620 if (!box_intersect(&box, &clip.extents)) 14621 continue; 14622 14623 box.x1 += dx; box.x2 += dx; 14624 box.y1 += dy; box.y2 += dy; 14625 14626 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14627 br00, br13, gc, 14628 &box, &origin); 14629 } while (--n); 14630 } else { 14631 const BoxRec * const clip_start = RegionBoxptr(&clip); 14632 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14633 const BoxRec *c; 14634 14635 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14636 clip_start->x1, clip_start->y1, 14637 clip_start->x2, clip_start->y2, 14638 clip_end->x1, clip_end->y1, 14639 clip_end->x2, clip_end->y2)); 14640 do { 14641 BoxRec unclipped; 14642 14643 unclipped.x1 = r->x + drawable->x; 14644 unclipped.x2 = bound(unclipped.x1, r->width); 14645 unclipped.y1 = r->y + drawable->y; 14646 unclipped.y2 = bound(unclipped.y1, r->height); 14647 r++; 14648 14649 c = find_clip_box_for_y(clip_start, 14650 clip_end, 14651 unclipped.y1); 14652 while (c != clip_end) { 14653 BoxRec box; 14654 14655 if (unclipped.y2 <= c->y1) 14656 break; 14657 14658 box = unclipped; 14659 if (!box_intersect(&box, c++)) 14660 continue; 14661 14662 box.x1 += dx; box.x2 += dx; 14663 box.y1 += dy; box.y2 += dy; 14664 14665 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14666 br00, br13, gc, 14667 &box, &origin); 14668 } 14669 } while (--n); 14670 } 14671 } 14672 14673 assert_pixmap_damage(pixmap); 14674 if (tile) 14675 kgem_bo_destroy(&sna->kgem, tile); 14676 sna->blt_state.fill_bo = 0; 14677 return true; 14678} 14679 14680static bool 14681sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 14682 struct kgem_bo *bo, 14683 struct sna_damage **damage, 14684 GCPtr gc, int n, xRectangle *rect, 14685 const BoxRec *extents, unsigned clipped) 14686{ 14687 14688 PixmapPtr stipple = gc->stipple; 14689 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14690 14691 if (bo->tiling == I915_TILING_Y) { 14692 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 14693 /* This is cheating, but only the gpu_bo can be tiled */ 14694 assert(bo == __sna_pixmap_get_bo(pixmap)); 14695 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 14696 if (bo == NULL) { 14697 DBG(("%s: fallback -- unable to change tiling\n", 14698 __FUNCTION__)); 14699 return false; 14700 } 14701 } 14702 14703 if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo)) 14704 return false; 14705 14706 if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ)) 14707 return false; 14708 14709 DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n", 14710 __FUNCTION__, gc->patOrg.x, gc->patOrg.y, 14711 extents->x2 - gc->patOrg.x - drawable->x, 14712 extents->y2 - gc->patOrg.y - drawable->y, 14713 stipple->drawable.width, stipple->drawable.height)); 14714 14715 if ((stipple->drawable.width | stipple->drawable.height) == 8) 14716 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14717 gc, n, rect, 14718 extents, clipped); 14719 14720 if ((stipple->drawable.width | stipple->drawable.height) <= 0xc && 14721 is_power_of_two(stipple->drawable.width) && 14722 is_power_of_two(stipple->drawable.height)) 14723 return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage, 14724 gc, n, rect, 14725 extents, clipped); 14726 14727 if (extents->x1 - gc->patOrg.x - drawable->x >= 0 && 14728 extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width && 14729 extents->y1 - gc->patOrg.y - drawable->y >= 0 && 14730 extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) { 14731 if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8) 14732 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14733 gc, n, rect, 14734 extents, clipped); 14735 else 14736 return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage, 14737 gc, n, rect, 14738 extents, clipped); 14739 } else { 14740 return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage, 14741 gc, n, rect, 14742 extents, clipped); 14743 } 14744} 14745 14746static unsigned 14747sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc, 14748 int *_n, xRectangle **_r, 14749 BoxPtr out) 14750{ 14751 int n; 14752 xRectangle *r; 14753 Box32Rec box; 14754 bool clipped; 14755 14756 if (*_n == 0) 14757 return 0; 14758 14759 DBG(("%s: [0] = (%d, %d)x(%d, %d)\n", 14760 __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height)); 14761 14762 /* Remove any zero-size rectangles from the array */ 14763 while (*_n && ((*_r)->width == 0 || (*_r)->height == 0)) 14764 --*_n, ++*_r; 14765 14766 if (*_n == 0) 14767 return 0; 14768 14769 n = *_n; 14770 r = *_r; 14771 14772 box.x1 = r->x; 14773 box.x2 = box.x1 + r->width; 14774 box.y1 = r->y; 14775 box.y2 = box.y1 + r->height; 14776 r++; 14777 14778 while (--n) { 14779 if (r->width == 0 || r->height == 0) 14780 goto slow; 14781 14782 box32_add_rect(&box, r++); 14783 } 14784 goto done; 14785slow: 14786 { 14787 xRectangle *rr = r; 14788 do { 14789 do { 14790 --*_n, r++; 14791 } while (--n && (r->width == 0 || r->height == 0)); 14792 while (n && r->width && r->height) { 14793 box32_add_rect(&box, r); 14794 *rr++ = *r++; 14795 n--; 14796 } 14797 } while (n); 14798 } 14799done: 14800 14801 clipped = box32_trim_and_translate(&box, drawable, gc); 14802 if (!box32_to_box16(&box, out)) 14803 return 0; 14804 14805 return 1 | clipped << 1; 14806} 14807 14808static void 14809sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect) 14810{ 14811 PixmapPtr pixmap = get_drawable_pixmap(draw); 14812 struct sna *sna = to_sna_from_pixmap(pixmap); 14813 struct sna_pixmap *priv = sna_pixmap(pixmap); 14814 struct sna_damage **damage; 14815 struct kgem_bo *bo; 14816 RegionRec region; 14817 unsigned flags, hint; 14818 uint32_t color; 14819 14820 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 14821 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 14822 (gc->fillStyle == FillSolid || 14823 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 14824 gc->fillStyle, gc->tileIsPixel, 14825 gc->alu)); 14826 14827 flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, ®ion.extents); 14828 if (flags == 0) { 14829 DBG(("%s, nothing to do\n", __FUNCTION__)); 14830 return; 14831 } 14832 14833 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 14834 region.extents.x1, region.extents.y1, 14835 region.extents.x2, region.extents.y2, 14836 flags)); 14837 14838 if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) { 14839 DBG(("%s: fallback forced\n", __FUNCTION__)); 14840 goto fallback; 14841 } 14842 14843 if (priv == NULL) { 14844 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 14845 goto fallback; 14846 } 14847 14848 if (wedged(sna)) { 14849 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14850 goto fallback; 14851 } 14852 14853 if (!PM_IS_SOLID(draw, gc->planemask)) { 14854 DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n", 14855 __FUNCTION__, gc->planemask)); 14856 goto fallback; 14857 } 14858 14859 if (alu_overwrites(gc->alu)) 14860 flags |= OVERWRITES; 14861 14862 /* Clear the cpu damage so that we refresh the GPU status of the 14863 * pixmap upon a redraw after a period of inactivity. 14864 */ 14865 hint = PREFER_GPU; 14866 if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) { 14867 int16_t dx, dy; 14868 14869 region.data = NULL; 14870 14871 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) { 14872 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 14873 RegionTranslate(®ion, dx, dy); 14874 } 14875 14876 if ((flags & IS_CLIPPED) == 0) { 14877 hint |= IGNORE_DAMAGE; 14878 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 14879 discard_cpu_damage(sna, priv); 14880 hint |= REPLACES; 14881 } else { 14882 if (priv->cpu_damage && 14883 region_subsumes_damage(®ion, priv->cpu_damage)) 14884 discard_cpu_damage(sna, priv); 14885 } 14886 } 14887 if (priv->cpu_damage == NULL) { 14888 if (priv->gpu_bo && 14889 (hint & REPLACES || 14890 box_covers_pixmap(pixmap, ®ion.extents) || 14891 box_inplace(pixmap, ®ion.extents))) { 14892 DBG(("%s: promoting to full GPU\n", 14893 __FUNCTION__)); 14894 assert(priv->gpu_bo->proxy == NULL); 14895 sna_damage_all(&priv->gpu_damage, pixmap); 14896 } 14897 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 14898 priv->cpu = false; 14899 } 14900 14901 if (dx | dy) 14902 RegionTranslate(®ion, -dx, -dy); 14903 } 14904 14905 /* If the source is already on the GPU, keep the operation on the GPU */ 14906 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 14907 sna_pixmap_is_gpu(gc->tile.pixmap)) { 14908 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 14909 hint |= FORCE_GPU; 14910 } 14911 14912 bo = sna_drawable_use_bo(draw, hint, ®ion.extents, &damage); 14913 if (bo == NULL) { 14914 DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint)); 14915 goto fallback; 14916 } 14917 if (hint & REPLACES && UNDO) 14918 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 14919 14920 if (gc_is_solid(gc, &color)) { 14921 DBG(("%s: solid fill [%08x], testing for blt\n", 14922 __FUNCTION__, color)); 14923 14924 if (sna_poly_fill_rect_blt(draw, 14925 bo, damage, 14926 gc, color, n, rect, 14927 ®ion.extents, flags)) 14928 return; 14929 } else if (gc->fillStyle == FillTiled) { 14930 DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__)); 14931 14932 if (sna_poly_fill_rect_tiled_blt(draw, bo, damage, 14933 gc, n, rect, 14934 ®ion.extents, flags)) 14935 return; 14936 } else { 14937 DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__)); 14938 14939 if (sna_poly_fill_rect_stippled_blt(draw, bo, damage, 14940 gc, n, rect, 14941 ®ion.extents, flags)) 14942 return; 14943 } 14944 14945fallback: 14946 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 14947 region.extents.x1, region.extents.y1, 14948 region.extents.x2, region.extents.y2)); 14949 region.data = NULL; 14950 if (!region_maybe_clip(®ion, gc->pCompositeClip)) { 14951 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 14952 return; 14953 } 14954 14955 if (!sna_gc_move_to_cpu(gc, draw, ®ion)) 14956 goto out; 14957 if (!sna_drawable_move_region_to_cpu(draw, ®ion, 14958 drawable_gc_flags(draw, gc, n > 1))) 14959 goto out; 14960 14961 if (sigtrap_get() == 0) { 14962 DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__)); 14963 fbPolyFillRect(draw, gc, n, rect); 14964 FALLBACK_FLUSH(draw); 14965 sigtrap_put(); 14966 } 14967out: 14968 sna_gc_move_to_gpu(gc); 14969 RegionUninit(®ion); 14970} 14971 14972static void 14973sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r) 14974{ 14975 struct sna_fill_spans *data = sna_gc(gc)->priv; 14976 uint32_t color; 14977 14978 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 14979 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 14980 (gc->fillStyle == FillSolid || 14981 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 14982 gc->fillStyle, gc->tileIsPixel, 14983 gc->alu)); 14984 14985 assert(PM_IS_SOLID(draw, gc->planemask)); 14986 if (n == 0) 14987 return; 14988 14989 /* The mi routines do not attempt to keep the spans it generates 14990 * within the clip, so we must run them through the clipper. 14991 */ 14992 14993 if (gc_is_solid(gc, &color)) { 14994 (void)sna_poly_fill_rect_blt(draw, 14995 data->bo, NULL, 14996 gc, color, n, r, 14997 &data->region.extents, 14998 IS_CLIPPED); 14999 } else if (gc->fillStyle == FillTiled) { 15000 (void)sna_poly_fill_rect_tiled_blt(draw, 15001 data->bo, NULL, 15002 gc, n, r, 15003 &data->region.extents, 15004 IS_CLIPPED); 15005 } else { 15006 (void)sna_poly_fill_rect_stippled_blt(draw, 15007 data->bo, NULL, 15008 gc, n, r, 15009 &data->region.extents, 15010 IS_CLIPPED); 15011 } 15012} 15013 15014static void 15015sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc) 15016{ 15017 struct sna_fill_spans data; 15018 struct sna_pixmap *priv; 15019 15020 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15021 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15022 (gc->fillStyle == FillSolid || 15023 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15024 gc->fillStyle, gc->tileIsPixel, 15025 gc->alu)); 15026 15027 data.flags = sna_poly_arc_extents(draw, gc, n, arc, 15028 &data.region.extents); 15029 if (data.flags == 0) 15030 return; 15031 15032 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 15033 data.region.extents.x1, data.region.extents.y1, 15034 data.region.extents.x2, data.region.extents.y2, 15035 data.flags)); 15036 15037 data.region.data = NULL; 15038 15039 if (FORCE_FALLBACK) 15040 goto fallback; 15041 15042 if (!ACCEL_POLY_FILL_ARC) 15043 goto fallback; 15044 15045 data.pixmap = get_drawable_pixmap(draw); 15046 data.sna = to_sna_from_pixmap(data.pixmap); 15047 priv = sna_pixmap(data.pixmap); 15048 if (priv == NULL) { 15049 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 15050 goto fallback; 15051 } 15052 15053 if (wedged(data.sna)) { 15054 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15055 goto fallback; 15056 } 15057 15058 if (!PM_IS_SOLID(draw, gc->planemask)) 15059 goto fallback; 15060 15061 if ((data.bo = sna_drawable_use_bo(draw, 15062 use_fill_spans(draw, gc, &data.region.extents, data.flags), 15063 &data.region.extents, 15064 &data.damage))) { 15065 uint32_t color; 15066 15067 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 15068 sna_gc(gc)->priv = &data; 15069 15070 if (gc_is_solid(gc, &color)) { 15071 struct sna_fill_op fill; 15072 15073 if (!sna_fill_init_blt(&fill, 15074 data.sna, data.pixmap, 15075 data.bo, gc->alu, color, 15076 FILL_SPANS)) 15077 goto fallback; 15078 15079 data.op = &fill; 15080 15081 if ((data.flags & IS_CLIPPED) == 0) { 15082 if (data.dx | data.dy) 15083 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 15084 else 15085 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 15086 } else { 15087 if (!region_maybe_clip(&data.region, 15088 gc->pCompositeClip)) 15089 return; 15090 15091 if (region_is_singular(&data.region)) 15092 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 15093 else 15094 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 15095 } 15096 assert(gc->miTranslate); 15097 gc->ops = &sna_gc_ops__tmp; 15098 15099 miPolyFillArc(draw, gc, n, arc); 15100 fill.done(data.sna, &fill); 15101 } else { 15102 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 15103 gc->ops = &sna_gc_ops__tmp; 15104 15105 miPolyFillArc(draw, gc, n, arc); 15106 } 15107 15108 gc->ops = (GCOps *)&sna_gc_ops; 15109 if (data.damage) { 15110 if (data.dx | data.dy) 15111 pixman_region_translate(&data.region, data.dx, data.dy); 15112 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 15113 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 15114 } 15115 assert_pixmap_damage(data.pixmap); 15116 RegionUninit(&data.region); 15117 return; 15118 } 15119 15120fallback: 15121 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 15122 data.region.extents.x1, data.region.extents.y1, 15123 data.region.extents.x2, data.region.extents.y2)); 15124 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 15125 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15126 return; 15127 } 15128 15129 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 15130 goto out; 15131 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 15132 drawable_gc_flags(draw, gc, true))) 15133 goto out; 15134 15135 if (sigtrap_get() == 0) { 15136 DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n", 15137 __FUNCTION__)); 15138 miPolyFillArc(draw, gc, n, arc); 15139 sigtrap_put(); 15140 } 15141out: 15142 sna_gc_move_to_gpu(gc); 15143 RegionUninit(&data.region); 15144} 15145 15146struct sna_font { 15147 CharInfoRec glyphs8[256]; 15148 CharInfoRec *glyphs16[256]; 15149}; 15150#define GLYPH_INVALID (void *)1 15151#define GLYPH_EMPTY (void *)2 15152 15153static Bool 15154sna_realize_font(ScreenPtr screen, FontPtr font) 15155{ 15156 struct sna_font *priv; 15157 15158 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15159 15160 priv = calloc(1, sizeof(struct sna_font)); 15161 if (priv == NULL) 15162 return FALSE; 15163 15164 if (!FontSetPrivate(font, sna_font_key, priv)) { 15165 free(priv); 15166 return FALSE; 15167 } 15168 15169 return TRUE; 15170} 15171 15172static Bool 15173sna_unrealize_font(ScreenPtr screen, FontPtr font) 15174{ 15175 struct sna_font *priv = FontGetPrivate(font, sna_font_key); 15176 int i, j; 15177 15178 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15179 15180 if (priv == NULL) 15181 return TRUE; 15182 15183 for (i = 0; i < 256; i++) { 15184 if ((uintptr_t)priv->glyphs8[i].bits & ~3) 15185 free(priv->glyphs8[i].bits); 15186 } 15187 for (j = 0; j < 256; j++) { 15188 if (priv->glyphs16[j] == NULL) 15189 continue; 15190 15191 for (i = 0; i < 256; i++) { 15192 if ((uintptr_t)priv->glyphs16[j][i].bits & ~3) 15193 free(priv->glyphs16[j][i].bits); 15194 } 15195 free(priv->glyphs16[j]); 15196 } 15197 free(priv); 15198 15199 FontSetPrivate(font, sna_font_key, NULL); 15200 return TRUE; 15201} 15202 15203static bool 15204sna_glyph_blt(DrawablePtr drawable, GCPtr gc, 15205 int _x, int _y, unsigned int _n, 15206 CharInfoPtr *_info, 15207 RegionRec *clip, 15208 uint32_t fg, uint32_t bg, 15209 bool transparent) 15210{ 15211 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15212 struct sna *sna = to_sna_from_pixmap(pixmap); 15213 struct kgem_bo *bo; 15214 struct sna_damage **damage; 15215 const BoxRec *extents, *last_extents; 15216 uint32_t *b; 15217 int16_t dx, dy; 15218 uint32_t br00; 15219 uint16_t unwind_batch, unwind_reloc; 15220 unsigned hint; 15221 15222 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15223 15224 DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n", 15225 __FUNCTION__, _x, _y, _n, fg, bg, rop)); 15226 15227 if (wedged(sna)) { 15228 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15229 return false; 15230 } 15231 15232 if (!transparent && clip->data == NULL) 15233 hint = PREFER_GPU | IGNORE_DAMAGE; 15234 else 15235 hint = PREFER_GPU; 15236 15237 bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage); 15238 if (bo == NULL) 15239 return false; 15240 15241 if (bo->tiling == I915_TILING_Y) { 15242 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15243 assert(bo == __sna_pixmap_get_bo(pixmap)); 15244 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15245 if (bo == NULL) { 15246 DBG(("%s: fallback -- unable to change tiling\n", 15247 __FUNCTION__)); 15248 return false; 15249 } 15250 } 15251 15252 if (!kgem_bo_can_blt(&sna->kgem, bo)) 15253 return false; 15254 15255 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15256 RegionTranslate(clip, dx, dy); 15257 _x += drawable->x + dx; 15258 _y += drawable->y + dy; 15259 15260 extents = region_rects(clip); 15261 last_extents = extents + region_num_rects(clip); 15262 15263 if (!transparent) { /* emulate miImageGlyphBlt */ 15264 if (!sna_blt_fill_boxes(sna, GXcopy, 15265 bo, drawable->bitsPerPixel, 15266 bg, extents, last_extents - extents)) { 15267 RegionTranslate(clip, -dx, -dy); 15268 return false; 15269 } 15270 } 15271 15272 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15273 assert(kgem_bo_can_blt(&sna->kgem, bo)); 15274 if (!kgem_check_batch(&sna->kgem, 20) || 15275 !kgem_check_bo_fenced(&sna->kgem, bo) || 15276 !kgem_check_reloc(&sna->kgem, 1)) { 15277 kgem_submit(&sna->kgem); 15278 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 15279 RegionTranslate(clip, -dx, -dy); 15280 return false; 15281 } 15282 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15283 } 15284 15285 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15286 __FUNCTION__, 15287 extents->x1, extents->y1, 15288 extents->x2, extents->y2)); 15289 15290 unwind_batch = sna->kgem.nbatch; 15291 unwind_reloc = sna->kgem.nreloc; 15292 15293 assert(sna->kgem.mode == KGEM_BLT); 15294 b = sna->kgem.batch + sna->kgem.nbatch; 15295 if (sna->kgem.gen >= 0100) { 15296 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15297 b[1] = bo->pitch; 15298 if (sna->kgem.gen >= 040 && bo->tiling) { 15299 b[0] |= BLT_DST_TILED; 15300 b[1] >>= 2; 15301 } 15302 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15303 b[2] = extents->y1 << 16 | extents->x1; 15304 b[3] = extents->y2 << 16 | extents->x2; 15305 *(uint64_t *)(b+4) = 15306 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15307 I915_GEM_DOMAIN_RENDER << 16 | 15308 I915_GEM_DOMAIN_RENDER | 15309 KGEM_RELOC_FENCED, 15310 0); 15311 b[6] = bg; 15312 b[7] = fg; 15313 b[8] = 0; 15314 b[9] = 0; 15315 sna->kgem.nbatch += 10; 15316 } else { 15317 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15318 b[1] = bo->pitch; 15319 if (sna->kgem.gen >= 040 && bo->tiling) { 15320 b[0] |= BLT_DST_TILED; 15321 b[1] >>= 2; 15322 } 15323 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15324 b[2] = extents->y1 << 16 | extents->x1; 15325 b[3] = extents->y2 << 16 | extents->x2; 15326 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15327 I915_GEM_DOMAIN_RENDER << 16 | 15328 I915_GEM_DOMAIN_RENDER | 15329 KGEM_RELOC_FENCED, 15330 0); 15331 b[5] = bg; 15332 b[6] = fg; 15333 b[7] = 0; 15334 sna->kgem.nbatch += 8; 15335 } 15336 15337 br00 = XY_TEXT_IMMEDIATE_BLT; 15338 if (bo->tiling && sna->kgem.gen >= 040) 15339 br00 |= BLT_DST_TILED; 15340 15341 do { 15342 CharInfoPtr *info = _info; 15343 int x = _x, y = _y, n = _n; 15344 15345 do { 15346 CharInfoPtr c = *info++; 15347 int w = GLYPHWIDTHPIXELS(c); 15348 int h = GLYPHHEIGHTPIXELS(c); 15349 int w8 = (w + 7) >> 3; 15350 int x1, y1, len; 15351 15352 if (c->bits == GLYPH_EMPTY) 15353 goto skip; 15354 15355 len = (w8 * h + 7) >> 3 << 1; 15356 x1 = x + c->metrics.leftSideBearing; 15357 y1 = y - c->metrics.ascent; 15358 15359 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 15360 x,y, x1, y1, w, w8, h, len)); 15361 15362 if (x1 >= extents->x2 || y1 >= extents->y2) 15363 goto skip; 15364 if (x1 + w <= extents->x1 || y1 + h <= extents->y1) 15365 goto skip; 15366 15367 assert(len > 0); 15368 if (!kgem_check_batch(&sna->kgem, 3+len)) { 15369 _kgem_submit(&sna->kgem); 15370 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15371 15372 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 15373 __FUNCTION__, 15374 extents->x1, extents->y1, 15375 extents->x2, extents->y2)); 15376 15377 unwind_batch = sna->kgem.nbatch; 15378 unwind_reloc = sna->kgem.nreloc; 15379 15380 assert(sna->kgem.mode == KGEM_BLT); 15381 b = sna->kgem.batch + sna->kgem.nbatch; 15382 if (sna->kgem.gen >= 0100) { 15383 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15384 b[1] = bo->pitch; 15385 if (bo->tiling) { 15386 b[0] |= BLT_DST_TILED; 15387 b[1] >>= 2; 15388 } 15389 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15390 b[2] = extents->y1 << 16 | extents->x1; 15391 b[3] = extents->y2 << 16 | extents->x2; 15392 *(uint64_t *)(b+4) = 15393 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15394 I915_GEM_DOMAIN_RENDER << 16 | 15395 I915_GEM_DOMAIN_RENDER | 15396 KGEM_RELOC_FENCED, 15397 0); 15398 b[6] = bg; 15399 b[7] = fg; 15400 b[8] = 0; 15401 b[9] = 0; 15402 sna->kgem.nbatch += 10; 15403 } else { 15404 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15405 b[1] = bo->pitch; 15406 if (sna->kgem.gen >= 040 && bo->tiling) { 15407 b[0] |= BLT_DST_TILED; 15408 b[1] >>= 2; 15409 } 15410 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15411 b[2] = extents->y1 << 16 | extents->x1; 15412 b[3] = extents->y2 << 16 | extents->x2; 15413 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15414 I915_GEM_DOMAIN_RENDER << 16 | 15415 I915_GEM_DOMAIN_RENDER | 15416 KGEM_RELOC_FENCED, 15417 0); 15418 b[5] = bg; 15419 b[6] = fg; 15420 b[7] = 0; 15421 sna->kgem.nbatch += 8; 15422 } 15423 } 15424 15425 assert(sna->kgem.mode == KGEM_BLT); 15426 b = sna->kgem.batch + sna->kgem.nbatch; 15427 sna->kgem.nbatch += 3 + len; 15428 15429 b[0] = br00 | (1 + len); 15430 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 15431 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 15432 { 15433 uint64_t *src = (uint64_t *)c->bits; 15434 uint64_t *dst = (uint64_t *)(b + 3); 15435 do { 15436 *dst++ = *src++; 15437 len -= 2; 15438 } while (len); 15439 } 15440 15441 if (damage) { 15442 BoxRec r; 15443 15444 r.x1 = x1; 15445 r.y1 = y1; 15446 r.x2 = x1 + w; 15447 r.y2 = y1 + h; 15448 if (box_intersect(&r, extents)) 15449 sna_damage_add_box(damage, &r); 15450 } 15451skip: 15452 x += c->metrics.characterWidth; 15453 } while (--n); 15454 15455 if (++extents == last_extents) 15456 break; 15457 15458 if (kgem_check_batch(&sna->kgem, 3)) { 15459 assert(sna->kgem.mode == KGEM_BLT); 15460 b = sna->kgem.batch + sna->kgem.nbatch; 15461 sna->kgem.nbatch += 3; 15462 15463 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15464 __FUNCTION__, 15465 extents->x1, extents->y1, 15466 extents->x2, extents->y2)); 15467 15468 b[0] = XY_SETUP_CLIP; 15469 b[1] = extents->y1 << 16 | extents->x1; 15470 b[2] = extents->y2 << 16 | extents->x2; 15471 } 15472 } while (1); 15473 15474 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 15475 sna->kgem.nbatch = unwind_batch; 15476 sna->kgem.nreloc = unwind_reloc; 15477 if (sna->kgem.nbatch == 0) 15478 kgem_bo_undo(&sna->kgem, bo); 15479 } 15480 15481 assert_pixmap_damage(pixmap); 15482 sna->blt_state.fill_bo = 0; 15483 return true; 15484} 15485 15486static void 15487sna_glyph_extents(FontPtr font, 15488 CharInfoPtr *info, 15489 unsigned long count, 15490 ExtentInfoRec *extents) 15491{ 15492 extents->drawDirection = font->info.drawDirection; 15493 extents->fontAscent = font->info.fontAscent; 15494 extents->fontDescent = font->info.fontDescent; 15495 15496 extents->overallAscent = info[0]->metrics.ascent; 15497 extents->overallDescent = info[0]->metrics.descent; 15498 extents->overallLeft = info[0]->metrics.leftSideBearing; 15499 extents->overallRight = info[0]->metrics.rightSideBearing; 15500 extents->overallWidth = info[0]->metrics.characterWidth; 15501 15502 while (--count) { 15503 CharInfoPtr p =*++info; 15504 int v; 15505 15506 if (p->metrics.ascent > extents->overallAscent) 15507 extents->overallAscent = p->metrics.ascent; 15508 if (p->metrics.descent > extents->overallDescent) 15509 extents->overallDescent = p->metrics.descent; 15510 15511 v = extents->overallWidth + p->metrics.leftSideBearing; 15512 if (v < extents->overallLeft) 15513 extents->overallLeft = v; 15514 15515 v = extents->overallWidth + p->metrics.rightSideBearing; 15516 if (v > extents->overallRight) 15517 extents->overallRight = v; 15518 15519 extents->overallWidth += p->metrics.characterWidth; 15520 } 15521} 15522 15523static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out) 15524{ 15525 int w = GLYPHWIDTHPIXELS(in); 15526 int h = GLYPHHEIGHTPIXELS(in); 15527 int stride = GLYPHWIDTHBYTESPADDED(in); 15528 uint8_t *dst, *src; 15529 int clear = 1; 15530 15531 out->metrics = in->metrics; 15532 15533 /* Skip empty glyphs */ 15534 if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) { 15535 out->bits = GLYPH_EMPTY; 15536 return true; 15537 } 15538 15539 w = (w + 7) >> 3; 15540 15541 out->bits = malloc((w*h + 7) & ~7); 15542 if (out->bits == NULL) 15543 return false; 15544 15545 VG(memset(out->bits, 0, (w*h + 7) & ~7)); 15546 src = (uint8_t *)in->bits; 15547 dst = (uint8_t *)out->bits; 15548 stride -= w; 15549 do { 15550 int i = w; 15551 do { 15552 clear &= *src == 0; 15553 *dst++ = byte_reverse(*src++); 15554 } while (--i); 15555 src += stride; 15556 } while (--h); 15557 15558 if (clear) { 15559 free(out->bits); 15560 out->bits = GLYPH_EMPTY; 15561 } 15562 15563 return true; 15564} 15565 15566inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv, 15567 uint8_t g, CharInfoPtr *out) 15568{ 15569 unsigned long n; 15570 CharInfoPtr p, ret; 15571 15572 p = &priv->glyphs8[g]; 15573 if (p->bits) { 15574 *out = p; 15575 return p->bits != GLYPH_INVALID; 15576 } 15577 15578 font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret); 15579 if (n == 0) { 15580 p->bits = GLYPH_INVALID; 15581 return false; 15582 } 15583 15584 return sna_set_glyph(ret, *out = p); 15585} 15586 15587inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv, 15588 uint16_t g, CharInfoPtr *out) 15589{ 15590 unsigned long n; 15591 CharInfoPtr page, p, ret; 15592 15593 page = priv->glyphs16[g>>8]; 15594 if (page == NULL) 15595 page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec)); 15596 15597 p = &page[g&0xff]; 15598 if (p->bits) { 15599 *out = p; 15600 return p->bits != GLYPH_INVALID; 15601 } 15602 15603 font->get_glyphs(font, 1, (unsigned char *)&g, 15604 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit, 15605 &n, &ret); 15606 if (n == 0) { 15607 p->bits = GLYPH_INVALID; 15608 return false; 15609 } 15610 15611 return sna_set_glyph(ret, *out = p); 15612} 15613 15614static inline bool sna_font_too_large(FontPtr font) 15615{ 15616 int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font)); 15617 int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font)); 15618 int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth)); 15619 DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__, 15620 top, bot, width, (top + bot) * (width + 7)/8)); 15621 return (top + bot) * (width + 7)/8 > 124; 15622} 15623 15624static int 15625sna_poly_text8(DrawablePtr drawable, GCPtr gc, 15626 int x, int y, 15627 int count, char *chars) 15628{ 15629 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15630 CharInfoPtr info[255]; 15631 ExtentInfoRec extents; 15632 RegionRec region; 15633 long unsigned i, n; 15634 uint32_t fg; 15635 15636 for (i = n = 0; i < count; i++) { 15637 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15638 n++; 15639 } 15640 if (n == 0) 15641 return x; 15642 15643 sna_glyph_extents(gc->font, info, n, &extents); 15644 region.extents.x1 = x + extents.overallLeft; 15645 region.extents.y1 = y - extents.overallAscent; 15646 region.extents.x2 = x + extents.overallRight; 15647 region.extents.y2 = y + extents.overallDescent; 15648 15649 translate_box(®ion.extents, drawable); 15650 clip_box(®ion.extents, gc); 15651 if (box_empty(®ion.extents)) 15652 return x + extents.overallRight; 15653 15654 region.data = NULL; 15655 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15656 return x + extents.overallRight; 15657 15658 if (FORCE_FALLBACK) 15659 goto fallback; 15660 15661 if (!ACCEL_POLY_TEXT8) 15662 goto fallback; 15663 15664 if (sna_font_too_large(gc->font)) 15665 goto fallback; 15666 15667 if (!PM_IS_SOLID(drawable, gc->planemask)) 15668 goto fallback; 15669 15670 if (!gc_is_solid(gc, &fg)) 15671 goto fallback; 15672 15673 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15674fallback: 15675 DBG(("%s: fallback\n", __FUNCTION__)); 15676 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15677 Linear8Bit, &n, info); 15678 15679 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15680 goto out; 15681 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15682 MOVE_READ | MOVE_WRITE)) 15683 goto out; 15684 15685 if (sigtrap_get() == 0) { 15686 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15687 fbPolyGlyphBlt(drawable, gc, x, y, n, 15688 info, FONTGLYPHS(gc->font)); 15689 FALLBACK_FLUSH(drawable); 15690 sigtrap_put(); 15691 } 15692out: 15693 sna_gc_move_to_gpu(gc); 15694 } 15695 RegionUninit(®ion); 15696 return x + extents.overallRight; 15697} 15698 15699static int 15700sna_poly_text16(DrawablePtr drawable, GCPtr gc, 15701 int x, int y, 15702 int count, unsigned short *chars) 15703{ 15704 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15705 CharInfoPtr info[255]; 15706 ExtentInfoRec extents; 15707 RegionRec region; 15708 long unsigned i, n; 15709 uint32_t fg; 15710 15711 for (i = n = 0; i < count; i++) { 15712 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15713 n++; 15714 } 15715 if (n == 0) 15716 return x; 15717 15718 sna_glyph_extents(gc->font, info, n, &extents); 15719 region.extents.x1 = x + extents.overallLeft; 15720 region.extents.y1 = y - extents.overallAscent; 15721 region.extents.x2 = x + extents.overallRight; 15722 region.extents.y2 = y + extents.overallDescent; 15723 15724 translate_box(®ion.extents, drawable); 15725 clip_box(®ion.extents, gc); 15726 if (box_empty(®ion.extents)) 15727 return x + extents.overallRight; 15728 15729 region.data = NULL; 15730 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15731 return x + extents.overallRight; 15732 15733 if (FORCE_FALLBACK) 15734 goto fallback; 15735 15736 if (!ACCEL_POLY_TEXT16) 15737 goto fallback; 15738 15739 if (sna_font_too_large(gc->font)) 15740 goto fallback; 15741 15742 if (!PM_IS_SOLID(drawable, gc->planemask)) 15743 goto fallback; 15744 15745 if (!gc_is_solid(gc, &fg)) 15746 goto fallback; 15747 15748 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15749fallback: 15750 DBG(("%s: fallback\n", __FUNCTION__)); 15751 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15752 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15753 &n, info); 15754 15755 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15756 goto out; 15757 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15758 MOVE_READ | MOVE_WRITE)) 15759 goto out; 15760 15761 if (sigtrap_get() == 0) { 15762 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15763 fbPolyGlyphBlt(drawable, gc, x, y, n, 15764 info, FONTGLYPHS(gc->font)); 15765 FALLBACK_FLUSH(drawable); 15766 sigtrap_put(); 15767 } 15768out: 15769 sna_gc_move_to_gpu(gc); 15770 } 15771 RegionUninit(®ion); 15772 return x + extents.overallRight; 15773} 15774 15775static void 15776sna_image_text8(DrawablePtr drawable, GCPtr gc, 15777 int x, int y, 15778 int count, char *chars) 15779{ 15780 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15781 CharInfoPtr info[255]; 15782 ExtentInfoRec extents; 15783 RegionRec region; 15784 long unsigned i, n; 15785 15786 for (i = n = 0; i < count; i++) { 15787 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15788 n++; 15789 } 15790 if (n == 0) 15791 return; 15792 15793 sna_glyph_extents(gc->font, info, n, &extents); 15794 region.extents.x1 = x + MIN(0, extents.overallLeft); 15795 region.extents.y1 = y - extents.fontAscent; 15796 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 15797 region.extents.y2 = y + extents.fontDescent; 15798 15799 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 15800 __FUNCTION__, n, count, 15801 extents.overallLeft, extents.overallRight, extents.overallWidth, 15802 extents.fontAscent, extents.fontDescent, 15803 region.extents.x1, region.extents.y1, 15804 region.extents.x2, region.extents.y2)); 15805 15806 translate_box(®ion.extents, drawable); 15807 clip_box(®ion.extents, gc); 15808 if (box_empty(®ion.extents)) 15809 return; 15810 15811 region.data = NULL; 15812 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15813 return; 15814 15815 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 15816 __FUNCTION__, 15817 region.extents.x1, region.extents.y1, 15818 region.extents.x2, region.extents.y2)); 15819 15820 if (FORCE_FALLBACK) 15821 goto fallback; 15822 15823 if (!ACCEL_IMAGE_TEXT8) 15824 goto fallback; 15825 15826 if (sna_font_too_large(gc->font)) 15827 goto fallback; 15828 15829 if (!PM_IS_SOLID(drawable, gc->planemask)) 15830 goto fallback; 15831 15832 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 15833 gc->fgPixel, gc->bgPixel, false)) { 15834fallback: 15835 DBG(("%s: fallback\n", __FUNCTION__)); 15836 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15837 Linear8Bit, &n, info); 15838 15839 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15840 goto out; 15841 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 15842 goto out; 15843 15844 if (sigtrap_get() == 0) { 15845 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 15846 fbImageGlyphBlt(drawable, gc, x, y, n, 15847 info, FONTGLYPHS(gc->font)); 15848 FALLBACK_FLUSH(drawable); 15849 sigtrap_put(); 15850 } 15851out: 15852 sna_gc_move_to_gpu(gc); 15853 } 15854 RegionUninit(®ion); 15855} 15856 15857static void 15858sna_image_text16(DrawablePtr drawable, GCPtr gc, 15859 int x, int y, 15860 int count, unsigned short *chars) 15861{ 15862 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15863 CharInfoPtr info[255]; 15864 ExtentInfoRec extents; 15865 RegionRec region; 15866 long unsigned i, n; 15867 15868 for (i = n = 0; i < count; i++) { 15869 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15870 n++; 15871 } 15872 if (n == 0) 15873 return; 15874 15875 sna_glyph_extents(gc->font, info, n, &extents); 15876 region.extents.x1 = x + MIN(0, extents.overallLeft); 15877 region.extents.y1 = y - extents.fontAscent; 15878 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 15879 region.extents.y2 = y + extents.fontDescent; 15880 15881 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 15882 __FUNCTION__, n, count, 15883 extents.overallLeft, extents.overallRight, extents.overallWidth, 15884 extents.fontAscent, extents.fontDescent, 15885 region.extents.x1, region.extents.y1, 15886 region.extents.x2, region.extents.y2)); 15887 15888 translate_box(®ion.extents, drawable); 15889 clip_box(®ion.extents, gc); 15890 if (box_empty(®ion.extents)) 15891 return; 15892 15893 region.data = NULL; 15894 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15895 return; 15896 15897 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 15898 __FUNCTION__, 15899 region.extents.x1, region.extents.y1, 15900 region.extents.x2, region.extents.y2)); 15901 15902 if (FORCE_FALLBACK) 15903 goto fallback; 15904 15905 if (!ACCEL_IMAGE_TEXT16) 15906 goto fallback; 15907 15908 if (sna_font_too_large(gc->font)) 15909 goto fallback; 15910 15911 if (!PM_IS_SOLID(drawable, gc->planemask)) 15912 goto fallback; 15913 15914 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 15915 gc->fgPixel, gc->bgPixel, false)) { 15916fallback: 15917 DBG(("%s: fallback\n", __FUNCTION__)); 15918 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15919 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15920 &n, info); 15921 15922 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15923 goto out; 15924 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 15925 goto out; 15926 15927 if (sigtrap_get() == 0) { 15928 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 15929 fbImageGlyphBlt(drawable, gc, x, y, n, 15930 info, FONTGLYPHS(gc->font)); 15931 FALLBACK_FLUSH(drawable); 15932 sigtrap_put(); 15933 } 15934out: 15935 sna_gc_move_to_gpu(gc); 15936 } 15937 RegionUninit(®ion); 15938} 15939 15940/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ 15941static bool 15942sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, 15943 int _x, int _y, unsigned int _n, 15944 CharInfoPtr *_info, pointer _base, 15945 struct kgem_bo *bo, 15946 struct sna_damage **damage, 15947 RegionPtr clip, 15948 uint32_t fg, uint32_t bg, 15949 bool transparent) 15950{ 15951 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15952 struct sna *sna = to_sna_from_pixmap(pixmap); 15953 const BoxRec *extents, *last_extents; 15954 uint32_t *b; 15955 int16_t dx, dy; 15956 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15957 uint16_t unwind_batch, unwind_reloc; 15958 15959 DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n", 15960 __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg)); 15961 15962 if (bo->tiling == I915_TILING_Y) { 15963 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15964 assert(bo == __sna_pixmap_get_bo(pixmap)); 15965 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15966 if (bo == NULL) { 15967 DBG(("%s: fallback -- unable to change tiling\n", 15968 __FUNCTION__)); 15969 return false; 15970 } 15971 } 15972 15973 if (!kgem_bo_can_blt(&sna->kgem, bo)) 15974 return false; 15975 15976 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15977 RegionTranslate(clip, dx, dy); 15978 _x += drawable->x + dx; 15979 _y += drawable->y + dy; 15980 15981 extents = region_rects(clip); 15982 last_extents = extents + region_num_rects(clip); 15983 15984 if (!transparent) { /* emulate miImageGlyphBlt */ 15985 if (!sna_blt_fill_boxes(sna, GXcopy, 15986 bo, drawable->bitsPerPixel, 15987 bg, extents, last_extents - extents)) { 15988 RegionTranslate(clip, -dx, -dy); 15989 return false; 15990 } 15991 } 15992 15993 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15994 assert(kgem_bo_can_blt(&sna->kgem, bo)); 15995 if (!kgem_check_batch(&sna->kgem, 20) || 15996 !kgem_check_bo_fenced(&sna->kgem, bo) || 15997 !kgem_check_reloc(&sna->kgem, 1)) { 15998 kgem_submit(&sna->kgem); 15999 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 16000 RegionTranslate(clip, -dx, -dy); 16001 return false; 16002 } 16003 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16004 } 16005 16006 unwind_batch = sna->kgem.nbatch; 16007 unwind_reloc = sna->kgem.nreloc; 16008 16009 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16010 __FUNCTION__, 16011 extents->x1, extents->y1, 16012 extents->x2, extents->y2)); 16013 16014 assert(sna->kgem.mode == KGEM_BLT); 16015 b = sna->kgem.batch + sna->kgem.nbatch; 16016 if (sna->kgem.gen >= 0100) { 16017 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16018 b[1] = bo->pitch; 16019 if (sna->kgem.gen >= 040 && bo->tiling) { 16020 b[0] |= BLT_DST_TILED; 16021 b[1] >>= 2; 16022 } 16023 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16024 b[2] = extents->y1 << 16 | extents->x1; 16025 b[3] = extents->y2 << 16 | extents->x2; 16026 *(uint64_t *)(b+4) = 16027 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16028 I915_GEM_DOMAIN_RENDER << 16 | 16029 I915_GEM_DOMAIN_RENDER | 16030 KGEM_RELOC_FENCED, 16031 0); 16032 b[6] = bg; 16033 b[7] = fg; 16034 b[8] = 0; 16035 b[9] = 0; 16036 sna->kgem.nbatch += 10; 16037 } else { 16038 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16039 b[1] = bo->pitch; 16040 if (sna->kgem.gen >= 040 && bo->tiling) { 16041 b[0] |= BLT_DST_TILED; 16042 b[1] >>= 2; 16043 } 16044 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16045 b[2] = extents->y1 << 16 | extents->x1; 16046 b[3] = extents->y2 << 16 | extents->x2; 16047 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16048 I915_GEM_DOMAIN_RENDER << 16 | 16049 I915_GEM_DOMAIN_RENDER | 16050 KGEM_RELOC_FENCED, 16051 0); 16052 b[5] = bg; 16053 b[6] = fg; 16054 b[7] = 0; 16055 sna->kgem.nbatch += 8; 16056 } 16057 16058 do { 16059 CharInfoPtr *info = _info; 16060 int x = _x, y = _y, n = _n; 16061 16062 do { 16063 CharInfoPtr c = *info++; 16064 uint8_t *glyph = FONTGLYPHBITS(base, c); 16065 int w = GLYPHWIDTHPIXELS(c); 16066 int h = GLYPHHEIGHTPIXELS(c); 16067 int stride = GLYPHWIDTHBYTESPADDED(c); 16068 int w8 = (w + 7) >> 3; 16069 int x1, y1, len, i; 16070 uint8_t *byte; 16071 16072 if (w == 0 || h == 0) 16073 goto skip; 16074 16075 len = (w8 * h + 7) >> 3 << 1; 16076 x1 = x + c->metrics.leftSideBearing; 16077 y1 = y - c->metrics.ascent; 16078 16079 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 16080 x,y, x1, y1, w, w8, h, len)); 16081 16082 if (x1 >= extents->x2 || y1 >= extents->y2 || 16083 x1 + w <= extents->x1 || y1 + h <= extents->y1) { 16084 DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n", 16085 __FUNCTION__, 16086 x1, y1, w, h, 16087 extents->x1, extents->y1, 16088 extents->x2, extents->y2)); 16089 goto skip; 16090 } 16091 16092 { 16093 int clear = 1, j = h; 16094 uint8_t *g = glyph; 16095 16096 do { 16097 i = w8; 16098 do { 16099 clear = *g++ == 0; 16100 } while (clear && --i); 16101 g += stride - w8; 16102 } while (clear && --j); 16103 if (clear) { 16104 DBG(("%s: skipping clear glyph for ImageGlyph\n", 16105 __FUNCTION__)); 16106 goto skip; 16107 } 16108 } 16109 16110 assert(len > 0); 16111 if (!kgem_check_batch(&sna->kgem, 3+len)) { 16112 _kgem_submit(&sna->kgem); 16113 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16114 16115 unwind_batch = sna->kgem.nbatch; 16116 unwind_reloc = sna->kgem.nreloc; 16117 16118 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 16119 __FUNCTION__, 16120 extents->x1, extents->y1, 16121 extents->x2, extents->y2)); 16122 16123 assert(sna->kgem.mode == KGEM_BLT); 16124 b = sna->kgem.batch + sna->kgem.nbatch; 16125 if (sna->kgem.gen >= 0100) { 16126 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16127 b[1] = bo->pitch; 16128 if (bo->tiling) { 16129 b[0] |= BLT_DST_TILED; 16130 b[1] >>= 2; 16131 } 16132 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16133 b[2] = extents->y1 << 16 | extents->x1; 16134 b[3] = extents->y2 << 16 | extents->x2; 16135 *(uint64_t *)(b+4) = 16136 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16137 I915_GEM_DOMAIN_RENDER << 16 | 16138 I915_GEM_DOMAIN_RENDER | 16139 KGEM_RELOC_FENCED, 16140 0); 16141 b[6] = bg; 16142 b[7] = fg; 16143 b[8] = 0; 16144 b[9] = 0; 16145 sna->kgem.nbatch += 10; 16146 } else { 16147 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16148 b[1] = bo->pitch; 16149 if (sna->kgem.gen >= 040 && bo->tiling) { 16150 b[0] |= BLT_DST_TILED; 16151 b[1] >>= 2; 16152 } 16153 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16154 b[2] = extents->y1 << 16 | extents->x1; 16155 b[3] = extents->y2 << 16 | extents->x2; 16156 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16157 I915_GEM_DOMAIN_RENDER << 16 | 16158 I915_GEM_DOMAIN_RENDER | 16159 KGEM_RELOC_FENCED, 16160 0); 16161 b[5] = bg; 16162 b[6] = fg; 16163 b[7] = 0; 16164 sna->kgem.nbatch += 8; 16165 } 16166 } 16167 16168 assert(sna->kgem.mode == KGEM_BLT); 16169 b = sna->kgem.batch + sna->kgem.nbatch; 16170 sna->kgem.nbatch += 3 + len; 16171 16172 b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); 16173 if (bo->tiling && sna->kgem.gen >= 040) 16174 b[0] |= BLT_DST_TILED; 16175 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 16176 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 16177 16178 byte = (uint8_t *)&b[3]; 16179 stride -= w8; 16180 do { 16181 i = w8; 16182 do { 16183 *byte++ = byte_reverse(*glyph++); 16184 } while (--i); 16185 glyph += stride; 16186 } while (--h); 16187 while ((byte - (uint8_t *)&b[3]) & 7) 16188 *byte++ = 0; 16189 assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); 16190 16191 if (damage) { 16192 BoxRec r; 16193 16194 r.x1 = x1; 16195 r.y1 = y1; 16196 r.x2 = x1 + w; 16197 r.y2 = y1 + h; 16198 if (box_intersect(&r, extents)) 16199 sna_damage_add_box(damage, &r); 16200 } 16201skip: 16202 x += c->metrics.characterWidth; 16203 } while (--n); 16204 16205 if (++extents == last_extents) 16206 break; 16207 16208 if (kgem_check_batch(&sna->kgem, 3 + 5)) { 16209 assert(sna->kgem.mode == KGEM_BLT); 16210 b = sna->kgem.batch + sna->kgem.nbatch; 16211 sna->kgem.nbatch += 3; 16212 16213 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16214 __FUNCTION__, 16215 extents->x1, extents->y1, 16216 extents->x2, extents->y2)); 16217 16218 b[0] = XY_SETUP_CLIP; 16219 b[1] = extents->y1 << 16 | extents->x1; 16220 b[2] = extents->y2 << 16 | extents->x2; 16221 } 16222 } while (1); 16223 16224 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 16225 sna->kgem.nbatch = unwind_batch; 16226 sna->kgem.nreloc = unwind_reloc; 16227 if (sna->kgem.nbatch == 0) 16228 kgem_bo_undo(&sna->kgem, bo); 16229 } 16230 16231 assert_pixmap_damage(pixmap); 16232 sna->blt_state.fill_bo = 0; 16233 return true; 16234} 16235 16236static void 16237sna_image_glyph(DrawablePtr drawable, GCPtr gc, 16238 int x, int y, unsigned int n, 16239 CharInfoPtr *info, pointer base) 16240{ 16241 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16242 struct sna *sna = to_sna_from_pixmap(pixmap); 16243 ExtentInfoRec extents; 16244 RegionRec region; 16245 struct sna_damage **damage; 16246 struct kgem_bo *bo; 16247 unsigned hint; 16248 16249 if (n == 0) 16250 return; 16251 16252 sna_glyph_extents(gc->font, info, n, &extents); 16253 region.extents.x1 = x + MIN(0, extents.overallLeft); 16254 region.extents.y1 = y - extents.fontAscent; 16255 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16256 region.extents.y2 = y + extents.fontDescent; 16257 16258 DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16259 __FUNCTION__, n, 16260 extents.overallLeft, extents.overallRight, extents.overallWidth, 16261 extents.fontAscent, extents.fontDescent, 16262 region.extents.x1, region.extents.y1, 16263 region.extents.x2, region.extents.y2)); 16264 16265 translate_box(®ion.extents, drawable); 16266 clip_box(®ion.extents, gc); 16267 if (box_empty(®ion.extents)) 16268 return; 16269 16270 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16271 region.extents.x1, region.extents.y1, 16272 region.extents.x2, region.extents.y2)); 16273 16274 region.data = NULL; 16275 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16276 return; 16277 16278 if (FORCE_FALLBACK) 16279 goto fallback; 16280 16281 if (!ACCEL_IMAGE_GLYPH) 16282 goto fallback; 16283 16284 if (wedged(sna)) { 16285 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16286 goto fallback; 16287 } 16288 16289 if (!PM_IS_SOLID(drawable, gc->planemask)) 16290 goto fallback; 16291 16292 if (sna_font_too_large(gc->font)) 16293 goto fallback; 16294 16295 if (region.data == NULL) 16296 hint = IGNORE_DAMAGE | PREFER_GPU; 16297 else 16298 hint = PREFER_GPU; 16299 if ((bo = sna_drawable_use_bo(drawable, hint, 16300 ®ion.extents, &damage)) && 16301 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16302 bo, damage, ®ion, 16303 gc->fgPixel, gc->bgPixel, false)) 16304 goto out; 16305 16306fallback: 16307 DBG(("%s: fallback\n", __FUNCTION__)); 16308 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16309 goto out_gc; 16310 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16311 goto out_gc; 16312 16313 if (sigtrap_get() == 0) { 16314 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16315 fbImageGlyphBlt(drawable, gc, x, y, n, info, base); 16316 FALLBACK_FLUSH(drawable); 16317 sigtrap_put(); 16318 } 16319out_gc: 16320 sna_gc_move_to_gpu(gc); 16321out: 16322 RegionUninit(®ion); 16323} 16324 16325static void 16326sna_poly_glyph(DrawablePtr drawable, GCPtr gc, 16327 int x, int y, unsigned int n, 16328 CharInfoPtr *info, pointer base) 16329{ 16330 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16331 struct sna *sna = to_sna_from_pixmap(pixmap); 16332 ExtentInfoRec extents; 16333 RegionRec region; 16334 struct sna_damage **damage; 16335 struct kgem_bo *bo; 16336 uint32_t fg; 16337 16338 if (n == 0) 16339 return; 16340 16341 sna_glyph_extents(gc->font, info, n, &extents); 16342 region.extents.x1 = x + extents.overallLeft; 16343 region.extents.y1 = y - extents.overallAscent; 16344 region.extents.x2 = x + extents.overallRight; 16345 region.extents.y2 = y + extents.overallDescent; 16346 16347 translate_box(®ion.extents, drawable); 16348 clip_box(®ion.extents, gc); 16349 if (box_empty(®ion.extents)) 16350 return; 16351 16352 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16353 region.extents.x1, region.extents.y1, 16354 region.extents.x2, region.extents.y2)); 16355 16356 region.data = NULL; 16357 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16358 return; 16359 16360 if (FORCE_FALLBACK) 16361 goto fallback; 16362 16363 if (!ACCEL_POLY_GLYPH) 16364 goto fallback; 16365 16366 if (wedged(sna)) { 16367 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16368 goto fallback; 16369 } 16370 16371 if (!PM_IS_SOLID(drawable, gc->planemask)) 16372 goto fallback; 16373 16374 if (!gc_is_solid(gc, &fg)) 16375 goto fallback; 16376 16377 if (sna_font_too_large(gc->font)) 16378 goto fallback; 16379 16380 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 16381 ®ion.extents, &damage)) && 16382 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16383 bo, damage, ®ion, fg, -1, true)) 16384 goto out; 16385 16386fallback: 16387 DBG(("%s: fallback\n", __FUNCTION__)); 16388 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16389 goto out_gc; 16390 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16391 MOVE_READ | MOVE_WRITE)) 16392 goto out_gc; 16393 16394 if (sigtrap_get() == 0) { 16395 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 16396 fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); 16397 FALLBACK_FLUSH(drawable); 16398 sigtrap_put(); 16399 } 16400out_gc: 16401 sna_gc_move_to_gpu(gc); 16402out: 16403 RegionUninit(®ion); 16404} 16405 16406static bool 16407sna_push_pixels_solid_blt(GCPtr gc, 16408 PixmapPtr bitmap, 16409 DrawablePtr drawable, 16410 RegionPtr region) 16411{ 16412 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16413 struct sna *sna = to_sna_from_pixmap(pixmap); 16414 struct sna_damage **damage; 16415 struct kgem_bo *bo; 16416 const BoxRec *box; 16417 int16_t dx, dy; 16418 int n; 16419 uint8_t rop = copy_ROP[gc->alu]; 16420 16421 bo = sna_drawable_use_bo(drawable, PREFER_GPU, ®ion->extents, &damage); 16422 if (bo == NULL) 16423 return false; 16424 16425 if (bo->tiling == I915_TILING_Y) { 16426 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16427 assert(bo == __sna_pixmap_get_bo(pixmap)); 16428 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16429 if (bo == NULL) { 16430 DBG(("%s: fallback -- unable to change tiling\n", 16431 __FUNCTION__)); 16432 return false; 16433 } 16434 } 16435 16436 if (!kgem_bo_can_blt(&sna->kgem, bo)) 16437 return false; 16438 16439 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16440 RegionTranslate(region, dx, dy); 16441 16442 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 16443 if (damage) 16444 sna_damage_add_to_pixmap(damage, region, pixmap); 16445 assert_pixmap_damage(pixmap); 16446 16447 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, 16448 region->extents.x1, region->extents.y1, 16449 region->extents.x2, region->extents.y2)); 16450 16451 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16452 assert(kgem_bo_can_blt(&sna->kgem, bo)); 16453 16454 /* Region is pre-clipped and translated into pixmap space */ 16455 box = region_rects(region); 16456 n = region_num_rects(region); 16457 do { 16458 int bx1 = (box->x1 - region->extents.x1) & ~7; 16459 int bx2 = (box->x2 - region->extents.x1 + 7) & ~7; 16460 int bw = (bx2 - bx1)/8; 16461 int bh = box->y2 - box->y1; 16462 int bstride = ALIGN(bw, 2); 16463 struct kgem_bo *upload; 16464 void *ptr; 16465 16466 if (!kgem_check_batch(&sna->kgem, 10) || 16467 !kgem_check_bo_fenced(&sna->kgem, bo) || 16468 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 16469 kgem_submit(&sna->kgem); 16470 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 16471 return false; 16472 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16473 } 16474 16475 upload = kgem_create_buffer(&sna->kgem, 16476 bstride*bh, 16477 KGEM_BUFFER_WRITE_INPLACE, 16478 &ptr); 16479 if (!upload) 16480 break; 16481 16482 if (sigtrap_get() == 0) { 16483 uint8_t *dst = ptr; 16484 16485 int src_stride = bitmap->devKind; 16486 uint8_t *src; 16487 uint32_t *b; 16488 16489 assert(src_stride); 16490 src = (uint8_t*)bitmap->devPrivate.ptr; 16491 src += (box->y1 - region->extents.y1) * src_stride + bx1/8; 16492 src_stride -= bstride; 16493 do { 16494 int i = bstride; 16495 do { 16496 *dst++ = byte_reverse(*src++); 16497 *dst++ = byte_reverse(*src++); 16498 i -= 2; 16499 } while (i); 16500 src += src_stride; 16501 } while (--bh); 16502 16503 assert(sna->kgem.mode == KGEM_BLT); 16504 b = sna->kgem.batch + sna->kgem.nbatch; 16505 if (sna->kgem.gen >= 0100) { 16506 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 16507 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16508 b[1] = bo->pitch; 16509 if (sna->kgem.gen >= 040 && bo->tiling) { 16510 b[0] |= BLT_DST_TILED; 16511 b[1] >>= 2; 16512 } 16513 b[1] |= 1 << 29; 16514 b[1] |= blt_depth(drawable->depth) << 24; 16515 b[1] |= rop << 16; 16516 b[2] = box->y1 << 16 | box->x1; 16517 b[3] = box->y2 << 16 | box->x2; 16518 *(uint64_t *)(b+4) = 16519 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16520 I915_GEM_DOMAIN_RENDER << 16 | 16521 I915_GEM_DOMAIN_RENDER | 16522 KGEM_RELOC_FENCED, 16523 0); 16524 *(uint64_t *)(b+6) = 16525 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 16526 I915_GEM_DOMAIN_RENDER << 16 | 16527 KGEM_RELOC_FENCED, 16528 0); 16529 b[8] = gc->bgPixel; 16530 b[9] = gc->fgPixel; 16531 sna->kgem.nbatch += 10; 16532 } else { 16533 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 16534 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16535 b[1] = bo->pitch; 16536 if (sna->kgem.gen >= 040 && bo->tiling) { 16537 b[0] |= BLT_DST_TILED; 16538 b[1] >>= 2; 16539 } 16540 b[1] |= 1 << 29; 16541 b[1] |= blt_depth(drawable->depth) << 24; 16542 b[1] |= rop << 16; 16543 b[2] = box->y1 << 16 | box->x1; 16544 b[3] = box->y2 << 16 | box->x2; 16545 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16546 I915_GEM_DOMAIN_RENDER << 16 | 16547 I915_GEM_DOMAIN_RENDER | 16548 KGEM_RELOC_FENCED, 16549 0); 16550 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 16551 I915_GEM_DOMAIN_RENDER << 16 | 16552 KGEM_RELOC_FENCED, 16553 0); 16554 b[6] = gc->bgPixel; 16555 b[7] = gc->fgPixel; 16556 16557 sna->kgem.nbatch += 8; 16558 } 16559 sigtrap_put(); 16560 } 16561 16562 kgem_bo_destroy(&sna->kgem, upload); 16563 16564 box++; 16565 } while (--n); 16566 16567 sna->blt_state.fill_bo = 0; 16568 return true; 16569} 16570 16571static void 16572sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable, 16573 int w, int h, 16574 int x, int y) 16575{ 16576 RegionRec region; 16577 16578 if (w == 0 || h == 0) 16579 return; 16580 16581 DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 16582 16583 region.extents.x1 = x; 16584 region.extents.y1 = y; 16585 region.extents.x2 = region.extents.x1 + w; 16586 region.extents.y2 = region.extents.y1 + h; 16587 16588 clip_box(®ion.extents, gc); 16589 if (box_empty(®ion.extents)) 16590 return; 16591 16592 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16593 region.extents.x1, region.extents.y1, 16594 region.extents.x2, region.extents.y2)); 16595 16596 region.data = NULL; 16597 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16598 return; 16599 16600 switch (gc->fillStyle) { 16601 case FillSolid: 16602 if (sna_push_pixels_solid_blt(gc, bitmap, drawable, ®ion)) 16603 return; 16604 break; 16605 default: 16606 break; 16607 } 16608 16609 DBG(("%s: fallback\n", __FUNCTION__)); 16610 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16611 goto out; 16612 if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ)) 16613 goto out; 16614 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16615 drawable_gc_flags(drawable, gc, false))) 16616 goto out; 16617 16618 if (sigtrap_get() == 0) { 16619 DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n", 16620 __FUNCTION__, w, h, x, y)); 16621 fbPushPixels(gc, bitmap, drawable, w, h, x, y); 16622 FALLBACK_FLUSH(drawable); 16623 sigtrap_put(); 16624 } 16625out: 16626 sna_gc_move_to_gpu(gc); 16627 RegionUninit(®ion); 16628} 16629 16630static const GCOps sna_gc_ops = { 16631 sna_fill_spans, 16632 sna_set_spans, 16633 sna_put_image, 16634 sna_copy_area, 16635 sna_copy_plane, 16636 sna_poly_point, 16637 sna_poly_line, 16638 sna_poly_segment, 16639 sna_poly_rectangle, 16640 sna_poly_arc, 16641 sna_poly_fill_polygon, 16642 sna_poly_fill_rect, 16643 sna_poly_fill_arc, 16644 sna_poly_text8, 16645 sna_poly_text16, 16646 sna_image_text8, 16647 sna_image_text16, 16648 sna_image_glyph, 16649 sna_poly_glyph, 16650 sna_push_pixels, 16651}; 16652 16653static const GCOps sna_gc_ops__cpu = { 16654 fbFillSpans, 16655 fbSetSpans, 16656 fbPutImage, 16657 fbCopyArea, 16658 fbCopyPlane, 16659 sna_poly_point__cpu, 16660 fbPolyLine, 16661 fbPolySegment, 16662 miPolyRectangle, 16663 fbPolyArc, 16664 miFillPolygon, 16665 fbPolyFillRect, 16666 miPolyFillArc, 16667 miPolyText8, 16668 miPolyText16, 16669 miImageText8, 16670 miImageText16, 16671 fbImageGlyphBlt, 16672 fbPolyGlyphBlt, 16673 fbPushPixels 16674}; 16675 16676static GCOps sna_gc_ops__tmp = { 16677 sna_fill_spans, 16678 sna_set_spans, 16679 sna_put_image, 16680 sna_copy_area, 16681 sna_copy_plane, 16682 sna_poly_point, 16683 sna_poly_line, 16684 sna_poly_segment, 16685 sna_poly_rectangle, 16686 sna_poly_arc, 16687 sna_poly_fill_polygon, 16688 sna_poly_fill_rect, 16689 sna_poly_fill_arc, 16690 sna_poly_text8, 16691 sna_poly_text16, 16692 sna_image_text8, 16693 sna_image_text16, 16694 sna_image_glyph, 16695 sna_poly_glyph, 16696 sna_push_pixels, 16697}; 16698 16699static void 16700sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) 16701{ 16702 DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc, 16703 changes, gc->serialNumber, drawable->serialNumber)); 16704 16705 if (changes & (GCClipMask|GCSubwindowMode) || 16706 drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) || 16707 (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) { 16708 DBG(("%s: recomputing clip\n", __FUNCTION__)); 16709 miComputeCompositeClip(gc, drawable); 16710 DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n", 16711 __FUNCTION__, 16712 region_num_rects(gc->pCompositeClip), 16713 gc->pCompositeClip->extents.x1, 16714 gc->pCompositeClip->extents.y1, 16715 gc->pCompositeClip->extents.x2, 16716 gc->pCompositeClip->extents.y2, 16717 gc->pCompositeClip)); 16718 } 16719 16720 assert(gc->pCompositeClip); 16721 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x); 16722 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y); 16723 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width); 16724 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height); 16725 16726 sna_gc(gc)->changes |= changes; 16727 sna_gc(gc)->serial = gc->serialNumber; 16728} 16729 16730static const GCFuncs sna_gc_funcs = { 16731 sna_validate_gc, 16732 miChangeGC, 16733 miCopyGC, 16734 miDestroyGC, 16735 miChangeClip, 16736 miDestroyClip, 16737 miCopyClip 16738}; 16739 16740static const GCFuncs sna_gc_funcs__cpu = { 16741 fbValidateGC, 16742 miChangeGC, 16743 miCopyGC, 16744 miDestroyGC, 16745 miChangeClip, 16746 miDestroyClip, 16747 miCopyClip 16748}; 16749 16750static int sna_create_gc(GCPtr gc) 16751{ 16752 gc->miTranslate = 1; 16753 gc->fExpose = 1; 16754 16755 gc->freeCompClip = 0; 16756 gc->pCompositeClip = 0; 16757 16758 fb_gc(gc)->bpp = bits_per_pixel(gc->depth); 16759 16760 gc->funcs = (GCFuncs *)&sna_gc_funcs; 16761 gc->ops = (GCOps *)&sna_gc_ops; 16762 return true; 16763} 16764 16765static bool 16766sna_get_image__inplace(PixmapPtr pixmap, 16767 RegionPtr region, 16768 char *dst, 16769 unsigned flags, 16770 bool idle) 16771{ 16772 struct sna_pixmap *priv = sna_pixmap(pixmap); 16773 struct sna *sna = to_sna_from_pixmap(pixmap); 16774 char *src; 16775 16776 if (!USE_INPLACE) 16777 return false; 16778 16779 assert(priv && priv->gpu_bo); 16780 16781 switch (priv->gpu_bo->tiling) { 16782 case I915_TILING_Y: 16783 return false; 16784 case I915_TILING_X: 16785 if (!sna->kgem.memcpy_from_tiled_x) 16786 return false; 16787 default: 16788 break; 16789 } 16790 16791 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 16792 return false; 16793 16794 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 16795 return false; 16796 16797 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 16798 return false; 16799 16800 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 16801 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 16802 16803 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 16804 if (src == NULL) 16805 return false; 16806 16807 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 16808 16809 if (sigtrap_get()) 16810 return false; 16811 16812 if (priv->gpu_bo->tiling) { 16813 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 16814 memcpy_from_tiled_x(&sna->kgem, src, dst, 16815 pixmap->drawable.bitsPerPixel, 16816 priv->gpu_bo->pitch, 16817 PixmapBytePad(region->extents.x2 - region->extents.x1, 16818 pixmap->drawable.depth), 16819 region->extents.x1, region->extents.y1, 16820 0, 0, 16821 region->extents.x2 - region->extents.x1, 16822 region->extents.y2 - region->extents.y1); 16823 } else { 16824 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 16825 memcpy_blt(src, dst, 16826 pixmap->drawable.bitsPerPixel, 16827 priv->gpu_bo->pitch, 16828 PixmapBytePad(region->extents.x2 - region->extents.x1, 16829 pixmap->drawable.depth), 16830 region->extents.x1, region->extents.y1, 16831 0, 0, 16832 region->extents.x2 - region->extents.x1, 16833 region->extents.y2 - region->extents.y1); 16834 if (!priv->shm) { 16835 assert(src == MAP(priv->gpu_bo->map__cpu)); 16836 pixmap->devPrivate.ptr = src; 16837 pixmap->devKind = priv->gpu_bo->pitch; 16838 priv->mapped = MAPPED_CPU; 16839 assert_pixmap_map(pixmap, priv); 16840 priv->cpu = true; 16841 } 16842 } 16843 16844 sigtrap_put(); 16845 return true; 16846} 16847 16848static bool 16849sna_get_image__blt(PixmapPtr pixmap, 16850 RegionPtr region, 16851 char *dst, 16852 unsigned flags) 16853{ 16854 struct sna_pixmap *priv = sna_pixmap(pixmap); 16855 struct sna *sna = to_sna_from_pixmap(pixmap); 16856 struct kgem_bo *dst_bo; 16857 bool ok = false; 16858 int pitch; 16859 16860 assert(priv && priv->gpu_bo); 16861 16862 if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS) 16863 return false; 16864 16865 if (!sna->kgem.can_blt_cpu) 16866 return false; 16867 16868 if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT && 16869 kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 16870 if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT)) 16871 return false; 16872 16873 if (priv->gpu_damage == NULL) 16874 return false; 16875 16876 assert(priv->gpu_bo); 16877 if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 16878 return false; 16879 } else { 16880 if (priv->gpu_damage == NULL) 16881 return false; 16882 16883 assert(priv->gpu_bo); 16884 } 16885 16886 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 16887 return false; 16888 16889 DBG(("%s: download through a temporary map\n", __FUNCTION__)); 16890 16891 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 16892 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 16893 16894 pitch = PixmapBytePad(region->extents.x2 - region->extents.x1, 16895 pixmap->drawable.depth); 16896 dst_bo = kgem_create_map(&sna->kgem, dst, 16897 pitch * (region->extents.y2 - region->extents.y1), 16898 false); 16899 if (dst_bo) { 16900 dst_bo->pitch = pitch; 16901 kgem_bo_mark_unreusable(dst_bo); 16902 16903 ok = sna->render.copy_boxes(sna, GXcopy, 16904 &pixmap->drawable, priv->gpu_bo, 0, 0, 16905 &pixmap->drawable, dst_bo, 16906 -region->extents.x1, 16907 -region->extents.y1, 16908 ®ion->extents, 1, 16909 COPY_LAST); 16910 16911 kgem_bo_sync__cpu(&sna->kgem, dst_bo); 16912 assert(dst_bo->rq == NULL); 16913 kgem_bo_destroy(&sna->kgem, dst_bo); 16914 } 16915 16916 return ok; 16917} 16918 16919static bool 16920sna_get_image__fast(PixmapPtr pixmap, 16921 RegionPtr region, 16922 char *dst, 16923 unsigned flags) 16924{ 16925 struct sna_pixmap *priv = sna_pixmap(pixmap); 16926 16927 DBG(("%s: attached?=%d, has gpu damage?=%d\n", 16928 __FUNCTION__, priv != NULL, priv && priv->gpu_damage)); 16929 if (priv == NULL || priv->gpu_damage == NULL) 16930 return false; 16931 16932 if (priv->clear) { 16933 int w = region->extents.x2 - region->extents.x1; 16934 int h = region->extents.y2 - region->extents.y1; 16935 int pitch = PixmapBytePad(w, pixmap->drawable.depth); 16936 16937 DBG(("%s: applying clear [%08x]\n", 16938 __FUNCTION__, priv->clear_color)); 16939 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 16940 assert(priv->cpu_damage == NULL); 16941 16942 if (priv->clear_color == 0 || 16943 pixmap->drawable.bitsPerPixel == 8 || 16944 priv->clear_color == (1U << pixmap->drawable.depth) - 1) { 16945 DBG(("%s: memset clear [%02x]\n", 16946 __FUNCTION__, priv->clear_color & 0xff)); 16947 memset(dst, priv->clear_color, pitch * h); 16948 } else { 16949 pixman_fill((uint32_t *)dst, 16950 pitch/sizeof(uint32_t), 16951 pixmap->drawable.bitsPerPixel, 16952 0, 0, 16953 w, h, 16954 priv->clear_color); 16955 } 16956 16957 return true; 16958 } 16959 16960 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 16961 !sna_damage_contains_box__no_reduce(priv->gpu_damage, 16962 ®ion->extents)) 16963 return false; 16964 16965 if (sna_get_image__inplace(pixmap, region, dst, flags, true)) 16966 return true; 16967 16968 if (sna_get_image__blt(pixmap, region, dst, flags)) 16969 return true; 16970 16971 if (sna_get_image__inplace(pixmap, region, dst, flags, false)) 16972 return true; 16973 16974 return false; 16975} 16976 16977static void 16978sna_get_image(DrawablePtr drawable, 16979 int x, int y, int w, int h, 16980 unsigned int format, unsigned long mask, 16981 char *dst) 16982{ 16983 RegionRec region; 16984 unsigned int flags; 16985 16986 if (!fbDrawableEnabled(drawable)) 16987 return; 16988 16989 DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n", 16990 __FUNCTION__, 16991 (long)get_drawable_pixmap(drawable)->drawable.serialNumber, 16992 x, y, w, h, format, mask, drawable->depth)); 16993 16994 flags = MOVE_READ; 16995 if ((w | h) == 1) 16996 flags |= MOVE_INPLACE_HINT; 16997 if (w == drawable->width) 16998 flags |= MOVE_WHOLE_HINT; 16999 17000 if (ACCEL_GET_IMAGE && 17001 !FORCE_FALLBACK && 17002 format == ZPixmap && 17003 drawable->bitsPerPixel >= 8 && 17004 PM_IS_SOLID(drawable, mask)) { 17005 PixmapPtr pixmap = get_drawable_pixmap(drawable); 17006 int16_t dx, dy; 17007 17008 get_drawable_deltas(drawable, pixmap, &dx, &dy); 17009 region.extents.x1 = x + drawable->x + dx; 17010 region.extents.y1 = y + drawable->y + dy; 17011 region.extents.x2 = region.extents.x1 + w; 17012 region.extents.y2 = region.extents.y1 + h; 17013 region.data = NULL; 17014 17015 if (sna_get_image__fast(pixmap, ®ion, dst, flags)) 17016 return; 17017 17018 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 17019 ®ion, flags)) 17020 return; 17021 17022 DBG(("%s: copy box (%d, %d), (%d, %d)\n", 17023 __FUNCTION__, 17024 region.extents.x1, region.extents.y1, 17025 region.extents.x2, region.extents.y2)); 17026 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ)); 17027 if (sigtrap_get() == 0) { 17028 assert(pixmap->devKind); 17029 memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel, 17030 pixmap->devKind, PixmapBytePad(w, drawable->depth), 17031 region.extents.x1, region.extents.y1, 0, 0, w, h); 17032 sigtrap_put(); 17033 } 17034 } else { 17035 region.extents.x1 = x + drawable->x; 17036 region.extents.y1 = y + drawable->y; 17037 region.extents.x2 = region.extents.x1 + w; 17038 region.extents.y2 = region.extents.y1 + h; 17039 region.data = NULL; 17040 17041 if (sna_drawable_move_region_to_cpu(drawable, ®ion, flags)) 17042 fbGetImage(drawable, x, y, w, h, format, mask, dst); 17043 } 17044} 17045 17046static void 17047sna_get_spans(DrawablePtr drawable, int wMax, 17048 DDXPointPtr pt, int *width, int n, char *start) 17049{ 17050 RegionRec region; 17051 17052 if (!fbDrawableEnabled(drawable)) 17053 return; 17054 17055 if (sna_spans_extents(drawable, NULL, n, pt, width, ®ion.extents) == 0) 17056 return; 17057 17058 region.data = NULL; 17059 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_READ)) 17060 return; 17061 17062 fbGetSpans(drawable, wMax, pt, width, n, start); 17063} 17064 17065static void 17066sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src) 17067{ 17068 PixmapPtr pixmap = get_window_pixmap(win); 17069 struct sna *sna = to_sna_from_pixmap(pixmap); 17070 RegionRec dst; 17071 int dx, dy; 17072 17073 DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y)); 17074 if (!fbWindowEnabled(win)) 17075 return; 17076 17077 dx = origin.x - win->drawable.x; 17078 dy = origin.y - win->drawable.y; 17079 RegionTranslate(src, -dx, -dy); 17080 17081 RegionNull(&dst); 17082 RegionIntersect(&dst, &win->borderClip, src); 17083 if (box_empty(&dst.extents)) 17084 return; 17085 17086#ifdef COMPOSITE 17087 if (pixmap->screen_x | pixmap->screen_y) 17088 RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y); 17089#endif 17090 17091 if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) { 17092 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 17093 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 17094 return; 17095 17096 if (sigtrap_get() == 0) { 17097 miCopyRegion(&pixmap->drawable, &pixmap->drawable, 17098 0, &dst, dx, dy, fbCopyNtoN, 0, NULL); 17099 sigtrap_put(); 17100 } 17101 } else { 17102 sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL, 17103 &dst, dx, dy, 0, NULL); 17104 } 17105 17106 RegionUninit(&dst); 17107} 17108 17109static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) 17110{ 17111 bool ret = true; 17112 17113 DBG(("%s\n", __FUNCTION__)); 17114 17115 /* Check if the fb layer wishes to modify the attached pixmaps, 17116 * to fix up mismatches between the window and pixmap depths. 17117 */ 17118 if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) { 17119 DBG(("%s: flushing background pixmap\n", __FUNCTION__)); 17120 ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap); 17121 } 17122 17123 if (mask & CWBorderPixmap && win->borderIsPixel == false) { 17124 DBG(("%s: flushing border pixmap\n", __FUNCTION__)); 17125 ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap); 17126 } 17127 17128 return ret; 17129} 17130 17131void sna_accel_flush(struct sna *sna) 17132{ 17133 struct sna_pixmap *priv; 17134 17135 /* XXX we should be able to reduce the frequency of flushes further 17136 * by checking for outgoing damage events or sync replies. Tricky, 17137 * and doesn't appear to mitigate the performance loss. 17138 */ 17139 DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__, 17140 sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps))); 17141 17142 /* flush any pending damage from shadow copies to tfp clients */ 17143 while (!list_is_empty(&sna->flush_pixmaps)) { 17144 bool ret; 17145 17146 priv = list_first_entry(&sna->flush_pixmaps, 17147 struct sna_pixmap, flush_list); 17148 17149 list_del(&priv->flush_list); 17150 if (priv->shm) { 17151 DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n", 17152 __FUNCTION__, 17153 priv->pixmap->drawable.serialNumber, 17154 priv->pixmap->refcnt)); 17155 assert(!priv->flush); 17156 ret = sna_pixmap_move_to_cpu(priv->pixmap, 17157 MOVE_READ | MOVE_WRITE); 17158 assert(!ret || priv->gpu_bo == NULL); 17159 if (priv->pixmap->refcnt == 0) { 17160 sna_damage_destroy(&priv->cpu_damage); 17161 __sna_free_pixmap(sna, priv->pixmap, priv); 17162 } 17163 } else { 17164 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__, 17165 priv->pixmap->drawable.serialNumber)); 17166 assert(priv->flush); 17167 if (sna_pixmap_move_to_gpu(priv->pixmap, 17168 MOVE_READ | __MOVE_FORCE)) { 17169 if (priv->flush & IS_CLIPPED) { 17170 kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 17171 sna_damage_all(&priv->gpu_damage, priv->pixmap); 17172 assert(priv->cpu_damage == NULL); 17173 priv->clear = false; 17174 priv->cpu = false; 17175 } 17176 } 17177 } 17178 (void)ret; 17179 } 17180 17181 if (sna->kgem.flush) 17182 kgem_submit(&sna->kgem); 17183} 17184 17185static void 17186sna_accel_flush_callback(CallbackListPtr *list, 17187 pointer user_data, pointer call_data) 17188{ 17189 sna_accel_flush(user_data); 17190} 17191 17192static struct sna_pixmap *sna_accel_scanout(struct sna *sna) 17193{ 17194 struct sna_pixmap *priv; 17195 17196 if (sna->mode.front_active == 0) 17197 return NULL; 17198 17199 assert(sna->vblank_interval); 17200 assert(sna->front); 17201 17202 priv = sna_pixmap(sna->front); 17203 if (priv->gpu_bo == NULL) 17204 return NULL; 17205 17206 return priv; 17207} 17208 17209#define TIME currentTime.milliseconds 17210static void sna_accel_disarm_timer(struct sna *sna, int id) 17211{ 17212 DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME)); 17213 sna->timer_active &= ~(1<<id); 17214} 17215 17216static bool has_offload_slaves(struct sna *sna) 17217{ 17218#if HAS_PIXMAP_SHARING 17219 ScreenPtr screen = sna->scrn->pScreen; 17220 PixmapDirtyUpdatePtr dirty; 17221 17222 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17223 assert(dirty->src == sna->front); 17224 if (RegionNotEmpty(DamageRegion(dirty->damage))) 17225 return true; 17226 } 17227#endif 17228 return false; 17229} 17230 17231static bool has_shadow(struct sna *sna) 17232{ 17233 DamagePtr damage = sna->mode.shadow_damage; 17234 17235 if (damage == NULL) 17236 return false; 17237 17238 DBG(("%s: has pending damage? %d, outstanding flips: %d\n", 17239 __FUNCTION__, 17240 RegionNotEmpty(DamageRegion(damage)), 17241 sna->mode.flip_active)); 17242 17243 return RegionNotEmpty(DamageRegion(damage)); 17244} 17245 17246static bool start_flush(struct sna *sna) 17247{ 17248 struct sna_pixmap *scanout; 17249 17250 if (has_offload_slaves(sna)) { 17251 DBG(("%s: has offload slaves\n", __FUNCTION__)); 17252 return true; 17253 } 17254 17255 if (has_shadow(sna)) { 17256 DBG(("%s: has dirty shadow\n", __FUNCTION__)); 17257 return true; 17258 } 17259 17260 scanout = sna_accel_scanout(sna); 17261 if (!scanout) 17262 return false; 17263 17264 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17265 scanout->gpu_bo->needs_flush = true; 17266 return true; 17267 } 17268 17269 if (scanout->cpu_damage || scanout->gpu_bo->needs_flush) 17270 return true; 17271 17272 kgem_scanout_flush(&sna->kgem, scanout->gpu_bo); 17273 return false; 17274} 17275 17276static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout) 17277{ 17278 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 17279 __FUNCTION__, 17280 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 17281 has_shadow(sna), has_offload_slaves(sna), 17282 scanout && scanout->cpu_damage != NULL, 17283 scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL)); 17284 17285 if (has_offload_slaves(sna)) 17286 return true; 17287 17288 if (has_shadow(sna)) 17289 return true; 17290 17291 if (!scanout) 17292 return false; 17293 17294 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17295 scanout->gpu_bo->needs_flush = true; 17296 return true; 17297 } 17298 17299 return scanout->cpu_damage || scanout->gpu_bo->needs_flush; 17300} 17301 17302static void timer_enable(struct sna *sna, int whom, int interval) 17303{ 17304 if (!sna->timer_active) 17305 UpdateCurrentTimeIf(); 17306 sna->timer_active |= 1 << whom; 17307 sna->timer_expire[whom] = TIME + interval; 17308 DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); 17309} 17310 17311static bool sna_scanout_do_flush(struct sna *sna) 17312{ 17313 int interval = sna->vblank_interval ?: 50; 17314 if (sna->timer_active & (1<<(FLUSH_TIMER))) { 17315 int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME; 17316 DBG(("%s: flush timer active: delta=%d\n", 17317 __FUNCTION__, delta)); 17318 if (delta <= 3) { 17319 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17320 sna->timer_expire[FLUSH_TIMER] = TIME + interval; 17321 return true; 17322 } 17323 } else { 17324 if (start_flush(sna)) 17325 timer_enable(sna, FLUSH_TIMER, interval/2); 17326 } 17327 17328 return false; 17329} 17330 17331static bool sna_accel_do_throttle(struct sna *sna) 17332{ 17333 if (sna->timer_active & (1<<(THROTTLE_TIMER))) { 17334 int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME; 17335 if (delta <= 3) { 17336 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17337 sna->timer_expire[THROTTLE_TIMER] = TIME + 20; 17338 return true; 17339 } 17340 } else if (!sna->kgem.need_retire) { 17341 DBG(("%s -- no pending activity\n", __FUNCTION__)); 17342 } else 17343 timer_enable(sna, THROTTLE_TIMER, 20); 17344 17345 return false; 17346} 17347 17348static bool sna_accel_do_expire(struct sna *sna) 17349{ 17350 if (sna->timer_active & (1<<(EXPIRE_TIMER))) { 17351 int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME; 17352 if (delta <= 3) { 17353 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17354 sna->timer_expire[EXPIRE_TIMER] = 17355 TIME + MAX_INACTIVE_TIME * 1000; 17356 return true; 17357 } 17358 } else if (sna->kgem.need_expire) 17359 timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000); 17360 17361 return false; 17362} 17363 17364static void sna_accel_post_damage(struct sna *sna) 17365{ 17366#if HAS_PIXMAP_SHARING 17367 ScreenPtr screen = sna->scrn->pScreen; 17368 PixmapDirtyUpdatePtr dirty; 17369 bool flush = false; 17370 17371 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17372 RegionRec region, *damage; 17373 DrawablePtr src; 17374 PixmapPtr dst; 17375 const BoxRec *box; 17376 int16_t dx, dy; 17377 int n; 17378 17379 assert(dirty->src == sna->front); 17380 17381 damage = DamageRegion(dirty->damage); 17382 if (RegionNil(damage)) 17383 continue; 17384 17385 src = dirty->src; 17386 dst = dirty->slave_dst->master_pixmap; 17387 17388 region.extents.x1 = dirty->x; 17389 region.extents.x2 = dirty->x + dst->drawable.width; 17390 region.extents.y1 = dirty->y; 17391 region.extents.y2 = dirty->y + dst->drawable.height; 17392 region.data = NULL; 17393 17394 DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__, 17395 damage->extents.x1, damage->extents.y1, 17396 damage->extents.x2, damage->extents.y2, 17397 region_num_rects(damage), 17398 dst->drawable.serialNumber, 17399 region.extents.x1, region.extents.y1, 17400 region.extents.x2, region.extents.y2)); 17401 17402 RegionIntersect(®ion, ®ion, damage); 17403 if (RegionNil(®ion)) 17404 goto skip; 17405 17406 dx = -dirty->x; 17407 dy = -dirty->y; 17408#if HAS_DIRTYTRACKING2 17409 dx += dirty->dst_x; 17410 dy += dirty->dst_y; 17411#endif 17412 RegionTranslate(®ion, dx, dy); 17413 DamageRegionAppend(&dirty->slave_dst->drawable, ®ion); 17414 17415 DBG(("%s: slave: ((%d, %d), (%d, %d))x%d\n", __FUNCTION__, 17416 region.extents.x1, region.extents.y1, 17417 region.extents.x2, region.extents.y2, 17418 region_num_rects(®ion))); 17419 17420 box = region_rects(®ion); 17421 n = region_num_rects(®ion); 17422 if (wedged(sna)) { 17423fallback: 17424 if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) 17425 goto skip; 17426 17427 if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT)) 17428 goto skip; 17429 17430 if (sigtrap_get() == 0) { 17431 assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel); 17432 do { 17433 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 17434 __FUNCTION__, 17435 box->x1 - dx, box->y1 - dy, 17436 box->x1, box->y1, 17437 box->x2 - box->x1, box->y2 - box->y1)); 17438 17439 assert(box->x2 > box->x1); 17440 assert(box->y2 > box->y1); 17441 17442 assert(box->x1 - dx >= 0); 17443 assert(box->y1 - dy >= 0); 17444 assert(box->x2 - dx <= src->drawable.width); 17445 assert(box->y2 - dy <= src->drawable.height); 17446 17447 assert(box->x1 >= 0); 17448 assert(box->y1 >= 0); 17449 assert(box->x2 <= src->drawable.width); 17450 assert(box->y2 <= src->drawable.height); 17451 17452 assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ)); 17453 assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE)); 17454 assert(src->devKind); 17455 assert(dst->devKind); 17456 memcpy_blt(src->devPrivate.ptr, 17457 dst->devPrivate.ptr, 17458 src->drawable.bitsPerPixel, 17459 src->devKind, dst->devKind, 17460 box->x1 - dx, box->y1 - dy, 17461 box->x1, box->y1, 17462 box->x2 - box->x1, box->y2 - box->y1); 17463 box++; 17464 } while (--n); 17465 sigtrap_put(); 17466 } 17467 } else { 17468 if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17469 goto fallback; 17470 17471 if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17472 goto fallback; 17473 17474 if (!sna->render.copy_boxes(sna, GXcopy, 17475 &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy, 17476 &dst->drawable, __sna_pixmap_get_bo(dst), 0, 0, 17477 box, n, COPY_LAST)) 17478 goto fallback; 17479 17480 flush = true; 17481 } 17482 17483 DamageRegionProcessPending(&dirty->slave_dst->drawable); 17484skip: 17485 RegionUninit(®ion); 17486 DamageEmpty(dirty->damage); 17487 } 17488 if (flush) 17489 kgem_submit(&sna->kgem); 17490#endif 17491} 17492 17493static void sna_scanout_flush(struct sna *sna) 17494{ 17495 struct sna_pixmap *priv = sna_accel_scanout(sna); 17496 bool busy; 17497 17498 DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n", 17499 __FUNCTION__, (long)TIME, 17500 priv && priv->cpu_damage, 17501 priv && priv->gpu_bo->exec != NULL, 17502 sna->kgem.nbatch, 17503 sna->kgem.busy)); 17504 17505 busy = stop_flush(sna, priv); 17506 if (!sna->kgem.busy && !busy) 17507 sna_accel_disarm_timer(sna, FLUSH_TIMER); 17508 sna->kgem.busy = busy; 17509 17510 if (priv && 17511 sna->mode.shadow_damage == NULL && 17512 sna_pixmap_force_to_gpu(priv->pixmap, 17513 MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) 17514 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 17515 17516 sna_mode_redisplay(sna); 17517 sna_accel_post_damage(sna); 17518} 17519 17520static void sna_accel_throttle(struct sna *sna) 17521{ 17522 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17523 17524 if (sna->kgem.need_throttle) { 17525 kgem_submit(&sna->kgem); 17526 kgem_throttle(&sna->kgem); 17527 } 17528 17529 if (!sna->kgem.need_retire) 17530 sna_accel_disarm_timer(sna, THROTTLE_TIMER); 17531} 17532 17533static void sna_pixmap_expire(struct sna *sna) 17534{ 17535 while (sna->freed_pixmap) { 17536 PixmapPtr pixmap = __pop_freed_pixmap(sna); 17537 free(sna_pixmap(pixmap)); 17538 FreePixmap(pixmap); 17539 } 17540} 17541 17542static void sna_accel_expire(struct sna *sna) 17543{ 17544 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17545 17546 kgem_expire_cache(&sna->kgem); 17547 sna_pixmap_expire(sna); 17548 17549 if (!sna->kgem.need_expire) 17550 sna_accel_disarm_timer(sna, EXPIRE_TIMER); 17551} 17552 17553#ifdef DEBUG_MEMORY 17554static bool sna_accel_do_debug_memory(struct sna *sna) 17555{ 17556 int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME; 17557 17558 if (delta <= 3) { 17559 sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000; 17560 return true; 17561 } else 17562 return false; 17563} 17564 17565static void sna_accel_debug_memory(struct sna *sna) 17566{ 17567 ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n", 17568 sna->debug_memory.pixmap_allocs, 17569 sna->debug_memory.pixmap_cached, 17570 sna->kgem.debug_memory.bo_allocs, 17571 (unsigned long)sna->kgem.debug_memory.bo_bytes, 17572 sna->debug_memory.cpu_bo_allocs, 17573 (unsigned long)sna->debug_memory.cpu_bo_bytes); 17574 17575#ifdef VALGRIND_DO_ADDED_LEAK_CHECK 17576 VG(VALGRIND_DO_ADDED_LEAK_CHECK); 17577#endif 17578} 17579 17580#else 17581#define sna_accel_do_debug_memory(x) 0 17582static void sna_accel_debug_memory(struct sna *sna) { } 17583#endif 17584 17585static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL }; 17586 17587static PixmapPtr 17588sna_get_window_pixmap(WindowPtr window) 17589{ 17590 return get_window_pixmap(window); 17591} 17592 17593static void 17594sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) 17595{ 17596 DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n", 17597 __FUNCTION__, window->drawable.id, 17598 get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0, 17599 pixmap->drawable.serialNumber)); 17600 17601 sna_dri2_decouple_window(window); 17602 17603 *(PixmapPtr *)__get_private(window, sna_window_key) = pixmap; 17604} 17605 17606struct sna_visit_set_pixmap_window { 17607 PixmapPtr old, new; 17608}; 17609 17610static int 17611sna_visit_set_window_pixmap(WindowPtr window, pointer data) 17612{ 17613 struct sna_visit_set_pixmap_window *visit = data; 17614 17615 if (sna_get_window_pixmap(window) == visit->old) { 17616 window->drawable.pScreen->SetWindowPixmap(window, visit->new); 17617 return WT_WALKCHILDREN; 17618 } 17619 17620 return WT_DONTWALKCHILDREN; 17621} 17622 17623static void 17624migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front) 17625{ 17626#if HAS_PIXMAP_SHARING 17627 ScreenPtr screen = old_front->drawable.pScreen; 17628 PixmapDirtyUpdatePtr dirty, safe; 17629 17630 xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) { 17631 assert(dirty->src == old_front); 17632 if (dirty->src != old_front) 17633 continue; 17634 17635 DamageUnregister(&dirty->src->drawable, dirty->damage); 17636 DamageDestroy(dirty->damage); 17637 17638 dirty->damage = DamageCreate(NULL, NULL, 17639 DamageReportNone, 17640 TRUE, screen, screen); 17641 if (!dirty->damage) { 17642 xorg_list_del(&dirty->ent); 17643 free(dirty); 17644 continue; 17645 } 17646 17647 DamageRegister(&new_front->drawable, dirty->damage); 17648 dirty->src = new_front; 17649 } 17650#endif 17651} 17652 17653static void 17654sna_set_screen_pixmap(PixmapPtr pixmap) 17655{ 17656 ScreenPtr screen = pixmap->drawable.pScreen; 17657 PixmapPtr old_front = screen->devPrivate; 17658 WindowPtr root; 17659 17660 DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n", 17661 __FUNCTION__, 17662 old_front ? (long)old_front->drawable.serialNumber : 0, 17663 pixmap ? (long)pixmap->drawable.serialNumber : 0, 17664 to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0)); 17665 17666 assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen)); 17667 assert(to_sna_from_pixmap(pixmap)->front == old_front); 17668 17669 if (old_front) { 17670 assert(to_sna_from_pixmap(old_front)->front == old_front); 17671 migrate_dirty_tracking(old_front, pixmap); 17672 } 17673 17674 root = get_root_window(screen); 17675 if (root) { 17676 struct sna_visit_set_pixmap_window visit = { old_front, pixmap }; 17677 TraverseTree(root, sna_visit_set_window_pixmap, &visit); 17678 assert(fbGetWindowPixmap(root) == pixmap); 17679 } 17680 17681 to_sna_from_pixmap(pixmap)->front = pixmap; 17682 screen->devPrivate = pixmap; 17683 pixmap->refcnt++; 17684 17685 if (old_front) 17686 screen->DestroyPixmap(old_front); 17687} 17688 17689static Bool 17690sna_create_window(WindowPtr win) 17691{ 17692 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate); 17693 return TRUE; 17694} 17695 17696static Bool 17697sna_map_window(WindowPtr win) 17698{ 17699 return TRUE; 17700} 17701 17702static Bool 17703sna_position_window(WindowPtr win, int x, int y) 17704{ 17705 return TRUE; 17706} 17707 17708static Bool 17709sna_unmap_window(WindowPtr win) 17710{ 17711 return TRUE; 17712} 17713 17714static Bool 17715sna_destroy_window(WindowPtr win) 17716{ 17717 sna_video_destroy_window(win); 17718 sna_dri2_destroy_window(win); 17719 return TRUE; 17720} 17721 17722static void 17723sna_query_best_size(int class, 17724 unsigned short *width, unsigned short *height, 17725 ScreenPtr screen) 17726{ 17727 unsigned short w; 17728 17729 switch (class) { 17730 case CursorShape: 17731 if (*width > screen->width) 17732 *width = screen->width; 17733 if (*height > screen->height) 17734 *height = screen->height; 17735 break; 17736 17737 case TileShape: 17738 case StippleShape: 17739 w = *width; 17740 if ((w & (w - 1)) && w < FB_UNIT) { 17741 for (w = 1; w < *width; w <<= 1) 17742 ; 17743 *width = w; 17744 } 17745 break; 17746 } 17747} 17748 17749static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def) 17750{ 17751} 17752 17753static bool sna_picture_init(ScreenPtr screen) 17754{ 17755 PictureScreenPtr ps; 17756 17757 DBG(("%s\n", __FUNCTION__)); 17758 17759 if (!miPictureInit(screen, NULL, 0)) 17760 return false; 17761 17762 ps = GetPictureScreen(screen); 17763 assert(ps != NULL); 17764 assert(ps->CreatePicture != NULL); 17765 assert(ps->DestroyPicture != NULL); 17766 17767 ps->Composite = sna_composite; 17768 ps->CompositeRects = sna_composite_rectangles; 17769 ps->Glyphs = sna_glyphs; 17770 if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0])) 17771 ps->Glyphs = sna_glyphs__shared; 17772 ps->UnrealizeGlyph = sna_glyph_unrealize; 17773 ps->AddTraps = sna_add_traps; 17774 ps->Trapezoids = sna_composite_trapezoids; 17775#if HAS_PIXMAN_TRIANGLES 17776 ps->Triangles = sna_composite_triangles; 17777#if PICTURE_SCREEN_VERSION >= 2 17778 ps->TriStrip = sna_composite_tristrip; 17779 ps->TriFan = sna_composite_trifan; 17780#endif 17781#endif 17782 17783 return true; 17784} 17785 17786static bool sna_option_accel_none(struct sna *sna) 17787{ 17788 const char *s; 17789 17790 if (wedged(sna)) 17791 return true; 17792 17793 if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE)) 17794 return true; 17795 17796 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 17797 if (s == NULL) 17798 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 17799 17800 return strcasecmp(s, "none") == 0; 17801} 17802 17803static bool sna_option_accel_blt(struct sna *sna) 17804{ 17805 const char *s; 17806 17807 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 17808 if (s == NULL) 17809 return false; 17810 17811 return strcasecmp(s, "blt") == 0; 17812} 17813 17814bool sna_accel_init(ScreenPtr screen, struct sna *sna) 17815{ 17816 const char *backend; 17817 17818 DBG(("%s\n", __FUNCTION__)); 17819 17820 sna_font_key = AllocateFontPrivateIndex(); 17821 17822 list_init(&sna->flush_pixmaps); 17823 list_init(&sna->active_pixmaps); 17824 17825#if HAVE_NOTIFY_FD 17826 SetNotifyFd(sna->kgem.fd, NULL, X_NOTIFY_NONE, NULL); 17827#else 17828 AddGeneralSocket(sna->kgem.fd); 17829#endif 17830 17831#ifdef DEBUG_MEMORY 17832 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000; 17833#endif 17834 17835 screen->defColormap = FakeClientID(0); 17836 /* let CreateDefColormap do whatever it wants for pixels */ 17837 screen->blackPixel = screen->whitePixel = (Pixel) 0; 17838 screen->QueryBestSize = sna_query_best_size; 17839 assert(screen->GetImage == NULL); 17840 screen->GetImage = sna_get_image; 17841 assert(screen->GetSpans == NULL); 17842 screen->GetSpans = sna_get_spans; 17843 assert(screen->CreateWindow == NULL); 17844 screen->CreateWindow = sna_create_window; 17845 assert(screen->DestroyWindow == NULL); 17846 screen->DestroyWindow = sna_destroy_window; 17847 screen->PositionWindow = sna_position_window; 17848 screen->ChangeWindowAttributes = sna_change_window_attributes; 17849 screen->RealizeWindow = sna_map_window; 17850 screen->UnrealizeWindow = sna_unmap_window; 17851 screen->CopyWindow = sna_copy_window; 17852 assert(screen->CreatePixmap == NULL); 17853 screen->CreatePixmap = sna_create_pixmap; 17854 assert(screen->DestroyPixmap == NULL); 17855 screen->DestroyPixmap = sna_destroy_pixmap; 17856#ifdef CREATE_PIXMAP_USAGE_SHARED 17857 screen->SharePixmapBacking = sna_share_pixmap_backing; 17858 screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing; 17859#endif 17860 screen->RealizeFont = sna_realize_font; 17861 screen->UnrealizeFont = sna_unrealize_font; 17862 assert(screen->CreateGC == NULL); 17863 screen->CreateGC = sna_create_gc; 17864 screen->CreateColormap = miInitializeColormap; 17865 screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA; 17866 screen->InstallColormap = miInstallColormap; 17867 screen->UninstallColormap = miUninstallColormap; 17868 screen->ListInstalledColormaps = miListInstalledColormaps; 17869 screen->ResolveColor = miResolveColor; 17870 assert(screen->StoreColors == NULL); 17871 screen->StoreColors = sna_store_colors; 17872 screen->BitmapToRegion = fbBitmapToRegion; 17873 17874#if HAS_PIXMAP_SHARING 17875 screen->StartPixmapTracking = PixmapStartDirtyTracking; 17876 screen->StopPixmapTracking = PixmapStopDirtyTracking; 17877#endif 17878 17879 assert(screen->GetWindowPixmap == NULL); 17880 screen->GetWindowPixmap = sna_get_window_pixmap; 17881 assert(screen->SetWindowPixmap == NULL); 17882 screen->SetWindowPixmap = sna_set_window_pixmap; 17883 17884 screen->SetScreenPixmap = sna_set_screen_pixmap; 17885 17886 if (sna->kgem.has_userptr) 17887 ShmRegisterFuncs(screen, &shm_funcs); 17888 else 17889 ShmRegisterFbFuncs(screen); 17890 17891 if (!sna_picture_init(screen)) 17892 return false; 17893 17894 backend = no_render_init(sna); 17895 if (sna_option_accel_none(sna)) { 17896 backend = "disabled"; 17897 sna->kgem.wedged = true; 17898 sna_render_mark_wedged(sna); 17899 } else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110) 17900 (void)backend; 17901 else if (sna->info->gen >= 0100) 17902 backend = gen8_render_init(sna, backend); 17903 else if (sna->info->gen >= 070) 17904 backend = gen7_render_init(sna, backend); 17905 else if (sna->info->gen >= 060) 17906 backend = gen6_render_init(sna, backend); 17907 else if (sna->info->gen >= 050) 17908 backend = gen5_render_init(sna, backend); 17909 else if (sna->info->gen >= 040) 17910 backend = gen4_render_init(sna, backend); 17911 else if (sna->info->gen >= 030) 17912 backend = gen3_render_init(sna, backend); 17913 else if (sna->info->gen >= 020) 17914 backend = gen2_render_init(sna, backend); 17915 17916 DBG(("%s(backend=%s, prefer_gpu=%x)\n", 17917 __FUNCTION__, backend, sna->render.prefer_gpu)); 17918 17919 kgem_reset(&sna->kgem); 17920 sigtrap_init(); 17921 17922 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 17923 "SNA initialized with %s backend\n", 17924 backend); 17925 17926 return true; 17927} 17928 17929void sna_accel_create(struct sna *sna) 17930{ 17931 DBG(("%s\n", __FUNCTION__)); 17932 17933 if (!sna_glyphs_create(sna)) 17934 goto fail; 17935 17936 if (!sna_gradients_create(sna)) 17937 goto fail; 17938 17939 if (!sna_composite_create(sna)) 17940 goto fail; 17941 17942 return; 17943 17944fail: 17945 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 17946 "Failed to allocate caches, disabling RENDER acceleration\n"); 17947 no_render_init(sna); 17948} 17949 17950void sna_accel_watch_flush(struct sna *sna, int enable) 17951{ 17952 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 17953 assert(enable); 17954 17955 if (sna->watch_flush == 0) { 17956 DBG(("%s: installing watchers\n", __FUNCTION__)); 17957 assert(enable > 0); 17958 if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) { 17959 xf86DrvMsg(sna->scrn->scrnIndex, X_Error, 17960 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n"); 17961 } 17962 sna->watch_flush++; 17963 } 17964 17965 sna->watch_flush += enable; 17966} 17967 17968void sna_accel_leave(struct sna *sna) 17969{ 17970 DBG(("%s\n", __FUNCTION__)); 17971 17972 /* as root we always have permission to render */ 17973 if (geteuid() == 0) 17974 return; 17975 17976 /* as a user, we can only render now if we have a rendernode */ 17977 if (intel_has_render_node(sna->dev)) 17978 return; 17979 17980 /* no longer authorized to use our fd */ 17981 DBG(("%s: dropping render privileges\n", __FUNCTION__)); 17982 17983 kgem_submit(&sna->kgem); 17984 sna->kgem.wedged |= 2; 17985} 17986 17987void sna_accel_enter(struct sna *sna) 17988{ 17989 DBG(("%s\n", __FUNCTION__)); 17990 sna->kgem.wedged &= kgem_is_wedged(&sna->kgem); 17991 kgem_throttle(&sna->kgem); 17992} 17993 17994void sna_accel_close(struct sna *sna) 17995{ 17996 DBG(("%s\n", __FUNCTION__)); 17997 17998 sna_composite_close(sna); 17999 sna_gradients_close(sna); 18000 sna_glyphs_close(sna); 18001 18002 sna_pixmap_expire(sna); 18003 18004 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 18005#if HAVE_NOTIFY_FD 18006 RemoveNotifyFd(sna->kgem.fd); 18007#else 18008 RemoveGeneralSocket(sna->kgem.fd); 18009#endif 18010 18011 kgem_cleanup_cache(&sna->kgem); 18012} 18013 18014void sna_accel_block_handler(struct sna *sna, struct timeval **tv) 18015{ 18016 sigtrap_assert_inactive(); 18017 18018 if (sna->kgem.need_retire) 18019 kgem_retire(&sna->kgem); 18020 kgem_retire__buffers(&sna->kgem); 18021 18022 if (sna->timer_active) 18023 UpdateCurrentTimeIf(); 18024 18025 if (sna->kgem.nbatch && 18026 (sna->kgem.scanout_busy || 18027 kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) { 18028 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 18029 _kgem_submit(&sna->kgem); 18030 } 18031 18032 if (sna->mode.dirty) 18033 sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn)); 18034 18035restart: 18036 if (sna_scanout_do_flush(sna)) 18037 sna_scanout_flush(sna); 18038 assert(sna_accel_scanout(sna) == NULL || 18039 !sna_accel_scanout(sna)->gpu_bo->needs_flush || 18040 sna->timer_active & (1<<(FLUSH_TIMER))); 18041 18042 if (sna_accel_do_throttle(sna)) 18043 sna_accel_throttle(sna); 18044 assert(!sna->kgem.need_retire || 18045 sna->timer_active & (1<<(THROTTLE_TIMER))); 18046 18047 if (sna_accel_do_expire(sna)) 18048 sna_accel_expire(sna); 18049 assert(!sna->kgem.need_expire || 18050 sna->timer_active & (1<<(EXPIRE_TIMER))); 18051 18052 if (sna_accel_do_debug_memory(sna)) 18053 sna_accel_debug_memory(sna); 18054 18055 if (sna->watch_flush == 1) { 18056 DBG(("%s: removing watchers\n", __FUNCTION__)); 18057 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 18058 sna->watch_flush = 0; 18059 } 18060 18061 if (sna->timer_active & 1) { 18062 int32_t timeout; 18063 18064 DBG(("%s: evaluating timers, active=%x\n", 18065 __FUNCTION__, sna->timer_active)); 18066 18067 timeout = sna->timer_expire[FLUSH_TIMER] - TIME; 18068 DBG(("%s: flush timer expires in %d [%d]\n", 18069 __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER])); 18070 if (timeout < 3) 18071 goto restart; 18072 18073 if (*tv == NULL) { 18074 *tv = &sna->timer_tv; 18075 goto set_tv; 18076 } 18077 if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) { 18078set_tv: 18079 (*tv)->tv_sec = timeout / 1000; 18080 (*tv)->tv_usec = timeout % 1000 * 1000; 18081 } 18082 } 18083 18084 sna->kgem.scanout_busy = false; 18085 18086 if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) { 18087 DBG(("%s hardware acceleration\n", 18088 sna->kgem.wedged ? "Re-enabling" : "Disabling")); 18089 kgem_submit(&sna->kgem); 18090 sna->kgem.wedged = !sna->kgem.wedged; 18091 } 18092} 18093 18094void sna_accel_wakeup_handler(struct sna *sna) 18095{ 18096 DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__, 18097 sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge)); 18098 18099 if (!sna->kgem.nbatch) 18100 return; 18101 18102 if (kgem_is_idle(&sna->kgem)) { 18103 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 18104 _kgem_submit(&sna->kgem); 18105 } 18106 18107 sigtrap_assert_inactive(); 18108} 18109 18110void sna_accel_free(struct sna *sna) 18111{ 18112 DBG(("%s\n", __FUNCTION__)); 18113 sigtrap_assert_inactive(); 18114} 18115