sna_accel.c revision 63ef14f0
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 <X11/extensions/damageproto.h> 54 55#include <sys/time.h> 56#include <sys/mman.h> 57#include <sys/ioctl.h> 58#include <unistd.h> 59 60#ifdef HAVE_VALGRIND 61#include <valgrind.h> 62#include <memcheck.h> 63#endif 64 65#define FAULT_INJECTION 0 66 67#define FORCE_INPLACE 0 68#define FORCE_FALLBACK 0 69#define FORCE_FLUSH 0 70#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */ 71 72#define DEFAULT_PIXMAP_TILING I915_TILING_X 73#define DEFAULT_SCANOUT_TILING I915_TILING_X 74 75#define USE_INPLACE 1 76#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */ 77#define USE_CPU_BO 1 78#define USE_USERPTR_UPLOADS 1 79#define USE_USERPTR_DOWNLOADS 1 80#define USE_COW 1 81#define UNDO 1 82 83#define MIGRATE_ALL 0 84#define DBG_NO_PARTIAL_MOVE_TO_CPU 0 85#define DBG_NO_CPU_UPLOAD 0 86#define DBG_NO_CPU_DOWNLOAD 0 87 88#define ACCEL_FILL_SPANS 1 89#define ACCEL_SET_SPANS 1 90#define ACCEL_PUT_IMAGE 1 91#define ACCEL_GET_IMAGE 1 92#define ACCEL_COPY_AREA 1 93#define ACCEL_COPY_PLANE 1 94#define ACCEL_COPY_WINDOW 1 95#define ACCEL_POLY_POINT 1 96#define ACCEL_POLY_LINE 1 97#define ACCEL_POLY_SEGMENT 1 98#define ACCEL_POLY_RECTANGLE 1 99#define ACCEL_POLY_ARC 1 100#define ACCEL_POLY_FILL_POLYGON 1 101#define ACCEL_POLY_FILL_RECT 1 102#define ACCEL_POLY_FILL_ARC 1 103#define ACCEL_POLY_TEXT8 1 104#define ACCEL_POLY_TEXT16 1 105#define ACCEL_POLY_GLYPH 1 106#define ACCEL_IMAGE_TEXT8 1 107#define ACCEL_IMAGE_TEXT16 1 108#define ACCEL_IMAGE_GLYPH 1 109#define ACCEL_PUSH_PIXELS 1 110 111#define NO_TILE_8x8 0 112#define NO_STIPPLE_8x8 0 113 114#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) 115#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) 116#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) 117 118#define IS_CLIPPED 0x2 119#define RECTILINEAR 0x4 120#define OVERWRITES 0x8 121 122#if XFONT2_CLIENT_FUNCS_VERSION >= 1 123#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index() 124#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data) 125#endif 126 127#if 0 128static void __sna_fallback_flush(DrawablePtr d) 129{ 130 PixmapPtr pixmap = get_drawable_pixmap(d); 131 struct sna *sna = to_sna_from_pixmap(pixmap); 132 struct sna_pixmap *priv; 133 BoxRec box; 134 PixmapPtr tmp; 135 int i, j; 136 char *src, *dst; 137 138 DBG(("%s: uploading CPU damage...\n", __FUNCTION__)); 139 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 140 if (priv == NULL) 141 return; 142 143 DBG(("%s: downloading GPU damage...\n", __FUNCTION__)); 144 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 145 return; 146 147 box.x1 = box.y1 = 0; 148 box.x2 = pixmap->drawable.width; 149 box.y2 = pixmap->drawable.height; 150 151 tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen, 152 pixmap->drawable.width, 153 pixmap->drawable.height, 154 pixmap->drawable.depth, 155 0); 156 157 DBG(("%s: comparing with direct read...\n", __FUNCTION__)); 158 sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1); 159 160 src = pixmap->devPrivate.ptr; 161 dst = tmp->devPrivate.ptr; 162 for (i = 0; i < tmp->drawable.height; i++) { 163 if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) { 164 for (j = 0; src[j] == dst[j]; j++) 165 ; 166 ERR(("mismatch at (%d, %d)\n", 167 8*j / tmp->drawable.bitsPerPixel, i)); 168 abort(); 169 } 170 src += pixmap->devKind; 171 dst += tmp->devKind; 172 } 173 tmp->drawable.pScreen->DestroyPixmap(tmp); 174} 175#define FALLBACK_FLUSH(d) __sna_fallback_flush(d) 176#else 177#define FALLBACK_FLUSH(d) 178#endif 179 180static int sna_font_key; 181 182static const uint8_t copy_ROP[] = { 183 ROP_0, /* GXclear */ 184 ROP_DSa, /* GXand */ 185 ROP_SDna, /* GXandReverse */ 186 ROP_S, /* GXcopy */ 187 ROP_DSna, /* GXandInverted */ 188 ROP_D, /* GXnoop */ 189 ROP_DSx, /* GXxor */ 190 ROP_DSo, /* GXor */ 191 ROP_DSon, /* GXnor */ 192 ROP_DSxn, /* GXequiv */ 193 ROP_Dn, /* GXinvert */ 194 ROP_SDno, /* GXorReverse */ 195 ROP_Sn, /* GXcopyInverted */ 196 ROP_DSno, /* GXorInverted */ 197 ROP_DSan, /* GXnand */ 198 ROP_1 /* GXset */ 199}; 200static const uint8_t fill_ROP[] = { 201 ROP_0, 202 ROP_DPa, 203 ROP_PDna, 204 ROP_P, 205 ROP_DPna, 206 ROP_D, 207 ROP_DPx, 208 ROP_DPo, 209 ROP_DPon, 210 ROP_PDxn, 211 ROP_Dn, 212 ROP_PDno, 213 ROP_Pn, 214 ROP_DPno, 215 ROP_DPan, 216 ROP_1 217}; 218 219static const GCOps sna_gc_ops; 220static const GCOps sna_gc_ops__cpu; 221static GCOps sna_gc_ops__tmp; 222static const GCFuncs sna_gc_funcs; 223static const GCFuncs sna_gc_funcs__cpu; 224 225static void sna_shm_watch_flush(struct sna *sna, int enable); 226static void 227sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect); 228 229static inline void region_set(RegionRec *r, const BoxRec *b) 230{ 231 r->extents = *b; 232 r->data = NULL; 233} 234 235static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip) 236{ 237 if (clip->data && !RegionIntersect(r, r, clip)) 238 return false; 239 240 return !box_empty(&r->extents); 241} 242 243static inline bool region_is_singular(const RegionRec *r) 244{ 245 return r->data == NULL; 246} 247 248static inline bool region_is_unclipped(const RegionRec *r, int w, int h) 249{ 250 return (region_is_singular(r) && 251 w == r->extents.x2 - r->extents.x1 && 252 h == r->extents.y2 - r->extents.y1); 253} 254 255typedef struct box32 { 256 int32_t x1, y1, x2, y2; 257} Box32Rec; 258 259#define PM_IS_SOLID(_draw, _pm) \ 260 (((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth)) 261 262#ifndef NDEBUG 263static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function) 264{ 265 if (box->x1 < 0 || box->y1 < 0 || 266 box->x2 > pixmap->drawable.width || 267 box->y2 > pixmap->drawable.height) 268 { 269 FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n", 270 function, box->x1, box->y1, box->x2, box->y2, 271 pixmap->drawable.serialNumber, 272 pixmap->drawable.width, 273 pixmap->drawable.height); 274 } 275} 276 277static void 278_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function) 279{ 280 if (damage == NULL) 281 return; 282 283 _assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function); 284} 285#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__) 286#else 287#define assert_pixmap_contains_damage(p,d) 288#endif 289 290#define __assert_pixmap_damage(p) do { \ 291 struct sna_pixmap *priv__ = sna_pixmap(p); \ 292 if (priv__) { \ 293 assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \ 294 assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \ 295 assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \ 296 assert_pixmap_contains_damage(p, priv__->gpu_damage); \ 297 assert_pixmap_contains_damage(p, priv__->cpu_damage); \ 298 assert_pixmap_map(p, priv__); \ 299 } \ 300} while (0) 301 302#ifdef DEBUG_PIXMAP 303static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function) 304{ 305 BoxRec b = *box; 306 b.x1 += dx; b.x2 += dx; 307 b.y1 += dy; b.y2 += dy; 308 _assert_pixmap_contains_box(pixmap, &b, function); 309} 310 311static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function) 312{ 313 BoxRec extents; 314 315 extents = *box; 316 while (--n) { 317 ++box; 318 319 if (box->x1 < extents.x1) 320 extents.x1 = box->x1; 321 if (box->x2 > extents.x2) 322 extents.x2 = box->x2; 323 324 if (box->y1 < extents.y1) 325 extents.y1 = box->y1; 326 if (box->y2 > extents.y2) 327 extents.y2 = box->y2; 328 } 329 extents.x1 += dx; 330 extents.x2 += dx; 331 extents.y1 += dy; 332 extents.y2 += dy; 333 _assert_pixmap_contains_box(pixmap, &extents, function); 334} 335 336 337static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function) 338{ 339 BoxRec extents; 340 341 extents.x2 = extents.x1 = pt->x; 342 extents.y2 = extents.y1 = pt->y; 343 while (--n) { 344 ++pt; 345 346 if (pt->x < extents.x1) 347 extents.x1 = pt->x; 348 else if (pt->x > extents.x2) 349 extents.x2 = pt->x; 350 351 if (pt->y < extents.y1) 352 extents.y1 = pt->y; 353 else if (pt->y > extents.y2) 354 extents.y2 = pt->y; 355 } 356 extents.x1 += dx; 357 extents.x2 += dx + 1; 358 extents.y1 += dy; 359 extents.y2 += dy + 1; 360 _assert_pixmap_contains_box(pixmap, &extents, function); 361} 362 363static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function) 364{ 365 if (box->x1 < drawable->x || 366 box->y1 < drawable->y || 367 box->x2 > drawable->x + drawable->width || 368 box->y2 > drawable->y + drawable->height) 369 { 370 FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n", 371 function, 372 box->x1, box->y1, box->x2, box->y2, 373 drawable->x, drawable->y, 374 drawable->width, drawable->height); 375 } 376} 377 378static void assert_pixmap_damage(PixmapPtr p) 379{ 380 struct sna_pixmap *priv; 381 RegionRec reg, cpu, gpu; 382 383 priv = sna_pixmap(p); 384 if (priv == NULL) 385 return; 386 387 __assert_pixmap_damage(p); 388 389 if (priv->clear) { 390 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 391 assert(priv->cpu_damage == NULL); 392 } 393 394 if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) { 395 /* special upload buffer */ 396 assert(priv->gpu_bo && priv->gpu_bo->proxy); 397 assert(priv->cpu_bo == NULL); 398 return; 399 } 400 401 assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL); 402 assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL); 403 404 /* Avoid reducing damage to minimise interferrence */ 405 RegionNull(®); 406 RegionNull(&gpu); 407 RegionNull(&cpu); 408 409 if (priv->gpu_damage) 410 _sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu); 411 412 if (priv->cpu_damage) 413 _sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu); 414 415 RegionIntersect(®, &cpu, &gpu); 416 assert(RegionNil(®)); 417 418 RegionUninit(®); 419 RegionUninit(&gpu); 420 RegionUninit(&cpu); 421} 422 423#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 424#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__) 425#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__) 426#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__) 427#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__) 428 429#else 430#define assert_pixmap_contains_box(p, b) 431#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) 432#define assert_pixmap_contains_boxes(p, b, n, x, y) 433#define assert_pixmap_contains_points(p, pt, n, x, y) 434#define assert_drawable_contains_box(d, b) 435#ifndef NDEBUG 436#define assert_pixmap_damage(p) __assert_pixmap_damage(p) 437#else 438#define assert_pixmap_damage(p) 439#endif 440#endif 441 442jmp_buf sigjmp[4]; 443volatile sig_atomic_t sigtrap; 444 445static int sigtrap_handler(int sig) 446{ 447 /* XXX rate-limited squawk? */ 448 DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap)); 449 sna_threads_trap(sig); 450 451 if (sigtrap) 452 siglongjmp(sigjmp[--sigtrap], sig); 453 454 return -1; 455} 456 457static void sigtrap_init(void) 458{ 459#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 460 OsRegisterSigWrapper(sigtrap_handler); 461#endif 462} 463 464inline static bool 465sna_fill_init_blt(struct sna_fill_op *fill, 466 struct sna *sna, 467 PixmapPtr pixmap, 468 struct kgem_bo *bo, 469 uint8_t alu, 470 uint32_t pixel, 471 unsigned flags) 472{ 473 return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill); 474} 475 476static bool 477sna_copy_init_blt(struct sna_copy_op *copy, 478 struct sna *sna, 479 PixmapPtr src, struct kgem_bo *src_bo, 480 PixmapPtr dst, struct kgem_bo *dst_bo, 481 uint8_t alu) 482{ 483 memset(copy, 0, sizeof(*copy)); 484 return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); 485} 486 487static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv) 488{ 489 DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned)); 490 assert(priv->gpu_damage == NULL || priv->gpu_bo); 491 492 if (priv->cow) 493 sna_pixmap_undo_cow(sna, priv, MOVE_WRITE); 494 assert(priv->cow == NULL); 495 496 if (priv->move_to_gpu) { 497 sna_pixmap_discard_shadow_damage(priv, NULL); 498 priv->move_to_gpu(sna, priv, MOVE_WRITE); 499 } 500 501 sna_damage_destroy(&priv->gpu_damage); 502 priv->clear = false; 503 504 if (priv->gpu_bo) { 505 if (!priv->pinned) { 506 assert(!priv->flush); 507 assert(!priv->move_to_gpu); 508 sna_pixmap_unmap(priv->pixmap, priv); 509 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 510 priv->gpu_bo = NULL; 511 } else 512 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 513 } 514 515 /* and reset the upload counter */ 516 priv->source_count = SOURCE_BIAS; 517} 518 519static bool must_check 520sna_pixmap_alloc_cpu(struct sna *sna, 521 PixmapPtr pixmap, 522 struct sna_pixmap *priv, 523 unsigned flags) 524{ 525 /* Restore after a GTT mapping? */ 526 assert(priv->gpu_damage == NULL || priv->gpu_bo); 527 assert(!priv->shm); 528 if (priv->ptr) 529 goto done; 530 531 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 532 assert(priv->stride); 533 534 if (priv->create & KGEM_CAN_CREATE_CPU) { 535 unsigned hint; 536 537 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__, 538 pixmap->drawable.width, pixmap->drawable.height)); 539 540 hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE; 541 if ((flags & MOVE_ASYNC_HINT) || 542 (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu)) 543 hint = 0; 544 545 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem, 546 pixmap->drawable.width, 547 pixmap->drawable.height, 548 pixmap->drawable.bitsPerPixel, 549 hint); 550 if (priv->cpu_bo) { 551 priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 552 if (priv->ptr) { 553 DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__, 554 priv->cpu_bo->handle, priv->cpu_bo->snoop)); 555 priv->stride = priv->cpu_bo->pitch; 556#ifdef DEBUG_MEMORY 557 sna->debug_memory.cpu_bo_allocs++; 558 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 559#endif 560 } else { 561 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 562 priv->cpu_bo = NULL; 563 } 564 } 565 } 566 567 if (priv->ptr == NULL) { 568 DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n", 569 __FUNCTION__, priv->stride * pixmap->drawable.height)); 570 priv->ptr = malloc(priv->stride * pixmap->drawable.height); 571 } 572 573done: 574 assert(priv->stride); 575 assert(!priv->mapped); 576 pixmap->devPrivate.ptr = PTR(priv->ptr); 577 pixmap->devKind = priv->stride; 578 return priv->ptr != NULL; 579} 580 581static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 582{ 583 if (priv->cpu_bo) { 584 DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n", 585 __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo))); 586#ifdef DEBUG_MEMORY 587 sna->debug_memory.cpu_bo_allocs--; 588 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 589#endif 590 if (priv->cpu_bo->flush) { 591 assert(!priv->cpu_bo->reusable); 592 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 593 sna_shm_watch_flush(sna, -1); 594 } 595 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 596 } else if (!IS_STATIC_PTR(priv->ptr)) 597 free(priv->ptr); 598} 599 600static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active) 601{ 602 if (active) 603 return false; 604 605 if (IS_STATIC_PTR(priv->ptr)) 606 return false; 607 608 if (priv->ptr == NULL) 609 return true; 610 611 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 612 __sna_pixmap_free_cpu(sna, priv); 613 614 priv->cpu_bo = NULL; 615 priv->ptr = NULL; 616 617 if (priv->mapped == MAPPED_NONE) 618 priv->pixmap->devPrivate.ptr = NULL; 619 620 return true; 621} 622 623static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) 624{ 625#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE 626 return I915_TILING_NONE; 627#elif DEFAULT_PIXMAP_TILING == I915_TILING_X 628 return I915_TILING_X; 629#else 630 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ 631 if (sna->kgem.gen == 021) 632 return I915_TILING_X; 633 634 /* Only on later generations was the render pipeline 635 * more flexible than the BLT. So on gen2/3, prefer to 636 * keep large objects accessible through the BLT. 637 */ 638 if (sna->kgem.gen < 040 && 639 (pixmap->drawable.width > sna->render.max_3d_size || 640 pixmap->drawable.height > sna->render.max_3d_size)) 641 return I915_TILING_X; 642 643 return I915_TILING_Y; 644#endif 645} 646 647pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap) 648{ 649 /* Also adjust tiling if it is not supported or likely to 650 * slow us down, 651 */ 652 return kgem_choose_tiling(&sna->kgem, 653 default_tiling(sna, pixmap), 654 pixmap->drawable.width, 655 pixmap->drawable.height, 656 pixmap->drawable.bitsPerPixel); 657} 658 659struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) 660{ 661 struct sna_pixmap *priv = sna_pixmap(pixmap); 662 struct sna *sna = to_sna_from_pixmap(pixmap); 663 struct kgem_bo *bo; 664 BoxRec box; 665 666 DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n", 667 __FUNCTION__, priv->gpu_bo->tiling, tiling, 668 pixmap->drawable.width, pixmap->drawable.height)); 669 assert(priv->gpu_damage == NULL || priv->gpu_bo); 670 assert(priv->gpu_bo->tiling != tiling); 671 672 if (priv->pinned) { 673 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 674 return NULL; 675 } 676 677 if (wedged(sna)) { 678 DBG(("%s: can't convert bo, wedged\n", __FUNCTION__)); 679 return NULL; 680 } 681 682 assert_pixmap_damage(pixmap); 683 assert(!priv->move_to_gpu); 684 685 bo = kgem_create_2d(&sna->kgem, 686 pixmap->drawable.width, 687 pixmap->drawable.height, 688 pixmap->drawable.bitsPerPixel, 689 tiling, 0); 690 if (bo == NULL) { 691 DBG(("%s: allocation failed\n", __FUNCTION__)); 692 return NULL; 693 } 694 695 if (bo->tiling == priv->gpu_bo->tiling) { 696 DBG(("%s: tiling request failed\n", __FUNCTION__)); 697 kgem_bo_destroy(&sna->kgem, bo); 698 return NULL; 699 } 700 701 box.x1 = box.y1 = 0; 702 box.x2 = pixmap->drawable.width; 703 box.y2 = pixmap->drawable.height; 704 705 if (!sna->render.copy_boxes(sna, GXcopy, 706 &pixmap->drawable, priv->gpu_bo, 0, 0, 707 &pixmap->drawable, bo, 0, 0, 708 &box, 1, 0)) { 709 DBG(("%s: copy failed\n", __FUNCTION__)); 710 kgem_bo_destroy(&sna->kgem, bo); 711 return NULL; 712 } 713 714 sna_pixmap_unmap(pixmap, priv); 715 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 716 717 return priv->gpu_bo = bo; 718} 719 720static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna) 721{ 722 ((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna; 723 assert(sna_pixmap(pixmap) == sna); 724} 725 726static struct sna_pixmap * 727_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) 728{ 729 list_init(&priv->flush_list); 730 list_init(&priv->cow_list); 731 priv->source_count = SOURCE_BIAS; 732 priv->pixmap = pixmap; 733 734 return priv; 735} 736 737static struct sna_pixmap * 738_sna_pixmap_reset(PixmapPtr pixmap) 739{ 740 struct sna_pixmap *priv; 741 742 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 743 assert(pixmap->drawable.class == 0); 744 assert(pixmap->drawable.x == 0); 745 assert(pixmap->drawable.y == 0); 746 747 priv = sna_pixmap(pixmap); 748 assert(priv != NULL); 749 750 memset(priv, 0, sizeof(*priv)); 751 return _sna_pixmap_init(priv, pixmap); 752} 753 754static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) 755{ 756 struct sna_pixmap *priv; 757 758 priv = calloc(1, sizeof(*priv)); 759 if (!priv) 760 return NULL; 761 762 sna_set_pixmap(pixmap, priv); 763 return _sna_pixmap_init(priv, pixmap); 764} 765 766struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) 767{ 768 struct sna_pixmap *priv; 769 770 assert(bo); 771 assert(bo->proxy == NULL); 772 assert(bo->unique_id); 773 774 priv = sna_pixmap_attach(pixmap); 775 if (!priv) 776 return NULL; 777 778 DBG(("%s: attaching %s handle=%d to pixmap=%ld\n", 779 __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber)); 780 781 assert(!priv->mapped); 782 assert(!priv->move_to_gpu); 783 784 if (bo->snoop) { 785 priv->cpu_bo = bo; 786 sna_damage_all(&priv->cpu_damage, pixmap); 787 } else { 788 priv->gpu_bo = bo; 789 sna_damage_all(&priv->gpu_damage, pixmap); 790 } 791 792 return priv; 793} 794 795static int bits_per_pixel(int depth) 796{ 797 switch (depth) { 798 case 1: return 1; 799 case 4: 800 case 8: return 8; 801 case 15: 802 case 16: return 16; 803 case 24: 804 case 30: 805 case 32: return 32; 806 default: return 0; 807 } 808} 809static PixmapPtr 810create_pixmap(struct sna *sna, ScreenPtr screen, 811 int width, int height, int depth, 812 unsigned usage_hint) 813{ 814 PixmapPtr pixmap; 815 size_t datasize; 816 size_t stride; 817 int base, bpp; 818 819 bpp = bits_per_pixel(depth); 820 if (bpp == 0) 821 return NullPixmap; 822 823 stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 824 if (stride / 4 > 32767 || height > 32767) 825 return NullPixmap; 826 827 datasize = height * stride; 828 base = screen->totalPixmapSize; 829 if (datasize && base & 15) { 830 int adjust = 16 - (base & 15); 831 base += adjust; 832 datasize += adjust; 833 } 834 835 DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n", 836 __FUNCTION__, width, height, depth, bpp, (long)datasize)); 837 pixmap = AllocatePixmap(screen, datasize); 838 if (!pixmap) 839 return NullPixmap; 840 841 ((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna; 842 assert(to_sna_from_pixmap(pixmap) == sna); 843 844 pixmap->drawable.type = DRAWABLE_PIXMAP; 845 pixmap->drawable.class = 0; 846 pixmap->drawable.pScreen = screen; 847 pixmap->drawable.depth = depth; 848 pixmap->drawable.bitsPerPixel = bpp; 849 pixmap->drawable.id = 0; 850 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 851 pixmap->drawable.x = 0; 852 pixmap->drawable.y = 0; 853 pixmap->drawable.width = width; 854 pixmap->drawable.height = height; 855 pixmap->devKind = stride; 856 pixmap->refcnt = 1; 857 pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL; 858 859#ifdef COMPOSITE 860 pixmap->screen_x = 0; 861 pixmap->screen_y = 0; 862#endif 863 864 pixmap->usage_hint = usage_hint; 865#if DEBUG_MEMORY 866 sna->debug_memory.pixmap_allocs++; 867#endif 868 869 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 870 __FUNCTION__, 871 pixmap->drawable.serialNumber, 872 pixmap->usage_hint, 873 pixmap->drawable.width, 874 pixmap->drawable.height)); 875 876 return pixmap; 877} 878 879static PixmapPtr 880__pop_freed_pixmap(struct sna *sna) 881{ 882 PixmapPtr pixmap; 883 884 assert(sna->freed_pixmap); 885 886 pixmap = sna->freed_pixmap; 887 sna->freed_pixmap = pixmap->devPrivate.ptr; 888 889 DBG(("%s: reusing freed pixmap=%ld header\n", 890 __FUNCTION__, pixmap->drawable.serialNumber)); 891 892 assert(pixmap->refcnt == 0); 893 assert(pixmap->devKind = 0xdeadbeef); 894 assert(sna_pixmap(pixmap)); 895 assert(sna_pixmap(pixmap)->header); 896 897#if DEBUG_MEMORY 898 sna->debug_memory.pixmap_cached--; 899#endif 900 901 return pixmap; 902} 903 904inline static PixmapPtr 905create_pixmap_hdr(struct sna *sna, ScreenPtr screen, 906 int width, int height, int depth, int usage, 907 struct sna_pixmap **priv) 908{ 909 PixmapPtr pixmap; 910 911 if (sna->freed_pixmap == NULL) { 912 pixmap = create_pixmap(sna, screen, 0, 0, depth, usage); 913 if (pixmap == NullPixmap) 914 return NullPixmap; 915 916 *priv = sna_pixmap_attach(pixmap); 917 if (!*priv) { 918 FreePixmap(pixmap); 919 return NullPixmap; 920 } 921 } else { 922 pixmap = __pop_freed_pixmap(sna); 923 *priv = _sna_pixmap_reset(pixmap); 924 925 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 926 assert(pixmap->drawable.class == 0); 927 assert(pixmap->drawable.pScreen == screen); 928 assert(pixmap->drawable.x == 0); 929 assert(pixmap->drawable.y == 0); 930 931 pixmap->drawable.id = 0; 932 933 pixmap->drawable.depth = depth; 934 pixmap->drawable.bitsPerPixel = bits_per_pixel(depth); 935 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 936 937 pixmap->devKind = 0; 938 pixmap->devPrivate.ptr = NULL; 939 940#ifdef COMPOSITE 941 pixmap->screen_x = 0; 942 pixmap->screen_y = 0; 943#endif 944 945#if DEBUG_MEMORY 946 sna->debug_memory.pixmap_allocs++; 947#endif 948 949 pixmap->refcnt = 1; 950 } 951 952 DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__, 953 pixmap->drawable.serialNumber, width, height, usage)); 954 pixmap->drawable.width = width; 955 pixmap->drawable.height = height; 956 pixmap->usage_hint = usage; 957 958 (*priv)->header = true; 959 return pixmap; 960} 961 962static PixmapPtr 963sna_pixmap_create_shm(ScreenPtr screen, 964 int width, int height, int depth, 965 char *addr) 966{ 967 struct sna *sna = to_sna_from_screen(screen); 968 int bpp = bits_per_pixel(depth); 969 int pitch = PixmapBytePad(width, depth); 970 struct sna_pixmap *priv; 971 PixmapPtr pixmap; 972 973 DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n", 974 __FUNCTION__, width, height, depth, bpp, pitch)); 975 976 if (wedged(sna) || bpp == 0 || pitch*height < 4096) { 977fallback: 978 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 979 if (pixmap == NULL) 980 return NULL; 981 982 if (!screen->ModifyPixmapHeader(pixmap, width, height, depth, 983 bpp, pitch, addr)) { 984 screen->DestroyPixmap(pixmap); 985 return NULL; 986 } 987 988 return pixmap; 989 } 990 991 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv); 992 if (pixmap == NullPixmap) { 993 DBG(("%s: allocation failed\n", __FUNCTION__)); 994 goto fallback; 995 } 996 997 priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false); 998 if (priv->cpu_bo == NULL) { 999 DBG(("%s: mapping SHM segment failed\n", __FUNCTION__)); 1000 sna_pixmap_destroy(pixmap); 1001 goto fallback; 1002 } 1003 priv->cpu_bo->pitch = pitch; 1004 kgem_bo_mark_unreusable(priv->cpu_bo); 1005 sna_shm_watch_flush(sna, 1); 1006#ifdef DEBUG_MEMORY 1007 sna->debug_memory.cpu_bo_allocs++; 1008 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 1009#endif 1010 1011 /* Be wary as we cannot cache SHM Pixmap in our freed cache */ 1012 priv->header = false; 1013 priv->cpu = true; 1014 priv->shm = true; 1015 priv->stride = pitch; 1016 priv->ptr = MAKE_STATIC_PTR(addr); 1017 sna_damage_all(&priv->cpu_damage, pixmap); 1018 1019 pixmap->devKind = pitch; 1020 pixmap->devPrivate.ptr = addr; 1021 1022 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1023 __FUNCTION__, 1024 pixmap->drawable.serialNumber, 1025 pixmap->drawable.width, 1026 pixmap->drawable.height, 1027 pixmap->usage_hint)); 1028 return pixmap; 1029} 1030 1031PixmapPtr 1032sna_pixmap_create_unattached(ScreenPtr screen, 1033 int width, int height, int depth) 1034{ 1035 return create_pixmap(to_sna_from_screen(screen), 1036 screen, width, height, depth, 1037 -1); 1038} 1039 1040static PixmapPtr 1041sna_pixmap_create_scratch(ScreenPtr screen, 1042 int width, int height, int depth, 1043 uint32_t tiling) 1044{ 1045 struct sna *sna = to_sna_from_screen(screen); 1046 struct sna_pixmap *priv; 1047 PixmapPtr pixmap; 1048 int bpp; 1049 1050 DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__, 1051 width, height, depth, tiling)); 1052 1053 bpp = bits_per_pixel(depth); 1054 if (tiling == I915_TILING_Y && 1055 (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0) 1056 tiling = I915_TILING_X; 1057 1058 if (tiling == I915_TILING_Y && 1059 (width > sna->render.max_3d_size || 1060 height > sna->render.max_3d_size)) 1061 tiling = I915_TILING_X; 1062 1063 tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp); 1064 1065 /* you promise never to access this via the cpu... */ 1066 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv); 1067 if (pixmap == NullPixmap) 1068 return NullPixmap; 1069 1070 priv->stride = PixmapBytePad(width, depth); 1071 1072 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1073 width, height, bpp, tiling, 1074 CREATE_TEMPORARY); 1075 if (priv->gpu_bo == NULL) { 1076 free(priv); 1077 FreePixmap(pixmap); 1078 return NullPixmap; 1079 } 1080 1081 sna_damage_all(&priv->gpu_damage, pixmap); 1082 1083 assert(to_sna_from_pixmap(pixmap) == sna); 1084 assert(pixmap->drawable.pScreen == screen); 1085 assert(pixmap->refcnt == 1); 1086 1087 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1088 __FUNCTION__, 1089 pixmap->drawable.serialNumber, 1090 pixmap->drawable.width, 1091 pixmap->drawable.height, 1092 pixmap->usage_hint)); 1093 return pixmap; 1094} 1095 1096static unsigned small_copy(const RegionRec *region) 1097{ 1098 if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) { 1099 DBG(("%s: region:%dx%d\n", __FUNCTION__, 1100 (region->extents.x2 - region->extents.x1), 1101 (region->extents.y2 - region->extents.y1))); 1102 return COPY_SMALL; 1103 } 1104 1105 return 0; 1106} 1107 1108#ifdef CREATE_PIXMAP_USAGE_SHARED 1109static Bool 1110sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle) 1111{ 1112 struct sna *sna = to_sna_from_pixmap(pixmap); 1113 struct sna_pixmap *priv; 1114 int fd; 1115 1116 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1117 1118 priv = sna_pixmap_move_to_gpu(pixmap, 1119 MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE); 1120 if (priv == NULL) 1121 return FALSE; 1122 1123 assert(!priv->shm); 1124 assert(priv->gpu_bo); 1125 assert(priv->stride); 1126 1127 /* XXX negotiate format and stride restrictions */ 1128 if (priv->gpu_bo->tiling != I915_TILING_NONE || 1129 priv->gpu_bo->pitch & 255) { 1130 struct kgem_bo *bo; 1131 BoxRec box; 1132 1133 DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n", 1134 __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch, 1135 pixmap->drawable.width, pixmap->drawable.height, 1136 pixmap->drawable.serialNumber)); 1137 1138 if (priv->pinned) { 1139 DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__, 1140 priv->pinned)); 1141 return FALSE; 1142 } 1143 1144 assert_pixmap_damage(pixmap); 1145 1146 bo = kgem_create_2d(&sna->kgem, 1147 pixmap->drawable.width, 1148 pixmap->drawable.height, 1149 pixmap->drawable.bitsPerPixel, 1150 I915_TILING_NONE, 1151 CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT); 1152 if (bo == NULL) { 1153 DBG(("%s: allocation failed\n", __FUNCTION__)); 1154 return FALSE; 1155 } 1156 1157 box.x1 = box.y1 = 0; 1158 box.x2 = pixmap->drawable.width; 1159 box.y2 = pixmap->drawable.height; 1160 1161 assert(!wedged(sna)); /* XXX */ 1162 if (!sna->render.copy_boxes(sna, GXcopy, 1163 &pixmap->drawable, priv->gpu_bo, 0, 0, 1164 &pixmap->drawable, bo, 0, 0, 1165 &box, 1, 0)) { 1166 DBG(("%s: copy failed\n", __FUNCTION__)); 1167 kgem_bo_destroy(&sna->kgem, bo); 1168 return FALSE; 1169 } 1170 1171 sna_pixmap_unmap(pixmap, priv); 1172 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1173 priv->gpu_bo = bo; 1174 } 1175 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1176 assert((priv->gpu_bo->pitch & 255) == 0); 1177 1178 /* And export the bo->pitch via pixmap->devKind */ 1179 if (!priv->mapped) { 1180 void *ptr; 1181 1182 ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1183 if (ptr == NULL) 1184 return FALSE; 1185 1186 pixmap->devPrivate.ptr = ptr; 1187 pixmap->devKind = priv->gpu_bo->pitch; 1188 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1189 } 1190 assert_pixmap_map(pixmap, priv); 1191 1192 fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo); 1193 if (fd == -1) 1194 return FALSE; 1195 1196 priv->pinned |= PIN_PRIME; 1197 1198 *fd_handle = (void *)(intptr_t)fd; 1199 return TRUE; 1200} 1201 1202static Bool 1203sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle) 1204{ 1205 struct sna *sna = to_sna_from_pixmap(pixmap); 1206 struct sna_pixmap *priv; 1207 struct kgem_bo *bo; 1208 1209 DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n", 1210 __FUNCTION__, pixmap->drawable.serialNumber, 1211 pixmap->drawable.width, pixmap->drawable.height, 1212 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, 1213 pixmap->devKind)); 1214 1215 priv = sna_pixmap(pixmap); 1216 if (priv == NULL) 1217 return FALSE; 1218 1219 if (priv->pinned & ~PIN_PRIME) 1220 return FALSE; 1221 1222 assert(!priv->flush); 1223 1224 if (priv->gpu_bo) { 1225 priv->clear = false; 1226 sna_damage_destroy(&priv->gpu_damage); 1227 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1228 priv->gpu_bo = NULL; 1229 priv->pinned = 0; 1230 } 1231 1232 assert(!priv->pinned); 1233 1234 assert(priv->cpu_bo == NULL); 1235 assert(priv->cpu_damage == NULL); 1236 1237 assert(priv->gpu_bo == NULL); 1238 assert(priv->gpu_damage == NULL); 1239 1240 bo = kgem_create_for_prime(&sna->kgem, 1241 (intptr_t)fd_handle, 1242 pixmap->devKind * pixmap->drawable.height); 1243 if (bo == NULL) 1244 return FALSE; 1245 1246 sna_damage_all(&priv->gpu_damage, pixmap); 1247 1248 bo->pitch = pixmap->devKind; 1249 priv->stride = pixmap->devKind; 1250 1251 assert(!priv->mapped); 1252 priv->gpu_bo = bo; 1253 priv->pinned |= PIN_PRIME; 1254 1255 close((intptr_t)fd_handle); 1256 return TRUE; 1257} 1258 1259static PixmapPtr 1260sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, 1261 int width, int height, int depth) 1262{ 1263 PixmapPtr pixmap; 1264 struct sna_pixmap *priv; 1265 1266 DBG(("%s: width=%d, height=%d, depth=%d\n", 1267 __FUNCTION__, width, height, depth)); 1268 1269 /* Create a stub to be attached later */ 1270 pixmap = create_pixmap_hdr(sna, screen, 1271 width, height, depth, 0, 1272 &priv); 1273 if (pixmap == NullPixmap) 1274 return NullPixmap; 1275 1276 assert(!priv->mapped); 1277 priv->stride = 0; 1278 priv->create = 0; 1279 1280 if (width|height) { 1281 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1282 width, height, 1283 pixmap->drawable.bitsPerPixel, 1284 I915_TILING_NONE, 1285 CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT); 1286 if (priv->gpu_bo == NULL) { 1287 free(priv); 1288 FreePixmap(pixmap); 1289 return NullPixmap; 1290 } 1291 1292 /* minimal interface for sharing is linear, 256 byte pitch */ 1293 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1294 assert((priv->gpu_bo->pitch & 255) == 0); 1295 1296 pixmap->devPrivate.ptr = 1297 kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1298 if (pixmap->devPrivate.ptr == NULL) { 1299 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1300 free(priv); 1301 FreePixmap(pixmap); 1302 return FALSE; 1303 } 1304 1305 pixmap->devKind = priv->gpu_bo->pitch; 1306 1307 priv->stride = priv->gpu_bo->pitch; 1308 priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1309 assert_pixmap_map(pixmap, priv); 1310 1311 sna_damage_all(&priv->gpu_damage, pixmap); 1312 } 1313 1314 return pixmap; 1315} 1316#endif 1317 1318static PixmapPtr sna_create_pixmap(ScreenPtr screen, 1319 int width, int height, int depth, 1320 unsigned int usage) 1321{ 1322 struct sna *sna = to_sna_from_screen(screen); 1323 PixmapPtr pixmap; 1324 struct sna_pixmap *priv; 1325 unsigned flags; 1326 int pad; 1327 void *ptr; 1328 1329 DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__, 1330 width, height, depth, usage)); 1331 1332#ifdef CREATE_PIXMAP_USAGE_SHARED 1333 if (usage == CREATE_PIXMAP_USAGE_SHARED) 1334 return sna_create_pixmap_shared(sna, screen, 1335 width, height, depth); 1336#endif 1337 1338 if ((width|height) == 0) { 1339 usage = -1; 1340 goto fallback; 1341 } 1342 assert(width && height); 1343 1344 flags = kgem_can_create_2d(&sna->kgem, width, height, depth); 1345 if (flags == 0) { 1346 DBG(("%s: can not use GPU, just creating shadow\n", 1347 __FUNCTION__)); 1348 goto fallback; 1349 } 1350 1351 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)) 1352 flags &= ~KGEM_CAN_CREATE_GPU; 1353 if (wedged(sna) && usage != SNA_CREATE_FB) 1354 flags &= ~KGEM_CAN_CREATE_GTT; 1355 1356 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags)); 1357 switch (usage) { 1358 case CREATE_PIXMAP_USAGE_SCRATCH: 1359 if (flags & KGEM_CAN_CREATE_GPU) 1360 return sna_pixmap_create_scratch(screen, 1361 width, height, depth, 1362 I915_TILING_X); 1363 else 1364 goto fallback; 1365 1366 case SNA_CREATE_SCRATCH: 1367 if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU)) 1368 return sna_pixmap_create_scratch(screen, 1369 width, height, depth, 1370 I915_TILING_Y); 1371 else 1372 return NullPixmap; 1373 } 1374 1375 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) 1376 flags &= ~KGEM_CAN_CREATE_GPU; 1377 if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 1378 usage = 0; 1379 1380 pad = PixmapBytePad(width, depth); 1381 if (pad * height < 4096) { 1382 DBG(("%s: small buffer [%d], attaching to shadow pixmap\n", 1383 __FUNCTION__, pad * height)); 1384 pixmap = create_pixmap(sna, screen, 1385 width, height, depth, usage); 1386 if (pixmap == NullPixmap) 1387 return NullPixmap; 1388 1389 ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 1390 pad = pixmap->devKind; 1391 flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU); 1392 1393 priv = sna_pixmap_attach(pixmap); 1394 if (priv == NULL) { 1395 free(pixmap); 1396 goto fallback; 1397 } 1398 } else { 1399 DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n", 1400 __FUNCTION__, width, height, pad, flags)); 1401 1402 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv); 1403 if (pixmap == NullPixmap) 1404 return NullPixmap; 1405 1406 ptr = NULL; 1407 } 1408 1409 priv->stride = pad; 1410 priv->create = flags; 1411 priv->ptr = ptr; 1412 1413 assert(to_sna_from_pixmap(pixmap) == sna); 1414 assert(pixmap->drawable.pScreen == screen); 1415 assert(pixmap->refcnt == 1); 1416 1417 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1418 __FUNCTION__, 1419 pixmap->drawable.serialNumber, 1420 pixmap->drawable.width, 1421 pixmap->drawable.height, 1422 pixmap->usage_hint)); 1423 return pixmap; 1424 1425fallback: 1426 return create_pixmap(sna, screen, width, height, depth, usage); 1427} 1428 1429void sna_add_flush_pixmap(struct sna *sna, 1430 struct sna_pixmap *priv, 1431 struct kgem_bo *bo) 1432{ 1433 DBG(("%s: marking pixmap=%ld for flushing\n", 1434 __FUNCTION__, priv->pixmap->drawable.serialNumber)); 1435 assert(bo); 1436 assert(bo->flush); 1437 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1438 list_move(&priv->flush_list, &sna->flush_pixmaps); 1439 1440 if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) { 1441 DBG(("%s: new flush bo, flushing before\n", __FUNCTION__)); 1442 _kgem_submit(&sna->kgem); 1443 } 1444} 1445 1446static void __sna_free_pixmap(struct sna *sna, 1447 PixmapPtr pixmap, 1448 struct sna_pixmap *priv) 1449{ 1450 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1451 list_del(&priv->flush_list); 1452 1453 assert(priv->gpu_damage == NULL); 1454 assert(priv->cpu_damage == NULL); 1455 1456 __sna_pixmap_free_cpu(sna, priv); 1457 1458 if (priv->flush) 1459 sna_watch_flush(sna, -1); 1460 1461#if !NDEBUG 1462 pixmap->devKind = 0xdeadbeef; 1463#endif 1464 if (priv->header) { 1465 assert(pixmap->drawable.pScreen == to_screen_from_sna(sna)); 1466 assert(!priv->shm); 1467 pixmap->devPrivate.ptr = sna->freed_pixmap; 1468 sna->freed_pixmap = pixmap; 1469#if DEBUG_MEMORY 1470 sna->debug_memory.pixmap_cached++; 1471#endif 1472 } else { 1473 free(priv); 1474 FreePixmap(pixmap); 1475 } 1476} 1477 1478static Bool sna_destroy_pixmap(PixmapPtr pixmap) 1479{ 1480 struct sna *sna; 1481 struct sna_pixmap *priv; 1482 1483 assert(pixmap->refcnt > 0); 1484 if (--pixmap->refcnt) 1485 return TRUE; 1486 1487#if DEBUG_MEMORY 1488 to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--; 1489#endif 1490 1491 priv = sna_pixmap(pixmap); 1492 DBG(("%s: pixmap=%ld, attached?=%d\n", 1493 __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL)); 1494 if (priv == NULL) { 1495 FreePixmap(pixmap); 1496 return TRUE; 1497 } 1498 1499 assert_pixmap_damage(pixmap); 1500 sna = to_sna_from_pixmap(pixmap); 1501 1502 sna_damage_destroy(&priv->gpu_damage); 1503 sna_damage_destroy(&priv->cpu_damage); 1504 1505 list_del(&priv->cow_list); 1506 if (priv->cow) { 1507 struct sna_cow *cow = COW(priv->cow); 1508 DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", 1509 __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); 1510 assert(cow->refcnt); 1511 if (!--cow->refcnt) 1512 free(cow); 1513 priv->cow = NULL; 1514 } else 1515 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1516 1517 if (priv->move_to_gpu) 1518 (void)priv->move_to_gpu(sna, priv, 0); 1519 1520 /* Always release the gpu bo back to the lower levels of caching */ 1521 if (priv->gpu_bo) { 1522 sna_pixmap_unmap(pixmap, priv); 1523 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1524 priv->gpu_bo = NULL; 1525 } 1526 1527 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { 1528 DBG(("%s: deferring release of active SHM pixmap=%ld\n", 1529 __FUNCTION__, pixmap->drawable.serialNumber)); 1530 add_shm_flush(sna, priv); 1531 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ 1532 } else 1533 __sna_free_pixmap(sna, pixmap, priv); 1534 return TRUE; 1535} 1536 1537void sna_pixmap_destroy(PixmapPtr pixmap) 1538{ 1539 assert(pixmap->refcnt == 1); 1540 assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true); 1541 1542 sna_destroy_pixmap(pixmap); 1543} 1544 1545static inline bool has_coherent_map(struct sna *sna, 1546 struct kgem_bo *bo, 1547 unsigned flags) 1548{ 1549 assert(bo); 1550 1551 if (kgem_bo_mapped(&sna->kgem, bo)) 1552 return true; 1553 1554 if (bo->tiling == I915_TILING_Y) 1555 return false; 1556 1557 return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE); 1558} 1559 1560static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1561{ 1562 if (priv == NULL) 1563 return true; 1564 1565 if (flags & MOVE_ASYNC_HINT) { 1566 /* Not referencing the pointer itself, so do not care */ 1567 return true; 1568 } 1569 1570 if (!priv->mapped) { 1571 if (!priv->cpu_bo) 1572 return true; 1573 1574 assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0); 1575 assert(priv->pixmap->devKind == priv->cpu_bo->pitch); 1576 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu); 1577 } 1578 1579 assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0); 1580 1581 assert_pixmap_map(priv->pixmap, priv); 1582 assert(priv->pixmap->devKind == priv->gpu_bo->pitch); 1583 1584 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) { 1585 assert(priv->mapped == MAPPED_CPU); 1586 1587 if (priv->gpu_bo->tiling != I915_TILING_NONE) 1588 return false; 1589 1590 return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE); 1591 } 1592 1593 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) { 1594 assert(priv->mapped == MAPPED_GTT); 1595 1596 if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21) 1597 return false; 1598 1599 return true; 1600 } 1601 1602 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) { 1603 assert(priv->mapped == MAPPED_GTT); 1604 return true; 1605 } 1606 1607 return false; 1608} 1609 1610static inline bool pixmap_inplace(struct sna *sna, 1611 PixmapPtr pixmap, 1612 struct sna_pixmap *priv, 1613 unsigned flags) 1614{ 1615 if (FORCE_INPLACE) 1616 return FORCE_INPLACE > 0; 1617 1618 if (wedged(sna) && !priv->pinned) { 1619 DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__)); 1620 return false; 1621 } 1622 1623 if (priv->move_to_gpu && flags & MOVE_WRITE) 1624 return false; 1625 1626 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 1627 if (priv->clear) { 1628 DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__)); 1629 return false; 1630 } 1631 1632 if (flags & MOVE_ASYNC_HINT) { 1633 DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__)); 1634 return false; 1635 } 1636 1637 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) { 1638 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__)); 1639 return false; 1640 } 1641 1642 if ((flags & MOVE_READ) == 0) { 1643 DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes")); 1644 return !priv->pinned; 1645 } 1646 } 1647 1648 if (priv->mapped) { 1649 DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 1650 return has_coherent_map(sna, priv->gpu_bo, flags); 1651 } 1652 1653 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 1654 DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__)); 1655 return true; 1656 } 1657 1658 if (priv->cpu_bo && priv->cpu) { 1659 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 1660 return false; 1661 } 1662 1663 if (flags & MOVE_READ && 1664 (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) { 1665 DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__)); 1666 return false; 1667 } 1668 1669 return (priv->stride * pixmap->drawable.height >> 12) > 1670 sna->kgem.half_cpu_cache_pages; 1671} 1672 1673static bool sna_pixmap_alloc_gpu(struct sna *sna, 1674 PixmapPtr pixmap, 1675 struct sna_pixmap *priv, 1676 unsigned flags) 1677{ 1678 uint32_t tiling; 1679 1680 /* Use tiling by default, but disable per user request */ 1681 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) { 1682 flags |= CREATE_SCANOUT; 1683 tiling = kgem_choose_tiling(&sna->kgem, 1684 -DEFAULT_SCANOUT_TILING, 1685 pixmap->drawable.width, 1686 pixmap->drawable.height, 1687 pixmap->drawable.bitsPerPixel); 1688 } else 1689 tiling = sna_pixmap_default_tiling(sna, pixmap); 1690 1691 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1692 1693 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1694 pixmap->drawable.width, 1695 pixmap->drawable.height, 1696 pixmap->drawable.bitsPerPixel, 1697 tiling, flags); 1698 return priv->gpu_bo != NULL; 1699} 1700 1701static bool 1702sna_pixmap_create_mappable_gpu(PixmapPtr pixmap, 1703 bool can_replace) 1704{ 1705 struct sna *sna = to_sna_from_pixmap(pixmap); 1706 struct sna_pixmap *priv = sna_pixmap(pixmap); 1707 1708 if (wedged(sna)) 1709 goto out; 1710 1711 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) 1712 goto out; 1713 1714 assert_pixmap_damage(pixmap); 1715 1716 if (can_replace && priv->gpu_bo && 1717 (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) || 1718 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1719 if (priv->pinned) 1720 return false; 1721 1722 DBG(("%s: discard busy GPU bo\n", __FUNCTION__)); 1723 sna_pixmap_free_gpu(sna, priv); 1724 } 1725 1726 if (priv->gpu_bo == NULL) { 1727 assert_pixmap_damage(pixmap); 1728 assert(priv->gpu_damage == NULL); 1729 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE); 1730 } 1731 1732out: 1733 if (priv->gpu_bo == NULL) 1734 return false; 1735 1736 return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1737 !kgem_bo_is_busy(priv->gpu_bo)); 1738} 1739 1740static inline bool gpu_bo_download(struct sna *sna, 1741 struct sna_pixmap *priv, 1742 int n, const BoxRec *box, 1743 bool idle) 1744{ 1745 char *src; 1746 1747 if (!USE_INPLACE) 1748 return false; 1749 1750 switch (priv->gpu_bo->tiling) { 1751 case I915_TILING_Y: 1752 return false; 1753 case I915_TILING_X: 1754 if (!sna->kgem.memcpy_from_tiled_x) 1755 return false; 1756 default: 1757 break; 1758 } 1759 1760 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 1761 return false; 1762 1763 if (idle) { 1764 if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 1765 return false; 1766 1767 if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) 1768 return false; 1769 } 1770 1771 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 1772 if (src == NULL) 1773 return false; 1774 1775 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 1776 1777 if (priv->cpu_bo) 1778 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1779 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1780 1781 if (sigtrap_get()) 1782 return false; 1783 1784 if (priv->gpu_bo->tiling) { 1785 int bpp = priv->pixmap->drawable.bitsPerPixel; 1786 void *dst = priv->pixmap->devPrivate.ptr; 1787 int dst_pitch = priv->pixmap->devKind; 1788 1789 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 1790 do { 1791 DBG(("%s: box (%d, %d), (%d, %d)\n", 1792 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1793 memcpy_from_tiled_x(&sna->kgem, src, dst, bpp, 1794 priv->gpu_bo->pitch, dst_pitch, 1795 box->x1, box->y1, 1796 box->x1, box->y1, 1797 box->x2 - box->x1, box->y2 - box->y1); 1798 box++; 1799 } while (--n); 1800 } else { 1801 int bpp = priv->pixmap->drawable.bitsPerPixel; 1802 void *dst = priv->pixmap->devPrivate.ptr; 1803 int dst_pitch = priv->pixmap->devKind; 1804 1805 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 1806 do { 1807 DBG(("%s: box (%d, %d), (%d, %d)\n", 1808 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1809 memcpy_blt(src, dst, bpp, 1810 priv->gpu_bo->pitch, dst_pitch, 1811 box->x1, box->y1, 1812 box->x1, box->y1, 1813 box->x2 - box->x1, box->y2 - box->y1); 1814 box++; 1815 } while (--n); 1816 } 1817 1818 sigtrap_put(); 1819 return true; 1820} 1821 1822static inline bool cpu_bo_download(struct sna *sna, 1823 struct sna_pixmap *priv, 1824 int n, const BoxRec *box) 1825{ 1826 if (DBG_NO_CPU_DOWNLOAD) 1827 return false; 1828 1829 if (wedged(sna)) 1830 return false; 1831 1832 if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu) 1833 return false; 1834 1835 if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) { 1836 /* Is it worth detiling? */ 1837 assert(box[0].y1 < box[n-1].y2); 1838 if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1839 (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) { 1840 DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n", 1841 __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch)); 1842 return false; 1843 } 1844 } 1845 1846 DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__)); 1847 return sna->render.copy_boxes(sna, GXcopy, 1848 &priv->pixmap->drawable, priv->gpu_bo, 0, 0, 1849 &priv->pixmap->drawable, priv->cpu_bo, 0, 0, 1850 box, n, COPY_LAST); 1851} 1852 1853static void download_boxes(struct sna *sna, 1854 struct sna_pixmap *priv, 1855 int n, const BoxRec *box) 1856{ 1857 bool ok; 1858 1859 DBG(("%s: nbox=%d\n", __FUNCTION__, n)); 1860 1861 ok = gpu_bo_download(sna, priv, n, box, true); 1862 if (!ok) 1863 ok = cpu_bo_download(sna, priv, n, box); 1864 if (!ok) 1865 ok = gpu_bo_download(sna, priv, n, box, false); 1866 if (!ok) { 1867 if (priv->cpu_bo) 1868 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1869 assert(priv->mapped == MAPPED_NONE); 1870 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1871 sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n); 1872 } 1873} 1874 1875static inline bool use_cpu_bo_for_upload(struct sna *sna, 1876 struct sna_pixmap *priv, 1877 unsigned flags) 1878{ 1879 if (DBG_NO_CPU_UPLOAD) 1880 return false; 1881 1882 if (wedged(sna)) 1883 return false; 1884 1885 if (priv->cpu_bo == NULL) 1886 return false; 1887 1888 DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__, 1889 flags, 1890 kgem_bo_is_busy(priv->gpu_bo), 1891 kgem_bo_is_busy(priv->cpu_bo))); 1892 1893 if (!priv->cpu) 1894 return true; 1895 1896 if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) 1897 return true; 1898 1899 if (priv->gpu_bo->tiling) 1900 return true; 1901 1902 return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo); 1903} 1904 1905bool 1906sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1907{ 1908 struct sna_cow *cow = COW(priv->cow); 1909 1910 DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n", 1911 __FUNCTION__, 1912 priv->pixmap->drawable.serialNumber, 1913 priv->gpu_bo->handle, 1914 priv->gpu_bo->refcnt, 1915 cow->refcnt, 1916 flags)); 1917 1918 assert(priv->gpu_bo == cow->bo); 1919 assert(cow->refcnt); 1920 1921 if (flags && /* flags == 0 => force decouple */ 1922 (flags & MOVE_WRITE) == 0 && 1923 (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow))) 1924 return true; 1925 1926 if (!IS_COW_OWNER(priv->cow)) 1927 list_del(&priv->cow_list); 1928 1929 if (!--cow->refcnt) { 1930 DBG(("%s: freeing cow\n", __FUNCTION__)); 1931 assert(list_is_empty(&cow->list)); 1932 free(cow); 1933 } else if (IS_COW_OWNER(priv->cow) && priv->pinned) { 1934 PixmapPtr pixmap = priv->pixmap; 1935 struct kgem_bo *bo; 1936 BoxRec box; 1937 1938 DBG(("%s: copying the Holy cow\n", __FUNCTION__)); 1939 1940 box.x1 = box.y1 = 0; 1941 box.x2 = pixmap->drawable.width; 1942 box.y2 = pixmap->drawable.height; 1943 1944 bo = kgem_create_2d(&sna->kgem, 1945 box.x2, box.y2, 1946 pixmap->drawable.bitsPerPixel, 1947 sna_pixmap_default_tiling(sna, pixmap), 1948 0); 1949 if (bo == NULL) { 1950 cow->refcnt++; 1951 DBG(("%s: allocation failed\n", __FUNCTION__)); 1952 return false; 1953 } 1954 1955 if (!sna->render.copy_boxes(sna, GXcopy, 1956 &pixmap->drawable, priv->gpu_bo, 0, 0, 1957 &pixmap->drawable, bo, 0, 0, 1958 &box, 1, 0)) { 1959 DBG(("%s: copy failed\n", __FUNCTION__)); 1960 kgem_bo_destroy(&sna->kgem, bo); 1961 cow->refcnt++; 1962 return false; 1963 } 1964 1965 assert(!list_is_empty(&cow->list)); 1966 while (!list_is_empty(&cow->list)) { 1967 struct sna_pixmap *clone; 1968 1969 clone = list_first_entry(&cow->list, 1970 struct sna_pixmap, cow_list); 1971 list_del(&clone->cow_list); 1972 1973 assert(clone->gpu_bo == cow->bo); 1974 sna_pixmap_unmap(clone->pixmap, clone); 1975 kgem_bo_destroy(&sna->kgem, clone->gpu_bo); 1976 clone->gpu_bo = kgem_bo_reference(bo); 1977 } 1978 cow->bo = bo; 1979 kgem_bo_destroy(&sna->kgem, bo); 1980 } else { 1981 struct kgem_bo *bo = NULL; 1982 1983 if (flags & MOVE_READ) { 1984 PixmapPtr pixmap = priv->pixmap; 1985 unsigned create, tiling; 1986 BoxRec box; 1987 1988 DBG(("%s: copying cow\n", __FUNCTION__)); 1989 1990 box.x1 = box.y1 = 0; 1991 box.x2 = pixmap->drawable.width; 1992 box.y2 = pixmap->drawable.height; 1993 1994 if (flags & __MOVE_PRIME) { 1995 create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT; 1996 tiling = I915_TILING_NONE; 1997 } else { 1998 create = 0; 1999 tiling = sna_pixmap_default_tiling(sna, pixmap); 2000 } 2001 2002 bo = kgem_create_2d(&sna->kgem, 2003 box.x2, box.y2, 2004 pixmap->drawable.bitsPerPixel, 2005 tiling, create); 2006 if (bo == NULL) { 2007 cow->refcnt++; 2008 DBG(("%s: allocation failed\n", __FUNCTION__)); 2009 return false; 2010 } 2011 2012 if (!sna->render.copy_boxes(sna, GXcopy, 2013 &pixmap->drawable, priv->gpu_bo, 0, 0, 2014 &pixmap->drawable, bo, 0, 0, 2015 &box, 1, 0)) { 2016 DBG(("%s: copy failed\n", __FUNCTION__)); 2017 kgem_bo_destroy(&sna->kgem, bo); 2018 cow->refcnt++; 2019 return false; 2020 } 2021 } 2022 2023 assert(priv->gpu_bo); 2024 sna_pixmap_unmap(priv->pixmap, priv); 2025 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2026 priv->gpu_bo = bo; 2027 } 2028 2029 priv->cow = NULL; 2030 return true; 2031} 2032 2033static bool 2034sna_pixmap_make_cow(struct sna *sna, 2035 struct sna_pixmap *src_priv, 2036 struct sna_pixmap *dst_priv) 2037{ 2038 struct sna_cow *cow; 2039 2040 assert(src_priv->gpu_bo); 2041 2042 if (!USE_COW) 2043 return false; 2044 2045 if (src_priv->gpu_bo->proxy) 2046 return false; 2047 2048 DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n", 2049 __FUNCTION__, 2050 src_priv->pixmap->drawable.serialNumber, 2051 dst_priv->pixmap->drawable.serialNumber, 2052 src_priv->gpu_bo->handle, 2053 src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0, 2054 dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0)); 2055 2056 if (dst_priv->pinned) { 2057 DBG(("%s: can't cow, dst_pinned=%x\n", 2058 __FUNCTION__, dst_priv->pinned)); 2059 return false; 2060 } 2061 2062 assert(dst_priv->move_to_gpu == NULL); 2063 assert(!dst_priv->flush); 2064 assert(list_is_empty(&dst_priv->cow_list)); 2065 2066 cow = COW(src_priv->cow); 2067 if (cow == NULL) { 2068 cow = malloc(sizeof(*cow)); 2069 if (cow == NULL) 2070 return false; 2071 2072 list_init(&cow->list); 2073 2074 cow->bo = src_priv->gpu_bo; 2075 cow->refcnt = 1; 2076 2077 DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n", 2078 __FUNCTION__, 2079 src_priv->pixmap->drawable.serialNumber, 2080 cow->bo->handle)); 2081 2082 src_priv->cow = MAKE_COW_OWNER(cow); 2083 if (src_priv->flush & FLUSH_WRITE) { 2084 assert(!src_priv->shm); 2085 sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo); 2086 } 2087 } 2088 2089 if (cow == COW(dst_priv->cow)) { 2090 assert(dst_priv->gpu_bo == cow->bo); 2091 return true; 2092 } 2093 2094 if (dst_priv->cow) 2095 sna_pixmap_undo_cow(sna, dst_priv, 0); 2096 2097 if (dst_priv->gpu_bo) { 2098 sna_pixmap_unmap(dst_priv->pixmap, dst_priv); 2099 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 2100 } 2101 assert(!dst_priv->mapped); 2102 dst_priv->gpu_bo = kgem_bo_reference(cow->bo); 2103 dst_priv->cow = cow; 2104 list_add(&dst_priv->cow_list, &cow->list); 2105 cow->refcnt++; 2106 2107 DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n", 2108 __FUNCTION__, 2109 dst_priv->pixmap->drawable.serialNumber, 2110 src_priv->pixmap->drawable.serialNumber, 2111 cow->bo->handle)); 2112 2113 return true; 2114} 2115 2116static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags) 2117{ 2118 if (!USE_INPLACE) 2119 return false; 2120 2121 if ((flags & MOVE_INPLACE_HINT) == 0) { 2122 DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__)); 2123 return false; 2124 } 2125 2126 assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE)); 2127 2128 if (priv->move_to_gpu && flags & MOVE_WRITE) { 2129 DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__)); 2130 return false; 2131 } 2132 2133 if (priv->cow && flags & MOVE_WRITE) { 2134 DBG(("%s: no, has COW\n", __FUNCTION__)); 2135 return false; 2136 } 2137 2138 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) { 2139 DBG(("%s: no, not accessible via GTT\n", __FUNCTION__)); 2140 return false; 2141 } 2142 2143 if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) { 2144 DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__)); 2145 return false; 2146 } 2147 2148 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 2149 DBG(("%s: yes, CPU is busy\n", __FUNCTION__)); 2150 return true; 2151 } 2152 2153 if (priv->create & KGEM_CAN_CREATE_LARGE) { 2154 DBG(("%s: large object, has GPU? %d\n", 2155 __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0)); 2156 return priv->gpu_bo != NULL; 2157 } 2158 2159 if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) { 2160 DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__)); 2161 return false; 2162 } 2163 2164 return true; 2165} 2166 2167bool 2168_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) 2169{ 2170 struct sna *sna = to_sna_from_pixmap(pixmap); 2171 struct sna_pixmap *priv; 2172 2173 DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__, 2174 pixmap->drawable.serialNumber, 2175 pixmap->drawable.width, 2176 pixmap->drawable.height, 2177 flags)); 2178 2179 assert(flags & (MOVE_READ | MOVE_WRITE)); 2180 assert_pixmap_damage(pixmap); 2181 2182 priv = sna_pixmap(pixmap); 2183 if (priv == NULL) { 2184 DBG(("%s: not attached\n", __FUNCTION__)); 2185 return true; 2186 } 2187 2188 DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n", 2189 __FUNCTION__, 2190 priv->gpu_bo ? priv->gpu_bo->handle : 0, 2191 priv->gpu_damage, priv->cpu_damage, priv->clear)); 2192 2193 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2194 2195 if ((flags & MOVE_READ) == 0 && UNDO) { 2196 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 2197 if (priv->move_to_gpu) 2198 sna_pixmap_discard_shadow_damage(priv, NULL); 2199 } 2200 2201 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2202 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2203 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2204 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2205 goto skip; 2206 } 2207 2208 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2209 assert(priv->gpu_damage == NULL); 2210 assert(!priv->pinned); 2211 assert(!priv->mapped); 2212 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2213 priv->gpu_bo = NULL; 2214 } 2215 2216 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 2217 DBG(("%s: CPU all-damaged\n", __FUNCTION__)); 2218 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); 2219 assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0); 2220 goto done; 2221 } 2222 2223 if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) { 2224 assert(flags & MOVE_WRITE); 2225 DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n", 2226 __FUNCTION__, priv->gpu_damage != NULL, priv->clear)); 2227 2228 if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) && 2229 pixmap_inplace(sna, pixmap, priv, flags) && 2230 sna_pixmap_create_mappable_gpu(pixmap, true)) { 2231 void *ptr; 2232 2233 DBG(("%s: write inplace\n", __FUNCTION__)); 2234 assert(!priv->shm); 2235 assert(priv->cow == NULL); 2236 assert(priv->move_to_gpu == NULL); 2237 assert(priv->gpu_bo->exec == NULL); 2238 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2239 2240 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2241 if (ptr == NULL) 2242 goto skip_inplace_map; 2243 2244 pixmap->devPrivate.ptr = ptr; 2245 pixmap->devKind = priv->gpu_bo->pitch; 2246 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2247 assert(has_coherent_ptr(sna, priv, flags)); 2248 2249 assert(priv->gpu_bo->proxy == NULL); 2250 sna_damage_all(&priv->gpu_damage, pixmap); 2251 sna_damage_destroy(&priv->cpu_damage); 2252 priv->clear = false; 2253 list_del(&priv->flush_list); 2254 2255 assert(!priv->shm); 2256 assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush); 2257 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2258 priv->cpu &= priv->mapped == MAPPED_CPU; 2259 2260 assert_pixmap_damage(pixmap); 2261 return true; 2262 } 2263 2264skip_inplace_map: 2265 sna_damage_destroy(&priv->gpu_damage); 2266 priv->clear = false; 2267 if ((flags & MOVE_ASYNC_HINT) == 0 && 2268 priv->cpu_bo && !priv->cpu_bo->flush && 2269 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2270 DBG(("%s: discarding busy CPU bo\n", __FUNCTION__)); 2271 assert(!priv->shm); 2272 assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL); 2273 2274 sna_damage_destroy(&priv->cpu_damage); 2275 sna_pixmap_free_cpu(sna, priv, false); 2276 2277 assert(priv->mapped == MAPPED_NONE); 2278 if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0)) 2279 return false; 2280 assert(priv->mapped == MAPPED_NONE); 2281 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2282 2283 goto mark_damage; 2284 } 2285 } 2286 2287 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2288 2289 if (operate_inplace(priv, flags) && 2290 pixmap_inplace(sna, pixmap, priv, flags) && 2291 sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) { 2292 void *ptr; 2293 2294 DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__)); 2295 assert(priv->gpu_bo); 2296 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2297 assert(!priv->move_to_gpu); 2298 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2299 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2300 /* XXX only sync for writes? */ 2301 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2302 assert(priv->gpu_bo->exec == NULL); 2303 2304 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2305 if (ptr != NULL) { 2306 pixmap->devPrivate.ptr = ptr; 2307 pixmap->devKind = priv->gpu_bo->pitch; 2308 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2309 assert(has_coherent_ptr(sna, priv, flags)); 2310 2311 if (flags & MOVE_WRITE) { 2312 assert(priv->gpu_bo->proxy == NULL); 2313 sna_damage_all(&priv->gpu_damage, pixmap); 2314 sna_damage_destroy(&priv->cpu_damage); 2315 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2316 list_del(&priv->flush_list); 2317 priv->clear = false; 2318 } 2319 priv->cpu &= priv->mapped == MAPPED_CPU; 2320 2321 assert_pixmap_damage(pixmap); 2322 DBG(("%s: operate inplace (GTT)\n", __FUNCTION__)); 2323 return true; 2324 } 2325 } 2326 2327 sna_pixmap_unmap(pixmap, priv); 2328 2329 if (USE_INPLACE && 2330 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL && 2331 priv->gpu_bo->tiling == I915_TILING_NONE && 2332 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) && 2333 (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) && 2334 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2335 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) { 2336 void *ptr; 2337 2338 DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__)); 2339 assert(priv->gpu_bo); 2340 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2341 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2342 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2343 2344 assert(!priv->mapped); 2345 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 2346 2347 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2348 if (ptr != NULL) { 2349 pixmap->devPrivate.ptr = ptr; 2350 pixmap->devKind = priv->gpu_bo->pitch; 2351 priv->mapped = MAPPED_CPU; 2352 assert(has_coherent_ptr(sna, priv, flags)); 2353 2354 if (flags & MOVE_WRITE) { 2355 assert(priv->gpu_bo->proxy == NULL); 2356 sna_damage_all(&priv->gpu_damage, pixmap); 2357 sna_damage_destroy(&priv->cpu_damage); 2358 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2359 list_del(&priv->flush_list); 2360 priv->clear = false; 2361 priv->cpu = true; 2362 } 2363 2364 assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)); 2365 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2366 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2367 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2368 assert_pixmap_damage(pixmap); 2369 assert(has_coherent_ptr(sna, priv, flags)); 2370 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2371 return true; 2372 } 2373 } 2374 2375 assert(priv->mapped == MAPPED_NONE); 2376 if (((flags & MOVE_READ) == 0 || priv->clear) && 2377 priv->cpu_bo && !priv->cpu_bo->flush && 2378 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2379 assert(!priv->shm); 2380 sna_pixmap_free_cpu(sna, priv, false); 2381 } 2382 2383 assert(priv->mapped == MAPPED_NONE); 2384 if (pixmap->devPrivate.ptr == NULL && 2385 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2386 return false; 2387 assert(priv->mapped == MAPPED_NONE); 2388 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2389 2390 if (flags & MOVE_READ) { 2391 if (priv->clear) { 2392 DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n", 2393 __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height, 2394 pixmap->devKind, pixmap->devKind * pixmap->drawable.height)); 2395 2396 if (priv->cpu_bo) { 2397 kgem_bo_undo(&sna->kgem, priv->cpu_bo); 2398 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2399 sna->kgem.can_blt_cpu && 2400 sna->render.fill_one(sna, 2401 pixmap, priv->cpu_bo, priv->clear_color, 2402 0, 0, 2403 pixmap->drawable.width, 2404 pixmap->drawable.height, 2405 GXcopy)) 2406 goto clear_done; 2407 2408 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2409 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2410 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2411 } 2412 2413 if (sigtrap_get() == 0) { 2414 assert(pixmap->devKind); 2415 sigtrap_assert_active(); 2416 if (priv->clear_color == 0 || 2417 pixmap->drawable.bitsPerPixel == 8 || 2418 priv->clear_color == (1 << pixmap->drawable.depth) - 1) { 2419 memset(pixmap->devPrivate.ptr, priv->clear_color, 2420 (size_t)pixmap->devKind * pixmap->drawable.height); 2421 } else { 2422 pixman_fill(pixmap->devPrivate.ptr, 2423 pixmap->devKind/sizeof(uint32_t), 2424 pixmap->drawable.bitsPerPixel, 2425 0, 0, 2426 pixmap->drawable.width, 2427 pixmap->drawable.height, 2428 priv->clear_color); 2429 } 2430 sigtrap_put(); 2431 } else 2432 return false; 2433 2434clear_done: 2435 sna_damage_all(&priv->cpu_damage, pixmap); 2436 sna_pixmap_free_gpu(sna, priv); 2437 assert(priv->gpu_damage == NULL); 2438 assert(priv->clear == false); 2439 } 2440 2441 if (priv->gpu_damage) { 2442 const BoxRec *box; 2443 int n; 2444 2445 DBG(("%s: flushing GPU damage\n", __FUNCTION__)); 2446 assert(priv->gpu_bo); 2447 2448 n = sna_damage_get_boxes(priv->gpu_damage, &box); 2449 if (n) { 2450 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) { 2451 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2452 return false; 2453 } 2454 2455 download_boxes(sna, priv, n, box); 2456 } 2457 2458 __sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage)); 2459 priv->gpu_damage = NULL; 2460 } 2461 } 2462 2463 if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) { 2464mark_damage: 2465 DBG(("%s: marking as damaged\n", __FUNCTION__)); 2466 sna_damage_all(&priv->cpu_damage, pixmap); 2467 sna_pixmap_free_gpu(sna, priv); 2468 assert(priv->gpu_damage == NULL); 2469 assert(priv->clear == false); 2470 2471 if (priv->flush) { 2472 assert(!priv->shm); 2473 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2474 } 2475 } 2476 2477done: 2478 if (flags & MOVE_WRITE) { 2479 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2480 assert(priv->gpu_damage == NULL); 2481 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2482 if (priv->cow) 2483 sna_pixmap_undo_cow(sna, priv, 0); 2484 if (priv->gpu_bo && priv->gpu_bo->rq == NULL) { 2485 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__)); 2486 sna_pixmap_free_gpu(sna, priv); 2487 } 2488 if (priv->flush) { 2489 assert(!priv->shm); 2490 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2491 } 2492 priv->source_count = SOURCE_BIAS; 2493 } 2494 2495 if (priv->cpu_bo) { 2496 if ((flags & MOVE_ASYNC_HINT) == 0) { 2497 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2498 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2499 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2500 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2501 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2502 } 2503 } 2504skip: 2505 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 2506 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2507 assert(pixmap->devKind); 2508 assert_pixmap_damage(pixmap); 2509 assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags)); 2510 return true; 2511} 2512 2513static bool 2514region_overlaps_damage(const RegionRec *region, 2515 struct sna_damage *damage, 2516 int dx, int dy) 2517{ 2518 const BoxRec *re, *de; 2519 2520 DBG(("%s?\n", __FUNCTION__)); 2521 2522 if (damage == NULL) 2523 return false; 2524 2525 if (DAMAGE_IS_ALL(damage)) 2526 return true; 2527 2528 re = ®ion->extents; 2529 de = &DAMAGE_PTR(damage)->extents; 2530 DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n", 2531 __FUNCTION__, 2532 re->x1, re->y1, re->x2, re->y2, 2533 de->x1, de->y1, de->x2, de->y2)); 2534 2535 return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 && 2536 re->y1 + dy < de->y2 && re->y2 + dy > de->y1); 2537} 2538 2539static inline bool region_inplace(struct sna *sna, 2540 PixmapPtr pixmap, 2541 RegionPtr region, 2542 struct sna_pixmap *priv, 2543 unsigned flags) 2544{ 2545 assert_pixmap_damage(pixmap); 2546 2547 if (FORCE_INPLACE) 2548 return FORCE_INPLACE > 0; 2549 2550 if (wedged(sna) && !priv->pinned) 2551 return false; 2552 2553 if (priv->gpu_damage && 2554 (priv->clear || (flags & MOVE_READ) == 0) && 2555 kgem_bo_is_busy(priv->gpu_bo)) 2556 return false; 2557 2558 if (flags & MOVE_READ && 2559 (priv->cpu || 2560 priv->gpu_damage == NULL || 2561 region_overlaps_damage(region, priv->cpu_damage, 0, 0))) { 2562 DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__)); 2563 return false; 2564 } 2565 2566 if (priv->mapped) { 2567 DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__, 2568 has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 2569 return has_coherent_map(sna, priv->gpu_bo, flags); 2570 } 2571 2572 if (priv->flush) { 2573 DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__)); 2574 return true; 2575 } 2576 2577 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2578 DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__)); 2579 assert(priv->gpu_bo); 2580 return true; 2581 } 2582 2583 if (priv->cpu_bo && priv->cpu) { 2584 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 2585 return false; 2586 } 2587 2588 DBG(("%s: (%dx%d), inplace? %d\n", 2589 __FUNCTION__, 2590 region->extents.x2 - region->extents.x1, 2591 region->extents.y2 - region->extents.y1, 2592 ((int)(region->extents.x2 - region->extents.x1) * 2593 (int)(region->extents.y2 - region->extents.y1) * 2594 pixmap->drawable.bitsPerPixel >> 12) 2595 >= sna->kgem.half_cpu_cache_pages)); 2596 return ((int)(region->extents.x2 - region->extents.x1) * 2597 (int)(region->extents.y2 - region->extents.y1) * 2598 pixmap->drawable.bitsPerPixel >> 12) 2599 >= sna->kgem.half_cpu_cache_pages; 2600} 2601 2602static bool cpu_clear_boxes(struct sna *sna, 2603 PixmapPtr pixmap, 2604 struct sna_pixmap *priv, 2605 const BoxRec *box, int n) 2606{ 2607 struct sna_fill_op fill; 2608 2609 if (!sna->kgem.can_blt_cpu) 2610 return false; 2611 2612 if (!sna_fill_init_blt(&fill, sna, 2613 pixmap, priv->cpu_bo, 2614 GXcopy, priv->clear_color, 2615 FILL_BOXES)) { 2616 DBG(("%s: unsupported fill\n", 2617 __FUNCTION__)); 2618 return false; 2619 } 2620 2621 fill.boxes(sna, &fill, box, n); 2622 fill.done(sna, &fill); 2623 return true; 2624} 2625 2626bool 2627sna_drawable_move_region_to_cpu(DrawablePtr drawable, 2628 RegionPtr region, 2629 unsigned flags) 2630{ 2631 PixmapPtr pixmap = get_drawable_pixmap(drawable); 2632 struct sna *sna = to_sna_from_pixmap(pixmap); 2633 struct sna_pixmap *priv; 2634 int16_t dx, dy; 2635 2636 DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n", 2637 __FUNCTION__, pixmap->drawable.serialNumber, 2638 pixmap->drawable.width, pixmap->drawable.height, 2639 RegionExtents(region)->x1, RegionExtents(region)->y1, 2640 RegionExtents(region)->x2, RegionExtents(region)->y2, 2641 flags)); 2642 2643 assert_pixmap_damage(pixmap); 2644 if (flags & MOVE_WRITE) { 2645 assert_drawable_contains_box(drawable, ®ion->extents); 2646 } 2647 assert(flags & (MOVE_WRITE | MOVE_READ)); 2648 2649 if (box_empty(®ion->extents)) 2650 return true; 2651 2652 if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) { 2653 if (!region_subsumes_pixmap(region, pixmap)) 2654 flags |= MOVE_READ; 2655 return _sna_pixmap_move_to_cpu(pixmap, flags); 2656 } 2657 2658 priv = sna_pixmap(pixmap); 2659 if (priv == NULL) { 2660 DBG(("%s: not attached to pixmap %ld (depth %d)\n", 2661 __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth)); 2662 return true; 2663 } 2664 2665 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2666 2667 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2668 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2669 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2670 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2671 goto skip; 2672 } 2673 2674 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2675 assert(priv->gpu_damage == NULL); 2676 assert(!priv->pinned); 2677 assert(!priv->mapped); 2678 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2679 priv->gpu_bo = NULL; 2680 } 2681 2682 if (sna_damage_is_all(&priv->cpu_damage, 2683 pixmap->drawable.width, 2684 pixmap->drawable.height)) { 2685 bool discard_gpu = priv->cpu; 2686 2687 DBG(("%s: pixmap=%ld all damaged on CPU\n", 2688 __FUNCTION__, pixmap->drawable.serialNumber)); 2689 assert(!priv->clear); 2690 2691 sna_damage_destroy(&priv->gpu_damage); 2692 2693 if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2694 priv->cpu_bo && !priv->cpu_bo->flush && 2695 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2696 DBG(("%s: active CPU bo replacing\n", __FUNCTION__)); 2697 assert(!priv->shm); 2698 assert(!IS_STATIC_PTR(priv->ptr)); 2699 2700 if (!region_subsumes_pixmap(region, pixmap)) { 2701 DBG(("%s: partial replacement\n", __FUNCTION__)); 2702 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 2703 RegionTranslate(region, dx, dy); 2704 2705 if (sna->kgem.has_llc && !priv->pinned && 2706 sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) { 2707#ifdef DEBUG_MEMORY 2708 sna->debug_memory.cpu_bo_allocs--; 2709 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 2710#endif 2711 DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__)); 2712 if (priv->gpu_bo) 2713 sna_pixmap_free_gpu(sna, priv); 2714 priv->gpu_bo = priv->cpu_bo; 2715 priv->cpu_bo = NULL; 2716 priv->ptr = NULL; 2717 pixmap->devPrivate.ptr = NULL; 2718 2719 priv->gpu_damage = priv->cpu_damage; 2720 priv->cpu_damage = NULL; 2721 2722 sna_damage_subtract(&priv->gpu_damage, region); 2723 discard_gpu = false; 2724 } else { 2725 DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__)); 2726 sna_damage_subtract(&priv->cpu_damage, region); 2727 assert(priv->cpu_damage); 2728 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2729 sna_pixmap_free_cpu(sna, priv, false); 2730 if (priv->flush) 2731 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2732 2733 assert(priv->cpu_damage == NULL); 2734 sna_damage_all(&priv->gpu_damage, pixmap); 2735 sna_damage_subtract(&priv->gpu_damage, region); 2736 discard_gpu = false; 2737 } 2738 } 2739 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 2740 if (priv->flush) { 2741 assert(!priv->shm); 2742 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2743 } 2744 2745 if (dx | dy) 2746 RegionTranslate(region, -dx, -dy); 2747 } else 2748 sna_pixmap_free_cpu(sna, priv, false); 2749 } 2750 2751 if (flags & MOVE_WRITE && discard_gpu) 2752 sna_pixmap_free_gpu(sna, priv); 2753 2754 sna_pixmap_unmap(pixmap, priv); 2755 assert(priv->mapped == MAPPED_NONE); 2756 if (pixmap->devPrivate.ptr == NULL && 2757 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2758 return false; 2759 assert(priv->mapped == MAPPED_NONE); 2760 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2761 2762 goto out; 2763 } 2764 2765 if (USE_INPLACE && 2766 (priv->create & KGEM_CAN_CREATE_LARGE || 2767 ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2768 (priv->flush || 2769 (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) || 2770 box_inplace(pixmap, ®ion->extents))))) { 2771 DBG(("%s: marking for inplace hint (%d, %d)\n", 2772 __FUNCTION__, priv->flush, box_inplace(pixmap, ®ion->extents))); 2773 flags |= MOVE_INPLACE_HINT; 2774 } 2775 2776 if (region_subsumes_pixmap(region, pixmap)) { 2777 DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n", 2778 __FUNCTION__, 2779 region->extents.x1, 2780 region->extents.y1, 2781 region->extents.x2, 2782 region->extents.y2, 2783 get_drawable_dx(drawable), get_drawable_dy(drawable), 2784 pixmap->drawable.width, 2785 pixmap->drawable.height)); 2786 return _sna_pixmap_move_to_cpu(pixmap, flags); 2787 } 2788 2789 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2790 2791 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 2792 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 2793 RegionTranslate(region, dx, dy); 2794 } 2795 2796 if (priv->move_to_gpu) { 2797 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 2798 if ((flags & MOVE_READ) == 0) 2799 sna_pixmap_discard_shadow_damage(priv, region); 2800 if (!priv->move_to_gpu(sna, priv, MOVE_READ)) { 2801 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2802 return NULL; 2803 } 2804 } 2805 2806 if (operate_inplace(priv, flags) && 2807 region_inplace(sna, pixmap, region, priv, flags) && 2808 sna_pixmap_create_mappable_gpu(pixmap, false)) { 2809 void *ptr; 2810 2811 DBG(("%s: try to operate inplace\n", __FUNCTION__)); 2812 assert(priv->gpu_bo); 2813 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2814 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2815 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2816 2817 /* XXX only sync for writes? */ 2818 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2819 assert(priv->gpu_bo->exec == NULL); 2820 2821 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2822 if (ptr != NULL) { 2823 pixmap->devPrivate.ptr = ptr; 2824 pixmap->devKind = priv->gpu_bo->pitch; 2825 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2826 assert(has_coherent_ptr(sna, priv, flags)); 2827 2828 if (flags & MOVE_WRITE) { 2829 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2830 assert(!priv->clear); 2831 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2832 if (sna_damage_is_all(&priv->gpu_damage, 2833 pixmap->drawable.width, 2834 pixmap->drawable.height)) { 2835 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2836 __FUNCTION__)); 2837 sna_damage_destroy(&priv->cpu_damage); 2838 list_del(&priv->flush_list); 2839 } else 2840 sna_damage_subtract(&priv->cpu_damage, 2841 region); 2842 } 2843 priv->clear = false; 2844 } 2845 priv->cpu &= priv->mapped == MAPPED_CPU; 2846 assert_pixmap_damage(pixmap); 2847 if (dx | dy) 2848 RegionTranslate(region, -dx, -dy); 2849 DBG(("%s: operate inplace\n", __FUNCTION__)); 2850 return true; 2851 } 2852 } 2853 2854 if (priv->clear && flags & MOVE_WRITE) { 2855 DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__)); 2856demote_to_cpu: 2857 if (dx | dy) 2858 RegionTranslate(region, -dx, -dy); 2859 return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ); 2860 } 2861 2862 if (flags & MOVE_WHOLE_HINT) { 2863 DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n", 2864 __FUNCTION__, 2865 region->extents.x1, 2866 region->extents.y1, 2867 region->extents.x2, 2868 region->extents.y2, 2869 pixmap->drawable.width, 2870 pixmap->drawable.height)); 2871move_to_cpu: 2872 if ((flags & MOVE_READ) == 0) 2873 sna_damage_subtract(&priv->gpu_damage, region); 2874 goto demote_to_cpu; 2875 } 2876 2877 sna_pixmap_unmap(pixmap, priv); 2878 2879 if (USE_INPLACE && 2880 priv->gpu_damage && 2881 priv->gpu_bo->tiling == I915_TILING_NONE && 2882 ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) && 2883 (DAMAGE_IS_ALL(priv->gpu_damage) || 2884 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2885 ®ion->extents)) && 2886 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) && 2887 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2888 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 2889 void *ptr; 2890 2891 DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n", 2892 __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE))); 2893 assert(priv->gpu_bo); 2894 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2895 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2896 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2897 2898 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2899 if (ptr != NULL) { 2900 pixmap->devPrivate.ptr = ptr; 2901 pixmap->devKind = priv->gpu_bo->pitch; 2902 priv->mapped = MAPPED_CPU; 2903 assert(has_coherent_ptr(sna, priv, flags)); 2904 2905 if (flags & MOVE_WRITE) { 2906 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2907 assert(!priv->clear); 2908 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2909 if (sna_damage_is_all(&priv->gpu_damage, 2910 pixmap->drawable.width, 2911 pixmap->drawable.height)) { 2912 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2913 __FUNCTION__)); 2914 sna_damage_destroy(&priv->cpu_damage); 2915 list_del(&priv->flush_list); 2916 } else 2917 sna_damage_subtract(&priv->cpu_damage, 2918 region); 2919 } 2920 priv->clear = false; 2921 } 2922 assert_pixmap_damage(pixmap); 2923 2924 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2925 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2926 priv->cpu = true; 2927 2928 assert_pixmap_map(pixmap, priv); 2929 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2930 if (dx | dy) 2931 RegionTranslate(region, -dx, -dy); 2932 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2933 return true; 2934 } 2935 } 2936 2937 if ((priv->clear || (flags & MOVE_READ) == 0) && 2938 priv->cpu_bo && !priv->cpu_bo->flush && 2939 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2940 sna_damage_subtract(&priv->cpu_damage, region); 2941 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2942 assert(priv->gpu_bo); 2943 sna_damage_all(&priv->gpu_damage, pixmap); 2944 sna_pixmap_free_cpu(sna, priv, false); 2945 } 2946 } 2947 2948 assert(priv->mapped == MAPPED_NONE); 2949 if (pixmap->devPrivate.ptr == NULL && 2950 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) { 2951 DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__)); 2952 goto move_to_cpu; 2953 } 2954 assert(priv->mapped == MAPPED_NONE); 2955 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2956 2957 if (priv->gpu_bo == NULL) { 2958 assert(priv->gpu_damage == NULL); 2959 goto done; 2960 } 2961 2962 assert(priv->gpu_bo->proxy == NULL); 2963 2964 if ((flags & MOVE_READ) == 0) { 2965 assert(flags & MOVE_WRITE); 2966 sna_damage_subtract(&priv->gpu_damage, region); 2967 priv->clear = false; 2968 goto done; 2969 } 2970 2971 if (priv->clear) { 2972 int n = region_num_rects(region); 2973 const BoxRec *box = region_rects(region); 2974 2975 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 2976 assert(priv->cpu_damage == NULL); 2977 2978 DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__)); 2979 if (priv->cpu_bo) { 2980 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2981 cpu_clear_boxes(sna, pixmap, priv, box, n)) 2982 goto clear_done; 2983 2984 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2985 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2986 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2987 } 2988 2989 if (sigtrap_get() == 0) { 2990 assert(pixmap->devKind); 2991 sigtrap_assert_active(); 2992 do { 2993 pixman_fill(pixmap->devPrivate.ptr, 2994 pixmap->devKind/sizeof(uint32_t), 2995 pixmap->drawable.bitsPerPixel, 2996 box->x1, box->y1, 2997 box->x2 - box->x1, 2998 box->y2 - box->y1, 2999 priv->clear_color); 3000 box++; 3001 } while (--n); 3002 sigtrap_put(); 3003 } else 3004 return false; 3005 3006clear_done: 3007 if (flags & MOVE_WRITE || 3008 region->extents.x2 - region->extents.x1 > 1 || 3009 region->extents.y2 - region->extents.y1 > 1) { 3010 sna_damage_subtract(&priv->gpu_damage, region); 3011 priv->clear = false; 3012 } 3013 goto done; 3014 } 3015 3016 if (priv->gpu_damage && 3017 (DAMAGE_IS_ALL(priv->gpu_damage) || 3018 sna_damage_overlaps_box(priv->gpu_damage, ®ion->extents))) { 3019 DBG(("%s: region (%dx%d) overlaps gpu damage\n", 3020 __FUNCTION__, 3021 region->extents.x2 - region->extents.x1, 3022 region->extents.y2 - region->extents.y1)); 3023 assert(priv->gpu_bo); 3024 3025 if (priv->cpu_damage == NULL) { 3026 if ((flags & MOVE_WRITE) == 0 && 3027 region->extents.x2 - region->extents.x1 == 1 && 3028 region->extents.y2 - region->extents.y1 == 1) { 3029 /* Often associated with synchronisation, KISS */ 3030 DBG(("%s: single pixel read\n", __FUNCTION__)); 3031 sna_read_boxes(sna, pixmap, priv->gpu_bo, 3032 ®ion->extents, 1); 3033 goto done; 3034 } 3035 } else { 3036 if (DAMAGE_IS_ALL(priv->cpu_damage) || 3037 sna_damage_contains_box__no_reduce(priv->cpu_damage, 3038 ®ion->extents)) { 3039 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 3040 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 3041 3042 DBG(("%s: region already in CPU damage\n", 3043 __FUNCTION__)); 3044 goto already_damaged; 3045 } 3046 } 3047 3048 if (sna_damage_contains_box(&priv->gpu_damage, 3049 ®ion->extents) != PIXMAN_REGION_OUT) { 3050 RegionRec want, *r = region; 3051 3052 DBG(("%s: region (%dx%d) intersects gpu damage\n", 3053 __FUNCTION__, 3054 region->extents.x2 - region->extents.x1, 3055 region->extents.y2 - region->extents.y1)); 3056 3057 if ((flags & MOVE_WRITE) == 0 && 3058 region->extents.x2 - region->extents.x1 == 1 && 3059 region->extents.y2 - region->extents.y1 == 1) { 3060 sna_read_boxes(sna, pixmap, priv->gpu_bo, 3061 ®ion->extents, 1); 3062 goto done; 3063 } 3064 3065 /* Expand the region to move 32x32 pixel blocks at a 3066 * time, as we assume that we will continue writing 3067 * afterwards and so aim to coallesce subsequent 3068 * reads. 3069 */ 3070 if (flags & MOVE_WRITE) { 3071 int n = region_num_rects(region), i; 3072 const BoxRec *boxes = region_rects(region); 3073 BoxPtr blocks; 3074 3075 blocks = NULL; 3076 if (priv->cpu_damage == NULL) 3077 blocks = malloc(sizeof(BoxRec) * n); 3078 if (blocks) { 3079 for (i = 0; i < n; i++) { 3080 blocks[i].x1 = boxes[i].x1 & ~31; 3081 if (blocks[i].x1 < 0) 3082 blocks[i].x1 = 0; 3083 3084 blocks[i].x2 = (boxes[i].x2 + 31) & ~31; 3085 if (blocks[i].x2 > pixmap->drawable.width) 3086 blocks[i].x2 = pixmap->drawable.width; 3087 3088 blocks[i].y1 = boxes[i].y1 & ~31; 3089 if (blocks[i].y1 < 0) 3090 blocks[i].y1 = 0; 3091 3092 blocks[i].y2 = (boxes[i].y2 + 31) & ~31; 3093 if (blocks[i].y2 > pixmap->drawable.height) 3094 blocks[i].y2 = pixmap->drawable.height; 3095 } 3096 if (pixman_region_init_rects(&want, blocks, i)) 3097 r = &want; 3098 free(blocks); 3099 } 3100 } 3101 3102 if (region_subsumes_damage(r, priv->gpu_damage)) { 3103 const BoxRec *box; 3104 int n; 3105 3106 DBG(("%s: region wholly contains damage\n", 3107 __FUNCTION__)); 3108 3109 n = sna_damage_get_boxes(priv->gpu_damage, &box); 3110 if (n) 3111 download_boxes(sna, priv, n, box); 3112 3113 sna_damage_destroy(&priv->gpu_damage); 3114 } else if (DAMAGE_IS_ALL(priv->gpu_damage) || 3115 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3116 &r->extents)) { 3117 3118 DBG(("%s: region wholly inside damage\n", 3119 __FUNCTION__)); 3120 3121 assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN); 3122 assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT); 3123 3124 download_boxes(sna, priv, 3125 region_num_rects(r), 3126 region_rects(r)); 3127 sna_damage_subtract(&priv->gpu_damage, r); 3128 } else { 3129 RegionRec need; 3130 3131 pixman_region_init(&need); 3132 if (sna_damage_intersect(priv->gpu_damage, r, &need)) { 3133 DBG(("%s: region intersects damage\n", 3134 __FUNCTION__)); 3135 3136 download_boxes(sna, priv, 3137 region_num_rects(&need), 3138 region_rects(&need)); 3139 sna_damage_subtract(&priv->gpu_damage, r); 3140 RegionUninit(&need); 3141 } 3142 } 3143 if (r == &want) 3144 pixman_region_fini(&want); 3145 } 3146 } 3147 3148done: 3149 if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) { 3150 DBG(("%s: applying cpu damage\n", __FUNCTION__)); 3151 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3152 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 3153 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 3154 sna_damage_reduce_all(&priv->cpu_damage, pixmap); 3155 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3156 DBG(("%s: replaced entire pixmap\n", __FUNCTION__)); 3157 sna_pixmap_free_gpu(sna, priv); 3158 } 3159 if (priv->flush) { 3160 assert(!priv->shm); 3161 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3162 } 3163 } 3164 3165already_damaged: 3166 if (dx | dy) 3167 RegionTranslate(region, -dx, -dy); 3168 3169out: 3170 if (flags & MOVE_WRITE) { 3171 assert(!DAMAGE_IS_ALL(priv->gpu_damage)); 3172 priv->source_count = SOURCE_BIAS; 3173 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3174 assert(priv->gpu_bo || priv->gpu_damage == NULL); 3175 assert(!priv->flush || !list_is_empty(&priv->flush_list)); 3176 assert(!priv->clear); 3177 } 3178 if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) { 3179 DBG(("%s: syncing cpu bo\n", __FUNCTION__)); 3180 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 3181 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 3182 FORCE_FULL_SYNC || flags & MOVE_WRITE); 3183 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 3184 } 3185skip: 3186 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 3187 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 3188 assert(pixmap->devKind); 3189 assert_pixmap_damage(pixmap); 3190 assert(has_coherent_ptr(sna, priv, flags)); 3191 return true; 3192} 3193 3194bool 3195sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags) 3196{ 3197 RegionRec region; 3198 PixmapPtr pixmap; 3199 int16_t dx, dy; 3200 3201 if (drawable->type == DRAWABLE_PIXMAP) 3202 return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags); 3203 3204 pixmap = get_window_pixmap((WindowPtr)drawable); 3205 get_drawable_deltas(drawable, pixmap, &dx, &dy); 3206 3207 DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n", 3208 __FUNCTION__, 3209 drawable->x, drawable->y, 3210 drawable->width, drawable->height, 3211 dx, dy, flags)); 3212 3213 region.extents.x1 = drawable->x + dx; 3214 region.extents.y1 = drawable->y + dy; 3215 region.extents.x2 = region.extents.x1 + drawable->width; 3216 region.extents.y2 = region.extents.y1 + drawable->height; 3217 region.data = NULL; 3218 3219 if (region.extents.x1 < 0) 3220 region.extents.x1 = 0; 3221 if (region.extents.y1 < 0) 3222 region.extents.y1 = 0; 3223 if (region.extents.x2 > pixmap->drawable.width) 3224 region.extents.x2 = pixmap->drawable.width; 3225 if (region.extents.y2 > pixmap->drawable.height) 3226 region.extents.y2 = pixmap->drawable.height; 3227 3228 if (box_empty(®ion.extents)) 3229 return true; 3230 3231 return sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags); 3232} 3233 3234pure static bool alu_overwrites(uint8_t alu) 3235{ 3236 switch (alu) { 3237 case GXclear: 3238 case GXcopy: 3239 case GXcopyInverted: 3240 case GXset: 3241 return true; 3242 default: 3243 return false; 3244 } 3245} 3246 3247inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc) 3248{ 3249 if (!alu_overwrites(gc->alu)) 3250 return false; 3251 3252 if (!PM_IS_SOLID(draw, gc->planemask)) 3253 return false; 3254 3255 if (gc->fillStyle == FillStippled) 3256 return false; 3257 3258 return true; 3259} 3260 3261inline static unsigned 3262drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial) 3263{ 3264 assert(sna_gc(gc)->changes == 0); 3265 3266 if (gc->fillStyle == FillStippled) { 3267 DBG(("%s: read due to fill %d\n", 3268 __FUNCTION__, gc->fillStyle)); 3269 return MOVE_READ | MOVE_WRITE; 3270 } 3271 3272 if (fb_gc(gc)->and | fb_gc(gc)->bgand) { 3273 DBG(("%s: read due to rrop %d:%x\n", 3274 __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and)); 3275 return MOVE_READ | MOVE_WRITE; 3276 } 3277 3278 DBG(("%s: try operating on drawable inplace [hint? %d]\n", 3279 __FUNCTION__, drawable_gc_inplace_hint(draw, gc))); 3280 3281 return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT; 3282} 3283 3284static inline struct sna_pixmap * 3285sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv) 3286{ 3287 assert(priv->gpu_bo); 3288 DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__, 3289 priv->pixmap->drawable.serialNumber, 3290 priv->gpu_bo->handle)); 3291 return priv; 3292} 3293 3294inline static struct sna_pixmap * 3295__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags) 3296{ 3297 struct sna_pixmap *priv; 3298 3299 assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE)); 3300 if ((flags & __MOVE_FORCE) == 0 && wedged(sna)) 3301 return NULL; 3302 3303 priv = sna_pixmap(pixmap); 3304 if (priv == NULL) { 3305 DBG(("%s: not attached\n", __FUNCTION__)); 3306 if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0) 3307 return NULL; 3308 3309 if (pixmap->usage_hint == -1) { 3310 DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__)); 3311 return NULL; 3312 } 3313 3314 DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__)); 3315 3316 priv = sna_pixmap_attach(pixmap); 3317 if (priv == NULL) 3318 return NULL; 3319 3320 sna_damage_all(&priv->cpu_damage, pixmap); 3321 3322 assert(priv->gpu_bo == NULL); 3323 assert(priv->gpu_damage == NULL); 3324 } 3325 3326 return priv; 3327} 3328 3329inline static void sna_pixmap_unclean(struct sna *sna, 3330 struct sna_pixmap *priv, 3331 unsigned flags) 3332{ 3333 struct drm_i915_gem_busy busy; 3334 3335 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 3336 assert(priv->gpu_bo); 3337 assert(priv->gpu_bo->proxy == NULL); 3338 assert_pixmap_map(priv->pixmap, priv); 3339 3340 sna_damage_destroy(&priv->cpu_damage); 3341 list_del(&priv->flush_list); 3342 3343 if (flags & (__MOVE_DRI | __MOVE_SCANOUT)) 3344 return; 3345 3346 if (!priv->flush || priv->gpu_bo->exec) 3347 return; 3348 3349 busy.handle = priv->gpu_bo->handle; 3350 busy.busy = 0; 3351 ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 3352 3353 DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n", 3354 __FUNCTION__, 3355 priv->pixmap->drawable.serialNumber, 3356 busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16)))); 3357 3358 if (busy.busy) { 3359 unsigned mode = KGEM_RENDER; 3360 if (busy.busy & (0xfffe << 16)) 3361 mode = KGEM_BLT; 3362 kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode); 3363 } else 3364 __kgem_bo_clear_busy(priv->gpu_bo); 3365} 3366 3367struct sna_pixmap * 3368sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags) 3369{ 3370 struct sna *sna = to_sna_from_pixmap(pixmap); 3371 struct sna_pixmap *priv; 3372 RegionRec i, r; 3373 3374 DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n", 3375 __FUNCTION__, pixmap->drawable.serialNumber, 3376 box->x1, box->y1, box->x2, box->y2, flags)); 3377 3378 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 3379 if (priv == NULL) 3380 return NULL; 3381 3382 assert(box->x2 > box->x1 && box->y2 > box->y1); 3383 assert_pixmap_damage(pixmap); 3384 assert_pixmap_contains_box(pixmap, box); 3385 assert(priv->gpu_damage == NULL || priv->gpu_bo); 3386 3387 if ((flags & MOVE_READ) == 0) 3388 sna_damage_subtract_box(&priv->cpu_damage, box); 3389 3390 if (priv->move_to_gpu) { 3391 unsigned int hint; 3392 3393 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3394 hint = flags | MOVE_READ; 3395 if ((flags & MOVE_READ) == 0) { 3396 RegionRec region; 3397 3398 region.extents = *box; 3399 region.data = NULL; 3400 sna_pixmap_discard_shadow_damage(priv, ®ion); 3401 if (region_subsumes_pixmap(®ion, pixmap)) 3402 hint &= ~MOVE_READ; 3403 } else { 3404 if (priv->cpu_damage) 3405 hint |= MOVE_WRITE; 3406 } 3407 if (!priv->move_to_gpu(sna, priv, hint)) { 3408 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3409 return NULL; 3410 } 3411 } 3412 3413 if (priv->cow) { 3414 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 3415 3416 assert(cow); 3417 3418 if ((flags & MOVE_READ) == 0) { 3419 if (priv->gpu_damage) { 3420 r.extents = *box; 3421 r.data = NULL; 3422 if (!region_subsumes_damage(&r, priv->gpu_damage)) 3423 cow |= MOVE_READ | __MOVE_FORCE; 3424 } 3425 } else { 3426 if (priv->cpu_damage) { 3427 r.extents = *box; 3428 r.data = NULL; 3429 if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0)) 3430 cow |= MOVE_WRITE; 3431 } 3432 } 3433 3434 if (!sna_pixmap_undo_cow(sna, priv, cow)) 3435 return NULL; 3436 3437 if (priv->gpu_bo == NULL) 3438 sna_damage_destroy(&priv->gpu_damage); 3439 } 3440 3441 if (sna_damage_is_all(&priv->gpu_damage, 3442 pixmap->drawable.width, 3443 pixmap->drawable.height)) { 3444 DBG(("%s: already all-damaged\n", __FUNCTION__)); 3445 sna_pixmap_unclean(sna, priv, flags); 3446 goto done; 3447 } 3448 3449 if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 3450 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 3451 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3452 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3453 assert(!priv->pinned); 3454 assert(!priv->mapped); 3455 sna_damage_destroy(&priv->gpu_damage); 3456 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 3457 priv->gpu_bo = NULL; 3458 } 3459 3460 sna_damage_reduce(&priv->cpu_damage); 3461 assert_pixmap_damage(pixmap); 3462 3463 if (priv->cpu_damage == NULL) { 3464 list_del(&priv->flush_list); 3465 return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags); 3466 } 3467 3468 if (priv->gpu_bo == NULL) { 3469 assert(priv->gpu_damage == NULL); 3470 3471 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) 3472 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE); 3473 3474 if (priv->gpu_bo == NULL) 3475 return NULL; 3476 3477 DBG(("%s: created gpu bo\n", __FUNCTION__)); 3478 } 3479 3480 if (priv->gpu_bo->proxy) { 3481 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 3482 assert((flags & MOVE_WRITE) == 0); 3483 assert(priv->gpu_damage == NULL); 3484 return priv; 3485 } 3486 3487 add_shm_flush(sna, priv); 3488 3489 assert(priv->cpu_damage); 3490 region_set(&r, box); 3491 if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) { 3492 bool ok = false; 3493 int n; 3494 3495 n = sna_damage_get_boxes(priv->cpu_damage, &box); 3496 assert(n); 3497 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3498 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3499 ok = sna->render.copy_boxes(sna, GXcopy, 3500 &pixmap->drawable, priv->cpu_bo, 0, 0, 3501 &pixmap->drawable, priv->gpu_bo, 0, 0, 3502 box, n, 0); 3503 } 3504 if (!ok) { 3505 sna_pixmap_unmap(pixmap, priv); 3506 if (pixmap->devPrivate.ptr == NULL) 3507 return NULL; 3508 3509 assert(pixmap->devKind); 3510 if (n == 1 && !priv->pinned && 3511 box->x1 <= 0 && box->y1 <= 0 && 3512 box->x2 >= pixmap->drawable.width && 3513 box->y2 >= pixmap->drawable.height) { 3514 ok = sna_replace(sna, pixmap, 3515 pixmap->devPrivate.ptr, 3516 pixmap->devKind); 3517 } else { 3518 ok = sna_write_boxes(sna, pixmap, 3519 priv->gpu_bo, 0, 0, 3520 pixmap->devPrivate.ptr, 3521 pixmap->devKind, 3522 0, 0, 3523 box, n); 3524 } 3525 if (!ok) 3526 return NULL; 3527 } 3528 3529 sna_damage_destroy(&priv->cpu_damage); 3530 } else if (DAMAGE_IS_ALL(priv->cpu_damage) || 3531 sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) { 3532 bool ok = false; 3533 3534 assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT); 3535 assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN); 3536 3537 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3538 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3539 ok = sna->render.copy_boxes(sna, GXcopy, 3540 &pixmap->drawable, priv->cpu_bo, 0, 0, 3541 &pixmap->drawable, priv->gpu_bo, 0, 0, 3542 box, 1, 0); 3543 } 3544 if (!ok) { 3545 sna_pixmap_unmap(pixmap, priv); 3546 if (pixmap->devPrivate.ptr != NULL) { 3547 assert(pixmap->devKind); 3548 ok = sna_write_boxes(sna, pixmap, 3549 priv->gpu_bo, 0, 0, 3550 pixmap->devPrivate.ptr, 3551 pixmap->devKind, 3552 0, 0, 3553 box, 1); 3554 } 3555 } 3556 if (!ok) 3557 return NULL; 3558 3559 sna_damage_subtract(&priv->cpu_damage, &r); 3560 } else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) { 3561 int n = region_num_rects(&i); 3562 bool ok; 3563 3564 box = region_rects(&i); 3565 ok = false; 3566 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3567 DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n)); 3568 ok = sna->render.copy_boxes(sna, GXcopy, 3569 &pixmap->drawable, priv->cpu_bo, 0, 0, 3570 &pixmap->drawable, priv->gpu_bo, 0, 0, 3571 box, n, 0); 3572 } 3573 if (!ok) { 3574 sna_pixmap_unmap(pixmap, priv); 3575 if (pixmap->devPrivate.ptr != NULL) { 3576 assert(pixmap->devKind); 3577 ok = sna_write_boxes(sna, pixmap, 3578 priv->gpu_bo, 0, 0, 3579 pixmap->devPrivate.ptr, 3580 pixmap->devKind, 3581 0, 0, 3582 box, n); 3583 } 3584 } 3585 if (!ok) 3586 return NULL; 3587 3588 sna_damage_subtract(&priv->cpu_damage, &r); 3589 RegionUninit(&i); 3590 } 3591 3592done: 3593 if (priv->cpu_damage == NULL && priv->flush) 3594 list_del(&priv->flush_list); 3595 if (flags & MOVE_WRITE) { 3596 priv->clear = false; 3597 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 3598 priv->cpu_damage == NULL && 3599 (box_covers_pixmap(pixmap, &r.extents) || 3600 box_inplace(pixmap, &r.extents))) { 3601 DBG(("%s: large operation on undamaged, discarding CPU shadow\n", 3602 __FUNCTION__)); 3603 assert(priv->gpu_bo); 3604 assert(priv->gpu_bo->proxy == NULL); 3605 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) { 3606 DBG(("%s: large operation on undamaged, promoting to full GPU\n", 3607 __FUNCTION__)); 3608 sna_damage_all(&priv->gpu_damage, pixmap); 3609 } 3610 } 3611 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3612 sna_pixmap_free_cpu(sna, priv, priv->cpu); 3613 sna_damage_destroy(&priv->cpu_damage); 3614 list_del(&priv->flush_list); 3615 } 3616 priv->cpu = false; 3617 } 3618 3619 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3620 return sna_pixmap_mark_active(sna, priv); 3621} 3622 3623struct kgem_bo * 3624sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box, 3625 struct sna_damage ***damage) 3626{ 3627 PixmapPtr pixmap = get_drawable_pixmap(drawable); 3628 struct sna_pixmap *priv = sna_pixmap(pixmap); 3629 struct sna *sna; 3630 RegionRec region; 3631 int16_t dx, dy; 3632 int ret; 3633 3634 DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n", 3635 __FUNCTION__, 3636 pixmap->drawable.serialNumber, 3637 box->x1, box->y1, box->x2, box->y2, 3638 flags)); 3639 3640 assert(box->x2 > box->x1 && box->y2 > box->y1); 3641 assert(pixmap->refcnt); 3642 assert_pixmap_damage(pixmap); 3643 assert_drawable_contains_box(drawable, box); 3644 3645 if (priv == NULL) { 3646 DBG(("%s: not attached\n", __FUNCTION__)); 3647 return NULL; 3648 } 3649 3650 if (priv->cow) { 3651 unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE; 3652 assert(cow); 3653 3654 if (flags & IGNORE_DAMAGE) { 3655 if (priv->gpu_damage) { 3656 region.extents = *box; 3657 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3658 region.extents.x1 += dx; 3659 region.extents.x2 += dx; 3660 region.extents.y1 += dy; 3661 region.extents.y2 += dy; 3662 } 3663 region.data = NULL; 3664 if (region_subsumes_damage(®ion, 3665 priv->gpu_damage)) 3666 cow &= ~MOVE_READ; 3667 } else 3668 cow &= ~MOVE_READ; 3669 } 3670 3671 if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow)) 3672 return NULL; 3673 3674 if (priv->gpu_bo == NULL) 3675 sna_damage_destroy(&priv->gpu_damage); 3676 } 3677 3678 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 3679 DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__)); 3680 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3681 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3682 assert(!priv->pinned); 3683 assert(!priv->mapped); 3684 sna_damage_destroy(&priv->gpu_damage); 3685 kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem, 3686 priv->gpu_bo); 3687 priv->gpu_bo = NULL; 3688 goto use_cpu_bo; 3689 } 3690 3691 if (priv->flush) { 3692 DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__)); 3693 flags |= PREFER_GPU; 3694 } 3695 if (priv->shm) { 3696 DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__)); 3697 flags &= ~PREFER_GPU; 3698 } 3699 if (priv->pinned) { 3700 DBG(("%s: pinned, never REPLACES\n", __FUNCTION__)); 3701 flags &= ~REPLACES; 3702 } 3703 if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) { 3704 DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__)); 3705 flags &= ~PREFER_GPU; 3706 } 3707 3708 if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) { 3709 if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) { 3710 DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__)); 3711 flags |= PREFER_GPU; 3712 } 3713 } 3714 3715 DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n", 3716 __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags)); 3717 3718 if ((flags & PREFER_GPU) == 0 && 3719 (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) { 3720 DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__)); 3721 goto use_cpu_bo; 3722 } 3723 3724 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3725 DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__)); 3726 assert(priv->cpu_damage == NULL); 3727 assert(priv->gpu_bo); 3728 assert(priv->gpu_bo->proxy == NULL); 3729 goto use_gpu_bo; 3730 } 3731 3732 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3733 assert(priv->gpu_damage == NULL); 3734 if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) { 3735 DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n", 3736 __FUNCTION__)); 3737 goto use_cpu_bo; 3738 } 3739 } 3740 3741 DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__, 3742 priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL, 3743 priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL)); 3744 if (priv->gpu_bo == NULL) { 3745 unsigned int move; 3746 3747 if ((flags & FORCE_GPU) == 0 && 3748 (priv->create & KGEM_CAN_CREATE_GPU) == 0) { 3749 DBG(("%s: untiled, will not force allocation\n", 3750 __FUNCTION__)); 3751 goto use_cpu_bo; 3752 } 3753 3754 if ((flags & IGNORE_DAMAGE) == 0) { 3755 if (priv->cpu_bo) { 3756 if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) { 3757 if (kgem_bo_is_busy(priv->cpu_bo)) { 3758 DBG(("%s: already using CPU bo, will not force allocation\n", 3759 __FUNCTION__)); 3760 goto use_cpu_bo; 3761 } 3762 3763 if ((flags & RENDER_GPU) == 0) { 3764 DBG(("%s: prefer cpu", __FUNCTION__)); 3765 goto use_cpu_bo; 3766 } 3767 } else { 3768 if (kgem_bo_is_busy(priv->cpu_bo)) { 3769 DBG(("%s: CPU bo active, must force allocation\n", 3770 __FUNCTION__)); 3771 goto create_gpu_bo; 3772 } 3773 } 3774 } 3775 3776 if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) { 3777 if ((flags & PREFER_GPU) == 0) { 3778 DBG(("%s: already damaged and prefer cpu", 3779 __FUNCTION__)); 3780 goto use_cpu_bo; 3781 } 3782 3783 if (!box_inplace(pixmap, box)) { 3784 DBG(("%s: damaged with a small operation, will not force allocation\n", 3785 __FUNCTION__)); 3786 goto use_cpu_bo; 3787 } 3788 } 3789 } else if (priv->cpu_damage) { 3790 region.extents = *box; 3791 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3792 region.extents.x1 += dx; 3793 region.extents.x2 += dx; 3794 region.extents.y1 += dy; 3795 region.extents.y2 += dy; 3796 } 3797 region.data = NULL; 3798 3799 sna_damage_subtract(&priv->cpu_damage, ®ion); 3800 if (priv->cpu_damage == NULL) { 3801 list_del(&priv->flush_list); 3802 priv->cpu = false; 3803 } 3804 } 3805 3806create_gpu_bo: 3807 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3808 if (flags & FORCE_GPU) 3809 move |= __MOVE_FORCE; 3810 if (!sna_pixmap_move_to_gpu(pixmap, move)) 3811 goto use_cpu_bo; 3812 3813 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3814 goto done; 3815 } 3816 3817 3818 region.extents = *box; 3819 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3820 region.extents.x1 += dx; 3821 region.extents.x2 += dx; 3822 region.extents.y1 += dy; 3823 region.extents.y2 += dy; 3824 } 3825 region.data = NULL; 3826 3827 DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__, 3828 region.extents.x1, region.extents.y1, 3829 region.extents.x2, region.extents.y2)); 3830 3831 if (priv->gpu_damage) { 3832 assert(priv->gpu_bo); 3833 if (!priv->cpu_damage || flags & IGNORE_DAMAGE) { 3834 if (flags & REPLACES || box_covers_pixmap(pixmap, ®ion.extents)) { 3835 unsigned int move; 3836 3837 if (flags & IGNORE_DAMAGE) 3838 move = MOVE_WRITE; 3839 else 3840 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3841 3842 if (sna_pixmap_move_to_gpu(pixmap, move)) { 3843 sna_damage_all(&priv->gpu_damage, 3844 pixmap); 3845 goto use_gpu_bo; 3846 } 3847 } 3848 3849 if (DAMAGE_IS_ALL(priv->gpu_damage) || 3850 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3851 ®ion.extents)) { 3852 DBG(("%s: region wholly contained within GPU damage\n", 3853 __FUNCTION__)); 3854 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3855 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3856 goto use_gpu_bo; 3857 } else { 3858 DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n", 3859 __FUNCTION__)); 3860 goto move_to_gpu; 3861 } 3862 } 3863 3864 ret = sna_damage_contains_box(&priv->gpu_damage, ®ion.extents); 3865 if (ret == PIXMAN_REGION_IN) { 3866 DBG(("%s: region wholly contained within GPU damage\n", 3867 __FUNCTION__)); 3868 goto use_gpu_bo; 3869 } 3870 3871 if (ret != PIXMAN_REGION_OUT) { 3872 DBG(("%s: region partially contained within GPU damage\n", 3873 __FUNCTION__)); 3874 goto move_to_gpu; 3875 } 3876 } 3877 3878 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) { 3879 ret = sna_damage_contains_box(&priv->cpu_damage, ®ion.extents); 3880 if (ret == PIXMAN_REGION_IN) { 3881 DBG(("%s: region wholly contained within CPU damage\n", 3882 __FUNCTION__)); 3883 goto use_cpu_bo; 3884 } 3885 3886 if (box_inplace(pixmap, box)) { 3887 DBG(("%s: forcing inplace\n", __FUNCTION__)); 3888 goto move_to_gpu; 3889 } 3890 3891 if (ret != PIXMAN_REGION_OUT) { 3892 DBG(("%s: region partially contained within CPU damage\n", 3893 __FUNCTION__)); 3894 goto use_cpu_bo; 3895 } 3896 } 3897 3898move_to_gpu: 3899 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion.extents, 3900 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) { 3901 DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__)); 3902 assert(priv->gpu_bo == NULL); 3903 goto use_cpu_bo; 3904 } 3905 3906done: 3907 assert(priv->move_to_gpu == NULL); 3908 assert(priv->gpu_bo != NULL); 3909 assert(priv->gpu_bo->refcnt); 3910 if (sna_damage_is_all(&priv->gpu_damage, 3911 pixmap->drawable.width, 3912 pixmap->drawable.height)) { 3913 sna_damage_destroy(&priv->cpu_damage); 3914 list_del(&priv->flush_list); 3915 *damage = NULL; 3916 } else 3917 *damage = &priv->gpu_damage; 3918 3919 DBG(("%s: using GPU bo with damage? %d\n", 3920 __FUNCTION__, *damage != NULL)); 3921 assert(*damage == NULL || !DAMAGE_IS_ALL(*damage)); 3922 assert(priv->gpu_bo->proxy == NULL); 3923 assert(priv->clear == false); 3924 assert(priv->cpu == false); 3925 assert(!priv->shm); 3926 return priv->gpu_bo; 3927 3928use_gpu_bo: 3929 if (priv->move_to_gpu) { 3930 unsigned hint = MOVE_READ | MOVE_WRITE; 3931 3932 sna = to_sna_from_pixmap(pixmap); 3933 3934 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3935 if (flags & IGNORE_DAMAGE) { 3936 region.extents = *box; 3937 region.data = NULL; 3938 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3939 region.extents.x1 += dx; 3940 region.extents.x2 += dx; 3941 region.extents.y1 += dy; 3942 region.extents.y2 += dy; 3943 } 3944 sna_pixmap_discard_shadow_damage(priv, ®ion); 3945 if (region_subsumes_pixmap(®ion, pixmap)) { 3946 DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__)); 3947 hint = MOVE_WRITE; 3948 } 3949 } 3950 3951 if (!priv->move_to_gpu(sna, priv, hint)) { 3952 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3953 goto use_cpu_bo; 3954 } 3955 } 3956 3957 if (priv->shm) { 3958 assert(!priv->flush); 3959 list_move(&priv->flush_list, &sna->flush_pixmaps); 3960 } 3961 3962 DBG(("%s: using whole GPU bo\n", __FUNCTION__)); 3963 assert(priv->gpu_bo != NULL); 3964 assert(priv->gpu_bo->refcnt); 3965 assert(priv->gpu_bo->proxy == NULL); 3966 assert(priv->gpu_damage); 3967 priv->cpu = false; 3968 priv->clear = false; 3969 *damage = NULL; 3970 return priv->gpu_bo; 3971 3972use_cpu_bo: 3973 if (!USE_CPU_BO || priv->cpu_bo == NULL) { 3974 if ((flags & FORCE_GPU) == 0) { 3975 DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__)); 3976 return NULL; 3977 } 3978 3979 flags &= ~FORCE_GPU; 3980 3981 region.extents = *box; 3982 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3983 region.extents.x1 += dx; 3984 region.extents.x2 += dx; 3985 region.extents.y1 += dy; 3986 region.extents.y2 += dy; 3987 } 3988 region.data = NULL; 3989 3990 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3991 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) || 3992 priv->cpu_bo == NULL) { 3993 DBG(("%s: did not create CPU bo\n", __FUNCTION__)); 3994cpu_fail: 3995 if (priv->gpu_bo) 3996 goto move_to_gpu; 3997 3998 return NULL; 3999 } 4000 } 4001 4002 assert(priv->cpu_bo->refcnt); 4003 4004 sna = to_sna_from_pixmap(pixmap); 4005 if ((flags & FORCE_GPU) == 0 && 4006 !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 4007 DBG(("%s: has CPU bo, but is idle and acceleration not forced\n", 4008 __FUNCTION__)); 4009 return NULL; 4010 } 4011 4012 region.extents = *box; 4013 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 4014 region.extents.x1 += dx; 4015 region.extents.x2 += dx; 4016 region.extents.y1 += dy; 4017 region.extents.y2 += dy; 4018 } 4019 region.data = NULL; 4020 4021 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 4022 DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n", 4023 __FUNCTION__)); 4024 goto move_to_gpu; 4025 } 4026 4027 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4028 4029 if (flags & RENDER_GPU) { 4030 flags &= ~RENDER_GPU; 4031 4032 if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) { 4033 DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__)); 4034 4035prefer_gpu_bo: 4036 if (priv->gpu_bo == NULL) { 4037 if ((flags & FORCE_GPU) == 0) { 4038 DBG(("%s: untiled, will not force allocation\n", 4039 __FUNCTION__)); 4040 return NULL; 4041 } 4042 4043 if (flags & IGNORE_DAMAGE) { 4044 sna_damage_subtract(&priv->cpu_damage, ®ion); 4045 if (priv->cpu_damage == NULL) { 4046 list_del(&priv->flush_list); 4047 priv->cpu = false; 4048 } 4049 } 4050 4051 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 4052 return NULL; 4053 4054 sna_damage_all(&priv->gpu_damage, pixmap); 4055 4056 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 4057 goto done; 4058 } 4059 goto move_to_gpu; 4060 } 4061 4062 if (!priv->shm) { 4063 if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) { 4064 if (priv->gpu_bo && priv->gpu_bo->tiling) { 4065 DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__)); 4066 goto prefer_gpu_bo; 4067 } 4068 4069 if (priv->cpu_bo->pitch >= 4096) { 4070 DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__)); 4071 goto prefer_gpu_bo; 4072 } 4073 } 4074 4075 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) { 4076 DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__)); 4077 goto prefer_gpu_bo; 4078 } 4079 4080 if (!sna->kgem.can_blt_cpu) { 4081 DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__)); 4082 goto prefer_gpu_bo; 4083 } 4084 } 4085 } 4086 4087 if (!sna->kgem.can_blt_cpu) 4088 goto cpu_fail; 4089 4090 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 4091 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) { 4092 DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__)); 4093 goto cpu_fail; 4094 } 4095 4096 if (priv->shm) { 4097 add_shm_flush(sna, priv); 4098 /* As we may have flushed and retired,, recheck for busy bo */ 4099 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo)) 4100 return NULL; 4101 } 4102 if (priv->flush) { 4103 assert(!priv->shm); 4104 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 4105 } 4106 4107 if (sna_damage_is_all(&priv->cpu_damage, 4108 pixmap->drawable.width, 4109 pixmap->drawable.height)) { 4110 sna_damage_destroy(&priv->gpu_damage); 4111 *damage = NULL; 4112 } else { 4113 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 4114 if (priv->cpu_damage && 4115 sna_damage_contains_box__no_reduce(priv->cpu_damage, 4116 ®ion.extents)) { 4117 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 4118 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 4119 *damage = NULL; 4120 } else 4121 *damage = &priv->cpu_damage; 4122 } 4123 4124 DBG(("%s: using CPU bo with damage? %d\n", 4125 __FUNCTION__, *damage != NULL)); 4126 assert(damage == NULL || !DAMAGE_IS_ALL(*damage)); 4127 assert(priv->clear == false); 4128 priv->cpu = false; 4129 return priv->cpu_bo; 4130} 4131 4132PixmapPtr 4133sna_pixmap_create_upload(ScreenPtr screen, 4134 int width, int height, int depth, 4135 unsigned flags) 4136{ 4137 struct sna *sna = to_sna_from_screen(screen); 4138 PixmapPtr pixmap; 4139 struct sna_pixmap *priv; 4140 void *ptr; 4141 4142 DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__, 4143 width, height, depth, flags)); 4144 assert(width); 4145 assert(height); 4146 4147 if (depth < 8) 4148 return create_pixmap(sna, screen, width, height, depth, 4149 CREATE_PIXMAP_USAGE_SCRATCH); 4150 4151 pixmap = create_pixmap_hdr(sna, screen, 4152 width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, 4153 &priv); 4154 if (!pixmap) 4155 return NullPixmap; 4156 4157 priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem, 4158 width, height, 4159 pixmap->drawable.bitsPerPixel, 4160 flags, &ptr); 4161 if (!priv->gpu_bo) { 4162 free(priv); 4163 FreePixmap(pixmap); 4164 return NullPixmap; 4165 } 4166 4167 /* Marking both the shadow and the GPU bo is a little dubious, 4168 * but will work so long as we always check before doing the 4169 * transfer. 4170 */ 4171 sna_damage_all(&priv->gpu_damage, pixmap); 4172 sna_damage_all(&priv->cpu_damage, pixmap); 4173 4174 pixmap->devKind = priv->gpu_bo->pitch; 4175 pixmap->devPrivate.ptr = ptr; 4176 priv->ptr = MAKE_STATIC_PTR(ptr); 4177 priv->stride = priv->gpu_bo->pitch; 4178 priv->create = 0; 4179 4180 pixmap->usage_hint = 0; 4181 if (!kgem_buffer_is_inplace(priv->gpu_bo)) 4182 pixmap->usage_hint = 1; 4183 4184 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 4185 __FUNCTION__, 4186 pixmap->drawable.serialNumber, 4187 pixmap->drawable.width, 4188 pixmap->drawable.height, 4189 pixmap->usage_hint)); 4190 return pixmap; 4191} 4192 4193static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags) 4194{ 4195 assert(priv->gpu_bo == NULL); 4196 4197 if (priv->cpu_bo == NULL) 4198 return false; 4199 4200 if (priv->shm) 4201 return false; 4202 4203 /* Linear scanout have a restriction that their pitch must be 4204 * 64 byte aligned. Force the creation of a proper GPU bo if 4205 * this CPU bo is not suitable for scanout. 4206 */ 4207 if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT) 4208 if (priv->cpu_bo->pitch & 63) 4209 return false; 4210 4211 if (flags & __MOVE_PRIME) 4212 if (priv->cpu_bo->pitch & 255) 4213 return false; 4214 4215 return true; 4216} 4217 4218struct sna_pixmap * 4219sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags) 4220{ 4221 struct sna *sna = to_sna_from_pixmap(pixmap); 4222 struct sna_pixmap *priv; 4223 const BoxRec *box; 4224 int n; 4225 4226 DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n", 4227 __FUNCTION__, 4228 pixmap->drawable.serialNumber, 4229 pixmap->usage_hint, 4230 flags)); 4231 4232 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 4233 if (priv == NULL) 4234 return NULL; 4235 4236 assert_pixmap_damage(pixmap); 4237 4238 if (priv->move_to_gpu && 4239 !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) { 4240 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 4241 return NULL; 4242 } 4243 4244 if ((flags & MOVE_READ) == 0 && UNDO) 4245 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4246 4247 if (priv->cow) { 4248 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 4249 assert(cow); 4250 if (flags & MOVE_READ && priv->cpu_damage) 4251 cow |= MOVE_WRITE; 4252 if (!sna_pixmap_undo_cow(sna, priv, cow)) 4253 return NULL; 4254 4255 if (priv->gpu_bo == NULL) 4256 sna_damage_destroy(&priv->gpu_damage); 4257 } 4258 4259 if (sna_damage_is_all(&priv->gpu_damage, 4260 pixmap->drawable.width, 4261 pixmap->drawable.height)) { 4262 DBG(("%s: already all-damaged\n", __FUNCTION__)); 4263 sna_pixmap_unclean(sna, priv, flags); 4264 goto active; 4265 } 4266 4267 if ((flags & MOVE_READ) == 0) 4268 sna_damage_destroy(&priv->cpu_damage); 4269 4270 sna_damage_reduce(&priv->cpu_damage); 4271 assert_pixmap_damage(pixmap); 4272 DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL)); 4273 if (priv->gpu_bo == NULL || 4274 kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 4275 struct kgem_bo *proxy; 4276 4277 proxy = priv->gpu_bo; 4278 priv->gpu_bo = NULL; 4279 4280 DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n", 4281 __FUNCTION__, 4282 pixmap->drawable.width, 4283 pixmap->drawable.height, 4284 pixmap->drawable.bitsPerPixel, 4285 priv->create)); 4286 assert(!priv->mapped); 4287 assert(list_is_empty(&priv->flush_list)); 4288 4289 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) { 4290 bool is_linear; 4291 4292 assert(pixmap->drawable.width > 0); 4293 assert(pixmap->drawable.height > 0); 4294 assert(pixmap->drawable.bitsPerPixel >= 8); 4295 4296 if (flags & __MOVE_PRIME) { 4297 assert((flags & __MOVE_TILED) == 0); 4298 is_linear = true; 4299 } else { 4300 is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE; 4301 if (is_linear && flags & __MOVE_TILED) { 4302 DBG(("%s: not creating linear GPU bo\n", 4303 __FUNCTION__)); 4304 return NULL; 4305 } 4306 } 4307 4308 if (is_linear && 4309 can_convert_to_gpu(priv, flags) && 4310 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4311 assert(!priv->mapped); 4312 assert(!IS_STATIC_PTR(priv->ptr)); 4313#ifdef DEBUG_MEMORY 4314 sna->debug_memory.cpu_bo_allocs--; 4315 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4316#endif 4317 priv->gpu_bo = priv->cpu_bo; 4318 priv->cpu_bo = NULL; 4319 priv->ptr = NULL; 4320 pixmap->devPrivate.ptr = NULL; 4321 sna_damage_all(&priv->gpu_damage, pixmap); 4322 sna_damage_destroy(&priv->cpu_damage); 4323 } else { 4324 unsigned create = 0; 4325 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL)) 4326 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4327 if (flags & __MOVE_PRIME) 4328 create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT; 4329 4330 sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4331 } 4332 } 4333 4334 if (priv->gpu_bo == NULL) { 4335 DBG(("%s: not creating GPU bo\n", __FUNCTION__)); 4336 assert(priv->gpu_damage == NULL); 4337 priv->gpu_bo = proxy; 4338 if (proxy) 4339 sna_damage_all(&priv->cpu_damage, pixmap); 4340 return NULL; 4341 } 4342 4343 if (proxy) { 4344 DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle)); 4345 4346 if (priv->cpu_damage && 4347 sna->render.copy_boxes(sna, GXcopy, 4348 &pixmap->drawable, proxy, 0, 0, 4349 &pixmap->drawable, priv->gpu_bo, 0, 0, 4350 region_rects(DAMAGE_REGION(priv->cpu_damage)), 4351 region_num_rects(DAMAGE_REGION(priv->cpu_damage)), 4352 0)) 4353 sna_damage_destroy(&priv->cpu_damage); 4354 4355 kgem_bo_destroy(&sna->kgem, proxy); 4356 } 4357 4358 if (flags & MOVE_WRITE && priv->cpu_damage == NULL) { 4359 /* Presume that we will only ever write to the GPU 4360 * bo. Readbacks are expensive but fairly constant 4361 * in cost for all sizes i.e. it is the act of 4362 * synchronisation that takes the most time. This is 4363 * mitigated by avoiding fallbacks in the first place. 4364 */ 4365 assert(priv->gpu_bo); 4366 assert(priv->gpu_bo->proxy == NULL); 4367 sna_damage_all(&priv->gpu_damage, pixmap); 4368 DBG(("%s: marking as all-damaged for GPU\n", 4369 __FUNCTION__)); 4370 goto active; 4371 } 4372 } 4373 4374 if (priv->gpu_bo->proxy) { 4375 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 4376 assert((flags & MOVE_WRITE) == 0); 4377 assert(priv->gpu_damage == NULL); 4378 return priv; 4379 } 4380 4381 if (priv->cpu_damage == NULL) 4382 goto done; 4383 4384 if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo && 4385 !priv->pinned && !priv->shm && 4386 priv->gpu_bo->tiling == I915_TILING_NONE && 4387 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4388 assert(!priv->mapped); 4389 assert(!IS_STATIC_PTR(priv->ptr)); 4390#ifdef DEBUG_MEMORY 4391 sna->debug_memory.cpu_bo_allocs--; 4392 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4393#endif 4394 sna_pixmap_free_gpu(sna, priv); 4395 priv->gpu_bo = priv->cpu_bo; 4396 priv->cpu_bo = NULL; 4397 priv->ptr = NULL; 4398 pixmap->devPrivate.ptr = NULL; 4399 sna_damage_all(&priv->gpu_damage, pixmap); 4400 sna_damage_destroy(&priv->cpu_damage); 4401 goto done; 4402 } 4403 4404 add_shm_flush(sna, priv); 4405 4406 n = sna_damage_get_boxes(priv->cpu_damage, &box); 4407 assert(n); 4408 if (n) { 4409 bool ok; 4410 4411 assert_pixmap_contains_damage(pixmap, priv->cpu_damage); 4412 DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n)); 4413 4414 ok = false; 4415 if (use_cpu_bo_for_upload(sna, priv, flags)) { 4416 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 4417 ok = sna->render.copy_boxes(sna, GXcopy, 4418 &pixmap->drawable, priv->cpu_bo, 0, 0, 4419 &pixmap->drawable, priv->gpu_bo, 0, 0, 4420 box, n, 0); 4421 } 4422 if (!ok) { 4423 sna_pixmap_unmap(pixmap, priv); 4424 if (pixmap->devPrivate.ptr == NULL) 4425 return NULL; 4426 4427 assert(pixmap->devKind); 4428 if (n == 1 && !priv->pinned && 4429 (box->x2 - box->x1) >= pixmap->drawable.width && 4430 (box->y2 - box->y1) >= pixmap->drawable.height) { 4431 ok = sna_replace(sna, pixmap, 4432 pixmap->devPrivate.ptr, 4433 pixmap->devKind); 4434 } else { 4435 ok = sna_write_boxes(sna, pixmap, 4436 priv->gpu_bo, 0, 0, 4437 pixmap->devPrivate.ptr, 4438 pixmap->devKind, 4439 0, 0, 4440 box, n); 4441 } 4442 if (!ok) 4443 return NULL; 4444 } 4445 } 4446 4447 __sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage)); 4448 priv->cpu_damage = NULL; 4449 4450 /* For large bo, try to keep only a single copy around */ 4451 if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) { 4452 DBG(("%s: disposing of system copy for large/source\n", 4453 __FUNCTION__)); 4454 assert(!priv->shm); 4455 assert(priv->gpu_bo); 4456 assert(priv->gpu_bo->proxy == NULL); 4457 sna_damage_all(&priv->gpu_damage, pixmap); 4458 sna_pixmap_free_cpu(sna, priv, 4459 (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu); 4460 } 4461done: 4462 list_del(&priv->flush_list); 4463 4464 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4465 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4466 sna_pixmap_free_cpu(sna, priv, priv->cpu); 4467 4468active: 4469 if (flags & MOVE_WRITE) { 4470 priv->clear = false; 4471 priv->cpu = false; 4472 } 4473 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 4474 return sna_pixmap_mark_active(sna, priv); 4475} 4476 4477static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap) 4478{ 4479 DBG(("%s: target bpp=%d, source bpp=%d\n", 4480 __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel)); 4481 4482 if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel && 4483 FbEvenTile(pixmap->drawable.width * 4484 pixmap->drawable.bitsPerPixel)) { 4485 DBG(("%s: flushing pixmap\n", __FUNCTION__)); 4486 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 4487 return false; 4488 4489 fbPadPixmap(pixmap); 4490 } 4491 4492 return true; 4493} 4494 4495static bool must_check sna_gc_move_to_cpu(GCPtr gc, 4496 DrawablePtr drawable, 4497 RegionPtr region) 4498{ 4499 struct sna_gc *sgc = sna_gc(gc); 4500 long changes = sgc->changes; 4501 4502 DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes)); 4503 assert(drawable); 4504 assert(region); 4505 4506 assert(gc->ops == (GCOps *)&sna_gc_ops); 4507 gc->ops = (GCOps *)&sna_gc_ops__cpu; 4508 4509 assert(gc->funcs); 4510 sgc->old_funcs = gc->funcs; 4511 gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu; 4512 4513 assert(gc->pCompositeClip); 4514 sgc->priv = gc->pCompositeClip; 4515 gc->pCompositeClip = region; 4516 4517#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 4518 if (gc->clientClipType == CT_PIXMAP) { 4519 PixmapPtr clip = gc->clientClip; 4520 gc->clientClip = region_from_bitmap(gc->pScreen, clip); 4521 gc->pScreen->DestroyPixmap(clip); 4522 gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE; 4523 changes |= GCClipMask; 4524 } else 4525 changes &= ~GCClipMask; 4526#else 4527 changes &= ~GCClipMask; 4528#endif 4529 4530 if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) { 4531 long tmp = gc->serialNumber; 4532 gc->serialNumber = sgc->serial; 4533 4534 if (fb_gc(gc)->bpp != drawable->bitsPerPixel) { 4535 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask; 4536 fb_gc(gc)->bpp = drawable->bitsPerPixel; 4537 } 4538 4539 if (changes & GCTile && !gc->tileIsPixel) { 4540 DBG(("%s: flushing tile pixmap\n", __FUNCTION__)); 4541 if (!sna_validate_pixmap(drawable, gc->tile.pixmap)) 4542 return false; 4543 } 4544 4545 if (changes & GCStipple && gc->stipple) { 4546 DBG(("%s: flushing stipple pixmap\n", __FUNCTION__)); 4547 if (!sna_validate_pixmap(drawable, gc->stipple)) 4548 return false; 4549 } 4550 4551 fbValidateGC(gc, changes, drawable); 4552 gc->serialNumber = tmp; 4553 } 4554 sgc->changes = 0; 4555 4556 switch (gc->fillStyle) { 4557 case FillTiled: 4558 DBG(("%s: moving tile to cpu\n", __FUNCTION__)); 4559 return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ); 4560 case FillStippled: 4561 case FillOpaqueStippled: 4562 DBG(("%s: moving stipple to cpu\n", __FUNCTION__)); 4563 return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ); 4564 default: 4565 return true; 4566 } 4567} 4568 4569static void sna_gc_move_to_gpu(GCPtr gc) 4570{ 4571 DBG(("%s(%p)\n", __FUNCTION__, gc)); 4572 4573 assert(gc->ops == (GCOps *)&sna_gc_ops__cpu); 4574 assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu); 4575 4576 gc->ops = (GCOps *)&sna_gc_ops; 4577 gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs; 4578 assert(gc->funcs); 4579 gc->pCompositeClip = sna_gc(gc)->priv; 4580 assert(gc->pCompositeClip); 4581} 4582 4583static inline bool clip_box(BoxPtr box, GCPtr gc) 4584{ 4585 const BoxRec *clip; 4586 bool clipped; 4587 4588 assert(gc->pCompositeClip); 4589 clip = &gc->pCompositeClip->extents; 4590 4591 clipped = !region_is_singular(gc->pCompositeClip); 4592 if (box->x1 < clip->x1) 4593 box->x1 = clip->x1, clipped = true; 4594 if (box->x2 > clip->x2) 4595 box->x2 = clip->x2, clipped = true; 4596 4597 if (box->y1 < clip->y1) 4598 box->y1 = clip->y1, clipped = true; 4599 if (box->y2 > clip->y2) 4600 box->y2 = clip->y2, clipped = true; 4601 4602 return clipped; 4603} 4604 4605static inline void translate_box(BoxPtr box, DrawablePtr d) 4606{ 4607 box->x1 += d->x; 4608 box->x2 += d->x; 4609 4610 box->y1 += d->y; 4611 box->y2 += d->y; 4612} 4613 4614static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc) 4615{ 4616 translate_box(box, d); 4617 return clip_box(box, gc); 4618} 4619 4620static inline bool box32_clip(Box32Rec *box, GCPtr gc) 4621{ 4622 bool clipped = !region_is_singular(gc->pCompositeClip); 4623 const BoxRec *clip = &gc->pCompositeClip->extents; 4624 4625 if (box->x1 < clip->x1) 4626 box->x1 = clip->x1, clipped = true; 4627 if (box->x2 > clip->x2) 4628 box->x2 = clip->x2, clipped = true; 4629 4630 if (box->y1 < clip->y1) 4631 box->y1 = clip->y1, clipped = true; 4632 if (box->y2 > clip->y2) 4633 box->y2 = clip->y2, clipped = true; 4634 4635 return clipped; 4636} 4637 4638static inline void box32_translate(Box32Rec *box, DrawablePtr d) 4639{ 4640 box->x1 += d->x; 4641 box->x2 += d->x; 4642 4643 box->y1 += d->y; 4644 box->y2 += d->y; 4645} 4646 4647static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc) 4648{ 4649 box32_translate(box, d); 4650 return box32_clip(box, gc); 4651} 4652 4653static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y) 4654{ 4655 if (box->x1 > x) 4656 box->x1 = x; 4657 else if (box->x2 < x) 4658 box->x2 = x; 4659 4660 if (box->y1 > y) 4661 box->y1 = y; 4662 else if (box->y2 < y) 4663 box->y2 = y; 4664} 4665 4666static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt) 4667{ 4668 box_add_xy(box, pt->x, pt->y); 4669} 4670 4671static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16) 4672{ 4673 b16->x1 = b32->x1; 4674 b16->y1 = b32->y1; 4675 b16->x2 = b32->x2; 4676 b16->y2 = b32->y2; 4677 4678 return b16->x2 > b16->x1 && b16->y2 > b16->y1; 4679} 4680 4681static inline void box32_add_rect(Box32Rec *box, const xRectangle *r) 4682{ 4683 int32_t v; 4684 4685 v = r->x; 4686 if (box->x1 > v) 4687 box->x1 = v; 4688 v += r->width; 4689 if (box->x2 < v) 4690 box->x2 = v; 4691 4692 v = r->y; 4693 if (box->y1 > v) 4694 box->y1 = v; 4695 v += r->height; 4696 if (box->y2 < v) 4697 box->y2 = v; 4698} 4699 4700static bool 4701can_create_upload_tiled_x(struct sna *sna, 4702 PixmapPtr pixmap, 4703 struct sna_pixmap *priv, 4704 bool replaces) 4705{ 4706 if (priv->shm || (priv->cpu && !replaces)) 4707 return false; 4708 4709 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 4710 return false; 4711 4712 if (sna->kgem.has_llc) 4713 return true; 4714 4715 if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap)) 4716 return false; 4717 4718 return true; 4719} 4720 4721static bool 4722create_upload_tiled_x(struct sna *sna, 4723 PixmapPtr pixmap, 4724 struct sna_pixmap *priv, 4725 bool replaces) 4726{ 4727 unsigned create; 4728 4729 if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces)) 4730 return false; 4731 4732 assert(priv->gpu_bo == NULL); 4733 assert(priv->gpu_damage == NULL); 4734 4735 if (sna->kgem.has_llc) 4736 create = CREATE_CPU_MAP | CREATE_INACTIVE; 4737 else if (sna->kgem.has_wc_mmap) 4738 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4739 else 4740 create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED; 4741 4742 return sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4743} 4744 4745static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo) 4746{ 4747 return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap; 4748} 4749 4750static bool 4751try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region, 4752 int x, int y, int w, int h, char *bits, int stride) 4753{ 4754 struct sna *sna = to_sna_from_pixmap(pixmap); 4755 struct sna_pixmap *priv = sna_pixmap(pixmap); 4756 const BoxRec *box; 4757 uint8_t *dst; 4758 int n; 4759 4760 if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) { 4761 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4762 return false; 4763 } 4764 4765 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4766 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4767 return false; 4768 4769 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4770 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4771 return false; 4772 4773 if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) { 4774 dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 4775 if (dst == NULL) 4776 return false; 4777 4778 kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo); 4779 } else { 4780 dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo); 4781 if (dst == NULL) 4782 return false; 4783 4784 kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo); 4785 } 4786 4787 box = region_rects(region); 4788 n = region_num_rects(region); 4789 4790 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4791 4792 if (sigtrap_get()) 4793 return false; 4794 4795 if (priv->gpu_bo->tiling) { 4796 do { 4797 DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n", 4798 __FUNCTION__, 4799 box->x1 - x, box->y1 - y, 4800 box->x1, box->y1, 4801 box->x2 - box->x1, box->y2 - box->y1)); 4802 4803 assert(box->x2 > box->x1); 4804 assert(box->y2 > box->y1); 4805 4806 assert(box->x1 >= 0); 4807 assert(box->y1 >= 0); 4808 assert(box->x2 <= pixmap->drawable.width); 4809 assert(box->y2 <= pixmap->drawable.height); 4810 4811 assert(box->x1 - x >= 0); 4812 assert(box->y1 - y >= 0); 4813 assert(box->x2 - x <= w); 4814 assert(box->y2 - y <= h); 4815 4816 memcpy_to_tiled_x(&sna->kgem, bits, dst, 4817 pixmap->drawable.bitsPerPixel, 4818 stride, priv->gpu_bo->pitch, 4819 box->x1 - x, box->y1 - y, 4820 box->x1, box->y1, 4821 box->x2 - box->x1, box->y2 - box->y1); 4822 box++; 4823 } while (--n); 4824 } else { 4825 do { 4826 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4827 __FUNCTION__, 4828 box->x1 - x, box->y1 - y, 4829 box->x1, box->y1, 4830 box->x2 - box->x1, box->y2 - box->y1)); 4831 4832 assert(box->x2 > box->x1); 4833 assert(box->y2 > box->y1); 4834 4835 assert(box->x1 >= 0); 4836 assert(box->y1 >= 0); 4837 assert(box->x2 <= pixmap->drawable.width); 4838 assert(box->y2 <= pixmap->drawable.height); 4839 4840 assert(box->x1 - x >= 0); 4841 assert(box->y1 - y >= 0); 4842 assert(box->x2 - x <= w); 4843 assert(box->y2 - y <= h); 4844 4845 memcpy_blt(bits, dst, 4846 pixmap->drawable.bitsPerPixel, 4847 stride, priv->gpu_bo->pitch, 4848 box->x1 - x, box->y1 - y, 4849 box->x1, box->y1, 4850 box->x2 - box->x1, box->y2 - box->y1); 4851 box++; 4852 } while (--n); 4853 4854 if (!priv->shm) { 4855 pixmap->devPrivate.ptr = dst; 4856 pixmap->devKind = priv->gpu_bo->pitch; 4857 if (dst == MAP(priv->gpu_bo->map__cpu)) { 4858 priv->mapped = MAPPED_CPU; 4859 priv->cpu = true; 4860 } else 4861 priv->mapped = MAPPED_GTT; 4862 assert_pixmap_map(pixmap, priv); 4863 } 4864 } 4865 4866 sigtrap_put(); 4867 return true; 4868} 4869 4870static bool 4871try_upload__inplace(PixmapPtr pixmap, RegionRec *region, 4872 int x, int y, int w, int h, char *bits, int stride) 4873{ 4874 struct sna *sna = to_sna_from_pixmap(pixmap); 4875 struct sna_pixmap *priv = sna_pixmap(pixmap); 4876 bool ignore_cpu = false; 4877 bool replaces; 4878 const BoxRec *box; 4879 uint8_t *dst; 4880 int n; 4881 4882 if (!USE_INPLACE) 4883 return false; 4884 4885 assert(priv); 4886 4887 if (priv->shm && priv->gpu_damage == NULL) 4888 return false; 4889 4890 replaces = region_subsumes_pixmap(region, pixmap); 4891 4892 DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__, 4893 priv->gpu_bo != NULL, 4894 priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0, 4895 replaces)); 4896 4897 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 4898 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 4899 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 4900 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 4901 assert(!priv->pinned); 4902 assert(!priv->mapped); 4903 sna_damage_destroy(&priv->gpu_damage); 4904 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 4905 priv->gpu_bo = NULL; 4906 } 4907 4908 if (priv->gpu_bo && replaces) { 4909 if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4910 if (can_create_upload_tiled_x(sna, pixmap, priv, true) && 4911 (priv->cow || 4912 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4913 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4914 DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4915 kgem_bo_is_busy(priv->gpu_bo), 4916 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4917 sna_pixmap_free_gpu(sna, priv); 4918 ignore_cpu = true; 4919 } 4920 } 4921 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4922 4923 if (priv->cow || 4924 (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) { 4925 DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n", 4926 __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL)); 4927 return false; 4928 } 4929 4930 if (priv->gpu_damage && 4931 region_subsumes_damage(region, priv->gpu_damage)) { 4932 if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo); 4933 if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) && 4934 (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4935 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4936 DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4937 kgem_bo_is_busy(priv->gpu_bo), 4938 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4939 sna_pixmap_free_gpu(sna, priv); 4940 ignore_cpu = priv->cpu_damage == NULL; 4941 if (priv->ptr) 4942 sna_damage_all(&priv->cpu_damage, pixmap); 4943 } 4944 } 4945 4946 if (priv->gpu_bo == NULL && 4947 !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu)) 4948 return false; 4949 4950 DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling)); 4951 switch (priv->gpu_bo->tiling) { 4952 case I915_TILING_Y: 4953 break; 4954 case I915_TILING_X: 4955 if (!sna->kgem.memcpy_to_tiled_x) 4956 break; 4957 default: 4958 if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride)) 4959 goto done; 4960 break; 4961 } 4962 4963 if (priv->gpu_damage == NULL && !box_inplace(pixmap, ®ion->extents)) { 4964 DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__)); 4965 return false; 4966 } 4967 4968 if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 4969 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4970 return false; 4971 } 4972 4973 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4974 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4975 return false; 4976 4977 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4978 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4979 return false; 4980 4981 dst = kgem_bo_map(&sna->kgem, priv->gpu_bo); 4982 if (dst == NULL) 4983 return false; 4984 4985 pixmap->devPrivate.ptr = dst; 4986 pixmap->devKind = priv->gpu_bo->pitch; 4987 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 4988 priv->cpu &= priv->mapped == MAPPED_CPU; 4989 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 4990 4991 box = region_rects(region); 4992 n = region_num_rects(region); 4993 4994 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4995 4996 if (sigtrap_get()) 4997 return false; 4998 4999 do { 5000 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 5001 __FUNCTION__, 5002 box->x1 - x, box->y1 - y, 5003 box->x1, box->y1, 5004 box->x2 - box->x1, box->y2 - box->y1)); 5005 5006 assert(box->x2 > box->x1); 5007 assert(box->y2 > box->y1); 5008 5009 assert(box->x1 >= 0); 5010 assert(box->y1 >= 0); 5011 assert(box->x2 <= pixmap->drawable.width); 5012 assert(box->y2 <= pixmap->drawable.height); 5013 5014 assert(box->x1 - x >= 0); 5015 assert(box->y1 - y >= 0); 5016 assert(box->x2 - x <= w); 5017 assert(box->y2 - y <= h); 5018 5019 memcpy_blt(bits, dst, 5020 pixmap->drawable.bitsPerPixel, 5021 stride, priv->gpu_bo->pitch, 5022 box->x1 - x, box->y1 - y, 5023 box->x1, box->y1, 5024 box->x2 - box->x1, box->y2 - box->y1); 5025 box++; 5026 } while (--n); 5027 5028 sigtrap_put(); 5029 5030done: 5031 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5032 if (replaces) { 5033 sna_damage_all(&priv->gpu_damage, pixmap); 5034 } else { 5035 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5036 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 5037 } 5038 if (DAMAGE_IS_ALL(priv->gpu_damage)) 5039 sna_damage_destroy(&priv->cpu_damage); 5040 else 5041 sna_damage_subtract(&priv->cpu_damage, region); 5042 5043 if (priv->cpu_damage == NULL) { 5044 list_del(&priv->flush_list); 5045 sna_damage_all(&priv->gpu_damage, pixmap); 5046 } 5047 5048 add_shm_flush(sna, priv); 5049 } 5050 5051 assert(!priv->clear); 5052 return true; 5053} 5054 5055static bool 5056try_upload__blt(PixmapPtr pixmap, RegionRec *region, 5057 int x, int y, int w, int h, char *bits, int stride) 5058{ 5059 struct sna *sna = to_sna_from_pixmap(pixmap); 5060 struct sna_pixmap *priv; 5061 struct kgem_bo *src_bo; 5062 bool ok; 5063 5064 if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS) 5065 return false; 5066 5067 priv = sna_pixmap(pixmap); 5068 assert(priv); 5069 assert(priv->gpu_bo); 5070 assert(priv->gpu_bo->proxy == NULL); 5071 5072 if (priv->cpu_damage && 5073 (DAMAGE_IS_ALL(priv->cpu_damage) || 5074 sna_damage_contains_box__no_reduce(priv->cpu_damage, 5075 ®ion->extents)) && 5076 !box_inplace(pixmap, ®ion->extents)) { 5077 DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__)); 5078 return false; 5079 } 5080 5081 src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true); 5082 if (src_bo == NULL) 5083 return false; 5084 5085 src_bo->pitch = stride; 5086 kgem_bo_mark_unreusable(src_bo); 5087 5088 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 5089 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) { 5090 kgem_bo_destroy(&sna->kgem, src_bo); 5091 return false; 5092 } 5093 5094 DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n", 5095 __FUNCTION__, x, y, w, h, region_num_rects(region))); 5096 5097 if (sigtrap_get() == 0) { 5098 ok = sna->render.copy_boxes(sna, GXcopy, 5099 &pixmap->drawable, src_bo, -x, -y, 5100 &pixmap->drawable, priv->gpu_bo, 0, 0, 5101 region_rects(region), 5102 region_num_rects(region), 5103 COPY_LAST); 5104 sigtrap_put(); 5105 } else 5106 ok = false; 5107 5108 kgem_bo_sync__cpu(&sna->kgem, src_bo); 5109 assert(src_bo->rq == NULL); 5110 kgem_bo_destroy(&sna->kgem, src_bo); 5111 5112 if (!ok) { 5113 DBG(("%s: copy failed!\n", __FUNCTION__)); 5114 return false; 5115 } 5116 5117 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5118 assert(!priv->clear); 5119 if (region_subsumes_drawable(region, &pixmap->drawable)) { 5120 sna_damage_all(&priv->gpu_damage, pixmap); 5121 } else { 5122 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5123 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 5124 } 5125 if (DAMAGE_IS_ALL(priv->gpu_damage)) 5126 sna_damage_destroy(&priv->cpu_damage); 5127 else 5128 sna_damage_subtract(&priv->cpu_damage, region); 5129 if (priv->cpu_damage == NULL) { 5130 list_del(&priv->flush_list); 5131 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) 5132 sna_damage_all(&priv->gpu_damage, pixmap); 5133 } 5134 } 5135 priv->cpu = false; 5136 priv->clear = false; 5137 5138 return true; 5139} 5140 5141static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region) 5142{ 5143 if (region_subsumes_pixmap(region, priv->pixmap)) 5144 return true; 5145 5146 if (priv->cpu_damage != NULL) { 5147 if (DAMAGE_IS_ALL(priv->cpu_damage)) 5148 return false; 5149 5150 if (!box_inplace(priv->pixmap, ®ion->extents)) 5151 return false; 5152 5153 if (sna_damage_contains_box__no_reduce(priv->cpu_damage, ®ion->extents)) 5154 return false; 5155 } 5156 5157 return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo); 5158 5159} 5160 5161static bool 5162try_upload__fast(PixmapPtr pixmap, RegionRec *region, 5163 int x, int y, int w, int h, char *bits, int stride) 5164{ 5165 struct sna *sna = to_sna_from_pixmap(pixmap); 5166 struct sna_pixmap *priv; 5167 5168 if (wedged(sna)) 5169 return false; 5170 5171 priv = sna_pixmap(pixmap); 5172 if (priv == NULL) 5173 return false; 5174 5175 if (ignore_cpu_damage(sna, priv, region)) { 5176 DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__)); 5177 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5178 return true; 5179 } 5180 5181 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) { 5182 DBG(("%s: no, no gpu damage\n", __FUNCTION__)); 5183 return false; 5184 } 5185 5186 assert(priv->gpu_bo); 5187 assert(priv->gpu_bo->proxy == NULL); 5188 5189 if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride)) 5190 return true; 5191 5192 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5193 return true; 5194 5195 return false; 5196} 5197 5198static bool 5199sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5200 int x, int y, int w, int h, char *bits, int stride) 5201{ 5202 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5203 unsigned int hint; 5204 const BoxRec *box; 5205 int16_t dx, dy; 5206 int n; 5207 5208 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5209 5210 if (gc->alu != GXcopy) 5211 return false; 5212 5213 if (drawable->depth < 8) 5214 return false; 5215 5216 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5217 x += dx + drawable->x; 5218 y += dy + drawable->y; 5219 assert(region->extents.x1 >= x); 5220 assert(region->extents.y1 >= y); 5221 assert(region->extents.x2 <= x + w); 5222 assert(region->extents.y2 <= y + h); 5223 5224 if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride)) 5225 return true; 5226 5227 hint = MOVE_WRITE; 5228 if (region_is_unclipped(region, pixmap->drawable.width, h) && 5229 (h+1)*stride > 65536) { 5230 DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n", 5231 __FUNCTION__, h*stride)); 5232 hint |= MOVE_WHOLE_HINT; 5233 } 5234 5235 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint)) 5236 return false; 5237 5238 if (sigtrap_get()) 5239 return false; 5240 5241 /* Region is pre-clipped and translated into pixmap space */ 5242 box = region_rects(region); 5243 n = region_num_rects(region); 5244 DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n)); 5245 do { 5246 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 5247 __FUNCTION__, 5248 box->x1 - x, box->y1 - y, 5249 box->x1, box->y1, 5250 box->x2 - box->x1, box->y2 - box->y1)); 5251 5252 assert(box->x2 > box->x1); 5253 assert(box->y2 > box->y1); 5254 5255 assert(box->x1 >= 0); 5256 assert(box->y1 >= 0); 5257 assert(box->x2 <= pixmap->drawable.width); 5258 assert(box->y2 <= pixmap->drawable.height); 5259 5260 assert(box->x1 - x >= 0); 5261 assert(box->y1 - y >= 0); 5262 assert(box->x2 - x <= w); 5263 assert(box->y2 - y <= h); 5264 5265 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE)); 5266 assert(pixmap->devKind); 5267 memcpy_blt(bits, pixmap->devPrivate.ptr, 5268 pixmap->drawable.bitsPerPixel, 5269 stride, pixmap->devKind, 5270 box->x1 - x, box->y1 - y, 5271 box->x1, box->y1, 5272 box->x2 - box->x1, box->y2 - box->y1); 5273 box++; 5274 } while (--n); 5275 5276 sigtrap_put(); 5277 assert_pixmap_damage(pixmap); 5278 return true; 5279} 5280 5281static inline uint8_t byte_reverse(uint8_t b) 5282{ 5283 return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; 5284} 5285 5286static inline uint8_t blt_depth(int depth) 5287{ 5288 switch (depth) { 5289 case 8: return 0; 5290 case 15: return 0x2; 5291 case 16: return 0x1; 5292 default: return 0x3; 5293 } 5294} 5295 5296inline static void blt_done(struct sna *sna) 5297{ 5298 sna->blt_state.fill_bo = 0; 5299 if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) { 5300 DBG(("%s: flushing BLT operation on empty ring\n", 5301 __FUNCTION__)); 5302 _kgem_submit(&sna->kgem); 5303 } 5304} 5305 5306static bool 5307sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5308 int x, int y, int w, int h, char *bits) 5309{ 5310 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5311 struct sna *sna = to_sna_from_pixmap(pixmap); 5312 struct sna_damage **damage; 5313 struct kgem_bo *bo; 5314 const BoxRec *box; 5315 int16_t dx, dy; 5316 int n; 5317 uint8_t rop = copy_ROP[gc->alu]; 5318 5319 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5320 ®ion->extents, &damage); 5321 if (bo == NULL) 5322 return false; 5323 5324 if (bo->tiling == I915_TILING_Y) { 5325 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5326 assert(bo == __sna_pixmap_get_bo(pixmap)); 5327 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5328 if (bo == NULL) { 5329 DBG(("%s: fallback -- unable to change tiling\n", 5330 __FUNCTION__)); 5331 return false; 5332 } 5333 } 5334 5335 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5336 return false; 5337 5338 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5339 if (damage) 5340 sna_damage_add_to_pixmap(damage, region, pixmap); 5341 assert_pixmap_damage(pixmap); 5342 5343 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5344 5345 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5346 x += dx + drawable->x; 5347 y += dy + drawable->y; 5348 5349 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5350 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5351 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5352 5353 /* Region is pre-clipped and translated into pixmap space */ 5354 box = region_rects(region); 5355 n = region_num_rects(region); 5356 do { 5357 int bx1 = (box->x1 - x) & ~7; 5358 int bx2 = (box->x2 - x + 7) & ~7; 5359 int bw = (bx2 - bx1)/8; 5360 int bh = box->y2 - box->y1; 5361 int bstride = ALIGN(bw, 2); 5362 struct kgem_bo *upload; 5363 void *ptr; 5364 5365 if (!kgem_check_batch(&sna->kgem, 10) || 5366 !kgem_check_bo_fenced(&sna->kgem, bo) || 5367 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5368 kgem_submit(&sna->kgem); 5369 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5370 return false; 5371 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5372 } 5373 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5374 5375 upload = kgem_create_buffer(&sna->kgem, 5376 bstride*bh, 5377 KGEM_BUFFER_WRITE_INPLACE, 5378 &ptr); 5379 if (!upload) 5380 break; 5381 5382 5383 if (sigtrap_get() == 0) { 5384 int src_stride = BitmapBytePad(w); 5385 uint8_t *dst = ptr; 5386 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5387 uint32_t *b; 5388 5389 bstride -= bw; 5390 src_stride -= bw; 5391 5392 do { 5393 int i = bw; 5394 assert(src >= (uint8_t *)bits); 5395 do { 5396 *dst++ = byte_reverse(*src++); 5397 } while (--i); 5398 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5399 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5400 dst += bstride; 5401 src += src_stride; 5402 } while (--bh); 5403 5404 assert(sna->kgem.mode == KGEM_BLT); 5405 if (sna->kgem.gen >= 0100) { 5406 b = sna->kgem.batch + sna->kgem.nbatch; 5407 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 5408 b[0] |= ((box->x1 - x) & 7) << 17; 5409 b[1] = bo->pitch; 5410 if (bo->tiling) { 5411 b[0] |= BLT_DST_TILED; 5412 b[1] >>= 2; 5413 } 5414 b[1] |= blt_depth(drawable->depth) << 24; 5415 b[1] |= rop << 16; 5416 b[2] = box->y1 << 16 | box->x1; 5417 b[3] = box->y2 << 16 | box->x2; 5418 *(uint64_t *)(b+4) = 5419 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5420 I915_GEM_DOMAIN_RENDER << 16 | 5421 I915_GEM_DOMAIN_RENDER | 5422 KGEM_RELOC_FENCED, 5423 0); 5424 *(uint64_t *)(b+6) = 5425 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5426 I915_GEM_DOMAIN_RENDER << 16 | 5427 KGEM_RELOC_FENCED, 5428 0); 5429 b[8] = gc->bgPixel; 5430 b[9] = gc->fgPixel; 5431 5432 sna->kgem.nbatch += 10; 5433 } else { 5434 b = sna->kgem.batch + sna->kgem.nbatch; 5435 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 5436 b[0] |= ((box->x1 - x) & 7) << 17; 5437 b[1] = bo->pitch; 5438 if (sna->kgem.gen >= 040 && bo->tiling) { 5439 b[0] |= BLT_DST_TILED; 5440 b[1] >>= 2; 5441 } 5442 b[1] |= blt_depth(drawable->depth) << 24; 5443 b[1] |= rop << 16; 5444 b[2] = box->y1 << 16 | box->x1; 5445 b[3] = box->y2 << 16 | box->x2; 5446 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5447 I915_GEM_DOMAIN_RENDER << 16 | 5448 I915_GEM_DOMAIN_RENDER | 5449 KGEM_RELOC_FENCED, 5450 0); 5451 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5452 I915_GEM_DOMAIN_RENDER << 16 | 5453 KGEM_RELOC_FENCED, 5454 0); 5455 b[6] = gc->bgPixel; 5456 b[7] = gc->fgPixel; 5457 5458 sna->kgem.nbatch += 8; 5459 } 5460 sigtrap_put(); 5461 } 5462 kgem_bo_destroy(&sna->kgem, upload); 5463 5464 box++; 5465 } while (--n); 5466 5467 blt_done(sna); 5468 return true; 5469} 5470 5471static bool 5472sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5473 int x, int y, int w, int h, int left,char *bits) 5474{ 5475 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5476 struct sna *sna = to_sna_from_pixmap(pixmap); 5477 struct sna_damage **damage; 5478 struct kgem_bo *bo; 5479 int16_t dx, dy; 5480 unsigned i, skip; 5481 5482 if (gc->alu != GXcopy) 5483 return false; 5484 5485 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5486 ®ion->extents, &damage); 5487 if (bo == NULL) 5488 return false; 5489 5490 if (bo->tiling == I915_TILING_Y) { 5491 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5492 assert(bo == __sna_pixmap_get_bo(pixmap)); 5493 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5494 if (bo == NULL) { 5495 DBG(("%s: fallback -- unable to change tiling\n", 5496 __FUNCTION__)); 5497 return false; 5498 } 5499 } 5500 5501 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5502 return false; 5503 5504 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5505 if (damage) 5506 sna_damage_add_to_pixmap(damage, region, pixmap); 5507 assert_pixmap_damage(pixmap); 5508 5509 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5510 5511 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5512 x += dx + drawable->x; 5513 y += dy + drawable->y; 5514 5515 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5516 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5517 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5518 5519 skip = h * BitmapBytePad(w + left); 5520 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { 5521 const BoxRec *box = region_rects(region); 5522 int n = region_num_rects(region); 5523 5524 if ((gc->planemask & i) == 0) 5525 continue; 5526 5527 /* Region is pre-clipped and translated into pixmap space */ 5528 do { 5529 int bx1 = (box->x1 - x) & ~7; 5530 int bx2 = (box->x2 - x + 7) & ~7; 5531 int bw = (bx2 - bx1)/8; 5532 int bh = box->y2 - box->y1; 5533 int bstride = ALIGN(bw, 2); 5534 struct kgem_bo *upload; 5535 void *ptr; 5536 5537 if (!kgem_check_batch(&sna->kgem, 14) || 5538 !kgem_check_bo_fenced(&sna->kgem, bo) || 5539 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5540 kgem_submit(&sna->kgem); 5541 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5542 return false; 5543 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5544 } 5545 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5546 5547 upload = kgem_create_buffer(&sna->kgem, 5548 bstride*bh, 5549 KGEM_BUFFER_WRITE_INPLACE, 5550 &ptr); 5551 if (!upload) 5552 break; 5553 5554 if (sigtrap_get() == 0) { 5555 int src_stride = BitmapBytePad(w); 5556 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5557 uint8_t *dst = ptr; 5558 uint32_t *b; 5559 5560 bstride -= bw; 5561 src_stride -= bw; 5562 do { 5563 int j = bw; 5564 assert(src >= (uint8_t *)bits); 5565 do { 5566 *dst++ = byte_reverse(*src++); 5567 } while (--j); 5568 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5569 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5570 dst += bstride; 5571 src += src_stride; 5572 } while (--bh); 5573 5574 assert(sna->kgem.mode == KGEM_BLT); 5575 if (sna->kgem.gen >= 0100) { 5576 assert(sna->kgem.mode == KGEM_BLT); 5577 b = sna->kgem.batch + sna->kgem.nbatch; 5578 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12; 5579 b[0] |= ((box->x1 - x) & 7) << 17; 5580 b[1] = bo->pitch; 5581 if (bo->tiling) { 5582 b[0] |= BLT_DST_TILED; 5583 b[1] >>= 2; 5584 } 5585 b[1] |= 1 << 31; /* solid pattern */ 5586 b[1] |= blt_depth(drawable->depth) << 24; 5587 b[1] |= 0xce << 16; /* S or (D and !P) */ 5588 b[2] = box->y1 << 16 | box->x1; 5589 b[3] = box->y2 << 16 | box->x2; 5590 *(uint64_t *)(b+4) = 5591 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5592 I915_GEM_DOMAIN_RENDER << 16 | 5593 I915_GEM_DOMAIN_RENDER | 5594 KGEM_RELOC_FENCED, 5595 0); 5596 *(uint64_t *)(b+6) = 5597 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5598 I915_GEM_DOMAIN_RENDER << 16 | 5599 KGEM_RELOC_FENCED, 5600 0); 5601 b[8] = 0; 5602 b[9] = i; 5603 b[10] = i; 5604 b[11] = i; 5605 b[12] = -1; 5606 b[13] = -1; 5607 sna->kgem.nbatch += 14; 5608 } else { 5609 b = sna->kgem.batch + sna->kgem.nbatch; 5610 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10; 5611 b[0] |= ((box->x1 - x) & 7) << 17; 5612 b[1] = bo->pitch; 5613 if (sna->kgem.gen >= 040 && bo->tiling) { 5614 b[0] |= BLT_DST_TILED; 5615 b[1] >>= 2; 5616 } 5617 b[1] |= 1 << 31; /* solid pattern */ 5618 b[1] |= blt_depth(drawable->depth) << 24; 5619 b[1] |= 0xce << 16; /* S or (D and !P) */ 5620 b[2] = box->y1 << 16 | box->x1; 5621 b[3] = box->y2 << 16 | box->x2; 5622 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5623 I915_GEM_DOMAIN_RENDER << 16 | 5624 I915_GEM_DOMAIN_RENDER | 5625 KGEM_RELOC_FENCED, 5626 0); 5627 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5628 I915_GEM_DOMAIN_RENDER << 16 | 5629 KGEM_RELOC_FENCED, 5630 0); 5631 b[6] = 0; 5632 b[7] = i; 5633 b[8] = i; 5634 b[9] = i; 5635 b[10] = -1; 5636 b[11] = -1; 5637 sna->kgem.nbatch += 12; 5638 } 5639 sigtrap_put(); 5640 } 5641 kgem_bo_destroy(&sna->kgem, upload); 5642 5643 box++; 5644 } while (--n); 5645 } 5646 5647 blt_done(sna); 5648 return true; 5649} 5650 5651static void 5652sna_put_image(DrawablePtr drawable, GCPtr gc, int depth, 5653 int x, int y, int w, int h, int left, int format, 5654 char *bits) 5655{ 5656 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5657 struct sna *sna = to_sna_from_pixmap(pixmap); 5658 struct sna_pixmap *priv = sna_pixmap(pixmap); 5659 RegionRec region; 5660 int16_t dx, dy; 5661 5662 DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n", 5663 __FUNCTION__, x, y, w, h, depth, format)); 5664 5665 if (w == 0 || h == 0) 5666 return; 5667 5668 region.extents.x1 = x + drawable->x; 5669 region.extents.y1 = y + drawable->y; 5670 region.extents.x2 = region.extents.x1 + w; 5671 region.extents.y2 = region.extents.y1 + h; 5672 region.data = NULL; 5673 5674 if (!region_is_singular(gc->pCompositeClip) || 5675 gc->pCompositeClip->extents.x1 > region.extents.x1 || 5676 gc->pCompositeClip->extents.y1 > region.extents.y1 || 5677 gc->pCompositeClip->extents.x2 < region.extents.x2 || 5678 gc->pCompositeClip->extents.y2 < region.extents.y2) { 5679 if (!RegionIntersect(®ion, ®ion, gc->pCompositeClip) || 5680 box_empty(®ion.extents)) 5681 return; 5682 } 5683 5684 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 5685 RegionTranslate(®ion, dx, dy); 5686 5687 if (priv == NULL) { 5688 DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n", 5689 __FUNCTION__, x, y, w, h)); 5690 goto fallback; 5691 } 5692 5693 if (FORCE_FALLBACK) 5694 goto fallback; 5695 5696 if (wedged(sna)) 5697 goto fallback; 5698 5699 if (!ACCEL_PUT_IMAGE) 5700 goto fallback; 5701 5702 switch (format) { 5703 case ZPixmap: 5704 if (!PM_IS_SOLID(drawable, gc->planemask)) 5705 goto fallback; 5706 5707 if (sna_put_zpixmap_blt(drawable, gc, ®ion, 5708 x, y, w, h, 5709 bits, PixmapBytePad(w, depth))) 5710 return; 5711 break; 5712 5713 case XYBitmap: 5714 if (!PM_IS_SOLID(drawable, gc->planemask)) 5715 goto fallback; 5716 5717 if (sna_put_xybitmap_blt(drawable, gc, ®ion, 5718 x, y, w, h, 5719 bits)) 5720 return; 5721 break; 5722 5723 case XYPixmap: 5724 if (sna_put_xypixmap_blt(drawable, gc, ®ion, 5725 x, y, w, h, left, 5726 bits)) 5727 return; 5728 break; 5729 5730 default: 5731 return; 5732 } 5733 5734fallback: 5735 DBG(("%s: fallback\n", __FUNCTION__)); 5736 RegionTranslate(®ion, -dx, -dy); 5737 5738 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 5739 goto out; 5740 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 5741 format == XYPixmap ? 5742 MOVE_READ | MOVE_WRITE : 5743 drawable_gc_flags(drawable, gc, false))) 5744 goto out; 5745 5746 if (sigtrap_get() == 0) { 5747 DBG(("%s: fbPutImage(%d, %d, %d, %d)\n", 5748 __FUNCTION__, x, y, w, h)); 5749 fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits); 5750 FALLBACK_FLUSH(drawable); 5751 sigtrap_put(); 5752 } 5753out: 5754 sna_gc_move_to_gpu(gc); 5755 RegionUninit(®ion); 5756} 5757 5758static bool 5759source_contains_region(struct sna_damage *damage, 5760 const RegionRec *region, int16_t dx, int16_t dy) 5761{ 5762 BoxRec box; 5763 5764 if (DAMAGE_IS_ALL(damage)) 5765 return true; 5766 5767 if (damage == NULL) 5768 return false; 5769 5770 box = region->extents; 5771 box.x1 += dx; 5772 box.x2 += dx; 5773 box.y1 += dy; 5774 box.y2 += dy; 5775 return sna_damage_contains_box__no_reduce(damage, &box); 5776} 5777 5778static bool 5779move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv, 5780 RegionRec *region, int16_t dx, int16_t dy, 5781 uint8_t alu, bool dst_is_gpu) 5782{ 5783 int w = region->extents.x2 - region->extents.x1; 5784 int h = region->extents.y2 - region->extents.y1; 5785 int count; 5786 5787 assert_pixmap_map(pixmap, priv); 5788 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 5789 assert(priv->gpu_bo); 5790 return true; 5791 } 5792 5793 if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) { 5794 DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n", 5795 __FUNCTION__, 5796 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5797 priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0, 5798 priv->cpu)); 5799 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 5800 return false; 5801 5802 if (priv->cpu && 5803 source_contains_region(priv->cpu_damage, region, dx, dy)) 5804 return false; 5805 } 5806 5807 if (priv->gpu_bo) { 5808 DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n", 5809 __FUNCTION__, 5810 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5811 priv->cpu, priv->gpu_bo->tiling)); 5812 5813 if (priv->cpu_damage == NULL) 5814 return true; 5815 5816 if (alu != GXcopy) 5817 return true; 5818 5819 if (!priv->cpu) 5820 return true; 5821 5822 if (priv->gpu_bo->tiling) 5823 return true; 5824 5825 RegionTranslate(region, dx, dy); 5826 count = region_subsumes_damage(region, priv->cpu_damage); 5827 RegionTranslate(region, -dx, -dy); 5828 if (count) 5829 return true; 5830 } else { 5831 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 5832 return false; 5833 if (priv->shm) 5834 return false; 5835 } 5836 5837 count = priv->source_count++; 5838 if (priv->cpu_bo) { 5839 if (priv->cpu_bo->flush && count > SOURCE_BIAS) 5840 return true; 5841 5842 if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE) 5843 return false; 5844 5845 if (priv->cpu) 5846 return false; 5847 5848 return count > SOURCE_BIAS; 5849 } else { 5850 if (w == pixmap->drawable.width && h == pixmap->drawable.height) 5851 return count > SOURCE_BIAS; 5852 5853 return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height; 5854 } 5855} 5856 5857static const BoxRec * 5858reorder_boxes(const BoxRec *box, int n, int dx, int dy) 5859{ 5860 const BoxRec *next, *base; 5861 BoxRec *new; 5862 5863 DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy)); 5864 5865 if (dy <= 0 && dx <= 0) { 5866 BoxRec *tmp; 5867 5868 new = malloc(sizeof(BoxRec) * n); 5869 if (new == NULL) 5870 return NULL; 5871 5872 tmp = new; 5873 next = box + n; 5874 do { 5875 *tmp++ = *--next; 5876 } while (next != box); 5877 } else if (dy < 0) { 5878 new = malloc(sizeof(BoxRec) * n); 5879 if (new == NULL) 5880 return NULL; 5881 5882 base = next = box + n - 1; 5883 while (base >= box) { 5884 const BoxRec *tmp; 5885 5886 while (next >= box && base->y1 == next->y1) 5887 next--; 5888 tmp = next + 1; 5889 while (tmp <= base) 5890 *new++ = *tmp++; 5891 base = next; 5892 } 5893 new -= n; 5894 } else { 5895 new = malloc(sizeof(BoxRec) * n); 5896 if (!new) 5897 return NULL; 5898 5899 base = next = box; 5900 while (base < box + n) { 5901 const BoxRec *tmp; 5902 5903 while (next < box + n && next->y1 == base->y1) 5904 next++; 5905 tmp = next; 5906 while (tmp != base) 5907 *new++ = *--tmp; 5908 base = next; 5909 } 5910 new -= n; 5911 } 5912 5913 return new; 5914} 5915 5916static void 5917sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5918 RegionPtr region,int dx, int dy, 5919 Pixel bitplane, void *closure) 5920{ 5921 PixmapPtr pixmap = get_drawable_pixmap(src); 5922 struct sna *sna = to_sna_from_pixmap(pixmap); 5923 struct sna_pixmap *priv = sna_pixmap(pixmap); 5924 const BoxRec *box = region_rects(region); 5925 int n = region_num_rects(region); 5926 int alu = gc ? gc->alu : GXcopy; 5927 int16_t tx, ty, sx, sy; 5928 5929 assert(pixmap == get_drawable_pixmap(dst)); 5930 5931 assert(region_num_rects(region)); 5932 if (((dx | dy) == 0 && alu == GXcopy)) 5933 return; 5934 5935 if (n > 1 && (dx | dy) < 0) { 5936 box = reorder_boxes(box, n, dx, dy); 5937 if (box == NULL) 5938 return; 5939 } 5940 5941 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n", 5942 __FUNCTION__, n, 5943 region->extents.x1, region->extents.y1, 5944 region->extents.x2, region->extents.y2, 5945 dx, dy, alu, 5946 pixmap->drawable.width, pixmap->drawable.height)); 5947 5948 get_drawable_deltas(dst, pixmap, &tx, &ty); 5949 get_drawable_deltas(src, pixmap, &sx, &sy); 5950 sx += dx; 5951 sy += dy; 5952 5953 if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) { 5954 DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__)); 5955 goto fallback; 5956 } 5957 5958 if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) { 5959 assert(priv->gpu_bo); 5960 5961 if (alu == GXcopy && priv->clear) 5962 goto free_boxes; 5963 5964 assert(priv->gpu_bo->proxy == NULL); 5965 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) { 5966 DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n", 5967 __FUNCTION__)); 5968 goto fallback; 5969 } 5970 assert(priv->cpu_damage == NULL); 5971 5972 if (!sna->render.copy_boxes(sna, alu, 5973 &pixmap->drawable, priv->gpu_bo, sx, sy, 5974 &pixmap->drawable, priv->gpu_bo, tx, ty, 5975 box, n, small_copy(region))) { 5976 DBG(("%s: fallback - accelerated copy boxes failed\n", 5977 __FUNCTION__)); 5978 goto fallback; 5979 } 5980 5981 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5982 assert(!priv->clear); 5983 if (sna_pixmap_free_cpu(sna, priv, false)) { 5984 sna_damage_all(&priv->gpu_damage, pixmap); 5985 } else { 5986 RegionTranslate(region, tx, ty); 5987 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5988 } 5989 } 5990 assert_pixmap_damage(pixmap); 5991 } else { 5992fallback: 5993 DBG(("%s: fallback\n", __FUNCTION__)); 5994 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 5995 goto free_boxes; 5996 5997 if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) { 5998 assert(pixmap->devKind); 5999 if (sigtrap_get() == 0) { 6000 FbBits *dst_bits, *src_bits; 6001 int stride = pixmap->devKind; 6002 int bpp = pixmap->drawable.bitsPerPixel; 6003 int i; 6004 6005 dst_bits = (FbBits *) 6006 ((char *)pixmap->devPrivate.ptr + 6007 ty * stride + tx * bpp / 8); 6008 src_bits = (FbBits *) 6009 ((char *)pixmap->devPrivate.ptr + 6010 sy * stride + sx * bpp / 8); 6011 6012 for (i = 0; i < n; i++) 6013 memmove_box(src_bits, dst_bits, 6014 bpp, stride, box+i, 6015 dx, dy); 6016 sigtrap_put(); 6017 } 6018 } else { 6019 if (gc && !sna_gc_move_to_cpu(gc, dst, region)) 6020 goto out; 6021 6022 if (sigtrap_get() == 0) { 6023 miCopyRegion(src, dst, gc, 6024 region, dx, dy, 6025 fbCopyNtoN, 0, NULL); 6026 sigtrap_put(); 6027 } 6028 6029 if (gc) 6030out: 6031 sna_gc_move_to_gpu(gc); 6032 } 6033 } 6034 6035free_boxes: 6036 if (box != region_rects(region)) 6037 free((void *)box); 6038} 6039 6040static inline bool 6041sna_pixmap_is_gpu(PixmapPtr pixmap) 6042{ 6043 struct sna_pixmap *priv = sna_pixmap(pixmap); 6044 6045 if (priv == NULL || priv->clear) 6046 return false; 6047 6048 if (DAMAGE_IS_ALL(priv->gpu_damage) || 6049 (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy)) 6050 return true; 6051 6052 return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo); 6053} 6054 6055static int 6056copy_prefer_gpu(struct sna *sna, 6057 struct sna_pixmap *dst_priv, 6058 struct sna_pixmap *src_priv, 6059 RegionRec *region, 6060 int16_t dx, int16_t dy) 6061{ 6062 assert(dst_priv); 6063 6064 if (wedged(sna) && !dst_priv->pinned) 6065 return 0; 6066 6067 if (src_priv == NULL) { 6068 DBG(("%s: source unattached, use cpu\n", __FUNCTION__)); 6069 return 0; 6070 } 6071 6072 if (src_priv->clear) { 6073 DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__)); 6074 return 0; 6075 } 6076 6077 if (src_priv->gpu_damage && 6078 !source_contains_region(src_priv->cpu_damage, region, dx, dy)) { 6079 DBG(("%s: source has gpu damage, force gpu? %d\n", 6080 __FUNCTION__, src_priv->cpu_damage == NULL)); 6081 assert(src_priv->gpu_bo); 6082 return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU; 6083 } 6084 6085 if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) { 6086 DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__)); 6087 return PREFER_GPU | FORCE_GPU; 6088 } 6089 6090 if (source_contains_region(src_priv->cpu_damage, region, dx, dy)) 6091 return src_priv->cpu_bo && kgem_is_idle(&sna->kgem); 6092 6093 DBG(("%s: source has GPU bo? %d\n", 6094 __FUNCTION__, src_priv->gpu_bo != NULL)); 6095 return src_priv->gpu_bo != NULL; 6096} 6097 6098static bool use_shm_bo(struct sna *sna, 6099 struct kgem_bo *bo, 6100 struct sna_pixmap *priv, 6101 int alu, bool replaces) 6102{ 6103 if (priv == NULL || priv->cpu_bo == NULL) { 6104 DBG(("%s: no, not attached\n", __FUNCTION__)); 6105 return false; 6106 } 6107 6108 if (!priv->shm && !priv->cpu) { 6109 DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__)); 6110 return true; 6111 } 6112 6113 if (alu != GXcopy) { 6114 DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu)); 6115 return true; 6116 } 6117 6118 if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) { 6119 DBG(("%s: yes, dst is busy\n", __FUNCTION__)); 6120 return true; 6121 } 6122 6123 if (priv->cpu_bo->needs_flush && 6124 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 6125 DBG(("%s: yes, src is busy\n", __FUNCTION__)); 6126 return true; 6127 } 6128 6129 return false; 6130} 6131 6132static bool 6133sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage, 6134 const BoxRec *extents, 6135 int16_t dx, int16_t dy) 6136{ 6137 BoxRec _extents; 6138 6139 if (dx | dy) { 6140 _extents.x1 = extents->x1 + dx; 6141 _extents.x2 = extents->x2 + dx; 6142 _extents.y1 = extents->y1 + dy; 6143 _extents.y2 = extents->y2 + dy; 6144 extents = &_extents; 6145 } 6146 6147 return sna_damage_contains_box__no_reduce(damage, extents); 6148} 6149 6150static bool 6151sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu, 6152 PixmapPtr src_pixmap, struct sna_pixmap *src_priv, 6153 int dx, int dy, 6154 PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv, 6155 bool replaces) 6156{ 6157 const BoxRec *box; 6158 char *ptr; 6159 int n; 6160 6161 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6162 6163 if (alu != GXcopy) { 6164 DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu)); 6165 return false; 6166 } 6167 6168 if (!USE_INPLACE) { 6169 DBG(("%s - no, compile time disabled\n", __FUNCTION__)); 6170 return false; 6171 } 6172 6173 if (dst_priv == src_priv) { 6174 DBG(("%s - no, dst == src\n", __FUNCTION__)); 6175 return false; 6176 } 6177 6178 if (src_priv == NULL || src_priv->gpu_bo == NULL) { 6179 if (dst_priv && dst_priv->gpu_bo) 6180 goto upload_inplace; 6181 6182 DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__)); 6183 return false; 6184 } 6185 6186 switch (src_priv->gpu_bo->tiling) { 6187 case I915_TILING_Y: 6188 DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__)); 6189 return false; 6190 case I915_TILING_X: 6191 if (!sna->kgem.memcpy_from_tiled_x) { 6192 DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__)); 6193 return false; 6194 } 6195 default: 6196 break; 6197 } 6198 6199 if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) { 6200 DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__)); 6201 return false; 6202 } 6203 6204 if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) { 6205 DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__)); 6206 return false; 6207 } 6208 6209 if (src_priv->gpu_damage == NULL || 6210 !(DAMAGE_IS_ALL(src_priv->gpu_damage) || 6211 sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage, 6212 ®ion->extents, 6213 dx, dy))) { 6214 DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__)); 6215 return false; 6216 } 6217 6218 assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_IN); 6219 assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_OUT); 6220 6221 ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo); 6222 if (ptr == NULL) { 6223 DBG(("%s - no, map failed\n", __FUNCTION__)); 6224 return false; 6225 } 6226 6227 if (dst_priv && 6228 !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6229 region, MOVE_WRITE | MOVE_INPLACE_HINT)) { 6230 DBG(("%s - no, dst sync failed\n", __FUNCTION__)); 6231 return false; 6232 } 6233 6234 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC); 6235 6236 if (sigtrap_get()) 6237 return false; 6238 6239 box = region_rects(region); 6240 n = region_num_rects(region); 6241 if (src_priv->gpu_bo->tiling) { 6242 DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__)); 6243 assert(dst_pixmap->devKind); 6244 do { 6245 memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr, 6246 src_pixmap->drawable.bitsPerPixel, 6247 src_priv->gpu_bo->pitch, 6248 dst_pixmap->devKind, 6249 box->x1 + dx, box->y1 + dy, 6250 box->x1, box->y1, 6251 box->x2 - box->x1, box->y2 - box->y1); 6252 box++; 6253 } while (--n); 6254 } else { 6255 DBG(("%s: copy from a linear CPU map\n", __FUNCTION__)); 6256 assert(dst_pixmap->devKind); 6257 do { 6258 memcpy_blt(ptr, dst_pixmap->devPrivate.ptr, 6259 src_pixmap->drawable.bitsPerPixel, 6260 src_priv->gpu_bo->pitch, 6261 dst_pixmap->devKind, 6262 box->x1 + dx, box->y1 + dy, 6263 box->x1, box->y1, 6264 box->x2 - box->x1, box->y2 - box->y1); 6265 box++; 6266 } while (--n); 6267 6268 if (!src_priv->shm) { 6269 assert(ptr == MAP(src_priv->gpu_bo->map__cpu)); 6270 src_pixmap->devPrivate.ptr = ptr; 6271 src_pixmap->devKind = src_priv->gpu_bo->pitch; 6272 src_priv->mapped = MAPPED_CPU; 6273 assert_pixmap_map(src_pixmap, src_priv); 6274 src_priv->cpu = true; 6275 } 6276 } 6277 6278 sigtrap_put(); 6279 6280 return true; 6281 6282upload_inplace: 6283 switch (dst_priv->gpu_bo->tiling) { 6284 case I915_TILING_Y: 6285 DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__)); 6286 return false; 6287 case I915_TILING_X: 6288 if (!sna->kgem.memcpy_to_tiled_x) { 6289 DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__)); 6290 return false; 6291 } 6292 default: 6293 break; 6294 } 6295 6296 if (dst_priv->move_to_gpu) { 6297 DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__)); 6298 return false; 6299 } 6300 6301 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) || 6302 __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) { 6303 if (replaces && !dst_priv->pinned) { 6304 unsigned create; 6305 struct kgem_bo *bo; 6306 6307 create = CREATE_CPU_MAP | CREATE_INACTIVE; 6308 if (dst_priv->gpu_bo->scanout) 6309 create |= CREATE_SCANOUT; 6310 6311 bo = kgem_create_2d(&sna->kgem, 6312 dst_pixmap->drawable.width, 6313 dst_pixmap->drawable.height, 6314 dst_pixmap->drawable.bitsPerPixel, 6315 dst_priv->gpu_bo->tiling, 6316 create); 6317 if (bo == NULL) 6318 return false; 6319 6320 sna_pixmap_unmap(dst_pixmap, dst_priv); 6321 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 6322 dst_priv->gpu_bo = bo; 6323 } else { 6324 DBG(("%s - no, dst is busy\n", __FUNCTION__)); 6325 return false; 6326 } 6327 6328 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) { 6329 DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__)); 6330 return false; 6331 } 6332 } 6333 6334 if (src_priv && 6335 !sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6336 region, MOVE_READ)) { 6337 DBG(("%s - no, src sync failed\n", __FUNCTION__)); 6338 return false; 6339 } 6340 6341 if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) { 6342 ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo); 6343 if (ptr == NULL) { 6344 DBG(("%s - no, map failed\n", __FUNCTION__)); 6345 return false; 6346 } 6347 6348 kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo); 6349 } else { 6350 ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo); 6351 if (ptr == NULL) { 6352 DBG(("%s - no, map failed\n", __FUNCTION__)); 6353 return false; 6354 } 6355 6356 kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo); 6357 } 6358 6359 if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) { 6360 assert(!dst_priv->clear); 6361 sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap); 6362 if (sna_damage_is_all(&dst_priv->gpu_damage, 6363 dst_pixmap->drawable.width, 6364 dst_pixmap->drawable.height)) { 6365 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 6366 __FUNCTION__)); 6367 sna_damage_destroy(&dst_priv->cpu_damage); 6368 list_del(&dst_priv->flush_list); 6369 } else 6370 sna_damage_subtract(&dst_priv->cpu_damage, 6371 region); 6372 } 6373 dst_priv->clear = false; 6374 6375 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6376 6377 if (sigtrap_get()) 6378 return false; 6379 6380 box = region_rects(region); 6381 n = region_num_rects(region); 6382 if (dst_priv->gpu_bo->tiling) { 6383 DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__)); 6384 assert(dst_priv->gpu_bo->tiling == I915_TILING_X); 6385 assert(src_pixmap->devKind); 6386 do { 6387 memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr, 6388 src_pixmap->drawable.bitsPerPixel, 6389 src_pixmap->devKind, 6390 dst_priv->gpu_bo->pitch, 6391 box->x1 + dx, box->y1 + dy, 6392 box->x1, box->y1, 6393 box->x2 - box->x1, box->y2 - box->y1); 6394 box++; 6395 } while (--n); 6396 } else { 6397 DBG(("%s: copy to a linear CPU map\n", __FUNCTION__)); 6398 assert(src_pixmap->devKind); 6399 do { 6400 memcpy_blt(src_pixmap->devPrivate.ptr, ptr, 6401 src_pixmap->drawable.bitsPerPixel, 6402 src_pixmap->devKind, 6403 dst_priv->gpu_bo->pitch, 6404 box->x1 + dx, box->y1 + dy, 6405 box->x1, box->y1, 6406 box->x2 - box->x1, box->y2 - box->y1); 6407 box++; 6408 } while (--n); 6409 6410 if (!dst_priv->shm) { 6411 dst_pixmap->devPrivate.ptr = ptr; 6412 dst_pixmap->devKind = dst_priv->gpu_bo->pitch; 6413 if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) { 6414 dst_priv->mapped = MAPPED_CPU; 6415 dst_priv->cpu = true; 6416 } else 6417 dst_priv->mapped = MAPPED_GTT; 6418 assert_pixmap_map(dst_pixmap, dst_priv); 6419 } 6420 } 6421 6422 sigtrap_put(); 6423 6424 return true; 6425} 6426 6427static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv) 6428{ 6429 if (priv->cpu_damage == NULL && !priv->shm) 6430 return; 6431 6432 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 6433 6434 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 6435 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 6436 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 6437 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 6438 assert(!priv->pinned); 6439 assert(!priv->mapped); 6440 sna_damage_destroy(&priv->gpu_damage); 6441 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 6442 priv->gpu_bo = NULL; 6443 } 6444 6445 sna_damage_destroy(&priv->cpu_damage); 6446 list_del(&priv->flush_list); 6447 6448 if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu)) 6449 sna_damage_all(&priv->gpu_damage, priv->pixmap); 6450 priv->cpu = false; 6451} 6452 6453static void 6454sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6455 RegionPtr region, int dx, int dy, 6456 Pixel bitplane, void *closure) 6457{ 6458 PixmapPtr src_pixmap = get_drawable_pixmap(src); 6459 struct sna_pixmap *src_priv = sna_pixmap(src_pixmap); 6460 PixmapPtr dst_pixmap = get_drawable_pixmap(dst); 6461 struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap); 6462 struct sna *sna = to_sna_from_pixmap(src_pixmap); 6463 struct sna_damage **damage; 6464 struct kgem_bo *bo; 6465 int16_t src_dx, src_dy; 6466 int16_t dst_dx, dst_dy; 6467 const BoxRec *box = region_rects(region); 6468 int n = region_num_rects(region); 6469 int alu = gc->alu; 6470 int stride, bpp; 6471 char *bits; 6472 bool replaces; 6473 6474 assert(region_num_rects(region)); 6475 6476 if (src_priv && 6477 src_priv->gpu_bo == NULL && 6478 src_priv->cpu_bo == NULL && 6479 src_priv->ptr == NULL) { 6480 /* Rare but still happens, nothing to copy */ 6481 DBG(("%s: src pixmap=%ld is empty\n", 6482 __FUNCTION__, src_pixmap->drawable.serialNumber)); 6483 return; 6484 } 6485 6486 if (src_pixmap == dst_pixmap) 6487 return sna_self_copy_boxes(src, dst, gc, 6488 region, dx, dy, 6489 bitplane, closure); 6490 6491 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", 6492 __FUNCTION__, n, 6493 box[0].x1, box[0].y1, box[0].x2, box[0].y2, 6494 src_pixmap->drawable.serialNumber, dx, dy, 6495 dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst), 6496 alu, 6497 src_pixmap->drawable.width, src_pixmap->drawable.height, 6498 dst_pixmap->drawable.width, dst_pixmap->drawable.height)); 6499 6500 assert_pixmap_damage(dst_pixmap); 6501 assert_pixmap_damage(src_pixmap); 6502 6503 bpp = dst_pixmap->drawable.bitsPerPixel; 6504 6505 if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy)) 6506 RegionTranslate(region, dst_dx, dst_dy); 6507 get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy); 6508 src_dx += dx - dst_dx; 6509 src_dy += dy - dst_dy; 6510 6511 assert_pixmap_contains_box(dst_pixmap, RegionExtents(region)); 6512 assert_pixmap_contains_box_with_offset(src_pixmap, 6513 RegionExtents(region), 6514 src_dx, src_dy); 6515 6516 replaces = n == 1 && 6517 alu_overwrites(alu) && 6518 box->x1 <= 0 && 6519 box->y1 <= 0 && 6520 box->x2 >= dst_pixmap->drawable.width && 6521 box->y2 >= dst_pixmap->drawable.height; 6522 6523 DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n", 6524 __FUNCTION__, 6525 dst_priv, 6526 dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0, 6527 dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0, 6528 src_priv, 6529 src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0, 6530 src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0, 6531 replaces)); 6532 6533 if (dst_priv == NULL) { 6534 DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__)); 6535 goto fallback; 6536 } 6537 6538 if (alu == GXcopy && 6539 src_priv && src_priv->cow && 6540 COW(src_priv->cow) == COW(dst_priv->cow)) { 6541 if ((dx | dy) == 0) { 6542 DBG(("%s: ignoring cow for no op\n", 6543 __FUNCTION__)); 6544 return; 6545 } else if (IS_COW_OWNER(dst_priv->cow)) { 6546 /* XXX hack for firefox -- subsequent uses of src will be corrupt! */ 6547 DBG(("%s: ignoring cow reference for cousin copy\n", 6548 __FUNCTION__)); 6549 assert(src_priv->cpu_damage == NULL); 6550 assert(dst_priv->move_to_gpu == NULL); 6551 bo = dst_priv->gpu_bo; 6552 damage = NULL; 6553 } else 6554 goto discard_cow; 6555 } else { 6556 unsigned hint; 6557discard_cow: 6558 hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy); 6559 if (replaces) { 6560 discard_cpu_damage(sna, dst_priv); 6561 hint |= REPLACES | IGNORE_DAMAGE; 6562 } else if (alu_overwrites(alu)) { 6563 if (region->data == NULL) 6564 hint |= IGNORE_DAMAGE; 6565 if (dst_priv->cpu_damage && 6566 region_subsumes_damage(region, 6567 dst_priv->cpu_damage)) 6568 discard_cpu_damage(sna, dst_priv); 6569 } 6570 bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint, 6571 ®ion->extents, &damage); 6572 } 6573 if (bo) { 6574 if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) { 6575 uint32_t color; 6576 6577 if (alu == GXset) 6578 color = (1 << dst_pixmap->drawable.depth) - 1; 6579 else if (alu == GXclear) 6580 color = 0; 6581 else 6582 color = src_priv->clear_color; 6583 DBG(("%s: applying src clear [%08x] to dst\n", 6584 __FUNCTION__, src_priv->clear_color)); 6585 6586 if (n == 1) { 6587 if (replaces && UNDO) 6588 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6589 6590 if (!sna->render.fill_one(sna, 6591 dst_pixmap, bo, color, 6592 box->x1, box->y1, 6593 box->x2, box->y2, 6594 alu)) { 6595 DBG(("%s: unsupported fill\n", 6596 __FUNCTION__)); 6597 goto fallback; 6598 } 6599 6600 if (replaces && bo == dst_priv->gpu_bo) { 6601 DBG(("%s: marking dst handle=%d as all clear [%08x]\n", 6602 __FUNCTION__, 6603 dst_priv->gpu_bo->handle, 6604 src_priv->clear_color)); 6605 dst_priv->clear = true; 6606 dst_priv->clear_color = color; 6607 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6608 sna_damage_destroy(&dst_priv->cpu_damage); 6609 list_del(&dst_priv->flush_list); 6610 return; 6611 } 6612 } else { 6613 struct sna_fill_op fill; 6614 6615 if (!sna_fill_init_blt(&fill, sna, 6616 dst_pixmap, bo, 6617 alu, color, 6618 FILL_BOXES)) { 6619 DBG(("%s: unsupported fill\n", 6620 __FUNCTION__)); 6621 goto fallback; 6622 } 6623 6624 fill.boxes(sna, &fill, box, n); 6625 fill.done(sna, &fill); 6626 } 6627 6628 if (damage) 6629 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6630 return; 6631 } 6632 6633 if (src_priv && 6634 move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) && 6635 sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 6636 DBG(("%s: move whole src_pixmap to GPU and copy\n", 6637 __FUNCTION__)); 6638 if (replaces && UNDO) 6639 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6640 6641 if (replaces && 6642 src_pixmap->drawable.width == dst_pixmap->drawable.width && 6643 src_pixmap->drawable.height == dst_pixmap->drawable.height) { 6644 assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth); 6645 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6646 if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) { 6647 assert(dst_priv->gpu_bo == src_priv->gpu_bo); 6648 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6649 sna_damage_destroy(&dst_priv->cpu_damage); 6650 list_del(&dst_priv->flush_list); 6651 add_shm_flush(sna, dst_priv); 6652 return; 6653 } 6654 } 6655 if (!sna->render.copy_boxes(sna, alu, 6656 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6657 &dst_pixmap->drawable, bo, 0, 0, 6658 box, n, small_copy(region))) { 6659 DBG(("%s: fallback - accelerated copy boxes failed\n", 6660 __FUNCTION__)); 6661 goto fallback; 6662 } 6663 6664 if (damage) 6665 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6666 return; 6667 } 6668 6669 if (src_priv && 6670 region_overlaps_damage(region, src_priv->gpu_damage, 6671 src_dx, src_dy)) { 6672 BoxRec area; 6673 6674 DBG(("%s: region overlaps GPU damage, upload and copy\n", 6675 __FUNCTION__)); 6676 6677 area = region->extents; 6678 area.x1 += src_dx; 6679 area.x2 += src_dx; 6680 area.y1 += src_dy; 6681 area.y2 += src_dy; 6682 6683 if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area, 6684 MOVE_READ | MOVE_ASYNC_HINT)) { 6685 DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__)); 6686 goto fallback; 6687 } 6688 6689 if (replaces && UNDO) 6690 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6691 6692 if (!sna->render.copy_boxes(sna, alu, 6693 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6694 &dst_pixmap->drawable, bo, 0, 0, 6695 box, n, small_copy(region))) { 6696 DBG(("%s: fallback - accelerated copy boxes failed\n", 6697 __FUNCTION__)); 6698 goto fallback; 6699 } 6700 6701 if (damage) 6702 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6703 return; 6704 } 6705 6706 if (bo != dst_priv->gpu_bo) 6707 goto fallback; 6708 6709 if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) { 6710 bool ret; 6711 6712 DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n", 6713 __FUNCTION__, src_priv->shm)); 6714 6715 assert(bo != dst_priv->cpu_bo); 6716 6717 RegionTranslate(region, src_dx, src_dy); 6718 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6719 region, 6720 MOVE_READ | MOVE_ASYNC_HINT); 6721 RegionTranslate(region, -src_dx, -src_dy); 6722 if (!ret) { 6723 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6724 goto fallback; 6725 } 6726 6727 if (replaces && UNDO) 6728 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6729 6730 add_shm_flush(sna, src_priv); 6731 6732 if (!sna->render.copy_boxes(sna, alu, 6733 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy, 6734 &dst_pixmap->drawable, bo, 0, 0, 6735 box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) { 6736 DBG(("%s: fallback - accelerated copy boxes failed\n", 6737 __FUNCTION__)); 6738 goto fallback; 6739 } 6740 6741 if (damage) 6742 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6743 return; 6744 } 6745 6746 if (src_priv) { 6747 bool ret; 6748 6749 RegionTranslate(region, src_dx, src_dy); 6750 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6751 region, MOVE_READ); 6752 RegionTranslate(region, -src_dx, -src_dy); 6753 if (!ret) { 6754 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6755 goto fallback; 6756 } 6757 6758 assert(!src_priv->mapped); 6759 if (src_pixmap->devPrivate.ptr == NULL) 6760 /* uninitialised!*/ 6761 return; 6762 } 6763 6764 if (USE_USERPTR_UPLOADS && 6765 sna->kgem.has_userptr && 6766 (alu != GXcopy || 6767 (box_inplace(src_pixmap, ®ion->extents) && 6768 __kgem_bo_is_busy(&sna->kgem, bo)))) { 6769 struct kgem_bo *src_bo; 6770 bool ok = false; 6771 6772 DBG(("%s: upload through a temporary map\n", 6773 __FUNCTION__)); 6774 6775 assert(src_pixmap->devKind); 6776 src_bo = kgem_create_map(&sna->kgem, 6777 src_pixmap->devPrivate.ptr, 6778 src_pixmap->devKind * src_pixmap->drawable.height, 6779 true); 6780 if (src_bo) { 6781 src_bo->pitch = src_pixmap->devKind; 6782 kgem_bo_mark_unreusable(src_bo); 6783 6784 ok = sna->render.copy_boxes(sna, alu, 6785 &src_pixmap->drawable, src_bo, src_dx, src_dy, 6786 &dst_pixmap->drawable, bo, 0, 0, 6787 box, n, small_copy(region) | COPY_LAST); 6788 kgem_bo_sync__cpu(&sna->kgem, src_bo); 6789 assert(src_bo->rq == NULL); 6790 kgem_bo_destroy(&sna->kgem, src_bo); 6791 } 6792 6793 if (ok) { 6794 if (damage) 6795 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6796 return; 6797 } 6798 } 6799 6800 if (alu != GXcopy) { 6801 PixmapPtr tmp; 6802 struct kgem_bo *src_bo; 6803 int i; 6804 6805 assert(src_pixmap->drawable.depth != 1); 6806 6807 DBG(("%s: creating temporary source upload for non-copy alu [%d]\n", 6808 __FUNCTION__, alu)); 6809 6810 tmp = sna_pixmap_create_upload(src->pScreen, 6811 region->extents.x2 - region->extents.x1, 6812 region->extents.y2 - region->extents.y1, 6813 src->depth, 6814 KGEM_BUFFER_WRITE_INPLACE); 6815 if (tmp == NullPixmap) 6816 return; 6817 6818 src_bo = __sna_pixmap_get_bo(tmp); 6819 assert(src_bo != NULL); 6820 6821 dx = -region->extents.x1; 6822 dy = -region->extents.y1; 6823 for (i = 0; i < n; i++) { 6824 assert(box[i].x1 + src_dx >= 0); 6825 assert(box[i].y1 + src_dy >= 0); 6826 assert(box[i].x2 + src_dx <= src_pixmap->drawable.width); 6827 assert(box[i].y2 + src_dy <= src_pixmap->drawable.height); 6828 6829 assert(box[i].x1 + dx >= 0); 6830 assert(box[i].y1 + dy >= 0); 6831 assert(box[i].x2 + dx <= tmp->drawable.width); 6832 assert(box[i].y2 + dy <= tmp->drawable.height); 6833 6834 assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ)); 6835 assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE)); 6836 assert(src_pixmap->devKind); 6837 assert(tmp->devKind); 6838 memcpy_blt(src_pixmap->devPrivate.ptr, 6839 tmp->devPrivate.ptr, 6840 src_pixmap->drawable.bitsPerPixel, 6841 src_pixmap->devKind, 6842 tmp->devKind, 6843 box[i].x1 + src_dx, 6844 box[i].y1 + src_dy, 6845 box[i].x1 + dx, 6846 box[i].y1 + dy, 6847 box[i].x2 - box[i].x1, 6848 box[i].y2 - box[i].y1); 6849 } 6850 6851 if (n == 1 && 6852 tmp->drawable.width == src_pixmap->drawable.width && 6853 tmp->drawable.height == src_pixmap->drawable.height) { 6854 DBG(("%s: caching upload for src bo\n", 6855 __FUNCTION__)); 6856 assert(src_priv->gpu_damage == NULL); 6857 assert(src_priv->gpu_bo == NULL); 6858 kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo); 6859 } 6860 6861 if (!sna->render.copy_boxes(sna, alu, 6862 &tmp->drawable, src_bo, dx, dy, 6863 &dst_pixmap->drawable, bo, 0, 0, 6864 box, n, 0)) { 6865 DBG(("%s: fallback - accelerated copy boxes failed\n", 6866 __FUNCTION__)); 6867 tmp->drawable.pScreen->DestroyPixmap(tmp); 6868 goto fallback; 6869 } 6870 tmp->drawable.pScreen->DestroyPixmap(tmp); 6871 6872 if (damage) 6873 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6874 return; 6875 } else { 6876 DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n", 6877 __FUNCTION__)); 6878 6879 assert(src_pixmap->devKind); 6880 if (!dst_priv->pinned && replaces) { 6881 stride = src_pixmap->devKind; 6882 bits = src_pixmap->devPrivate.ptr; 6883 bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8; 6884 6885 if (!sna_replace(sna, dst_pixmap, bits, stride)) { 6886 DBG(("%s: replace failed, fallback\n", __FUNCTION__)); 6887 goto fallback; 6888 } 6889 } else { 6890 assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage)); 6891 if (!sna_write_boxes(sna, dst_pixmap, 6892 dst_priv->gpu_bo, 0, 0, 6893 src_pixmap->devPrivate.ptr, 6894 src_pixmap->devKind, 6895 src_dx, src_dy, 6896 box, n)) { 6897 DBG(("%s: write failed, fallback\n", __FUNCTION__)); 6898 goto fallback; 6899 } 6900 } 6901 6902 assert(dst_priv->clear == false); 6903 dst_priv->cpu = false; 6904 if (damage) { 6905 assert(!dst_priv->clear); 6906 assert(dst_priv->gpu_bo); 6907 assert(dst_priv->gpu_bo->proxy == NULL); 6908 assert(*damage == dst_priv->gpu_damage); 6909 if (replaces) { 6910 sna_damage_destroy(&dst_priv->cpu_damage); 6911 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6912 list_del(&dst_priv->flush_list); 6913 } else 6914 sna_damage_add(&dst_priv->gpu_damage, 6915 region); 6916 assert_pixmap_damage(dst_pixmap); 6917 } 6918 } 6919 6920 return; 6921 } 6922 6923fallback: 6924 if (alu == GXcopy && src_priv && src_priv->clear) { 6925 DBG(("%s: copying clear [%08x]\n", 6926 __FUNCTION__, src_priv->clear_color)); 6927 6928 if (dst_priv) { 6929 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6930 region, 6931 MOVE_WRITE | MOVE_INPLACE_HINT)) 6932 return; 6933 } 6934 6935 if (sigtrap_get() == 0) { 6936 assert(dst_pixmap->devPrivate.ptr); 6937 assert(dst_pixmap->devKind); 6938 sigtrap_assert_active(); 6939 do { 6940 pixman_fill(dst_pixmap->devPrivate.ptr, 6941 dst_pixmap->devKind/sizeof(uint32_t), 6942 dst_pixmap->drawable.bitsPerPixel, 6943 box->x1, box->y1, 6944 box->x2 - box->x1, 6945 box->y2 - box->y1, 6946 src_priv->clear_color); 6947 box++; 6948 } while (--n); 6949 sigtrap_put(); 6950 } 6951 } else if (!sna_copy_boxes__inplace(sna, region, alu, 6952 src_pixmap, src_priv, 6953 src_dx, src_dy, 6954 dst_pixmap, dst_priv, 6955 replaces)) { 6956 FbBits *dst_bits, *src_bits; 6957 int dst_stride, src_stride; 6958 6959 DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", 6960 __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); 6961 if (src_priv) { 6962 unsigned mode; 6963 6964 RegionTranslate(region, src_dx, src_dy); 6965 6966 assert_pixmap_contains_box(src_pixmap, 6967 RegionExtents(region)); 6968 6969 mode = MOVE_READ; 6970 if (!sna->kgem.can_blt_cpu || 6971 (src_priv->cpu_bo == NULL && 6972 (src_priv->create & KGEM_CAN_CREATE_CPU) == 0)) 6973 mode |= MOVE_INPLACE_HINT; 6974 6975 if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6976 region, mode)) 6977 return; 6978 6979 RegionTranslate(region, -src_dx, -src_dy); 6980 } 6981 assert(src_priv == sna_pixmap(src_pixmap)); 6982 6983 if (dst_priv) { 6984 unsigned mode; 6985 6986 if (alu_overwrites(alu)) 6987 mode = MOVE_WRITE | MOVE_INPLACE_HINT; 6988 else 6989 mode = MOVE_WRITE | MOVE_READ; 6990 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6991 region, mode)) 6992 return; 6993 } 6994 assert(dst_priv == sna_pixmap(dst_pixmap)); 6995 6996 assert(dst_pixmap->devKind); 6997 assert(src_pixmap->devKind); 6998 dst_stride = dst_pixmap->devKind; 6999 src_stride = src_pixmap->devKind; 7000 7001 if (alu == GXcopy && bpp >= 8) { 7002 dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr; 7003 src_bits = (FbBits *) 7004 ((char *)src_pixmap->devPrivate.ptr + 7005 src_dy * src_stride + src_dx * bpp / 8); 7006 7007 if (sigtrap_get() == 0) { 7008 do { 7009 DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", 7010 __FUNCTION__, 7011 box->x1, box->y1, 7012 box->x2 - box->x1, 7013 box->y2 - box->y1, 7014 src_dx, src_dy, 7015 src_stride, dst_stride)); 7016 7017 assert(box->x1 >= 0); 7018 assert(box->y1 >= 0); 7019 assert(box->x2 <= dst_pixmap->drawable.width); 7020 assert(box->y2 <= dst_pixmap->drawable.height); 7021 7022 assert(box->x1 + src_dx >= 0); 7023 assert(box->y1 + src_dy >= 0); 7024 assert(box->x2 + src_dx <= src_pixmap->drawable.width); 7025 assert(box->y2 + src_dy <= src_pixmap->drawable.height); 7026 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 7027 assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); 7028 assert(src_stride); 7029 assert(dst_stride); 7030 memcpy_blt(src_bits, dst_bits, bpp, 7031 src_stride, dst_stride, 7032 box->x1, box->y1, 7033 box->x1, box->y1, 7034 box->x2 - box->x1, 7035 box->y2 - box->y1); 7036 box++; 7037 } while (--n); 7038 sigtrap_put(); 7039 } 7040 } else { 7041 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); 7042 7043 RegionTranslate(region, -dst_dx, -dst_dy); 7044 7045 if (sna_gc_move_to_cpu(gc, dst, region) && 7046 sigtrap_get() == 0) { 7047 miCopyRegion(src, dst, gc, 7048 region, dx, dy, 7049 fbCopyNtoN, 0, NULL); 7050 sigtrap_put(); 7051 } 7052 7053 sna_gc_move_to_gpu(gc); 7054 } 7055 } 7056} 7057 7058typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7059 RegionPtr region, int dx, int dy, 7060 Pixel bitPlane, void *closure); 7061 7062static inline bool box_equal(const BoxRec *a, const BoxRec *b) 7063{ 7064 return *(const uint64_t *)a == *(const uint64_t *)b; 7065} 7066 7067static inline bool has_clip(GCPtr gc) 7068{ 7069#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 7070 return gc->clientClipType != CT_NONE; 7071#else 7072 return gc->clientClip != NULL; 7073#endif 7074} 7075 7076static RegionPtr 7077sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7078 int sx, int sy, 7079 int width, int height, 7080 int dx, int dy, 7081 sna_copy_func copy, Pixel bitPlane, void *closure) 7082{ 7083 RegionPtr clip; 7084 RegionRec region; 7085 BoxRec src_extents; 7086 bool expose; 7087 7088 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 7089 __FUNCTION__, sx, sy, dx, dy, width, height)); 7090 7091 /* Short cut for unmapped windows */ 7092 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) { 7093 DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n", 7094 __FUNCTION__, get_window_pixmap((WindowPtr)dst))); 7095 return NULL; 7096 } 7097 7098 SourceValidate(src, sx, sy, width, height, gc->subWindowMode); 7099 7100 sx += src->x; 7101 sy += src->y; 7102 7103 dx += dst->x; 7104 dy += dst->y; 7105 7106 DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 7107 __FUNCTION__, sx, sy, dx, dy, width, height)); 7108 7109 region.extents.x1 = dx; 7110 region.extents.y1 = dy; 7111 region.extents.x2 = bound(dx, width); 7112 region.extents.y2 = bound(dy, height); 7113 region.data = NULL; 7114 7115 DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__, 7116 region.extents.x1, region.extents.y1, 7117 region.extents.x2, region.extents.y2, 7118 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 7119 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2, 7120 dst->width, dst->height)); 7121 7122 if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) { 7123 DBG(("%s: dst clipped out\n", __FUNCTION__)); 7124 return NULL; 7125 } 7126 7127 DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7128 region.extents.x1, region.extents.y1, 7129 region.extents.x2, region.extents.y2)); 7130 assert_drawable_contains_box(dst, ®ion.extents); 7131 7132 region.extents.x1 = clamp(region.extents.x1, sx - dx); 7133 region.extents.x2 = clamp(region.extents.x2, sx - dx); 7134 region.extents.y1 = clamp(region.extents.y1, sy - dy); 7135 region.extents.y2 = clamp(region.extents.y2, sy - dy); 7136 7137 src_extents = region.extents; 7138 expose = true; 7139 7140 DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7141 region.extents.x1, region.extents.y1, 7142 region.extents.x2, region.extents.y2)); 7143 7144 if (region.extents.x1 < src->x) 7145 region.extents.x1 = src->x; 7146 if (region.extents.y1 < src->y) 7147 region.extents.y1 = src->y; 7148 if (region.extents.x2 > src->x + (int) src->width) 7149 region.extents.x2 = src->x + (int) src->width; 7150 if (region.extents.y2 > src->y + (int) src->height) 7151 region.extents.y2 = src->y + (int) src->height; 7152 7153 DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7154 region.extents.x1, region.extents.y1, 7155 region.extents.x2, region.extents.y2)); 7156 if (box_empty(®ion.extents)) { 7157 DBG(("%s: src clipped out\n", __FUNCTION__)); 7158 return NULL; 7159 } 7160 7161 /* Compute source clip region */ 7162 if (src->type == DRAWABLE_PIXMAP) { 7163 if (src == dst && !has_clip(gc)) { 7164 DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__)); 7165 clip = gc->pCompositeClip; 7166 } else { 7167 DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__)); 7168 expose = false; 7169 clip = NULL; 7170 } 7171 } else { 7172 WindowPtr w = (WindowPtr)src; 7173 if (gc->subWindowMode == IncludeInferiors) { 7174 DBG(("%s: window -- include inferiors\n", __FUNCTION__)); 7175 7176 if (w->winSize.data) 7177 RegionIntersect(®ion, ®ion, &w->winSize); 7178 else 7179 box_intersect(®ion.extents, &w->winSize.extents); 7180 clip = &w->borderClip; 7181 } else { 7182 DBG(("%s: window -- clip by children\n", __FUNCTION__)); 7183 clip = &w->clipList; 7184 } 7185 } 7186 if (clip != NULL) { 7187 if (clip->data == NULL) { 7188 box_intersect(®ion.extents, &clip->extents); 7189 if (box_equal(&src_extents, ®ion.extents)) 7190 expose = false; 7191 } else 7192 RegionIntersect(®ion, ®ion, clip); 7193 } 7194 DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__, 7195 region.extents.x1, region.extents.y1, 7196 region.extents.x2, region.extents.y2, 7197 region_num_rects(®ion))); 7198 7199 RegionTranslate(®ion, dx-sx, dy-sy); 7200 if (gc->pCompositeClip->data) 7201 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 7202 DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n", 7203 __FUNCTION__, 7204 region.extents.x1, region.extents.y1, 7205 region.extents.x2, region.extents.y2, 7206 region_num_rects(®ion), 7207 sx-dx, sy-dy)); 7208 7209 if (!box_empty(®ion.extents)) 7210 copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure); 7211 assert(gc->pCompositeClip != ®ion); 7212 RegionUninit(®ion); 7213 7214 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 7215 clip = NULL; 7216 if (expose && gc->fExpose) 7217 clip = miHandleExposures(src, dst, gc, 7218 sx - src->x, sy - src->y, 7219 width, height, 7220 dx - dst->x, dy - dst->y, 7221 (unsigned long) bitPlane); 7222 return clip; 7223} 7224 7225static void 7226sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7227 RegionPtr region, int dx, int dy, 7228 Pixel bitplane, void *closure) 7229{ 7230 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n", 7231 __FUNCTION__, region_num_rects(region), 7232 region->extents.x1, region->extents.y1, 7233 region->extents.x2, region->extents.y2, 7234 dx, dy, gc->alu)); 7235 7236 if (!sna_gc_move_to_cpu(gc, dst, region)) 7237 goto out; 7238 7239 RegionTranslate(region, dx, dy); 7240 if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ)) 7241 goto out; 7242 RegionTranslate(region, -dx, -dy); 7243 7244 if (src == dst || 7245 get_drawable_pixmap(src) == get_drawable_pixmap(dst)) { 7246 DBG(("%s: self-copy\n", __FUNCTION__)); 7247 if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ)) 7248 goto out; 7249 } else { 7250 if (!sna_drawable_move_region_to_cpu(dst, region, 7251 drawable_gc_flags(dst, gc, false))) 7252 goto out; 7253 } 7254 7255 if (sigtrap_get() == 0) { 7256 miCopyRegion(src, dst, gc, 7257 region, dx, dy, 7258 fbCopyNtoN, 0, NULL); 7259 FALLBACK_FLUSH(dst); 7260 sigtrap_put(); 7261 } 7262out: 7263 sna_gc_move_to_gpu(gc); 7264} 7265 7266static RegionPtr 7267sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7268 int src_x, int src_y, 7269 int width, int height, 7270 int dst_x, int dst_y) 7271{ 7272 struct sna *sna = to_sna_from_drawable(dst); 7273 sna_copy_func copy; 7274 7275 if (gc->planemask == 0) 7276 return NULL; 7277 7278 if (sna->ignore_copy_area) 7279 return NULL; 7280 7281 DBG(("%s: src=pixmap=%ld:(%d, %d)x(%d, %d)+(%d, %d) -> dst=pixmap=%ld:(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n", 7282 __FUNCTION__, 7283 get_drawable_pixmap(src)->drawable.serialNumber, 7284 src_x, src_y, width, height, src->x, src->y, 7285 get_drawable_pixmap(dst)->drawable.serialNumber, 7286 dst_x, dst_y, dst->x, dst->y, 7287 gc->alu, gc->planemask, gc->depth)); 7288 7289 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) || 7290 !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) { 7291 DBG(("%s: fallback copy\n", __FUNCTION__)); 7292 copy = sna_fallback_copy_boxes; 7293 } else if (src == dst) { 7294 DBG(("%s: self copy\n", __FUNCTION__)); 7295 copy = sna_self_copy_boxes; 7296 } else { 7297 DBG(("%s: normal copy\n", __FUNCTION__)); 7298 copy = sna_copy_boxes; 7299 } 7300 7301 return sna_do_copy(src, dst, gc, 7302 src_x, src_y, 7303 width, height, 7304 dst_x, dst_y, 7305 copy, 0, NULL); 7306} 7307 7308const BoxRec * 7309__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) 7310{ 7311 assert(end - begin > 1); 7312 do { 7313 const BoxRec *mid = begin + (end - begin) / 2; 7314 if (mid->y2 > y) 7315 end = mid; 7316 else 7317 begin = mid; 7318 } while (end > begin + 1); 7319 if (begin->y2 > y) 7320 return begin; 7321 else 7322 return end; 7323} 7324 7325struct sna_fill_spans { 7326 struct sna *sna; 7327 PixmapPtr pixmap; 7328 RegionRec region; 7329 unsigned flags; 7330 uint32_t phase; 7331 struct kgem_bo *bo; 7332 struct sna_damage **damage; 7333 int16_t dx, dy; 7334 void *op; 7335}; 7336 7337static void 7338sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc, 7339 int mode, int n, DDXPointPtr pt) 7340{ 7341 fbPolyPoint(drawable, gc, mode, n, pt, -1); 7342} 7343 7344static void 7345sna_poly_point__fill(DrawablePtr drawable, GCPtr gc, 7346 int mode, int n, DDXPointPtr pt) 7347{ 7348 struct sna_fill_spans *data = sna_gc(gc)->priv; 7349 struct sna_fill_op *op = data->op; 7350 BoxRec box[512]; 7351 DDXPointRec last; 7352 7353 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7354 if (n == 0) 7355 return; 7356 7357 last.x = drawable->x + data->dx; 7358 last.y = drawable->y + data->dy; 7359 if (op->points && mode != CoordModePrevious) { 7360 op->points(data->sna, op, last.x, last.y, pt, n); 7361 } else do { 7362 BoxRec *b = box; 7363 unsigned nbox = n; 7364 if (nbox > ARRAY_SIZE(box)) 7365 nbox = ARRAY_SIZE(box); 7366 n -= nbox; 7367 do { 7368 *(DDXPointRec *)b = *pt++; 7369 7370 b->x1 += last.x; 7371 b->y1 += last.y; 7372 if (mode == CoordModePrevious) 7373 last = *(DDXPointRec *)b; 7374 7375 b->x2 = b->x1 + 1; 7376 b->y2 = b->y1 + 1; 7377 b++; 7378 } while (--nbox); 7379 op->boxes(data->sna, op, box, b - box); 7380 } while (n); 7381} 7382 7383static void 7384sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc, 7385 int mode, int n, DDXPointPtr pt) 7386{ 7387 struct sna_fill_spans *data = sna_gc(gc)->priv; 7388 struct sna_fill_op fill; 7389 BoxRec box[512]; 7390 DDXPointRec last; 7391 7392 if (!sna_fill_init_blt(&fill, 7393 data->sna, data->pixmap, 7394 data->bo, gc->alu, gc->fgPixel, 7395 FILL_POINTS)) 7396 return; 7397 7398 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7399 7400 last.x = drawable->x; 7401 last.y = drawable->y; 7402 while (n) { 7403 BoxRec *b = box; 7404 unsigned nbox = n; 7405 if (nbox > ARRAY_SIZE(box)) 7406 nbox = ARRAY_SIZE(box); 7407 n -= nbox; 7408 do { 7409 *(DDXPointRec *)b = *pt++; 7410 7411 b->x1 += last.x; 7412 b->y1 += last.y; 7413 if (mode == CoordModePrevious) 7414 last = *(DDXPointRec *)b; 7415 7416 if (RegionContainsPoint(&data->region, 7417 b->x1, b->y1, NULL)) { 7418 b->x1 += data->dx; 7419 b->y1 += data->dy; 7420 b->x2 = b->x1 + 1; 7421 b->y2 = b->y1 + 1; 7422 b++; 7423 } 7424 } while (--nbox); 7425 if (b != box) 7426 fill.boxes(data->sna, &fill, box, b - box); 7427 } 7428 fill.done(data->sna, &fill); 7429} 7430 7431static void 7432sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc, 7433 int mode, int n, DDXPointPtr pt) 7434{ 7435 struct sna_fill_spans *data = sna_gc(gc)->priv; 7436 struct sna_fill_op *op = data->op; 7437 const BoxRec *extents = &data->region.extents; 7438 BoxRec box[512], *b = box; 7439 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7440 DDXPointRec last; 7441 7442 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7443 7444 last.x = drawable->x + data->dx; 7445 last.y = drawable->y + data->dy; 7446 while (n--) { 7447 *(DDXPointRec *)b = *pt++; 7448 7449 b->x1 += last.x; 7450 b->y1 += last.y; 7451 if (mode == CoordModePrevious) 7452 last = *(DDXPointRec *)b; 7453 7454 if (b->x1 >= extents->x1 && b->x1 < extents->x2 && 7455 b->y1 >= extents->y1 && b->y1 < extents->y2) { 7456 b->x2 = b->x1 + 1; 7457 b->y2 = b->y1 + 1; 7458 if (++b == last_box) { 7459 op->boxes(data->sna, op, box, last_box - box); 7460 b = box; 7461 } 7462 } 7463 } 7464 if (b != box) 7465 op->boxes(data->sna, op, box, b - box); 7466} 7467 7468static void 7469sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc, 7470 int mode, int n, DDXPointPtr pt) 7471{ 7472 struct sna_fill_spans *data = sna_gc(gc)->priv; 7473 struct sna_fill_op *op = data->op; 7474 RegionRec *clip = &data->region; 7475 BoxRec box[512], *b = box; 7476 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7477 DDXPointRec last; 7478 7479 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7480 7481 last.x = drawable->x + data->dx; 7482 last.y = drawable->y + data->dy; 7483 while (n--) { 7484 *(DDXPointRec *)b = *pt++; 7485 7486 b->x1 += last.x; 7487 b->y1 += last.y; 7488 if (mode == CoordModePrevious) 7489 last = *(DDXPointRec *)b; 7490 7491 if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) { 7492 b->x2 = b->x1 + 1; 7493 b->y2 = b->y1 + 1; 7494 if (++b == last_box) { 7495 op->boxes(data->sna, op, box, last_box - box); 7496 b = box; 7497 } 7498 } 7499 } 7500 if (b != box) 7501 op->boxes(data->sna, op, box, b - box); 7502} 7503 7504static void 7505sna_poly_point__dash(DrawablePtr drawable, GCPtr gc, 7506 int mode, int n, DDXPointPtr pt) 7507{ 7508 struct sna_fill_spans *data = sna_gc(gc)->priv; 7509 if (data->phase == gc->fgPixel) 7510 sna_poly_point__fill(drawable, gc, mode, n, pt); 7511} 7512 7513static void 7514sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc, 7515 int mode, int n, DDXPointPtr pt) 7516{ 7517 struct sna_fill_spans *data = sna_gc(gc)->priv; 7518 if (data->phase == gc->fgPixel) 7519 sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt); 7520} 7521 7522static void 7523sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc, 7524 int mode, int n, DDXPointPtr pt) 7525{ 7526 struct sna_fill_spans *data = sna_gc(gc)->priv; 7527 if (data->phase == gc->fgPixel) 7528 sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt); 7529} 7530 7531static void 7532sna_fill_spans__fill(DrawablePtr drawable, 7533 GCPtr gc, int n, 7534 DDXPointPtr pt, int *width, int sorted) 7535{ 7536 struct sna_fill_spans *data = sna_gc(gc)->priv; 7537 struct sna_fill_op *op = data->op; 7538 BoxRec box[512]; 7539 7540 DBG(("%s: alu=%d, fg=%08lx, count=%d\n", 7541 __FUNCTION__, gc->alu, gc->fgPixel, n)); 7542 7543 while (n) { 7544 BoxRec *b = box; 7545 int nbox = n; 7546 if (nbox > ARRAY_SIZE(box)) 7547 nbox = ARRAY_SIZE(box); 7548 n -= nbox; 7549 do { 7550 *(DDXPointRec *)b = *pt++; 7551 b->x2 = b->x1 + (int)*width++; 7552 b->y2 = b->y1 + 1; 7553 DBG(("%s: (%d, %d), (%d, %d)\n", 7554 __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); 7555 assert(b->x1 >= drawable->x); 7556 assert(b->x2 <= drawable->x + drawable->width); 7557 assert(b->y1 >= drawable->y); 7558 assert(b->y2 <= drawable->y + drawable->height); 7559 if (b->x2 > b->x1) { 7560 if (b != box && 7561 b->y1 == b[-1].y2 && 7562 b->x1 == b[-1].x1 && 7563 b->x2 == b[-1].x2) 7564 b[-1].y2 = b->y2; 7565 else 7566 b++; 7567 } 7568 } while (--nbox); 7569 if (b != box) 7570 op->boxes(data->sna, op, box, b - box); 7571 } 7572} 7573 7574static void 7575sna_fill_spans__dash(DrawablePtr drawable, 7576 GCPtr gc, int n, 7577 DDXPointPtr pt, int *width, int sorted) 7578{ 7579 struct sna_fill_spans *data = sna_gc(gc)->priv; 7580 if (data->phase == gc->fgPixel) 7581 sna_fill_spans__fill(drawable, gc, n, pt, width, sorted); 7582} 7583 7584static void 7585sna_fill_spans__fill_offset(DrawablePtr drawable, 7586 GCPtr gc, int n, 7587 DDXPointPtr pt, int *width, int sorted) 7588{ 7589 struct sna_fill_spans *data = sna_gc(gc)->priv; 7590 struct sna_fill_op *op = data->op; 7591 BoxRec box[512]; 7592 7593 DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); 7594 7595 while (n) { 7596 BoxRec *b = box; 7597 int nbox = n; 7598 if (nbox > ARRAY_SIZE(box)) 7599 nbox = ARRAY_SIZE(box); 7600 n -= nbox; 7601 do { 7602 *(DDXPointRec *)b = *pt++; 7603 b->x1 += data->dx; 7604 b->y1 += data->dy; 7605 b->x2 = b->x1 + (int)*width++; 7606 b->y2 = b->y1 + 1; 7607 if (b->x2 > b->x1) 7608 b++; 7609 } while (--nbox); 7610 if (b != box) 7611 op->boxes(data->sna, op, box, b - box); 7612 } 7613} 7614 7615static void 7616sna_fill_spans__dash_offset(DrawablePtr drawable, 7617 GCPtr gc, int n, 7618 DDXPointPtr pt, int *width, int sorted) 7619{ 7620 struct sna_fill_spans *data = sna_gc(gc)->priv; 7621 if (data->phase == gc->fgPixel) 7622 sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted); 7623} 7624 7625static void 7626sna_fill_spans__fill_clip_extents(DrawablePtr drawable, 7627 GCPtr gc, int n, 7628 DDXPointPtr pt, int *width, int sorted) 7629{ 7630 struct sna_fill_spans *data = sna_gc(gc)->priv; 7631 struct sna_fill_op *op = data->op; 7632 const BoxRec *extents = &data->region.extents; 7633 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7634 7635 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7636 __FUNCTION__, gc->alu, gc->fgPixel, n, 7637 extents->x1, extents->y1, 7638 extents->x2, extents->y2)); 7639 7640 while (n--) { 7641 DBG(("%s: [%d] pt=(%d, %d), width=%d\n", 7642 __FUNCTION__, n, pt->x, pt->y, *width)); 7643 *(DDXPointRec *)b = *pt++; 7644 b->x2 = b->x1 + (int)*width++; 7645 b->y2 = b->y1 + 1; 7646 if (box_intersect(b, extents)) { 7647 DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n", 7648 __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2)); 7649 if (data->dx|data->dy) { 7650 b->x1 += data->dx; b->x2 += data->dx; 7651 b->y1 += data->dy; b->y2 += data->dy; 7652 } 7653 if (b != box && 7654 b->y1 == b[-1].y2 && 7655 b->x1 == b[-1].x1 && 7656 b->x2 == b[-1].x2) { 7657 b[-1].y2 = b->y2; 7658 } else if (++b == last_box) { 7659 op->boxes(data->sna, op, box, last_box - box); 7660 b = box; 7661 } 7662 } 7663 } 7664 if (b != box) 7665 op->boxes(data->sna, op, box, b - box); 7666} 7667 7668static void 7669sna_fill_spans__dash_clip_extents(DrawablePtr drawable, 7670 GCPtr gc, int n, 7671 DDXPointPtr pt, int *width, int sorted) 7672{ 7673 struct sna_fill_spans *data = sna_gc(gc)->priv; 7674 if (data->phase == gc->fgPixel) 7675 sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted); 7676} 7677 7678static void 7679sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, 7680 GCPtr gc, int n, 7681 DDXPointPtr pt, int *width, int sorted) 7682{ 7683 struct sna_fill_spans *data = sna_gc(gc)->priv; 7684 struct sna_fill_op *op = data->op; 7685 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7686 const BoxRec * const clip_start = RegionBoxptr(&data->region); 7687 const BoxRec * const clip_end = clip_start + data->region.data->numRects; 7688 7689 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7690 __FUNCTION__, gc->alu, gc->fgPixel, n, 7691 data->region.extents.x1, data->region.extents.y1, 7692 data->region.extents.x2, data->region.extents.y2)); 7693 7694 while (n--) { 7695 int16_t X1 = pt->x; 7696 int16_t y = pt->y; 7697 int16_t X2 = X1 + (int)*width; 7698 const BoxRec *c; 7699 7700 pt++; 7701 width++; 7702 7703 if (y < data->region.extents.y1 || data->region.extents.y2 <= y) 7704 continue; 7705 7706 if (X1 < data->region.extents.x1) 7707 X1 = data->region.extents.x1; 7708 7709 if (X2 > data->region.extents.x2) 7710 X2 = data->region.extents.x2; 7711 7712 if (X1 >= X2) 7713 continue; 7714 7715 c = find_clip_box_for_y(clip_start, clip_end, y); 7716 while (c != clip_end) { 7717 if (y + 1 <= c->y1 || X2 <= c->x1) 7718 break; 7719 7720 if (X1 >= c->x2) { 7721 c++; 7722 continue; 7723 } 7724 7725 b->x1 = c->x1; 7726 b->x2 = c->x2; 7727 c++; 7728 7729 if (b->x1 < X1) 7730 b->x1 = X1; 7731 if (b->x2 > X2) 7732 b->x2 = X2; 7733 if (b->x2 <= b->x1) 7734 continue; 7735 7736 b->x1 += data->dx; 7737 b->x2 += data->dx; 7738 b->y1 = y + data->dy; 7739 b->y2 = b->y1 + 1; 7740 if (++b == last_box) { 7741 op->boxes(data->sna, op, box, last_box - box); 7742 b = box; 7743 } 7744 } 7745 } 7746 if (b != box) 7747 op->boxes(data->sna, op, box, b - box); 7748} 7749 7750static void 7751sna_fill_spans__dash_clip_boxes(DrawablePtr drawable, 7752 GCPtr gc, int n, 7753 DDXPointPtr pt, int *width, int sorted) 7754{ 7755 struct sna_fill_spans *data = sna_gc(gc)->priv; 7756 if (data->phase == gc->fgPixel) 7757 sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted); 7758} 7759 7760static bool 7761sna_fill_spans_blt(DrawablePtr drawable, 7762 struct kgem_bo *bo, struct sna_damage **damage, 7763 GCPtr gc, uint32_t pixel, 7764 int n, DDXPointPtr pt, int *width, int sorted, 7765 const BoxRec *extents, unsigned clipped) 7766{ 7767 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7768 struct sna *sna = to_sna_from_pixmap(pixmap); 7769 int16_t dx, dy; 7770 struct sna_fill_op fill; 7771 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7772 static void * const jump[] = { 7773 &&no_damage, 7774 &&damage, 7775 &&no_damage_clipped, 7776 &&damage_clipped, 7777 }; 7778 unsigned v; 7779 7780 DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n", 7781 __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped)); 7782 7783 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 7784 return false; 7785 7786 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7787 7788 v = (damage != NULL) | clipped; 7789 goto *jump[v]; 7790 7791no_damage: 7792 if (dx|dy) { 7793 do { 7794 int nbox = n; 7795 if (nbox > last_box - box) 7796 nbox = last_box - box; 7797 n -= nbox; 7798 do { 7799 *(DDXPointRec *)b = *pt++; 7800 b->x1 += dx; 7801 b->y1 += dy; 7802 b->x2 = b->x1 + (int)*width++; 7803 b->y2 = b->y1 + 1; 7804 b++; 7805 } while (--nbox); 7806 fill.boxes(sna, &fill, box, b - box); 7807 b = box; 7808 } while (n); 7809 } else { 7810 do { 7811 int nbox = n; 7812 if (nbox > last_box - box) 7813 nbox = last_box - box; 7814 n -= nbox; 7815 do { 7816 *(DDXPointRec *)b = *pt++; 7817 b->x2 = b->x1 + (int)*width++; 7818 b->y2 = b->y1 + 1; 7819 b++; 7820 } while (--nbox); 7821 fill.boxes(sna, &fill, box, b - box); 7822 b = box; 7823 } while (n); 7824 } 7825 goto done; 7826 7827damage: 7828 do { 7829 *(DDXPointRec *)b = *pt++; 7830 b->x1 += dx; 7831 b->y1 += dy; 7832 b->x2 = b->x1 + (int)*width++; 7833 b->y2 = b->y1 + 1; 7834 7835 if (++b == last_box) { 7836 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7837 fill.boxes(sna, &fill, box, last_box - box); 7838 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7839 b = box; 7840 } 7841 } while (--n); 7842 if (b != box) { 7843 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7844 fill.boxes(sna, &fill, box, b - box); 7845 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7846 } 7847 goto done; 7848 7849no_damage_clipped: 7850 { 7851 RegionRec clip; 7852 7853 region_set(&clip, extents); 7854 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7855 return true; 7856 7857 assert(dx + clip.extents.x1 >= 0); 7858 assert(dy + clip.extents.y1 >= 0); 7859 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7860 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7861 7862 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7863 __FUNCTION__, 7864 region_num_rects(&clip), 7865 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7866 n, pt->x, pt->y)); 7867 7868 if (clip.data == NULL) { 7869 do { 7870 *(DDXPointRec *)b = *pt++; 7871 b->x2 = b->x1 + (int)*width++; 7872 b->y2 = b->y1 + 1; 7873 7874 if (box_intersect(b, &clip.extents)) { 7875 if (dx|dy) { 7876 b->x1 += dx; b->x2 += dx; 7877 b->y1 += dy; b->y2 += dy; 7878 } 7879 if (++b == last_box) { 7880 fill.boxes(sna, &fill, box, last_box - box); 7881 b = box; 7882 } 7883 } 7884 } while (--n); 7885 } else { 7886 const BoxRec * const clip_start = RegionBoxptr(&clip); 7887 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7888 do { 7889 int16_t X1 = pt->x; 7890 int16_t y = pt->y; 7891 int16_t X2 = X1 + (int)*width; 7892 const BoxRec *c; 7893 7894 pt++; 7895 width++; 7896 7897 if (y < extents->y1 || extents->y2 <= y) 7898 continue; 7899 7900 if (X1 < extents->x1) 7901 X1 = extents->x1; 7902 7903 if (X2 > extents->x2) 7904 X2 = extents->x2; 7905 7906 if (X1 >= X2) 7907 continue; 7908 7909 c = find_clip_box_for_y(clip_start, 7910 clip_end, 7911 y); 7912 while (c != clip_end) { 7913 if (y + 1 <= c->y1 || X2 <= c->x1) 7914 break; 7915 7916 if (X1 >= c->x2) { 7917 c++; 7918 continue; 7919 } 7920 7921 b->x1 = c->x1; 7922 b->x2 = c->x2; 7923 c++; 7924 7925 if (b->x1 < X1) 7926 b->x1 = X1; 7927 if (b->x2 > X2) 7928 b->x2 = X2; 7929 if (b->x2 <= b->x1) 7930 continue; 7931 7932 b->x1 += dx; 7933 b->x2 += dx; 7934 b->y1 = y + dy; 7935 b->y2 = b->y1 + 1; 7936 if (++b == last_box) { 7937 fill.boxes(sna, &fill, box, last_box - box); 7938 b = box; 7939 } 7940 } 7941 } while (--n); 7942 RegionUninit(&clip); 7943 } 7944 if (b != box) 7945 fill.boxes(sna, &fill, box, b - box); 7946 goto done; 7947 } 7948 7949damage_clipped: 7950 { 7951 RegionRec clip; 7952 7953 region_set(&clip, extents); 7954 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7955 return true; 7956 7957 assert(dx + clip.extents.x1 >= 0); 7958 assert(dy + clip.extents.y1 >= 0); 7959 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7960 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7961 7962 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7963 __FUNCTION__, 7964 region_num_rects(&clip), 7965 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7966 n, pt->x, pt->y)); 7967 7968 if (clip.data == NULL) { 7969 do { 7970 *(DDXPointRec *)b = *pt++; 7971 b->x2 = b->x1 + (int)*width++; 7972 b->y2 = b->y1 + 1; 7973 7974 if (box_intersect(b, &clip.extents)) { 7975 b->x1 += dx; 7976 b->x2 += dx; 7977 b->y1 += dy; 7978 b->y2 += dy; 7979 if (++b == last_box) { 7980 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7981 fill.boxes(sna, &fill, box, last_box - box); 7982 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7983 b = box; 7984 } 7985 } 7986 } while (--n); 7987 } else { 7988 const BoxRec * const clip_start = RegionBoxptr(&clip); 7989 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7990 do { 7991 int16_t X1 = pt->x; 7992 int16_t y = pt->y; 7993 int16_t X2 = X1 + (int)*width; 7994 const BoxRec *c; 7995 7996 pt++; 7997 width++; 7998 7999 if (y < extents->y1 || extents->y2 <= y) 8000 continue; 8001 8002 if (X1 < extents->x1) 8003 X1 = extents->x1; 8004 8005 if (X2 > extents->x2) 8006 X2 = extents->x2; 8007 8008 if (X1 >= X2) 8009 continue; 8010 8011 c = find_clip_box_for_y(clip_start, 8012 clip_end, 8013 y); 8014 while (c != clip_end) { 8015 if (y + 1 <= c->y1 || X2 <= c->x1) 8016 break; 8017 8018 if (X1 >= c->x2) { 8019 c++; 8020 continue; 8021 } 8022 8023 b->x1 = c->x1; 8024 b->x2 = c->x2; 8025 c++; 8026 8027 if (b->x1 < X1) 8028 b->x1 = X1; 8029 if (b->x2 > X2) 8030 b->x2 = X2; 8031 if (b->x2 <= b->x1) 8032 continue; 8033 8034 b->x1 += dx; 8035 b->x2 += dx; 8036 b->y1 = y + dy; 8037 b->y2 = b->y1 + 1; 8038 if (++b == last_box) { 8039 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 8040 fill.boxes(sna, &fill, box, last_box - box); 8041 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 8042 b = box; 8043 } 8044 } 8045 } while (--n); 8046 RegionUninit(&clip); 8047 } 8048 if (b != box) { 8049 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 8050 fill.boxes(sna, &fill, box, b - box); 8051 sna_damage_add_boxes(damage, box, b - box, 0, 0); 8052 } 8053 goto done; 8054 } 8055 8056done: 8057 fill.done(sna, &fill); 8058 assert_pixmap_damage(pixmap); 8059 return true; 8060} 8061 8062static bool 8063sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 8064 struct kgem_bo *bo, 8065 struct sna_damage **damage, 8066 GCPtr gc, int n, xRectangle *rect, 8067 const BoxRec *extents, unsigned clipped); 8068 8069static bool 8070sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 8071 struct kgem_bo *bo, 8072 struct sna_damage **damage, 8073 GCPtr gc, int n, xRectangle *rect, 8074 const BoxRec *extents, unsigned clipped); 8075 8076static inline bool 8077gc_is_solid(GCPtr gc, uint32_t *color) 8078{ 8079 assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask)); 8080 8081 if (gc->alu == GXclear) { 8082 *color = 0; 8083 return true; 8084 } 8085 if (gc->alu == GXset) { 8086 *color = (1 << gc->depth) - 1; 8087 return true; 8088 } 8089 8090 if (gc->fillStyle == FillSolid || 8091 (gc->fillStyle == FillTiled && gc->tileIsPixel) || 8092 (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { 8093 *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; 8094 return true; 8095 } 8096 8097 return false; 8098} 8099 8100static void 8101sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n, 8102 DDXPointPtr pt, int *width, int sorted) 8103{ 8104 struct sna_fill_spans *data = sna_gc(gc)->priv; 8105 uint32_t color; 8106 8107 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 8108 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 8109 8110 assert(PM_IS_SOLID(drawable, gc->planemask)); 8111 if (n == 0) 8112 return; 8113 8114 /* The mi routines do not attempt to keep the spans it generates 8115 * within the clip, so we must run them through the clipper. 8116 */ 8117 8118 if (gc_is_solid(gc, &color)) { 8119 sna_fill_spans_blt(drawable, 8120 data->bo, NULL, 8121 gc, color, n, pt, width, sorted, 8122 &data->region.extents, 2); 8123 } else { 8124 /* Try converting these to a set of rectangles instead */ 8125 xRectangle *rect; 8126 int i; 8127 8128 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8129 8130 rect = malloc (n * sizeof (xRectangle)); 8131 if (rect == NULL) 8132 return; 8133 8134 for (i = 0; i < n; i++) { 8135 rect[i].x = pt[i].x - drawable->x; 8136 rect[i].width = width[i]; 8137 rect[i].y = pt[i].y - drawable->y; 8138 rect[i].height = 1; 8139 } 8140 8141 if (gc->fillStyle == FillTiled) { 8142 (void)sna_poly_fill_rect_tiled_blt(drawable, 8143 data->bo, NULL, 8144 gc, n, rect, 8145 &data->region.extents, 2); 8146 } else { 8147 (void)sna_poly_fill_rect_stippled_blt(drawable, 8148 data->bo, NULL, 8149 gc, n, rect, 8150 &data->region.extents, 2); 8151 } 8152 free (rect); 8153 } 8154} 8155 8156static unsigned 8157sna_spans_extents(DrawablePtr drawable, GCPtr gc, 8158 int n, DDXPointPtr pt, int *width, 8159 BoxPtr out) 8160{ 8161 BoxRec box; 8162 bool clipped = false; 8163 8164 if (n == 0) 8165 return 0; 8166 8167 box.x1 = pt->x; 8168 box.x2 = box.x1 + *width; 8169 box.y2 = box.y1 = pt->y; 8170 8171 while (--n) { 8172 pt++; 8173 width++; 8174 if (box.x1 > pt->x) 8175 box.x1 = pt->x; 8176 if (box.x2 < pt->x + *width) 8177 box.x2 = pt->x + *width; 8178 8179 if (box.y1 > pt->y) 8180 box.y1 = pt->y; 8181 else if (box.y2 < pt->y) 8182 box.y2 = pt->y; 8183 } 8184 box.y2++; 8185 8186 if (gc) 8187 clipped = clip_box(&box, gc); 8188 if (box_empty(&box)) 8189 return 0; 8190 8191 *out = box; 8192 return 1 | clipped << 1; 8193} 8194 8195static void 8196sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n, 8197 DDXPointPtr pt, int *width, int sorted) 8198{ 8199 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8200 struct sna *sna = to_sna_from_pixmap(pixmap); 8201 struct sna_damage **damage; 8202 struct kgem_bo *bo; 8203 RegionRec region; 8204 unsigned flags; 8205 uint32_t color; 8206 8207 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 8208 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 8209 8210 flags = sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents); 8211 if (flags == 0) 8212 return; 8213 8214 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 8215 region.extents.x1, region.extents.y1, 8216 region.extents.x2, region.extents.y2)); 8217 8218 if (FORCE_FALLBACK) 8219 goto fallback; 8220 8221 if (!ACCEL_FILL_SPANS) 8222 goto fallback; 8223 8224 if (wedged(sna)) { 8225 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8226 goto fallback; 8227 } 8228 8229 DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__, 8230 gc->fillStyle, gc->fillStyle == FillSolid, 8231 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 8232 if (!PM_IS_SOLID(drawable, gc->planemask)) 8233 goto fallback; 8234 8235 bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8236 ®ion.extents, &damage); 8237 if (bo) { 8238 if (gc_is_solid(gc, &color)) { 8239 DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n", 8240 __FUNCTION__, gc->alu, gc->fgPixel)); 8241 8242 sna_fill_spans_blt(drawable, 8243 bo, damage, 8244 gc, color, n, pt, width, sorted, 8245 ®ion.extents, flags & IS_CLIPPED); 8246 } else { 8247 /* Try converting these to a set of rectangles instead */ 8248 xRectangle *rect; 8249 int i; 8250 8251 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8252 8253 rect = malloc (n * sizeof (xRectangle)); 8254 if (rect == NULL) 8255 return; 8256 8257 for (i = 0; i < n; i++) { 8258 rect[i].x = pt[i].x - drawable->x; 8259 rect[i].width = width[i]; 8260 rect[i].y = pt[i].y - drawable->y; 8261 rect[i].height = 1; 8262 } 8263 8264 if (gc->fillStyle == FillTiled) { 8265 i = sna_poly_fill_rect_tiled_blt(drawable, 8266 bo, damage, 8267 gc, n, rect, 8268 ®ion.extents, flags & IS_CLIPPED); 8269 } else { 8270 i = sna_poly_fill_rect_stippled_blt(drawable, 8271 bo, damage, 8272 gc, n, rect, 8273 ®ion.extents, flags & IS_CLIPPED); 8274 } 8275 free (rect); 8276 8277 if (i) 8278 return; 8279 } 8280 } 8281 8282fallback: 8283 DBG(("%s: fallback\n", __FUNCTION__)); 8284 region.data = NULL; 8285 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8286 return; 8287 8288 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8289 goto out; 8290 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8291 drawable_gc_flags(drawable, gc, n > 1))) 8292 goto out; 8293 8294 if (sigtrap_get() == 0) { 8295 DBG(("%s: fbFillSpans\n", __FUNCTION__)); 8296 fbFillSpans(drawable, gc, n, pt, width, sorted); 8297 FALLBACK_FLUSH(drawable); 8298 sigtrap_put(); 8299 } 8300out: 8301 sna_gc_move_to_gpu(gc); 8302 RegionUninit(®ion); 8303} 8304 8305static void 8306sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 8307 DDXPointPtr pt, int *width, int n, int sorted) 8308{ 8309 RegionRec region; 8310 8311 if (sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents) == 0) 8312 return; 8313 8314 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 8315 region.extents.x1, region.extents.y1, 8316 region.extents.x2, region.extents.y2)); 8317 8318 if (FORCE_FALLBACK) 8319 goto fallback; 8320 8321 if (!ACCEL_SET_SPANS) 8322 goto fallback; 8323 8324fallback: 8325 region.data = NULL; 8326 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8327 return; 8328 8329 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8330 goto out; 8331 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8332 drawable_gc_flags(drawable, gc, n > 1))) 8333 goto out; 8334 8335 if (sigtrap_get() == 0) { 8336 DBG(("%s: fbSetSpans\n", __FUNCTION__)); 8337 fbSetSpans(drawable, gc, src, pt, width, n, sorted); 8338 FALLBACK_FLUSH(drawable); 8339 sigtrap_put(); 8340 } 8341out: 8342 sna_gc_move_to_gpu(gc); 8343 RegionUninit(®ion); 8344} 8345 8346struct sna_copy_plane { 8347 struct sna_damage **damage; 8348 struct kgem_bo *bo; 8349}; 8350 8351static void 8352sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, 8353 RegionRec *region, int sx, int sy, 8354 Pixel bitplane, void *closure) 8355{ 8356 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8357 struct sna *sna = to_sna_from_pixmap(pixmap); 8358 struct sna_copy_plane *arg = closure; 8359 PixmapPtr bitmap = (PixmapPtr)_bitmap; 8360 uint32_t br00, br13; 8361 int16_t dx, dy; 8362 const BoxRec *box; 8363 int n; 8364 8365 DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n", 8366 __FUNCTION__, (unsigned)bitplane, 8367 region->extents.x1, region->extents.y1, 8368 region->extents.x2, region->extents.y2, 8369 region_num_rects(region))); 8370 8371 box = region_rects(region); 8372 n = region_num_rects(region); 8373 assert(n); 8374 8375 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8376 assert_pixmap_contains_boxes(pixmap, box, n, dx, dy); 8377 8378 br00 = 3 << 20; 8379 br13 = arg->bo->pitch; 8380 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8381 br00 |= BLT_DST_TILED; 8382 br13 >>= 2; 8383 } 8384 br13 |= blt_depth(drawable->depth) << 24; 8385 br13 |= copy_ROP[gc->alu] << 16; 8386 DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n", 8387 __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel)); 8388 8389 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8390 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8391 do { 8392 int bx1 = (box->x1 + sx) & ~7; 8393 int bx2 = (box->x2 + sx + 7) & ~7; 8394 int bw = (bx2 - bx1)/8; 8395 int bh = box->y2 - box->y1; 8396 int bstride = ALIGN(bw, 2); 8397 int src_stride; 8398 uint8_t *dst, *src; 8399 uint32_t *b; 8400 8401 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8402 __FUNCTION__, 8403 box->x1, box->y1, 8404 box->x2, box->y2, 8405 sx, sy, bx1, bx2)); 8406 8407 src_stride = bstride*bh; 8408 assert(src_stride > 0); 8409 if (src_stride <= 128) { 8410 src_stride = ALIGN(src_stride, 8) / 4; 8411 assert(src_stride <= 32); 8412 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 8413 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8414 !kgem_check_reloc(&sna->kgem, 1)) { 8415 kgem_submit(&sna->kgem); 8416 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8417 return; /* XXX fallback? */ 8418 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8419 } 8420 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8421 8422 assert(sna->kgem.mode == KGEM_BLT); 8423 if (sna->kgem.gen >= 0100) { 8424 b = sna->kgem.batch + sna->kgem.nbatch; 8425 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 8426 b[0] |= ((box->x1 + sx) & 7) << 17; 8427 b[1] = br13; 8428 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8429 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8430 *(uint64_t *)(b+4) = 8431 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8432 I915_GEM_DOMAIN_RENDER << 16 | 8433 I915_GEM_DOMAIN_RENDER | 8434 KGEM_RELOC_FENCED, 8435 0); 8436 b[6] = gc->bgPixel; 8437 b[7] = gc->fgPixel; 8438 8439 dst = (uint8_t *)&b[8]; 8440 sna->kgem.nbatch += 8 + src_stride; 8441 } else { 8442 b = sna->kgem.batch + sna->kgem.nbatch; 8443 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 8444 b[0] |= ((box->x1 + sx) & 7) << 17; 8445 b[1] = br13; 8446 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8447 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8448 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8449 I915_GEM_DOMAIN_RENDER << 16 | 8450 I915_GEM_DOMAIN_RENDER | 8451 KGEM_RELOC_FENCED, 8452 0); 8453 b[5] = gc->bgPixel; 8454 b[6] = gc->fgPixel; 8455 8456 dst = (uint8_t *)&b[7]; 8457 sna->kgem.nbatch += 7 + src_stride; 8458 } 8459 8460 assert(bitmap->devKind); 8461 src_stride = bitmap->devKind; 8462 src = bitmap->devPrivate.ptr; 8463 src += (box->y1 + sy) * src_stride + bx1/8; 8464 src_stride -= bstride; 8465 do { 8466 int i = bstride; 8467 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8468 do { 8469 *dst++ = byte_reverse(*src++); 8470 *dst++ = byte_reverse(*src++); 8471 i -= 2; 8472 } while (i); 8473 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8474 src += src_stride; 8475 } while (--bh); 8476 } else { 8477 struct kgem_bo *upload; 8478 void *ptr; 8479 8480 if (!kgem_check_batch(&sna->kgem, 10) || 8481 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8482 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8483 kgem_submit(&sna->kgem); 8484 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8485 return; /* XXX fallback? */ 8486 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8487 } 8488 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8489 8490 upload = kgem_create_buffer(&sna->kgem, 8491 bstride*bh, 8492 KGEM_BUFFER_WRITE_INPLACE, 8493 &ptr); 8494 if (!upload) 8495 break; 8496 8497 if (sigtrap_get() == 0) { 8498 assert(sna->kgem.mode == KGEM_BLT); 8499 b = sna->kgem.batch + sna->kgem.nbatch; 8500 if (sna->kgem.gen >= 0100) { 8501 b[0] = XY_MONO_SRC_COPY | br00 | 8; 8502 b[0] |= ((box->x1 + sx) & 7) << 17; 8503 b[1] = br13; 8504 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8505 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8506 *(uint64_t *)(b+4) = 8507 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8508 I915_GEM_DOMAIN_RENDER << 16 | 8509 I915_GEM_DOMAIN_RENDER | 8510 KGEM_RELOC_FENCED, 8511 0); 8512 *(uint64_t *)(b+6) = 8513 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8514 I915_GEM_DOMAIN_RENDER << 16 | 8515 KGEM_RELOC_FENCED, 8516 0); 8517 b[8] = gc->bgPixel; 8518 b[9] = gc->fgPixel; 8519 8520 sna->kgem.nbatch += 10; 8521 } else { 8522 b[0] = XY_MONO_SRC_COPY | br00 | 6; 8523 b[0] |= ((box->x1 + sx) & 7) << 17; 8524 b[1] = br13; 8525 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8526 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8527 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8528 I915_GEM_DOMAIN_RENDER << 16 | 8529 I915_GEM_DOMAIN_RENDER | 8530 KGEM_RELOC_FENCED, 8531 0); 8532 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8533 I915_GEM_DOMAIN_RENDER << 16 | 8534 KGEM_RELOC_FENCED, 8535 0); 8536 b[6] = gc->bgPixel; 8537 b[7] = gc->fgPixel; 8538 8539 sna->kgem.nbatch += 8; 8540 } 8541 8542 dst = ptr; 8543 assert(bitmap->devKind); 8544 src_stride = bitmap->devKind; 8545 src = bitmap->devPrivate.ptr; 8546 src += (box->y1 + sy) * src_stride + bx1/8; 8547 src_stride -= bstride; 8548 do { 8549 int i = bstride; 8550 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8551 do { 8552 *dst++ = byte_reverse(*src++); 8553 *dst++ = byte_reverse(*src++); 8554 i -= 2; 8555 } while (i); 8556 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8557 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 8558 src += src_stride; 8559 } while (--bh); 8560 8561 sigtrap_put(); 8562 } 8563 8564 kgem_bo_destroy(&sna->kgem, upload); 8565 } 8566 8567 box++; 8568 } while (--n); 8569 8570 if (arg->damage) { 8571 RegionTranslate(region, dx, dy); 8572 sna_damage_add_to_pixmap(arg->damage, region, pixmap); 8573 } 8574 assert_pixmap_damage(pixmap); 8575 blt_done(sna); 8576} 8577 8578static void 8579sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, 8580 RegionPtr region, int sx, int sy, 8581 Pixel bitplane, void *closure) 8582{ 8583 PixmapPtr dst_pixmap = get_drawable_pixmap(drawable); 8584 PixmapPtr src_pixmap = get_drawable_pixmap(source); 8585 struct sna *sna = to_sna_from_pixmap(dst_pixmap); 8586 struct sna_copy_plane *arg = closure; 8587 int16_t dx, dy; 8588 int bit = ffs(bitplane) - 1; 8589 uint32_t br00, br13; 8590 const BoxRec *box = region_rects(region); 8591 int n = region_num_rects(region); 8592 8593 DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__, 8594 (unsigned)bitplane, bit, n)); 8595 8596 if (n == 0) 8597 return; 8598 8599 if (get_drawable_deltas(source, src_pixmap, &dx, &dy)) 8600 sx += dx, sy += dy; 8601 8602 get_drawable_deltas(drawable, dst_pixmap, &dx, &dy); 8603 assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy); 8604 8605 br00 = XY_MONO_SRC_COPY | 3 << 20; 8606 br13 = arg->bo->pitch; 8607 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8608 br00 |= BLT_DST_TILED; 8609 br13 >>= 2; 8610 } 8611 br13 |= blt_depth(drawable->depth) << 24; 8612 br13 |= copy_ROP[gc->alu] << 16; 8613 8614 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8615 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8616 do { 8617 int bx1 = (box->x1 + sx) & ~7; 8618 int bx2 = (box->x2 + sx + 7) & ~7; 8619 int bw = (bx2 - bx1)/8; 8620 int bh = box->y2 - box->y1; 8621 int bstride = ALIGN(bw, 2); 8622 struct kgem_bo *upload; 8623 void *ptr; 8624 8625 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8626 __FUNCTION__, 8627 box->x1, box->y1, 8628 box->x2, box->y2, 8629 sx, sy, bx1, bx2)); 8630 8631 if (!kgem_check_batch(&sna->kgem, 10) || 8632 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8633 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8634 kgem_submit(&sna->kgem); 8635 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8636 return; /* XXX fallback? */ 8637 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8638 } 8639 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8640 8641 upload = kgem_create_buffer(&sna->kgem, 8642 bstride*bh, 8643 KGEM_BUFFER_WRITE_INPLACE, 8644 &ptr); 8645 if (!upload) 8646 break; 8647 8648 if (sigtrap_get() == 0) { 8649 uint32_t *b; 8650 8651 assert(src_pixmap->devKind); 8652 switch (source->bitsPerPixel) { 8653 case 32: 8654 { 8655 uint32_t *src = src_pixmap->devPrivate.ptr; 8656 int src_stride = src_pixmap->devKind/sizeof(uint32_t); 8657 uint8_t *dst = ptr; 8658 8659 src += (box->y1 + sy) * src_stride; 8660 src += bx1; 8661 8662 src_stride -= bw * 8; 8663 bstride -= bw; 8664 8665 do { 8666 int i = bw; 8667 do { 8668 uint8_t v = 0; 8669 8670 v |= ((*src++ >> bit) & 1) << 7; 8671 v |= ((*src++ >> bit) & 1) << 6; 8672 v |= ((*src++ >> bit) & 1) << 5; 8673 v |= ((*src++ >> bit) & 1) << 4; 8674 v |= ((*src++ >> bit) & 1) << 3; 8675 v |= ((*src++ >> bit) & 1) << 2; 8676 v |= ((*src++ >> bit) & 1) << 1; 8677 v |= ((*src++ >> bit) & 1) << 0; 8678 8679 *dst++ = v; 8680 } while (--i); 8681 dst += bstride; 8682 src += src_stride; 8683 } while (--bh); 8684 break; 8685 } 8686 case 16: 8687 { 8688 uint16_t *src = src_pixmap->devPrivate.ptr; 8689 int src_stride = src_pixmap->devKind/sizeof(uint16_t); 8690 uint8_t *dst = ptr; 8691 8692 src += (box->y1 + sy) * src_stride; 8693 src += bx1; 8694 8695 src_stride -= bw * 8; 8696 bstride -= bw; 8697 8698 do { 8699 int i = bw; 8700 do { 8701 uint8_t v = 0; 8702 8703 v |= ((*src++ >> bit) & 1) << 7; 8704 v |= ((*src++ >> bit) & 1) << 6; 8705 v |= ((*src++ >> bit) & 1) << 5; 8706 v |= ((*src++ >> bit) & 1) << 4; 8707 v |= ((*src++ >> bit) & 1) << 3; 8708 v |= ((*src++ >> bit) & 1) << 2; 8709 v |= ((*src++ >> bit) & 1) << 1; 8710 v |= ((*src++ >> bit) & 1) << 0; 8711 8712 *dst++ = v; 8713 } while (--i); 8714 dst += bstride; 8715 src += src_stride; 8716 } while (--bh); 8717 break; 8718 } 8719 default: 8720 assert(0); 8721 case 8: 8722 { 8723 uint8_t *src = src_pixmap->devPrivate.ptr; 8724 int src_stride = src_pixmap->devKind/sizeof(uint8_t); 8725 uint8_t *dst = ptr; 8726 8727 src += (box->y1 + sy) * src_stride; 8728 src += bx1; 8729 8730 src_stride -= bw * 8; 8731 bstride -= bw; 8732 8733 do { 8734 int i = bw; 8735 do { 8736 uint8_t v = 0; 8737 8738 v |= ((*src++ >> bit) & 1) << 7; 8739 v |= ((*src++ >> bit) & 1) << 6; 8740 v |= ((*src++ >> bit) & 1) << 5; 8741 v |= ((*src++ >> bit) & 1) << 4; 8742 v |= ((*src++ >> bit) & 1) << 3; 8743 v |= ((*src++ >> bit) & 1) << 2; 8744 v |= ((*src++ >> bit) & 1) << 1; 8745 v |= ((*src++ >> bit) & 1) << 0; 8746 8747 *dst++ = v; 8748 } while (--i); 8749 dst += bstride; 8750 src += src_stride; 8751 } while (--bh); 8752 break; 8753 } 8754 } 8755 8756 kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo); 8757 8758 assert(sna->kgem.mode == KGEM_BLT); 8759 b = sna->kgem.batch + sna->kgem.nbatch; 8760 if (sna->kgem.gen >= 0100) { 8761 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8; 8762 b[1] = br13; 8763 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8764 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8765 *(uint64_t *)(b+4) = 8766 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8767 I915_GEM_DOMAIN_RENDER << 16 | 8768 I915_GEM_DOMAIN_RENDER | 8769 KGEM_RELOC_FENCED, 8770 0); 8771 *(uint64_t *)(b+6) = 8772 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8773 I915_GEM_DOMAIN_RENDER << 16 | 8774 KGEM_RELOC_FENCED, 8775 0); 8776 b[8] = gc->bgPixel; 8777 b[9] = gc->fgPixel; 8778 8779 sna->kgem.nbatch += 10; 8780 } else { 8781 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6; 8782 b[1] = br13; 8783 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8784 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8785 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8786 I915_GEM_DOMAIN_RENDER << 16 | 8787 I915_GEM_DOMAIN_RENDER | 8788 KGEM_RELOC_FENCED, 8789 0); 8790 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8791 I915_GEM_DOMAIN_RENDER << 16 | 8792 KGEM_RELOC_FENCED, 8793 0); 8794 b[6] = gc->bgPixel; 8795 b[7] = gc->fgPixel; 8796 8797 sna->kgem.nbatch += 8; 8798 } 8799 sigtrap_put(); 8800 } 8801 kgem_bo_destroy(&sna->kgem, upload); 8802 8803 box++; 8804 } while (--n); 8805 8806 if (arg->damage) { 8807 RegionTranslate(region, dx, dy); 8808 sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap); 8809 } 8810 assert_pixmap_damage(dst_pixmap); 8811 blt_done(sna); 8812} 8813 8814static RegionPtr 8815sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 8816 int src_x, int src_y, 8817 int w, int h, 8818 int dst_x, int dst_y, 8819 unsigned long bit) 8820{ 8821 PixmapPtr pixmap = get_drawable_pixmap(dst); 8822 struct sna *sna = to_sna_from_pixmap(pixmap); 8823 RegionRec region, *ret = NULL; 8824 struct sna_copy_plane arg; 8825 8826 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__, 8827 src_x, src_y, dst_x, dst_y, w, h)); 8828 8829 if (gc->planemask == 0) 8830 goto empty; 8831 8832 if (src->bitsPerPixel == 1 && (bit&1) == 0) 8833 goto empty; 8834 8835 region.extents.x1 = dst_x + dst->x; 8836 region.extents.y1 = dst_y + dst->y; 8837 region.extents.x2 = region.extents.x1 + w; 8838 region.extents.y2 = region.extents.y1 + h; 8839 region.data = NULL; 8840 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 8841 8842 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", 8843 __FUNCTION__, 8844 region.extents.x1, region.extents.y1, 8845 region.extents.x2, region.extents.y2)); 8846 8847 { 8848 RegionRec clip; 8849 8850 clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x); 8851 clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y); 8852 clip.extents.x2 = clip.extents.x1 + src->width; 8853 clip.extents.y2 = clip.extents.y1 + src->height; 8854 clip.data = NULL; 8855 8856 DBG(("%s: src extents (%d, %d), (%d, %d)\n", 8857 __FUNCTION__, 8858 clip.extents.x1, clip.extents.y1, 8859 clip.extents.x2, clip.extents.y2)); 8860 8861 RegionIntersect(®ion, ®ion, &clip); 8862 } 8863 DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n", 8864 __FUNCTION__, 8865 region.extents.x1, region.extents.y1, 8866 region.extents.x2, region.extents.y2)); 8867 if (box_empty(®ion.extents)) 8868 goto empty; 8869 8870 RegionTranslate(®ion, 8871 src_x - dst_x - dst->x + src->x, 8872 src_y - dst_y - dst->y + src->y); 8873 8874 if (!sna_drawable_move_region_to_cpu(src, ®ion, MOVE_READ)) 8875 goto out; 8876 8877 RegionTranslate(®ion, 8878 -(src_x - dst_x - dst->x + src->x), 8879 -(src_y - dst_y - dst->y + src->y)); 8880 8881 if (FORCE_FALLBACK) 8882 goto fallback; 8883 8884 if (!ACCEL_COPY_PLANE) 8885 goto fallback; 8886 8887 if (wedged(sna)) 8888 goto fallback; 8889 8890 if (!PM_IS_SOLID(dst, gc->planemask)) 8891 goto fallback; 8892 8893 arg.bo = sna_drawable_use_bo(dst, PREFER_GPU, 8894 ®ion.extents, &arg.damage); 8895 if (arg.bo) { 8896 if (arg.bo->tiling == I915_TILING_Y) { 8897 assert(arg.bo == __sna_pixmap_get_bo(pixmap)); 8898 arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 8899 if (arg.bo == NULL) { 8900 DBG(("%s: fallback -- unable to change tiling\n", 8901 __FUNCTION__)); 8902 goto fallback; 8903 } 8904 } 8905 8906 if (!kgem_bo_can_blt(&sna->kgem, arg.bo)) 8907 return false; 8908 8909 RegionUninit(®ion); 8910 return sna_do_copy(src, dst, gc, 8911 src_x, src_y, 8912 w, h, 8913 dst_x, dst_y, 8914 src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt, 8915 (Pixel)bit, &arg); 8916 } 8917 8918fallback: 8919 DBG(("%s: fallback\n", __FUNCTION__)); 8920 if (!sna_gc_move_to_cpu(gc, dst, ®ion)) 8921 goto out; 8922 if (!sna_drawable_move_region_to_cpu(dst, ®ion, 8923 drawable_gc_flags(dst, gc, false))) 8924 goto out; 8925 8926 if (sigtrap_get() == 0) { 8927 DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n", 8928 __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit)); 8929 ret = miDoCopy(src, dst, gc, 8930 src_x, src_y, w, h, dst_x, dst_y, 8931 src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN, 8932 bit, 0); 8933 FALLBACK_FLUSH(dst); 8934 sigtrap_put(); 8935 } 8936out: 8937 sna_gc_move_to_gpu(gc); 8938 RegionUninit(®ion); 8939 return ret; 8940empty: 8941 return miHandleExposures(src, dst, gc, 8942 src_x, src_y, 8943 w, h, 8944 dst_x, dst_y, bit); 8945} 8946 8947static bool 8948sna_poly_point_blt(DrawablePtr drawable, 8949 struct kgem_bo *bo, 8950 struct sna_damage **damage, 8951 GCPtr gc, int mode, int n, DDXPointPtr pt, 8952 bool clipped) 8953{ 8954 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8955 struct sna *sna = to_sna_from_pixmap(pixmap); 8956 BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box); 8957 struct sna_fill_op fill; 8958 DDXPointRec last; 8959 int16_t dx, dy; 8960 8961 DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n", 8962 __FUNCTION__, gc->alu, gc->fgPixel, clipped)); 8963 8964 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS)) 8965 return false; 8966 8967 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8968 8969 last.x = drawable->x; 8970 last.y = drawable->y; 8971 8972 if (!clipped) { 8973 last.x += dx; 8974 last.y += dy; 8975 8976 assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y); 8977 sna_damage_add_points(damage, pt, n, last.x, last.y); 8978 if (fill.points && mode != CoordModePrevious) { 8979 fill.points(sna, &fill, last.x, last.y, pt, n); 8980 } else { 8981 do { 8982 unsigned nbox = n; 8983 if (nbox > ARRAY_SIZE(box)) 8984 nbox = ARRAY_SIZE(box); 8985 n -= nbox; 8986 do { 8987 *(DDXPointRec *)b = *pt++; 8988 8989 b->x1 += last.x; 8990 b->y1 += last.y; 8991 if (mode == CoordModePrevious) 8992 last = *(DDXPointRec *)b; 8993 8994 b->x2 = b->x1 + 1; 8995 b->y2 = b->y1 + 1; 8996 b++; 8997 } while (--nbox); 8998 fill.boxes(sna, &fill, box, b - box); 8999 b = box; 9000 } while (n); 9001 } 9002 } else { 9003 RegionPtr clip = gc->pCompositeClip; 9004 9005 while (n--) { 9006 int x, y; 9007 9008 x = pt->x; 9009 y = pt->y; 9010 pt++; 9011 if (mode == CoordModePrevious) { 9012 x += last.x; 9013 y += last.y; 9014 last.x = x; 9015 last.y = y; 9016 } else { 9017 x += drawable->x; 9018 y += drawable->y; 9019 } 9020 9021 if (RegionContainsPoint(clip, x, y, NULL)) { 9022 b->x1 = x + dx; 9023 b->y1 = y + dy; 9024 b->x2 = b->x1 + 1; 9025 b->y2 = b->y1 + 1; 9026 if (++b == last_box){ 9027 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 9028 fill.boxes(sna, &fill, box, last_box - box); 9029 if (damage) 9030 sna_damage_add_boxes(damage, box, last_box-box, 0, 0); 9031 b = box; 9032 } 9033 } 9034 } 9035 if (b != box){ 9036 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9037 fill.boxes(sna, &fill, box, b - box); 9038 if (damage) 9039 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9040 } 9041 } 9042 fill.done(sna, &fill); 9043 assert_pixmap_damage(pixmap); 9044 return true; 9045} 9046 9047static unsigned 9048sna_poly_point_extents(DrawablePtr drawable, GCPtr gc, 9049 int mode, int n, DDXPointPtr pt, BoxPtr out) 9050{ 9051 BoxRec box; 9052 bool clipped; 9053 9054 if (n == 0) 9055 return 0; 9056 9057 box.x2 = box.x1 = pt->x; 9058 box.y2 = box.y1 = pt->y; 9059 if (mode == CoordModePrevious) { 9060 DDXPointRec last = *pt++; 9061 while (--n) { 9062 last.x += pt->x; 9063 last.y += pt->y; 9064 pt++; 9065 box_add_xy(&box, last.x, last.y); 9066 } 9067 } else { 9068 while (--n) 9069 box_add_pt(&box, ++pt); 9070 } 9071 box.x2++; 9072 box.y2++; 9073 9074 clipped = trim_and_translate_box(&box, drawable, gc); 9075 if (box_empty(&box)) 9076 return 0; 9077 9078 *out = box; 9079 return 1 | clipped << 1; 9080} 9081 9082static void 9083sna_poly_point(DrawablePtr drawable, GCPtr gc, 9084 int mode, int n, DDXPointPtr pt) 9085{ 9086 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9087 struct sna *sna = to_sna_from_pixmap(pixmap); 9088 RegionRec region; 9089 unsigned flags; 9090 9091 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n", 9092 __FUNCTION__, mode, n, pt[0].x, pt[0].y)); 9093 9094 flags = sna_poly_point_extents(drawable, gc, mode, n, pt, ®ion.extents); 9095 if (flags == 0) 9096 return; 9097 9098 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9099 region.extents.x1, region.extents.y1, 9100 region.extents.x2, region.extents.y2, 9101 flags)); 9102 9103 if (FORCE_FALLBACK) 9104 goto fallback; 9105 9106 if (!ACCEL_POLY_POINT) 9107 goto fallback; 9108 9109 if (wedged(sna)) { 9110 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9111 goto fallback; 9112 } 9113 9114 if (PM_IS_SOLID(drawable, gc->planemask)) { 9115 struct sna_damage **damage; 9116 struct kgem_bo *bo; 9117 9118 DBG(("%s: trying solid fill [%08lx] blt paths\n", 9119 __FUNCTION__, gc->fgPixel)); 9120 9121 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9122 ®ion.extents, &damage)) && 9123 sna_poly_point_blt(drawable, bo, damage, 9124 gc, mode, n, pt, flags & IS_CLIPPED)) 9125 return; 9126 } 9127 9128fallback: 9129 DBG(("%s: fallback\n", __FUNCTION__)); 9130 region.data = NULL; 9131 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 9132 return; 9133 9134 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 9135 goto out; 9136 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 9137 MOVE_READ | MOVE_WRITE)) 9138 goto out; 9139 9140 if (sigtrap_get() == 0) { 9141 DBG(("%s: fbPolyPoint\n", __FUNCTION__)); 9142 fbPolyPoint(drawable, gc, mode, n, pt, flags); 9143 FALLBACK_FLUSH(drawable); 9144 sigtrap_put(); 9145 } 9146out: 9147 sna_gc_move_to_gpu(gc); 9148 RegionUninit(®ion); 9149} 9150 9151static bool 9152sna_poly_zero_line_blt(DrawablePtr drawable, 9153 struct kgem_bo *bo, 9154 struct sna_damage **damage, 9155 GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt, 9156 const BoxRec *extents, unsigned clipped) 9157{ 9158 static void * const _jump[] = { 9159 &&no_damage, 9160 &&damage, 9161 9162 &&no_damage_offset, 9163 &&damage_offset, 9164 }; 9165 9166 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9167 struct sna *sna = to_sna_from_pixmap(pixmap); 9168 int x2, y2, xstart, ystart, oc2; 9169 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 9170 bool degenerate = true; 9171 struct sna_fill_op fill; 9172 RegionRec clip; 9173 BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box); 9174 const BoxRec *last_extents; 9175 int16_t dx, dy; 9176 void *jump, *ret; 9177 9178 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 9179 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 9180 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS)) 9181 return false; 9182 9183 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9184 9185 region_set(&clip, extents); 9186 if (clipped) { 9187 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9188 return true; 9189 } 9190 9191 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 9192 DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n", 9193 __FUNCTION__, clipped, 9194 clip.extents.x1, clip.extents.y1, 9195 clip.extents.x2, clip.extents.y2, 9196 dx, dy, damage)); 9197 9198 extents = region_rects(&clip); 9199 last_extents = extents + region_num_rects(&clip); 9200 9201 b = box; 9202 do { 9203 int n = _n; 9204 const DDXPointRec *pt = _pt; 9205 9206 xstart = pt->x + drawable->x; 9207 ystart = pt->y + drawable->y; 9208 9209 x2 = xstart; 9210 y2 = ystart; 9211 oc2 = 0; 9212 OUTCODES(oc2, x2, y2, extents); 9213 9214 while (--n) { 9215 int16_t sdx, sdy; 9216 int adx, ady, length; 9217 int e, e1, e2, e3; 9218 int x1 = x2, x; 9219 int y1 = y2, y; 9220 int oc1 = oc2; 9221 int octant; 9222 9223 ++pt; 9224 9225 x2 = pt->x; 9226 y2 = pt->y; 9227 if (mode == CoordModePrevious) { 9228 x2 += x1; 9229 y2 += y1; 9230 } else { 9231 x2 += drawable->x; 9232 y2 += drawable->y; 9233 } 9234 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 9235 __FUNCTION__, x1, y1, x2, y2)); 9236 if (x2 == x1 && y2 == y1) 9237 continue; 9238 9239 degenerate = false; 9240 9241 oc2 = 0; 9242 OUTCODES(oc2, x2, y2, extents); 9243 if (oc1 & oc2) 9244 continue; 9245 9246 CalcLineDeltas(x1, y1, x2, y2, 9247 adx, ady, sdx, sdy, 9248 1, 1, octant); 9249 9250 DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n", 9251 __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2)); 9252 if (adx == 0 || ady == 0) { 9253 if (x1 <= x2) { 9254 b->x1 = x1; 9255 b->x2 = x2; 9256 } else { 9257 b->x1 = x2; 9258 b->x2 = x1; 9259 } 9260 if (y1 <= y2) { 9261 b->y1 = y1; 9262 b->y2 = y2; 9263 } else { 9264 b->y1 = y2; 9265 b->y2 = y1; 9266 } 9267 b->x2++; 9268 b->y2++; 9269 if (oc1 | oc2) { 9270 bool intersects; 9271 9272 intersects = box_intersect(b, extents); 9273 assert(intersects); 9274 } 9275 if (++b == last_box) { 9276 ret = &&rectangle_continue; 9277 goto *jump; 9278rectangle_continue: 9279 b = box; 9280 } 9281 } else if (adx >= ady) { 9282 int x2_clipped = x2, y2_clipped = y2; 9283 bool dirty; 9284 9285 /* X-major segment */ 9286 e1 = ady << 1; 9287 e2 = e1 - (adx << 1); 9288 e = e1 - adx; 9289 length = adx; 9290 9291 FIXUP_ERROR(e, octant, bias); 9292 9293 x = x1; 9294 y = y1; 9295 9296 if (oc1 | oc2) { 9297 int pt1_clipped, pt2_clipped; 9298 9299 if (miZeroClipLine(extents->x1, extents->y1, 9300 extents->x2-1, extents->y2-1, 9301 &x, &y, &x2_clipped, &y2_clipped, 9302 adx, ady, 9303 &pt1_clipped, &pt2_clipped, 9304 octant, bias, oc1, oc2) == -1) 9305 continue; 9306 9307 length = abs(x2_clipped - x); 9308 if (length == 0) 9309 continue; 9310 9311 if (pt1_clipped) { 9312 int clipdx = abs(x - x1); 9313 int clipdy = abs(y - y1); 9314 e += clipdy * e2 + (clipdx - clipdy) * e1; 9315 } 9316 } 9317 9318 e3 = e2 - e1; 9319 e = e - e1; 9320 9321 b->x1 = x; 9322 b->y1 = y; 9323 dirty = false; 9324 while (length--) { 9325 e += e1; 9326 dirty = true; 9327 if (e >= 0) { 9328 e += e3; 9329 9330 if (sdx < 0) { 9331 b->x2 = b->x1 + 1; 9332 b->x1 = x; 9333 } else 9334 b->x2 = x + 1; 9335 b->y2 = b->y1 + 1; 9336 9337 if (++b == last_box) { 9338 ret = &&X_continue; 9339 goto *jump; 9340X_continue: 9341 b = box; 9342 } 9343 9344 b->x1 = x + sdx; 9345 b->y1 = y += sdy; 9346 dirty = false; 9347 } 9348 x += sdx; 9349 } 9350 if (dirty) { 9351 x -= sdx; 9352 if (sdx < 0) { 9353 b->x2 = b->x1 + 1; 9354 b->x1 = x; 9355 } else 9356 b->x2 = x + 1; 9357 b->y2 = b->y1 + 1; 9358 9359 if (++b == last_box) { 9360 ret = &&X2_continue; 9361 goto *jump; 9362X2_continue: 9363 b = box; 9364 } 9365 } 9366 } else { 9367 int x2_clipped = x2, y2_clipped = y2; 9368 bool dirty; 9369 9370 /* Y-major segment */ 9371 e1 = adx << 1; 9372 e2 = e1 - (ady << 1); 9373 e = e1 - ady; 9374 length = ady; 9375 9376 SetYMajorOctant(octant); 9377 FIXUP_ERROR(e, octant, bias); 9378 9379 x = x1; 9380 y = y1; 9381 9382 if (oc1 | oc2) { 9383 int pt1_clipped, pt2_clipped; 9384 9385 if (miZeroClipLine(extents->x1, extents->y1, 9386 extents->x2-1, extents->y2-1, 9387 &x, &y, &x2_clipped, &y2_clipped, 9388 adx, ady, 9389 &pt1_clipped, &pt2_clipped, 9390 octant, bias, oc1, oc2) == -1) 9391 continue; 9392 9393 length = abs(y2_clipped - y); 9394 if (length == 0) 9395 continue; 9396 9397 if (pt1_clipped) { 9398 int clipdx = abs(x - x1); 9399 int clipdy = abs(y - y1); 9400 e += clipdx * e2 + (clipdy - clipdx) * e1; 9401 } 9402 } 9403 9404 e3 = e2 - e1; 9405 e = e - e1; 9406 9407 b->x1 = x; 9408 b->y1 = y; 9409 dirty = false; 9410 while (length--) { 9411 e += e1; 9412 dirty = true; 9413 if (e >= 0) { 9414 e += e3; 9415 9416 if (sdy < 0) { 9417 b->y2 = b->y1 + 1; 9418 b->y1 = y; 9419 } else 9420 b->y2 = y + 1; 9421 b->x2 = x + 1; 9422 9423 if (++b == last_box) { 9424 ret = &&Y_continue; 9425 goto *jump; 9426Y_continue: 9427 b = box; 9428 } 9429 9430 b->x1 = x += sdx; 9431 b->y1 = y + sdy; 9432 dirty = false; 9433 } 9434 y += sdy; 9435 } 9436 9437 if (dirty) { 9438 y -= sdy; 9439 if (sdy < 0) { 9440 b->y2 = b->y1 + 1; 9441 b->y1 = y; 9442 } else 9443 b->y2 = y + 1; 9444 b->x2 = x + 1; 9445 9446 if (++b == last_box) { 9447 ret = &&Y2_continue; 9448 goto *jump; 9449Y2_continue: 9450 b = box; 9451 } 9452 } 9453 } 9454 } 9455 9456#if 0 9457 /* Only do the CapNotLast check on the last segment 9458 * and only if the endpoint wasn't clipped. And then, if the last 9459 * point is the same as the first point, do not draw it, unless the 9460 * line is degenerate 9461 */ 9462 if (!pt2_clipped && 9463 gc->capStyle != CapNotLast && 9464 !(xstart == x2 && ystart == y2 && !degenerate)) 9465 { 9466 b->x2 = x2; 9467 b->y2 = y2; 9468 if (b->x2 < b->x1) { 9469 int16_t t = b->x1; 9470 b->x1 = b->x2; 9471 b->x2 = t; 9472 } 9473 if (b->y2 < b->y1) { 9474 int16_t t = b->y1; 9475 b->y1 = b->y2; 9476 b->y2 = t; 9477 } 9478 b->x2++; 9479 b->y2++; 9480 b++; 9481 } 9482#endif 9483 } while (++extents != last_extents); 9484 9485 if (b != box) { 9486 ret = &&done; 9487 goto *jump; 9488 } 9489 9490done: 9491 fill.done(sna, &fill); 9492 assert_pixmap_damage(pixmap); 9493 RegionUninit(&clip); 9494 return true; 9495 9496damage: 9497 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9498 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9499no_damage: 9500 fill.boxes(sna, &fill, box, b-box); 9501 goto *ret; 9502 9503no_damage_offset: 9504 { 9505 BoxRec *bb = box; 9506 do { 9507 bb->x1 += dx; 9508 bb->x2 += dx; 9509 bb->y1 += dy; 9510 bb->y2 += dy; 9511 } while (++bb != b); 9512 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9513 fill.boxes(sna, &fill, box, b - box); 9514 } 9515 goto *ret; 9516 9517damage_offset: 9518 { 9519 BoxRec *bb = box; 9520 do { 9521 bb->x1 += dx; 9522 bb->x2 += dx; 9523 bb->y1 += dy; 9524 bb->y2 += dy; 9525 } while (++bb != b); 9526 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9527 fill.boxes(sna, &fill, box, b - box); 9528 sna_damage_add_boxes(damage, box, b - box, 0, 0); 9529 } 9530 goto *ret; 9531} 9532 9533static bool 9534sna_poly_line_blt(DrawablePtr drawable, 9535 struct kgem_bo *bo, 9536 struct sna_damage **damage, 9537 GCPtr gc, uint32_t pixel, 9538 int mode, int n, DDXPointPtr pt, 9539 const BoxRec *extents, bool clipped) 9540{ 9541 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9542 struct sna *sna = to_sna_from_pixmap(pixmap); 9543 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 9544 struct sna_fill_op fill; 9545 DDXPointRec last; 9546 int16_t dx, dy; 9547 9548 DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped)); 9549 9550 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) 9551 return false; 9552 9553 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9554 9555 if (!clipped) { 9556 dx += drawable->x; 9557 dy += drawable->y; 9558 9559 last.x = pt->x + dx; 9560 last.y = pt->y + dy; 9561 pt++; 9562 9563 while (--n) { 9564 DDXPointRec p; 9565 9566 p = *pt++; 9567 if (mode == CoordModePrevious) { 9568 p.x += last.x; 9569 p.y += last.y; 9570 } else { 9571 p.x += dx; 9572 p.y += dy; 9573 } 9574 DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y)); 9575 9576 if (last.x == p.x) { 9577 b->x1 = last.x; 9578 b->x2 = last.x + 1; 9579 } else if (last.x < p.x) { 9580 b->x1 = last.x; 9581 b->x2 = p.x; 9582 } else { 9583 b->x1 = p.x; 9584 b->x2 = last.x; 9585 } 9586 9587 if (last.y == p.y) { 9588 b->y1 = last.y; 9589 b->y2 = last.y + 1; 9590 } else if (last.y < p.y) { 9591 b->y1 = last.y; 9592 b->y2 = p.y; 9593 } else { 9594 b->y1 = p.y; 9595 b->y2 = last.y; 9596 } 9597 b->y2 += last.x == p.x && last.y != p.y; 9598 b->x2 += last.y == p.y && last.x != p.x; 9599 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9600 __FUNCTION__, 9601 b->x1, b->y1, b->x2, b->y2)); 9602 9603 if (++b == last_box) { 9604 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9605 fill.boxes(sna, &fill, boxes, last_box - boxes); 9606 if (damage) 9607 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9608 b = boxes; 9609 } 9610 9611 last = p; 9612 } 9613 } else { 9614 RegionRec clip; 9615 9616 region_set(&clip, extents); 9617 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9618 return true; 9619 9620 last.x = pt->x + drawable->x; 9621 last.y = pt->y + drawable->y; 9622 pt++; 9623 9624 if (clip.data == NULL) { 9625 while (--n) { 9626 DDXPointRec p; 9627 9628 p = *pt++; 9629 if (mode == CoordModePrevious) { 9630 p.x += last.x; 9631 p.y += last.y; 9632 } else { 9633 p.x += drawable->x; 9634 p.y += drawable->y; 9635 } 9636 if (last.x == p.x) { 9637 b->x1 = last.x; 9638 b->x2 = last.x + 1; 9639 } else if (last.x < p.x) { 9640 b->x1 = last.x; 9641 b->x2 = p.x; 9642 } else { 9643 b->x1 = p.x; 9644 b->x2 = last.x; 9645 } 9646 if (last.y == p.y) { 9647 b->y1 = last.y; 9648 b->y2 = last.y + 1; 9649 } else if (last.y < p.y) { 9650 b->y1 = last.y; 9651 b->y2 = p.y; 9652 } else { 9653 b->y1 = p.y; 9654 b->y2 = last.y; 9655 } 9656 b->y2 += last.x == p.x && last.y != p.y; 9657 b->x2 += last.y == p.y && last.x != p.x; 9658 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9659 __FUNCTION__, 9660 b->x1, b->y1, b->x2, b->y2)); 9661 if (box_intersect(b, &clip.extents)) { 9662 b->x1 += dx; 9663 b->x2 += dx; 9664 b->y1 += dy; 9665 b->y2 += dy; 9666 if (++b == last_box) { 9667 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9668 fill.boxes(sna, &fill, boxes, last_box - boxes); 9669 if (damage) 9670 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9671 b = boxes; 9672 } 9673 } 9674 9675 last = p; 9676 } 9677 } else { 9678 const BoxRec * const clip_start = RegionBoxptr(&clip); 9679 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9680 const BoxRec *c; 9681 9682 while (--n) { 9683 DDXPointRec p; 9684 BoxRec box; 9685 9686 p = *pt++; 9687 if (mode == CoordModePrevious) { 9688 p.x += last.x; 9689 p.y += last.y; 9690 } else { 9691 p.x += drawable->x; 9692 p.y += drawable->y; 9693 } 9694 if (last.x == p.x) { 9695 box.x1 = last.x; 9696 box.x2 = last.x + 1; 9697 } else if (last.x < p.x) { 9698 box.x1 = last.x; 9699 box.x2 = p.x; 9700 } else { 9701 box.x1 = p.x; 9702 box.x2 = last.x; 9703 } 9704 if (last.y == p.y) { 9705 box.y1 = last.y; 9706 box.y2 = last.y + 1; 9707 } else if (last.y < p.y) { 9708 box.y1 = last.y; 9709 box.y2 = p.y; 9710 } else { 9711 box.y1 = p.y; 9712 box.y2 = last.y; 9713 } 9714 b->y2 += last.x == p.x && last.y != p.y; 9715 b->x2 += last.y == p.y && last.x != p.x; 9716 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9717 __FUNCTION__, 9718 box.x1, box.y1, box.x2, box.y2)); 9719 9720 c = find_clip_box_for_y(clip_start, 9721 clip_end, 9722 box.y1); 9723 while (c != clip_end) { 9724 if (box.y2 <= c->y1) 9725 break; 9726 9727 *b = box; 9728 if (box_intersect(b, c++)) { 9729 b->x1 += dx; 9730 b->x2 += dx; 9731 b->y1 += dy; 9732 b->y2 += dy; 9733 if (++b == last_box) { 9734 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9735 fill.boxes(sna, &fill, boxes, last_box-boxes); 9736 if (damage) 9737 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9738 b = boxes; 9739 } 9740 } 9741 } 9742 9743 last = p; 9744 } 9745 } 9746 RegionUninit(&clip); 9747 } 9748 if (b != boxes) { 9749 assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0); 9750 fill.boxes(sna, &fill, boxes, b - boxes); 9751 if (damage) 9752 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 9753 } 9754 fill.done(sna, &fill); 9755 assert_pixmap_damage(pixmap); 9756 return true; 9757} 9758 9759static unsigned 9760sna_poly_line_extents(DrawablePtr drawable, GCPtr gc, 9761 int mode, int n, DDXPointPtr pt, 9762 BoxPtr out) 9763{ 9764 BoxRec box; 9765 bool clip, blt = true; 9766 9767 if (n == 0) 9768 return 0; 9769 9770 box.x2 = box.x1 = pt->x; 9771 box.y2 = box.y1 = pt->y; 9772 if (mode == CoordModePrevious) { 9773 int x = box.x1; 9774 int y = box.y1; 9775 while (--n) { 9776 pt++; 9777 x += pt->x; 9778 y += pt->y; 9779 if (blt) 9780 blt &= pt->x == 0 || pt->y == 0; 9781 box_add_xy(&box, x, y); 9782 } 9783 } else { 9784 int x = box.x1; 9785 int y = box.y1; 9786 while (--n) { 9787 pt++; 9788 if (blt) { 9789 blt &= pt->x == x || pt->y == y; 9790 x = pt->x; 9791 y = pt->y; 9792 } 9793 box_add_pt(&box, pt); 9794 } 9795 } 9796 box.x2++; 9797 box.y2++; 9798 9799 if (gc->lineWidth) { 9800 int extra = gc->lineWidth >> 1; 9801 if (n > 1) { 9802 if (gc->joinStyle == JoinMiter) 9803 extra = 6 * gc->lineWidth; 9804 else if (gc->capStyle == CapProjecting) 9805 extra = gc->lineWidth; 9806 } 9807 if (extra) { 9808 box.x1 -= extra; 9809 box.x2 += extra; 9810 box.y1 -= extra; 9811 box.y2 += extra; 9812 } 9813 } 9814 9815 clip = trim_and_translate_box(&box, drawable, gc); 9816 if (box_empty(&box)) 9817 return 0; 9818 9819 *out = box; 9820 return 1 | blt << 2 | clip << 1; 9821} 9822 9823inline static int 9824_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9825{ 9826 uint32_t ignored; 9827 9828 if (USE_SPANS) 9829 return USE_SPANS > 0; 9830 9831 if (flags & RECTILINEAR) 9832 return PREFER_GPU; 9833 9834 if (gc->lineStyle != LineSolid && gc->lineWidth == 0) 9835 return 0; 9836 9837 if (gc_is_solid(gc, &ignored)) 9838 return PREFER_GPU; 9839 9840 return !drawable_gc_inplace_hint(drawable, gc); 9841} 9842 9843inline static int 9844use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9845{ 9846 int ret = _use_line_spans(drawable, gc, extents, flags); 9847 DBG(("%s? %d\n", __FUNCTION__, ret)); 9848 return ret; 9849} 9850 9851static void 9852sna_poly_line(DrawablePtr drawable, GCPtr gc, 9853 int mode, int n, DDXPointPtr pt) 9854{ 9855 struct sna_pixmap *priv; 9856 struct sna_fill_spans data; 9857 uint32_t color; 9858 9859 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n", 9860 __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth)); 9861 9862 data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt, 9863 &data.region.extents); 9864 if (data.flags == 0) 9865 return; 9866 9867 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9868 data.region.extents.x1, data.region.extents.y1, 9869 data.region.extents.x2, data.region.extents.y2, 9870 data.flags)); 9871 9872 data.region.data = NULL; 9873 9874 if (FORCE_FALLBACK) 9875 goto fallback; 9876 9877 if (!ACCEL_POLY_LINE) 9878 goto fallback; 9879 9880 data.pixmap = get_drawable_pixmap(drawable); 9881 data.sna = to_sna_from_pixmap(data.pixmap); 9882 if (wedged(data.sna)) { 9883 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9884 goto fallback; 9885 } 9886 9887 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n", 9888 __FUNCTION__, 9889 gc->fillStyle, gc->fillStyle == FillSolid, 9890 gc->lineStyle, gc->lineStyle == LineSolid, 9891 gc->lineWidth, 9892 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 9893 data.flags & RECTILINEAR)); 9894 9895 if (!PM_IS_SOLID(drawable, gc->planemask)) 9896 goto fallback; 9897 9898 priv = sna_pixmap(data.pixmap); 9899 if (!priv) { 9900 DBG(("%s: not attached to pixmap %ld\n", 9901 __FUNCTION__, data.pixmap->drawable.serialNumber)); 9902 goto fallback; 9903 } 9904 9905 if (gc->lineStyle != LineSolid) { 9906 DBG(("%s: lineStyle, %d, is not solid\n", 9907 __FUNCTION__, gc->lineStyle)); 9908 goto spans_fallback; 9909 } 9910 if (!(gc->lineWidth == 0 || 9911 (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) { 9912 DBG(("%s: non-zero lineWidth %d\n", 9913 __FUNCTION__, gc->lineWidth)); 9914 goto spans_fallback; 9915 } 9916 9917 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9918 &data.region.extents, 9919 &data.damage); 9920 if (data.bo == NULL) 9921 goto fallback; 9922 9923 if (gc_is_solid(gc, &color)) { 9924 DBG(("%s: trying solid fill [%08x]\n", 9925 __FUNCTION__, (unsigned)color)); 9926 if (data.flags & RECTILINEAR) { 9927 if (sna_poly_line_blt(drawable, 9928 data.bo, data.damage, 9929 gc, color, mode, n, pt, 9930 &data.region.extents, 9931 data.flags & IS_CLIPPED)) 9932 return; 9933 } else { /* !rectilinear */ 9934 if (sna_poly_zero_line_blt(drawable, 9935 data.bo, data.damage, 9936 gc, mode, n, pt, 9937 &data.region.extents, 9938 data.flags & IS_CLIPPED)) 9939 return; 9940 9941 } 9942 } else if (data.flags & RECTILINEAR) { 9943 /* Try converting these to a set of rectangles instead */ 9944 DDXPointRec p1, p2; 9945 xRectangle *rect; 9946 int i; 9947 9948 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 9949 9950 rect = malloc (n * sizeof (xRectangle)); 9951 if (rect == NULL) 9952 return; 9953 9954 p1 = pt[0]; 9955 for (i = 1; i < n; i++) { 9956 if (mode == CoordModePrevious) { 9957 p2.x = p1.x + pt[i].x; 9958 p2.y = p1.y + pt[i].y; 9959 } else 9960 p2 = pt[i]; 9961 if (p1.x < p2.x) { 9962 rect[i].x = p1.x; 9963 rect[i].width = p2.x - p1.x + 1; 9964 } else if (p1.x > p2.x) { 9965 rect[i].x = p2.x; 9966 rect[i].width = p1.x - p2.x + 1; 9967 } else { 9968 rect[i].x = p1.x; 9969 rect[i].width = 1; 9970 } 9971 if (p1.y < p2.y) { 9972 rect[i].y = p1.y; 9973 rect[i].height = p2.y - p1.y + 1; 9974 } else if (p1.y > p2.y) { 9975 rect[i].y = p2.y; 9976 rect[i].height = p1.y - p2.y + 1; 9977 } else { 9978 rect[i].y = p1.y; 9979 rect[i].height = 1; 9980 } 9981 9982 /* don't paint last pixel */ 9983 if (gc->capStyle == CapNotLast) { 9984 if (p1.x == p2.x) 9985 rect[i].height--; 9986 else 9987 rect[i].width--; 9988 } 9989 p1 = p2; 9990 } 9991 9992 if (gc->fillStyle == FillTiled) { 9993 i = sna_poly_fill_rect_tiled_blt(drawable, 9994 data.bo, data.damage, 9995 gc, n - 1, rect + 1, 9996 &data.region.extents, 9997 data.flags & IS_CLIPPED); 9998 } else { 9999 i = sna_poly_fill_rect_stippled_blt(drawable, 10000 data.bo, data.damage, 10001 gc, n - 1, rect + 1, 10002 &data.region.extents, 10003 data.flags & IS_CLIPPED); 10004 } 10005 free (rect); 10006 10007 if (i) 10008 return; 10009 } 10010 10011spans_fallback: 10012 if ((data.bo = sna_drawable_use_bo(drawable, 10013 use_line_spans(drawable, gc, &data.region.extents, data.flags), 10014 &data.region.extents, &data.damage))) { 10015 DBG(("%s: converting line into spans\n", __FUNCTION__)); 10016 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10017 sna_gc(gc)->priv = &data; 10018 10019 if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) { 10020 struct sna_fill_op fill; 10021 10022 if (gc->lineStyle == LineSolid) { 10023 if (!sna_fill_init_blt(&fill, 10024 data.sna, data.pixmap, 10025 data.bo, gc->alu, color, 10026 FILL_POINTS | FILL_SPANS)) 10027 goto fallback; 10028 10029 data.op = &fill; 10030 10031 if ((data.flags & IS_CLIPPED) == 0) { 10032 if (data.dx | data.dy) 10033 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10034 else 10035 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10036 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10037 } else { 10038 if (!region_maybe_clip(&data.region, 10039 gc->pCompositeClip)) 10040 return; 10041 10042 if (region_is_singular(&data.region)) { 10043 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10044 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10045 } else { 10046 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10047 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10048 } 10049 } 10050 assert(gc->miTranslate); 10051 10052 gc->ops = &sna_gc_ops__tmp; 10053 DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__)); 10054 miZeroLine(drawable, gc, mode, n, pt); 10055 fill.done(data.sna, &fill); 10056 } else { 10057 data.op = &fill; 10058 10059 if ((data.flags & IS_CLIPPED) == 0) { 10060 if (data.dx | data.dy) 10061 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset; 10062 else 10063 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash; 10064 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash; 10065 } else { 10066 if (!region_maybe_clip(&data.region, 10067 gc->pCompositeClip)) 10068 return; 10069 10070 if (region_is_singular(&data.region)) { 10071 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents; 10072 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents; 10073 } else { 10074 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes; 10075 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes; 10076 } 10077 } 10078 assert(gc->miTranslate); 10079 10080 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n", 10081 __FUNCTION__, 10082 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 10083 gc->fgPixel)); 10084 10085 if (!sna_fill_init_blt(&fill, 10086 data.sna, data.pixmap, 10087 data.bo, gc->alu, color, 10088 FILL_POINTS | FILL_SPANS)) 10089 goto fallback; 10090 10091 gc->ops = &sna_gc_ops__tmp; 10092 data.phase = gc->fgPixel; 10093 miZeroDashLine(drawable, gc, mode, n, pt); 10094 fill.done(data.sna, &fill); 10095 10096 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n", 10097 __FUNCTION__, 10098 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 10099 gc->bgPixel)); 10100 10101 if (sna_fill_init_blt(&fill, 10102 data.sna, data.pixmap, 10103 data.bo, gc->alu, 10104 gc->bgPixel, 10105 FILL_POINTS | FILL_SPANS)) { 10106 data.phase = gc->bgPixel; 10107 miZeroDashLine(drawable, gc, mode, n, pt); 10108 fill.done(data.sna, &fill); 10109 } 10110 } 10111 } else { 10112 /* Note that the WideDash functions alternate 10113 * between filling using fgPixel and bgPixel 10114 * so we need to reset state between FillSpans and 10115 * cannot use the fill fast paths. 10116 */ 10117 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10118 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 10119 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 10120 gc->ops = &sna_gc_ops__tmp; 10121 10122 switch (gc->lineStyle) { 10123 default: 10124 assert(0); 10125 case LineSolid: 10126 if (gc->lineWidth == 0) { 10127 DBG(("%s: miZeroLine\n", __FUNCTION__)); 10128 miZeroLine(drawable, gc, mode, n, pt); 10129 } else { 10130 DBG(("%s: miWideLine\n", __FUNCTION__)); 10131 miWideLine(drawable, gc, mode, n, pt); 10132 } 10133 break; 10134 case LineOnOffDash: 10135 case LineDoubleDash: 10136 if (gc->lineWidth == 0) { 10137 DBG(("%s: miZeroDashLine\n", __FUNCTION__)); 10138 miZeroDashLine(drawable, gc, mode, n, pt); 10139 } else { 10140 DBG(("%s: miWideDash\n", __FUNCTION__)); 10141 miWideDash(drawable, gc, mode, n, pt); 10142 } 10143 break; 10144 } 10145 } 10146 10147 gc->ops = (GCOps *)&sna_gc_ops; 10148 if (data.damage) { 10149 if (data.dx | data.dy) 10150 pixman_region_translate(&data.region, data.dx, data.dy); 10151 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10152 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 10153 assert_pixmap_damage(data.pixmap); 10154 } 10155 RegionUninit(&data.region); 10156 return; 10157 } 10158 10159fallback: 10160 DBG(("%s: fallback\n", __FUNCTION__)); 10161 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 10162 return; 10163 10164 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10165 goto out; 10166 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10167 drawable_gc_flags(drawable, gc, 10168 !(data.flags & RECTILINEAR && n == 2)))) 10169 goto out; 10170 10171 if (sigtrap_get() == 0) { 10172 DBG(("%s: fbPolyLine\n", __FUNCTION__)); 10173 fbPolyLine(drawable, gc, mode, n, pt); 10174 FALLBACK_FLUSH(drawable); 10175 sigtrap_put(); 10176 } 10177out: 10178 sna_gc_move_to_gpu(gc); 10179 RegionUninit(&data.region); 10180} 10181 10182static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc) 10183{ 10184 if (seg->x1 == seg->x2) { 10185 if (seg->y1 > seg->y2) { 10186 b->y2 = seg->y1 + 1; 10187 b->y1 = seg->y2 + 1; 10188 if (gc->capStyle != CapNotLast) 10189 b->y1--; 10190 } else { 10191 b->y1 = seg->y1; 10192 b->y2 = seg->y2; 10193 if (gc->capStyle != CapNotLast) 10194 b->y2++; 10195 } 10196 if (b->y1 >= b->y2) 10197 return false; 10198 10199 b->x1 = seg->x1; 10200 b->x2 = seg->x1 + 1; 10201 } else { 10202 if (seg->x1 > seg->x2) { 10203 b->x2 = seg->x1 + 1; 10204 b->x1 = seg->x2 + 1; 10205 if (gc->capStyle != CapNotLast) 10206 b->x1--; 10207 } else { 10208 b->x1 = seg->x1; 10209 b->x2 = seg->x2; 10210 if (gc->capStyle != CapNotLast) 10211 b->x2++; 10212 } 10213 if (b->x1 >= b->x2) 10214 return false; 10215 10216 b->y1 = seg->y1; 10217 b->y2 = seg->y1 + 1; 10218 } 10219 10220 DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n", 10221 __FUNCTION__, 10222 seg->x1, seg->y1, seg->x2, seg->y2, 10223 b->x1, b->y1, b->x2, b->y2)); 10224 return true; 10225} 10226 10227static bool 10228sna_poly_segment_blt(DrawablePtr drawable, 10229 struct kgem_bo *bo, 10230 struct sna_damage **damage, 10231 GCPtr gc, uint32_t pixel, 10232 int n, xSegment *seg, 10233 const BoxRec *extents, unsigned clipped) 10234{ 10235 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10236 struct sna *sna = to_sna_from_pixmap(pixmap); 10237 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 10238 struct sna_fill_op fill; 10239 int16_t dx, dy; 10240 10241 DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n", 10242 __FUNCTION__, n, gc->alu, gc->fgPixel, clipped)); 10243 10244 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 10245 return false; 10246 10247 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10248 10249 if (!clipped) { 10250 dx += drawable->x; 10251 dy += drawable->y; 10252 if (dx|dy) { 10253 do { 10254 unsigned nbox = n; 10255 if (nbox > ARRAY_SIZE(boxes)) 10256 nbox = ARRAY_SIZE(boxes); 10257 n -= nbox; 10258 do { 10259 if (box_from_seg(b, seg++, gc)) { 10260 assert(!box_empty(b)); 10261 b->x1 += dx; 10262 b->x2 += dx; 10263 b->y1 += dy; 10264 b->y2 += dy; 10265 assert(!box_empty(b)); 10266 b++; 10267 } 10268 } while (--nbox); 10269 10270 if (b != boxes) { 10271 fill.boxes(sna, &fill, boxes, b-boxes); 10272 if (damage) 10273 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10274 b = boxes; 10275 } 10276 } while (n); 10277 } else { 10278 do { 10279 unsigned nbox = n; 10280 if (nbox > ARRAY_SIZE(boxes)) 10281 nbox = ARRAY_SIZE(boxes); 10282 n -= nbox; 10283 do { 10284 if (box_from_seg(b, seg++, gc)) { 10285 assert(!box_empty(b)); 10286 b++; 10287 } 10288 } while (--nbox); 10289 10290 if (b != boxes) { 10291 fill.boxes(sna, &fill, boxes, b-boxes); 10292 if (damage) 10293 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10294 b = boxes; 10295 } 10296 } while (n); 10297 } 10298 } else { 10299 RegionRec clip; 10300 10301 region_set(&clip, extents); 10302 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10303 goto done; 10304 10305 if (clip.data) { 10306 const BoxRec * const clip_start = RegionBoxptr(&clip); 10307 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10308 const BoxRec *c; 10309 do { 10310 BoxRec box; 10311 10312 if (!box_from_seg(&box, seg++, gc)) 10313 continue; 10314 10315 assert(!box_empty(&box)); 10316 box.x1 += drawable->x; 10317 box.x2 += drawable->x; 10318 box.y1 += drawable->y; 10319 box.y2 += drawable->y; 10320 c = find_clip_box_for_y(clip_start, 10321 clip_end, 10322 box.y1); 10323 while (c != clip_end) { 10324 if (box.y2 <= c->y1) 10325 break; 10326 10327 *b = box; 10328 if (box_intersect(b, c++)) { 10329 b->x1 += dx; 10330 b->x2 += dx; 10331 b->y1 += dy; 10332 b->y2 += dy; 10333 assert(!box_empty(b)); 10334 if (++b == last_box) { 10335 fill.boxes(sna, &fill, boxes, last_box-boxes); 10336 if (damage) 10337 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10338 b = boxes; 10339 } 10340 } 10341 } 10342 } while (--n); 10343 } else { 10344 do { 10345 if (!box_from_seg(b, seg++, gc)) 10346 continue; 10347 10348 assert(!box_empty(b)); 10349 b->x1 += drawable->x; 10350 b->x2 += drawable->x; 10351 b->y1 += drawable->y; 10352 b->y2 += drawable->y; 10353 if (box_intersect(b, &clip.extents)) { 10354 b->x1 += dx; 10355 b->x2 += dx; 10356 b->y1 += dy; 10357 b->y2 += dy; 10358 assert(!box_empty(b)); 10359 if (++b == last_box) { 10360 fill.boxes(sna, &fill, boxes, last_box-boxes); 10361 if (damage) 10362 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10363 b = boxes; 10364 } 10365 } 10366 } while (--n); 10367 } 10368 RegionUninit(&clip); 10369 } 10370 if (b != boxes) { 10371 fill.boxes(sna, &fill, boxes, b - boxes); 10372 if (damage) 10373 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 10374 } 10375done: 10376 fill.done(sna, &fill); 10377 assert_pixmap_damage(pixmap); 10378 return true; 10379} 10380 10381static bool 10382sna_poly_zero_segment_blt(DrawablePtr drawable, 10383 struct kgem_bo *bo, 10384 struct sna_damage **damage, 10385 GCPtr gc, const int _n, const xSegment *_s, 10386 const BoxRec *extents, unsigned clipped) 10387{ 10388 static void * const _jump[] = { 10389 &&no_damage, 10390 &&damage, 10391 10392 &&no_damage_offset, 10393 &&damage_offset, 10394 }; 10395 10396 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10397 struct sna *sna = to_sna_from_pixmap(pixmap); 10398 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 10399 struct sna_fill_op fill; 10400 RegionRec clip; 10401 const BoxRec *last_extents; 10402 BoxRec box[512], *b; 10403 BoxRec *const last_box = box + ARRAY_SIZE(box); 10404 int16_t dx, dy; 10405 void *jump, *ret; 10406 10407 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 10408 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 10409 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10410 return false; 10411 10412 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10413 10414 region_set(&clip, extents); 10415 if (clipped) { 10416 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10417 return true; 10418 } 10419 DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n", 10420 __FUNCTION__, 10421 clip.extents.x1, clip.extents.y1, 10422 clip.extents.x2, clip.extents.y2, 10423 dx, dy)); 10424 10425 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 10426 10427 b = box; 10428 extents = region_rects(&clip); 10429 last_extents = extents + region_num_rects(&clip); 10430 do { 10431 int n = _n; 10432 const xSegment *s = _s; 10433 do { 10434 int16_t sdx, sdy; 10435 int adx, ady, length; 10436 int e, e1, e2, e3; 10437 int x1, x2; 10438 int y1, y2; 10439 int oc1, oc2; 10440 int octant; 10441 10442 x1 = s->x1 + drawable->x; 10443 y1 = s->y1 + drawable->y; 10444 x2 = s->x2 + drawable->x; 10445 y2 = s->y2 + drawable->y; 10446 s++; 10447 10448 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 10449 __FUNCTION__, x1, y1, x2, y2)); 10450 if (x2 == x1 && y2 == y1) 10451 continue; 10452 10453 oc1 = 0; 10454 OUTCODES(oc1, x1, y1, extents); 10455 oc2 = 0; 10456 OUTCODES(oc2, x2, y2, extents); 10457 if (oc1 & oc2) 10458 continue; 10459 10460 CalcLineDeltas(x1, y1, x2, y2, 10461 adx, ady, sdx, sdy, 10462 1, 1, octant); 10463 10464 DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n", 10465 __FUNCTION__, adx, ady, sdx, sdy)); 10466 if (adx == 0 || ady == 0) { 10467 if (x1 <= x2) { 10468 b->x1 = x1; 10469 b->x2 = x2; 10470 } else { 10471 b->x1 = x2; 10472 b->x2 = x1; 10473 } 10474 if (y1 <= y2) { 10475 b->y1 = y1; 10476 b->y2 = y2; 10477 } else { 10478 b->y1 = y2; 10479 b->y2 = y1; 10480 } 10481 b->x2++; 10482 b->y2++; 10483 10484 if ((oc1 | oc2) && !box_intersect(b, extents)) 10485 continue; 10486 10487 assert(!box_empty(b)); 10488 if (++b == last_box) { 10489 ret = &&rectangle_continue; 10490 goto *jump; 10491rectangle_continue: 10492 b = box; 10493 } 10494 } else if (adx >= ady) { 10495 bool dirty; 10496 10497 /* X-major segment */ 10498 e1 = ady << 1; 10499 e2 = e1 - (adx << 1); 10500 e = e1 - adx; 10501 length = adx; /* don't draw endpoint in main loop */ 10502 10503 FIXUP_ERROR(e, octant, bias); 10504 10505 if (oc1 | oc2) { 10506 int pt1_clipped, pt2_clipped; 10507 int x = x1, y = y1; 10508 10509 if (miZeroClipLine(extents->x1, extents->y1, 10510 extents->x2-1, extents->y2-1, 10511 &x1, &y1, &x2, &y2, 10512 adx, ady, 10513 &pt1_clipped, &pt2_clipped, 10514 octant, bias, oc1, oc2) == -1) 10515 continue; 10516 10517 length = abs(x2 - x1); 10518 if (length == 0) 10519 continue; 10520 10521 if (pt1_clipped) { 10522 int clipdx = abs(x1 - x); 10523 int clipdy = abs(y1 - y); 10524 e += clipdy * e2 + (clipdx - clipdy) * e1; 10525 } 10526 } 10527 e3 = e2 - e1; 10528 e = e - e1; 10529 10530 b->x1 = x1; 10531 b->y1 = y1; 10532 dirty = false; 10533 while (length--) { 10534 dirty = true; 10535 e += e1; 10536 if (e >= 0) { 10537 e += e3; 10538 10539 if (sdx < 0) { 10540 b->x2 = b->x1 + 1; 10541 b->x1 = x1; 10542 } else 10543 b->x2 = x1 + 1; 10544 b->y2 = b->y1 + 1; 10545 10546 DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n", 10547 __FUNCTION__, x1, y1, 10548 b->x1, b->y1, b->x2, b->y2)); 10549 10550 assert(!box_empty(b)); 10551 if (++b == last_box) { 10552 ret = &&X_continue; 10553 goto *jump; 10554X_continue: 10555 b = box; 10556 } 10557 10558 b->x1 = x1 + sdx; 10559 b->y1 = y1 += sdy; 10560 dirty = false; 10561 } 10562 x1 += sdx; 10563 } 10564 if (dirty) { 10565 x1 -= sdx; 10566 DBG(("%s: horizontal tail: (%d, %d)\n", 10567 __FUNCTION__, x1, y1)); 10568 if (sdx < 0) { 10569 b->x2 = b->x1 + 1; 10570 b->x1 = x1; 10571 } else 10572 b->x2 = x1 + 1; 10573 b->y2 = b->y1 + 1; 10574 10575 assert(!box_empty(b)); 10576 if (++b == last_box) { 10577 ret = &&X2_continue; 10578 goto *jump; 10579X2_continue: 10580 b = box; 10581 } 10582 } 10583 } else { 10584 bool dirty; 10585 10586 /* Y-major segment */ 10587 e1 = adx << 1; 10588 e2 = e1 - (ady << 1); 10589 e = e1 - ady; 10590 length = ady; /* don't draw endpoint in main loop */ 10591 10592 SetYMajorOctant(octant); 10593 FIXUP_ERROR(e, octant, bias); 10594 10595 if (oc1 | oc2) { 10596 int pt1_clipped, pt2_clipped; 10597 int x = x1, y = y1; 10598 10599 if (miZeroClipLine(extents->x1, extents->y1, 10600 extents->x2-1, extents->y2-1, 10601 &x1, &y1, &x2, &y2, 10602 adx, ady, 10603 &pt1_clipped, &pt2_clipped, 10604 octant, bias, oc1, oc2) == -1) 10605 continue; 10606 10607 length = abs(y2 - y1); 10608 if (length == 0) 10609 continue; 10610 10611 if (pt1_clipped) { 10612 int clipdx = abs(x1 - x); 10613 int clipdy = abs(y1 - y); 10614 e += clipdx * e2 + (clipdy - clipdx) * e1; 10615 } 10616 } 10617 10618 e3 = e2 - e1; 10619 e = e - e1; 10620 10621 b->x1 = x1; 10622 b->y1 = y1; 10623 dirty = false; 10624 while (length--) { 10625 e += e1; 10626 dirty = true; 10627 if (e >= 0) { 10628 e += e3; 10629 10630 if (sdy < 0) { 10631 b->y2 = b->y1 + 1; 10632 b->y1 = y1; 10633 } else 10634 b->y2 = y1 + 1; 10635 b->x2 = x1 + 1; 10636 10637 assert(!box_empty(b)); 10638 if (++b == last_box) { 10639 ret = &&Y_continue; 10640 goto *jump; 10641Y_continue: 10642 b = box; 10643 } 10644 10645 b->x1 = x1 += sdx; 10646 b->y1 = y1 + sdy; 10647 dirty = false; 10648 } 10649 y1 += sdy; 10650 } 10651 10652 if (dirty) { 10653 y1 -= sdy; 10654 if (sdy < 0) { 10655 b->y2 = b->y1 + 1; 10656 b->y1 = y1; 10657 } else 10658 b->y2 = y1 + 1; 10659 b->x2 = x1 + 1; 10660 10661 assert(!box_empty(b)); 10662 if (++b == last_box) { 10663 ret = &&Y2_continue; 10664 goto *jump; 10665Y2_continue: 10666 b = box; 10667 } 10668 } 10669 } 10670 } while (--n); 10671 } while (++extents != last_extents); 10672 10673 if (b != box) { 10674 ret = &&done; 10675 goto *jump; 10676 } 10677 10678done: 10679 fill.done(sna, &fill); 10680 assert_pixmap_damage(pixmap); 10681 RegionUninit(&clip); 10682 return true; 10683 10684damage: 10685 sna_damage_add_boxes(damage, box, b-box, 0, 0); 10686no_damage: 10687 fill.boxes(sna, &fill, box, b-box); 10688 goto *ret; 10689 10690no_damage_offset: 10691 { 10692 BoxRec *bb = box; 10693 do { 10694 bb->x1 += dx; 10695 bb->x2 += dx; 10696 bb->y1 += dy; 10697 bb->y2 += dy; 10698 } while (++bb != b); 10699 fill.boxes(sna, &fill, box, b - box); 10700 } 10701 goto *ret; 10702 10703damage_offset: 10704 { 10705 BoxRec *bb = box; 10706 do { 10707 bb->x1 += dx; 10708 bb->x2 += dx; 10709 bb->y1 += dy; 10710 bb->y2 += dy; 10711 } while (++bb != b); 10712 fill.boxes(sna, &fill, box, b - box); 10713 sna_damage_add_boxes(damage, box, b - box, 0, 0); 10714 } 10715 goto *ret; 10716} 10717 10718static unsigned 10719sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc, 10720 int n, xSegment *seg, 10721 BoxPtr out) 10722{ 10723 BoxRec box; 10724 bool clipped, can_blit; 10725 10726 if (n == 0) 10727 return 0; 10728 10729 if (seg->x2 >= seg->x1) { 10730 box.x1 = seg->x1; 10731 box.x2 = seg->x2; 10732 } else { 10733 box.x2 = seg->x1; 10734 box.x1 = seg->x2; 10735 } 10736 10737 if (seg->y2 >= seg->y1) { 10738 box.y1 = seg->y1; 10739 box.y2 = seg->y2; 10740 } else { 10741 box.y2 = seg->y1; 10742 box.y1 = seg->y2; 10743 } 10744 10745 can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2; 10746 while (--n) { 10747 seg++; 10748 if (seg->x2 > seg->x1) { 10749 if (seg->x1 < box.x1) box.x1 = seg->x1; 10750 if (seg->x2 > box.x2) box.x2 = seg->x2; 10751 } else { 10752 if (seg->x2 < box.x1) box.x1 = seg->x2; 10753 if (seg->x1 > box.x2) box.x2 = seg->x1; 10754 } 10755 10756 if (seg->y2 > seg->y1) { 10757 if (seg->y1 < box.y1) box.y1 = seg->y1; 10758 if (seg->y2 > box.y2) box.y2 = seg->y2; 10759 } else { 10760 if (seg->y2 < box.y1) box.y1 = seg->y2; 10761 if (seg->y1 > box.y2) box.y2 = seg->y1; 10762 } 10763 10764 if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2)) 10765 can_blit = false; 10766 } 10767 10768 box.x2++; 10769 box.y2++; 10770 10771 if (gc->lineWidth) { 10772 int extra = gc->lineWidth; 10773 if (gc->capStyle != CapProjecting) 10774 extra >>= 1; 10775 if (extra) { 10776 box.x1 -= extra; 10777 box.x2 += extra; 10778 box.y1 -= extra; 10779 box.y2 += extra; 10780 } 10781 } 10782 10783 DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n", 10784 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10785 10786 clipped = trim_and_translate_box(&box, drawable, gc); 10787 if (box_empty(&box)) 10788 return 0; 10789 10790 *out = box; 10791 return 1 | clipped << 1 | can_blit << 2; 10792} 10793 10794static void 10795sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg) 10796{ 10797 struct sna_pixmap *priv; 10798 struct sna_fill_spans data; 10799 uint32_t color; 10800 10801 DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n", 10802 __FUNCTION__, 10803 n, seg->x1, seg->y1, seg->x2, seg->y2, 10804 gc->lineWidth)); 10805 10806 data.flags = sna_poly_segment_extents(drawable, gc, n, seg, 10807 &data.region.extents); 10808 if (data.flags == 0) 10809 return; 10810 10811 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 10812 data.region.extents.x1, data.region.extents.y1, 10813 data.region.extents.x2, data.region.extents.y2)); 10814 10815 data.region.data = NULL; 10816 10817 if (FORCE_FALLBACK) 10818 goto fallback; 10819 10820 if (!ACCEL_POLY_SEGMENT) 10821 goto fallback; 10822 10823 data.pixmap = get_drawable_pixmap(drawable); 10824 data.sna = to_sna_from_pixmap(data.pixmap); 10825 priv = sna_pixmap(data.pixmap); 10826 if (priv == NULL) { 10827 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10828 goto fallback; 10829 } 10830 10831 if (wedged(data.sna)) { 10832 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10833 goto fallback; 10834 } 10835 10836 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 10837 __FUNCTION__, 10838 gc->fillStyle, gc->fillStyle == FillSolid, 10839 gc->lineStyle, gc->lineStyle == LineSolid, 10840 gc->lineWidth, 10841 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 10842 data.flags & RECTILINEAR)); 10843 if (!PM_IS_SOLID(drawable, gc->planemask)) 10844 goto fallback; 10845 10846 if (gc->lineStyle != LineSolid || gc->lineWidth > 1) 10847 goto spans_fallback; 10848 10849 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 10850 &data.region.extents, 10851 &data.damage); 10852 if (data.bo == NULL) 10853 goto fallback; 10854 10855 if (gc_is_solid(gc, &color)) { 10856 DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n", 10857 __FUNCTION__, (unsigned)color, data.flags)); 10858 10859 if (data.flags & RECTILINEAR) { 10860 if (sna_poly_segment_blt(drawable, 10861 data.bo, data.damage, 10862 gc, color, n, seg, 10863 &data.region.extents, 10864 data.flags & IS_CLIPPED)) 10865 return; 10866 } else { 10867 if (sna_poly_zero_segment_blt(drawable, 10868 data.bo, data.damage, 10869 gc, n, seg, 10870 &data.region.extents, 10871 data.flags & IS_CLIPPED)) 10872 return; 10873 } 10874 } else if (data.flags & RECTILINEAR) { 10875 /* Try converting these to a set of rectangles instead */ 10876 xRectangle *rect; 10877 int i; 10878 10879 DBG(("%s: converting to rectangles\n", __FUNCTION__)); 10880 10881 rect = malloc (n * sizeof (xRectangle)); 10882 if (rect == NULL) 10883 return; 10884 10885 for (i = 0; i < n; i++) { 10886 if (seg[i].x1 < seg[i].x2) { 10887 rect[i].x = seg[i].x1; 10888 rect[i].width = seg[i].x2 - seg[i].x1 + 1; 10889 } else if (seg[i].x1 > seg[i].x2) { 10890 rect[i].x = seg[i].x2; 10891 rect[i].width = seg[i].x1 - seg[i].x2 + 1; 10892 } else { 10893 rect[i].x = seg[i].x1; 10894 rect[i].width = 1; 10895 } 10896 if (seg[i].y1 < seg[i].y2) { 10897 rect[i].y = seg[i].y1; 10898 rect[i].height = seg[i].y2 - seg[i].y1 + 1; 10899 } else if (seg[i].y1 > seg[i].y2) { 10900 rect[i].y = seg[i].y2; 10901 rect[i].height = seg[i].y1 - seg[i].y2 + 1; 10902 } else { 10903 rect[i].y = seg[i].y1; 10904 rect[i].height = 1; 10905 } 10906 10907 /* don't paint last pixel */ 10908 if (gc->capStyle == CapNotLast) { 10909 if (seg[i].x1 == seg[i].x2) 10910 rect[i].height--; 10911 else 10912 rect[i].width--; 10913 } 10914 } 10915 10916 if (gc->fillStyle == FillTiled) { 10917 i = sna_poly_fill_rect_tiled_blt(drawable, 10918 data.bo, data.damage, 10919 gc, n, rect, 10920 &data.region.extents, 10921 data.flags); 10922 } else { 10923 i = sna_poly_fill_rect_stippled_blt(drawable, 10924 data.bo, data.damage, 10925 gc, n, rect, 10926 &data.region.extents, 10927 data.flags); 10928 } 10929 free (rect); 10930 10931 if (i) 10932 return; 10933 } 10934 10935spans_fallback: 10936 if ((data.bo = sna_drawable_use_bo(drawable, 10937 use_line_spans(drawable, gc, &data.region.extents, data.flags), 10938 &data.region.extents, 10939 &data.damage))) { 10940 void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr); 10941 int i; 10942 10943 DBG(("%s: converting segments into spans\n", __FUNCTION__)); 10944 10945 switch (gc->lineStyle) { 10946 default: 10947 case LineSolid: 10948 if (gc->lineWidth == 0) 10949 line = miZeroLine; 10950 else 10951 line = miWideLine; 10952 break; 10953 case LineOnOffDash: 10954 case LineDoubleDash: 10955 if (gc->lineWidth == 0) 10956 line = miZeroDashLine; 10957 else 10958 line = miWideDash; 10959 break; 10960 } 10961 10962 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10963 sna_gc(gc)->priv = &data; 10964 10965 if (gc->lineWidth == 0 && 10966 gc->lineStyle == LineSolid && 10967 gc_is_solid(gc, &color)) { 10968 struct sna_fill_op fill; 10969 10970 if (!sna_fill_init_blt(&fill, 10971 data.sna, data.pixmap, 10972 data.bo, gc->alu, color, 10973 FILL_POINTS | FILL_SPANS)) 10974 goto fallback; 10975 10976 data.op = &fill; 10977 10978 if ((data.flags & IS_CLIPPED) == 0) { 10979 if (data.dx | data.dy) 10980 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10981 else 10982 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10983 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10984 } else { 10985 if (!region_maybe_clip(&data.region, 10986 gc->pCompositeClip)) 10987 return; 10988 10989 if (region_is_singular(&data.region)) { 10990 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10991 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10992 } else { 10993 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10994 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10995 } 10996 } 10997 assert(gc->miTranslate); 10998 gc->ops = &sna_gc_ops__tmp; 10999 for (i = 0; i < n; i++) 11000 line(drawable, gc, CoordModeOrigin, 2, 11001 (DDXPointPtr)&seg[i]); 11002 11003 fill.done(data.sna, &fill); 11004 } else { 11005 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11006 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 11007 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11008 gc->ops = &sna_gc_ops__tmp; 11009 11010 for (i = 0; i < n; i++) 11011 line(drawable, gc, CoordModeOrigin, 2, 11012 (DDXPointPtr)&seg[i]); 11013 } 11014 11015 gc->ops = (GCOps *)&sna_gc_ops; 11016 if (data.damage) { 11017 if (data.dx | data.dy) 11018 pixman_region_translate(&data.region, data.dx, data.dy); 11019 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11020 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 11021 } 11022 assert_pixmap_damage(data.pixmap); 11023 RegionUninit(&data.region); 11024 return; 11025 } 11026 11027fallback: 11028 DBG(("%s: fallback\n", __FUNCTION__)); 11029 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11030 return; 11031 11032 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11033 goto out; 11034 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11035 drawable_gc_flags(drawable, gc, 11036 !(data.flags & RECTILINEAR && n == 1)))) 11037 goto out; 11038 11039 if (sigtrap_get() == 0) { 11040 DBG(("%s: fbPolySegment\n", __FUNCTION__)); 11041 fbPolySegment(drawable, gc, n, seg); 11042 FALLBACK_FLUSH(drawable); 11043 sigtrap_put(); 11044 } 11045out: 11046 sna_gc_move_to_gpu(gc); 11047 RegionUninit(&data.region); 11048} 11049 11050static unsigned 11051sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, 11052 int n, xRectangle *r, 11053 BoxPtr out) 11054{ 11055 Box32Rec box; 11056 int extra = gc->lineWidth >> 1; 11057 bool clipped; 11058 bool zero = false; 11059 11060 if (n == 0) 11061 return 0; 11062 11063 box.x1 = r->x; 11064 box.y1 = r->y; 11065 box.x2 = box.x1 + r->width; 11066 box.y2 = box.y1 + r->height; 11067 zero |= (r->width | r->height) == 0; 11068 11069 while (--n) { 11070 r++; 11071 zero |= (r->width | r->height) == 0; 11072 box32_add_rect(&box, r); 11073 } 11074 11075 box.x2++; 11076 box.y2++; 11077 11078 if (extra) { 11079 box.x1 -= extra; 11080 box.x2 += extra; 11081 box.y1 -= extra; 11082 box.y2 += extra; 11083 zero = !zero; 11084 } else 11085 zero = true; 11086 11087 DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n", 11088 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 11089 clipped = box32_trim_and_translate(&box, drawable, gc); 11090 if (!box32_to_box16(&box, out)) 11091 return 0; 11092 11093 DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n", 11094 __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped)); 11095 return 1 | clipped << 1 | zero << 2; 11096} 11097 11098static bool 11099sna_poly_rectangle_blt(DrawablePtr drawable, 11100 struct kgem_bo *bo, 11101 struct sna_damage **damage, 11102 GCPtr gc, int n, xRectangle *r, 11103 const BoxRec *extents, unsigned clipped) 11104{ 11105 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11106 struct sna *sna = to_sna_from_pixmap(pixmap); 11107 struct sna_fill_op fill; 11108 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11109 int16_t dx, dy; 11110 static void * const jump[] = { 11111 &&wide, 11112 &&zero, 11113 &&wide_clipped, 11114 &&zero_clipped, 11115 }; 11116 11117 DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", 11118 __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); 11119 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 11120 return false; 11121 11122 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11123 11124 goto *jump[(gc->lineWidth <= 1) | clipped]; 11125 11126zero: 11127 dx += drawable->x; 11128 dy += drawable->y; 11129 11130 do { 11131 xRectangle rr = *r++; 11132 11133 if ((rr.width | rr.height) == 0) 11134 continue; /* XXX -> PolyLine */ 11135 11136 DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11137 n, rr.x, rr.y, rr.width, rr.height)); 11138 rr.x += dx; 11139 rr.y += dy; 11140 11141 if (b+4 > last_box) { 11142 fill.boxes(sna, &fill, boxes, b-boxes); 11143 if (damage) 11144 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11145 b = boxes; 11146 } 11147 11148 if (rr.width <= 1 || rr.height <= 1) { 11149 b->x1 = rr.x; 11150 b->y1 = rr.y; 11151 b->x2 = rr.x + rr.width + (rr.height != 0); 11152 b->y2 = rr.y + rr.height + (rr.width != 0); 11153 DBG(("%s: blt (%d, %d), (%d, %d)\n", 11154 __FUNCTION__, 11155 b->x1, b->y1, b->x2,b->y2)); 11156 b++; 11157 } else { 11158 b[0].x1 = rr.x; 11159 b[0].y1 = rr.y; 11160 b[0].x2 = rr.x + rr.width + 1; 11161 b[0].y2 = rr.y + 1; 11162 11163 b[1] = b[0]; 11164 b[1].y1 += rr.height; 11165 b[1].y2 += rr.height; 11166 11167 b[2].y1 = rr.y + 1; 11168 b[2].y2 = rr.y + rr.height; 11169 b[2].x1 = rr.x; 11170 b[2].x2 = rr.x + 1; 11171 11172 b[3] = b[2]; 11173 b[3].x1 += rr.width; 11174 b[3].x2 += rr.width; 11175 11176 b += 4; 11177 } 11178 } while (--n); 11179 goto done; 11180 11181zero_clipped: 11182 { 11183 RegionRec clip; 11184 BoxRec box[4]; 11185 int count; 11186 11187 region_set(&clip, extents); 11188 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11189 goto done; 11190 11191 if (clip.data) { 11192 const BoxRec * const clip_start = RegionBoxptr(&clip); 11193 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11194 const BoxRec *c; 11195 do { 11196 xRectangle rr = *r++; 11197 11198 DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11199 n, rr.x, rr.y, rr.width, rr.height)); 11200 11201 if ((rr.width | rr.height) == 0) 11202 continue; /* XXX -> PolyLine */ 11203 11204 rr.x += drawable->x; 11205 rr.y += drawable->y; 11206 11207 if (rr.width <= 1 || rr.height <= 1) { 11208 box[0].x1 = rr.x; 11209 box[0].y1 = rr.y; 11210 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11211 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11212 count = 1; 11213 } else { 11214 box[0].x1 = rr.x; 11215 box[0].y1 = rr.y; 11216 box[0].x2 = rr.x + rr.width + 1; 11217 box[0].y2 = rr.y + 1; 11218 11219 box[1] = box[0]; 11220 box[1].y1 += rr.height; 11221 box[1].y2 += rr.height; 11222 11223 box[2].y1 = rr.y + 1; 11224 box[2].y2 = rr.y + rr.height; 11225 box[2].x1 = rr.x; 11226 box[2].x2 = rr.x + 1; 11227 11228 box[3] = box[2]; 11229 box[3].x1 += rr.width; 11230 box[3].x2 += rr.width; 11231 count = 4; 11232 } 11233 11234 while (count--) { 11235 c = find_clip_box_for_y(clip_start, 11236 clip_end, 11237 box[count].y1); 11238 while (c != clip_end) { 11239 if (box[count].y2 <= c->y1) 11240 break; 11241 11242 *b = box[count]; 11243 if (box_intersect(b, c++)) { 11244 b->x1 += dx; 11245 b->x2 += dx; 11246 b->y1 += dy; 11247 b->y2 += dy; 11248 if (++b == last_box) { 11249 fill.boxes(sna, &fill, boxes, last_box-boxes); 11250 if (damage) 11251 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11252 b = boxes; 11253 } 11254 } 11255 11256 } 11257 } 11258 } while (--n); 11259 } else { 11260 do { 11261 xRectangle rr = *r++; 11262 DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11263 n, rr.x, rr.y, rr.width, rr.height)); 11264 11265 if ((rr.width | rr.height) == 0) 11266 continue; /* XXX -> PolyLine */ 11267 11268 rr.x += drawable->x; 11269 rr.y += drawable->y; 11270 11271 if (rr.width <= 1 || rr.height <= 1) { 11272 box[0].x1 = rr.x; 11273 box[0].y1 = rr.y; 11274 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11275 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11276 count = 1; 11277 } else { 11278 box[0].x1 = rr.x; 11279 box[0].y1 = rr.y; 11280 box[0].x2 = rr.x + rr.width + 1; 11281 box[0].y2 = rr.y + 1; 11282 11283 box[1] = box[0]; 11284 box[1].y1 += rr.height; 11285 box[1].y2 += rr.height; 11286 11287 box[2].y1 = rr.y + 1; 11288 box[2].y2 = rr.y + rr.height; 11289 box[2].x1 = rr.x; 11290 box[2].x2 = rr.x + 1; 11291 11292 box[3] = box[2]; 11293 box[3].x1 += rr.width; 11294 box[3].x2 += rr.width; 11295 count = 4; 11296 } 11297 11298 while (count--) { 11299 *b = box[count]; 11300 if (box_intersect(b, &clip.extents)) { 11301 b->x1 += dx; 11302 b->x2 += dx; 11303 b->y1 += dy; 11304 b->y2 += dy; 11305 if (++b == last_box) { 11306 fill.boxes(sna, &fill, boxes, last_box-boxes); 11307 if (damage) 11308 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11309 b = boxes; 11310 } 11311 } 11312 11313 } 11314 } while (--n); 11315 } 11316 RegionUninit(&clip); 11317 } 11318 goto done; 11319 11320wide_clipped: 11321 { 11322 RegionRec clip; 11323 BoxRec box[4]; 11324 int16_t offset2 = gc->lineWidth; 11325 int16_t offset1 = offset2 >> 1; 11326 int16_t offset3 = offset2 - offset1; 11327 11328 region_set(&clip, extents); 11329 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11330 goto done; 11331 11332 DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n", 11333 __FUNCTION__, 11334 clip.extents.x1, clip.extents.y1, 11335 clip.extents.x2, clip.extents.y2)); 11336 11337 if (clip.data) { 11338 const BoxRec * const clip_start = RegionBoxptr(&clip); 11339 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11340 const BoxRec *c; 11341 do { 11342 xRectangle rr = *r++; 11343 int count; 11344 11345 if ((rr.width | rr.height) == 0) 11346 continue; /* XXX -> PolyLine */ 11347 11348 rr.x += drawable->x; 11349 rr.y += drawable->y; 11350 11351 if (rr.height <= offset2 || rr.width <= offset2) { 11352 if (rr.height == 0) { 11353 box[0].x1 = rr.x; 11354 box[0].x2 = rr.x + rr.width; 11355 } else { 11356 box[0].x1 = rr.x - offset1; 11357 box[0].x2 = rr.x + rr.width + offset3; 11358 } 11359 if (rr.width == 0) { 11360 box[0].y1 = rr.y; 11361 box[0].y2 = rr.y + rr.height; 11362 } else { 11363 box[0].y1 = rr.y - offset1; 11364 box[0].y2 = rr.y + rr.height + offset3; 11365 } 11366 count = 1; 11367 } else { 11368 box[0].x1 = rr.x - offset1; 11369 box[0].x2 = box[0].x1 + rr.width + offset2; 11370 box[0].y1 = rr.y - offset1; 11371 box[0].y2 = box[0].y1 + offset2; 11372 11373 box[1].x1 = rr.x - offset1; 11374 box[1].x2 = box[1].x1 + offset2; 11375 box[1].y1 = rr.y + offset3; 11376 box[1].y2 = rr.y + rr.height - offset1; 11377 11378 box[2] = box[1]; 11379 box[2].x1 += rr.width; 11380 box[2].x2 += rr.width; 11381 11382 box[3] = box[0]; 11383 box[3].y1 += rr.height; 11384 box[3].y2 += rr.height; 11385 count = 4; 11386 } 11387 11388 while (count--) { 11389 c = find_clip_box_for_y(clip_start, 11390 clip_end, 11391 box[count].y1); 11392 while (c != clip_end) { 11393 if (box[count].y2 <= c->y1) 11394 break; 11395 11396 *b = box[count]; 11397 if (box_intersect(b, c++)) { 11398 b->x1 += dx; 11399 b->x2 += dx; 11400 b->y1 += dy; 11401 b->y2 += dy; 11402 if (++b == last_box) { 11403 fill.boxes(sna, &fill, boxes, last_box-boxes); 11404 if (damage) 11405 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11406 b = boxes; 11407 } 11408 } 11409 } 11410 } 11411 } while (--n); 11412 } else { 11413 DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n", 11414 __FUNCTION__, offset1, offset2, offset3)); 11415 do { 11416 xRectangle rr = *r++; 11417 int count; 11418 rr.x += drawable->x; 11419 rr.y += drawable->y; 11420 11421 DBG(("%s: r=(%d, %d)x(%d, %d)\n", 11422 __FUNCTION__, rr.x, rr.y, rr.width, rr.height)); 11423 if (rr.height <= offset2 || rr.width <= offset2) { 11424 if (rr.height == 0) { 11425 box[0].x1 = rr.x; 11426 box[0].x2 = rr.x + rr.width; 11427 } else { 11428 box[0].x1 = rr.x - offset1; 11429 box[0].x2 = box[0].x1 + rr.width + offset2; 11430 } 11431 if (rr.width == 0) { 11432 box[0].y1 = rr.y; 11433 box[0].y2 = rr.y + rr.height; 11434 } else { 11435 box[0].y1 = rr.y - offset1; 11436 box[0].y2 = box[0].y1 + rr.height + offset2; 11437 } 11438 count = 1; 11439 } else { 11440 box[0].x1 = rr.x - offset1; 11441 box[0].x2 = box[0].x1 + rr.width + offset2; 11442 box[0].y1 = rr.y - offset1; 11443 box[0].y2 = box[0].y1 + offset2; 11444 DBG(("%s: box[0]=(%d, %d), (%d, %d)\n", 11445 __FUNCTION__, 11446 box[0].x1, box[0].y1, 11447 box[0].x2, box[0].y2)); 11448 11449 box[1].x1 = rr.x - offset1; 11450 box[1].x2 = box[1].x1 + offset2; 11451 box[1].y1 = rr.y + offset3; 11452 box[1].y2 = rr.y + rr.height - offset1; 11453 DBG(("%s: box[1]=(%d, %d), (%d, %d)\n", 11454 __FUNCTION__, 11455 box[1].x1, box[1].y1, 11456 box[1].x2, box[1].y2)); 11457 11458 box[2] = box[1]; 11459 box[2].x1 += rr.width; 11460 box[2].x2 += rr.width; 11461 DBG(("%s: box[2]=(%d, %d), (%d, %d)\n", 11462 __FUNCTION__, 11463 box[2].x1, box[2].y1, 11464 box[2].x2, box[2].y2)); 11465 11466 box[3] = box[0]; 11467 box[3].y1 += rr.height; 11468 box[3].y2 += rr.height; 11469 DBG(("%s: box[3]=(%d, %d), (%d, %d)\n", 11470 __FUNCTION__, 11471 box[3].x1, box[3].y1, 11472 box[3].x2, box[3].y2)); 11473 11474 count = 4; 11475 } 11476 11477 while (count--) { 11478 *b = box[count]; 11479 if (box_intersect(b, &clip.extents)) { 11480 b->x1 += dx; 11481 b->x2 += dx; 11482 b->y1 += dy; 11483 b->y2 += dy; 11484 if (++b == last_box) { 11485 fill.boxes(sna, &fill, boxes, last_box-boxes); 11486 if (damage) 11487 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11488 b = boxes; 11489 } 11490 } 11491 } 11492 } while (--n); 11493 } 11494 RegionUninit(&clip); 11495 } 11496 goto done; 11497 11498wide: 11499 { 11500 int offset2 = gc->lineWidth; 11501 int offset1 = offset2 >> 1; 11502 int offset3 = offset2 - offset1; 11503 11504 dx += drawable->x; 11505 dy += drawable->y; 11506 11507 do { 11508 xRectangle rr = *r++; 11509 11510 if ((rr.width | rr.height) == 0) 11511 continue; /* XXX -> PolyLine */ 11512 11513 rr.x += dx; 11514 rr.y += dy; 11515 11516 if (b+4 > last_box) { 11517 fill.boxes(sna, &fill, boxes, last_box-boxes); 11518 if (damage) 11519 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11520 b = boxes; 11521 } 11522 11523 if (rr.height <= offset2 || rr.width <= offset2) { 11524 if (rr.height == 0) { 11525 b->x1 = rr.x; 11526 b->x2 = rr.x + rr.width; 11527 } else { 11528 b->x1 = rr.x - offset1; 11529 b->x2 = rr.x + rr.width + offset3; 11530 } 11531 if (rr.width == 0) { 11532 b->y1 = rr.y; 11533 b->y2 = rr.y + rr.height; 11534 } else { 11535 b->y1 = rr.y - offset1; 11536 b->y2 = rr.y + rr.height + offset3; 11537 } 11538 b++; 11539 } else { 11540 b[0].x1 = rr.x - offset1; 11541 b[0].x2 = b[0].x1 + rr.width + offset2; 11542 b[0].y1 = rr.y - offset1; 11543 b[0].y2 = b[0].y1 + offset2; 11544 11545 b[1].x1 = rr.x - offset1; 11546 b[1].x2 = b[1].x1 + offset2; 11547 b[1].y1 = rr.y + offset3; 11548 b[1].y2 = rr.y + rr.height - offset1; 11549 11550 b[2] = b[1]; 11551 b[2].x1 += rr.width; 11552 b[2].x2 += rr.width; 11553 11554 b[3] = b[0]; 11555 b[3].y1 += rr.height; 11556 b[3].y2 += rr.height; 11557 b += 4; 11558 } 11559 } while (--n); 11560 } 11561 goto done; 11562 11563done: 11564 if (b != boxes) { 11565 fill.boxes(sna, &fill, boxes, b-boxes); 11566 if (damage) 11567 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11568 } 11569 fill.done(sna, &fill); 11570 assert_pixmap_damage(pixmap); 11571 return true; 11572} 11573 11574static void 11575sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) 11576{ 11577 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11578 struct sna *sna = to_sna_from_pixmap(pixmap); 11579 struct sna_damage **damage; 11580 struct kgem_bo *bo; 11581 RegionRec region; 11582 unsigned flags; 11583 11584 DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", 11585 __FUNCTION__, 11586 n, r->x, r->y, r->width, r->height, 11587 gc->lineWidth)); 11588 11589 flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); 11590 if (flags == 0) 11591 return; 11592 11593 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11594 region.extents.x1, region.extents.y1, 11595 region.extents.x2, region.extents.y2, 11596 flags)); 11597 11598 if (FORCE_FALLBACK) 11599 goto fallback; 11600 11601 if (!ACCEL_POLY_RECTANGLE) 11602 goto fallback; 11603 11604 if (wedged(sna)) { 11605 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11606 goto fallback; 11607 } 11608 11609 DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n", 11610 __FUNCTION__, 11611 gc->fillStyle, gc->fillStyle == FillSolid, 11612 gc->lineStyle, gc->lineStyle == LineSolid, 11613 gc->joinStyle, gc->joinStyle == JoinMiter, 11614 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 11615 11616 if (!PM_IS_SOLID(drawable, gc->planemask)) 11617 goto fallback; 11618 11619 if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) { 11620 DBG(("%s: trying blt solid fill [%08lx] paths\n", 11621 __FUNCTION__, gc->fgPixel)); 11622 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11623 ®ion.extents, &damage)) && 11624 sna_poly_rectangle_blt(drawable, bo, damage, 11625 gc, n, r, ®ion.extents, flags&2)) 11626 return; 11627 } else { 11628 /* Not a trivial outline, but we still maybe able to break it 11629 * down into simpler operations that we can accelerate. 11630 */ 11631 if (sna_drawable_use_bo(drawable, PREFER_GPU, 11632 ®ion.extents, &damage)) { 11633 miPolyRectangle(drawable, gc, n, r); 11634 return; 11635 } 11636 } 11637 11638fallback: 11639 DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11640 region_num_rects(gc->pCompositeClip), 11641 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 11642 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2)); 11643 11644 region.data = NULL; 11645 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 11646 return; 11647 11648 DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11649 region_num_rects(®ion), 11650 region.extents.x1, region.extents.y1, 11651 region.extents.x2, region.extents.y2)); 11652 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 11653 goto out; 11654 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 11655 drawable_gc_flags(drawable, gc, true))) 11656 goto out; 11657 11658 if (sigtrap_get() == 0) { 11659 DBG(("%s: miPolyRectangle\n", __FUNCTION__)); 11660 miPolyRectangle(drawable, gc, n, r); 11661 FALLBACK_FLUSH(drawable); 11662 sigtrap_put(); 11663 } 11664out: 11665 sna_gc_move_to_gpu(gc); 11666 RegionUninit(®ion); 11667} 11668 11669static unsigned 11670sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, 11671 int n, xArc *arc, 11672 BoxPtr out) 11673{ 11674 BoxRec box; 11675 bool clipped; 11676 int v; 11677 11678 if (n == 0) 11679 return 0; 11680 11681 box.x1 = arc->x; 11682 box.x2 = bound(box.x1, arc->width); 11683 box.y1 = arc->y; 11684 box.y2 = bound(box.y1, arc->height); 11685 11686 while (--n) { 11687 arc++; 11688 if (box.x1 > arc->x) 11689 box.x1 = arc->x; 11690 v = bound(arc->x, arc->width); 11691 if (box.x2 < v) 11692 box.x2 = v; 11693 if (box.y1 > arc->y) 11694 box.y1 = arc->y; 11695 v = bound(arc->y, arc->height); 11696 if (box.y2 < v) 11697 box.y2 = v; 11698 } 11699 11700 v = gc->lineWidth >> 1; 11701 if (v) { 11702 box.x1 -= v; 11703 box.x2 += v; 11704 box.y1 -= v; 11705 box.y2 += v; 11706 } 11707 11708 box.x2++; 11709 box.y2++; 11710 11711 clipped = trim_and_translate_box(&box, drawable, gc); 11712 if (box_empty(&box)) 11713 return 0; 11714 11715 *out = box; 11716 return 1 | clipped << 1; 11717} 11718 11719static void 11720sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc) 11721{ 11722 struct sna_fill_spans data; 11723 struct sna_pixmap *priv; 11724 11725 DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth)); 11726 11727 data.flags = sna_poly_arc_extents(drawable, gc, n, arc, 11728 &data.region.extents); 11729 if (data.flags == 0) 11730 return; 11731 11732 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11733 data.region.extents.x1, data.region.extents.y1, 11734 data.region.extents.x2, data.region.extents.y2, 11735 data.flags)); 11736 11737 data.region.data = NULL; 11738 11739 if (FORCE_FALLBACK) 11740 goto fallback; 11741 11742 if (!ACCEL_POLY_ARC) 11743 goto fallback; 11744 11745 data.pixmap = get_drawable_pixmap(drawable); 11746 data.sna = to_sna_from_pixmap(data.pixmap); 11747 priv = sna_pixmap(data.pixmap); 11748 if (priv == NULL) { 11749 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11750 goto fallback; 11751 } 11752 11753 if (wedged(data.sna)) { 11754 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11755 goto fallback; 11756 } 11757 11758 if (!PM_IS_SOLID(drawable, gc->planemask)) 11759 goto fallback; 11760 11761 if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11762 &data.region.extents, &data.damage))) { 11763 uint32_t color; 11764 11765 DBG(("%s: converting arcs into spans\n", __FUNCTION__)); 11766 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 11767 11768 if (gc_is_solid(gc, &color)) { 11769 sna_gc(gc)->priv = &data; 11770 11771 assert(gc->miTranslate); 11772 if (gc->lineStyle == LineSolid) { 11773 struct sna_fill_op fill; 11774 11775 if (!sna_fill_init_blt(&fill, 11776 data.sna, data.pixmap, 11777 data.bo, gc->alu, color, 11778 FILL_POINTS | FILL_SPANS)) 11779 goto fallback; 11780 11781 if ((data.flags & IS_CLIPPED) == 0) { 11782 if (data.dx | data.dy) 11783 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 11784 else 11785 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 11786 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 11787 } else { 11788 if (!region_maybe_clip(&data.region, 11789 gc->pCompositeClip)) 11790 return; 11791 11792 if (region_is_singular(&data.region)) { 11793 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 11794 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 11795 } else { 11796 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 11797 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 11798 } 11799 } 11800 11801 data.op = &fill; 11802 gc->ops = &sna_gc_ops__tmp; 11803 if (gc->lineWidth == 0) 11804 miZeroPolyArc(drawable, gc, n, arc); 11805 else 11806 miPolyArc(drawable, gc, n, arc); 11807 gc->ops = (GCOps *)&sna_gc_ops; 11808 11809 fill.done(data.sna, &fill); 11810 } else { 11811 if (!region_maybe_clip(&data.region, 11812 gc->pCompositeClip)) 11813 return; 11814 11815 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11816 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11817 11818 gc->ops = &sna_gc_ops__tmp; 11819 if (gc->lineWidth == 0) 11820 miZeroPolyArc(drawable, gc, n, arc); 11821 else 11822 miPolyArc(drawable, gc, n, arc); 11823 gc->ops = (GCOps *)&sna_gc_ops; 11824 } 11825 11826 if (data.damage) { 11827 if (data.dx | data.dy) 11828 pixman_region_translate(&data.region, data.dx, data.dy); 11829 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11830 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 11831 } 11832 assert_pixmap_damage(data.pixmap); 11833 RegionUninit(&data.region); 11834 return; 11835 } 11836 11837 /* XXX still around 10x slower for x11perf -ellipse */ 11838 if (gc->lineWidth == 0) 11839 miZeroPolyArc(drawable, gc, n, arc); 11840 else 11841 miPolyArc(drawable, gc, n, arc); 11842 return; 11843 } 11844 11845fallback: 11846 DBG(("%s -- fallback\n", __FUNCTION__)); 11847 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11848 return; 11849 11850 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11851 goto out; 11852 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11853 drawable_gc_flags(drawable, gc, true))) 11854 goto out; 11855 11856 if (sigtrap_get() == 0) { 11857 DBG(("%s -- fbPolyArc\n", __FUNCTION__)); 11858 fbPolyArc(drawable, gc, n, arc); 11859 FALLBACK_FLUSH(drawable); 11860 sigtrap_put(); 11861 } 11862out: 11863 sna_gc_move_to_gpu(gc); 11864 RegionUninit(&data.region); 11865} 11866 11867static bool 11868sna_poly_fill_rect_blt(DrawablePtr drawable, 11869 struct kgem_bo *bo, 11870 struct sna_damage **damage, 11871 GCPtr gc, uint32_t pixel, 11872 int n, const xRectangle *rect, 11873 const BoxRec *extents, 11874 unsigned flags) 11875{ 11876 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11877 struct sna *sna = to_sna_from_pixmap(pixmap); 11878 struct sna_fill_op fill; 11879 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11880 int16_t dx, dy; 11881 11882 DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n", 11883 __FUNCTION__, pixmap->drawable.serialNumber, n, 11884 rect->x, rect->y, rect->width, rect->height, 11885 drawable->x, drawable->y, 11886 flags&2)); 11887 11888 if (n == 1 && region_is_singular(gc->pCompositeClip)) { 11889 BoxRec r; 11890 bool success = true; 11891 11892 r.x1 = rect->x + drawable->x; 11893 r.y1 = rect->y + drawable->y; 11894 r.x2 = bound(r.x1, rect->width); 11895 r.y2 = bound(r.y1, rect->height); 11896 if (box_intersect(&r, &gc->pCompositeClip->extents)) { 11897 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 11898 r.x1 += dx; r.y1 += dy; 11899 r.x2 += dx; r.y2 += dy; 11900 } 11901 DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n", 11902 __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL)); 11903 11904 assert_pixmap_contains_box(pixmap, &r); 11905 if (sna->render.fill_one(sna, pixmap, bo, pixel, 11906 r.x1, r.y1, r.x2, r.y2, 11907 gc->alu)) { 11908 if (r.x2 - r.x1 == pixmap->drawable.width && 11909 r.y2 - r.y1 == pixmap->drawable.height) { 11910 if (damage) { 11911 sna_damage_all(damage, pixmap); 11912 damage = NULL; 11913 } 11914 if (flags & OVERWRITES) { 11915 struct sna_pixmap *priv = sna_pixmap(pixmap); 11916 if (bo == priv->gpu_bo) { 11917 assert(damage == NULL || damage == &priv->gpu_damage); 11918 assert(priv->gpu_bo->proxy == NULL); 11919 sna_damage_destroy(&priv->cpu_damage); 11920 list_del(&priv->flush_list); 11921 priv->clear = true; 11922 priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel; 11923 11924 DBG(("%s: pixmap=%ld, marking clear [%08x]\n", 11925 __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); 11926 } 11927 } 11928 } 11929 if (damage) 11930 sna_damage_add_box(damage, &r); 11931 assert_pixmap_damage(pixmap); 11932 } else 11933 success = false; 11934 } 11935 11936 return success; 11937 } 11938 11939 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) { 11940 DBG(("%s: unsupported blt\n", __FUNCTION__)); 11941 return false; 11942 } 11943 11944 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11945 if ((flags & IS_CLIPPED) == 0) { 11946 dx += drawable->x; 11947 dy += drawable->y; 11948 11949 sna_damage_add_rectangles(damage, rect, n, dx, dy); 11950 if (dx|dy) { 11951 do { 11952 unsigned nbox = n; 11953 if (nbox > ARRAY_SIZE(boxes)) 11954 nbox = ARRAY_SIZE(boxes); 11955 n -= nbox; 11956 while (nbox >= 2) { 11957 b[0].x1 = rect[0].x + dx; 11958 b[0].y1 = rect[0].y + dy; 11959 b[0].x2 = b[0].x1 + rect[0].width; 11960 b[0].y2 = b[0].y1 + rect[0].height; 11961 11962 b[1].x1 = rect[1].x + dx; 11963 b[1].y1 = rect[1].y + dy; 11964 b[1].x2 = b[1].x1 + rect[1].width; 11965 b[1].y2 = b[1].y1 + rect[1].height; 11966 11967 b += 2; 11968 rect += 2; 11969 nbox -= 2; 11970 } 11971 if (nbox) { 11972 b->x1 = rect->x + dx; 11973 b->y1 = rect->y + dy; 11974 b->x2 = b->x1 + rect->width; 11975 b->y2 = b->y1 + rect->height; 11976 b++; 11977 rect++; 11978 } 11979 fill.boxes(sna, &fill, boxes, b-boxes); 11980 b = boxes; 11981 } while (n); 11982 } else { 11983 do { 11984 unsigned nbox = n; 11985 if (nbox > ARRAY_SIZE(boxes)) 11986 nbox = ARRAY_SIZE(boxes); 11987 n -= nbox; 11988 while (nbox >= 2) { 11989 b[0].x1 = rect[0].x; 11990 b[0].y1 = rect[0].y; 11991 b[0].x2 = b[0].x1 + rect[0].width; 11992 b[0].y2 = b[0].y1 + rect[0].height; 11993 11994 b[1].x1 = rect[1].x; 11995 b[1].y1 = rect[1].y; 11996 b[1].x2 = b[1].x1 + rect[1].width; 11997 b[1].y2 = b[1].y1 + rect[1].height; 11998 11999 b += 2; 12000 rect += 2; 12001 nbox -= 2; 12002 } 12003 if (nbox) { 12004 b->x1 = rect->x; 12005 b->y1 = rect->y; 12006 b->x2 = b->x1 + rect->width; 12007 b->y2 = b->y1 + rect->height; 12008 b++; 12009 rect++; 12010 } 12011 fill.boxes(sna, &fill, boxes, b-boxes); 12012 b = boxes; 12013 } while (n); 12014 } 12015 } else { 12016 RegionRec clip; 12017 12018 region_set(&clip, extents); 12019 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12020 goto done; 12021 12022 if (clip.data == NULL) { 12023 do { 12024 b->x1 = rect->x + drawable->x; 12025 b->y1 = rect->y + drawable->y; 12026 b->x2 = bound(b->x1, rect->width); 12027 b->y2 = bound(b->y1, rect->height); 12028 rect++; 12029 12030 if (box_intersect(b, &clip.extents)) { 12031 b->x1 += dx; 12032 b->x2 += dx; 12033 b->y1 += dy; 12034 b->y2 += dy; 12035 if (++b == last_box) { 12036 fill.boxes(sna, &fill, boxes, last_box-boxes); 12037 if (damage) 12038 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 12039 b = boxes; 12040 } 12041 } 12042 } while (--n); 12043 } else { 12044 const BoxRec * const clip_start = RegionBoxptr(&clip); 12045 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12046 const BoxRec *c; 12047 12048 do { 12049 BoxRec box; 12050 12051 box.x1 = rect->x + drawable->x; 12052 box.y1 = rect->y + drawable->y; 12053 box.x2 = bound(box.x1, rect->width); 12054 box.y2 = bound(box.y1, rect->height); 12055 rect++; 12056 12057 c = find_clip_box_for_y(clip_start, 12058 clip_end, 12059 box.y1); 12060 while (c != clip_end) { 12061 if (box.y2 <= c->y1) 12062 break; 12063 12064 *b = box; 12065 if (box_intersect(b, c++)) { 12066 b->x1 += dx; 12067 b->x2 += dx; 12068 b->y1 += dy; 12069 b->y2 += dy; 12070 if (++b == last_box) { 12071 fill.boxes(sna, &fill, boxes, last_box-boxes); 12072 if (damage) 12073 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 12074 b = boxes; 12075 } 12076 } 12077 12078 } 12079 } while (--n); 12080 } 12081 12082 RegionUninit(&clip); 12083 if (b != boxes) { 12084 fill.boxes(sna, &fill, boxes, b-boxes); 12085 if (damage) 12086 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 12087 } 12088 } 12089done: 12090 fill.done(sna, &fill); 12091 assert_pixmap_damage(pixmap); 12092 return true; 12093} 12094 12095static uint32_t 12096get_pixel(PixmapPtr pixmap) 12097{ 12098 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 12099 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12100 return 0; 12101 12102 switch (pixmap->drawable.bitsPerPixel) { 12103 case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 12104 case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 12105 default: return *(uint8_t *)pixmap->devPrivate.ptr; 12106 } 12107} 12108 12109inline static int 12110_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 12111{ 12112 if (USE_SPANS) 12113 return USE_SPANS > 0; 12114 12115 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 12116 sna_pixmap_is_gpu(gc->tile.pixmap)) { 12117 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 12118 return PREFER_GPU | FORCE_GPU; 12119 } 12120 12121 return PREFER_GPU; 12122} 12123 12124static int 12125use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 12126{ 12127 int ret = _use_fill_spans(drawable, gc, extents, flags); 12128 DBG(("%s? %d\n", __FUNCTION__, ret)); 12129 return ret; 12130} 12131 12132static void 12133sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, 12134 int shape, int mode, 12135 int n, DDXPointPtr pt) 12136{ 12137 struct sna_fill_spans data; 12138 struct sna_pixmap *priv; 12139 12140 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 12141 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 12142 (gc->fillStyle == FillSolid || 12143 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 12144 gc->fillStyle, gc->tileIsPixel, 12145 gc->alu)); 12146 DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n", 12147 __FUNCTION__, draw->serialNumber, 12148 draw->x, draw->y, draw->width, draw->height)); 12149 12150 data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, 12151 &data.region.extents); 12152 if (data.flags == 0) { 12153 DBG(("%s, nothing to do\n", __FUNCTION__)); 12154 return; 12155 } 12156 12157 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 12158 data.region.extents.x1, data.region.extents.y1, 12159 data.region.extents.x2, data.region.extents.y2, 12160 data.flags)); 12161 12162 data.region.data = NULL; 12163 12164 if (FORCE_FALLBACK) 12165 goto fallback; 12166 12167 if (!ACCEL_POLY_FILL_POLYGON) 12168 goto fallback; 12169 12170 data.pixmap = get_drawable_pixmap(draw); 12171 data.sna = to_sna_from_pixmap(data.pixmap); 12172 priv = sna_pixmap(data.pixmap); 12173 if (priv == NULL) { 12174 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 12175 goto fallback; 12176 } 12177 12178 if (wedged(data.sna)) { 12179 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 12180 goto fallback; 12181 } 12182 12183 if (!PM_IS_SOLID(draw, gc->planemask)) 12184 goto fallback; 12185 12186 if ((data.bo = sna_drawable_use_bo(draw, 12187 use_fill_spans(draw, gc, &data.region.extents, data.flags), 12188 &data.region.extents, 12189 &data.damage))) { 12190 uint32_t color; 12191 12192 sna_gc(gc)->priv = &data; 12193 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 12194 12195 if (gc_is_solid(gc, &color)) { 12196 struct sna_fill_op fill; 12197 12198 if (!sna_fill_init_blt(&fill, 12199 data.sna, data.pixmap, 12200 data.bo, gc->alu, color, 12201 FILL_SPANS)) 12202 goto fallback; 12203 12204 data.op = &fill; 12205 12206 if ((data.flags & IS_CLIPPED) == 0) { 12207 if (data.dx | data.dy) 12208 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 12209 else 12210 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 12211 } else { 12212 if (!region_maybe_clip(&data.region, 12213 gc->pCompositeClip)) 12214 return; 12215 12216 if (region_is_singular(&data.region)) 12217 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 12218 else 12219 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 12220 } 12221 assert(gc->miTranslate); 12222 gc->ops = &sna_gc_ops__tmp; 12223 12224 miFillPolygon(draw, gc, shape, mode, n, pt); 12225 fill.done(data.sna, &fill); 12226 } else { 12227 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 12228 gc->ops = &sna_gc_ops__tmp; 12229 12230 miFillPolygon(draw, gc, shape, mode, n, pt); 12231 } 12232 12233 gc->ops = (GCOps *)&sna_gc_ops; 12234 if (data.damage) { 12235 if (data.dx | data.dy) 12236 pixman_region_translate(&data.region, data.dx, data.dy); 12237 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 12238 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 12239 } 12240 assert_pixmap_damage(data.pixmap); 12241 RegionUninit(&data.region); 12242 return; 12243 } 12244 12245fallback: 12246 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 12247 data.region.extents.x1, data.region.extents.y1, 12248 data.region.extents.x2, data.region.extents.y2)); 12249 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 12250 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 12251 return; 12252 } 12253 12254 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 12255 goto out; 12256 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 12257 drawable_gc_flags(draw, gc, true))) 12258 goto out; 12259 12260 if (sigtrap_get() == 0) { 12261 DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", 12262 __FUNCTION__)); 12263 miFillPolygon(draw, gc, shape, mode, n, pt); 12264 sigtrap_put(); 12265 } 12266out: 12267 sna_gc_move_to_gpu(gc); 12268 RegionUninit(&data.region); 12269} 12270 12271static struct kgem_bo * 12272sna_pixmap_get_source_bo(PixmapPtr pixmap) 12273{ 12274 struct sna_pixmap *priv = sna_pixmap(pixmap); 12275 unsigned flags; 12276 BoxRec box; 12277 12278 box.x1 = box.y1 = 0; 12279 box.x2 = pixmap->drawable.width; 12280 box.y2 = pixmap->drawable.height; 12281 12282 DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__, 12283 pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 12284 12285 if (priv == NULL) { 12286 DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__)); 12287 return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12288 pixmap->devPrivate.ptr, &box, 12289 pixmap->devKind, 12290 pixmap->drawable.bitsPerPixel); 12291 } 12292 12293 if (priv->gpu_damage) { 12294 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) 12295 return kgem_bo_reference(priv->gpu_bo); 12296 } else if (priv->cpu_damage) { 12297 if (priv->cpu_bo) 12298 return kgem_bo_reference(priv->cpu_bo); 12299 } else { 12300 if (priv->gpu_bo) 12301 return kgem_bo_reference(priv->gpu_bo); 12302 if (priv->cpu_bo) 12303 return kgem_bo_reference(priv->cpu_bo); 12304 } 12305 12306 flags = MOVE_READ | MOVE_ASYNC_HINT; 12307 if (priv->gpu_bo && priv->gpu_bo->proxy) { 12308 struct kgem_bo *bo = priv->gpu_bo; 12309 if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096)) 12310 flags |= __MOVE_FORCE; 12311 } 12312 if (priv->gpu_bo == NULL) { 12313 if (++priv->source_count > SOURCE_BIAS) 12314 flags |= __MOVE_FORCE; 12315 } 12316 12317 if (!sna_pixmap_move_to_gpu(pixmap, flags)) { 12318 struct kgem_bo *upload; 12319 12320 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12321 return NULL; 12322 12323 upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12324 pixmap->devPrivate.ptr, &box, 12325 pixmap->devKind, 12326 pixmap->drawable.bitsPerPixel); 12327 if (upload == NULL) 12328 return NULL; 12329 12330 if (priv->gpu_bo == NULL) { 12331 DBG(("%s: adding upload cache to pixmap=%ld\n", 12332 __FUNCTION__, pixmap->drawable.serialNumber)); 12333 assert(upload->proxy != NULL); 12334 kgem_proxy_bo_attach(upload, &priv->gpu_bo); 12335 } 12336 12337 return upload; 12338 } 12339 12340 return kgem_bo_reference(priv->gpu_bo); 12341} 12342 12343/* 12344static bool 12345tile(DrawablePtr drawable, 12346 struct kgem_bo *bo, struct sna_damage **damage, 12347 PixmapPtr tile, const DDXPointRec * const origin, int alu, 12348 int n, xRectangle *rect, 12349 const BoxRec *extents, unsigned clipped) 12350 */ 12351 12352static bool 12353sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, 12354 struct kgem_bo *bo, struct sna_damage **damage, 12355 struct kgem_bo *tile_bo, GCPtr gc, 12356 int n, const xRectangle *r, 12357 const BoxRec *extents, unsigned clipped) 12358{ 12359 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12360 struct sna *sna = to_sna_from_pixmap(pixmap); 12361 const DDXPointRec * const origin = &gc->patOrg; 12362 uint32_t br00, br13; 12363 int tx, ty; 12364 int16_t dx, dy; 12365 uint32_t *b; 12366 12367 if (NO_TILE_8x8) 12368 return false; 12369 12370 DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n", 12371 __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y)); 12372 12373 DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch)); 12374 if (tile_bo->tiling) 12375 return false; 12376 12377 if (!kgem_bo_can_blt(&sna->kgem, bo) || 12378 !kgem_bo_can_blt(&sna->kgem, tile_bo)) 12379 return false; 12380 12381 assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3); 12382 12383 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12384 assert(kgem_bo_can_blt(&sna->kgem, bo)); 12385 if (!kgem_check_batch(&sna->kgem, 10+2*3) || 12386 !kgem_check_reloc(&sna->kgem, 2) || 12387 !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) { 12388 kgem_submit(&sna->kgem); 12389 if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) 12390 return false; 12391 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12392 } 12393 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12394 12395 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12396 assert(extents->x1 + dx >= 0); 12397 assert(extents->y1 + dy >= 0); 12398 assert(extents->x2 + dx <= pixmap->drawable.width); 12399 assert(extents->y2 + dy <= pixmap->drawable.height); 12400 12401 br00 = XY_SCANLINE_BLT; 12402 tx = (-drawable->x - dx - origin->x) % 8; 12403 if (tx < 0) 12404 tx += 8; 12405 ty = (-drawable->y - dy - origin->y) % 8; 12406 if (ty < 0) 12407 ty += 8; 12408 br00 |= tx << 12 | ty << 8; 12409 12410 br13 = bo->pitch; 12411 if (sna->kgem.gen >= 040 && bo->tiling) { 12412 br00 |= BLT_DST_TILED; 12413 br13 >>= 2; 12414 } 12415 br13 |= blt_depth(drawable->depth) << 24; 12416 br13 |= fill_ROP[gc->alu] << 16; 12417 12418 if (!clipped) { 12419 dx += drawable->x; 12420 dy += drawable->y; 12421 12422 sna_damage_add_rectangles(damage, r, n, dx, dy); 12423 if (n == 1) { 12424 DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12425 __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty)); 12426 12427 assert(r->x + dx >= 0); 12428 assert(r->y + dy >= 0); 12429 assert(r->x + dx + r->width <= pixmap->drawable.width); 12430 assert(r->y + dy + r->height <= pixmap->drawable.height); 12431 12432 assert(sna->kgem.mode == KGEM_BLT); 12433 b = sna->kgem.batch + sna->kgem.nbatch; 12434 if (sna->kgem.gen >= 0100) { 12435 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6; 12436 b[1] = br13; 12437 b[2] = (r->y + dy) << 16 | (r->x + dx); 12438 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12439 *(uint64_t *)(b+4) = 12440 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12441 I915_GEM_DOMAIN_RENDER << 16 | 12442 I915_GEM_DOMAIN_RENDER | 12443 KGEM_RELOC_FENCED, 12444 0); 12445 *(uint64_t *)(b+6) = 12446 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo, 12447 I915_GEM_DOMAIN_RENDER << 16 | 12448 KGEM_RELOC_FENCED, 12449 0); 12450 sna->kgem.nbatch += 8; 12451 } else { 12452 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4; 12453 b[1] = br13; 12454 b[2] = (r->y + dy) << 16 | (r->x + dx); 12455 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12456 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12457 I915_GEM_DOMAIN_RENDER << 16 | 12458 I915_GEM_DOMAIN_RENDER | 12459 KGEM_RELOC_FENCED, 12460 0); 12461 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo, 12462 I915_GEM_DOMAIN_RENDER << 16 | 12463 KGEM_RELOC_FENCED, 12464 0); 12465 sna->kgem.nbatch += 6; 12466 } 12467 } else do { 12468 int n_this_time, rem; 12469 12470 assert(sna->kgem.mode == KGEM_BLT); 12471 b = sna->kgem.batch + sna->kgem.nbatch; 12472 if (sna->kgem.gen >= 0100) { 12473 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12474 b[1] = br13; 12475 b[2] = 0; 12476 b[3] = 0; 12477 *(uint64_t *)(b+4) = 12478 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12479 I915_GEM_DOMAIN_RENDER << 16 | 12480 I915_GEM_DOMAIN_RENDER | 12481 KGEM_RELOC_FENCED, 12482 0); 12483 b[6] = gc->bgPixel; 12484 b[7] = gc->fgPixel; 12485 *(uint64_t *)(b+8) = 12486 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12487 I915_GEM_DOMAIN_RENDER << 16 | 12488 KGEM_RELOC_FENCED, 12489 0); 12490 sna->kgem.nbatch += 10; 12491 } else { 12492 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12493 b[1] = br13; 12494 b[2] = 0; 12495 b[3] = 0; 12496 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12497 I915_GEM_DOMAIN_RENDER << 16 | 12498 I915_GEM_DOMAIN_RENDER | 12499 KGEM_RELOC_FENCED, 12500 0); 12501 b[5] = gc->bgPixel; 12502 b[6] = gc->fgPixel; 12503 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12504 I915_GEM_DOMAIN_RENDER << 16 | 12505 KGEM_RELOC_FENCED, 12506 0); 12507 sna->kgem.nbatch += 8; 12508 } 12509 12510 n_this_time = n; 12511 rem = kgem_batch_space(&sna->kgem); 12512 if (3*n_this_time > rem) 12513 n_this_time = rem / 3; 12514 assert(n_this_time); 12515 n -= n_this_time; 12516 12517 assert(sna->kgem.mode == KGEM_BLT); 12518 b = sna->kgem.batch + sna->kgem.nbatch; 12519 sna->kgem.nbatch += 3*n_this_time; 12520 do { 12521 assert(r->x + dx >= 0); 12522 assert(r->y + dy >= 0); 12523 assert(r->x + dx + r->width <= pixmap->drawable.width); 12524 assert(r->y + dy + r->height <= pixmap->drawable.height); 12525 12526 b[0] = br00; 12527 b[1] = (r->y + dy) << 16 | (r->x + dx); 12528 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12529 b += 3; r++; 12530 } while (--n_this_time); 12531 12532 if (!n) 12533 break; 12534 12535 _kgem_submit(&sna->kgem); 12536 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12537 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12538 } while (1); 12539 } else { 12540 RegionRec clip; 12541 uint16_t unwind_batch, unwind_reloc; 12542 12543 region_set(&clip, extents); 12544 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12545 goto done; 12546 12547 unwind_batch = sna->kgem.nbatch; 12548 unwind_reloc = sna->kgem.nreloc; 12549 12550 assert(sna->kgem.mode == KGEM_BLT); 12551 b = sna->kgem.batch + sna->kgem.nbatch; 12552 if (sna->kgem.gen >= 0100) { 12553 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12554 b[1] = br13; 12555 b[2] = 0; 12556 b[3] = 0; 12557 *(uint64_t *)(b+4) = 12558 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12559 I915_GEM_DOMAIN_RENDER << 16 | 12560 I915_GEM_DOMAIN_RENDER | 12561 KGEM_RELOC_FENCED, 12562 0); 12563 b[6] = gc->bgPixel; 12564 b[7] = gc->fgPixel; 12565 *(uint64_t *)(b+8) = 12566 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12567 I915_GEM_DOMAIN_RENDER << 16 | 12568 KGEM_RELOC_FENCED, 12569 0); 12570 sna->kgem.nbatch += 10; 12571 } else { 12572 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12573 b[1] = br13; 12574 b[2] = 0; 12575 b[3] = 0; 12576 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12577 I915_GEM_DOMAIN_RENDER << 16 | 12578 I915_GEM_DOMAIN_RENDER | 12579 KGEM_RELOC_FENCED, 12580 0); 12581 b[5] = gc->bgPixel; 12582 b[6] = gc->fgPixel; 12583 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12584 I915_GEM_DOMAIN_RENDER << 16 | 12585 KGEM_RELOC_FENCED, 12586 0); 12587 sna->kgem.nbatch += 8; 12588 } 12589 12590 if (clip.data == NULL) { 12591 const BoxRec *c = &clip.extents; 12592 DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n)); 12593 while (n--) { 12594 BoxRec box; 12595 12596 box.x1 = r->x + drawable->x; 12597 box.y1 = r->y + drawable->y; 12598 box.x2 = bound(box.x1, r->width); 12599 box.y2 = bound(box.y1, r->height); 12600 r++; 12601 12602 if (box_intersect(&box, c)) { 12603 if (!kgem_check_batch(&sna->kgem, 3)) { 12604 _kgem_submit(&sna->kgem); 12605 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12606 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12607 12608 unwind_batch = sna->kgem.nbatch; 12609 unwind_reloc = sna->kgem.nreloc; 12610 12611 assert(sna->kgem.mode == KGEM_BLT); 12612 b = sna->kgem.batch + sna->kgem.nbatch; 12613 if (sna->kgem.gen >= 0100) { 12614 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12615 b[1] = br13; 12616 b[2] = 0; 12617 b[3] = 0; 12618 *(uint64_t *)(b+4) = 12619 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12620 I915_GEM_DOMAIN_RENDER << 16 | 12621 I915_GEM_DOMAIN_RENDER | 12622 KGEM_RELOC_FENCED, 12623 0); 12624 b[6] = gc->bgPixel; 12625 b[7] = gc->fgPixel; 12626 *(uint64_t *)(b+8) = 12627 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12628 I915_GEM_DOMAIN_RENDER << 16 | 12629 KGEM_RELOC_FENCED, 12630 0); 12631 sna->kgem.nbatch += 10; 12632 } else { 12633 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12634 b[1] = br13; 12635 b[2] = 0; 12636 b[3] = 0; 12637 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12638 I915_GEM_DOMAIN_RENDER << 16 | 12639 I915_GEM_DOMAIN_RENDER | 12640 KGEM_RELOC_FENCED, 12641 0); 12642 b[5] = gc->bgPixel; 12643 b[6] = gc->fgPixel; 12644 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12645 I915_GEM_DOMAIN_RENDER << 16 | 12646 KGEM_RELOC_FENCED, 12647 0); 12648 sna->kgem.nbatch += 8; 12649 } 12650 } 12651 12652 assert(box.x1 + dx >= 0); 12653 assert(box.y1 + dy >= 0); 12654 assert(box.x2 + dx <= pixmap->drawable.width); 12655 assert(box.y2 + dy <= pixmap->drawable.height); 12656 12657 DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12658 __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty)); 12659 12660 assert(sna->kgem.mode == KGEM_BLT); 12661 b = sna->kgem.batch + sna->kgem.nbatch; 12662 b[0] = br00; 12663 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 12664 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 12665 sna->kgem.nbatch += 3; 12666 } 12667 } 12668 } else { 12669 const BoxRec * const clip_start = RegionBoxptr(&clip); 12670 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12671 const BoxRec *c; 12672 12673 DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n)); 12674 do { 12675 BoxRec box; 12676 12677 box.x1 = r->x + drawable->x; 12678 box.y1 = r->y + drawable->y; 12679 box.x2 = bound(box.x1, r->width); 12680 box.y2 = bound(box.y1, r->height); 12681 DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__, 12682 r->x, r->y, r->width, r->height, 12683 box.x1, box.y1, box.x2, box.y2)); 12684 r++; 12685 12686 c = find_clip_box_for_y(clip_start, 12687 clip_end, 12688 box.y1); 12689 while (c != clip_end) { 12690 BoxRec bb; 12691 12692 DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2)); 12693 12694 if (box.y2 <= c->y1) 12695 break; 12696 12697 bb = box; 12698 if (box_intersect(&bb, c++)) { 12699 if (!kgem_check_batch(&sna->kgem, 3)) { 12700 DBG(("%s: emitting split batch\n", __FUNCTION__)); 12701 _kgem_submit(&sna->kgem); 12702 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12703 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12704 12705 unwind_batch = sna->kgem.nbatch; 12706 unwind_reloc = sna->kgem.nreloc; 12707 12708 assert(sna->kgem.mode == KGEM_BLT); 12709 b = sna->kgem.batch + sna->kgem.nbatch; 12710 if (sna->kgem.gen >= 0100) { 12711 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12712 b[1] = br13; 12713 b[2] = 0; 12714 b[3] = 0; 12715 *(uint64_t *)(b+4) = 12716 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12717 I915_GEM_DOMAIN_RENDER << 16 | 12718 I915_GEM_DOMAIN_RENDER | 12719 KGEM_RELOC_FENCED, 12720 0); 12721 b[6] = gc->bgPixel; 12722 b[7] = gc->fgPixel; 12723 *(uint64_t *)(b+8) = 12724 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12725 I915_GEM_DOMAIN_RENDER << 16 | 12726 KGEM_RELOC_FENCED, 12727 0); 12728 sna->kgem.nbatch += 10; 12729 } else { 12730 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12731 b[1] = br13; 12732 b[2] = 0; 12733 b[3] = 0; 12734 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12735 I915_GEM_DOMAIN_RENDER << 16 | 12736 I915_GEM_DOMAIN_RENDER | 12737 KGEM_RELOC_FENCED, 12738 0); 12739 b[5] = gc->bgPixel; 12740 b[6] = gc->fgPixel; 12741 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12742 I915_GEM_DOMAIN_RENDER << 16 | 12743 KGEM_RELOC_FENCED, 12744 0); 12745 sna->kgem.nbatch += 8; 12746 } 12747 } 12748 12749 assert(bb.x1 + dx >= 0); 12750 assert(bb.y1 + dy >= 0); 12751 assert(bb.x2 + dx <= pixmap->drawable.width); 12752 assert(bb.y2 + dy <= pixmap->drawable.height); 12753 12754 DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n", 12755 __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y)); 12756 12757 assert(sna->kgem.mode == KGEM_BLT); 12758 b = sna->kgem.batch + sna->kgem.nbatch; 12759 b[0] = br00; 12760 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 12761 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 12762 sna->kgem.nbatch += 3; 12763 } 12764 } 12765 } while (--n); 12766 } 12767 12768 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 12769 sna->kgem.nbatch = unwind_batch; 12770 sna->kgem.nreloc = unwind_reloc; 12771 if (sna->kgem.nbatch == 0) 12772 kgem_bo_pair_undo(&sna->kgem, bo, tile_bo); 12773 } 12774 } 12775done: 12776 assert_pixmap_damage(pixmap); 12777 blt_done(sna); 12778 return true; 12779} 12780 12781static bool tile8(int x) 12782{ 12783 switch(x) { 12784 case 1: 12785 case 2: 12786 case 4: 12787 case 8: 12788 return true; 12789 default: 12790 return false; 12791 } 12792} 12793 12794static int next8(int x, int max) 12795{ 12796 if (x > 2 && x <= 4) 12797 x = 4; 12798 else if (x < 8) 12799 x = 8; 12800 return MIN(x, max); 12801} 12802 12803static bool 12804sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable, 12805 struct kgem_bo *bo, 12806 struct sna_damage **damage, 12807 GCPtr gc, int n, const xRectangle *rect, 12808 const BoxRec *extents, unsigned clipped) 12809{ 12810 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12811 struct sna *sna = to_sna_from_pixmap(pixmap); 12812 PixmapPtr tile = gc->tile.pixmap; 12813 int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel; 12814 const DDXPointRec origin = gc->patOrg; 12815 struct kgem_bo *upload; 12816 bool ret = false; 12817 uint8_t *src; 12818 void *ptr; 12819 12820 tx = 0, tw = tile->drawable.width; 12821 if (!tile8(tw) && tw > extents->x2 - extents->x1) { 12822 tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw; 12823 if (tx < 0) 12824 tx += tw; 12825 tw = next8(extents->x2 - extents->x1, tw); 12826 gc->patOrg.x = extents->x1 - drawable->x; 12827 } 12828 12829 ty = 0, th = tile->drawable.height; 12830 if (!tile8(th) && th > extents->y2 - extents->y1) { 12831 ty = (extents->y1 - gc->patOrg.y - drawable->y) % th; 12832 if (ty < 0) 12833 ty += th; 12834 th = next8(extents->y2 - extents->y1, th); 12835 gc->patOrg.y = extents->y1 - drawable->y; 12836 } 12837 12838 DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__, 12839 tw, th, tx, ty, tile->drawable.width, tile->drawable.height)); 12840 assert(tx < tile->drawable.width && tx >= 0); 12841 assert(ty < tile->drawable.height && ty >= 0); 12842 assert(tw && tw <= 8 && tw <= tile->drawable.width); 12843 assert(is_power_of_two(tw)); 12844 assert(th && th <= 8 && th <= tile->drawable.height); 12845 assert(is_power_of_two(th)); 12846 12847 if (!sna_pixmap_move_to_cpu(tile, MOVE_READ)) 12848 goto out_gc; 12849 12850 assert(tile->devKind); 12851 assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ)); 12852 12853 src = tile->devPrivate.ptr; 12854 src += tile->devKind * ty; 12855 src += tx * bpp/8; 12856 12857 if ((tw | th) == 1) { 12858 uint32_t pixel; 12859 switch (bpp) { 12860 case 32: pixel = *(uint32_t *)src; break; 12861 case 16: pixel = *(uint16_t *)src; break; 12862 default: pixel = *(uint8_t *)src; break; 12863 } 12864 return sna_poly_fill_rect_blt(drawable, bo, damage, 12865 gc, pixel, n, rect, 12866 extents, clipped); 12867 } 12868 12869 upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr); 12870 if (upload == NULL) 12871 goto out_gc; 12872 12873 upload->pitch = bpp; /* for sanity checks */ 12874 12875 if (sigtrap_get() == 0) { 12876 uint8_t *dst = ptr; 12877 if (tx + tw > tile->drawable.width || 12878 ty + th > tile->drawable.height) { 12879 int sy = ty; 12880 src = tile->devPrivate.ptr; 12881 for (h = 0; h < th; h++) { 12882 int sx = tx; 12883 for (w = 0; w < tw; w++) { 12884 memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8); 12885 if (++sx == tile->drawable.width) 12886 sx = 0; 12887 } 12888 w *= bpp/8; 12889 while (w < bpp) { 12890 memcpy(dst+w, dst, w); 12891 w *= 2; 12892 } 12893 if (++sy == tile->drawable.height) 12894 sy = 0; 12895 dst += bpp; 12896 } 12897 while (h < 8) { 12898 memcpy(dst, ptr, bpp*h); 12899 dst += bpp * h; 12900 h *= 2; 12901 } 12902 } else { 12903 for (h = 0; h < th; h++) { 12904 w = tw*bpp/8; 12905 memcpy(dst, src, w); 12906 while (w < bpp) { 12907 memcpy(dst+w, dst, w); 12908 w *= 2; 12909 } 12910 assert(w == bpp); 12911 12912 src += tile->devKind; 12913 dst += bpp; 12914 } 12915 while (h < 8) { 12916 memcpy(dst, ptr, bpp*h); 12917 dst += bpp * h; 12918 h *= 2; 12919 } 12920 assert(h == 8); 12921 } 12922 12923 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12924 upload, gc, n, rect, 12925 extents, clipped); 12926 sigtrap_put(); 12927 } 12928 12929 kgem_bo_destroy(&sna->kgem, upload); 12930out_gc: 12931 gc->patOrg = origin; 12932 return ret; 12933} 12934 12935inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel) 12936{ 12937 PixmapPtr tile = gc->tile.pixmap; 12938 struct sna_pixmap *priv; 12939 12940 if ((tile->drawable.width | tile->drawable.height) == 1) { 12941 DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__)); 12942 *pixel = get_pixel(tile); 12943 return true; 12944 } 12945 12946 priv = sna_pixmap(tile); 12947 if (priv == NULL || !priv->clear) 12948 return false; 12949 12950 DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__)); 12951 *pixel = priv->clear_color; 12952 return true; 12953} 12954 12955static bool 12956sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 12957 struct kgem_bo *bo, 12958 struct sna_damage **damage, 12959 GCPtr gc, int n, xRectangle *rect, 12960 const BoxRec *extents, unsigned clipped) 12961{ 12962 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12963 struct sna *sna = to_sna_from_pixmap(pixmap); 12964 PixmapPtr tile = gc->tile.pixmap; 12965 struct kgem_bo *tile_bo; 12966 const DDXPointRec * const origin = &gc->patOrg; 12967 struct sna_copy_op copy; 12968 CARD32 alu = gc->alu; 12969 int tile_width, tile_height; 12970 int16_t dx, dy; 12971 uint32_t pixel; 12972 12973 DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n", 12974 __FUNCTION__, pixmap->drawable.serialNumber, 12975 n, rect->x, rect->y, rect->width, rect->height, 12976 clipped)); 12977 12978 assert(tile->drawable.depth == drawable->depth); 12979 assert(bo); 12980 12981 if (tile_is_solid(gc, &pixel)) 12982 return sna_poly_fill_rect_blt(drawable, bo, damage, 12983 gc, pixel, 12984 n, rect, 12985 extents, clipped); 12986 12987 /* XXX [248]x[238] tiling can be reduced to a pattern fill. 12988 * Also we can do the lg2 reduction for BLT and use repeat modes for 12989 * RENDER. 12990 */ 12991 12992 tile_width = tile->drawable.width; 12993 tile_height = tile->drawable.height; 12994 if ((tile_width | tile_height) == 8) { 12995 bool ret; 12996 12997 DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__)); 12998 12999 tile_bo = sna_pixmap_get_source_bo(tile); 13000 if (tile_bo == NULL) { 13001 DBG(("%s: unable to move tile go GPU, fallback\n", 13002 __FUNCTION__)); 13003 return false; 13004 } 13005 13006 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 13007 tile_bo, gc, n, rect, 13008 extents, clipped); 13009 if (ret) { 13010 kgem_bo_destroy(&sna->kgem, tile_bo); 13011 return true; 13012 } 13013 } else { 13014 int w = tile_width, h = tile_height; 13015 struct sna_pixmap *priv = sna_pixmap(tile); 13016 13017 if (priv == NULL || priv->gpu_damage == NULL) { 13018 w = next8(extents->x2 - extents->x1, w); 13019 h = next8(extents->y2 - extents->y1, h); 13020 } 13021 13022 DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n", 13023 __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1)); 13024 13025 if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) && 13026 sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage, 13027 gc, n, rect, 13028 extents, clipped)) 13029 return true; 13030 13031 tile_bo = sna_pixmap_get_source_bo(tile); 13032 if (tile_bo == NULL) { 13033 DBG(("%s: unable to move tile go GPU, fallback\n", 13034 __FUNCTION__)); 13035 return false; 13036 } 13037 } 13038 13039 if (!sna_copy_init_blt(©, sna, tile, tile_bo, pixmap, bo, alu)) { 13040 DBG(("%s: unsupported blt\n", __FUNCTION__)); 13041 kgem_bo_destroy(&sna->kgem, tile_bo); 13042 return false; 13043 } 13044 13045 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13046 DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n", 13047 __FUNCTION__, pixmap->drawable.serialNumber, dx, dy)); 13048 if (!clipped) { 13049 dx += drawable->x; 13050 dy += drawable->y; 13051 13052 sna_damage_add_rectangles(damage, rect, n, dx, dy); 13053 do { 13054 xRectangle r = *rect++; 13055 int16_t tile_y = (r.y - origin->y) % tile_height; 13056 if (tile_y < 0) 13057 tile_y += tile_height; 13058 13059 assert(r.x + dx >= 0); 13060 assert(r.y + dy >= 0); 13061 assert(r.x + dx + r.width <= pixmap->drawable.width); 13062 assert(r.y + dy + r.height <= pixmap->drawable.height); 13063 13064 r.y += dy; 13065 do { 13066 int16_t width = r.width; 13067 int16_t x = r.x + dx, tile_x; 13068 int16_t h = tile_height - tile_y; 13069 if (h > r.height) 13070 h = r.height; 13071 r.height -= h; 13072 13073 tile_x = (r.x - origin->x) % tile_width; 13074 if (tile_x < 0) 13075 tile_x += tile_width; 13076 13077 do { 13078 int16_t w = tile_width - tile_x; 13079 if (w > width) 13080 w = width; 13081 width -= w; 13082 13083 copy.blt(sna, ©, 13084 tile_x, tile_y, 13085 w, h, 13086 x, r.y); 13087 13088 x += w; 13089 tile_x = 0; 13090 } while (width); 13091 r.y += h; 13092 tile_y = 0; 13093 } while (r.height); 13094 } while (--n); 13095 } else { 13096 RegionRec clip; 13097 13098 region_set(&clip, extents); 13099 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13100 goto done; 13101 13102 if (clip.data == NULL) { 13103 const BoxRec *box = &clip.extents; 13104 DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n", 13105 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 13106 while (n--) { 13107 BoxRec r; 13108 13109 r.x1 = rect->x + drawable->x; 13110 r.y1 = rect->y + drawable->y; 13111 r.x2 = bound(r.x1, rect->width); 13112 r.y2 = bound(r.y1, rect->height); 13113 rect++; 13114 13115 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 13116 __FUNCTION__, r.x1, r.y1, r.x2, r.y2)); 13117 13118 if (box_intersect(&r, box)) { 13119 int height = r.y2 - r.y1; 13120 int dst_y = r.y1; 13121 int tile_y = (r.y1 - drawable->y - origin->y) % tile_height; 13122 if (tile_y < 0) 13123 tile_y += tile_height; 13124 13125 assert(r.x1 + dx >= 0); 13126 assert(r.y1 + dy >= 0); 13127 assert(r.x2 + dx <= pixmap->drawable.width); 13128 assert(r.y2 + dy <= pixmap->drawable.height); 13129 13130 while (height) { 13131 int width = r.x2 - r.x1; 13132 int dst_x = r.x1, tile_x; 13133 int h = tile_height - tile_y; 13134 if (h > height) 13135 h = height; 13136 height -= h; 13137 13138 tile_x = (r.x1 - drawable->x - origin->x) % tile_width; 13139 if (tile_x < 0) 13140 tile_x += tile_width; 13141 13142 while (width > 0) { 13143 int w = tile_width - tile_x; 13144 if (w > width) 13145 w = width; 13146 width -= w; 13147 13148 copy.blt(sna, ©, 13149 tile_x, tile_y, 13150 w, h, 13151 dst_x + dx, dst_y + dy); 13152 if (damage) { 13153 BoxRec b; 13154 13155 b.x1 = dst_x + dx; 13156 b.y1 = dst_y + dy; 13157 b.x2 = b.x1 + w; 13158 b.y2 = b.y1 + h; 13159 13160 assert_pixmap_contains_box(pixmap, &b); 13161 sna_damage_add_box(damage, &b); 13162 } 13163 13164 dst_x += w; 13165 tile_x = 0; 13166 } 13167 dst_y += h; 13168 tile_y = 0; 13169 } 13170 } 13171 } 13172 } else { 13173 while (n--) { 13174 RegionRec region; 13175 const BoxRec *box; 13176 int nbox; 13177 13178 region.extents.x1 = rect->x + drawable->x; 13179 region.extents.y1 = rect->y + drawable->y; 13180 region.extents.x2 = bound(region.extents.x1, rect->width); 13181 region.extents.y2 = bound(region.extents.y1, rect->height); 13182 rect++; 13183 13184 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 13185 __FUNCTION__, 13186 region.extents.x1, 13187 region.extents.y1, 13188 region.extents.x2, 13189 region.extents.y2)); 13190 13191 region.data = NULL; 13192 RegionIntersect(®ion, ®ion, &clip); 13193 13194 assert(region.extents.x1 + dx >= 0); 13195 assert(region.extents.y1 + dy >= 0); 13196 assert(region.extents.x2 + dx <= pixmap->drawable.width); 13197 assert(region.extents.y2 + dy <= pixmap->drawable.height); 13198 13199 nbox = region_num_rects(®ion); 13200 box = region_rects(®ion); 13201 DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox)); 13202 while (nbox--) { 13203 int height = box->y2 - box->y1; 13204 int dst_y = box->y1; 13205 int tile_y = (box->y1 - drawable->y - origin->y) % tile_height; 13206 if (tile_y < 0) 13207 tile_y += tile_height; 13208 13209 while (height) { 13210 int width = box->x2 - box->x1; 13211 int dst_x = box->x1, tile_x; 13212 int h = tile_height - tile_y; 13213 if (h > height) 13214 h = height; 13215 height -= h; 13216 13217 tile_x = (box->x1 - drawable->x - origin->x) % tile_width; 13218 if (tile_x < 0) 13219 tile_x += tile_width; 13220 13221 while (width > 0) { 13222 int w = tile_width - tile_x; 13223 if (w > width) 13224 w = width; 13225 width -= w; 13226 13227 copy.blt(sna, ©, 13228 tile_x, tile_y, 13229 w, h, 13230 dst_x + dx, dst_y + dy); 13231 if (damage) { 13232 BoxRec b; 13233 13234 b.x1 = dst_x + dx; 13235 b.y1 = dst_y + dy; 13236 b.x2 = b.x1 + w; 13237 b.y2 = b.y1 + h; 13238 13239 assert_pixmap_contains_box(pixmap, &b); 13240 sna_damage_add_box(damage, &b); 13241 } 13242 13243 dst_x += w; 13244 tile_x = 0; 13245 } 13246 dst_y += h; 13247 tile_y = 0; 13248 } 13249 box++; 13250 } 13251 13252 RegionUninit(®ion); 13253 } 13254 } 13255 13256 RegionUninit(&clip); 13257 } 13258done: 13259 copy.done(sna, ©); 13260 assert_pixmap_damage(pixmap); 13261 kgem_bo_destroy(&sna->kgem, tile_bo); 13262 return true; 13263} 13264 13265static bool 13266sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, 13267 struct kgem_bo *bo, 13268 struct sna_damage **damage, 13269 GCPtr gc, int n, xRectangle *r, 13270 const BoxRec *extents, unsigned clipped) 13271{ 13272 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13273 struct sna *sna = to_sna_from_pixmap(pixmap); 13274 uint32_t pat[2] = {0, 0}, br00, br13; 13275 int16_t dx, dy; 13276 uint32_t *b; 13277 13278 if (NO_STIPPLE_8x8) 13279 return false; 13280 13281 DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n", 13282 __FUNCTION__, gc->alu, 13283 extents->x1, extents->y1, 13284 extents->x2, extents->y2, 13285 gc->patOrg.x, gc->patOrg.y)); 13286 13287 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13288 { 13289 int px, py; 13290 13291 px = (0 - gc->patOrg.x - drawable->x - dx) % 8; 13292 if (px < 0) 13293 px += 8; 13294 13295 py = (0 - gc->patOrg.y - drawable->y - dy) % 8; 13296 if (py < 0) 13297 py += 8; 13298 DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py)); 13299 13300 br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20; 13301 br13 = bo->pitch; 13302 if (sna->kgem.gen >= 040 && bo->tiling) { 13303 br00 |= BLT_DST_TILED; 13304 br13 >>= 2; 13305 } 13306 br13 |= (gc->fillStyle == FillStippled) << 28; 13307 br13 |= blt_depth(drawable->depth) << 24; 13308 br13 |= fill_ROP[gc->alu] << 16; 13309 } 13310 13311 assert(gc->stipple->devKind); 13312 { 13313 uint8_t *dst = (uint8_t *)pat; 13314 const uint8_t *src = gc->stipple->devPrivate.ptr; 13315 int stride = gc->stipple->devKind; 13316 int j = gc->stipple->drawable.height; 13317 do { 13318 *dst++ = byte_reverse(*src); 13319 src += stride; 13320 } while (--j); 13321 } 13322 13323 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13324 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13325 if (!kgem_check_batch(&sna->kgem, 10 + 2*3) || 13326 !kgem_check_bo_fenced(&sna->kgem, bo) || 13327 !kgem_check_reloc(&sna->kgem, 1)) { 13328 kgem_submit(&sna->kgem); 13329 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13330 return false; 13331 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13332 } 13333 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13334 13335 if (!clipped) { 13336 dx += drawable->x; 13337 dy += drawable->y; 13338 13339 sna_damage_add_rectangles(damage, r, n, dx, dy); 13340 if (n == 1) { 13341 DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n", 13342 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13343 13344 assert(sna->kgem.mode == KGEM_BLT); 13345 b = sna->kgem.batch + sna->kgem.nbatch; 13346 if (sna->kgem.gen >= 0100) { 13347 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8; 13348 b[1] = br13; 13349 b[2] = (r->y + dy) << 16 | (r->x + dx); 13350 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13351 *(uint64_t *)(b+4) = 13352 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13353 I915_GEM_DOMAIN_RENDER << 16 | 13354 I915_GEM_DOMAIN_RENDER | 13355 KGEM_RELOC_FENCED, 13356 0); 13357 b[6] = gc->bgPixel; 13358 b[7] = gc->fgPixel; 13359 b[8] = pat[0]; 13360 b[9] = pat[1]; 13361 sna->kgem.nbatch += 10; 13362 } else { 13363 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7; 13364 b[1] = br13; 13365 b[2] = (r->y + dy) << 16 | (r->x + dx); 13366 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13367 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13368 I915_GEM_DOMAIN_RENDER << 16 | 13369 I915_GEM_DOMAIN_RENDER | 13370 KGEM_RELOC_FENCED, 13371 0); 13372 b[5] = gc->bgPixel; 13373 b[6] = gc->fgPixel; 13374 b[7] = pat[0]; 13375 b[8] = pat[1]; 13376 sna->kgem.nbatch += 9; 13377 } 13378 } else do { 13379 int n_this_time, rem; 13380 13381 assert(sna->kgem.mode == KGEM_BLT); 13382 b = sna->kgem.batch + sna->kgem.nbatch; 13383 if (sna->kgem.gen >= 0100) { 13384 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13385 b[1] = br13; 13386 b[2] = 0; 13387 b[3] = 0; 13388 *(uint64_t *)(b+4) = 13389 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13390 I915_GEM_DOMAIN_RENDER << 16 | 13391 I915_GEM_DOMAIN_RENDER | 13392 KGEM_RELOC_FENCED, 13393 0); 13394 b[6] = gc->bgPixel; 13395 b[7] = gc->fgPixel; 13396 b[8] = pat[0]; 13397 b[9] = pat[1]; 13398 sna->kgem.nbatch += 10; 13399 } else { 13400 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13401 b[1] = br13; 13402 b[2] = 0; 13403 b[3] = 0; 13404 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13405 I915_GEM_DOMAIN_RENDER << 16 | 13406 I915_GEM_DOMAIN_RENDER | 13407 KGEM_RELOC_FENCED, 13408 0); 13409 b[5] = gc->bgPixel; 13410 b[6] = gc->fgPixel; 13411 b[7] = pat[0]; 13412 b[8] = pat[1]; 13413 sna->kgem.nbatch += 9; 13414 } 13415 13416 n_this_time = n; 13417 rem = kgem_batch_space(&sna->kgem); 13418 if (3*n_this_time > rem) 13419 n_this_time = rem / 3; 13420 assert(n_this_time); 13421 n -= n_this_time; 13422 13423 assert(sna->kgem.mode == KGEM_BLT); 13424 b = sna->kgem.batch + sna->kgem.nbatch; 13425 sna->kgem.nbatch += 3 * n_this_time; 13426 do { 13427 DBG(("%s: rect (%d, %d)x(%d, %d)\n", 13428 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13429 assert(r->x + dx >= 0); 13430 assert(r->y + dy >= 0); 13431 assert(r->x + dx + r->width <= pixmap->drawable.width); 13432 assert(r->y + dy + r->height <= pixmap->drawable.height); 13433 13434 b[0] = br00; 13435 b[1] = (r->y + dy) << 16 | (r->x + dx); 13436 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13437 13438 b += 3; r++; 13439 } while(--n_this_time); 13440 13441 if (!n) 13442 break; 13443 13444 _kgem_submit(&sna->kgem); 13445 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13446 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13447 } while (1); 13448 } else { 13449 RegionRec clip; 13450 13451 region_set(&clip, extents); 13452 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13453 return true; 13454 13455 assert(sna->kgem.mode == KGEM_BLT); 13456 b = sna->kgem.batch + sna->kgem.nbatch; 13457 if (sna->kgem.gen >= 0100) { 13458 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13459 b[1] = br13; 13460 b[2] = 0; 13461 b[3] = 0; 13462 *(uint64_t *)(b+4) = 13463 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13464 I915_GEM_DOMAIN_RENDER << 16 | 13465 I915_GEM_DOMAIN_RENDER | 13466 KGEM_RELOC_FENCED, 13467 0); 13468 b[6] = gc->bgPixel; 13469 b[7] = gc->fgPixel; 13470 b[8] = pat[0]; 13471 b[9] = pat[1]; 13472 sna->kgem.nbatch += 10; 13473 } else { 13474 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13475 b[1] = br13; 13476 b[2] = 0; 13477 b[3] = 0; 13478 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13479 I915_GEM_DOMAIN_RENDER << 16 | 13480 I915_GEM_DOMAIN_RENDER | 13481 KGEM_RELOC_FENCED, 13482 0); 13483 b[5] = gc->bgPixel; 13484 b[6] = gc->fgPixel; 13485 b[7] = pat[0]; 13486 b[8] = pat[1]; 13487 sna->kgem.nbatch += 9; 13488 } 13489 13490 if (clip.data == NULL) { 13491 do { 13492 BoxRec box; 13493 13494 box.x1 = r->x + drawable->x; 13495 box.y1 = r->y + drawable->y; 13496 box.x2 = bound(box.x1, r->width); 13497 box.y2 = bound(box.y1, r->height); 13498 r++; 13499 13500 if (box_intersect(&box, &clip.extents)) { 13501 if (!kgem_check_batch(&sna->kgem, 3)) { 13502 _kgem_submit(&sna->kgem); 13503 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13504 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13505 13506 assert(sna->kgem.mode == KGEM_BLT); 13507 b = sna->kgem.batch + sna->kgem.nbatch; 13508 if (sna->kgem.gen >= 0100) { 13509 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13510 b[1] = br13; 13511 b[2] = 0; 13512 b[3] = 0; 13513 *(uint64_t *)(b+4) = 13514 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13515 I915_GEM_DOMAIN_RENDER << 16 | 13516 I915_GEM_DOMAIN_RENDER | 13517 KGEM_RELOC_FENCED, 13518 0); 13519 b[6] = gc->bgPixel; 13520 b[7] = gc->fgPixel; 13521 b[8] = pat[0]; 13522 b[9] = pat[1]; 13523 sna->kgem.nbatch += 10; 13524 } else { 13525 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13526 b[1] = br13; 13527 b[2] = 0; 13528 b[3] = 0; 13529 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13530 I915_GEM_DOMAIN_RENDER << 16 | 13531 I915_GEM_DOMAIN_RENDER | 13532 KGEM_RELOC_FENCED, 13533 0); 13534 b[5] = gc->bgPixel; 13535 b[6] = gc->fgPixel; 13536 b[7] = pat[0]; 13537 b[8] = pat[1]; 13538 sna->kgem.nbatch += 9; 13539 } 13540 } 13541 13542 assert(sna->kgem.mode == KGEM_BLT); 13543 b = sna->kgem.batch + sna->kgem.nbatch; 13544 sna->kgem.nbatch += 3; 13545 b[0] = br00; 13546 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 13547 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 13548 } 13549 } while (--n); 13550 } else { 13551 const BoxRec * const clip_start = RegionBoxptr(&clip); 13552 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13553 const BoxRec *c; 13554 13555 do { 13556 BoxRec box; 13557 13558 box.x1 = r->x + drawable->x; 13559 box.y1 = r->y + drawable->y; 13560 box.x2 = bound(box.x1, r->width); 13561 box.y2 = bound(box.y1, r->height); 13562 r++; 13563 13564 c = find_clip_box_for_y(clip_start, 13565 clip_end, 13566 box.y1); 13567 while (c != clip_end) { 13568 BoxRec bb; 13569 if (box.y2 <= c->y1) 13570 break; 13571 13572 bb = box; 13573 if (box_intersect(&bb, c++)) { 13574 if (!kgem_check_batch(&sna->kgem, 3)) { 13575 _kgem_submit(&sna->kgem); 13576 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13577 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13578 13579 assert(sna->kgem.mode == KGEM_BLT); 13580 b = sna->kgem.batch + sna->kgem.nbatch; 13581 if (sna->kgem.gen >= 0100) { 13582 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13583 b[1] = br13; 13584 b[2] = 0; 13585 b[3] = 0; 13586 *(uint64_t *)(b+4) = 13587 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13588 I915_GEM_DOMAIN_RENDER << 16 | 13589 I915_GEM_DOMAIN_RENDER | 13590 KGEM_RELOC_FENCED, 13591 0); 13592 b[6] = gc->bgPixel; 13593 b[7] = gc->fgPixel; 13594 b[8] = pat[0]; 13595 b[9] = pat[1]; 13596 sna->kgem.nbatch += 10; 13597 } else { 13598 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13599 b[1] = br13; 13600 b[2] = 0; 13601 b[3] = 0; 13602 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13603 I915_GEM_DOMAIN_RENDER << 16 | 13604 I915_GEM_DOMAIN_RENDER | 13605 KGEM_RELOC_FENCED, 13606 0); 13607 b[5] = gc->bgPixel; 13608 b[6] = gc->fgPixel; 13609 b[7] = pat[0]; 13610 b[8] = pat[1]; 13611 sna->kgem.nbatch += 9; 13612 } 13613 } 13614 13615 assert(sna->kgem.mode == KGEM_BLT); 13616 b = sna->kgem.batch + sna->kgem.nbatch; 13617 sna->kgem.nbatch += 3; 13618 b[0] = br00; 13619 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 13620 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 13621 } 13622 } 13623 } while (--n); 13624 } 13625 } 13626 13627 assert_pixmap_damage(pixmap); 13628 blt_done(sna); 13629 return true; 13630} 13631 13632static bool 13633sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable, 13634 struct kgem_bo *bo, 13635 struct sna_damage **damage, 13636 GCPtr gc, int n, xRectangle *r, 13637 const BoxRec *extents, unsigned clipped) 13638{ 13639 PixmapPtr scratch, stipple; 13640 uint8_t bytes[8], *dst = bytes; 13641 const uint8_t *src, *end; 13642 int j, stride; 13643 bool ret; 13644 13645 DBG(("%s: expanding %dx%d stipple to 8x8\n", 13646 __FUNCTION__, 13647 gc->stipple->drawable.width, 13648 gc->stipple->drawable.height)); 13649 13650 scratch = GetScratchPixmapHeader(drawable->pScreen, 13651 8, 8, 1, 1, 1, bytes); 13652 if (scratch == NullPixmap) 13653 return false; 13654 13655 stipple = gc->stipple; 13656 gc->stipple = scratch; 13657 13658 assert(stipple->devKind); 13659 stride = stipple->devKind; 13660 src = stipple->devPrivate.ptr; 13661 end = src + stride * stipple->drawable.height; 13662 for(j = 0; j < 8; j++) { 13663 switch (stipple->drawable.width) { 13664 case 1: *dst = (*src & 1) * 0xff; break; 13665 case 2: *dst = (*src & 3) * 0x55; break; 13666 case 4: *dst = (*src & 15) * 0x11; break; 13667 case 8: *dst = *src; break; 13668 default: assert(0); break; 13669 } 13670 dst++; 13671 src += stride; 13672 if (src == end) 13673 src = stipple->devPrivate.ptr; 13674 } 13675 13676 ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 13677 gc, n, r, extents, clipped); 13678 13679 gc->stipple = stipple; 13680 FreeScratchPixmapHeader(scratch); 13681 13682 return ret; 13683} 13684 13685static bool 13686sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, 13687 struct kgem_bo *bo, 13688 struct sna_damage **damage, 13689 GCPtr gc, int n, xRectangle *r, 13690 const BoxRec *extents, unsigned clipped) 13691{ 13692 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13693 struct sna *sna = to_sna_from_pixmap(pixmap); 13694 PixmapPtr stipple = gc->stipple; 13695 const DDXPointRec *origin = &gc->patOrg; 13696 int16_t dx, dy; 13697 uint32_t br00, br13; 13698 13699 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__, 13700 extents->x1, extents->y1, 13701 extents->x2, extents->y2, 13702 origin->x, origin->y, 13703 clipped)); 13704 13705 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13706 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13707 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13708 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13709 13710 br00 = 3 << 20; 13711 br13 = bo->pitch; 13712 if (sna->kgem.gen >= 040 && bo->tiling) { 13713 br00 |= BLT_DST_TILED; 13714 br13 >>= 2; 13715 } 13716 br13 |= (gc->fillStyle == FillStippled) << 29; 13717 br13 |= blt_depth(drawable->depth) << 24; 13718 br13 |= copy_ROP[gc->alu] << 16; 13719 13720 if (!clipped) { 13721 dx += drawable->x; 13722 dy += drawable->y; 13723 13724 sna_damage_add_rectangles(damage, r, n, dx, dy); 13725 do { 13726 int bx1 = (r->x - origin->x) & ~7; 13727 int bx2 = (r->x + r->width - origin->x + 7) & ~7; 13728 int bw = (bx2 - bx1)/8; 13729 int bh = r->height; 13730 int bstride = ALIGN(bw, 2); 13731 int src_stride; 13732 uint8_t *dst, *src; 13733 uint32_t *b; 13734 13735 DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d, src_stride=%d]\n", 13736 __FUNCTION__, 13737 r->x, r->y, r->width, r->height, 13738 bx1, bx2, bstride*bh)); 13739 13740 src_stride = bstride*bh; 13741 assert(src_stride > 0); 13742 if (src_stride <= 128) { 13743 src_stride = ALIGN(src_stride, 8) / 4; 13744 assert(src_stride <= 32); 13745 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13746 !kgem_check_bo_fenced(&sna->kgem, bo) || 13747 !kgem_check_reloc(&sna->kgem, 1)) { 13748 kgem_submit(&sna->kgem); 13749 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13750 return false; 13751 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13752 } 13753 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13754 13755 assert(sna->kgem.mode == KGEM_BLT); 13756 b = sna->kgem.batch + sna->kgem.nbatch; 13757 if (sna->kgem.gen >= 0100) { 13758 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13759 b[0] |= ((r->x - origin->x) & 7) << 17; 13760 b[1] = br13; 13761 b[2] = (r->y + dy) << 16 | (r->x + dx); 13762 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13763 *(uint64_t *)(b+4) = 13764 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13765 I915_GEM_DOMAIN_RENDER << 16 | 13766 I915_GEM_DOMAIN_RENDER | 13767 KGEM_RELOC_FENCED, 13768 0); 13769 b[6] = gc->bgPixel; 13770 b[7] = gc->fgPixel; 13771 13772 dst = (uint8_t *)&b[8]; 13773 sna->kgem.nbatch += 8 + src_stride; 13774 } else { 13775 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13776 b[0] |= ((r->x - origin->x) & 7) << 17; 13777 b[1] = br13; 13778 b[2] = (r->y + dy) << 16 | (r->x + dx); 13779 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13780 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13781 I915_GEM_DOMAIN_RENDER << 16 | 13782 I915_GEM_DOMAIN_RENDER | 13783 KGEM_RELOC_FENCED, 13784 0); 13785 b[5] = gc->bgPixel; 13786 b[6] = gc->fgPixel; 13787 13788 dst = (uint8_t *)&b[7]; 13789 sna->kgem.nbatch += 7 + src_stride; 13790 } 13791 assert(stipple->devKind); 13792 src_stride = stipple->devKind; 13793 src = stipple->devPrivate.ptr; 13794 src += (r->y - origin->y) * src_stride + bx1/8; 13795 src_stride -= bstride; 13796 do { 13797 int i = bstride; 13798 do { 13799 *dst++ = byte_reverse(*src++); 13800 *dst++ = byte_reverse(*src++); 13801 i -= 2; 13802 } while (i); 13803 src += src_stride; 13804 } while (--bh); 13805 } else { 13806 struct kgem_bo *upload; 13807 void *ptr; 13808 13809 if (!kgem_check_batch(&sna->kgem, 10) || 13810 !kgem_check_bo_fenced(&sna->kgem, bo) || 13811 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13812 kgem_submit(&sna->kgem); 13813 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13814 return false; 13815 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13816 } 13817 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13818 13819 upload = kgem_create_buffer(&sna->kgem, 13820 bstride*bh, 13821 KGEM_BUFFER_WRITE_INPLACE, 13822 &ptr); 13823 if (!upload) 13824 break; 13825 13826 if (sigtrap_get() == 0) { 13827 dst = ptr; 13828 assert(stipple->devKind); 13829 src_stride = stipple->devKind; 13830 src = stipple->devPrivate.ptr; 13831 src += (r->y - origin->y) * src_stride + bx1/8; 13832 src_stride -= bstride; 13833 do { 13834 int i = bstride; 13835 do { 13836 *dst++ = byte_reverse(*src++); 13837 *dst++ = byte_reverse(*src++); 13838 i -= 2; 13839 } while (i); 13840 src += src_stride; 13841 } while (--bh); 13842 13843 assert(sna->kgem.mode == KGEM_BLT); 13844 b = sna->kgem.batch + sna->kgem.nbatch; 13845 if (sna->kgem.gen >= 0100) { 13846 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13847 b[0] |= ((r->x - origin->x) & 7) << 17; 13848 b[1] = br13; 13849 b[2] = (r->y + dy) << 16 | (r->x + dx); 13850 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13851 *(uint64_t *)(b+4) = 13852 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13853 I915_GEM_DOMAIN_RENDER << 16 | 13854 I915_GEM_DOMAIN_RENDER | 13855 KGEM_RELOC_FENCED, 13856 0); 13857 *(uint64_t *)(b+6) = 13858 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13859 I915_GEM_DOMAIN_RENDER << 16 | 13860 KGEM_RELOC_FENCED, 13861 0); 13862 b[8] = gc->bgPixel; 13863 b[9] = gc->fgPixel; 13864 sna->kgem.nbatch += 10; 13865 } else { 13866 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13867 b[0] |= ((r->x - origin->x) & 7) << 17; 13868 b[1] = br13; 13869 b[2] = (r->y + dy) << 16 | (r->x + dx); 13870 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13871 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13872 I915_GEM_DOMAIN_RENDER << 16 | 13873 I915_GEM_DOMAIN_RENDER | 13874 KGEM_RELOC_FENCED, 13875 0); 13876 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13877 I915_GEM_DOMAIN_RENDER << 16 | 13878 KGEM_RELOC_FENCED, 13879 0); 13880 b[6] = gc->bgPixel; 13881 b[7] = gc->fgPixel; 13882 13883 sna->kgem.nbatch += 8; 13884 } 13885 sigtrap_put(); 13886 } 13887 13888 kgem_bo_destroy(&sna->kgem, upload); 13889 } 13890 13891 r++; 13892 } while (--n); 13893 } else { 13894 RegionRec clip; 13895 DDXPointRec pat; 13896 13897 region_set(&clip, extents); 13898 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13899 return true; 13900 13901 DBG(("%s: clip.extents=[(%d, %d), (%d, %d)] region?=%d\n", 13902 __FUNCTION__, 13903 clip.extents.x1, clip.extents.y1, 13904 clip.extents.x2, clip.extents.y2, 13905 clip.data ? clip.data->numRects : 0)); 13906 13907 pat.x = origin->x + drawable->x; 13908 pat.y = origin->y + drawable->y; 13909 13910 if (clip.data == NULL) { 13911 do { 13912 BoxRec box; 13913 int bx1, bx2, bw, bh, bstride; 13914 int src_stride; 13915 uint8_t *dst, *src; 13916 uint32_t *b; 13917 struct kgem_bo *upload; 13918 void *ptr; 13919 13920 box.x1 = r->x + drawable->x; 13921 box.x2 = bound(box.x1, r->width); 13922 box.y1 = r->y + drawable->y; 13923 box.y2 = bound(box.y1, r->height); 13924 r++; 13925 13926 if (!box_intersect(&box, &clip.extents)) 13927 continue; 13928 13929 bx1 = (box.x1 - pat.x) & ~7; 13930 bx2 = (box.x2 - pat.x + 7) & ~7; 13931 bw = (bx2 - bx1)/8; 13932 bh = box.y2 - box.y1; 13933 bstride = ALIGN(bw, 2); 13934 13935 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d, len=%d\n", 13936 __FUNCTION__, 13937 r->x, r->y, r->width, r->height, 13938 box.x1, box.y1, box.x2, box.y2, 13939 bx1, bx2, bw, bstride, bstride*bh)); 13940 13941 src_stride = bstride*bh; 13942 assert(src_stride > 0); 13943 if (src_stride <= 128) { 13944 src_stride = ALIGN(src_stride, 8) / 4; 13945 assert(src_stride <= 32); 13946 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13947 !kgem_check_bo_fenced(&sna->kgem, bo) || 13948 !kgem_check_reloc(&sna->kgem, 1)) { 13949 kgem_submit(&sna->kgem); 13950 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13951 return false; 13952 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13953 } 13954 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13955 13956 assert(sna->kgem.mode == KGEM_BLT); 13957 b = sna->kgem.batch + sna->kgem.nbatch; 13958 if (sna->kgem.gen >= 0100) { 13959 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13960 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13961 b[1] = br13; 13962 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13963 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13964 *(uint64_t *)(b+4) = 13965 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13966 I915_GEM_DOMAIN_RENDER << 16 | 13967 I915_GEM_DOMAIN_RENDER | 13968 KGEM_RELOC_FENCED, 13969 0); 13970 b[6] = gc->bgPixel; 13971 b[7] = gc->fgPixel; 13972 13973 dst = (uint8_t *)&b[8]; 13974 sna->kgem.nbatch += 8 + src_stride; 13975 } else { 13976 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13977 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13978 b[1] = br13; 13979 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13980 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13981 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13982 I915_GEM_DOMAIN_RENDER << 16 | 13983 I915_GEM_DOMAIN_RENDER | 13984 KGEM_RELOC_FENCED, 13985 0); 13986 b[5] = gc->bgPixel; 13987 b[6] = gc->fgPixel; 13988 13989 dst = (uint8_t *)&b[7]; 13990 sna->kgem.nbatch += 7 + src_stride; 13991 } 13992 13993 assert(stipple->devKind); 13994 src_stride = stipple->devKind; 13995 src = stipple->devPrivate.ptr; 13996 src += (box.y1 - pat.y) * src_stride + bx1/8; 13997 src_stride -= bstride; 13998 do { 13999 int i = bstride; 14000 do { 14001 *dst++ = byte_reverse(*src++); 14002 *dst++ = byte_reverse(*src++); 14003 i -= 2; 14004 } while (i); 14005 src += src_stride; 14006 } while (--bh); 14007 } else { 14008 if (!kgem_check_batch(&sna->kgem, 10) || 14009 !kgem_check_bo_fenced(&sna->kgem, bo) || 14010 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 14011 kgem_submit(&sna->kgem); 14012 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14013 return false; 14014 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14015 } 14016 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14017 14018 upload = kgem_create_buffer(&sna->kgem, 14019 bstride*bh, 14020 KGEM_BUFFER_WRITE_INPLACE, 14021 &ptr); 14022 if (!upload) 14023 break; 14024 14025 if (sigtrap_get() == 0) { 14026 dst = ptr; 14027 assert(stipple->devKind); 14028 src_stride = stipple->devKind; 14029 src = stipple->devPrivate.ptr; 14030 src += (box.y1 - pat.y) * src_stride + bx1/8; 14031 src_stride -= bstride; 14032 do { 14033 int i = bstride; 14034 do { 14035 *dst++ = byte_reverse(*src++); 14036 *dst++ = byte_reverse(*src++); 14037 i -= 2; 14038 } while (i); 14039 src += src_stride; 14040 } while (--bh); 14041 14042 assert(sna->kgem.mode == KGEM_BLT); 14043 b = sna->kgem.batch + sna->kgem.nbatch; 14044 if (sna->kgem.gen >= 0100) { 14045 b[0] = XY_MONO_SRC_COPY | br00 | 8; 14046 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14047 b[1] = br13; 14048 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14049 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14050 *(uint64_t *)(b+4) = 14051 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14052 I915_GEM_DOMAIN_RENDER << 16 | 14053 I915_GEM_DOMAIN_RENDER | 14054 KGEM_RELOC_FENCED, 14055 0); 14056 *(uint64_t *)(b+6) = 14057 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14058 I915_GEM_DOMAIN_RENDER << 16 | 14059 KGEM_RELOC_FENCED, 14060 0); 14061 b[8] = gc->bgPixel; 14062 b[9] = gc->fgPixel; 14063 sna->kgem.nbatch += 10; 14064 } else { 14065 b[0] = XY_MONO_SRC_COPY | br00 | 6; 14066 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14067 b[1] = br13; 14068 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14069 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14070 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14071 I915_GEM_DOMAIN_RENDER << 16 | 14072 I915_GEM_DOMAIN_RENDER | 14073 KGEM_RELOC_FENCED, 14074 0); 14075 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14076 I915_GEM_DOMAIN_RENDER << 16 | 14077 KGEM_RELOC_FENCED, 14078 0); 14079 b[6] = gc->bgPixel; 14080 b[7] = gc->fgPixel; 14081 14082 sna->kgem.nbatch += 8; 14083 } 14084 sigtrap_put(); 14085 } 14086 kgem_bo_destroy(&sna->kgem, upload); 14087 } 14088 } while (--n); 14089 } else { 14090 const BoxRec * const clip_start = RegionBoxptr(&clip); 14091 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14092 const BoxRec *c; 14093 14094 do { 14095 BoxRec unclipped; 14096 int bx1, bx2, bw, bh, bstride; 14097 int src_stride; 14098 uint8_t *dst, *src; 14099 uint32_t *b; 14100 struct kgem_bo *upload; 14101 void *ptr; 14102 14103 unclipped.x1 = r->x + drawable->x; 14104 unclipped.x2 = bound(unclipped.x1, r->width); 14105 unclipped.y1 = r->y + drawable->y; 14106 unclipped.y2 = bound(unclipped.y1, r->height); 14107 r++; 14108 14109 c = find_clip_box_for_y(clip_start, 14110 clip_end, 14111 unclipped.y1); 14112 while (c != clip_end) { 14113 BoxRec box; 14114 14115 if (unclipped.y2 <= c->y1) 14116 break; 14117 14118 box = unclipped; 14119 if (!box_intersect(&box, c++)) 14120 continue; 14121 14122 bx1 = (box.x1 - pat.x) & ~7; 14123 bx2 = (box.x2 - pat.x + 7) & ~7; 14124 bw = (bx2 - bx1)/8; 14125 bh = box.y2 - box.y1; 14126 bstride = ALIGN(bw, 2); 14127 14128 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n", 14129 __FUNCTION__, 14130 r->x, r->y, r->width, r->height, 14131 box.x1, box.y1, box.x2, box.y2, 14132 bx1, bx2)); 14133 14134 src_stride = bstride*bh; 14135 assert(src_stride > 0); 14136 if (src_stride <= 128) { 14137 src_stride = ALIGN(src_stride, 8) / 4; 14138 assert(src_stride <= 32); 14139 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 14140 !kgem_check_bo_fenced(&sna->kgem, bo) || 14141 !kgem_check_reloc(&sna->kgem, 1)) { 14142 kgem_submit(&sna->kgem); 14143 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14144 return false; 14145 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14146 } 14147 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14148 14149 assert(sna->kgem.mode == KGEM_BLT); 14150 b = sna->kgem.batch + sna->kgem.nbatch; 14151 if (sna->kgem.gen >= 0100) { 14152 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 14153 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14154 b[1] = br13; 14155 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14156 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14157 *(uint64_t *)(b+4) = 14158 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14159 I915_GEM_DOMAIN_RENDER << 16 | 14160 I915_GEM_DOMAIN_RENDER | 14161 KGEM_RELOC_FENCED, 14162 0); 14163 b[6] = gc->bgPixel; 14164 b[7] = gc->fgPixel; 14165 14166 dst = (uint8_t *)&b[8]; 14167 sna->kgem.nbatch += 8 + src_stride; 14168 } else { 14169 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 14170 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14171 b[1] = br13; 14172 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14173 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14174 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14175 I915_GEM_DOMAIN_RENDER << 16 | 14176 I915_GEM_DOMAIN_RENDER | 14177 KGEM_RELOC_FENCED, 14178 0); 14179 b[5] = gc->bgPixel; 14180 b[6] = gc->fgPixel; 14181 14182 dst = (uint8_t *)&b[7]; 14183 sna->kgem.nbatch += 7 + src_stride; 14184 } 14185 assert(stipple->devKind); 14186 src_stride = stipple->devKind; 14187 src = stipple->devPrivate.ptr; 14188 src += (box.y1 - pat.y) * src_stride + bx1/8; 14189 src_stride -= bstride; 14190 do { 14191 int i = bstride; 14192 do { 14193 *dst++ = byte_reverse(*src++); 14194 *dst++ = byte_reverse(*src++); 14195 i -= 2; 14196 } while (i); 14197 src += src_stride; 14198 } while (--bh); 14199 } else { 14200 if (!kgem_check_batch(&sna->kgem, 10) || 14201 !kgem_check_bo_fenced(&sna->kgem, bo) || 14202 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 14203 kgem_submit(&sna->kgem); 14204 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14205 return false; 14206 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14207 } 14208 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14209 14210 upload = kgem_create_buffer(&sna->kgem, 14211 bstride*bh, 14212 KGEM_BUFFER_WRITE_INPLACE, 14213 &ptr); 14214 if (!upload) 14215 break; 14216 14217 if (sigtrap_get() == 0) { 14218 dst = ptr; 14219 assert(stipple->devKind); 14220 src_stride = stipple->devKind; 14221 src = stipple->devPrivate.ptr; 14222 src += (box.y1 - pat.y) * src_stride + bx1/8; 14223 src_stride -= bstride; 14224 do { 14225 int i = bstride; 14226 do { 14227 *dst++ = byte_reverse(*src++); 14228 *dst++ = byte_reverse(*src++); 14229 i -= 2; 14230 } while (i); 14231 src += src_stride; 14232 } while (--bh); 14233 14234 assert(sna->kgem.mode == KGEM_BLT); 14235 b = sna->kgem.batch + sna->kgem.nbatch; 14236 if (sna->kgem.gen >= 0100) { 14237 b[0] = XY_MONO_SRC_COPY | br00 | 8; 14238 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14239 b[1] = br13; 14240 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14241 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14242 *(uint64_t *)(b+4) = 14243 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14244 I915_GEM_DOMAIN_RENDER << 16 | 14245 I915_GEM_DOMAIN_RENDER | 14246 KGEM_RELOC_FENCED, 14247 0); 14248 *(uint64_t *)(b+6) = 14249 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14250 I915_GEM_DOMAIN_RENDER << 16 | 14251 KGEM_RELOC_FENCED, 14252 0); 14253 b[8] = gc->bgPixel; 14254 b[9] = gc->fgPixel; 14255 sna->kgem.nbatch += 10; 14256 } else { 14257 b[0] = XY_MONO_SRC_COPY | br00 | 6; 14258 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14259 b[1] = br13; 14260 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14261 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14262 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14263 I915_GEM_DOMAIN_RENDER << 16 | 14264 I915_GEM_DOMAIN_RENDER | 14265 KGEM_RELOC_FENCED, 14266 0); 14267 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14268 I915_GEM_DOMAIN_RENDER << 16 | 14269 KGEM_RELOC_FENCED, 14270 0); 14271 b[6] = gc->bgPixel; 14272 b[7] = gc->fgPixel; 14273 14274 sna->kgem.nbatch += 8; 14275 } 14276 sigtrap_put(); 14277 } 14278 kgem_bo_destroy(&sna->kgem, upload); 14279 } 14280 } 14281 } while (--n); 14282 14283 } 14284 } 14285 14286 blt_done(sna); 14287 return true; 14288} 14289 14290static void 14291sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, 14292 struct kgem_bo *bo, 14293 uint32_t br00, uint32_t br13, 14294 const GC *gc, 14295 const BoxRec *box, 14296 const DDXPointRec *origin) 14297{ 14298 int x1, x2, y1, y2; 14299 uint32_t *b; 14300 14301 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14302 int oy = (y1 - origin->y) % gc->stipple->drawable.height; 14303 if (oy < 0) 14304 oy += gc->stipple->drawable.height; 14305 14306 y2 = box->y2; 14307 if (y2 - y1 > gc->stipple->drawable.height - oy) 14308 y2 = y1 + gc->stipple->drawable.height - oy; 14309 14310 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14311 int bx1, bx2, bw, bh, len, ox; 14312 uint8_t *dst, *src; 14313 14314 x2 = box->x2; 14315 ox = (x1 - origin->x) % gc->stipple->drawable.width; 14316 if (ox < 0) 14317 ox += gc->stipple->drawable.width; 14318 bx1 = ox & ~7; 14319 bx2 = ox + (x2 - x1); 14320 if (bx2 > gc->stipple->drawable.width) { 14321 bx2 = gc->stipple->drawable.width; 14322 x2 = x1 + bx2-ox; 14323 } 14324 bw = (bx2 - bx1 + 7)/8; 14325 bw = ALIGN(bw, 2); 14326 bh = y2 - y1; 14327 14328 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n", 14329 __FUNCTION__, 14330 x1, y1, x2-x1, y2-y1, 14331 origin->x, origin->y, 14332 ox, oy, bx1, bx2, 14333 gc->stipple->drawable.width, 14334 gc->stipple->drawable.height)); 14335 14336 len = bw*bh; 14337 len = ALIGN(len, 8) / 4; 14338 assert(len > 0); 14339 assert(len <= 32); 14340 if (!kgem_check_batch(&sna->kgem, 8+len) || 14341 !kgem_check_bo_fenced(&sna->kgem, bo) || 14342 !kgem_check_reloc(&sna->kgem, 1)) { 14343 kgem_submit(&sna->kgem); 14344 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14345 return; /* XXX fallback? */ 14346 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14347 } 14348 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14349 14350 assert(sna->kgem.mode == KGEM_BLT); 14351 b = sna->kgem.batch + sna->kgem.nbatch; 14352 if (sna->kgem.gen >= 0100) { 14353 b[0] = br00 | (6 + len) | (ox & 7) << 17; 14354 b[1] = br13; 14355 b[2] = y1 << 16 | x1; 14356 b[3] = y2 << 16 | x2; 14357 *(uint64_t *)(b+4) = 14358 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14359 I915_GEM_DOMAIN_RENDER << 16 | 14360 I915_GEM_DOMAIN_RENDER | 14361 KGEM_RELOC_FENCED, 14362 0); 14363 b[6] = gc->bgPixel; 14364 b[7] = gc->fgPixel; 14365 dst = (uint8_t *)&b[8]; 14366 sna->kgem.nbatch += 8 + len; 14367 } else { 14368 b[0] = br00 | (5 + len) | (ox & 7) << 17; 14369 b[1] = br13; 14370 b[2] = y1 << 16 | x1; 14371 b[3] = y2 << 16 | x2; 14372 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14373 I915_GEM_DOMAIN_RENDER << 16 | 14374 I915_GEM_DOMAIN_RENDER | 14375 KGEM_RELOC_FENCED, 14376 0); 14377 b[5] = gc->bgPixel; 14378 b[6] = gc->fgPixel; 14379 dst = (uint8_t *)&b[7]; 14380 sna->kgem.nbatch += 7 + len; 14381 } 14382 14383 assert(gc->stipple->devKind); 14384 len = gc->stipple->devKind; 14385 src = gc->stipple->devPrivate.ptr; 14386 src += oy*len + ox/8; 14387 len -= bw; 14388 do { 14389 int i = bw; 14390 do { 14391 *dst++ = byte_reverse(*src++); 14392 *dst++ = byte_reverse(*src++); 14393 i -= 2; 14394 } while (i); 14395 src += len; 14396 } while (--bh); 14397 } 14398 } 14399} 14400 14401static void 14402sna_poly_fill_rect_stippled_n_box(struct sna *sna, 14403 struct kgem_bo *bo, 14404 struct kgem_bo **tile, 14405 uint32_t br00, uint32_t br13, 14406 const GC *gc, 14407 const BoxRec *box, 14408 const DDXPointRec *origin) 14409{ 14410 int x1, x2, y1, y2; 14411 int w = gc->stipple->drawable.width; 14412 int h = gc->stipple->drawable.height; 14413 int stride = gc->stipple->devKind; 14414 uint32_t *b; 14415 14416 assert(stride); 14417 if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) { 14418 br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20)); 14419 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14420 br00, br13, gc, 14421 box, origin); 14422 return; 14423 } 14424 14425 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14426 int row, oy = (y1 - origin->y) % gc->stipple->drawable.height; 14427 if (oy < 0) 14428 oy += h; 14429 14430 y2 = box->y2; 14431 if (y2 - y1 > h - oy) 14432 y2 = y1 + h - oy; 14433 14434 row = oy * stride; 14435 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14436 int bx1, bx2, bw, bh, len, ox; 14437 bool use_tile; 14438 14439 x2 = box->x2; 14440 ox = (x1 - origin->x) % w; 14441 if (ox < 0) 14442 ox += w; 14443 bx1 = ox & ~7; 14444 bx2 = ox + (x2 - x1); 14445 if (bx2 > w) { 14446 bx2 = w; 14447 x2 = x1 + bx2-ox; 14448 } 14449 14450 use_tile = y2-y1 == h && x2-x1 == w; 14451 14452 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n", 14453 __FUNCTION__, 14454 x1, y1, x2-x1, y2-y1, 14455 origin->x, origin->y, 14456 ox, oy, bx1, bx2, w, h, 14457 use_tile)); 14458 14459 bw = (bx2 - bx1 + 7)/8; 14460 bw = ALIGN(bw, 2); 14461 bh = y2 - y1; 14462 14463 len = bw*bh; 14464 len = ALIGN(len, 8) / 4; 14465 assert(len > 0); 14466 if (!kgem_check_batch(&sna->kgem, 8+len) || 14467 !kgem_check_bo_fenced(&sna->kgem, bo) || 14468 !kgem_check_reloc(&sna->kgem, 2)) { 14469 kgem_submit(&sna->kgem); 14470 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14471 return; /* XXX fallback? */ 14472 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14473 } 14474 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14475 14476 assert(sna->kgem.mode == KGEM_BLT); 14477 b = sna->kgem.batch + sna->kgem.nbatch; 14478 14479 if (!use_tile && len <= 32) { 14480 uint8_t *dst, *src; 14481 14482 if (sna->kgem.gen >= 0100) { 14483 b[0] = XY_MONO_SRC_COPY_IMM; 14484 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14485 b[0] |= (ox & 7) << 17; 14486 b[0] |= (6 + len); 14487 b[1] = br13; 14488 b[2] = y1 << 16 | x1; 14489 b[3] = y2 << 16 | x2; 14490 *(uint64_t *)(b+4) = 14491 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14492 I915_GEM_DOMAIN_RENDER << 16 | 14493 I915_GEM_DOMAIN_RENDER | 14494 KGEM_RELOC_FENCED, 14495 0); 14496 b[6] = gc->bgPixel; 14497 b[7] = gc->fgPixel; 14498 14499 dst = (uint8_t *)&b[8]; 14500 sna->kgem.nbatch += 8 + len; 14501 } else { 14502 b[0] = XY_MONO_SRC_COPY_IMM; 14503 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14504 b[0] |= (ox & 7) << 17; 14505 b[0] |= (5 + len); 14506 b[1] = br13; 14507 b[2] = y1 << 16 | x1; 14508 b[3] = y2 << 16 | x2; 14509 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14510 I915_GEM_DOMAIN_RENDER << 16 | 14511 I915_GEM_DOMAIN_RENDER | 14512 KGEM_RELOC_FENCED, 14513 0); 14514 b[5] = gc->bgPixel; 14515 b[6] = gc->fgPixel; 14516 14517 dst = (uint8_t *)&b[7]; 14518 sna->kgem.nbatch += 7 + len; 14519 } 14520 14521 assert(gc->stipple->devKind); 14522 len = gc->stipple->devKind; 14523 src = gc->stipple->devPrivate.ptr; 14524 src += oy*len + ox/8; 14525 len -= bw; 14526 do { 14527 int i = bw; 14528 do { 14529 *dst++ = byte_reverse(*src++); 14530 *dst++ = byte_reverse(*src++); 14531 i -= 2; 14532 } while (i); 14533 src += len; 14534 } while (--bh); 14535 } else { 14536 bool has_tile = use_tile && *tile; 14537 struct kgem_bo *upload; 14538 uint8_t *dst, *src; 14539 void *ptr; 14540 14541 if (has_tile) { 14542 upload = kgem_bo_reference(*tile); 14543 } else { 14544 upload = kgem_create_buffer(&sna->kgem, bw*bh, 14545 KGEM_BUFFER_WRITE_INPLACE, 14546 &ptr); 14547 if (!upload) 14548 return; 14549 } 14550 14551 assert(sna->kgem.mode == KGEM_BLT); 14552 b = sna->kgem.batch + sna->kgem.nbatch; 14553 if (sna->kgem.gen >= 0100) { 14554 b[0] = br00 | (ox & 7) << 17 | 8; 14555 b[1] = br13; 14556 b[2] = y1 << 16 | x1; 14557 b[3] = y2 << 16 | x2; 14558 *(uint64_t *)(b+4) = 14559 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14560 I915_GEM_DOMAIN_RENDER << 16 | 14561 I915_GEM_DOMAIN_RENDER | 14562 KGEM_RELOC_FENCED, 14563 0); 14564 *(uint64_t *)(b+6) = 14565 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14566 I915_GEM_DOMAIN_RENDER << 16 | 14567 KGEM_RELOC_FENCED, 14568 0); 14569 b[8] = gc->bgPixel; 14570 b[9] = gc->fgPixel; 14571 sna->kgem.nbatch += 10; 14572 } else { 14573 b[0] = br00 | (ox & 7) << 17 | 6; 14574 b[1] = br13; 14575 b[2] = y1 << 16 | x1; 14576 b[3] = y2 << 16 | x2; 14577 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14578 I915_GEM_DOMAIN_RENDER << 16 | 14579 I915_GEM_DOMAIN_RENDER | 14580 KGEM_RELOC_FENCED, 14581 0); 14582 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14583 I915_GEM_DOMAIN_RENDER << 16 | 14584 KGEM_RELOC_FENCED, 14585 0); 14586 b[6] = gc->bgPixel; 14587 b[7] = gc->fgPixel; 14588 sna->kgem.nbatch += 8; 14589 } 14590 14591 if (!has_tile) { 14592 dst = ptr; 14593 len = stride; 14594 src = gc->stipple->devPrivate.ptr; 14595 src += row + (ox >> 3); 14596 len -= bw; 14597 do { 14598 int i = bw; 14599 do { 14600 *dst++ = byte_reverse(*src++); 14601 *dst++ = byte_reverse(*src++); 14602 i -= 2; 14603 } while (i); 14604 src += len; 14605 } while (--bh); 14606 if (use_tile) 14607 *tile = kgem_bo_reference(upload); 14608 } 14609 14610 kgem_bo_destroy(&sna->kgem, upload); 14611 } 14612 } 14613 } 14614} 14615 14616static bool 14617sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, 14618 struct kgem_bo *bo, 14619 struct sna_damage **damage, 14620 GCPtr gc, int n, xRectangle *r, 14621 const BoxRec *extents, unsigned clipped) 14622{ 14623 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14624 struct sna *sna = to_sna_from_pixmap(pixmap); 14625 DDXPointRec origin = gc->patOrg; 14626 int16_t dx, dy; 14627 uint32_t br00, br13; 14628 14629 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14630 extents->x1, extents->y1, 14631 extents->x2, extents->y2, 14632 origin.x, origin.y, 14633 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14634 14635 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14636 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14637 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14638 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14639 14640 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; 14641 br13 = bo->pitch; 14642 if (sna->kgem.gen >= 040 && bo->tiling) { 14643 br00 |= BLT_DST_TILED; 14644 br13 >>= 2; 14645 } 14646 br13 |= (gc->fillStyle == FillStippled) << 29; 14647 br13 |= blt_depth(drawable->depth) << 24; 14648 br13 |= copy_ROP[gc->alu] << 16; 14649 14650 origin.x += dx + drawable->x; 14651 origin.y += dy + drawable->y; 14652 14653 if (!clipped) { 14654 dx += drawable->x; 14655 dy += drawable->y; 14656 14657 sna_damage_add_rectangles(damage, r, n, dx, dy); 14658 do { 14659 BoxRec box; 14660 14661 box.x1 = r->x + dx; 14662 box.y1 = r->y + dy; 14663 box.x2 = box.x1 + r->width; 14664 box.y2 = box.y1 + r->height; 14665 14666 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14667 br00, br13, gc, 14668 &box, &origin); 14669 r++; 14670 } while (--n); 14671 } else { 14672 RegionRec clip; 14673 14674 region_set(&clip, extents); 14675 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14676 DBG(("%s: all clipped\n", __FUNCTION__)); 14677 return true; 14678 } 14679 14680 if (clip.data == NULL) { 14681 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14682 __FUNCTION__, 14683 clip.extents.x1, clip.extents.y1, 14684 clip.extents.x2, clip.extents.y2)); 14685 do { 14686 BoxRec box; 14687 14688 box.x1 = r->x + drawable->x; 14689 box.x2 = bound(box.x1, r->width); 14690 box.y1 = r->y + drawable->y; 14691 box.y2 = bound(box.y1, r->height); 14692 r++; 14693 14694 DBG(("%s: box (%d, %d), (%d, %d)\n", 14695 __FUNCTION__, 14696 box.x1, box.y1, box.x2, box.y2)); 14697 if (!box_intersect(&box, &clip.extents)) 14698 continue; 14699 14700 box.x1 += dx; box.x2 += dx; 14701 box.y1 += dy; box.y2 += dy; 14702 14703 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14704 br00, br13, gc, 14705 &box, &origin); 14706 } while (--n); 14707 } else { 14708 const BoxRec * const clip_start = RegionBoxptr(&clip); 14709 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14710 const BoxRec *c; 14711 14712 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14713 clip_start->x1, clip_start->y1, 14714 clip_start->x2, clip_start->y2, 14715 clip_end->x1, clip_end->y1, 14716 clip_end->x2, clip_end->y2)); 14717 do { 14718 BoxRec unclipped; 14719 14720 unclipped.x1 = r->x + drawable->x; 14721 unclipped.x2 = bound(unclipped.x1, r->width); 14722 unclipped.y1 = r->y + drawable->y; 14723 unclipped.y2 = bound(unclipped.y1, r->height); 14724 r++; 14725 14726 c = find_clip_box_for_y(clip_start, 14727 clip_end, 14728 unclipped.y1); 14729 while (c != clip_end) { 14730 BoxRec box; 14731 14732 if (unclipped.y2 <= c->y1) 14733 break; 14734 14735 box = unclipped; 14736 if (!box_intersect(&box, c++)) 14737 continue; 14738 14739 box.x1 += dx; box.x2 += dx; 14740 box.y1 += dy; box.y2 += dy; 14741 14742 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14743 br00, br13, gc, 14744 &box, &origin); 14745 } 14746 } while (--n); 14747 } 14748 } 14749 14750 assert_pixmap_damage(pixmap); 14751 blt_done(sna); 14752 return true; 14753} 14754 14755static bool 14756sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, 14757 struct kgem_bo *bo, 14758 struct sna_damage **damage, 14759 GCPtr gc, int n, xRectangle *r, 14760 const BoxRec *extents, unsigned clipped) 14761{ 14762 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14763 struct sna *sna = to_sna_from_pixmap(pixmap); 14764 DDXPointRec origin = gc->patOrg; 14765 struct kgem_bo *tile = NULL; 14766 int16_t dx, dy; 14767 uint32_t br00, br13; 14768 14769 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14770 extents->x1, extents->y1, 14771 extents->x2, extents->y2, 14772 origin.x, origin.y, 14773 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14774 14775 if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0) 14776 return sna_poly_fill_rect_stippled_n_blt__imm(drawable, 14777 bo, damage, 14778 gc, n, r, 14779 extents, clipped); 14780 14781 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14782 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14783 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14784 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14785 14786 br00 = XY_MONO_SRC_COPY | 3 << 20; 14787 br13 = bo->pitch; 14788 if (sna->kgem.gen >= 040 && bo->tiling) { 14789 br00 |= BLT_DST_TILED; 14790 br13 >>= 2; 14791 } 14792 br13 |= (gc->fillStyle == FillStippled) << 29; 14793 br13 |= blt_depth(drawable->depth) << 24; 14794 br13 |= copy_ROP[gc->alu] << 16; 14795 14796 origin.x += dx + drawable->x; 14797 origin.y += dy + drawable->y; 14798 14799 if (!clipped) { 14800 dx += drawable->x; 14801 dy += drawable->y; 14802 14803 sna_damage_add_rectangles(damage, r, n, dx, dy); 14804 do { 14805 BoxRec box; 14806 14807 box.x1 = r->x + dx; 14808 box.y1 = r->y + dy; 14809 box.x2 = box.x1 + r->width; 14810 box.y2 = box.y1 + r->height; 14811 14812 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14813 br00, br13, gc, 14814 &box, &origin); 14815 r++; 14816 } while (--n); 14817 } else { 14818 RegionRec clip; 14819 14820 region_set(&clip, extents); 14821 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14822 DBG(("%s: all clipped\n", __FUNCTION__)); 14823 return true; 14824 } 14825 14826 if (clip.data == NULL) { 14827 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14828 __FUNCTION__, 14829 clip.extents.x1, clip.extents.y1, 14830 clip.extents.x2, clip.extents.y2)); 14831 do { 14832 BoxRec box; 14833 14834 box.x1 = r->x + drawable->x; 14835 box.x2 = bound(box.x1, r->width); 14836 box.y1 = r->y + drawable->y; 14837 box.y2 = bound(box.y1, r->height); 14838 r++; 14839 14840 DBG(("%s: box (%d, %d), (%d, %d)\n", 14841 __FUNCTION__, 14842 box.x1, box.y1, box.x2, box.y2)); 14843 if (!box_intersect(&box, &clip.extents)) 14844 continue; 14845 14846 box.x1 += dx; box.x2 += dx; 14847 box.y1 += dy; box.y2 += dy; 14848 14849 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14850 br00, br13, gc, 14851 &box, &origin); 14852 } while (--n); 14853 } else { 14854 const BoxRec * const clip_start = RegionBoxptr(&clip); 14855 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14856 const BoxRec *c; 14857 14858 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14859 clip_start->x1, clip_start->y1, 14860 clip_start->x2, clip_start->y2, 14861 clip_end->x1, clip_end->y1, 14862 clip_end->x2, clip_end->y2)); 14863 do { 14864 BoxRec unclipped; 14865 14866 unclipped.x1 = r->x + drawable->x; 14867 unclipped.x2 = bound(unclipped.x1, r->width); 14868 unclipped.y1 = r->y + drawable->y; 14869 unclipped.y2 = bound(unclipped.y1, r->height); 14870 r++; 14871 14872 c = find_clip_box_for_y(clip_start, 14873 clip_end, 14874 unclipped.y1); 14875 while (c != clip_end) { 14876 BoxRec box; 14877 14878 if (unclipped.y2 <= c->y1) 14879 break; 14880 14881 box = unclipped; 14882 if (!box_intersect(&box, c++)) 14883 continue; 14884 14885 box.x1 += dx; box.x2 += dx; 14886 box.y1 += dy; box.y2 += dy; 14887 14888 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14889 br00, br13, gc, 14890 &box, &origin); 14891 } 14892 } while (--n); 14893 } 14894 } 14895 14896 assert_pixmap_damage(pixmap); 14897 if (tile) 14898 kgem_bo_destroy(&sna->kgem, tile); 14899 blt_done(sna); 14900 return true; 14901} 14902 14903static bool 14904sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 14905 struct kgem_bo *bo, 14906 struct sna_damage **damage, 14907 GCPtr gc, int n, xRectangle *rect, 14908 const BoxRec *extents, unsigned clipped) 14909{ 14910 14911 PixmapPtr stipple = gc->stipple; 14912 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14913 14914 if (bo->tiling == I915_TILING_Y) { 14915 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 14916 /* This is cheating, but only the gpu_bo can be tiled */ 14917 assert(bo == __sna_pixmap_get_bo(pixmap)); 14918 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 14919 if (bo == NULL) { 14920 DBG(("%s: fallback -- unable to change tiling\n", 14921 __FUNCTION__)); 14922 return false; 14923 } 14924 } 14925 14926 if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo)) 14927 return false; 14928 14929 if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ)) 14930 return false; 14931 14932 DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n", 14933 __FUNCTION__, gc->patOrg.x, gc->patOrg.y, 14934 extents->x2 - gc->patOrg.x - drawable->x, 14935 extents->y2 - gc->patOrg.y - drawable->y, 14936 stipple->drawable.width, stipple->drawable.height)); 14937 14938 if ((stipple->drawable.width | stipple->drawable.height) == 8) 14939 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14940 gc, n, rect, 14941 extents, clipped); 14942 14943 if ((stipple->drawable.width | stipple->drawable.height) <= 0xc && 14944 is_power_of_two(stipple->drawable.width) && 14945 is_power_of_two(stipple->drawable.height)) 14946 return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage, 14947 gc, n, rect, 14948 extents, clipped); 14949 14950 if (extents->x1 - gc->patOrg.x - drawable->x >= 0 && 14951 extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width && 14952 extents->y1 - gc->patOrg.y - drawable->y >= 0 && 14953 extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) { 14954 if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8) 14955 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14956 gc, n, rect, 14957 extents, clipped); 14958 else 14959 return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage, 14960 gc, n, rect, 14961 extents, clipped); 14962 } else { 14963 return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage, 14964 gc, n, rect, 14965 extents, clipped); 14966 } 14967} 14968 14969static unsigned 14970sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc, 14971 int *_n, xRectangle **_r, 14972 BoxPtr out) 14973{ 14974 int n; 14975 xRectangle *r; 14976 Box32Rec box; 14977 bool clipped; 14978 14979 if (*_n == 0) 14980 return 0; 14981 14982 DBG(("%s: [0] = (%d, %d)x(%d, %d)\n", 14983 __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height)); 14984 14985 /* Remove any zero-size rectangles from the array */ 14986 while (*_n && ((*_r)->width == 0 || (*_r)->height == 0)) 14987 --*_n, ++*_r; 14988 14989 if (*_n == 0) 14990 return 0; 14991 14992 n = *_n; 14993 r = *_r; 14994 14995 box.x1 = r->x; 14996 box.x2 = box.x1 + r->width; 14997 box.y1 = r->y; 14998 box.y2 = box.y1 + r->height; 14999 r++; 15000 15001 while (--n) { 15002 if (r->width == 0 || r->height == 0) 15003 goto slow; 15004 15005 box32_add_rect(&box, r++); 15006 } 15007 goto done; 15008slow: 15009 { 15010 xRectangle *rr = r; 15011 do { 15012 do { 15013 --*_n, r++; 15014 } while (--n && (r->width == 0 || r->height == 0)); 15015 while (n && r->width && r->height) { 15016 box32_add_rect(&box, r); 15017 *rr++ = *r++; 15018 n--; 15019 } 15020 } while (n); 15021 } 15022done: 15023 15024 clipped = box32_trim_and_translate(&box, drawable, gc); 15025 if (!box32_to_box16(&box, out)) 15026 return 0; 15027 15028 return 1 | clipped << 1; 15029} 15030 15031static void 15032sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect) 15033{ 15034 PixmapPtr pixmap = get_drawable_pixmap(draw); 15035 struct sna *sna = to_sna_from_pixmap(pixmap); 15036 struct sna_pixmap *priv = sna_pixmap(pixmap); 15037 struct sna_damage **damage; 15038 struct kgem_bo *bo; 15039 RegionRec region; 15040 unsigned flags, hint; 15041 uint32_t color; 15042 15043 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15044 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15045 (gc->fillStyle == FillSolid || 15046 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15047 gc->fillStyle, gc->tileIsPixel, 15048 gc->alu)); 15049 15050 flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, ®ion.extents); 15051 if (flags == 0) { 15052 DBG(("%s, nothing to do\n", __FUNCTION__)); 15053 return; 15054 } 15055 15056 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 15057 region.extents.x1, region.extents.y1, 15058 region.extents.x2, region.extents.y2, 15059 flags)); 15060 15061 if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) { 15062 DBG(("%s: fallback forced\n", __FUNCTION__)); 15063 goto fallback; 15064 } 15065 15066 if (priv == NULL) { 15067 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 15068 goto fallback; 15069 } 15070 15071 if (wedged(sna)) { 15072 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15073 goto fallback; 15074 } 15075 15076 if (!PM_IS_SOLID(draw, gc->planemask)) { 15077 DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n", 15078 __FUNCTION__, gc->planemask)); 15079 goto fallback; 15080 } 15081 15082 if (alu_overwrites(gc->alu)) 15083 flags |= OVERWRITES; 15084 15085 /* Clear the cpu damage so that we refresh the GPU status of the 15086 * pixmap upon a redraw after a period of inactivity. 15087 */ 15088 hint = PREFER_GPU; 15089 if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) { 15090 int16_t dx, dy; 15091 15092 region.data = NULL; 15093 15094 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) { 15095 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 15096 RegionTranslate(®ion, dx, dy); 15097 } 15098 15099 if ((flags & IS_CLIPPED) == 0) { 15100 hint |= IGNORE_DAMAGE; 15101 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 15102 discard_cpu_damage(sna, priv); 15103 hint |= REPLACES; 15104 } else { 15105 if (priv->cpu_damage && 15106 region_subsumes_damage(®ion, priv->cpu_damage)) 15107 discard_cpu_damage(sna, priv); 15108 } 15109 } 15110 if (priv->cpu_damage == NULL) { 15111 if (priv->gpu_bo && 15112 (hint & REPLACES || 15113 box_covers_pixmap(pixmap, ®ion.extents) || 15114 box_inplace(pixmap, ®ion.extents))) { 15115 DBG(("%s: promoting to full GPU\n", 15116 __FUNCTION__)); 15117 assert(priv->gpu_bo->proxy == NULL); 15118 sna_damage_all(&priv->gpu_damage, pixmap); 15119 } 15120 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 15121 priv->cpu = false; 15122 } 15123 15124 if (dx | dy) 15125 RegionTranslate(®ion, -dx, -dy); 15126 } 15127 15128 /* If the source is already on the GPU, keep the operation on the GPU */ 15129 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 15130 sna_pixmap_is_gpu(gc->tile.pixmap)) { 15131 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 15132 hint |= FORCE_GPU; 15133 } 15134 15135 bo = sna_drawable_use_bo(draw, hint, ®ion.extents, &damage); 15136 if (bo == NULL) { 15137 DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint)); 15138 goto fallback; 15139 } 15140 if (hint & REPLACES && UNDO) 15141 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 15142 15143 if (gc_is_solid(gc, &color)) { 15144 DBG(("%s: solid fill [%08x], testing for blt\n", 15145 __FUNCTION__, color)); 15146 15147 if (sna_poly_fill_rect_blt(draw, 15148 bo, damage, 15149 gc, color, n, rect, 15150 ®ion.extents, flags)) 15151 return; 15152 } else if (gc->fillStyle == FillTiled) { 15153 DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__)); 15154 15155 if (sna_poly_fill_rect_tiled_blt(draw, bo, damage, 15156 gc, n, rect, 15157 ®ion.extents, flags)) 15158 return; 15159 } else { 15160 DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__)); 15161 15162 if (sna_poly_fill_rect_stippled_blt(draw, bo, damage, 15163 gc, n, rect, 15164 ®ion.extents, flags)) 15165 return; 15166 } 15167 15168fallback: 15169 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 15170 region.extents.x1, region.extents.y1, 15171 region.extents.x2, region.extents.y2)); 15172 region.data = NULL; 15173 if (!region_maybe_clip(®ion, gc->pCompositeClip)) { 15174 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15175 return; 15176 } 15177 15178 if (!sna_gc_move_to_cpu(gc, draw, ®ion)) 15179 goto out; 15180 if (!sna_drawable_move_region_to_cpu(draw, ®ion, 15181 drawable_gc_flags(draw, gc, n > 1))) 15182 goto out; 15183 15184 if (sigtrap_get() == 0) { 15185 DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__)); 15186 fbPolyFillRect(draw, gc, n, rect); 15187 FALLBACK_FLUSH(draw); 15188 sigtrap_put(); 15189 } 15190out: 15191 sna_gc_move_to_gpu(gc); 15192 RegionUninit(®ion); 15193} 15194 15195static void 15196sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r) 15197{ 15198 struct sna_fill_spans *data = sna_gc(gc)->priv; 15199 uint32_t color; 15200 15201 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15202 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15203 (gc->fillStyle == FillSolid || 15204 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15205 gc->fillStyle, gc->tileIsPixel, 15206 gc->alu)); 15207 15208 assert(PM_IS_SOLID(draw, gc->planemask)); 15209 if (n == 0) 15210 return; 15211 15212 /* The mi routines do not attempt to keep the spans it generates 15213 * within the clip, so we must run them through the clipper. 15214 */ 15215 15216 if (gc_is_solid(gc, &color)) { 15217 (void)sna_poly_fill_rect_blt(draw, 15218 data->bo, NULL, 15219 gc, color, n, r, 15220 &data->region.extents, 15221 IS_CLIPPED); 15222 } else if (gc->fillStyle == FillTiled) { 15223 (void)sna_poly_fill_rect_tiled_blt(draw, 15224 data->bo, NULL, 15225 gc, n, r, 15226 &data->region.extents, 15227 IS_CLIPPED); 15228 } else { 15229 (void)sna_poly_fill_rect_stippled_blt(draw, 15230 data->bo, NULL, 15231 gc, n, r, 15232 &data->region.extents, 15233 IS_CLIPPED); 15234 } 15235} 15236 15237static void 15238sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc) 15239{ 15240 struct sna_fill_spans data; 15241 struct sna_pixmap *priv; 15242 15243 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15244 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15245 (gc->fillStyle == FillSolid || 15246 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15247 gc->fillStyle, gc->tileIsPixel, 15248 gc->alu)); 15249 15250 data.flags = sna_poly_arc_extents(draw, gc, n, arc, 15251 &data.region.extents); 15252 if (data.flags == 0) 15253 return; 15254 15255 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 15256 data.region.extents.x1, data.region.extents.y1, 15257 data.region.extents.x2, data.region.extents.y2, 15258 data.flags)); 15259 15260 data.region.data = NULL; 15261 15262 if (FORCE_FALLBACK) 15263 goto fallback; 15264 15265 if (!ACCEL_POLY_FILL_ARC) 15266 goto fallback; 15267 15268 data.pixmap = get_drawable_pixmap(draw); 15269 data.sna = to_sna_from_pixmap(data.pixmap); 15270 priv = sna_pixmap(data.pixmap); 15271 if (priv == NULL) { 15272 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 15273 goto fallback; 15274 } 15275 15276 if (wedged(data.sna)) { 15277 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15278 goto fallback; 15279 } 15280 15281 if (!PM_IS_SOLID(draw, gc->planemask)) 15282 goto fallback; 15283 15284 if ((data.bo = sna_drawable_use_bo(draw, 15285 use_fill_spans(draw, gc, &data.region.extents, data.flags), 15286 &data.region.extents, 15287 &data.damage))) { 15288 uint32_t color; 15289 15290 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 15291 sna_gc(gc)->priv = &data; 15292 15293 if (gc_is_solid(gc, &color)) { 15294 struct sna_fill_op fill; 15295 15296 if (!sna_fill_init_blt(&fill, 15297 data.sna, data.pixmap, 15298 data.bo, gc->alu, color, 15299 FILL_SPANS)) 15300 goto fallback; 15301 15302 data.op = &fill; 15303 15304 if ((data.flags & IS_CLIPPED) == 0) { 15305 if (data.dx | data.dy) 15306 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 15307 else 15308 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 15309 } else { 15310 if (!region_maybe_clip(&data.region, 15311 gc->pCompositeClip)) 15312 return; 15313 15314 if (region_is_singular(&data.region)) 15315 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 15316 else 15317 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 15318 } 15319 assert(gc->miTranslate); 15320 gc->ops = &sna_gc_ops__tmp; 15321 15322 miPolyFillArc(draw, gc, n, arc); 15323 fill.done(data.sna, &fill); 15324 } else { 15325 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 15326 gc->ops = &sna_gc_ops__tmp; 15327 15328 miPolyFillArc(draw, gc, n, arc); 15329 } 15330 15331 gc->ops = (GCOps *)&sna_gc_ops; 15332 if (data.damage) { 15333 if (data.dx | data.dy) 15334 pixman_region_translate(&data.region, data.dx, data.dy); 15335 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 15336 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 15337 } 15338 assert_pixmap_damage(data.pixmap); 15339 RegionUninit(&data.region); 15340 return; 15341 } 15342 15343fallback: 15344 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 15345 data.region.extents.x1, data.region.extents.y1, 15346 data.region.extents.x2, data.region.extents.y2)); 15347 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 15348 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15349 return; 15350 } 15351 15352 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 15353 goto out; 15354 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 15355 drawable_gc_flags(draw, gc, true))) 15356 goto out; 15357 15358 if (sigtrap_get() == 0) { 15359 DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n", 15360 __FUNCTION__)); 15361 miPolyFillArc(draw, gc, n, arc); 15362 sigtrap_put(); 15363 } 15364out: 15365 sna_gc_move_to_gpu(gc); 15366 RegionUninit(&data.region); 15367} 15368 15369struct sna_font { 15370 CharInfoRec glyphs8[256]; 15371 CharInfoRec *glyphs16[256]; 15372}; 15373#define GLYPH_INVALID (void *)1 15374#define GLYPH_EMPTY (void *)2 15375 15376static Bool 15377sna_realize_font(ScreenPtr screen, FontPtr font) 15378{ 15379 struct sna_font *priv; 15380 15381 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15382 15383 priv = calloc(1, sizeof(struct sna_font)); 15384 if (priv == NULL) 15385 return FALSE; 15386 15387 if (!FontSetPrivate(font, sna_font_key, priv)) { 15388 free(priv); 15389 return FALSE; 15390 } 15391 15392 return TRUE; 15393} 15394 15395static Bool 15396sna_unrealize_font(ScreenPtr screen, FontPtr font) 15397{ 15398 struct sna_font *priv = FontGetPrivate(font, sna_font_key); 15399 int i, j; 15400 15401 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15402 15403 if (priv == NULL) 15404 return TRUE; 15405 15406 for (i = 0; i < 256; i++) { 15407 if ((uintptr_t)priv->glyphs8[i].bits & ~3) 15408 free(priv->glyphs8[i].bits); 15409 } 15410 for (j = 0; j < 256; j++) { 15411 if (priv->glyphs16[j] == NULL) 15412 continue; 15413 15414 for (i = 0; i < 256; i++) { 15415 if ((uintptr_t)priv->glyphs16[j][i].bits & ~3) 15416 free(priv->glyphs16[j][i].bits); 15417 } 15418 free(priv->glyphs16[j]); 15419 } 15420 free(priv); 15421 15422 FontSetPrivate(font, sna_font_key, NULL); 15423 return TRUE; 15424} 15425 15426static bool 15427sna_glyph_blt(DrawablePtr drawable, GCPtr gc, 15428 int _x, int _y, unsigned int _n, 15429 CharInfoPtr *_info, 15430 RegionRec *clip, 15431 uint32_t fg, uint32_t bg, 15432 bool transparent) 15433{ 15434 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15435 struct sna *sna = to_sna_from_pixmap(pixmap); 15436 struct kgem_bo *bo; 15437 struct sna_damage **damage; 15438 const BoxRec *extents, *last_extents; 15439 uint32_t *b; 15440 int16_t dx, dy; 15441 uint32_t br00; 15442 uint16_t unwind_batch, unwind_reloc; 15443 unsigned hint; 15444 15445 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15446 15447 DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n", 15448 __FUNCTION__, _x, _y, _n, fg, bg, rop)); 15449 15450 if (wedged(sna)) { 15451 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15452 return false; 15453 } 15454 15455 if (!transparent && clip->data == NULL) 15456 hint = PREFER_GPU | IGNORE_DAMAGE; 15457 else 15458 hint = PREFER_GPU; 15459 15460 bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage); 15461 if (bo == NULL) 15462 return false; 15463 15464 if (bo->tiling == I915_TILING_Y) { 15465 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15466 assert(bo == __sna_pixmap_get_bo(pixmap)); 15467 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15468 if (bo == NULL) { 15469 DBG(("%s: fallback -- unable to change tiling\n", 15470 __FUNCTION__)); 15471 return false; 15472 } 15473 } 15474 15475 if (!kgem_bo_can_blt(&sna->kgem, bo)) 15476 return false; 15477 15478 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15479 RegionTranslate(clip, dx, dy); 15480 _x += drawable->x + dx; 15481 _y += drawable->y + dy; 15482 15483 extents = region_rects(clip); 15484 last_extents = extents + region_num_rects(clip); 15485 15486 if (!transparent) { /* emulate miImageGlyphBlt */ 15487 if (!sna_blt_fill_boxes(sna, GXcopy, 15488 bo, drawable->bitsPerPixel, 15489 bg, extents, last_extents - extents)) { 15490 RegionTranslate(clip, -dx, -dy); 15491 return false; 15492 } 15493 } 15494 15495 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15496 assert(kgem_bo_can_blt(&sna->kgem, bo)); 15497 if (!kgem_check_batch(&sna->kgem, 20) || 15498 !kgem_check_bo_fenced(&sna->kgem, bo) || 15499 !kgem_check_reloc(&sna->kgem, 1)) { 15500 kgem_submit(&sna->kgem); 15501 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 15502 RegionTranslate(clip, -dx, -dy); 15503 return false; 15504 } 15505 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15506 } 15507 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 15508 15509 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15510 __FUNCTION__, 15511 extents->x1, extents->y1, 15512 extents->x2, extents->y2)); 15513 15514 unwind_batch = sna->kgem.nbatch; 15515 unwind_reloc = sna->kgem.nreloc; 15516 15517 assert(sna->kgem.mode == KGEM_BLT); 15518 b = sna->kgem.batch + sna->kgem.nbatch; 15519 if (sna->kgem.gen >= 0100) { 15520 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15521 b[1] = bo->pitch; 15522 if (sna->kgem.gen >= 040 && bo->tiling) { 15523 b[0] |= BLT_DST_TILED; 15524 b[1] >>= 2; 15525 } 15526 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15527 b[2] = extents->y1 << 16 | extents->x1; 15528 b[3] = extents->y2 << 16 | extents->x2; 15529 *(uint64_t *)(b+4) = 15530 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15531 I915_GEM_DOMAIN_RENDER << 16 | 15532 I915_GEM_DOMAIN_RENDER | 15533 KGEM_RELOC_FENCED, 15534 0); 15535 b[6] = bg; 15536 b[7] = fg; 15537 b[8] = 0; 15538 b[9] = 0; 15539 sna->kgem.nbatch += 10; 15540 } else { 15541 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15542 b[1] = bo->pitch; 15543 if (sna->kgem.gen >= 040 && bo->tiling) { 15544 b[0] |= BLT_DST_TILED; 15545 b[1] >>= 2; 15546 } 15547 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15548 b[2] = extents->y1 << 16 | extents->x1; 15549 b[3] = extents->y2 << 16 | extents->x2; 15550 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15551 I915_GEM_DOMAIN_RENDER << 16 | 15552 I915_GEM_DOMAIN_RENDER | 15553 KGEM_RELOC_FENCED, 15554 0); 15555 b[5] = bg; 15556 b[6] = fg; 15557 b[7] = 0; 15558 sna->kgem.nbatch += 8; 15559 } 15560 15561 br00 = XY_TEXT_IMMEDIATE_BLT; 15562 if (bo->tiling && sna->kgem.gen >= 040) 15563 br00 |= BLT_DST_TILED; 15564 15565 do { 15566 CharInfoPtr *info = _info; 15567 int x = _x, y = _y, n = _n; 15568 15569 do { 15570 CharInfoPtr c = *info++; 15571 int w = GLYPHWIDTHPIXELS(c); 15572 int h = GLYPHHEIGHTPIXELS(c); 15573 int w8 = (w + 7) >> 3; 15574 int x1, y1, len; 15575 15576 if (c->bits == GLYPH_EMPTY) 15577 goto skip; 15578 15579 len = (w8 * h + 7) >> 3 << 1; 15580 x1 = x + c->metrics.leftSideBearing; 15581 y1 = y - c->metrics.ascent; 15582 15583 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 15584 x,y, x1, y1, w, w8, h, len)); 15585 15586 if (x1 >= extents->x2 || y1 >= extents->y2) 15587 goto skip; 15588 if (x1 + w <= extents->x1 || y1 + h <= extents->y1) 15589 goto skip; 15590 15591 assert(len > 0); 15592 if (!kgem_check_batch(&sna->kgem, 3+len)) { 15593 _kgem_submit(&sna->kgem); 15594 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15595 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 15596 15597 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 15598 __FUNCTION__, 15599 extents->x1, extents->y1, 15600 extents->x2, extents->y2)); 15601 15602 unwind_batch = sna->kgem.nbatch; 15603 unwind_reloc = sna->kgem.nreloc; 15604 15605 assert(sna->kgem.mode == KGEM_BLT); 15606 b = sna->kgem.batch + sna->kgem.nbatch; 15607 if (sna->kgem.gen >= 0100) { 15608 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15609 b[1] = bo->pitch; 15610 if (bo->tiling) { 15611 b[0] |= BLT_DST_TILED; 15612 b[1] >>= 2; 15613 } 15614 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15615 b[2] = extents->y1 << 16 | extents->x1; 15616 b[3] = extents->y2 << 16 | extents->x2; 15617 *(uint64_t *)(b+4) = 15618 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15619 I915_GEM_DOMAIN_RENDER << 16 | 15620 I915_GEM_DOMAIN_RENDER | 15621 KGEM_RELOC_FENCED, 15622 0); 15623 b[6] = bg; 15624 b[7] = fg; 15625 b[8] = 0; 15626 b[9] = 0; 15627 sna->kgem.nbatch += 10; 15628 } else { 15629 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15630 b[1] = bo->pitch; 15631 if (sna->kgem.gen >= 040 && bo->tiling) { 15632 b[0] |= BLT_DST_TILED; 15633 b[1] >>= 2; 15634 } 15635 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15636 b[2] = extents->y1 << 16 | extents->x1; 15637 b[3] = extents->y2 << 16 | extents->x2; 15638 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15639 I915_GEM_DOMAIN_RENDER << 16 | 15640 I915_GEM_DOMAIN_RENDER | 15641 KGEM_RELOC_FENCED, 15642 0); 15643 b[5] = bg; 15644 b[6] = fg; 15645 b[7] = 0; 15646 sna->kgem.nbatch += 8; 15647 } 15648 } 15649 15650 assert(sna->kgem.mode == KGEM_BLT); 15651 b = sna->kgem.batch + sna->kgem.nbatch; 15652 sna->kgem.nbatch += 3 + len; 15653 15654 b[0] = br00 | (1 + len); 15655 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 15656 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 15657 { 15658 uint64_t *src = (uint64_t *)c->bits; 15659 uint64_t *dst = (uint64_t *)(b + 3); 15660 do { 15661 *dst++ = *src++; 15662 len -= 2; 15663 } while (len); 15664 } 15665 15666 if (damage) { 15667 BoxRec r; 15668 15669 r.x1 = x1; 15670 r.y1 = y1; 15671 r.x2 = x1 + w; 15672 r.y2 = y1 + h; 15673 if (box_intersect(&r, extents)) 15674 sna_damage_add_box(damage, &r); 15675 } 15676skip: 15677 x += c->metrics.characterWidth; 15678 } while (--n); 15679 15680 if (++extents == last_extents) 15681 break; 15682 15683 if (kgem_check_batch(&sna->kgem, 3)) { 15684 assert(sna->kgem.mode == KGEM_BLT); 15685 b = sna->kgem.batch + sna->kgem.nbatch; 15686 sna->kgem.nbatch += 3; 15687 15688 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15689 __FUNCTION__, 15690 extents->x1, extents->y1, 15691 extents->x2, extents->y2)); 15692 15693 b[0] = XY_SETUP_CLIP; 15694 b[1] = extents->y1 << 16 | extents->x1; 15695 b[2] = extents->y2 << 16 | extents->x2; 15696 } 15697 } while (1); 15698 15699 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 15700 sna->kgem.nbatch = unwind_batch; 15701 sna->kgem.nreloc = unwind_reloc; 15702 if (sna->kgem.nbatch == 0) 15703 kgem_bo_undo(&sna->kgem, bo); 15704 } 15705 15706 assert_pixmap_damage(pixmap); 15707 blt_done(sna); 15708 return true; 15709} 15710 15711static void 15712sna_glyph_extents(FontPtr font, 15713 CharInfoPtr *info, 15714 unsigned long count, 15715 ExtentInfoRec *extents) 15716{ 15717 extents->drawDirection = font->info.drawDirection; 15718 extents->fontAscent = font->info.fontAscent; 15719 extents->fontDescent = font->info.fontDescent; 15720 15721 extents->overallAscent = info[0]->metrics.ascent; 15722 extents->overallDescent = info[0]->metrics.descent; 15723 extents->overallLeft = info[0]->metrics.leftSideBearing; 15724 extents->overallRight = info[0]->metrics.rightSideBearing; 15725 extents->overallWidth = info[0]->metrics.characterWidth; 15726 15727 while (--count) { 15728 CharInfoPtr p =*++info; 15729 int v; 15730 15731 if (p->metrics.ascent > extents->overallAscent) 15732 extents->overallAscent = p->metrics.ascent; 15733 if (p->metrics.descent > extents->overallDescent) 15734 extents->overallDescent = p->metrics.descent; 15735 15736 v = extents->overallWidth + p->metrics.leftSideBearing; 15737 if (v < extents->overallLeft) 15738 extents->overallLeft = v; 15739 15740 v = extents->overallWidth + p->metrics.rightSideBearing; 15741 if (v > extents->overallRight) 15742 extents->overallRight = v; 15743 15744 extents->overallWidth += p->metrics.characterWidth; 15745 } 15746} 15747 15748static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out) 15749{ 15750 int w = GLYPHWIDTHPIXELS(in); 15751 int h = GLYPHHEIGHTPIXELS(in); 15752 int stride = GLYPHWIDTHBYTESPADDED(in); 15753 uint8_t *dst, *src; 15754 int clear = 1; 15755 15756 out->metrics = in->metrics; 15757 15758 /* Skip empty glyphs */ 15759 if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) { 15760 out->bits = GLYPH_EMPTY; 15761 return true; 15762 } 15763 15764 w = (w + 7) >> 3; 15765 15766 out->bits = malloc((w*h + 7) & ~7); 15767 if (out->bits == NULL) 15768 return false; 15769 15770 VG(memset(out->bits, 0, (w*h + 7) & ~7)); 15771 src = (uint8_t *)in->bits; 15772 dst = (uint8_t *)out->bits; 15773 stride -= w; 15774 do { 15775 int i = w; 15776 do { 15777 clear &= *src == 0; 15778 *dst++ = byte_reverse(*src++); 15779 } while (--i); 15780 src += stride; 15781 } while (--h); 15782 15783 if (clear) { 15784 free(out->bits); 15785 out->bits = GLYPH_EMPTY; 15786 } 15787 15788 return true; 15789} 15790 15791inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv, 15792 uint8_t g, CharInfoPtr *out) 15793{ 15794 unsigned long n; 15795 CharInfoPtr p, ret; 15796 15797 p = &priv->glyphs8[g]; 15798 if (p->bits) { 15799 *out = p; 15800 return p->bits != GLYPH_INVALID; 15801 } 15802 15803 font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret); 15804 if (n == 0) { 15805 p->bits = GLYPH_INVALID; 15806 return false; 15807 } 15808 15809 return sna_set_glyph(ret, *out = p); 15810} 15811 15812inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv, 15813 uint16_t g, CharInfoPtr *out) 15814{ 15815 unsigned long n; 15816 CharInfoPtr page, p, ret; 15817 15818 page = priv->glyphs16[g>>8]; 15819 if (page == NULL) 15820 page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec)); 15821 15822 p = &page[g&0xff]; 15823 if (p->bits) { 15824 *out = p; 15825 return p->bits != GLYPH_INVALID; 15826 } 15827 15828 font->get_glyphs(font, 1, (unsigned char *)&g, 15829 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit, 15830 &n, &ret); 15831 if (n == 0) { 15832 p->bits = GLYPH_INVALID; 15833 return false; 15834 } 15835 15836 return sna_set_glyph(ret, *out = p); 15837} 15838 15839static inline bool sna_font_too_large(FontPtr font) 15840{ 15841 int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font)); 15842 int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font)); 15843 int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth)); 15844 DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__, 15845 top, bot, width, (top + bot) * (width + 7)/8)); 15846 return (top + bot) * (width + 7)/8 > 124; 15847} 15848 15849static int 15850sna_poly_text8(DrawablePtr drawable, GCPtr gc, 15851 int x, int y, 15852 int count, char *chars) 15853{ 15854 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15855 CharInfoPtr info[255]; 15856 ExtentInfoRec extents; 15857 RegionRec region; 15858 long unsigned i, n; 15859 uint32_t fg; 15860 15861 for (i = n = 0; i < count; i++) { 15862 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15863 n++; 15864 } 15865 if (n == 0) 15866 return x; 15867 15868 sna_glyph_extents(gc->font, info, n, &extents); 15869 region.extents.x1 = x + extents.overallLeft; 15870 region.extents.y1 = y - extents.overallAscent; 15871 region.extents.x2 = x + extents.overallRight; 15872 region.extents.y2 = y + extents.overallDescent; 15873 15874 translate_box(®ion.extents, drawable); 15875 clip_box(®ion.extents, gc); 15876 if (box_empty(®ion.extents)) 15877 return x + extents.overallRight; 15878 15879 region.data = NULL; 15880 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15881 return x + extents.overallRight; 15882 15883 if (FORCE_FALLBACK) 15884 goto fallback; 15885 15886 if (!ACCEL_POLY_TEXT8) 15887 goto fallback; 15888 15889 if (sna_font_too_large(gc->font)) 15890 goto fallback; 15891 15892 if (!PM_IS_SOLID(drawable, gc->planemask)) 15893 goto fallback; 15894 15895 if (!gc_is_solid(gc, &fg)) 15896 goto fallback; 15897 15898 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15899fallback: 15900 DBG(("%s: fallback\n", __FUNCTION__)); 15901 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15902 Linear8Bit, &n, info); 15903 15904 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15905 goto out; 15906 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15907 MOVE_READ | MOVE_WRITE)) 15908 goto out; 15909 15910 if (sigtrap_get() == 0) { 15911 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15912 fbPolyGlyphBlt(drawable, gc, x, y, n, 15913 info, FONTGLYPHS(gc->font)); 15914 FALLBACK_FLUSH(drawable); 15915 sigtrap_put(); 15916 } 15917out: 15918 sna_gc_move_to_gpu(gc); 15919 } 15920 RegionUninit(®ion); 15921 return x + extents.overallRight; 15922} 15923 15924static int 15925sna_poly_text16(DrawablePtr drawable, GCPtr gc, 15926 int x, int y, 15927 int count, unsigned short *chars) 15928{ 15929 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15930 CharInfoPtr info[255]; 15931 ExtentInfoRec extents; 15932 RegionRec region; 15933 long unsigned i, n; 15934 uint32_t fg; 15935 15936 for (i = n = 0; i < count; i++) { 15937 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15938 n++; 15939 } 15940 if (n == 0) 15941 return x; 15942 15943 sna_glyph_extents(gc->font, info, n, &extents); 15944 region.extents.x1 = x + extents.overallLeft; 15945 region.extents.y1 = y - extents.overallAscent; 15946 region.extents.x2 = x + extents.overallRight; 15947 region.extents.y2 = y + extents.overallDescent; 15948 15949 translate_box(®ion.extents, drawable); 15950 clip_box(®ion.extents, gc); 15951 if (box_empty(®ion.extents)) 15952 return x + extents.overallRight; 15953 15954 region.data = NULL; 15955 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15956 return x + extents.overallRight; 15957 15958 if (FORCE_FALLBACK) 15959 goto fallback; 15960 15961 if (!ACCEL_POLY_TEXT16) 15962 goto fallback; 15963 15964 if (sna_font_too_large(gc->font)) 15965 goto fallback; 15966 15967 if (!PM_IS_SOLID(drawable, gc->planemask)) 15968 goto fallback; 15969 15970 if (!gc_is_solid(gc, &fg)) 15971 goto fallback; 15972 15973 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15974fallback: 15975 DBG(("%s: fallback\n", __FUNCTION__)); 15976 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15977 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15978 &n, info); 15979 15980 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15981 goto out; 15982 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15983 MOVE_READ | MOVE_WRITE)) 15984 goto out; 15985 15986 if (sigtrap_get() == 0) { 15987 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15988 fbPolyGlyphBlt(drawable, gc, x, y, n, 15989 info, FONTGLYPHS(gc->font)); 15990 FALLBACK_FLUSH(drawable); 15991 sigtrap_put(); 15992 } 15993out: 15994 sna_gc_move_to_gpu(gc); 15995 } 15996 RegionUninit(®ion); 15997 return x + extents.overallRight; 15998} 15999 16000static void 16001sna_image_text8(DrawablePtr drawable, GCPtr gc, 16002 int x, int y, 16003 int count, char *chars) 16004{ 16005 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 16006 CharInfoPtr info[255]; 16007 ExtentInfoRec extents; 16008 RegionRec region; 16009 long unsigned i, n; 16010 16011 for (i = n = 0; i < count; i++) { 16012 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 16013 n++; 16014 } 16015 if (n == 0) 16016 return; 16017 16018 sna_glyph_extents(gc->font, info, n, &extents); 16019 region.extents.x1 = x + MIN(0, extents.overallLeft); 16020 region.extents.y1 = y - extents.fontAscent; 16021 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16022 region.extents.y2 = y + extents.fontDescent; 16023 16024 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16025 __FUNCTION__, n, count, 16026 extents.overallLeft, extents.overallRight, extents.overallWidth, 16027 extents.fontAscent, extents.fontDescent, 16028 region.extents.x1, region.extents.y1, 16029 region.extents.x2, region.extents.y2)); 16030 16031 translate_box(®ion.extents, drawable); 16032 clip_box(®ion.extents, gc); 16033 if (box_empty(®ion.extents)) 16034 return; 16035 16036 region.data = NULL; 16037 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16038 return; 16039 16040 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 16041 __FUNCTION__, 16042 region.extents.x1, region.extents.y1, 16043 region.extents.x2, region.extents.y2)); 16044 16045 if (FORCE_FALLBACK) 16046 goto fallback; 16047 16048 if (!ACCEL_IMAGE_TEXT8) 16049 goto fallback; 16050 16051 if (sna_font_too_large(gc->font)) 16052 goto fallback; 16053 16054 if (!PM_IS_SOLID(drawable, gc->planemask)) 16055 goto fallback; 16056 16057 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 16058 gc->fgPixel, gc->bgPixel, false)) { 16059fallback: 16060 DBG(("%s: fallback\n", __FUNCTION__)); 16061 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 16062 Linear8Bit, &n, info); 16063 16064 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16065 goto out; 16066 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16067 goto out; 16068 16069 if (sigtrap_get() == 0) { 16070 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16071 fbImageGlyphBlt(drawable, gc, x, y, n, 16072 info, FONTGLYPHS(gc->font)); 16073 FALLBACK_FLUSH(drawable); 16074 sigtrap_put(); 16075 } 16076out: 16077 sna_gc_move_to_gpu(gc); 16078 } 16079 RegionUninit(®ion); 16080} 16081 16082static void 16083sna_image_text16(DrawablePtr drawable, GCPtr gc, 16084 int x, int y, 16085 int count, unsigned short *chars) 16086{ 16087 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 16088 CharInfoPtr info[255]; 16089 ExtentInfoRec extents; 16090 RegionRec region; 16091 long unsigned i, n; 16092 16093 for (i = n = 0; i < count; i++) { 16094 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 16095 n++; 16096 } 16097 if (n == 0) 16098 return; 16099 16100 sna_glyph_extents(gc->font, info, n, &extents); 16101 region.extents.x1 = x + MIN(0, extents.overallLeft); 16102 region.extents.y1 = y - extents.fontAscent; 16103 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16104 region.extents.y2 = y + extents.fontDescent; 16105 16106 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16107 __FUNCTION__, n, count, 16108 extents.overallLeft, extents.overallRight, extents.overallWidth, 16109 extents.fontAscent, extents.fontDescent, 16110 region.extents.x1, region.extents.y1, 16111 region.extents.x2, region.extents.y2)); 16112 16113 translate_box(®ion.extents, drawable); 16114 clip_box(®ion.extents, gc); 16115 if (box_empty(®ion.extents)) 16116 return; 16117 16118 region.data = NULL; 16119 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16120 return; 16121 16122 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 16123 __FUNCTION__, 16124 region.extents.x1, region.extents.y1, 16125 region.extents.x2, region.extents.y2)); 16126 16127 if (FORCE_FALLBACK) 16128 goto fallback; 16129 16130 if (!ACCEL_IMAGE_TEXT16) 16131 goto fallback; 16132 16133 if (sna_font_too_large(gc->font)) 16134 goto fallback; 16135 16136 if (!PM_IS_SOLID(drawable, gc->planemask)) 16137 goto fallback; 16138 16139 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 16140 gc->fgPixel, gc->bgPixel, false)) { 16141fallback: 16142 DBG(("%s: fallback\n", __FUNCTION__)); 16143 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 16144 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 16145 &n, info); 16146 16147 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16148 goto out; 16149 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16150 goto out; 16151 16152 if (sigtrap_get() == 0) { 16153 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16154 fbImageGlyphBlt(drawable, gc, x, y, n, 16155 info, FONTGLYPHS(gc->font)); 16156 FALLBACK_FLUSH(drawable); 16157 sigtrap_put(); 16158 } 16159out: 16160 sna_gc_move_to_gpu(gc); 16161 } 16162 RegionUninit(®ion); 16163} 16164 16165/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ 16166static bool 16167sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, 16168 int _x, int _y, unsigned int _n, 16169 CharInfoPtr *_info, pointer _base, 16170 struct kgem_bo *bo, 16171 struct sna_damage **damage, 16172 RegionPtr clip, 16173 uint32_t fg, uint32_t bg, 16174 bool transparent) 16175{ 16176 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16177 struct sna *sna = to_sna_from_pixmap(pixmap); 16178 const BoxRec *extents, *last_extents; 16179 uint32_t *b; 16180 int16_t dx, dy; 16181 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 16182 uint16_t unwind_batch, unwind_reloc; 16183 16184 DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n", 16185 __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg)); 16186 16187 if (bo->tiling == I915_TILING_Y) { 16188 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16189 assert(bo == __sna_pixmap_get_bo(pixmap)); 16190 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16191 if (bo == NULL) { 16192 DBG(("%s: fallback -- unable to change tiling\n", 16193 __FUNCTION__)); 16194 return false; 16195 } 16196 } 16197 16198 if (!kgem_bo_can_blt(&sna->kgem, bo)) 16199 return false; 16200 16201 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16202 RegionTranslate(clip, dx, dy); 16203 _x += drawable->x + dx; 16204 _y += drawable->y + dy; 16205 16206 extents = region_rects(clip); 16207 last_extents = extents + region_num_rects(clip); 16208 16209 if (!transparent) { /* emulate miImageGlyphBlt */ 16210 if (!sna_blt_fill_boxes(sna, GXcopy, 16211 bo, drawable->bitsPerPixel, 16212 bg, extents, last_extents - extents)) { 16213 RegionTranslate(clip, -dx, -dy); 16214 return false; 16215 } 16216 } 16217 16218 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16219 assert(kgem_bo_can_blt(&sna->kgem, bo)); 16220 if (!kgem_check_batch(&sna->kgem, 20) || 16221 !kgem_check_bo_fenced(&sna->kgem, bo) || 16222 !kgem_check_reloc(&sna->kgem, 1)) { 16223 kgem_submit(&sna->kgem); 16224 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 16225 RegionTranslate(clip, -dx, -dy); 16226 return false; 16227 } 16228 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16229 } 16230 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16231 16232 unwind_batch = sna->kgem.nbatch; 16233 unwind_reloc = sna->kgem.nreloc; 16234 16235 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16236 __FUNCTION__, 16237 extents->x1, extents->y1, 16238 extents->x2, extents->y2)); 16239 16240 assert(sna->kgem.mode == KGEM_BLT); 16241 b = sna->kgem.batch + sna->kgem.nbatch; 16242 if (sna->kgem.gen >= 0100) { 16243 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16244 b[1] = bo->pitch; 16245 if (sna->kgem.gen >= 040 && bo->tiling) { 16246 b[0] |= BLT_DST_TILED; 16247 b[1] >>= 2; 16248 } 16249 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16250 b[2] = extents->y1 << 16 | extents->x1; 16251 b[3] = extents->y2 << 16 | extents->x2; 16252 *(uint64_t *)(b+4) = 16253 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16254 I915_GEM_DOMAIN_RENDER << 16 | 16255 I915_GEM_DOMAIN_RENDER | 16256 KGEM_RELOC_FENCED, 16257 0); 16258 b[6] = bg; 16259 b[7] = fg; 16260 b[8] = 0; 16261 b[9] = 0; 16262 sna->kgem.nbatch += 10; 16263 } else { 16264 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16265 b[1] = bo->pitch; 16266 if (sna->kgem.gen >= 040 && bo->tiling) { 16267 b[0] |= BLT_DST_TILED; 16268 b[1] >>= 2; 16269 } 16270 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16271 b[2] = extents->y1 << 16 | extents->x1; 16272 b[3] = extents->y2 << 16 | extents->x2; 16273 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16274 I915_GEM_DOMAIN_RENDER << 16 | 16275 I915_GEM_DOMAIN_RENDER | 16276 KGEM_RELOC_FENCED, 16277 0); 16278 b[5] = bg; 16279 b[6] = fg; 16280 b[7] = 0; 16281 sna->kgem.nbatch += 8; 16282 } 16283 16284 do { 16285 CharInfoPtr *info = _info; 16286 int x = _x, y = _y, n = _n; 16287 16288 do { 16289 CharInfoPtr c = *info++; 16290 uint8_t *glyph = FONTGLYPHBITS(base, c); 16291 int w = GLYPHWIDTHPIXELS(c); 16292 int h = GLYPHHEIGHTPIXELS(c); 16293 int stride = GLYPHWIDTHBYTESPADDED(c); 16294 int w8 = (w + 7) >> 3; 16295 int x1, y1, len, i; 16296 uint8_t *byte; 16297 16298 if (w == 0 || h == 0) 16299 goto skip; 16300 16301 len = (w8 * h + 7) >> 3 << 1; 16302 x1 = x + c->metrics.leftSideBearing; 16303 y1 = y - c->metrics.ascent; 16304 16305 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 16306 x,y, x1, y1, w, w8, h, len)); 16307 16308 if (x1 >= extents->x2 || y1 >= extents->y2 || 16309 x1 + w <= extents->x1 || y1 + h <= extents->y1) { 16310 DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n", 16311 __FUNCTION__, 16312 x1, y1, w, h, 16313 extents->x1, extents->y1, 16314 extents->x2, extents->y2)); 16315 goto skip; 16316 } 16317 16318 { 16319 int clear = 1, j = h; 16320 uint8_t *g = glyph; 16321 16322 do { 16323 i = w8; 16324 do { 16325 clear = *g++ == 0; 16326 } while (clear && --i); 16327 g += stride - w8; 16328 } while (clear && --j); 16329 if (clear) { 16330 DBG(("%s: skipping clear glyph for ImageGlyph\n", 16331 __FUNCTION__)); 16332 goto skip; 16333 } 16334 } 16335 16336 assert(len > 0); 16337 if (!kgem_check_batch(&sna->kgem, 3+len)) { 16338 _kgem_submit(&sna->kgem); 16339 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16340 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16341 16342 unwind_batch = sna->kgem.nbatch; 16343 unwind_reloc = sna->kgem.nreloc; 16344 16345 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 16346 __FUNCTION__, 16347 extents->x1, extents->y1, 16348 extents->x2, extents->y2)); 16349 16350 assert(sna->kgem.mode == KGEM_BLT); 16351 b = sna->kgem.batch + sna->kgem.nbatch; 16352 if (sna->kgem.gen >= 0100) { 16353 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16354 b[1] = bo->pitch; 16355 if (bo->tiling) { 16356 b[0] |= BLT_DST_TILED; 16357 b[1] >>= 2; 16358 } 16359 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16360 b[2] = extents->y1 << 16 | extents->x1; 16361 b[3] = extents->y2 << 16 | extents->x2; 16362 *(uint64_t *)(b+4) = 16363 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16364 I915_GEM_DOMAIN_RENDER << 16 | 16365 I915_GEM_DOMAIN_RENDER | 16366 KGEM_RELOC_FENCED, 16367 0); 16368 b[6] = bg; 16369 b[7] = fg; 16370 b[8] = 0; 16371 b[9] = 0; 16372 sna->kgem.nbatch += 10; 16373 } else { 16374 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16375 b[1] = bo->pitch; 16376 if (sna->kgem.gen >= 040 && bo->tiling) { 16377 b[0] |= BLT_DST_TILED; 16378 b[1] >>= 2; 16379 } 16380 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16381 b[2] = extents->y1 << 16 | extents->x1; 16382 b[3] = extents->y2 << 16 | extents->x2; 16383 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16384 I915_GEM_DOMAIN_RENDER << 16 | 16385 I915_GEM_DOMAIN_RENDER | 16386 KGEM_RELOC_FENCED, 16387 0); 16388 b[5] = bg; 16389 b[6] = fg; 16390 b[7] = 0; 16391 sna->kgem.nbatch += 8; 16392 } 16393 } 16394 16395 assert(sna->kgem.mode == KGEM_BLT); 16396 b = sna->kgem.batch + sna->kgem.nbatch; 16397 sna->kgem.nbatch += 3 + len; 16398 16399 b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); 16400 if (bo->tiling && sna->kgem.gen >= 040) 16401 b[0] |= BLT_DST_TILED; 16402 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 16403 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 16404 16405 byte = (uint8_t *)&b[3]; 16406 stride -= w8; 16407 do { 16408 i = w8; 16409 do { 16410 *byte++ = byte_reverse(*glyph++); 16411 } while (--i); 16412 glyph += stride; 16413 } while (--h); 16414 while ((byte - (uint8_t *)&b[3]) & 7) 16415 *byte++ = 0; 16416 assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); 16417 16418 if (damage) { 16419 BoxRec r; 16420 16421 r.x1 = x1; 16422 r.y1 = y1; 16423 r.x2 = x1 + w; 16424 r.y2 = y1 + h; 16425 if (box_intersect(&r, extents)) 16426 sna_damage_add_box(damage, &r); 16427 } 16428skip: 16429 x += c->metrics.characterWidth; 16430 } while (--n); 16431 16432 if (++extents == last_extents) 16433 break; 16434 16435 if (kgem_check_batch(&sna->kgem, 3 + 5)) { 16436 assert(sna->kgem.mode == KGEM_BLT); 16437 b = sna->kgem.batch + sna->kgem.nbatch; 16438 sna->kgem.nbatch += 3; 16439 16440 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16441 __FUNCTION__, 16442 extents->x1, extents->y1, 16443 extents->x2, extents->y2)); 16444 16445 b[0] = XY_SETUP_CLIP; 16446 b[1] = extents->y1 << 16 | extents->x1; 16447 b[2] = extents->y2 << 16 | extents->x2; 16448 } 16449 } while (1); 16450 16451 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 16452 sna->kgem.nbatch = unwind_batch; 16453 sna->kgem.nreloc = unwind_reloc; 16454 if (sna->kgem.nbatch == 0) 16455 kgem_bo_undo(&sna->kgem, bo); 16456 } 16457 16458 assert_pixmap_damage(pixmap); 16459 blt_done(sna); 16460 return true; 16461} 16462 16463static void 16464sna_image_glyph(DrawablePtr drawable, GCPtr gc, 16465 int x, int y, unsigned int n, 16466 CharInfoPtr *info, pointer base) 16467{ 16468 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16469 struct sna *sna = to_sna_from_pixmap(pixmap); 16470 ExtentInfoRec extents; 16471 RegionRec region; 16472 struct sna_damage **damage; 16473 struct kgem_bo *bo; 16474 unsigned hint; 16475 16476 if (n == 0) 16477 return; 16478 16479 sna_glyph_extents(gc->font, info, n, &extents); 16480 region.extents.x1 = x + MIN(0, extents.overallLeft); 16481 region.extents.y1 = y - extents.fontAscent; 16482 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16483 region.extents.y2 = y + extents.fontDescent; 16484 16485 DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16486 __FUNCTION__, n, 16487 extents.overallLeft, extents.overallRight, extents.overallWidth, 16488 extents.fontAscent, extents.fontDescent, 16489 region.extents.x1, region.extents.y1, 16490 region.extents.x2, region.extents.y2)); 16491 16492 translate_box(®ion.extents, drawable); 16493 clip_box(®ion.extents, gc); 16494 if (box_empty(®ion.extents)) 16495 return; 16496 16497 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16498 region.extents.x1, region.extents.y1, 16499 region.extents.x2, region.extents.y2)); 16500 16501 region.data = NULL; 16502 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16503 return; 16504 16505 if (FORCE_FALLBACK) 16506 goto fallback; 16507 16508 if (!ACCEL_IMAGE_GLYPH) 16509 goto fallback; 16510 16511 if (wedged(sna)) { 16512 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16513 goto fallback; 16514 } 16515 16516 if (!PM_IS_SOLID(drawable, gc->planemask)) 16517 goto fallback; 16518 16519 if (sna_font_too_large(gc->font)) 16520 goto fallback; 16521 16522 if (region.data == NULL) 16523 hint = IGNORE_DAMAGE | PREFER_GPU; 16524 else 16525 hint = PREFER_GPU; 16526 if ((bo = sna_drawable_use_bo(drawable, hint, 16527 ®ion.extents, &damage)) && 16528 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16529 bo, damage, ®ion, 16530 gc->fgPixel, gc->bgPixel, false)) 16531 goto out; 16532 16533fallback: 16534 DBG(("%s: fallback\n", __FUNCTION__)); 16535 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16536 goto out_gc; 16537 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16538 goto out_gc; 16539 16540 if (sigtrap_get() == 0) { 16541 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16542 fbImageGlyphBlt(drawable, gc, x, y, n, info, base); 16543 FALLBACK_FLUSH(drawable); 16544 sigtrap_put(); 16545 } 16546out_gc: 16547 sna_gc_move_to_gpu(gc); 16548out: 16549 RegionUninit(®ion); 16550} 16551 16552static void 16553sna_poly_glyph(DrawablePtr drawable, GCPtr gc, 16554 int x, int y, unsigned int n, 16555 CharInfoPtr *info, pointer base) 16556{ 16557 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16558 struct sna *sna = to_sna_from_pixmap(pixmap); 16559 ExtentInfoRec extents; 16560 RegionRec region; 16561 struct sna_damage **damage; 16562 struct kgem_bo *bo; 16563 uint32_t fg; 16564 16565 if (n == 0) 16566 return; 16567 16568 sna_glyph_extents(gc->font, info, n, &extents); 16569 region.extents.x1 = x + extents.overallLeft; 16570 region.extents.y1 = y - extents.overallAscent; 16571 region.extents.x2 = x + extents.overallRight; 16572 region.extents.y2 = y + extents.overallDescent; 16573 16574 translate_box(®ion.extents, drawable); 16575 clip_box(®ion.extents, gc); 16576 if (box_empty(®ion.extents)) 16577 return; 16578 16579 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16580 region.extents.x1, region.extents.y1, 16581 region.extents.x2, region.extents.y2)); 16582 16583 region.data = NULL; 16584 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16585 return; 16586 16587 if (FORCE_FALLBACK) 16588 goto fallback; 16589 16590 if (!ACCEL_POLY_GLYPH) 16591 goto fallback; 16592 16593 if (wedged(sna)) { 16594 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16595 goto fallback; 16596 } 16597 16598 if (!PM_IS_SOLID(drawable, gc->planemask)) 16599 goto fallback; 16600 16601 if (!gc_is_solid(gc, &fg)) 16602 goto fallback; 16603 16604 if (sna_font_too_large(gc->font)) 16605 goto fallback; 16606 16607 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 16608 ®ion.extents, &damage)) && 16609 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16610 bo, damage, ®ion, fg, -1, true)) 16611 goto out; 16612 16613fallback: 16614 DBG(("%s: fallback\n", __FUNCTION__)); 16615 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16616 goto out_gc; 16617 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16618 MOVE_READ | MOVE_WRITE)) 16619 goto out_gc; 16620 16621 if (sigtrap_get() == 0) { 16622 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 16623 fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); 16624 FALLBACK_FLUSH(drawable); 16625 sigtrap_put(); 16626 } 16627out_gc: 16628 sna_gc_move_to_gpu(gc); 16629out: 16630 RegionUninit(®ion); 16631} 16632 16633static bool 16634sna_push_pixels_solid_blt(GCPtr gc, 16635 PixmapPtr bitmap, 16636 DrawablePtr drawable, 16637 RegionPtr region) 16638{ 16639 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16640 struct sna *sna = to_sna_from_pixmap(pixmap); 16641 struct sna_damage **damage; 16642 struct kgem_bo *bo; 16643 const BoxRec *box; 16644 int16_t dx, dy; 16645 int n; 16646 uint8_t rop = copy_ROP[gc->alu]; 16647 16648 bo = sna_drawable_use_bo(drawable, PREFER_GPU, ®ion->extents, &damage); 16649 if (bo == NULL) 16650 return false; 16651 16652 if (bo->tiling == I915_TILING_Y) { 16653 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16654 assert(bo == __sna_pixmap_get_bo(pixmap)); 16655 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16656 if (bo == NULL) { 16657 DBG(("%s: fallback -- unable to change tiling\n", 16658 __FUNCTION__)); 16659 return false; 16660 } 16661 } 16662 16663 if (!kgem_bo_can_blt(&sna->kgem, bo)) 16664 return false; 16665 16666 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16667 RegionTranslate(region, dx, dy); 16668 16669 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 16670 if (damage) 16671 sna_damage_add_to_pixmap(damage, region, pixmap); 16672 assert_pixmap_damage(pixmap); 16673 16674 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, 16675 region->extents.x1, region->extents.y1, 16676 region->extents.x2, region->extents.y2)); 16677 16678 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16679 assert(kgem_bo_can_blt(&sna->kgem, bo)); 16680 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16681 16682 /* Region is pre-clipped and translated into pixmap space */ 16683 box = region_rects(region); 16684 n = region_num_rects(region); 16685 do { 16686 int bx1 = (box->x1 - region->extents.x1) & ~7; 16687 int bx2 = (box->x2 - region->extents.x1 + 7) & ~7; 16688 int bw = (bx2 - bx1)/8; 16689 int bh = box->y2 - box->y1; 16690 int bstride = ALIGN(bw, 2); 16691 struct kgem_bo *upload; 16692 void *ptr; 16693 16694 if (!kgem_check_batch(&sna->kgem, 10) || 16695 !kgem_check_bo_fenced(&sna->kgem, bo) || 16696 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 16697 kgem_submit(&sna->kgem); 16698 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 16699 return false; 16700 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16701 } 16702 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16703 16704 upload = kgem_create_buffer(&sna->kgem, 16705 bstride*bh, 16706 KGEM_BUFFER_WRITE_INPLACE, 16707 &ptr); 16708 if (!upload) 16709 break; 16710 16711 if (sigtrap_get() == 0) { 16712 uint8_t *dst = ptr; 16713 16714 int src_stride = bitmap->devKind; 16715 uint8_t *src; 16716 uint32_t *b; 16717 16718 assert(src_stride); 16719 src = (uint8_t*)bitmap->devPrivate.ptr; 16720 src += (box->y1 - region->extents.y1) * src_stride + bx1/8; 16721 src_stride -= bstride; 16722 do { 16723 int i = bstride; 16724 do { 16725 *dst++ = byte_reverse(*src++); 16726 *dst++ = byte_reverse(*src++); 16727 i -= 2; 16728 } while (i); 16729 src += src_stride; 16730 } while (--bh); 16731 16732 assert(sna->kgem.mode == KGEM_BLT); 16733 b = sna->kgem.batch + sna->kgem.nbatch; 16734 if (sna->kgem.gen >= 0100) { 16735 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 16736 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16737 b[1] = bo->pitch; 16738 if (sna->kgem.gen >= 040 && bo->tiling) { 16739 b[0] |= BLT_DST_TILED; 16740 b[1] >>= 2; 16741 } 16742 b[1] |= 1 << 29; 16743 b[1] |= blt_depth(drawable->depth) << 24; 16744 b[1] |= rop << 16; 16745 b[2] = box->y1 << 16 | box->x1; 16746 b[3] = box->y2 << 16 | box->x2; 16747 *(uint64_t *)(b+4) = 16748 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16749 I915_GEM_DOMAIN_RENDER << 16 | 16750 I915_GEM_DOMAIN_RENDER | 16751 KGEM_RELOC_FENCED, 16752 0); 16753 *(uint64_t *)(b+6) = 16754 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 16755 I915_GEM_DOMAIN_RENDER << 16 | 16756 KGEM_RELOC_FENCED, 16757 0); 16758 b[8] = gc->bgPixel; 16759 b[9] = gc->fgPixel; 16760 sna->kgem.nbatch += 10; 16761 } else { 16762 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 16763 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16764 b[1] = bo->pitch; 16765 if (sna->kgem.gen >= 040 && bo->tiling) { 16766 b[0] |= BLT_DST_TILED; 16767 b[1] >>= 2; 16768 } 16769 b[1] |= 1 << 29; 16770 b[1] |= blt_depth(drawable->depth) << 24; 16771 b[1] |= rop << 16; 16772 b[2] = box->y1 << 16 | box->x1; 16773 b[3] = box->y2 << 16 | box->x2; 16774 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16775 I915_GEM_DOMAIN_RENDER << 16 | 16776 I915_GEM_DOMAIN_RENDER | 16777 KGEM_RELOC_FENCED, 16778 0); 16779 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 16780 I915_GEM_DOMAIN_RENDER << 16 | 16781 KGEM_RELOC_FENCED, 16782 0); 16783 b[6] = gc->bgPixel; 16784 b[7] = gc->fgPixel; 16785 16786 sna->kgem.nbatch += 8; 16787 } 16788 sigtrap_put(); 16789 } 16790 16791 kgem_bo_destroy(&sna->kgem, upload); 16792 16793 box++; 16794 } while (--n); 16795 16796 blt_done(sna); 16797 return true; 16798} 16799 16800static void 16801sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable, 16802 int w, int h, 16803 int x, int y) 16804{ 16805 RegionRec region; 16806 16807 if (w == 0 || h == 0) 16808 return; 16809 16810 DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 16811 16812 region.extents.x1 = x; 16813 region.extents.y1 = y; 16814 region.extents.x2 = region.extents.x1 + w; 16815 region.extents.y2 = region.extents.y1 + h; 16816 16817 clip_box(®ion.extents, gc); 16818 if (box_empty(®ion.extents)) 16819 return; 16820 16821 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16822 region.extents.x1, region.extents.y1, 16823 region.extents.x2, region.extents.y2)); 16824 16825 region.data = NULL; 16826 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16827 return; 16828 16829 switch (gc->fillStyle) { 16830 case FillSolid: 16831 if (sna_push_pixels_solid_blt(gc, bitmap, drawable, ®ion)) 16832 return; 16833 break; 16834 default: 16835 break; 16836 } 16837 16838 DBG(("%s: fallback\n", __FUNCTION__)); 16839 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16840 goto out; 16841 if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ)) 16842 goto out; 16843 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16844 drawable_gc_flags(drawable, gc, false))) 16845 goto out; 16846 16847 if (sigtrap_get() == 0) { 16848 DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n", 16849 __FUNCTION__, w, h, x, y)); 16850 fbPushPixels(gc, bitmap, drawable, w, h, x, y); 16851 FALLBACK_FLUSH(drawable); 16852 sigtrap_put(); 16853 } 16854out: 16855 sna_gc_move_to_gpu(gc); 16856 RegionUninit(®ion); 16857} 16858 16859static const GCOps sna_gc_ops = { 16860 sna_fill_spans, 16861 sna_set_spans, 16862 sna_put_image, 16863 sna_copy_area, 16864 sna_copy_plane, 16865 sna_poly_point, 16866 sna_poly_line, 16867 sna_poly_segment, 16868 sna_poly_rectangle, 16869 sna_poly_arc, 16870 sna_poly_fill_polygon, 16871 sna_poly_fill_rect, 16872 sna_poly_fill_arc, 16873 sna_poly_text8, 16874 sna_poly_text16, 16875 sna_image_text8, 16876 sna_image_text16, 16877 sna_image_glyph, 16878 sna_poly_glyph, 16879 sna_push_pixels, 16880}; 16881 16882static const GCOps sna_gc_ops__cpu = { 16883 fbFillSpans, 16884 fbSetSpans, 16885 fbPutImage, 16886 fbCopyArea, 16887 fbCopyPlane, 16888 sna_poly_point__cpu, 16889 fbPolyLine, 16890 fbPolySegment, 16891 miPolyRectangle, 16892 fbPolyArc, 16893 miFillPolygon, 16894 fbPolyFillRect, 16895 miPolyFillArc, 16896 miPolyText8, 16897 miPolyText16, 16898 miImageText8, 16899 miImageText16, 16900 fbImageGlyphBlt, 16901 fbPolyGlyphBlt, 16902 fbPushPixels 16903}; 16904 16905static GCOps sna_gc_ops__tmp = { 16906 sna_fill_spans, 16907 sna_set_spans, 16908 sna_put_image, 16909 sna_copy_area, 16910 sna_copy_plane, 16911 sna_poly_point, 16912 sna_poly_line, 16913 sna_poly_segment, 16914 sna_poly_rectangle, 16915 sna_poly_arc, 16916 sna_poly_fill_polygon, 16917 sna_poly_fill_rect, 16918 sna_poly_fill_arc, 16919 sna_poly_text8, 16920 sna_poly_text16, 16921 sna_image_text8, 16922 sna_image_text16, 16923 sna_image_glyph, 16924 sna_poly_glyph, 16925 sna_push_pixels, 16926}; 16927 16928static void 16929sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) 16930{ 16931 DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc, 16932 changes, gc->serialNumber, drawable->serialNumber)); 16933 16934 if (changes & (GCClipMask|GCSubwindowMode) || 16935 drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) || 16936 (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) { 16937 DBG(("%s: recomputing clip\n", __FUNCTION__)); 16938 miComputeCompositeClip(gc, drawable); 16939 DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n", 16940 __FUNCTION__, 16941 region_num_rects(gc->pCompositeClip), 16942 gc->pCompositeClip->extents.x1, 16943 gc->pCompositeClip->extents.y1, 16944 gc->pCompositeClip->extents.x2, 16945 gc->pCompositeClip->extents.y2, 16946 gc->pCompositeClip)); 16947 } 16948 16949 assert(gc->pCompositeClip); 16950 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x); 16951 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y); 16952 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width); 16953 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height); 16954 16955 sna_gc(gc)->changes |= changes; 16956 sna_gc(gc)->serial = gc->serialNumber; 16957} 16958 16959static const GCFuncs sna_gc_funcs = { 16960 sna_validate_gc, 16961 miChangeGC, 16962 miCopyGC, 16963 miDestroyGC, 16964 miChangeClip, 16965 miDestroyClip, 16966 miCopyClip 16967}; 16968 16969static const GCFuncs sna_gc_funcs__cpu = { 16970 fbValidateGC, 16971 miChangeGC, 16972 miCopyGC, 16973 miDestroyGC, 16974 miChangeClip, 16975 miDestroyClip, 16976 miCopyClip 16977}; 16978 16979static int sna_create_gc(GCPtr gc) 16980{ 16981 gc->miTranslate = 1; 16982 gc->fExpose = 1; 16983 16984 gc->freeCompClip = 0; 16985 gc->pCompositeClip = 0; 16986#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0) 16987 gc->pRotatedPixmap = 0; 16988#endif 16989 16990 fb_gc(gc)->bpp = bits_per_pixel(gc->depth); 16991 16992 gc->funcs = (GCFuncs *)&sna_gc_funcs; 16993 gc->ops = (GCOps *)&sna_gc_ops; 16994 return true; 16995} 16996 16997static bool 16998sna_get_image__inplace(PixmapPtr pixmap, 16999 RegionPtr region, 17000 char *dst, 17001 unsigned flags, 17002 bool idle) 17003{ 17004 struct sna_pixmap *priv = sna_pixmap(pixmap); 17005 struct sna *sna = to_sna_from_pixmap(pixmap); 17006 char *src; 17007 17008 if (!USE_INPLACE) 17009 return false; 17010 17011 assert(priv && priv->gpu_bo); 17012 17013 switch (priv->gpu_bo->tiling) { 17014 case I915_TILING_Y: 17015 return false; 17016 case I915_TILING_X: 17017 if (!sna->kgem.memcpy_from_tiled_x) 17018 return false; 17019 default: 17020 break; 17021 } 17022 17023 if ((flags & MOVE_INPLACE_HINT) == 0 && 17024 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 17025 return false; 17026 17027 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 17028 return false; 17029 17030 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 17031 return false; 17032 17033 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 17034 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 17035 17036 if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) { 17037 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 17038 if (src == NULL) 17039 return false; 17040 17041 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 17042 } else { 17043 src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo); 17044 if (src == NULL) 17045 return false; 17046 17047 kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo); 17048 } 17049 17050 if (sigtrap_get()) 17051 return false; 17052 17053 if (priv->gpu_bo->tiling) { 17054 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 17055 memcpy_from_tiled_x(&sna->kgem, src, dst, 17056 pixmap->drawable.bitsPerPixel, 17057 priv->gpu_bo->pitch, 17058 PixmapBytePad(region->extents.x2 - region->extents.x1, 17059 pixmap->drawable.depth), 17060 region->extents.x1, region->extents.y1, 17061 0, 0, 17062 region->extents.x2 - region->extents.x1, 17063 region->extents.y2 - region->extents.y1); 17064 } else { 17065 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 17066 memcpy_blt(src, dst, 17067 pixmap->drawable.bitsPerPixel, 17068 priv->gpu_bo->pitch, 17069 PixmapBytePad(region->extents.x2 - region->extents.x1, 17070 pixmap->drawable.depth), 17071 region->extents.x1, region->extents.y1, 17072 0, 0, 17073 region->extents.x2 - region->extents.x1, 17074 region->extents.y2 - region->extents.y1); 17075 if (!priv->shm) { 17076 pixmap->devPrivate.ptr = src; 17077 pixmap->devKind = priv->gpu_bo->pitch; 17078 priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 17079 assert_pixmap_map(pixmap, priv); 17080 priv->cpu &= priv->mapped == MAPPED_CPU; 17081 } 17082 } 17083 17084 sigtrap_put(); 17085 return true; 17086} 17087 17088static bool 17089sna_get_image__blt(PixmapPtr pixmap, 17090 RegionPtr region, 17091 char *dst, 17092 unsigned flags) 17093{ 17094 struct sna_pixmap *priv = sna_pixmap(pixmap); 17095 struct sna *sna = to_sna_from_pixmap(pixmap); 17096 struct kgem_bo *dst_bo; 17097 bool ok = false; 17098 int pitch; 17099 17100 assert(priv && priv->gpu_bo); 17101 17102 if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS) 17103 return false; 17104 17105 if (!sna->kgem.can_blt_cpu) 17106 return false; 17107 17108 if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT && 17109 kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 17110 if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT)) 17111 return false; 17112 17113 if (priv->gpu_damage == NULL) 17114 return false; 17115 17116 assert(priv->gpu_bo); 17117 if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 17118 return false; 17119 } else { 17120 if (priv->gpu_damage == NULL) 17121 return false; 17122 17123 assert(priv->gpu_bo); 17124 } 17125 17126 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 17127 return false; 17128 17129 DBG(("%s: download through a temporary map\n", __FUNCTION__)); 17130 17131 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 17132 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 17133 17134 pitch = PixmapBytePad(region->extents.x2 - region->extents.x1, 17135 pixmap->drawable.depth); 17136 dst_bo = kgem_create_map(&sna->kgem, dst, 17137 pitch * (region->extents.y2 - region->extents.y1), 17138 false); 17139 if (dst_bo) { 17140 dst_bo->pitch = pitch; 17141 kgem_bo_mark_unreusable(dst_bo); 17142 17143 ok = sna->render.copy_boxes(sna, GXcopy, 17144 &pixmap->drawable, priv->gpu_bo, 0, 0, 17145 &pixmap->drawable, dst_bo, 17146 -region->extents.x1, 17147 -region->extents.y1, 17148 ®ion->extents, 1, 17149 COPY_LAST); 17150 17151 kgem_bo_sync__cpu(&sna->kgem, dst_bo); 17152 assert(dst_bo->rq == NULL); 17153 kgem_bo_destroy(&sna->kgem, dst_bo); 17154 } 17155 17156 return ok; 17157} 17158 17159static bool 17160sna_get_image__fast(PixmapPtr pixmap, 17161 RegionPtr region, 17162 char *dst, 17163 unsigned flags) 17164{ 17165 struct sna_pixmap *priv = sna_pixmap(pixmap); 17166 17167 DBG(("%s: attached?=%d, has gpu damage?=%d\n", 17168 __FUNCTION__, priv != NULL, priv && priv->gpu_damage)); 17169 if (priv == NULL || priv->gpu_damage == NULL) 17170 return false; 17171 17172 if (priv->clear && sigtrap_get() == 0) { 17173 int w = region->extents.x2 - region->extents.x1; 17174 int h = region->extents.y2 - region->extents.y1; 17175 int pitch = PixmapBytePad(w, pixmap->drawable.depth); 17176 17177 DBG(("%s: applying clear [%08x]\n", 17178 __FUNCTION__, priv->clear_color)); 17179 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 17180 assert(priv->cpu_damage == NULL); 17181 sigtrap_assert_active(); 17182 17183 if (priv->clear_color == 0 || 17184 pixmap->drawable.bitsPerPixel == 8 || 17185 priv->clear_color == (1U << pixmap->drawable.depth) - 1) { 17186 DBG(("%s: memset clear [%02x]\n", 17187 __FUNCTION__, priv->clear_color & 0xff)); 17188 memset(dst, priv->clear_color, pitch * h); 17189 } else { 17190 pixman_fill((uint32_t *)dst, 17191 pitch/sizeof(uint32_t), 17192 pixmap->drawable.bitsPerPixel, 17193 0, 0, 17194 w, h, 17195 priv->clear_color); 17196 } 17197 17198 sigtrap_put(); 17199 return true; 17200 } 17201 17202 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 17203 !sna_damage_contains_box__no_reduce(priv->gpu_damage, 17204 ®ion->extents)) 17205 return false; 17206 17207 if (sna_get_image__inplace(pixmap, region, dst, flags, true)) 17208 return true; 17209 17210 if (sna_get_image__blt(pixmap, region, dst, flags)) 17211 return true; 17212 17213 if (sna_get_image__inplace(pixmap, region, dst, flags, false)) 17214 return true; 17215 17216 return false; 17217} 17218 17219static void 17220sna_get_image(DrawablePtr drawable, 17221 int x, int y, int w, int h, 17222 unsigned int format, unsigned long mask, 17223 char *dst) 17224{ 17225 RegionRec region; 17226 unsigned int flags; 17227 17228 if (!fbDrawableEnabled(drawable)) 17229 return; 17230 17231 DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n", 17232 __FUNCTION__, 17233 (long)get_drawable_pixmap(drawable)->drawable.serialNumber, 17234 x, y, w, h, format, mask, drawable->depth)); 17235 17236 flags = MOVE_READ; 17237 if ((w | h) == 1) 17238 flags |= MOVE_INPLACE_HINT; 17239 if (w == drawable->width) 17240 flags |= MOVE_WHOLE_HINT; 17241 17242 if (ACCEL_GET_IMAGE && 17243 !FORCE_FALLBACK && 17244 format == ZPixmap && 17245 drawable->bitsPerPixel >= 8) { 17246 PixmapPtr pixmap = get_drawable_pixmap(drawable); 17247 int16_t dx, dy; 17248 17249 get_drawable_deltas(drawable, pixmap, &dx, &dy); 17250 region.extents.x1 = x + drawable->x + dx; 17251 region.extents.y1 = y + drawable->y + dy; 17252 region.extents.x2 = region.extents.x1 + w; 17253 region.extents.y2 = region.extents.y1 + h; 17254 region.data = NULL; 17255 17256 if (sna_get_image__fast(pixmap, ®ion, dst, flags)) 17257 goto apply_planemask; 17258 17259 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 17260 ®ion, flags)) 17261 return; 17262 17263 DBG(("%s: copy box (%d, %d), (%d, %d)\n", 17264 __FUNCTION__, 17265 region.extents.x1, region.extents.y1, 17266 region.extents.x2, region.extents.y2)); 17267 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ)); 17268 if (sigtrap_get() == 0) { 17269 assert(pixmap->devKind); 17270 memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel, 17271 pixmap->devKind, PixmapBytePad(w, drawable->depth), 17272 region.extents.x1, region.extents.y1, 0, 0, w, h); 17273 sigtrap_put(); 17274 } 17275 17276apply_planemask: 17277 if (!PM_IS_SOLID(drawable, mask)) { 17278 FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel); 17279 FbStip *d = (FbStip *)dst; 17280 int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h; 17281 17282 for (i = 0; i < n; i++) 17283 d[i] &= pm; 17284 } 17285 } else { 17286 region.extents.x1 = x + drawable->x; 17287 region.extents.y1 = y + drawable->y; 17288 region.extents.x2 = region.extents.x1 + w; 17289 region.extents.y2 = region.extents.y1 + h; 17290 region.data = NULL; 17291 17292 if (sna_drawable_move_region_to_cpu(drawable, ®ion, flags)) 17293 fbGetImage(drawable, x, y, w, h, format, mask, dst); 17294 } 17295} 17296 17297static void 17298sna_get_spans(DrawablePtr drawable, int wMax, 17299 DDXPointPtr pt, int *width, int n, char *start) 17300{ 17301 RegionRec region; 17302 17303 if (!fbDrawableEnabled(drawable)) 17304 return; 17305 17306 if (sna_spans_extents(drawable, NULL, n, pt, width, ®ion.extents) == 0) 17307 return; 17308 17309 region.data = NULL; 17310 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_READ)) 17311 return; 17312 17313 fbGetSpans(drawable, wMax, pt, width, n, start); 17314} 17315 17316static void 17317sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src) 17318{ 17319 PixmapPtr pixmap = get_window_pixmap(win); 17320 struct sna *sna = to_sna_from_pixmap(pixmap); 17321 RegionRec dst; 17322 int dx, dy; 17323 17324 DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y)); 17325 if (!fbWindowEnabled(win)) 17326 return; 17327 17328 dx = origin.x - win->drawable.x; 17329 dy = origin.y - win->drawable.y; 17330 RegionTranslate(src, -dx, -dy); 17331 17332 RegionNull(&dst); 17333 RegionIntersect(&dst, &win->borderClip, src); 17334 if (box_empty(&dst.extents)) 17335 return; 17336 17337#ifdef COMPOSITE 17338 if (pixmap->screen_x | pixmap->screen_y) 17339 RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y); 17340#endif 17341 17342 if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) { 17343 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 17344 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 17345 return; 17346 17347 if (sigtrap_get() == 0) { 17348 miCopyRegion(&pixmap->drawable, &pixmap->drawable, 17349 0, &dst, dx, dy, fbCopyNtoN, 0, NULL); 17350 sigtrap_put(); 17351 } 17352 } else { 17353 sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL, 17354 &dst, dx, dy, 0, NULL); 17355 } 17356 17357 RegionUninit(&dst); 17358} 17359 17360static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) 17361{ 17362 bool ret = true; 17363 17364 DBG(("%s\n", __FUNCTION__)); 17365 17366 /* Check if the fb layer wishes to modify the attached pixmaps, 17367 * to fix up mismatches between the window and pixmap depths. 17368 */ 17369 if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) { 17370 DBG(("%s: flushing background pixmap\n", __FUNCTION__)); 17371 ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap); 17372 } 17373 17374 if (mask & CWBorderPixmap && win->borderIsPixel == false) { 17375 DBG(("%s: flushing border pixmap\n", __FUNCTION__)); 17376 ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap); 17377 } 17378 17379 return ret; 17380} 17381 17382void sna_accel_flush(struct sna *sna) 17383{ 17384 struct sna_pixmap *priv; 17385 17386 /* XXX we should be able to reduce the frequency of flushes further 17387 * by checking for outgoing damage events or sync replies. Tricky, 17388 * and doesn't appear to mitigate the performance loss. 17389 */ 17390 DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__, 17391 sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps))); 17392 17393 /* flush any pending damage from shadow copies to tfp clients */ 17394 while (!list_is_empty(&sna->flush_pixmaps)) { 17395 bool ret; 17396 17397 priv = list_first_entry(&sna->flush_pixmaps, 17398 struct sna_pixmap, flush_list); 17399 17400 list_del(&priv->flush_list); 17401 if (priv->shm) { 17402 DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n", 17403 __FUNCTION__, 17404 priv->pixmap->drawable.serialNumber, 17405 priv->pixmap->refcnt)); 17406 assert(!priv->flush); 17407 ret = sna_pixmap_move_to_cpu(priv->pixmap, 17408 MOVE_READ | MOVE_WRITE); 17409 assert(!ret || priv->gpu_bo == NULL); 17410 if (priv->pixmap->refcnt == 0) { 17411 sna_damage_destroy(&priv->cpu_damage); 17412 __sna_free_pixmap(sna, priv->pixmap, priv); 17413 } 17414 } else { 17415 unsigned hints; 17416 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__, 17417 priv->pixmap->drawable.serialNumber)); 17418 assert(priv->flush); 17419 hints = MOVE_READ | __MOVE_FORCE; 17420 if (priv->flush & FLUSH_WRITE) 17421 hints |= MOVE_WRITE; 17422 if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) { 17423 if (priv->flush & FLUSH_WRITE) { 17424 kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 17425 sna_damage_all(&priv->gpu_damage, priv->pixmap); 17426 assert(priv->cpu_damage == NULL); 17427 assert(priv->clear == false); 17428 } 17429 } 17430 } 17431 (void)ret; 17432 } 17433 17434 if (sna->kgem.flush) 17435 kgem_submit(&sna->kgem); 17436} 17437 17438static void 17439sna_shm_flush_callback(CallbackListPtr *list, 17440 pointer user_data, pointer call_data) 17441{ 17442 struct sna *sna = user_data; 17443 17444 if (!sna->needs_shm_flush) 17445 return; 17446 17447 sna_accel_flush(sna); 17448 sna->needs_shm_flush = false; 17449} 17450 17451static void 17452sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data) 17453{ 17454 struct sna *sna = user_data; 17455 17456#if 0 /* XXX requires mesa to implement glXWaitX()! */ 17457 if (!sna->needs_dri_flush) 17458 return; 17459 17460 sna_accel_flush(sna); 17461 sna->needs_dri_flush = false; 17462#else 17463 sna_accel_flush(sna); 17464#endif 17465} 17466 17467static void 17468sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data) 17469{ 17470 EventInfoRec *eventinfo = call_data; 17471 struct sna *sna = user_data; 17472 int i; 17473 17474 if (sna->needs_dri_flush) 17475 return; 17476 17477 for (i = 0; i < eventinfo->count; i++) { 17478 if (eventinfo->events[i].u.u.type == sna->damage_event) { 17479 sna->needs_dri_flush = true; 17480 return; 17481 } 17482 } 17483} 17484 17485static struct sna_pixmap *sna_accel_scanout(struct sna *sna) 17486{ 17487 struct sna_pixmap *priv; 17488 17489 if (sna->mode.front_active == 0) 17490 return NULL; 17491 17492 assert(sna->vblank_interval); 17493 assert(sna->front); 17494 assert(!sna->mode.hidden); 17495 17496 priv = sna_pixmap(sna->front); 17497 if (priv->gpu_bo == NULL) 17498 return NULL; 17499 17500 return priv; 17501} 17502 17503#define TIME currentTime.milliseconds 17504static void sna_accel_disarm_timer(struct sna *sna, int id) 17505{ 17506 DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME)); 17507 sna->timer_active &= ~(1<<id); 17508} 17509 17510static bool has_offload_slaves(struct sna *sna) 17511{ 17512#if HAS_PIXMAP_SHARING 17513 ScreenPtr screen = to_screen_from_sna(sna); 17514 PixmapDirtyUpdatePtr dirty; 17515 17516 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17517 assert(dirty->src == sna->front); 17518 if (RegionNotEmpty(DamageRegion(dirty->damage))) 17519 return true; 17520 } 17521#endif 17522 return false; 17523} 17524 17525static bool has_shadow(struct sna *sna) 17526{ 17527 DamagePtr damage; 17528 17529 if (!sna->mode.shadow_enabled) 17530 return false; 17531 17532 damage = sna->mode.shadow_damage; 17533 assert(damage); 17534 17535 DBG(("%s: has pending damage? %d, outstanding flips: %d\n", 17536 __FUNCTION__, 17537 RegionNotEmpty(DamageRegion(damage)), 17538 sna->mode.flip_active)); 17539 17540 return RegionNotEmpty(DamageRegion(damage)); 17541} 17542 17543static bool start_flush(struct sna *sna) 17544{ 17545 struct sna_pixmap *scanout; 17546 17547 if (has_offload_slaves(sna)) { 17548 DBG(("%s: has offload slaves\n", __FUNCTION__)); 17549 return true; 17550 } 17551 17552 if (has_shadow(sna)) { 17553 DBG(("%s: has dirty shadow\n", __FUNCTION__)); 17554 return true; 17555 } 17556 17557 scanout = sna_accel_scanout(sna); 17558 if (!scanout) 17559 return false; 17560 17561 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17562 scanout->gpu_bo->needs_flush = true; 17563 return true; 17564 } 17565 17566 if (scanout->cpu_damage || scanout->gpu_bo->needs_flush) 17567 return true; 17568 17569 kgem_scanout_flush(&sna->kgem, scanout->gpu_bo); 17570 return false; 17571} 17572 17573static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout) 17574{ 17575 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 17576 __FUNCTION__, 17577 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 17578 has_shadow(sna), has_offload_slaves(sna), 17579 scanout && scanout->cpu_damage != NULL, 17580 scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL)); 17581 17582 if (has_offload_slaves(sna)) 17583 return true; 17584 17585 if (has_shadow(sna)) 17586 return true; 17587 17588 if (!scanout) 17589 return false; 17590 17591 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17592 scanout->gpu_bo->needs_flush = true; 17593 return true; 17594 } 17595 17596 return scanout->cpu_damage || scanout->gpu_bo->needs_flush; 17597} 17598 17599static void timer_enable(struct sna *sna, int whom, int interval) 17600{ 17601 if (!sna->timer_active) 17602 UpdateCurrentTimeIf(); 17603 sna->timer_active |= 1 << whom; 17604 sna->timer_expire[whom] = TIME + interval; 17605 DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); 17606} 17607 17608static bool sna_scanout_do_flush(struct sna *sna) 17609{ 17610 int interval = sna->vblank_interval ?: 50; 17611 if (sna->timer_active & (1<<(FLUSH_TIMER))) { 17612 int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME; 17613 DBG(("%s: flush timer active: delta=%d\n", 17614 __FUNCTION__, delta)); 17615 if (delta <= 3) { 17616 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17617 sna->timer_expire[FLUSH_TIMER] = TIME + interval; 17618 return true; 17619 } 17620 } else { 17621 if (start_flush(sna)) 17622 timer_enable(sna, FLUSH_TIMER, interval/2); 17623 } 17624 17625 return false; 17626} 17627 17628static bool sna_accel_do_throttle(struct sna *sna) 17629{ 17630 if (sna->timer_active & (1<<(THROTTLE_TIMER))) { 17631 int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME; 17632 if (delta <= 3) { 17633 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17634 sna->timer_expire[THROTTLE_TIMER] = TIME + 20; 17635 return true; 17636 } 17637 } else if (!sna->kgem.need_retire) { 17638 DBG(("%s -- no pending activity\n", __FUNCTION__)); 17639 } else 17640 timer_enable(sna, THROTTLE_TIMER, 20); 17641 17642 return false; 17643} 17644 17645static bool sna_accel_do_expire(struct sna *sna) 17646{ 17647 if (sna->timer_active & (1<<(EXPIRE_TIMER))) { 17648 int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME; 17649 if (delta <= 3) { 17650 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17651 sna->timer_expire[EXPIRE_TIMER] = 17652 TIME + MAX_INACTIVE_TIME * 1000; 17653 return true; 17654 } 17655 } else if (sna->kgem.need_expire) 17656 timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000); 17657 17658 return false; 17659} 17660 17661static void sna_accel_post_damage(struct sna *sna) 17662{ 17663#if HAS_PIXMAP_SHARING 17664 ScreenPtr screen = to_screen_from_sna(sna); 17665 PixmapDirtyUpdatePtr dirty; 17666 17667 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17668 RegionRec region, *damage; 17669 PixmapPtr src, dst; 17670 const BoxRec *box; 17671 int16_t dx, dy; 17672 int n; 17673 17674 damage = DamageRegion(dirty->damage); 17675 if (RegionNil(damage)) 17676 continue; 17677 17678 src = (PixmapPtr)dirty->src; 17679 dst = dirty->slave_dst->master_pixmap; 17680 17681 region.extents.x1 = dirty->x; 17682 region.extents.x2 = dirty->x + dst->drawable.width; 17683 region.extents.y1 = dirty->y; 17684 region.extents.y2 = dirty->y + dst->drawable.height; 17685 region.data = NULL; 17686 17687 DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__, 17688 damage->extents.x1, damage->extents.y1, 17689 damage->extents.x2, damage->extents.y2, 17690 region_num_rects(damage), 17691 dst->drawable.serialNumber, 17692 region.extents.x1, region.extents.y1, 17693 region.extents.x2, region.extents.y2)); 17694 17695 RegionIntersect(®ion, ®ion, damage); 17696 if (RegionNil(®ion)) 17697 goto skip; 17698 17699 dx = -dirty->x; 17700 dy = -dirty->y; 17701#if HAS_DIRTYTRACKING2 17702 dx += dirty->dst_x; 17703 dy += dirty->dst_y; 17704#endif 17705 RegionTranslate(®ion, dx, dy); 17706 DamageRegionAppend(&dirty->slave_dst->drawable, ®ion); 17707 17708 DBG(("%s: slave: ((%d, %d), (%d, %d))x%d\n", __FUNCTION__, 17709 region.extents.x1, region.extents.y1, 17710 region.extents.x2, region.extents.y2, 17711 region_num_rects(®ion))); 17712 17713 box = region_rects(®ion); 17714 n = region_num_rects(®ion); 17715 if (wedged(sna)) { 17716fallback: 17717 if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) 17718 goto skip; 17719 17720 if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT)) 17721 goto skip; 17722 17723 if (sigtrap_get() == 0) { 17724 assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel); 17725 do { 17726 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 17727 __FUNCTION__, 17728 box->x1 - dx, box->y1 - dy, 17729 box->x1, box->y1, 17730 box->x2 - box->x1, box->y2 - box->y1)); 17731 17732 assert(box->x2 > box->x1); 17733 assert(box->y2 > box->y1); 17734 17735 assert(box->x1 - dx >= 0); 17736 assert(box->y1 - dy >= 0); 17737 assert(box->x2 - dx <= src->drawable.width); 17738 assert(box->y2 - dy <= src->drawable.height); 17739 17740 assert(box->x1 >= 0); 17741 assert(box->y1 >= 0); 17742 assert(box->x2 <= src->drawable.width); 17743 assert(box->y2 <= src->drawable.height); 17744 17745 assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ)); 17746 assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE)); 17747 assert(src->devKind); 17748 assert(dst->devKind); 17749 memcpy_blt(src->devPrivate.ptr, 17750 dst->devPrivate.ptr, 17751 src->drawable.bitsPerPixel, 17752 src->devKind, dst->devKind, 17753 box->x1 - dx, box->y1 - dy, 17754 box->x1, box->y1, 17755 box->x2 - box->x1, box->y2 - box->y1); 17756 box++; 17757 } while (--n); 17758 sigtrap_put(); 17759 } 17760 } else { 17761 if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17762 goto fallback; 17763 17764 if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17765 goto fallback; 17766 17767 if (!sna->render.copy_boxes(sna, GXcopy, 17768 &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy, 17769 &dst->drawable, __sna_pixmap_get_bo(dst), 0, 0, 17770 box, n, COPY_LAST)) 17771 goto fallback; 17772 17773 /* Before signalling the slave via ProcessPending, 17774 * ensure not only the batch is submitted as the 17775 * slave may be using the Damage callback to perform 17776 * its copy, but also that the memory must be coherent 17777 * - we need to treat it as uncached for the PCI slave 17778 * will bypass LLC. 17779 */ 17780 kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst)); 17781 } 17782 17783 DamageRegionProcessPending(&dirty->slave_dst->drawable); 17784skip: 17785 RegionUninit(®ion); 17786 DamageEmpty(dirty->damage); 17787 } 17788#endif 17789} 17790 17791static void sna_scanout_flush(struct sna *sna) 17792{ 17793 struct sna_pixmap *priv = sna_accel_scanout(sna); 17794 bool busy; 17795 17796 DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n", 17797 __FUNCTION__, (long)TIME, 17798 priv && priv->cpu_damage, 17799 priv && priv->gpu_bo->exec != NULL, 17800 sna->kgem.nbatch, 17801 sna->kgem.busy)); 17802 17803 busy = stop_flush(sna, priv); 17804 if (!sna->kgem.busy && !busy) 17805 sna_accel_disarm_timer(sna, FLUSH_TIMER); 17806 sna->kgem.busy = busy; 17807 17808 if (priv && 17809 sna->mode.shadow_damage == NULL && 17810 sna_pixmap_force_to_gpu(priv->pixmap, 17811 MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) 17812 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 17813 17814 sna_mode_redisplay(sna); 17815 sna_accel_post_damage(sna); 17816} 17817 17818static void sna_accel_throttle(struct sna *sna) 17819{ 17820 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17821 17822 if (sna->kgem.need_throttle) { 17823 kgem_submit(&sna->kgem); 17824 kgem_throttle(&sna->kgem); 17825 } 17826 17827 if (!sna->kgem.need_retire) 17828 sna_accel_disarm_timer(sna, THROTTLE_TIMER); 17829} 17830 17831static void sna_pixmap_expire(struct sna *sna) 17832{ 17833 while (sna->freed_pixmap) { 17834 PixmapPtr pixmap = __pop_freed_pixmap(sna); 17835 free(sna_pixmap(pixmap)); 17836 FreePixmap(pixmap); 17837 } 17838} 17839 17840static void sna_accel_expire(struct sna *sna) 17841{ 17842 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17843 17844 kgem_expire_cache(&sna->kgem); 17845 sna_pixmap_expire(sna); 17846 17847 if (!sna->kgem.need_expire) 17848 sna_accel_disarm_timer(sna, EXPIRE_TIMER); 17849} 17850 17851#ifdef DEBUG_MEMORY 17852static bool sna_accel_do_debug_memory(struct sna *sna) 17853{ 17854 int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME; 17855 17856 if (delta <= 3) { 17857 sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000; 17858 return true; 17859 } else 17860 return false; 17861} 17862 17863static void sna_accel_debug_memory(struct sna *sna) 17864{ 17865 ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n", 17866 sna->debug_memory.pixmap_allocs, 17867 sna->debug_memory.pixmap_cached, 17868 sna->kgem.debug_memory.bo_allocs, 17869 (unsigned long)sna->kgem.debug_memory.bo_bytes, 17870 sna->debug_memory.cpu_bo_allocs, 17871 (unsigned long)sna->debug_memory.cpu_bo_bytes); 17872 17873#ifdef VALGRIND_DO_ADDED_LEAK_CHECK 17874 VG(VALGRIND_DO_ADDED_LEAK_CHECK); 17875#endif 17876} 17877 17878#else 17879#define sna_accel_do_debug_memory(x) 0 17880static void sna_accel_debug_memory(struct sna *sna) { } 17881#endif 17882 17883static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL }; 17884 17885static PixmapPtr 17886sna_get_window_pixmap(WindowPtr window) 17887{ 17888 return get_window_pixmap(window); 17889} 17890 17891static void 17892sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) 17893{ 17894 DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n", 17895 __FUNCTION__, window->drawable.id, 17896 get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0, 17897 pixmap->drawable.serialNumber)); 17898 17899 sna_dri2_decouple_window(window); 17900 17901 *(PixmapPtr *)__get_private(window, sna_window_key) = pixmap; 17902} 17903 17904struct sna_visit_set_pixmap_window { 17905 PixmapPtr old, new; 17906}; 17907 17908static int 17909sna_visit_set_window_pixmap(WindowPtr window, pointer data) 17910{ 17911 struct sna_visit_set_pixmap_window *visit = data; 17912 17913 if (sna_get_window_pixmap(window) == visit->old) { 17914 window->drawable.pScreen->SetWindowPixmap(window, visit->new); 17915 return WT_WALKCHILDREN; 17916 } 17917 17918 return WT_DONTWALKCHILDREN; 17919} 17920 17921static void 17922migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front) 17923{ 17924#if HAS_PIXMAP_SHARING 17925 ScreenPtr screen = old_front->drawable.pScreen; 17926 PixmapDirtyUpdatePtr dirty, safe; 17927 17928 xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) { 17929 assert(dirty->src == old_front); 17930 if ((PixmapPtr)dirty->src != old_front) 17931 continue; 17932 17933 DamageUnregister(&dirty->src->drawable, dirty->damage); 17934 DamageDestroy(dirty->damage); 17935 17936 dirty->damage = DamageCreate(NULL, NULL, 17937 DamageReportNone, 17938 TRUE, screen, screen); 17939 if (!dirty->damage) { 17940 xorg_list_del(&dirty->ent); 17941 free(dirty); 17942 continue; 17943 } 17944 17945 DamageRegister(&new_front->drawable, dirty->damage); 17946 dirty->src = (DrawablePtr)new_front; 17947 } 17948#endif 17949} 17950 17951static void 17952sna_set_screen_pixmap(PixmapPtr pixmap) 17953{ 17954 ScreenPtr screen = pixmap->drawable.pScreen; 17955 PixmapPtr old_front = screen->devPrivate; 17956 WindowPtr root; 17957 17958 DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n", 17959 __FUNCTION__, 17960 old_front ? (long)old_front->drawable.serialNumber : 0, 17961 pixmap ? (long)pixmap->drawable.serialNumber : 0, 17962 to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0)); 17963 17964 assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen)); 17965 assert(to_sna_from_pixmap(pixmap)->front == old_front); 17966 17967 if (old_front) { 17968 assert(to_sna_from_pixmap(old_front)->front == old_front); 17969 migrate_dirty_tracking(old_front, pixmap); 17970 } 17971 17972 root = get_root_window(screen); 17973 if (root) { 17974 struct sna_visit_set_pixmap_window visit = { old_front, pixmap }; 17975 TraverseTree(root, sna_visit_set_window_pixmap, &visit); 17976 assert(fbGetWindowPixmap(root) == pixmap); 17977 } 17978 17979 to_sna_from_pixmap(pixmap)->front = pixmap; 17980 screen->devPrivate = pixmap; 17981 pixmap->refcnt++; 17982 17983 if (old_front) 17984 screen->DestroyPixmap(old_front); 17985} 17986 17987static Bool 17988sna_create_window(WindowPtr win) 17989{ 17990 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 17991 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate); 17992 return TRUE; 17993} 17994 17995static Bool 17996sna_map_window(WindowPtr win) 17997{ 17998 return TRUE; 17999} 18000 18001static Bool 18002sna_position_window(WindowPtr win, int x, int y) 18003{ 18004 return TRUE; 18005} 18006 18007static Bool 18008sna_unmap_window(WindowPtr win) 18009{ 18010 return TRUE; 18011} 18012 18013static Bool 18014sna_destroy_window(WindowPtr win) 18015{ 18016 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 18017 sna_video_destroy_window(win); 18018 sna_dri2_destroy_window(win); 18019 return TRUE; 18020} 18021 18022static void 18023sna_query_best_size(int class, 18024 unsigned short *width, unsigned short *height, 18025 ScreenPtr screen) 18026{ 18027 unsigned short w; 18028 18029 switch (class) { 18030 case CursorShape: 18031 if (*width > screen->width) 18032 *width = screen->width; 18033 if (*height > screen->height) 18034 *height = screen->height; 18035 break; 18036 18037 case TileShape: 18038 case StippleShape: 18039 w = *width; 18040 if ((w & (w - 1)) && w < FB_UNIT) { 18041 for (w = 1; w < *width; w <<= 1) 18042 ; 18043 *width = w; 18044 } 18045 break; 18046 } 18047} 18048 18049static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def) 18050{ 18051} 18052 18053static bool sna_picture_init(ScreenPtr screen) 18054{ 18055 PictureScreenPtr ps; 18056 18057 DBG(("%s\n", __FUNCTION__)); 18058 18059 if (!miPictureInit(screen, NULL, 0)) 18060 return false; 18061 18062 ps = GetPictureScreen(screen); 18063 assert(ps != NULL); 18064 assert(ps->CreatePicture != NULL); 18065 assert(ps->DestroyPicture != NULL); 18066 18067 ps->Composite = sna_composite; 18068 ps->CompositeRects = sna_composite_rectangles; 18069 ps->Glyphs = sna_glyphs; 18070 if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0])) 18071 ps->Glyphs = sna_glyphs__shared; 18072 ps->UnrealizeGlyph = sna_glyph_unrealize; 18073 ps->AddTraps = sna_add_traps; 18074 ps->Trapezoids = sna_composite_trapezoids; 18075#if HAS_PIXMAN_TRIANGLES 18076 ps->Triangles = sna_composite_triangles; 18077#if PICTURE_SCREEN_VERSION >= 2 18078 ps->TriStrip = sna_composite_tristrip; 18079 ps->TriFan = sna_composite_trifan; 18080#endif 18081#endif 18082 18083 return true; 18084} 18085 18086static bool sna_option_accel_none(struct sna *sna) 18087{ 18088 const char *s; 18089 18090 if (wedged(sna)) 18091 return true; 18092 18093 if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE)) 18094 return true; 18095 18096 if (sna->kgem.gen >= 0120) 18097 return true; 18098 18099 if (!intel_option_cast_to_bool(sna->Options, 18100 OPTION_ACCEL_METHOD, 18101 !IS_DEFAULT_ACCEL_METHOD(NOACCEL))) 18102 return false; 18103 18104#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 18105 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 18106 if (s == NULL) 18107 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 18108 18109 return strcasecmp(s, "none") == 0; 18110#else 18111 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 18112#endif 18113} 18114 18115static bool sna_option_accel_blt(struct sna *sna) 18116{ 18117 const char *s; 18118 18119 assert(sna->kgem.gen < 0120); 18120 18121 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 18122 if (s == NULL) 18123 return false; 18124 18125 return strcasecmp(s, "blt") == 0; 18126} 18127 18128#if HAVE_NOTIFY_FD 18129static void sna_accel_notify(int fd, int ready, void *data) 18130{ 18131 sna_mode_wakeup(data); 18132} 18133#endif 18134 18135bool sna_accel_init(ScreenPtr screen, struct sna *sna) 18136{ 18137 const char *backend; 18138 18139 DBG(("%s\n", __FUNCTION__)); 18140 18141 sna_font_key = AllocateFontPrivateIndex(); 18142 18143 list_init(&sna->flush_pixmaps); 18144 list_init(&sna->active_pixmaps); 18145 18146 SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna); 18147 18148#ifdef DEBUG_MEMORY 18149 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000; 18150#endif 18151 18152 screen->defColormap = FakeClientID(0); 18153 /* let CreateDefColormap do whatever it wants for pixels */ 18154 screen->blackPixel = screen->whitePixel = (Pixel) 0; 18155 screen->QueryBestSize = sna_query_best_size; 18156 assert(screen->GetImage == NULL); 18157 screen->GetImage = sna_get_image; 18158 assert(screen->GetSpans == NULL); 18159 screen->GetSpans = sna_get_spans; 18160 assert(screen->CreateWindow == NULL); 18161 screen->CreateWindow = sna_create_window; 18162 assert(screen->DestroyWindow == NULL); 18163 screen->DestroyWindow = sna_destroy_window; 18164 screen->PositionWindow = sna_position_window; 18165 screen->ChangeWindowAttributes = sna_change_window_attributes; 18166 screen->RealizeWindow = sna_map_window; 18167 screen->UnrealizeWindow = sna_unmap_window; 18168 screen->CopyWindow = sna_copy_window; 18169 assert(screen->CreatePixmap == NULL); 18170 screen->CreatePixmap = sna_create_pixmap; 18171 assert(screen->DestroyPixmap == NULL); 18172 screen->DestroyPixmap = sna_destroy_pixmap; 18173#ifdef CREATE_PIXMAP_USAGE_SHARED 18174 screen->SharePixmapBacking = sna_share_pixmap_backing; 18175 screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing; 18176#endif 18177 screen->RealizeFont = sna_realize_font; 18178 screen->UnrealizeFont = sna_unrealize_font; 18179 assert(screen->CreateGC == NULL); 18180 screen->CreateGC = sna_create_gc; 18181 screen->CreateColormap = miInitializeColormap; 18182 screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA; 18183 screen->InstallColormap = miInstallColormap; 18184 screen->UninstallColormap = miUninstallColormap; 18185 screen->ListInstalledColormaps = miListInstalledColormaps; 18186 screen->ResolveColor = miResolveColor; 18187 assert(screen->StoreColors == NULL); 18188 screen->StoreColors = sna_store_colors; 18189 screen->BitmapToRegion = fbBitmapToRegion; 18190 18191#if HAS_PIXMAP_SHARING 18192 screen->StartPixmapTracking = PixmapStartDirtyTracking; 18193 screen->StopPixmapTracking = PixmapStopDirtyTracking; 18194#endif 18195 18196 assert(screen->GetWindowPixmap == NULL); 18197 screen->GetWindowPixmap = sna_get_window_pixmap; 18198 assert(screen->SetWindowPixmap == NULL); 18199 screen->SetWindowPixmap = sna_set_window_pixmap; 18200 18201 screen->SetScreenPixmap = sna_set_screen_pixmap; 18202 18203 if (sna->kgem.has_userptr) 18204 ShmRegisterFuncs(screen, &shm_funcs); 18205 else 18206 ShmRegisterFbFuncs(screen); 18207 18208 if (!sna_picture_init(screen)) 18209 return false; 18210 18211 backend = no_render_init(sna); 18212 if (sna_option_accel_none(sna)) { 18213 backend = "disabled"; 18214 sna->kgem.wedged = true; 18215 sna_render_mark_wedged(sna); 18216 } else if (sna_option_accel_blt(sna)) 18217 (void)backend; 18218 else if (sna->kgem.gen >= 0110) 18219 backend = gen9_render_init(sna, backend); 18220 else if (sna->kgem.gen >= 0100) 18221 backend = gen8_render_init(sna, backend); 18222 else if (sna->kgem.gen >= 070) 18223 backend = gen7_render_init(sna, backend); 18224 else if (sna->kgem.gen >= 060) 18225 backend = gen6_render_init(sna, backend); 18226 else if (sna->kgem.gen >= 050) 18227 backend = gen5_render_init(sna, backend); 18228 else if (sna->kgem.gen >= 040) 18229 backend = gen4_render_init(sna, backend); 18230 else if (sna->kgem.gen >= 030) 18231 backend = gen3_render_init(sna, backend); 18232 else if (sna->kgem.gen >= 020) 18233 backend = gen2_render_init(sna, backend); 18234 18235 DBG(("%s(backend=%s, prefer_gpu=%x)\n", 18236 __FUNCTION__, backend, sna->render.prefer_gpu)); 18237 18238 kgem_reset(&sna->kgem); 18239 sigtrap_init(); 18240 18241 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 18242 "SNA initialized with %s backend\n", 18243 backend); 18244 18245 return true; 18246} 18247 18248void sna_accel_create(struct sna *sna) 18249{ 18250 ExtensionEntry *damage; 18251 18252 DBG(("%s\n", __FUNCTION__)); 18253 18254 damage = CheckExtension("DAMAGE"); 18255 if (damage) 18256 sna->damage_event = damage->eventBase + XDamageNotify; 18257 18258 if (!sna_glyphs_create(sna)) 18259 goto fail; 18260 18261 if (!sna_gradients_create(sna)) 18262 goto fail; 18263 18264 if (!sna_composite_create(sna)) 18265 goto fail; 18266 18267 return; 18268 18269fail: 18270 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 18271 "Failed to allocate caches, disabling RENDER acceleration\n"); 18272 no_render_init(sna); 18273} 18274 18275static void sna_shm_watch_flush(struct sna *sna, int enable) 18276{ 18277 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 18278 assert(enable); 18279 18280 if (sna->watch_shm_flush == 0) { 18281 DBG(("%s: installing shm watchers\n", __FUNCTION__)); 18282 assert(enable > 0); 18283 18284 if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna)) 18285 return; 18286 18287 sna->watch_shm_flush++; 18288 } 18289 18290 sna->watch_shm_flush += enable; 18291} 18292 18293void sna_watch_flush(struct sna *sna, int enable) 18294{ 18295 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 18296 assert(enable); 18297 18298 if (sna->watch_dri_flush == 0) { 18299 int err = 0; 18300 18301 DBG(("%s: installing watchers\n", __FUNCTION__)); 18302 assert(enable > 0); 18303 18304 if (!sna->damage_event) 18305 return; 18306 18307 if (!AddCallback(&EventCallback, sna_event_callback, sna)) 18308 err = 1; 18309 18310 if (!AddCallback(&FlushCallback, sna_flush_callback, sna)) 18311 err = 1; 18312 18313 if (err) { 18314 xf86DrvMsg(sna->scrn->scrnIndex, X_Error, 18315 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n"); 18316 } 18317 18318 sna->watch_dri_flush++; 18319 } 18320 18321 sna->watch_dri_flush += enable; 18322} 18323 18324void sna_accel_leave(struct sna *sna) 18325{ 18326 DBG(("%s\n", __FUNCTION__)); 18327 sna_scanout_flush(sna); 18328 18329 /* as root we always have permission to render */ 18330 if (geteuid() == 0) 18331 return; 18332 18333 /* as a user, we can only render now if we have a rendernode */ 18334 if (intel_has_render_node(sna->dev)) 18335 return; 18336 18337 /* no longer authorized to use our fd */ 18338 DBG(("%s: dropping render privileges\n", __FUNCTION__)); 18339 18340 kgem_submit(&sna->kgem); 18341 sna->kgem.wedged |= 2; 18342} 18343 18344void sna_accel_enter(struct sna *sna) 18345{ 18346 DBG(("%s\n", __FUNCTION__)); 18347 sna->kgem.wedged &= kgem_is_wedged(&sna->kgem); 18348 kgem_throttle(&sna->kgem); 18349} 18350 18351void sna_accel_close(struct sna *sna) 18352{ 18353 DBG(("%s\n", __FUNCTION__)); 18354 18355 sna_composite_close(sna); 18356 sna_gradients_close(sna); 18357 sna_glyphs_close(sna); 18358 18359 sna_pixmap_expire(sna); 18360 18361 DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna); 18362 DeleteCallback(&FlushCallback, sna_flush_callback, sna); 18363 DeleteCallback(&EventCallback, sna_event_callback, sna); 18364 RemoveNotifyFd(sna->kgem.fd); 18365 18366 kgem_cleanup_cache(&sna->kgem); 18367} 18368 18369void sna_accel_block(struct sna *sna, struct timeval **tv) 18370{ 18371 sigtrap_assert_inactive(); 18372 18373 if (sna->kgem.need_retire) 18374 kgem_retire(&sna->kgem); 18375 kgem_retire__buffers(&sna->kgem); 18376 18377 if (sna->timer_active) 18378 UpdateCurrentTimeIf(); 18379 18380 if (sna->kgem.nbatch && 18381 (sna->kgem.scanout_busy || 18382 kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) { 18383 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 18384 _kgem_submit(&sna->kgem); 18385 } 18386 18387 if (sna->mode.dirty) 18388 sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn)); 18389 18390restart: 18391 if (sna_scanout_do_flush(sna)) 18392 sna_scanout_flush(sna); 18393 assert(sna_accel_scanout(sna) == NULL || 18394 !sna_accel_scanout(sna)->gpu_bo->needs_flush || 18395 sna->timer_active & (1<<(FLUSH_TIMER))); 18396 18397 if (sna_accel_do_throttle(sna)) 18398 sna_accel_throttle(sna); 18399 assert(!sna->kgem.need_retire || 18400 sna->timer_active & (1<<(THROTTLE_TIMER))); 18401 18402 if (sna_accel_do_expire(sna)) 18403 sna_accel_expire(sna); 18404 assert(!sna->kgem.need_expire || 18405 sna->timer_active & (1<<(EXPIRE_TIMER))); 18406 18407 if (sna_accel_do_debug_memory(sna)) 18408 sna_accel_debug_memory(sna); 18409 18410 if (sna->watch_shm_flush == 1) { 18411 DBG(("%s: removing shm watchers\n", __FUNCTION__)); 18412 DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna); 18413 sna->watch_shm_flush = 0; 18414 } 18415 18416 if (sna->watch_dri_flush == 1) { 18417 DBG(("%s: removing dri watchers\n", __FUNCTION__)); 18418 DeleteCallback(&FlushCallback, sna_flush_callback, sna); 18419 DeleteCallback(&EventCallback, sna_event_callback, sna); 18420 sna->watch_dri_flush = 0; 18421 } 18422 18423 if (sna->timer_active & 1) { 18424 int32_t timeout; 18425 18426 DBG(("%s: evaluating timers, active=%x\n", 18427 __FUNCTION__, sna->timer_active)); 18428 18429 timeout = sna->timer_expire[FLUSH_TIMER] - TIME; 18430 DBG(("%s: flush timer expires in %d [%d]\n", 18431 __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER])); 18432 if (timeout < 3) 18433 goto restart; 18434 18435 if (*tv == NULL) { 18436 *tv = &sna->timer_tv; 18437 goto set_tv; 18438 } 18439 if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) { 18440set_tv: 18441 (*tv)->tv_sec = timeout / 1000; 18442 (*tv)->tv_usec = timeout % 1000 * 1000; 18443 } 18444 } 18445 18446 sna->kgem.scanout_busy = false; 18447 18448 if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) { 18449 DBG(("%s hardware acceleration\n", 18450 sna->kgem.wedged ? "Re-enabling" : "Disabling")); 18451 kgem_submit(&sna->kgem); 18452 sna->kgem.wedged = !sna->kgem.wedged; 18453 } 18454} 18455 18456void sna_accel_free(struct sna *sna) 18457{ 18458 DBG(("%s\n", __FUNCTION__)); 18459 sigtrap_assert_inactive(); 18460} 18461