sna_accel.c revision a7f02474
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#undef FontSetPrivate 42 43#include <dixfontstr.h> 44 45#include <mi.h> 46#include <migc.h> 47#include <miline.h> 48#include <micmap.h> 49#ifdef RENDER 50#include <mipict.h> 51#endif 52#include <shmint.h> 53 54#include <X11/extensions/damageproto.h> 55 56#include <sys/time.h> 57#include <sys/mman.h> 58#include <sys/ioctl.h> 59#include <unistd.h> 60 61#ifdef HAVE_VALGRIND 62#include <valgrind.h> 63#include <memcheck.h> 64#endif 65 66#define FAULT_INJECTION 0 67 68#define FORCE_INPLACE 0 69#define FORCE_FALLBACK 0 70#define FORCE_FLUSH 0 71#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */ 72 73#define DEFAULT_PIXMAP_TILING I915_TILING_X 74#define DEFAULT_SCANOUT_TILING I915_TILING_X 75 76#define USE_INPLACE 1 77#define USE_SPANS 0 /* -1 force CPU, 1 force GPU */ 78#define USE_CPU_BO 1 79#define USE_USERPTR_UPLOADS 1 80#define USE_USERPTR_DOWNLOADS 1 81#define USE_COW 1 82#define UNDO 1 83 84#define MIGRATE_ALL 0 85#define DBG_NO_PARTIAL_MOVE_TO_CPU 0 86#define DBG_NO_CPU_UPLOAD 0 87#define DBG_NO_CPU_DOWNLOAD 0 88 89#define ACCEL_FILL_SPANS 1 90#define ACCEL_SET_SPANS 1 91#define ACCEL_PUT_IMAGE 1 92#define ACCEL_GET_IMAGE 1 93#define ACCEL_COPY_AREA 1 94#define ACCEL_COPY_PLANE 1 95#define ACCEL_COPY_WINDOW 1 96#define ACCEL_POLY_POINT 1 97#define ACCEL_POLY_LINE 1 98#define ACCEL_POLY_SEGMENT 1 99#define ACCEL_POLY_RECTANGLE 1 100#define ACCEL_POLY_ARC 1 101#define ACCEL_POLY_FILL_POLYGON 1 102#define ACCEL_POLY_FILL_RECT 1 103#define ACCEL_POLY_FILL_ARC 1 104#define ACCEL_POLY_TEXT8 1 105#define ACCEL_POLY_TEXT16 1 106#define ACCEL_POLY_GLYPH 1 107#define ACCEL_IMAGE_TEXT8 1 108#define ACCEL_IMAGE_TEXT16 1 109#define ACCEL_IMAGE_GLYPH 1 110#define ACCEL_PUSH_PIXELS 1 111 112#define NO_TILE_8x8 0 113#define NO_STIPPLE_8x8 0 114 115#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) 116#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) 117#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) 118 119#define IS_CLIPPED 0x2 120#define RECTILINEAR 0x4 121#define OVERWRITES 0x8 122 123#if XFONT2_CLIENT_FUNCS_VERSION >= 1 124#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index() 125#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data) 126#endif 127 128#if 0 129static void __sna_fallback_flush(DrawablePtr d) 130{ 131 PixmapPtr pixmap = get_drawable_pixmap(d); 132 struct sna *sna = to_sna_from_pixmap(pixmap); 133 struct sna_pixmap *priv; 134 BoxRec box; 135 PixmapPtr tmp; 136 int i, j; 137 char *src, *dst; 138 139 DBG(("%s: uploading CPU damage...\n", __FUNCTION__)); 140 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 141 if (priv == NULL) 142 return; 143 144 DBG(("%s: downloading GPU damage...\n", __FUNCTION__)); 145 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 146 return; 147 148 box.x1 = box.y1 = 0; 149 box.x2 = pixmap->drawable.width; 150 box.y2 = pixmap->drawable.height; 151 152 tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen, 153 pixmap->drawable.width, 154 pixmap->drawable.height, 155 pixmap->drawable.depth, 156 0); 157 158 DBG(("%s: comparing with direct read...\n", __FUNCTION__)); 159 sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1); 160 161 src = pixmap->devPrivate.ptr; 162 dst = tmp->devPrivate.ptr; 163 for (i = 0; i < tmp->drawable.height; i++) { 164 if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) { 165 for (j = 0; src[j] == dst[j]; j++) 166 ; 167 ERR(("mismatch at (%d, %d)\n", 168 8*j / tmp->drawable.bitsPerPixel, i)); 169 abort(); 170 } 171 src += pixmap->devKind; 172 dst += tmp->devKind; 173 } 174 tmp->drawable.pScreen->DestroyPixmap(tmp); 175} 176#define FALLBACK_FLUSH(d) __sna_fallback_flush(d) 177#else 178#define FALLBACK_FLUSH(d) 179#endif 180 181static int sna_font_key; 182 183static const uint8_t copy_ROP[] = { 184 ROP_0, /* GXclear */ 185 ROP_DSa, /* GXand */ 186 ROP_SDna, /* GXandReverse */ 187 ROP_S, /* GXcopy */ 188 ROP_DSna, /* GXandInverted */ 189 ROP_D, /* GXnoop */ 190 ROP_DSx, /* GXxor */ 191 ROP_DSo, /* GXor */ 192 ROP_DSon, /* GXnor */ 193 ROP_DSxn, /* GXequiv */ 194 ROP_Dn, /* GXinvert */ 195 ROP_SDno, /* GXorReverse */ 196 ROP_Sn, /* GXcopyInverted */ 197 ROP_DSno, /* GXorInverted */ 198 ROP_DSan, /* GXnand */ 199 ROP_1 /* GXset */ 200}; 201static const uint8_t fill_ROP[] = { 202 ROP_0, 203 ROP_DPa, 204 ROP_PDna, 205 ROP_P, 206 ROP_DPna, 207 ROP_D, 208 ROP_DPx, 209 ROP_DPo, 210 ROP_DPon, 211 ROP_PDxn, 212 ROP_Dn, 213 ROP_PDno, 214 ROP_Pn, 215 ROP_DPno, 216 ROP_DPan, 217 ROP_1 218}; 219 220static const GCOps sna_gc_ops; 221static const GCOps sna_gc_ops__cpu; 222static GCOps sna_gc_ops__tmp; 223static const GCFuncs sna_gc_funcs; 224static const GCFuncs sna_gc_funcs__cpu; 225 226static void sna_shm_watch_flush(struct sna *sna, int enable); 227static void 228sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect); 229 230static inline void region_set(RegionRec *r, const BoxRec *b) 231{ 232 r->extents = *b; 233 r->data = NULL; 234} 235 236static inline bool region_maybe_clip(RegionRec *r, RegionRec *clip) 237{ 238 if (clip->data && !RegionIntersect(r, r, clip)) 239 return false; 240 241 return !box_empty(&r->extents); 242} 243 244static inline bool region_is_singular(const RegionRec *r) 245{ 246 return r->data == NULL; 247} 248 249static inline bool region_is_unclipped(const RegionRec *r, int w, int h) 250{ 251 return (region_is_singular(r) && 252 w == r->extents.x2 - r->extents.x1 && 253 h == r->extents.y2 - r->extents.y1); 254} 255 256typedef struct box32 { 257 int32_t x1, y1, x2, y2; 258} Box32Rec; 259 260#define PM_IS_SOLID(_draw, _pm) \ 261 (((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth)) 262 263#ifndef NDEBUG 264static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function) 265{ 266 if (box->x1 < 0 || box->y1 < 0 || 267 box->x2 > pixmap->drawable.width || 268 box->y2 > pixmap->drawable.height) 269 { 270 FatalError("%s: damage box [(%d, %d), (%d, %d)] is beyond the pixmap=%ld size=%dx%d\n", 271 function, box->x1, box->y1, box->x2, box->y2, 272 pixmap->drawable.serialNumber, 273 pixmap->drawable.width, 274 pixmap->drawable.height); 275 } 276} 277 278static void 279_assert_pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage, const char *function) 280{ 281 if (damage == NULL) 282 return; 283 284 _assert_pixmap_contains_box(pixmap, &DAMAGE_PTR(damage)->extents, function); 285} 286#define assert_pixmap_contains_damage(p,d) _assert_pixmap_contains_damage(p, d, __FUNCTION__) 287#else 288#define assert_pixmap_contains_damage(p,d) 289#endif 290 291#define __assert_pixmap_damage(p) do { \ 292 struct sna_pixmap *priv__ = sna_pixmap(p); \ 293 if (priv__) { \ 294 assert(priv__->gpu_damage == NULL || priv__->gpu_bo); \ 295 assert(priv__->gpu_bo == NULL || priv__->gpu_bo->refcnt); \ 296 assert(priv__->cpu_bo == NULL || priv__->cpu_bo->refcnt); \ 297 assert_pixmap_contains_damage(p, priv__->gpu_damage); \ 298 assert_pixmap_contains_damage(p, priv__->cpu_damage); \ 299 assert_pixmap_map(p, priv__); \ 300 } \ 301} while (0) 302 303#ifdef DEBUG_PIXMAP 304static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function) 305{ 306 BoxRec b = *box; 307 b.x1 += dx; b.x2 += dx; 308 b.y1 += dy; b.y2 += dy; 309 _assert_pixmap_contains_box(pixmap, &b, function); 310} 311 312static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function) 313{ 314 BoxRec extents; 315 316 extents = *box; 317 while (--n) { 318 ++box; 319 320 if (box->x1 < extents.x1) 321 extents.x1 = box->x1; 322 if (box->x2 > extents.x2) 323 extents.x2 = box->x2; 324 325 if (box->y1 < extents.y1) 326 extents.y1 = box->y1; 327 if (box->y2 > extents.y2) 328 extents.y2 = box->y2; 329 } 330 extents.x1 += dx; 331 extents.x2 += dx; 332 extents.y1 += dy; 333 extents.y2 += dy; 334 _assert_pixmap_contains_box(pixmap, &extents, function); 335} 336 337 338static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function) 339{ 340 BoxRec extents; 341 342 extents.x2 = extents.x1 = pt->x; 343 extents.y2 = extents.y1 = pt->y; 344 while (--n) { 345 ++pt; 346 347 if (pt->x < extents.x1) 348 extents.x1 = pt->x; 349 else if (pt->x > extents.x2) 350 extents.x2 = pt->x; 351 352 if (pt->y < extents.y1) 353 extents.y1 = pt->y; 354 else if (pt->y > extents.y2) 355 extents.y2 = pt->y; 356 } 357 extents.x1 += dx; 358 extents.x2 += dx + 1; 359 extents.y1 += dy; 360 extents.y2 += dy + 1; 361 _assert_pixmap_contains_box(pixmap, &extents, function); 362} 363 364static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function) 365{ 366 if (box->x1 < drawable->x || 367 box->y1 < drawable->y || 368 box->x2 > drawable->x + drawable->width || 369 box->y2 > drawable->y + drawable->height) 370 { 371 FatalError("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n", 372 function, 373 box->x1, box->y1, box->x2, box->y2, 374 drawable->x, drawable->y, 375 drawable->width, drawable->height); 376 } 377} 378 379static void assert_pixmap_damage(PixmapPtr p) 380{ 381 struct sna_pixmap *priv; 382 RegionRec reg, cpu, gpu; 383 384 priv = sna_pixmap(p); 385 if (priv == NULL) 386 return; 387 388 __assert_pixmap_damage(p); 389 390 if (priv->clear) { 391 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 392 assert(priv->cpu_damage == NULL); 393 } 394 395 if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) { 396 /* special upload buffer */ 397 assert(priv->gpu_bo && priv->gpu_bo->proxy); 398 assert(priv->cpu_bo == NULL); 399 return; 400 } 401 402 assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL); 403 assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL); 404 405 /* Avoid reducing damage to minimise interferrence */ 406 RegionNull(®); 407 RegionNull(&gpu); 408 RegionNull(&cpu); 409 410 if (priv->gpu_damage) 411 _sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu); 412 413 if (priv->cpu_damage) 414 _sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu); 415 416 RegionIntersect(®, &cpu, &gpu); 417 assert(RegionNil(®)); 418 419 RegionUninit(®); 420 RegionUninit(&gpu); 421 RegionUninit(&cpu); 422} 423 424#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 425#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__) 426#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__) 427#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__) 428#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__) 429 430#else 431#define assert_pixmap_contains_box(p, b) 432#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) 433#define assert_pixmap_contains_boxes(p, b, n, x, y) 434#define assert_pixmap_contains_points(p, pt, n, x, y) 435#define assert_drawable_contains_box(d, b) 436#ifndef NDEBUG 437#define assert_pixmap_damage(p) __assert_pixmap_damage(p) 438#else 439#define assert_pixmap_damage(p) 440#endif 441#endif 442 443jmp_buf sigjmp[4]; 444volatile sig_atomic_t sigtrap; 445 446static int sigtrap_handler(int sig) 447{ 448 /* XXX rate-limited squawk? */ 449 DBG(("%s(sig=%d) sigtrap=%d\n", __FUNCTION__, sig, sigtrap)); 450 sna_threads_trap(sig); 451 452 if (sigtrap) 453 siglongjmp(sigjmp[--sigtrap], sig); 454 455 return -1; 456} 457 458static void sigtrap_init(void) 459{ 460#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 461 OsRegisterSigWrapper(sigtrap_handler); 462#endif 463} 464 465inline static bool 466sna_fill_init_blt(struct sna_fill_op *fill, 467 struct sna *sna, 468 PixmapPtr pixmap, 469 struct kgem_bo *bo, 470 uint8_t alu, 471 uint32_t pixel, 472 unsigned flags) 473{ 474 return sna->render.fill(sna, alu, pixmap, bo, pixel, flags, fill); 475} 476 477static bool 478sna_copy_init_blt(struct sna_copy_op *copy, 479 struct sna *sna, 480 PixmapPtr src, struct kgem_bo *src_bo, 481 PixmapPtr dst, struct kgem_bo *dst_bo, 482 uint8_t alu) 483{ 484 memset(copy, 0, sizeof(*copy)); 485 return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); 486} 487 488static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv) 489{ 490 DBG(("%s: handle=%d (pinned? %d)\n", __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->pinned)); 491 assert(priv->gpu_damage == NULL || priv->gpu_bo); 492 493 if (priv->cow) 494 sna_pixmap_undo_cow(sna, priv, MOVE_WRITE); 495 assert(priv->cow == NULL); 496 497 if (priv->move_to_gpu) { 498 sna_pixmap_discard_shadow_damage(priv, NULL); 499 priv->move_to_gpu(sna, priv, MOVE_WRITE); 500 } 501 502 sna_damage_destroy(&priv->gpu_damage); 503 priv->clear = false; 504 505 if (priv->gpu_bo) { 506 if (!priv->pinned) { 507 assert(!priv->flush); 508 assert(!priv->move_to_gpu); 509 sna_pixmap_unmap(priv->pixmap, priv); 510 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 511 priv->gpu_bo = NULL; 512 } else 513 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 514 } 515 516 /* and reset the upload counter */ 517 priv->source_count = SOURCE_BIAS; 518} 519 520static bool must_check 521sna_pixmap_alloc_cpu(struct sna *sna, 522 PixmapPtr pixmap, 523 struct sna_pixmap *priv, 524 unsigned flags) 525{ 526 /* Restore after a GTT mapping? */ 527 assert(priv->gpu_damage == NULL || priv->gpu_bo); 528 assert(!priv->shm); 529 if (priv->ptr) 530 goto done; 531 532 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 533 assert(priv->stride); 534 535 if (priv->create & KGEM_CAN_CREATE_CPU) { 536 unsigned hint; 537 538 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__, 539 pixmap->drawable.width, pixmap->drawable.height)); 540 541 hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE; 542 if ((flags & MOVE_ASYNC_HINT) || 543 (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu)) 544 hint = 0; 545 546 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem, 547 pixmap->drawable.width, 548 pixmap->drawable.height, 549 pixmap->drawable.bitsPerPixel, 550 hint); 551 if (priv->cpu_bo) { 552 priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 553 if (priv->ptr) { 554 DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__, 555 priv->cpu_bo->handle, priv->cpu_bo->snoop)); 556 priv->stride = priv->cpu_bo->pitch; 557#ifdef DEBUG_MEMORY 558 sna->debug_memory.cpu_bo_allocs++; 559 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 560#endif 561 } else { 562 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 563 priv->cpu_bo = NULL; 564 } 565 } 566 } 567 568 if (priv->ptr == NULL) { 569 DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n", 570 __FUNCTION__, priv->stride * pixmap->drawable.height)); 571 priv->ptr = malloc(priv->stride * pixmap->drawable.height); 572 } 573 574done: 575 assert(priv->stride); 576 assert(!priv->mapped); 577 pixmap->devPrivate.ptr = PTR(priv->ptr); 578 pixmap->devKind = priv->stride; 579 return priv->ptr != NULL; 580} 581 582static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 583{ 584 if (priv->cpu_bo) { 585 DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n", 586 __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo))); 587#ifdef DEBUG_MEMORY 588 sna->debug_memory.cpu_bo_allocs--; 589 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 590#endif 591 if (priv->cpu_bo->flush) { 592 assert(!priv->cpu_bo->reusable); 593 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 594 sna_shm_watch_flush(sna, -1); 595 } 596 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 597 } else if (!IS_STATIC_PTR(priv->ptr)) 598 free(priv->ptr); 599} 600 601static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool active) 602{ 603 if (active) 604 return false; 605 606 if (IS_STATIC_PTR(priv->ptr)) 607 return false; 608 609 if (priv->ptr == NULL) 610 return true; 611 612 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, priv->pixmap->drawable.serialNumber)); 613 __sna_pixmap_free_cpu(sna, priv); 614 615 priv->cpu_bo = NULL; 616 priv->ptr = NULL; 617 618 if (priv->mapped == MAPPED_NONE) 619 priv->pixmap->devPrivate.ptr = NULL; 620 621 return true; 622} 623 624static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap) 625{ 626#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE 627 return I915_TILING_NONE; 628#elif DEFAULT_PIXMAP_TILING == I915_TILING_X 629 return I915_TILING_X; 630#else 631 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ 632 if (sna->kgem.gen == 021) 633 return I915_TILING_X; 634 635 /* Only on later generations was the render pipeline 636 * more flexible than the BLT. So on gen2/3, prefer to 637 * keep large objects accessible through the BLT. 638 */ 639 if (sna->kgem.gen < 040 && 640 (pixmap->drawable.width > sna->render.max_3d_size || 641 pixmap->drawable.height > sna->render.max_3d_size)) 642 return I915_TILING_X; 643 644 return I915_TILING_Y; 645#endif 646} 647 648pure static uint32_t sna_pixmap_default_tiling(struct sna *sna, PixmapPtr pixmap) 649{ 650 /* Also adjust tiling if it is not supported or likely to 651 * slow us down, 652 */ 653 return kgem_choose_tiling(&sna->kgem, 654 default_tiling(sna, pixmap), 655 pixmap->drawable.width, 656 pixmap->drawable.height, 657 pixmap->drawable.bitsPerPixel); 658} 659 660struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) 661{ 662 struct sna_pixmap *priv = sna_pixmap(pixmap); 663 struct sna *sna = to_sna_from_pixmap(pixmap); 664 struct kgem_bo *bo; 665 BoxRec box; 666 667 DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n", 668 __FUNCTION__, priv->gpu_bo->tiling, tiling, 669 pixmap->drawable.width, pixmap->drawable.height)); 670 assert(priv->gpu_damage == NULL || priv->gpu_bo); 671 assert(priv->gpu_bo->tiling != tiling); 672 673 if (priv->pinned) { 674 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 675 return NULL; 676 } 677 678 if (wedged(sna)) { 679 DBG(("%s: can't convert bo, wedged\n", __FUNCTION__)); 680 return NULL; 681 } 682 683 assert_pixmap_damage(pixmap); 684 assert(!priv->move_to_gpu); 685 686 bo = kgem_create_2d(&sna->kgem, 687 pixmap->drawable.width, 688 pixmap->drawable.height, 689 pixmap->drawable.bitsPerPixel, 690 tiling, 0); 691 if (bo == NULL) { 692 DBG(("%s: allocation failed\n", __FUNCTION__)); 693 return NULL; 694 } 695 696 if (bo->tiling == priv->gpu_bo->tiling) { 697 DBG(("%s: tiling request failed\n", __FUNCTION__)); 698 kgem_bo_destroy(&sna->kgem, bo); 699 return NULL; 700 } 701 702 box.x1 = box.y1 = 0; 703 box.x2 = pixmap->drawable.width; 704 box.y2 = pixmap->drawable.height; 705 706 if (!sna->render.copy_boxes(sna, GXcopy, 707 &pixmap->drawable, priv->gpu_bo, 0, 0, 708 &pixmap->drawable, bo, 0, 0, 709 &box, 1, 0)) { 710 DBG(("%s: copy failed\n", __FUNCTION__)); 711 kgem_bo_destroy(&sna->kgem, bo); 712 return NULL; 713 } 714 715 sna_pixmap_unmap(pixmap, priv); 716 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 717 718 return priv->gpu_bo = bo; 719} 720 721static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna) 722{ 723 ((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna; 724 assert(sna_pixmap(pixmap) == sna); 725} 726 727static struct sna_pixmap * 728_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) 729{ 730 list_init(&priv->flush_list); 731 list_init(&priv->cow_list); 732 priv->source_count = SOURCE_BIAS; 733 priv->pixmap = pixmap; 734 735 return priv; 736} 737 738static struct sna_pixmap * 739_sna_pixmap_reset(PixmapPtr pixmap) 740{ 741 struct sna_pixmap *priv; 742 743 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 744 assert(pixmap->drawable.class == 0); 745 assert(pixmap->drawable.x == 0); 746 assert(pixmap->drawable.y == 0); 747 748 priv = sna_pixmap(pixmap); 749 assert(priv != NULL); 750 751 memset(priv, 0, sizeof(*priv)); 752 return _sna_pixmap_init(priv, pixmap); 753} 754 755static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) 756{ 757 struct sna_pixmap *priv; 758 759 priv = calloc(1, sizeof(*priv)); 760 if (!priv) 761 return NULL; 762 763 sna_set_pixmap(pixmap, priv); 764 return _sna_pixmap_init(priv, pixmap); 765} 766 767struct sna_pixmap *sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) 768{ 769 struct sna_pixmap *priv; 770 771 assert(bo); 772 assert(bo->proxy == NULL); 773 assert(bo->unique_id); 774 775 priv = sna_pixmap_attach(pixmap); 776 if (!priv) 777 return NULL; 778 779 DBG(("%s: attaching %s handle=%d to pixmap=%ld\n", 780 __FUNCTION__, bo->snoop ? "CPU" : "GPU", bo->handle, pixmap->drawable.serialNumber)); 781 782 assert(!priv->mapped); 783 assert(!priv->move_to_gpu); 784 785 if (bo->snoop) { 786 priv->cpu_bo = bo; 787 sna_damage_all(&priv->cpu_damage, pixmap); 788 } else { 789 priv->gpu_bo = bo; 790 sna_damage_all(&priv->gpu_damage, pixmap); 791 } 792 793 return priv; 794} 795 796static int bits_per_pixel(int depth) 797{ 798 switch (depth) { 799 case 1: return 1; 800 case 4: 801 case 8: return 8; 802 case 15: 803 case 16: return 16; 804 case 24: 805 case 30: 806 case 32: return 32; 807 default: return 0; 808 } 809} 810static PixmapPtr 811create_pixmap(struct sna *sna, ScreenPtr screen, 812 int width, int height, int depth, 813 unsigned usage_hint) 814{ 815 PixmapPtr pixmap; 816 size_t datasize; 817 size_t stride; 818 int base, bpp; 819 820 bpp = bits_per_pixel(depth); 821 if (bpp == 0) 822 return NullPixmap; 823 824 stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 825 if (stride / 4 > 32767 || height > 32767) 826 return NullPixmap; 827 828 datasize = height * stride; 829 base = screen->totalPixmapSize; 830 if (datasize && base & 15) { 831 int adjust = 16 - (base & 15); 832 base += adjust; 833 datasize += adjust; 834 } 835 836 DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n", 837 __FUNCTION__, width, height, depth, bpp, (long)datasize)); 838 pixmap = AllocatePixmap(screen, datasize); 839 if (!pixmap) 840 return NullPixmap; 841 842 ((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna; 843 assert(to_sna_from_pixmap(pixmap) == sna); 844 845 pixmap->drawable.type = DRAWABLE_PIXMAP; 846 pixmap->drawable.class = 0; 847 pixmap->drawable.pScreen = screen; 848 pixmap->drawable.depth = depth; 849 pixmap->drawable.bitsPerPixel = bpp; 850 pixmap->drawable.id = 0; 851 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 852 pixmap->drawable.x = 0; 853 pixmap->drawable.y = 0; 854 pixmap->drawable.width = width; 855 pixmap->drawable.height = height; 856 pixmap->devKind = stride; 857 pixmap->refcnt = 1; 858 pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL; 859 860#ifdef COMPOSITE 861 pixmap->screen_x = 0; 862 pixmap->screen_y = 0; 863#endif 864 865 pixmap->usage_hint = usage_hint; 866#if DEBUG_MEMORY 867 sna->debug_memory.pixmap_allocs++; 868#endif 869 870 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 871 __FUNCTION__, 872 pixmap->drawable.serialNumber, 873 pixmap->usage_hint, 874 pixmap->drawable.width, 875 pixmap->drawable.height)); 876 877 return pixmap; 878} 879 880static PixmapPtr 881__pop_freed_pixmap(struct sna *sna) 882{ 883 PixmapPtr pixmap; 884 885 assert(sna->freed_pixmap); 886 887 pixmap = sna->freed_pixmap; 888 sna->freed_pixmap = pixmap->devPrivate.ptr; 889 890 DBG(("%s: reusing freed pixmap=%ld header\n", 891 __FUNCTION__, pixmap->drawable.serialNumber)); 892 893 assert(pixmap->refcnt == 0); 894 assert(pixmap->devKind = 0xdeadbeef); 895 assert(sna_pixmap(pixmap)); 896 assert(sna_pixmap(pixmap)->header); 897 898#if DEBUG_MEMORY 899 sna->debug_memory.pixmap_cached--; 900#endif 901 902 return pixmap; 903} 904 905inline static PixmapPtr 906create_pixmap_hdr(struct sna *sna, ScreenPtr screen, 907 int width, int height, int depth, int usage, 908 struct sna_pixmap **priv) 909{ 910 PixmapPtr pixmap; 911 912 if (sna->freed_pixmap == NULL) { 913 pixmap = create_pixmap(sna, screen, 0, 0, depth, usage); 914 if (pixmap == NullPixmap) 915 return NullPixmap; 916 917 *priv = sna_pixmap_attach(pixmap); 918 if (!*priv) { 919 FreePixmap(pixmap); 920 return NullPixmap; 921 } 922 } else { 923 pixmap = __pop_freed_pixmap(sna); 924 *priv = _sna_pixmap_reset(pixmap); 925 926 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 927 assert(pixmap->drawable.class == 0); 928 assert(pixmap->drawable.pScreen == screen); 929 assert(pixmap->drawable.x == 0); 930 assert(pixmap->drawable.y == 0); 931 932 pixmap->drawable.id = 0; 933 934 pixmap->drawable.depth = depth; 935 pixmap->drawable.bitsPerPixel = bits_per_pixel(depth); 936 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 937 938 pixmap->devKind = 0; 939 pixmap->devPrivate.ptr = NULL; 940 941#ifdef COMPOSITE 942 pixmap->screen_x = 0; 943 pixmap->screen_y = 0; 944#endif 945 946#if DEBUG_MEMORY 947 sna->debug_memory.pixmap_allocs++; 948#endif 949 950 pixmap->refcnt = 1; 951 } 952 953 DBG(("%s: pixmap=%ld, width=%d, height=%d, usage=%d\n", __FUNCTION__, 954 pixmap->drawable.serialNumber, width, height, usage)); 955 pixmap->drawable.width = width; 956 pixmap->drawable.height = height; 957 pixmap->usage_hint = usage; 958 959 (*priv)->header = true; 960 return pixmap; 961} 962 963static PixmapPtr 964sna_pixmap_create_shm(ScreenPtr screen, 965 int width, int height, int depth, 966 char *addr) 967{ 968 struct sna *sna = to_sna_from_screen(screen); 969 int bpp = bits_per_pixel(depth); 970 int pitch = PixmapBytePad(width, depth); 971 struct sna_pixmap *priv; 972 PixmapPtr pixmap; 973 974 DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n", 975 __FUNCTION__, width, height, depth, bpp, pitch)); 976 977 if (wedged(sna) || bpp == 0 || pitch*height < 4096) { 978fallback: 979 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 980 if (pixmap == NULL) 981 return NULL; 982 983 if (!screen->ModifyPixmapHeader(pixmap, width, height, depth, 984 bpp, pitch, addr)) { 985 screen->DestroyPixmap(pixmap); 986 return NULL; 987 } 988 989 return pixmap; 990 } 991 992 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, 0, &priv); 993 if (pixmap == NullPixmap) { 994 DBG(("%s: allocation failed\n", __FUNCTION__)); 995 goto fallback; 996 } 997 998 priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false); 999 if (priv->cpu_bo == NULL) { 1000 DBG(("%s: mapping SHM segment failed\n", __FUNCTION__)); 1001 sna_pixmap_destroy(pixmap); 1002 goto fallback; 1003 } 1004 priv->cpu_bo->pitch = pitch; 1005 kgem_bo_mark_unreusable(priv->cpu_bo); 1006 sna_shm_watch_flush(sna, 1); 1007#ifdef DEBUG_MEMORY 1008 sna->debug_memory.cpu_bo_allocs++; 1009 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 1010#endif 1011 1012 /* Be wary as we cannot cache SHM Pixmap in our freed cache */ 1013 priv->header = false; 1014 priv->cpu = true; 1015 priv->shm = true; 1016 priv->stride = pitch; 1017 priv->ptr = MAKE_STATIC_PTR(addr); 1018 sna_damage_all(&priv->cpu_damage, pixmap); 1019 1020 pixmap->devKind = pitch; 1021 pixmap->devPrivate.ptr = addr; 1022 1023 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1024 __FUNCTION__, 1025 pixmap->drawable.serialNumber, 1026 pixmap->drawable.width, 1027 pixmap->drawable.height, 1028 pixmap->usage_hint)); 1029 return pixmap; 1030} 1031 1032PixmapPtr 1033sna_pixmap_create_unattached(ScreenPtr screen, 1034 int width, int height, int depth) 1035{ 1036 return create_pixmap(to_sna_from_screen(screen), 1037 screen, width, height, depth, 1038 -1); 1039} 1040 1041static PixmapPtr 1042sna_pixmap_create_scratch(ScreenPtr screen, 1043 int width, int height, int depth, 1044 uint32_t tiling) 1045{ 1046 struct sna *sna = to_sna_from_screen(screen); 1047 struct sna_pixmap *priv; 1048 PixmapPtr pixmap; 1049 int bpp; 1050 1051 DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__, 1052 width, height, depth, tiling)); 1053 1054 bpp = bits_per_pixel(depth); 1055 if (tiling == I915_TILING_Y && 1056 (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0) 1057 tiling = I915_TILING_X; 1058 1059 if (tiling == I915_TILING_Y && 1060 (width > sna->render.max_3d_size || 1061 height > sna->render.max_3d_size)) 1062 tiling = I915_TILING_X; 1063 1064 tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp); 1065 1066 /* you promise never to access this via the cpu... */ 1067 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, &priv); 1068 if (pixmap == NullPixmap) 1069 return NullPixmap; 1070 1071 priv->stride = PixmapBytePad(width, depth); 1072 1073 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1074 width, height, bpp, tiling, 1075 CREATE_TEMPORARY); 1076 if (priv->gpu_bo == NULL) { 1077 free(priv); 1078 FreePixmap(pixmap); 1079 return NullPixmap; 1080 } 1081 1082 sna_damage_all(&priv->gpu_damage, pixmap); 1083 1084 assert(to_sna_from_pixmap(pixmap) == sna); 1085 assert(pixmap->drawable.pScreen == screen); 1086 assert(pixmap->refcnt == 1); 1087 1088 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1089 __FUNCTION__, 1090 pixmap->drawable.serialNumber, 1091 pixmap->drawable.width, 1092 pixmap->drawable.height, 1093 pixmap->usage_hint)); 1094 return pixmap; 1095} 1096 1097static unsigned small_copy(const RegionRec *region) 1098{ 1099 if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) { 1100 DBG(("%s: region:%dx%d\n", __FUNCTION__, 1101 (region->extents.x2 - region->extents.x1), 1102 (region->extents.y2 - region->extents.y1))); 1103 return COPY_SMALL; 1104 } 1105 1106 return 0; 1107} 1108 1109#ifdef CREATE_PIXMAP_USAGE_SHARED 1110static Bool 1111sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle) 1112{ 1113 struct sna *sna = to_sna_from_pixmap(pixmap); 1114 struct sna_pixmap *priv; 1115 int fd; 1116 1117 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1118 1119 priv = sna_pixmap_move_to_gpu(pixmap, 1120 MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_PRIME | __MOVE_FORCE); 1121 if (priv == NULL) 1122 return FALSE; 1123 1124 assert(!priv->shm); 1125 assert(priv->gpu_bo); 1126 assert(priv->stride); 1127 1128 /* XXX negotiate format and stride restrictions */ 1129 if (priv->gpu_bo->tiling != I915_TILING_NONE || 1130 priv->gpu_bo->pitch & 255) { 1131 struct kgem_bo *bo; 1132 BoxRec box; 1133 1134 DBG(("%s: removing tiling %d, and aligning pitch %d for %dx%d pixmap=%ld\n", 1135 __FUNCTION__, priv->gpu_bo->tiling, priv->gpu_bo->pitch, 1136 pixmap->drawable.width, pixmap->drawable.height, 1137 pixmap->drawable.serialNumber)); 1138 1139 if (priv->pinned) { 1140 DBG(("%s: can't convert pinned %x bo\n", __FUNCTION__, 1141 priv->pinned)); 1142 return FALSE; 1143 } 1144 1145 assert_pixmap_damage(pixmap); 1146 1147 bo = kgem_create_2d(&sna->kgem, 1148 pixmap->drawable.width, 1149 pixmap->drawable.height, 1150 pixmap->drawable.bitsPerPixel, 1151 I915_TILING_NONE, 1152 CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT); 1153 if (bo == NULL) { 1154 DBG(("%s: allocation failed\n", __FUNCTION__)); 1155 return FALSE; 1156 } 1157 1158 box.x1 = box.y1 = 0; 1159 box.x2 = pixmap->drawable.width; 1160 box.y2 = pixmap->drawable.height; 1161 1162 assert(!wedged(sna)); /* XXX */ 1163 if (!sna->render.copy_boxes(sna, GXcopy, 1164 &pixmap->drawable, priv->gpu_bo, 0, 0, 1165 &pixmap->drawable, bo, 0, 0, 1166 &box, 1, 0)) { 1167 DBG(("%s: copy failed\n", __FUNCTION__)); 1168 kgem_bo_destroy(&sna->kgem, bo); 1169 return FALSE; 1170 } 1171 1172 sna_pixmap_unmap(pixmap, priv); 1173 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1174 priv->gpu_bo = bo; 1175 } 1176 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1177 assert((priv->gpu_bo->pitch & 255) == 0); 1178 1179 /* And export the bo->pitch via pixmap->devKind */ 1180 if (!priv->mapped) { 1181 void *ptr; 1182 1183 ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1184 if (ptr == NULL) 1185 return FALSE; 1186 1187 pixmap->devPrivate.ptr = ptr; 1188 pixmap->devKind = priv->gpu_bo->pitch; 1189 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1190 } 1191 assert_pixmap_map(pixmap, priv); 1192 1193 fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo); 1194 if (fd == -1) 1195 return FALSE; 1196 1197 priv->pinned |= PIN_PRIME; 1198 1199 *fd_handle = (void *)(intptr_t)fd; 1200 return TRUE; 1201} 1202 1203static Bool 1204sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle) 1205{ 1206 struct sna *sna = to_sna_from_pixmap(pixmap); 1207 struct sna_pixmap *priv; 1208 struct kgem_bo *bo; 1209 1210 DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n", 1211 __FUNCTION__, pixmap->drawable.serialNumber, 1212 pixmap->drawable.width, pixmap->drawable.height, 1213 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, 1214 pixmap->devKind)); 1215 1216 priv = sna_pixmap(pixmap); 1217 if (priv == NULL) 1218 return FALSE; 1219 1220 if (priv->pinned & ~PIN_PRIME) 1221 return FALSE; 1222 1223 assert(!priv->flush); 1224 1225 if (priv->gpu_bo) { 1226 priv->clear = false; 1227 sna_damage_destroy(&priv->gpu_damage); 1228 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1229 priv->gpu_bo = NULL; 1230 priv->pinned = 0; 1231 } 1232 1233 assert(!priv->pinned); 1234 1235 assert(priv->cpu_bo == NULL); 1236 assert(priv->cpu_damage == NULL); 1237 1238 assert(priv->gpu_bo == NULL); 1239 assert(priv->gpu_damage == NULL); 1240 1241 bo = kgem_create_for_prime(&sna->kgem, 1242 (intptr_t)fd_handle, 1243 pixmap->devKind * pixmap->drawable.height); 1244 if (bo == NULL) 1245 return FALSE; 1246 1247 sna_damage_all(&priv->gpu_damage, pixmap); 1248 1249 bo->pitch = pixmap->devKind; 1250 priv->stride = pixmap->devKind; 1251 1252 assert(!priv->mapped); 1253 priv->gpu_bo = bo; 1254 priv->pinned |= PIN_PRIME; 1255 1256 close((intptr_t)fd_handle); 1257 return TRUE; 1258} 1259 1260static PixmapPtr 1261sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, 1262 int width, int height, int depth) 1263{ 1264 PixmapPtr pixmap; 1265 struct sna_pixmap *priv; 1266 1267 DBG(("%s: width=%d, height=%d, depth=%d\n", 1268 __FUNCTION__, width, height, depth)); 1269 1270 /* Create a stub to be attached later */ 1271 pixmap = create_pixmap_hdr(sna, screen, 1272 width, height, depth, 0, 1273 &priv); 1274 if (pixmap == NullPixmap) 1275 return NullPixmap; 1276 1277 assert(!priv->mapped); 1278 priv->stride = 0; 1279 priv->create = 0; 1280 1281 if (width|height) { 1282 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1283 width, height, 1284 pixmap->drawable.bitsPerPixel, 1285 I915_TILING_NONE, 1286 CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT); 1287 if (priv->gpu_bo == NULL) { 1288 free(priv); 1289 FreePixmap(pixmap); 1290 return NullPixmap; 1291 } 1292 1293 /* minimal interface for sharing is linear, 256 byte pitch */ 1294 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1295 assert((priv->gpu_bo->pitch & 255) == 0); 1296 1297 pixmap->devPrivate.ptr = 1298 kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1299 if (pixmap->devPrivate.ptr == NULL) { 1300 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1301 free(priv); 1302 FreePixmap(pixmap); 1303 return FALSE; 1304 } 1305 1306 pixmap->devKind = priv->gpu_bo->pitch; 1307 1308 priv->stride = priv->gpu_bo->pitch; 1309 priv->mapped = pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 1310 assert_pixmap_map(pixmap, priv); 1311 1312 sna_damage_all(&priv->gpu_damage, pixmap); 1313 } 1314 1315 return pixmap; 1316} 1317#endif 1318 1319static PixmapPtr sna_create_pixmap(ScreenPtr screen, 1320 int width, int height, int depth, 1321 unsigned int usage) 1322{ 1323 struct sna *sna = to_sna_from_screen(screen); 1324 PixmapPtr pixmap; 1325 struct sna_pixmap *priv; 1326 unsigned flags; 1327 int pad; 1328 void *ptr; 1329 1330 DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__, 1331 width, height, depth, usage)); 1332 1333#ifdef CREATE_PIXMAP_USAGE_SHARED 1334 if (usage == CREATE_PIXMAP_USAGE_SHARED) 1335 return sna_create_pixmap_shared(sna, screen, 1336 width, height, depth); 1337#endif 1338 1339 if ((width|height) == 0) { 1340 usage = -1; 1341 goto fallback; 1342 } 1343 assert(width && height); 1344 1345 flags = kgem_can_create_2d(&sna->kgem, width, height, depth); 1346 if (flags == 0) { 1347 DBG(("%s: can not use GPU, just creating shadow\n", 1348 __FUNCTION__)); 1349 goto fallback; 1350 } 1351 1352 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)) 1353 flags &= ~KGEM_CAN_CREATE_GPU; 1354 if (wedged(sna) && usage != SNA_CREATE_FB) 1355 flags &= ~KGEM_CAN_CREATE_GTT; 1356 1357 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags)); 1358 switch (usage) { 1359 case CREATE_PIXMAP_USAGE_SCRATCH: 1360 if (flags & KGEM_CAN_CREATE_GPU) 1361 return sna_pixmap_create_scratch(screen, 1362 width, height, depth, 1363 I915_TILING_X); 1364 else 1365 goto fallback; 1366 1367 case SNA_CREATE_SCRATCH: 1368 if (flags & (KGEM_CAN_CREATE_CPU | KGEM_CAN_CREATE_GPU)) 1369 return sna_pixmap_create_scratch(screen, 1370 width, height, depth, 1371 I915_TILING_Y); 1372 else 1373 return NullPixmap; 1374 } 1375 1376 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) 1377 flags &= ~KGEM_CAN_CREATE_GPU; 1378 if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 1379 usage = 0; 1380 1381 pad = PixmapBytePad(width, depth); 1382 if (pad * height < 4096) { 1383 DBG(("%s: small buffer [%d], attaching to shadow pixmap\n", 1384 __FUNCTION__, pad * height)); 1385 pixmap = create_pixmap(sna, screen, 1386 width, height, depth, usage); 1387 if (pixmap == NullPixmap) 1388 return NullPixmap; 1389 1390 ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 1391 pad = pixmap->devKind; 1392 flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU); 1393 1394 priv = sna_pixmap_attach(pixmap); 1395 if (priv == NULL) { 1396 free(pixmap); 1397 goto fallback; 1398 } 1399 } else { 1400 DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n", 1401 __FUNCTION__, width, height, pad, flags)); 1402 1403 pixmap = create_pixmap_hdr(sna, screen, width, height, depth, usage, &priv); 1404 if (pixmap == NullPixmap) 1405 return NullPixmap; 1406 1407 ptr = NULL; 1408 } 1409 1410 priv->stride = pad; 1411 priv->create = flags; 1412 priv->ptr = ptr; 1413 1414 assert(to_sna_from_pixmap(pixmap) == sna); 1415 assert(pixmap->drawable.pScreen == screen); 1416 assert(pixmap->refcnt == 1); 1417 1418 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 1419 __FUNCTION__, 1420 pixmap->drawable.serialNumber, 1421 pixmap->drawable.width, 1422 pixmap->drawable.height, 1423 pixmap->usage_hint)); 1424 return pixmap; 1425 1426fallback: 1427 return create_pixmap(sna, screen, width, height, depth, usage); 1428} 1429 1430void sna_add_flush_pixmap(struct sna *sna, 1431 struct sna_pixmap *priv, 1432 struct kgem_bo *bo) 1433{ 1434 DBG(("%s: marking pixmap=%ld for flushing\n", 1435 __FUNCTION__, priv->pixmap->drawable.serialNumber)); 1436 assert(bo); 1437 assert(bo->flush); 1438 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1439 list_move(&priv->flush_list, &sna->flush_pixmaps); 1440 1441 if (bo->exec == NULL && sna->kgem.nbatch && kgem_is_idle(&sna->kgem)) { 1442 DBG(("%s: new flush bo, flushing before\n", __FUNCTION__)); 1443 _kgem_submit(&sna->kgem); 1444 } 1445} 1446 1447static void __sna_free_pixmap(struct sna *sna, 1448 PixmapPtr pixmap, 1449 struct sna_pixmap *priv) 1450{ 1451 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1452 list_del(&priv->flush_list); 1453 1454 assert(priv->gpu_damage == NULL); 1455 assert(priv->cpu_damage == NULL); 1456 1457 __sna_pixmap_free_cpu(sna, priv); 1458 1459 if (priv->flush) 1460 sna_watch_flush(sna, -1); 1461 1462#if !NDEBUG 1463 pixmap->devKind = 0xdeadbeef; 1464#endif 1465 if (priv->header) { 1466 assert(pixmap->drawable.pScreen == to_screen_from_sna(sna)); 1467 assert(!priv->shm); 1468 pixmap->devPrivate.ptr = sna->freed_pixmap; 1469 sna->freed_pixmap = pixmap; 1470#if DEBUG_MEMORY 1471 sna->debug_memory.pixmap_cached++; 1472#endif 1473 } else { 1474 free(priv); 1475 FreePixmap(pixmap); 1476 } 1477} 1478 1479static Bool sna_destroy_pixmap(PixmapPtr pixmap) 1480{ 1481 struct sna *sna; 1482 struct sna_pixmap *priv; 1483 1484 assert(pixmap->refcnt > 0); 1485 if (--pixmap->refcnt) 1486 return TRUE; 1487 1488#if DEBUG_MEMORY 1489 to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--; 1490#endif 1491 1492 priv = sna_pixmap(pixmap); 1493 DBG(("%s: pixmap=%ld, attached?=%d\n", 1494 __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL)); 1495 if (priv == NULL) { 1496 FreePixmap(pixmap); 1497 return TRUE; 1498 } 1499 1500 assert_pixmap_damage(pixmap); 1501 sna = to_sna_from_pixmap(pixmap); 1502 1503 sna_damage_destroy(&priv->gpu_damage); 1504 sna_damage_destroy(&priv->cpu_damage); 1505 1506 list_del(&priv->cow_list); 1507 if (priv->cow) { 1508 struct sna_cow *cow = COW(priv->cow); 1509 DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", 1510 __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); 1511 assert(cow->refcnt); 1512 if (!--cow->refcnt) 1513 free(cow); 1514 priv->cow = NULL; 1515 } else 1516 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 1517 1518 if (priv->move_to_gpu) 1519 (void)priv->move_to_gpu(sna, priv, 0); 1520 1521 /* Always release the gpu bo back to the lower levels of caching */ 1522 if (priv->gpu_bo) { 1523 sna_pixmap_unmap(pixmap, priv); 1524 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1525 priv->gpu_bo = NULL; 1526 } 1527 1528 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { 1529 DBG(("%s: deferring release of active SHM pixmap=%ld\n", 1530 __FUNCTION__, pixmap->drawable.serialNumber)); 1531 add_shm_flush(sna, priv); 1532 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ 1533 } else 1534 __sna_free_pixmap(sna, pixmap, priv); 1535 return TRUE; 1536} 1537 1538void sna_pixmap_destroy(PixmapPtr pixmap) 1539{ 1540 assert(pixmap->refcnt == 1); 1541 assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true); 1542 1543 sna_destroy_pixmap(pixmap); 1544} 1545 1546static inline bool has_coherent_map(struct sna *sna, 1547 struct kgem_bo *bo, 1548 unsigned flags) 1549{ 1550 assert(bo); 1551 1552 if (kgem_bo_mapped(&sna->kgem, bo)) 1553 return true; 1554 1555 if (bo->tiling == I915_TILING_Y) 1556 return false; 1557 1558 return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE); 1559} 1560 1561static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1562{ 1563 if (priv == NULL) 1564 return true; 1565 1566 if (flags & MOVE_ASYNC_HINT) { 1567 /* Not referencing the pointer itself, so do not care */ 1568 return true; 1569 } 1570 1571 if (!priv->mapped) { 1572 if (!priv->cpu_bo) 1573 return true; 1574 1575 assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0); 1576 assert(priv->pixmap->devKind == priv->cpu_bo->pitch); 1577 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu); 1578 } 1579 1580 assert(!priv->move_to_gpu || (flags & MOVE_WRITE) == 0); 1581 1582 assert_pixmap_map(priv->pixmap, priv); 1583 assert(priv->pixmap->devKind == priv->gpu_bo->pitch); 1584 1585 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)) { 1586 assert(priv->mapped == MAPPED_CPU); 1587 1588 if (priv->gpu_bo->tiling != I915_TILING_NONE) 1589 return false; 1590 1591 return flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE); 1592 } 1593 1594 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__gtt)) { 1595 assert(priv->mapped == MAPPED_GTT); 1596 1597 if (priv->gpu_bo->tiling == I915_TILING_Y && sna->kgem.gen == 0x21) 1598 return false; 1599 1600 return true; 1601 } 1602 1603 if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) { 1604 assert(priv->mapped == MAPPED_GTT); 1605 return true; 1606 } 1607 1608 return false; 1609} 1610 1611static inline bool pixmap_inplace(struct sna *sna, 1612 PixmapPtr pixmap, 1613 struct sna_pixmap *priv, 1614 unsigned flags) 1615{ 1616 if (FORCE_INPLACE) 1617 return FORCE_INPLACE > 0; 1618 1619 if (wedged(sna) && !priv->pinned) { 1620 DBG(("%s: no, wedged and unpinned; pull pixmap back to CPU\n", __FUNCTION__)); 1621 return false; 1622 } 1623 1624 if (priv->move_to_gpu && flags & MOVE_WRITE) 1625 return false; 1626 1627 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 1628 if (priv->clear) { 1629 DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__)); 1630 return false; 1631 } 1632 1633 if (flags & MOVE_ASYNC_HINT) { 1634 DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__)); 1635 return false; 1636 } 1637 1638 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) { 1639 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__)); 1640 return false; 1641 } 1642 1643 if ((flags & MOVE_READ) == 0) { 1644 DBG(("%s: %s, GPU bo is busy, but not reading\n", __FUNCTION__, priv->pinned ? "no" : "yes")); 1645 return !priv->pinned; 1646 } 1647 } 1648 1649 if (priv->mapped) { 1650 DBG(("%s: %s, already mapped\n", __FUNCTION__, has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 1651 return has_coherent_map(sna, priv->gpu_bo, flags); 1652 } 1653 1654 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 1655 DBG(("%s: yes, has CPU bo and is active on CPU\n", __FUNCTION__)); 1656 return true; 1657 } 1658 1659 if (priv->cpu_bo && priv->cpu) { 1660 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 1661 return false; 1662 } 1663 1664 if (flags & MOVE_READ && 1665 (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) { 1666 DBG(("%s:, no, reading and has CPU damage\n", __FUNCTION__)); 1667 return false; 1668 } 1669 1670 return (priv->stride * pixmap->drawable.height >> 12) > 1671 sna->kgem.half_cpu_cache_pages; 1672} 1673 1674static bool sna_pixmap_alloc_gpu(struct sna *sna, 1675 PixmapPtr pixmap, 1676 struct sna_pixmap *priv, 1677 unsigned flags) 1678{ 1679 uint32_t tiling; 1680 1681 /* Use tiling by default, but disable per user request */ 1682 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) { 1683 flags |= CREATE_SCANOUT; 1684 tiling = kgem_choose_tiling(&sna->kgem, 1685 -DEFAULT_SCANOUT_TILING, 1686 pixmap->drawable.width, 1687 pixmap->drawable.height, 1688 pixmap->drawable.bitsPerPixel); 1689 } else 1690 tiling = sna_pixmap_default_tiling(sna, pixmap); 1691 1692 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1693 1694 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1695 pixmap->drawable.width, 1696 pixmap->drawable.height, 1697 pixmap->drawable.bitsPerPixel, 1698 tiling, flags); 1699 return priv->gpu_bo != NULL; 1700} 1701 1702static bool 1703sna_pixmap_create_mappable_gpu(PixmapPtr pixmap, 1704 bool can_replace) 1705{ 1706 struct sna *sna = to_sna_from_pixmap(pixmap); 1707 struct sna_pixmap *priv = sna_pixmap(pixmap); 1708 1709 if (wedged(sna)) 1710 goto out; 1711 1712 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) 1713 goto out; 1714 1715 assert_pixmap_damage(pixmap); 1716 1717 if (can_replace && priv->gpu_bo && 1718 (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo) || 1719 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1720 if (priv->pinned) 1721 return false; 1722 1723 DBG(("%s: discard busy GPU bo\n", __FUNCTION__)); 1724 sna_pixmap_free_gpu(sna, priv); 1725 } 1726 1727 if (priv->gpu_bo == NULL) { 1728 assert_pixmap_damage(pixmap); 1729 assert(priv->gpu_damage == NULL); 1730 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_GTT_MAP | CREATE_INACTIVE); 1731 } 1732 1733out: 1734 if (priv->gpu_bo == NULL) 1735 return false; 1736 1737 return (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1738 !kgem_bo_is_busy(priv->gpu_bo)); 1739} 1740 1741static inline bool gpu_bo_download(struct sna *sna, 1742 struct sna_pixmap *priv, 1743 int n, const BoxRec *box, 1744 bool idle) 1745{ 1746 char *src; 1747 1748 if (!USE_INPLACE) 1749 return false; 1750 1751 switch (priv->gpu_bo->tiling) { 1752 case I915_TILING_Y: 1753 return false; 1754 case I915_TILING_X: 1755 if (!sna->kgem.memcpy_from_tiled_x) 1756 return false; 1757 default: 1758 break; 1759 } 1760 1761 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 1762 return false; 1763 1764 if (idle) { 1765 if (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 1766 return false; 1767 1768 if (priv->cpu_bo && __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) 1769 return false; 1770 } 1771 1772 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 1773 if (src == NULL) 1774 return false; 1775 1776 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 1777 1778 if (priv->cpu_bo) 1779 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1780 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1781 1782 if (sigtrap_get()) 1783 return false; 1784 1785 if (priv->gpu_bo->tiling) { 1786 int bpp = priv->pixmap->drawable.bitsPerPixel; 1787 void *dst = priv->pixmap->devPrivate.ptr; 1788 int dst_pitch = priv->pixmap->devKind; 1789 1790 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 1791 do { 1792 DBG(("%s: box (%d, %d), (%d, %d)\n", 1793 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1794 memcpy_from_tiled_x(&sna->kgem, src, dst, bpp, 1795 priv->gpu_bo->pitch, dst_pitch, 1796 box->x1, box->y1, 1797 box->x1, box->y1, 1798 box->x2 - box->x1, box->y2 - box->y1); 1799 box++; 1800 } while (--n); 1801 } else { 1802 int bpp = priv->pixmap->drawable.bitsPerPixel; 1803 void *dst = priv->pixmap->devPrivate.ptr; 1804 int dst_pitch = priv->pixmap->devKind; 1805 1806 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 1807 do { 1808 DBG(("%s: box (%d, %d), (%d, %d)\n", 1809 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 1810 memcpy_blt(src, dst, bpp, 1811 priv->gpu_bo->pitch, dst_pitch, 1812 box->x1, box->y1, 1813 box->x1, box->y1, 1814 box->x2 - box->x1, box->y2 - box->y1); 1815 box++; 1816 } while (--n); 1817 } 1818 1819 sigtrap_put(); 1820 return true; 1821} 1822 1823static inline bool cpu_bo_download(struct sna *sna, 1824 struct sna_pixmap *priv, 1825 int n, const BoxRec *box) 1826{ 1827 if (DBG_NO_CPU_DOWNLOAD) 1828 return false; 1829 1830 if (wedged(sna)) 1831 return false; 1832 1833 if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu) 1834 return false; 1835 1836 if (!kgem_bo_is_busy(priv->gpu_bo) && !kgem_bo_is_busy(priv->cpu_bo)) { 1837 /* Is it worth detiling? */ 1838 assert(box[0].y1 < box[n-1].y2); 1839 if (kgem_bo_can_map(&sna->kgem, priv->gpu_bo) && 1840 (box[n-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) { 1841 DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n", 1842 __FUNCTION__, box[n-1].y2-box[0].y1, priv->gpu_bo->pitch)); 1843 return false; 1844 } 1845 } 1846 1847 DBG(("%s: using GPU write to CPU bo for download from GPU\n", __FUNCTION__)); 1848 return sna->render.copy_boxes(sna, GXcopy, 1849 &priv->pixmap->drawable, priv->gpu_bo, 0, 0, 1850 &priv->pixmap->drawable, priv->cpu_bo, 0, 0, 1851 box, n, COPY_LAST); 1852} 1853 1854static void download_boxes(struct sna *sna, 1855 struct sna_pixmap *priv, 1856 int n, const BoxRec *box) 1857{ 1858 bool ok; 1859 1860 DBG(("%s: nbox=%d\n", __FUNCTION__, n)); 1861 1862 ok = gpu_bo_download(sna, priv, n, box, true); 1863 if (!ok) 1864 ok = cpu_bo_download(sna, priv, n, box); 1865 if (!ok) 1866 ok = gpu_bo_download(sna, priv, n, box, false); 1867 if (!ok) { 1868 if (priv->cpu_bo) 1869 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 1870 assert(priv->mapped == MAPPED_NONE); 1871 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 1872 sna_read_boxes(sna, priv->pixmap, priv->gpu_bo, box, n); 1873 } 1874} 1875 1876static inline bool use_cpu_bo_for_upload(struct sna *sna, 1877 struct sna_pixmap *priv, 1878 unsigned flags) 1879{ 1880 if (DBG_NO_CPU_UPLOAD) 1881 return false; 1882 1883 if (wedged(sna)) 1884 return false; 1885 1886 if (priv->cpu_bo == NULL) 1887 return false; 1888 1889 DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__, 1890 flags, 1891 kgem_bo_is_busy(priv->gpu_bo), 1892 kgem_bo_is_busy(priv->cpu_bo))); 1893 1894 if (!priv->cpu) 1895 return true; 1896 1897 if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) 1898 return true; 1899 1900 if (priv->gpu_bo->tiling) 1901 return true; 1902 1903 return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo); 1904} 1905 1906bool 1907sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1908{ 1909 struct sna_cow *cow = COW(priv->cow); 1910 1911 DBG(("%s: pixmap=%ld, handle=%d [refcnt=%d], cow refcnt=%d, flags=%x\n", 1912 __FUNCTION__, 1913 priv->pixmap->drawable.serialNumber, 1914 priv->gpu_bo->handle, 1915 priv->gpu_bo->refcnt, 1916 cow->refcnt, 1917 flags)); 1918 1919 assert(priv->gpu_bo == cow->bo); 1920 assert(cow->refcnt); 1921 1922 if (flags && /* flags == 0 => force decouple */ 1923 (flags & MOVE_WRITE) == 0 && 1924 (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow))) 1925 return true; 1926 1927 if (!IS_COW_OWNER(priv->cow)) 1928 list_del(&priv->cow_list); 1929 1930 if (!--cow->refcnt) { 1931 DBG(("%s: freeing cow\n", __FUNCTION__)); 1932 assert(list_is_empty(&cow->list)); 1933 free(cow); 1934 } else if (IS_COW_OWNER(priv->cow) && priv->pinned) { 1935 PixmapPtr pixmap = priv->pixmap; 1936 struct kgem_bo *bo; 1937 BoxRec box; 1938 1939 DBG(("%s: copying the Holy cow\n", __FUNCTION__)); 1940 1941 box.x1 = box.y1 = 0; 1942 box.x2 = pixmap->drawable.width; 1943 box.y2 = pixmap->drawable.height; 1944 1945 bo = kgem_create_2d(&sna->kgem, 1946 box.x2, box.y2, 1947 pixmap->drawable.bitsPerPixel, 1948 sna_pixmap_default_tiling(sna, pixmap), 1949 0); 1950 if (bo == NULL) { 1951 cow->refcnt++; 1952 DBG(("%s: allocation failed\n", __FUNCTION__)); 1953 return false; 1954 } 1955 1956 if (!sna->render.copy_boxes(sna, GXcopy, 1957 &pixmap->drawable, priv->gpu_bo, 0, 0, 1958 &pixmap->drawable, bo, 0, 0, 1959 &box, 1, 0)) { 1960 DBG(("%s: copy failed\n", __FUNCTION__)); 1961 kgem_bo_destroy(&sna->kgem, bo); 1962 cow->refcnt++; 1963 return false; 1964 } 1965 1966 assert(!list_is_empty(&cow->list)); 1967 while (!list_is_empty(&cow->list)) { 1968 struct sna_pixmap *clone; 1969 1970 clone = list_first_entry(&cow->list, 1971 struct sna_pixmap, cow_list); 1972 list_del(&clone->cow_list); 1973 1974 assert(clone->gpu_bo == cow->bo); 1975 sna_pixmap_unmap(clone->pixmap, clone); 1976 kgem_bo_destroy(&sna->kgem, clone->gpu_bo); 1977 clone->gpu_bo = kgem_bo_reference(bo); 1978 } 1979 cow->bo = bo; 1980 kgem_bo_destroy(&sna->kgem, bo); 1981 } else { 1982 struct kgem_bo *bo = NULL; 1983 1984 if (flags & MOVE_READ) { 1985 PixmapPtr pixmap = priv->pixmap; 1986 unsigned create, tiling; 1987 BoxRec box; 1988 1989 DBG(("%s: copying cow\n", __FUNCTION__)); 1990 1991 box.x1 = box.y1 = 0; 1992 box.x2 = pixmap->drawable.width; 1993 box.y2 = pixmap->drawable.height; 1994 1995 if (flags & __MOVE_PRIME) { 1996 create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT; 1997 tiling = I915_TILING_NONE; 1998 } else { 1999 create = 0; 2000 tiling = sna_pixmap_default_tiling(sna, pixmap); 2001 } 2002 2003 bo = kgem_create_2d(&sna->kgem, 2004 box.x2, box.y2, 2005 pixmap->drawable.bitsPerPixel, 2006 tiling, create); 2007 if (bo == NULL) { 2008 cow->refcnt++; 2009 DBG(("%s: allocation failed\n", __FUNCTION__)); 2010 return false; 2011 } 2012 2013 if (!sna->render.copy_boxes(sna, GXcopy, 2014 &pixmap->drawable, priv->gpu_bo, 0, 0, 2015 &pixmap->drawable, bo, 0, 0, 2016 &box, 1, 0)) { 2017 DBG(("%s: copy failed\n", __FUNCTION__)); 2018 kgem_bo_destroy(&sna->kgem, bo); 2019 cow->refcnt++; 2020 return false; 2021 } 2022 } 2023 2024 assert(priv->gpu_bo); 2025 sna_pixmap_unmap(priv->pixmap, priv); 2026 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2027 priv->gpu_bo = bo; 2028 } 2029 2030 priv->cow = NULL; 2031 return true; 2032} 2033 2034static bool 2035sna_pixmap_make_cow(struct sna *sna, 2036 struct sna_pixmap *src_priv, 2037 struct sna_pixmap *dst_priv) 2038{ 2039 struct sna_cow *cow; 2040 2041 assert(src_priv->gpu_bo); 2042 2043 if (!USE_COW) 2044 return false; 2045 2046 if (src_priv->gpu_bo->proxy) 2047 return false; 2048 2049 DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n", 2050 __FUNCTION__, 2051 src_priv->pixmap->drawable.serialNumber, 2052 dst_priv->pixmap->drawable.serialNumber, 2053 src_priv->gpu_bo->handle, 2054 src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0, 2055 dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0)); 2056 2057 if (dst_priv->pinned) { 2058 DBG(("%s: can't cow, dst_pinned=%x\n", 2059 __FUNCTION__, dst_priv->pinned)); 2060 return false; 2061 } 2062 2063 assert(dst_priv->move_to_gpu == NULL); 2064 assert(!dst_priv->flush); 2065 assert(list_is_empty(&dst_priv->cow_list)); 2066 2067 cow = COW(src_priv->cow); 2068 if (cow == NULL) { 2069 cow = malloc(sizeof(*cow)); 2070 if (cow == NULL) 2071 return false; 2072 2073 list_init(&cow->list); 2074 2075 cow->bo = src_priv->gpu_bo; 2076 cow->refcnt = 1; 2077 2078 DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n", 2079 __FUNCTION__, 2080 src_priv->pixmap->drawable.serialNumber, 2081 cow->bo->handle)); 2082 2083 src_priv->cow = MAKE_COW_OWNER(cow); 2084 if (src_priv->flush & FLUSH_WRITE) { 2085 assert(!src_priv->shm); 2086 sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo); 2087 } 2088 } 2089 2090 if (cow == COW(dst_priv->cow)) { 2091 assert(dst_priv->gpu_bo == cow->bo); 2092 return true; 2093 } 2094 2095 if (dst_priv->cow) 2096 sna_pixmap_undo_cow(sna, dst_priv, 0); 2097 2098 if (dst_priv->gpu_bo) { 2099 sna_pixmap_unmap(dst_priv->pixmap, dst_priv); 2100 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 2101 } 2102 assert(!dst_priv->mapped); 2103 dst_priv->gpu_bo = kgem_bo_reference(cow->bo); 2104 dst_priv->cow = cow; 2105 list_add(&dst_priv->cow_list, &cow->list); 2106 cow->refcnt++; 2107 2108 DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n", 2109 __FUNCTION__, 2110 dst_priv->pixmap->drawable.serialNumber, 2111 src_priv->pixmap->drawable.serialNumber, 2112 cow->bo->handle)); 2113 2114 return true; 2115} 2116 2117static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags) 2118{ 2119 if (!USE_INPLACE) 2120 return false; 2121 2122 if ((flags & MOVE_INPLACE_HINT) == 0) { 2123 DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__)); 2124 return false; 2125 } 2126 2127 assert((flags & MOVE_ASYNC_HINT) == 0 || (priv->create & KGEM_CAN_CREATE_LARGE)); 2128 2129 if (priv->move_to_gpu && flags & MOVE_WRITE) { 2130 DBG(("%s: no, has pending move-to-gpu\n", __FUNCTION__)); 2131 return false; 2132 } 2133 2134 if (priv->cow && flags & MOVE_WRITE) { 2135 DBG(("%s: no, has COW\n", __FUNCTION__)); 2136 return false; 2137 } 2138 2139 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) { 2140 DBG(("%s: no, not accessible via GTT\n", __FUNCTION__)); 2141 return false; 2142 } 2143 2144 if ((priv->gpu_damage == NULL || priv->cpu_damage) && flags & MOVE_READ) { 2145 DBG(("%s: no, has CPU damage and requires readback\n", __FUNCTION__)); 2146 return false; 2147 } 2148 2149 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 2150 DBG(("%s: yes, CPU is busy\n", __FUNCTION__)); 2151 return true; 2152 } 2153 2154 if (priv->create & KGEM_CAN_CREATE_LARGE) { 2155 DBG(("%s: large object, has GPU? %d\n", 2156 __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0)); 2157 return priv->gpu_bo != NULL; 2158 } 2159 2160 if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) { 2161 DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__)); 2162 return false; 2163 } 2164 2165 return true; 2166} 2167 2168bool 2169_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) 2170{ 2171 struct sna *sna = to_sna_from_pixmap(pixmap); 2172 struct sna_pixmap *priv; 2173 2174 DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__, 2175 pixmap->drawable.serialNumber, 2176 pixmap->drawable.width, 2177 pixmap->drawable.height, 2178 flags)); 2179 2180 assert(flags & (MOVE_READ | MOVE_WRITE)); 2181 assert_pixmap_damage(pixmap); 2182 2183 priv = sna_pixmap(pixmap); 2184 if (priv == NULL) { 2185 DBG(("%s: not attached\n", __FUNCTION__)); 2186 return true; 2187 } 2188 2189 DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n", 2190 __FUNCTION__, 2191 priv->gpu_bo ? priv->gpu_bo->handle : 0, 2192 priv->gpu_damage, priv->cpu_damage, priv->clear)); 2193 2194 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2195 2196 if ((flags & MOVE_READ) == 0 && UNDO) { 2197 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 2198 if (priv->move_to_gpu) 2199 sna_pixmap_discard_shadow_damage(priv, NULL); 2200 } 2201 2202 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2203 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2204 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2205 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2206 goto skip; 2207 } 2208 2209 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2210 assert(priv->gpu_damage == NULL); 2211 assert(!priv->pinned); 2212 assert(!priv->mapped); 2213 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2214 priv->gpu_bo = NULL; 2215 } 2216 2217 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 2218 DBG(("%s: CPU all-damaged\n", __FUNCTION__)); 2219 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); 2220 assert(priv->gpu_damage == NULL || (flags & MOVE_WRITE) == 0); 2221 goto done; 2222 } 2223 2224 if (USE_INPLACE && (flags & MOVE_READ) == 0 && !(priv->cow || priv->move_to_gpu)) { 2225 assert(flags & MOVE_WRITE); 2226 DBG(("%s: no readback, discarding gpu damage [%d], pending clear[%d]\n", 2227 __FUNCTION__, priv->gpu_damage != NULL, priv->clear)); 2228 2229 if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) && 2230 pixmap_inplace(sna, pixmap, priv, flags) && 2231 sna_pixmap_create_mappable_gpu(pixmap, true)) { 2232 void *ptr; 2233 2234 DBG(("%s: write inplace\n", __FUNCTION__)); 2235 assert(!priv->shm); 2236 assert(priv->cow == NULL); 2237 assert(priv->move_to_gpu == NULL); 2238 assert(priv->gpu_bo->exec == NULL); 2239 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2240 2241 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2242 if (ptr == NULL) 2243 goto skip_inplace_map; 2244 2245 pixmap->devPrivate.ptr = ptr; 2246 pixmap->devKind = priv->gpu_bo->pitch; 2247 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2248 assert(has_coherent_ptr(sna, priv, flags)); 2249 2250 assert(priv->gpu_bo->proxy == NULL); 2251 sna_damage_all(&priv->gpu_damage, pixmap); 2252 sna_damage_destroy(&priv->cpu_damage); 2253 priv->clear = false; 2254 list_del(&priv->flush_list); 2255 2256 assert(!priv->shm); 2257 assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush); 2258 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2259 priv->cpu &= priv->mapped == MAPPED_CPU; 2260 2261 assert_pixmap_damage(pixmap); 2262 return true; 2263 } 2264 2265skip_inplace_map: 2266 sna_damage_destroy(&priv->gpu_damage); 2267 priv->clear = false; 2268 if ((flags & MOVE_ASYNC_HINT) == 0 && 2269 priv->cpu_bo && !priv->cpu_bo->flush && 2270 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2271 DBG(("%s: discarding busy CPU bo\n", __FUNCTION__)); 2272 assert(!priv->shm); 2273 assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL); 2274 2275 sna_damage_destroy(&priv->cpu_damage); 2276 sna_pixmap_free_cpu(sna, priv, false); 2277 2278 assert(priv->mapped == MAPPED_NONE); 2279 if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, 0)) 2280 return false; 2281 assert(priv->mapped == MAPPED_NONE); 2282 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2283 2284 goto mark_damage; 2285 } 2286 } 2287 2288 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2289 2290 if (operate_inplace(priv, flags) && 2291 pixmap_inplace(sna, pixmap, priv, flags) && 2292 sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) { 2293 void *ptr; 2294 2295 DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__)); 2296 assert(priv->gpu_bo); 2297 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2298 assert(!priv->move_to_gpu); 2299 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2300 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 2301 /* XXX only sync for writes? */ 2302 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2303 assert(priv->gpu_bo->exec == NULL); 2304 2305 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2306 if (ptr != NULL) { 2307 pixmap->devPrivate.ptr = ptr; 2308 pixmap->devKind = priv->gpu_bo->pitch; 2309 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2310 assert(has_coherent_ptr(sna, priv, flags)); 2311 2312 if (flags & MOVE_WRITE) { 2313 assert(priv->gpu_bo->proxy == NULL); 2314 sna_damage_all(&priv->gpu_damage, pixmap); 2315 sna_damage_destroy(&priv->cpu_damage); 2316 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2317 list_del(&priv->flush_list); 2318 priv->clear = false; 2319 } 2320 priv->cpu &= priv->mapped == MAPPED_CPU; 2321 2322 assert_pixmap_damage(pixmap); 2323 DBG(("%s: operate inplace (GTT)\n", __FUNCTION__)); 2324 return true; 2325 } 2326 } 2327 2328 sna_pixmap_unmap(pixmap, priv); 2329 2330 if (USE_INPLACE && 2331 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL && 2332 priv->gpu_bo->tiling == I915_TILING_NONE && 2333 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) && 2334 (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) && 2335 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2336 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) { 2337 void *ptr; 2338 2339 DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__)); 2340 assert(priv->gpu_bo); 2341 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2342 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2343 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2344 2345 assert(!priv->mapped); 2346 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 2347 2348 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2349 if (ptr != NULL) { 2350 pixmap->devPrivate.ptr = ptr; 2351 pixmap->devKind = priv->gpu_bo->pitch; 2352 priv->mapped = MAPPED_CPU; 2353 assert(has_coherent_ptr(sna, priv, flags)); 2354 2355 if (flags & MOVE_WRITE) { 2356 assert(priv->gpu_bo->proxy == NULL); 2357 sna_damage_all(&priv->gpu_damage, pixmap); 2358 sna_damage_destroy(&priv->cpu_damage); 2359 sna_pixmap_free_cpu(sna, priv, priv->cpu); 2360 list_del(&priv->flush_list); 2361 priv->clear = false; 2362 priv->cpu = true; 2363 } 2364 2365 assert(pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__cpu)); 2366 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2367 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2368 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2369 assert_pixmap_damage(pixmap); 2370 assert(has_coherent_ptr(sna, priv, flags)); 2371 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2372 return true; 2373 } 2374 } 2375 2376 assert(priv->mapped == MAPPED_NONE); 2377 if (((flags & MOVE_READ) == 0 || priv->clear) && 2378 priv->cpu_bo && !priv->cpu_bo->flush && 2379 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2380 assert(!priv->shm); 2381 sna_pixmap_free_cpu(sna, priv, false); 2382 } 2383 2384 assert(priv->mapped == MAPPED_NONE); 2385 if (pixmap->devPrivate.ptr == NULL && 2386 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2387 return false; 2388 assert(priv->mapped == MAPPED_NONE); 2389 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2390 2391 if (flags & MOVE_READ) { 2392 if (priv->clear) { 2393 DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n", 2394 __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height, 2395 pixmap->devKind, pixmap->devKind * pixmap->drawable.height)); 2396 2397 if (priv->cpu_bo) { 2398 kgem_bo_undo(&sna->kgem, priv->cpu_bo); 2399 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2400 sna->kgem.can_blt_cpu && 2401 sna->render.fill_one(sna, 2402 pixmap, priv->cpu_bo, priv->clear_color, 2403 0, 0, 2404 pixmap->drawable.width, 2405 pixmap->drawable.height, 2406 GXcopy)) 2407 goto clear_done; 2408 2409 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2410 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2411 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2412 } 2413 2414 if (sigtrap_get() == 0) { 2415 assert(pixmap->devKind); 2416 sigtrap_assert_active(); 2417 if (priv->clear_color == 0 || 2418 pixmap->drawable.bitsPerPixel == 8 || 2419 priv->clear_color == (1 << pixmap->drawable.depth) - 1) { 2420 memset(pixmap->devPrivate.ptr, priv->clear_color, 2421 (size_t)pixmap->devKind * pixmap->drawable.height); 2422 } else { 2423 pixman_fill(pixmap->devPrivate.ptr, 2424 pixmap->devKind/sizeof(uint32_t), 2425 pixmap->drawable.bitsPerPixel, 2426 0, 0, 2427 pixmap->drawable.width, 2428 pixmap->drawable.height, 2429 priv->clear_color); 2430 } 2431 sigtrap_put(); 2432 } else 2433 return false; 2434 2435clear_done: 2436 sna_damage_all(&priv->cpu_damage, pixmap); 2437 sna_pixmap_free_gpu(sna, priv); 2438 assert(priv->gpu_damage == NULL); 2439 assert(priv->clear == false); 2440 } 2441 2442 if (priv->gpu_damage) { 2443 const BoxRec *box; 2444 int n; 2445 2446 DBG(("%s: flushing GPU damage\n", __FUNCTION__)); 2447 assert(priv->gpu_bo); 2448 2449 n = sna_damage_get_boxes(priv->gpu_damage, &box); 2450 if (n) { 2451 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) { 2452 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2453 return false; 2454 } 2455 2456 download_boxes(sna, priv, n, box); 2457 } 2458 2459 __sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage)); 2460 priv->gpu_damage = NULL; 2461 } 2462 } 2463 2464 if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) { 2465mark_damage: 2466 DBG(("%s: marking as damaged\n", __FUNCTION__)); 2467 sna_damage_all(&priv->cpu_damage, pixmap); 2468 sna_pixmap_free_gpu(sna, priv); 2469 assert(priv->gpu_damage == NULL); 2470 assert(priv->clear == false); 2471 2472 if (priv->flush) { 2473 assert(!priv->shm); 2474 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2475 } 2476 } 2477 2478done: 2479 if (flags & MOVE_WRITE) { 2480 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2481 assert(priv->gpu_damage == NULL); 2482 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2483 if (priv->cow) 2484 sna_pixmap_undo_cow(sna, priv, 0); 2485 if (priv->gpu_bo && priv->gpu_bo->rq == NULL) { 2486 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__)); 2487 sna_pixmap_free_gpu(sna, priv); 2488 } 2489 if (priv->flush) { 2490 assert(!priv->shm); 2491 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2492 } 2493 priv->source_count = SOURCE_BIAS; 2494 } 2495 2496 if (priv->cpu_bo) { 2497 if ((flags & MOVE_ASYNC_HINT) == 0) { 2498 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2499 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2500 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2501 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2502 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2503 } 2504 } 2505skip: 2506 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 2507 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2508 assert(pixmap->devKind); 2509 assert_pixmap_damage(pixmap); 2510 assert(has_coherent_ptr(sna, sna_pixmap(pixmap), flags)); 2511 return true; 2512} 2513 2514static bool 2515region_overlaps_damage(const RegionRec *region, 2516 struct sna_damage *damage, 2517 int dx, int dy) 2518{ 2519 const BoxRec *re, *de; 2520 2521 DBG(("%s?\n", __FUNCTION__)); 2522 2523 if (damage == NULL) 2524 return false; 2525 2526 if (DAMAGE_IS_ALL(damage)) 2527 return true; 2528 2529 re = ®ion->extents; 2530 de = &DAMAGE_PTR(damage)->extents; 2531 DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n", 2532 __FUNCTION__, 2533 re->x1, re->y1, re->x2, re->y2, 2534 de->x1, de->y1, de->x2, de->y2)); 2535 2536 return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 && 2537 re->y1 + dy < de->y2 && re->y2 + dy > de->y1); 2538} 2539 2540static inline bool region_inplace(struct sna *sna, 2541 PixmapPtr pixmap, 2542 RegionPtr region, 2543 struct sna_pixmap *priv, 2544 unsigned flags) 2545{ 2546 assert_pixmap_damage(pixmap); 2547 2548 if (FORCE_INPLACE) 2549 return FORCE_INPLACE > 0; 2550 2551 if (wedged(sna) && !priv->pinned) 2552 return false; 2553 2554 if (priv->gpu_damage && 2555 (priv->clear || (flags & MOVE_READ) == 0) && 2556 kgem_bo_is_busy(priv->gpu_bo)) 2557 return false; 2558 2559 if (flags & MOVE_READ && 2560 (priv->cpu || 2561 priv->gpu_damage == NULL || 2562 region_overlaps_damage(region, priv->cpu_damage, 0, 0))) { 2563 DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__)); 2564 return false; 2565 } 2566 2567 if (priv->mapped) { 2568 DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__, 2569 has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 2570 return has_coherent_map(sna, priv->gpu_bo, flags); 2571 } 2572 2573 if (priv->flush) { 2574 DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__)); 2575 return true; 2576 } 2577 2578 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2579 DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__)); 2580 assert(priv->gpu_bo); 2581 return true; 2582 } 2583 2584 if (priv->cpu_bo && priv->cpu) { 2585 DBG(("%s: no, has CPU bo and was last active on CPU, presume future CPU activity\n", __FUNCTION__)); 2586 return false; 2587 } 2588 2589 DBG(("%s: (%dx%d), inplace? %d\n", 2590 __FUNCTION__, 2591 region->extents.x2 - region->extents.x1, 2592 region->extents.y2 - region->extents.y1, 2593 ((int)(region->extents.x2 - region->extents.x1) * 2594 (int)(region->extents.y2 - region->extents.y1) * 2595 pixmap->drawable.bitsPerPixel >> 12) 2596 >= sna->kgem.half_cpu_cache_pages)); 2597 return ((int)(region->extents.x2 - region->extents.x1) * 2598 (int)(region->extents.y2 - region->extents.y1) * 2599 pixmap->drawable.bitsPerPixel >> 12) 2600 >= sna->kgem.half_cpu_cache_pages; 2601} 2602 2603static bool cpu_clear_boxes(struct sna *sna, 2604 PixmapPtr pixmap, 2605 struct sna_pixmap *priv, 2606 const BoxRec *box, int n) 2607{ 2608 struct sna_fill_op fill; 2609 2610 if (!sna->kgem.can_blt_cpu) 2611 return false; 2612 2613 if (!sna_fill_init_blt(&fill, sna, 2614 pixmap, priv->cpu_bo, 2615 GXcopy, priv->clear_color, 2616 FILL_BOXES)) { 2617 DBG(("%s: unsupported fill\n", 2618 __FUNCTION__)); 2619 return false; 2620 } 2621 2622 fill.boxes(sna, &fill, box, n); 2623 fill.done(sna, &fill); 2624 return true; 2625} 2626 2627bool 2628sna_drawable_move_region_to_cpu(DrawablePtr drawable, 2629 RegionPtr region, 2630 unsigned flags) 2631{ 2632 PixmapPtr pixmap = get_drawable_pixmap(drawable); 2633 struct sna *sna = to_sna_from_pixmap(pixmap); 2634 struct sna_pixmap *priv; 2635 int16_t dx, dy; 2636 2637 DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%x)\n", 2638 __FUNCTION__, pixmap->drawable.serialNumber, 2639 pixmap->drawable.width, pixmap->drawable.height, 2640 RegionExtents(region)->x1, RegionExtents(region)->y1, 2641 RegionExtents(region)->x2, RegionExtents(region)->y2, 2642 flags)); 2643 2644 assert_pixmap_damage(pixmap); 2645 if (flags & MOVE_WRITE) { 2646 assert_drawable_contains_box(drawable, ®ion->extents); 2647 } 2648 assert(flags & (MOVE_WRITE | MOVE_READ)); 2649 2650 if (box_empty(®ion->extents)) 2651 return true; 2652 2653 if (MIGRATE_ALL || DBG_NO_PARTIAL_MOVE_TO_CPU) { 2654 if (!region_subsumes_pixmap(region, pixmap)) 2655 flags |= MOVE_READ; 2656 return _sna_pixmap_move_to_cpu(pixmap, flags); 2657 } 2658 2659 priv = sna_pixmap(pixmap); 2660 if (priv == NULL) { 2661 DBG(("%s: not attached to pixmap %ld (depth %d)\n", 2662 __FUNCTION__, pixmap->drawable.serialNumber, pixmap->drawable.depth)); 2663 return true; 2664 } 2665 2666 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2667 2668 if (kgem_bo_discard_cache(priv->gpu_bo, flags & MOVE_WRITE)) { 2669 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2670 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2671 DBG(("%s: using magical upload buffer\n", __FUNCTION__)); 2672 goto skip; 2673 } 2674 2675 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2676 assert(priv->gpu_damage == NULL); 2677 assert(!priv->pinned); 2678 assert(!priv->mapped); 2679 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2680 priv->gpu_bo = NULL; 2681 } 2682 2683 if (sna_damage_is_all(&priv->cpu_damage, 2684 pixmap->drawable.width, 2685 pixmap->drawable.height)) { 2686 bool discard_gpu = priv->cpu; 2687 2688 DBG(("%s: pixmap=%ld all damaged on CPU\n", 2689 __FUNCTION__, pixmap->drawable.serialNumber)); 2690 assert(!priv->clear); 2691 2692 sna_damage_destroy(&priv->gpu_damage); 2693 2694 if ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2695 priv->cpu_bo && !priv->cpu_bo->flush && 2696 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2697 DBG(("%s: active CPU bo replacing\n", __FUNCTION__)); 2698 assert(!priv->shm); 2699 assert(!IS_STATIC_PTR(priv->ptr)); 2700 2701 if (!region_subsumes_pixmap(region, pixmap)) { 2702 DBG(("%s: partial replacement\n", __FUNCTION__)); 2703 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 2704 RegionTranslate(region, dx, dy); 2705 2706 if (sna->kgem.has_llc && !priv->pinned && 2707 sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE) { 2708#ifdef DEBUG_MEMORY 2709 sna->debug_memory.cpu_bo_allocs--; 2710 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 2711#endif 2712 DBG(("%s: promoting CPU bo to GPU bo\n", __FUNCTION__)); 2713 if (priv->gpu_bo) 2714 sna_pixmap_free_gpu(sna, priv); 2715 priv->gpu_bo = priv->cpu_bo; 2716 priv->cpu_bo = NULL; 2717 priv->ptr = NULL; 2718 pixmap->devPrivate.ptr = NULL; 2719 2720 priv->gpu_damage = priv->cpu_damage; 2721 priv->cpu_damage = NULL; 2722 2723 sna_damage_subtract(&priv->gpu_damage, region); 2724 discard_gpu = false; 2725 } else { 2726 DBG(("%s: pushing surrounding damage to GPU bo\n", __FUNCTION__)); 2727 sna_damage_subtract(&priv->cpu_damage, region); 2728 assert(priv->cpu_damage); 2729 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2730 sna_pixmap_free_cpu(sna, priv, false); 2731 if (priv->flush) 2732 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2733 2734 assert(priv->cpu_damage == NULL); 2735 sna_damage_all(&priv->gpu_damage, pixmap); 2736 sna_damage_subtract(&priv->gpu_damage, region); 2737 discard_gpu = false; 2738 } 2739 } 2740 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 2741 if (priv->flush) { 2742 assert(!priv->shm); 2743 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2744 } 2745 2746 if (dx | dy) 2747 RegionTranslate(region, -dx, -dy); 2748 } else 2749 sna_pixmap_free_cpu(sna, priv, false); 2750 } 2751 2752 if (flags & MOVE_WRITE && discard_gpu) 2753 sna_pixmap_free_gpu(sna, priv); 2754 2755 sna_pixmap_unmap(pixmap, priv); 2756 assert(priv->mapped == MAPPED_NONE); 2757 if (pixmap->devPrivate.ptr == NULL && 2758 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) 2759 return false; 2760 assert(priv->mapped == MAPPED_NONE); 2761 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2762 2763 goto out; 2764 } 2765 2766 if (USE_INPLACE && 2767 (priv->create & KGEM_CAN_CREATE_LARGE || 2768 ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2769 (priv->flush || 2770 (flags & MOVE_WHOLE_HINT && whole_pixmap_inplace(pixmap)) || 2771 box_inplace(pixmap, ®ion->extents))))) { 2772 DBG(("%s: marking for inplace hint (%d, %d)\n", 2773 __FUNCTION__, priv->flush, box_inplace(pixmap, ®ion->extents))); 2774 flags |= MOVE_INPLACE_HINT; 2775 } 2776 2777 if (region_subsumes_pixmap(region, pixmap)) { 2778 DBG(("%s: region (%d, %d), (%d, %d) + (%d, %d) subsumes pixmap (%dx%d)\n", 2779 __FUNCTION__, 2780 region->extents.x1, 2781 region->extents.y1, 2782 region->extents.x2, 2783 region->extents.y2, 2784 get_drawable_dx(drawable), get_drawable_dy(drawable), 2785 pixmap->drawable.width, 2786 pixmap->drawable.height)); 2787 return _sna_pixmap_move_to_cpu(pixmap, flags); 2788 } 2789 2790 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2791 2792 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 2793 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 2794 RegionTranslate(region, dx, dy); 2795 } 2796 2797 if (priv->move_to_gpu) { 2798 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 2799 if ((flags & MOVE_READ) == 0) 2800 sna_pixmap_discard_shadow_damage(priv, region); 2801 if (!priv->move_to_gpu(sna, priv, MOVE_READ)) { 2802 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 2803 return NULL; 2804 } 2805 } 2806 2807 if (operate_inplace(priv, flags) && 2808 region_inplace(sna, pixmap, region, priv, flags) && 2809 sna_pixmap_create_mappable_gpu(pixmap, false)) { 2810 void *ptr; 2811 2812 DBG(("%s: try to operate inplace\n", __FUNCTION__)); 2813 assert(priv->gpu_bo); 2814 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2815 assert(priv->move_to_gpu == NULL || (flags & MOVE_WRITE) == 0); 2816 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2817 2818 /* XXX only sync for writes? */ 2819 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2820 assert(priv->gpu_bo->exec == NULL); 2821 2822 ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2823 if (ptr != NULL) { 2824 pixmap->devPrivate.ptr = ptr; 2825 pixmap->devKind = priv->gpu_bo->pitch; 2826 priv->mapped = ptr == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 2827 assert(has_coherent_ptr(sna, priv, flags)); 2828 2829 if (flags & MOVE_WRITE) { 2830 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2831 assert(!priv->clear); 2832 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2833 if (sna_damage_is_all(&priv->gpu_damage, 2834 pixmap->drawable.width, 2835 pixmap->drawable.height)) { 2836 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2837 __FUNCTION__)); 2838 sna_damage_destroy(&priv->cpu_damage); 2839 list_del(&priv->flush_list); 2840 } else 2841 sna_damage_subtract(&priv->cpu_damage, 2842 region); 2843 } 2844 priv->clear = false; 2845 } 2846 priv->cpu &= priv->mapped == MAPPED_CPU; 2847 assert_pixmap_damage(pixmap); 2848 if (dx | dy) 2849 RegionTranslate(region, -dx, -dy); 2850 DBG(("%s: operate inplace\n", __FUNCTION__)); 2851 return true; 2852 } 2853 } 2854 2855 if (priv->clear && flags & MOVE_WRITE) { 2856 DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__)); 2857demote_to_cpu: 2858 if (dx | dy) 2859 RegionTranslate(region, -dx, -dy); 2860 return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ); 2861 } 2862 2863 if (flags & MOVE_WHOLE_HINT) { 2864 DBG(("%s: region (%d, %d), (%d, %d) marked with WHOLE hint, pixmap %dx%d\n", 2865 __FUNCTION__, 2866 region->extents.x1, 2867 region->extents.y1, 2868 region->extents.x2, 2869 region->extents.y2, 2870 pixmap->drawable.width, 2871 pixmap->drawable.height)); 2872move_to_cpu: 2873 if ((flags & MOVE_READ) == 0) 2874 sna_damage_subtract(&priv->gpu_damage, region); 2875 goto demote_to_cpu; 2876 } 2877 2878 sna_pixmap_unmap(pixmap, priv); 2879 2880 if (USE_INPLACE && 2881 priv->gpu_damage && 2882 priv->gpu_bo->tiling == I915_TILING_NONE && 2883 ((priv->cow == NULL && priv->move_to_gpu == NULL) || (flags & MOVE_WRITE) == 0) && 2884 (DAMAGE_IS_ALL(priv->gpu_damage) || 2885 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2886 ®ion->extents)) && 2887 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) && 2888 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2889 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 2890 void *ptr; 2891 2892 DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n", 2893 __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE))); 2894 assert(priv->gpu_bo); 2895 assert(priv->gpu_bo->proxy == NULL || (flags & MOVE_WRITE) == 0); 2896 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2897 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2898 2899 ptr = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2900 if (ptr != NULL) { 2901 pixmap->devPrivate.ptr = ptr; 2902 pixmap->devKind = priv->gpu_bo->pitch; 2903 priv->mapped = MAPPED_CPU; 2904 assert(has_coherent_ptr(sna, priv, flags)); 2905 2906 if (flags & MOVE_WRITE) { 2907 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2908 assert(!priv->clear); 2909 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 2910 if (sna_damage_is_all(&priv->gpu_damage, 2911 pixmap->drawable.width, 2912 pixmap->drawable.height)) { 2913 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2914 __FUNCTION__)); 2915 sna_damage_destroy(&priv->cpu_damage); 2916 list_del(&priv->flush_list); 2917 } else 2918 sna_damage_subtract(&priv->cpu_damage, 2919 region); 2920 } 2921 priv->clear = false; 2922 } 2923 assert_pixmap_damage(pixmap); 2924 2925 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2926 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2927 priv->cpu = true; 2928 2929 assert_pixmap_map(pixmap, priv); 2930 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2931 if (dx | dy) 2932 RegionTranslate(region, -dx, -dy); 2933 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2934 return true; 2935 } 2936 } 2937 2938 if ((priv->clear || (flags & MOVE_READ) == 0) && 2939 priv->cpu_bo && !priv->cpu_bo->flush && 2940 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2941 sna_damage_subtract(&priv->cpu_damage, region); 2942 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2943 assert(priv->gpu_bo); 2944 sna_damage_all(&priv->gpu_damage, pixmap); 2945 sna_pixmap_free_cpu(sna, priv, false); 2946 } 2947 } 2948 2949 assert(priv->mapped == MAPPED_NONE); 2950 if (pixmap->devPrivate.ptr == NULL && 2951 !sna_pixmap_alloc_cpu(sna, pixmap, priv, flags)) { 2952 DBG(("%s: CPU bo allocation failed, trying full move-to-cpu\n", __FUNCTION__)); 2953 goto move_to_cpu; 2954 } 2955 assert(priv->mapped == MAPPED_NONE); 2956 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 2957 2958 if (priv->gpu_bo == NULL) { 2959 assert(priv->gpu_damage == NULL); 2960 goto done; 2961 } 2962 2963 assert(priv->gpu_bo->proxy == NULL); 2964 2965 if ((flags & MOVE_READ) == 0) { 2966 assert(flags & MOVE_WRITE); 2967 sna_damage_subtract(&priv->gpu_damage, region); 2968 priv->clear = false; 2969 goto done; 2970 } 2971 2972 if (priv->clear) { 2973 int n = region_num_rects(region); 2974 const BoxRec *box = region_rects(region); 2975 2976 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 2977 assert(priv->cpu_damage == NULL); 2978 2979 DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__)); 2980 if (priv->cpu_bo) { 2981 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) && 2982 cpu_clear_boxes(sna, pixmap, priv, box, n)) 2983 goto clear_done; 2984 2985 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2986 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2987 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 2988 } 2989 2990 if (sigtrap_get() == 0) { 2991 assert(pixmap->devKind); 2992 sigtrap_assert_active(); 2993 do { 2994 pixman_fill(pixmap->devPrivate.ptr, 2995 pixmap->devKind/sizeof(uint32_t), 2996 pixmap->drawable.bitsPerPixel, 2997 box->x1, box->y1, 2998 box->x2 - box->x1, 2999 box->y2 - box->y1, 3000 priv->clear_color); 3001 box++; 3002 } while (--n); 3003 sigtrap_put(); 3004 } else 3005 return false; 3006 3007clear_done: 3008 if (flags & MOVE_WRITE || 3009 region->extents.x2 - region->extents.x1 > 1 || 3010 region->extents.y2 - region->extents.y1 > 1) { 3011 sna_damage_subtract(&priv->gpu_damage, region); 3012 priv->clear = false; 3013 } 3014 goto done; 3015 } 3016 3017 if (priv->gpu_damage && 3018 (DAMAGE_IS_ALL(priv->gpu_damage) || 3019 sna_damage_overlaps_box(priv->gpu_damage, ®ion->extents))) { 3020 DBG(("%s: region (%dx%d) overlaps gpu damage\n", 3021 __FUNCTION__, 3022 region->extents.x2 - region->extents.x1, 3023 region->extents.y2 - region->extents.y1)); 3024 assert(priv->gpu_bo); 3025 3026 if (priv->cpu_damage == NULL) { 3027 if ((flags & MOVE_WRITE) == 0 && 3028 region->extents.x2 - region->extents.x1 == 1 && 3029 region->extents.y2 - region->extents.y1 == 1) { 3030 /* Often associated with synchronisation, KISS */ 3031 DBG(("%s: single pixel read\n", __FUNCTION__)); 3032 sna_read_boxes(sna, pixmap, priv->gpu_bo, 3033 ®ion->extents, 1); 3034 goto done; 3035 } 3036 } else { 3037 if (DAMAGE_IS_ALL(priv->cpu_damage) || 3038 sna_damage_contains_box__no_reduce(priv->cpu_damage, 3039 ®ion->extents)) { 3040 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 3041 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 3042 3043 DBG(("%s: region already in CPU damage\n", 3044 __FUNCTION__)); 3045 goto already_damaged; 3046 } 3047 } 3048 3049 if (sna_damage_contains_box(&priv->gpu_damage, 3050 ®ion->extents) != PIXMAN_REGION_OUT) { 3051 RegionRec want, *r = region; 3052 3053 DBG(("%s: region (%dx%d) intersects gpu damage\n", 3054 __FUNCTION__, 3055 region->extents.x2 - region->extents.x1, 3056 region->extents.y2 - region->extents.y1)); 3057 3058 if ((flags & MOVE_WRITE) == 0 && 3059 region->extents.x2 - region->extents.x1 == 1 && 3060 region->extents.y2 - region->extents.y1 == 1) { 3061 sna_read_boxes(sna, pixmap, priv->gpu_bo, 3062 ®ion->extents, 1); 3063 goto done; 3064 } 3065 3066 /* Expand the region to move 32x32 pixel blocks at a 3067 * time, as we assume that we will continue writing 3068 * afterwards and so aim to coallesce subsequent 3069 * reads. 3070 */ 3071 if (flags & MOVE_WRITE) { 3072 int n = region_num_rects(region), i; 3073 const BoxRec *boxes = region_rects(region); 3074 BoxPtr blocks; 3075 3076 blocks = NULL; 3077 if (priv->cpu_damage == NULL) 3078 blocks = malloc(sizeof(BoxRec) * n); 3079 if (blocks) { 3080 for (i = 0; i < n; i++) { 3081 blocks[i].x1 = boxes[i].x1 & ~31; 3082 if (blocks[i].x1 < 0) 3083 blocks[i].x1 = 0; 3084 3085 blocks[i].x2 = (boxes[i].x2 + 31) & ~31; 3086 if (blocks[i].x2 > pixmap->drawable.width) 3087 blocks[i].x2 = pixmap->drawable.width; 3088 3089 blocks[i].y1 = boxes[i].y1 & ~31; 3090 if (blocks[i].y1 < 0) 3091 blocks[i].y1 = 0; 3092 3093 blocks[i].y2 = (boxes[i].y2 + 31) & ~31; 3094 if (blocks[i].y2 > pixmap->drawable.height) 3095 blocks[i].y2 = pixmap->drawable.height; 3096 } 3097 if (pixman_region_init_rects(&want, blocks, i)) 3098 r = &want; 3099 free(blocks); 3100 } 3101 } 3102 3103 if (region_subsumes_damage(r, priv->gpu_damage)) { 3104 const BoxRec *box; 3105 int n; 3106 3107 DBG(("%s: region wholly contains damage\n", 3108 __FUNCTION__)); 3109 3110 n = sna_damage_get_boxes(priv->gpu_damage, &box); 3111 if (n) 3112 download_boxes(sna, priv, n, box); 3113 3114 sna_damage_destroy(&priv->gpu_damage); 3115 } else if (DAMAGE_IS_ALL(priv->gpu_damage) || 3116 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3117 &r->extents)) { 3118 3119 DBG(("%s: region wholly inside damage\n", 3120 __FUNCTION__)); 3121 3122 assert(sna_damage_contains_box(&priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN); 3123 assert(sna_damage_contains_box(&priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT); 3124 3125 download_boxes(sna, priv, 3126 region_num_rects(r), 3127 region_rects(r)); 3128 sna_damage_subtract(&priv->gpu_damage, r); 3129 } else { 3130 RegionRec need; 3131 3132 pixman_region_init(&need); 3133 if (sna_damage_intersect(priv->gpu_damage, r, &need)) { 3134 DBG(("%s: region intersects damage\n", 3135 __FUNCTION__)); 3136 3137 download_boxes(sna, priv, 3138 region_num_rects(&need), 3139 region_rects(&need)); 3140 sna_damage_subtract(&priv->gpu_damage, r); 3141 RegionUninit(&need); 3142 } 3143 } 3144 if (r == &want) 3145 pixman_region_fini(&want); 3146 } 3147 } 3148 3149done: 3150 if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) { 3151 DBG(("%s: applying cpu damage\n", __FUNCTION__)); 3152 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 3153 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 3154 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap); 3155 sna_damage_reduce_all(&priv->cpu_damage, pixmap); 3156 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3157 DBG(("%s: replaced entire pixmap\n", __FUNCTION__)); 3158 sna_pixmap_free_gpu(sna, priv); 3159 } 3160 if (priv->flush) { 3161 assert(!priv->shm); 3162 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3163 } 3164 } 3165 3166already_damaged: 3167 if (dx | dy) 3168 RegionTranslate(region, -dx, -dy); 3169 3170out: 3171 if (flags & MOVE_WRITE) { 3172 assert(!DAMAGE_IS_ALL(priv->gpu_damage)); 3173 priv->source_count = SOURCE_BIAS; 3174 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3175 assert(priv->gpu_bo || priv->gpu_damage == NULL); 3176 assert(!priv->flush || !list_is_empty(&priv->flush_list)); 3177 assert(!priv->clear); 3178 } 3179 if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) { 3180 DBG(("%s: syncing cpu bo\n", __FUNCTION__)); 3181 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu)); 3182 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 3183 FORCE_FULL_SYNC || flags & MOVE_WRITE); 3184 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 3185 } 3186skip: 3187 priv->cpu |= (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE; 3188 assert(pixmap->devPrivate.ptr == PTR(priv->ptr)); 3189 assert(pixmap->devKind); 3190 assert_pixmap_damage(pixmap); 3191 assert(has_coherent_ptr(sna, priv, flags)); 3192 return true; 3193} 3194 3195bool 3196sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags) 3197{ 3198 RegionRec region; 3199 PixmapPtr pixmap; 3200 int16_t dx, dy; 3201 3202 if (drawable->type == DRAWABLE_PIXMAP) 3203 return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags); 3204 3205 pixmap = get_window_pixmap((WindowPtr)drawable); 3206 get_drawable_deltas(drawable, pixmap, &dx, &dy); 3207 3208 DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n", 3209 __FUNCTION__, 3210 drawable->x, drawable->y, 3211 drawable->width, drawable->height, 3212 dx, dy, flags)); 3213 3214 region.extents.x1 = drawable->x + dx; 3215 region.extents.y1 = drawable->y + dy; 3216 region.extents.x2 = region.extents.x1 + drawable->width; 3217 region.extents.y2 = region.extents.y1 + drawable->height; 3218 region.data = NULL; 3219 3220 if (region.extents.x1 < 0) 3221 region.extents.x1 = 0; 3222 if (region.extents.y1 < 0) 3223 region.extents.y1 = 0; 3224 if (region.extents.x2 > pixmap->drawable.width) 3225 region.extents.x2 = pixmap->drawable.width; 3226 if (region.extents.y2 > pixmap->drawable.height) 3227 region.extents.y2 = pixmap->drawable.height; 3228 3229 if (box_empty(®ion.extents)) 3230 return true; 3231 3232 return sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags); 3233} 3234 3235pure static bool alu_overwrites(uint8_t alu) 3236{ 3237 switch (alu) { 3238 case GXclear: 3239 case GXcopy: 3240 case GXcopyInverted: 3241 case GXset: 3242 return true; 3243 default: 3244 return false; 3245 } 3246} 3247 3248inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc) 3249{ 3250 if (!alu_overwrites(gc->alu)) 3251 return false; 3252 3253 if (!PM_IS_SOLID(draw, gc->planemask)) 3254 return false; 3255 3256 if (gc->fillStyle == FillStippled) 3257 return false; 3258 3259 return true; 3260} 3261 3262inline static unsigned 3263drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial) 3264{ 3265 assert(sna_gc(gc)->changes == 0); 3266 3267 if (gc->fillStyle == FillStippled) { 3268 DBG(("%s: read due to fill %d\n", 3269 __FUNCTION__, gc->fillStyle)); 3270 return MOVE_READ | MOVE_WRITE; 3271 } 3272 3273 if (fb_gc(gc)->and | fb_gc(gc)->bgand) { 3274 DBG(("%s: read due to rrop %d:%x\n", 3275 __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and)); 3276 return MOVE_READ | MOVE_WRITE; 3277 } 3278 3279 DBG(("%s: try operating on drawable inplace [hint? %d]\n", 3280 __FUNCTION__, drawable_gc_inplace_hint(draw, gc))); 3281 3282 return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT; 3283} 3284 3285static inline struct sna_pixmap * 3286sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv) 3287{ 3288 assert(priv->gpu_bo); 3289 DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__, 3290 priv->pixmap->drawable.serialNumber, 3291 priv->gpu_bo->handle)); 3292 return priv; 3293} 3294 3295inline static struct sna_pixmap * 3296__sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags) 3297{ 3298 struct sna_pixmap *priv; 3299 3300 assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE)); 3301 if ((flags & __MOVE_FORCE) == 0 && wedged(sna)) 3302 return NULL; 3303 3304 priv = sna_pixmap(pixmap); 3305 if (priv == NULL) { 3306 DBG(("%s: not attached\n", __FUNCTION__)); 3307 if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0) 3308 return NULL; 3309 3310 if (pixmap->usage_hint == -1) { 3311 DBG(("%s: not promoting SHM Pixmap for DRI\n", __FUNCTION__)); 3312 return NULL; 3313 } 3314 3315 DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__)); 3316 3317 priv = sna_pixmap_attach(pixmap); 3318 if (priv == NULL) 3319 return NULL; 3320 3321 sna_damage_all(&priv->cpu_damage, pixmap); 3322 3323 assert(priv->gpu_bo == NULL); 3324 assert(priv->gpu_damage == NULL); 3325 } 3326 3327 return priv; 3328} 3329 3330inline static void sna_pixmap_unclean(struct sna *sna, 3331 struct sna_pixmap *priv, 3332 unsigned flags) 3333{ 3334 struct drm_i915_gem_busy busy; 3335 3336 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 3337 assert(priv->gpu_bo); 3338 assert(priv->gpu_bo->proxy == NULL); 3339 assert_pixmap_map(priv->pixmap, priv); 3340 3341 sna_damage_destroy(&priv->cpu_damage); 3342 list_del(&priv->flush_list); 3343 3344 if (flags & (__MOVE_DRI | __MOVE_SCANOUT)) 3345 return; 3346 3347 if (!priv->flush || priv->gpu_bo->exec) 3348 return; 3349 3350 busy.handle = priv->gpu_bo->handle; 3351 busy.busy = 0; 3352 ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy); 3353 3354 DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n", 3355 __FUNCTION__, 3356 priv->pixmap->drawable.serialNumber, 3357 busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16)))); 3358 3359 if (busy.busy) { 3360 unsigned mode = KGEM_RENDER; 3361 if (busy.busy & (0xfffe << 16)) 3362 mode = KGEM_BLT; 3363 kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode); 3364 } else 3365 __kgem_bo_clear_busy(priv->gpu_bo); 3366} 3367 3368struct sna_pixmap * 3369sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags) 3370{ 3371 struct sna *sna = to_sna_from_pixmap(pixmap); 3372 struct sna_pixmap *priv; 3373 RegionRec i, r; 3374 3375 DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n", 3376 __FUNCTION__, pixmap->drawable.serialNumber, 3377 box->x1, box->y1, box->x2, box->y2, flags)); 3378 3379 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 3380 if (priv == NULL) 3381 return NULL; 3382 3383 assert(box->x2 > box->x1 && box->y2 > box->y1); 3384 assert_pixmap_damage(pixmap); 3385 assert_pixmap_contains_box(pixmap, box); 3386 assert(priv->gpu_damage == NULL || priv->gpu_bo); 3387 3388 if ((flags & MOVE_READ) == 0) 3389 sna_damage_subtract_box(&priv->cpu_damage, box); 3390 3391 if (priv->move_to_gpu) { 3392 unsigned int hint; 3393 3394 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3395 hint = flags | MOVE_READ; 3396 if ((flags & MOVE_READ) == 0) { 3397 RegionRec region; 3398 3399 region.extents = *box; 3400 region.data = NULL; 3401 sna_pixmap_discard_shadow_damage(priv, ®ion); 3402 if (region_subsumes_pixmap(®ion, pixmap)) 3403 hint &= ~MOVE_READ; 3404 } else { 3405 if (priv->cpu_damage) 3406 hint |= MOVE_WRITE; 3407 } 3408 if (!priv->move_to_gpu(sna, priv, hint)) { 3409 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3410 return NULL; 3411 } 3412 } 3413 3414 if (priv->cow) { 3415 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 3416 3417 assert(cow); 3418 3419 if ((flags & MOVE_READ) == 0) { 3420 if (priv->gpu_damage) { 3421 r.extents = *box; 3422 r.data = NULL; 3423 if (!region_subsumes_damage(&r, priv->gpu_damage)) 3424 cow |= MOVE_READ | __MOVE_FORCE; 3425 } 3426 } else { 3427 if (priv->cpu_damage) { 3428 r.extents = *box; 3429 r.data = NULL; 3430 if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0)) 3431 cow |= MOVE_WRITE; 3432 } 3433 } 3434 3435 if (!sna_pixmap_undo_cow(sna, priv, cow)) 3436 return NULL; 3437 3438 if (priv->gpu_bo == NULL) 3439 sna_damage_destroy(&priv->gpu_damage); 3440 } 3441 3442 if (sna_damage_is_all(&priv->gpu_damage, 3443 pixmap->drawable.width, 3444 pixmap->drawable.height)) { 3445 DBG(("%s: already all-damaged\n", __FUNCTION__)); 3446 sna_pixmap_unclean(sna, priv, flags); 3447 goto done; 3448 } 3449 3450 if (kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 3451 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 3452 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3453 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3454 assert(!priv->pinned); 3455 assert(!priv->mapped); 3456 sna_damage_destroy(&priv->gpu_damage); 3457 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 3458 priv->gpu_bo = NULL; 3459 } 3460 3461 sna_damage_reduce(&priv->cpu_damage); 3462 assert_pixmap_damage(pixmap); 3463 3464 if (priv->cpu_damage == NULL) { 3465 list_del(&priv->flush_list); 3466 return sna_pixmap_move_to_gpu(pixmap, MOVE_READ | flags); 3467 } 3468 3469 if (priv->gpu_bo == NULL) { 3470 assert(priv->gpu_damage == NULL); 3471 3472 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) 3473 sna_pixmap_alloc_gpu(sna, pixmap, priv, CREATE_INACTIVE); 3474 3475 if (priv->gpu_bo == NULL) 3476 return NULL; 3477 3478 DBG(("%s: created gpu bo\n", __FUNCTION__)); 3479 } 3480 3481 if (priv->gpu_bo->proxy) { 3482 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 3483 assert((flags & MOVE_WRITE) == 0); 3484 assert(priv->gpu_damage == NULL); 3485 return priv; 3486 } 3487 3488 add_shm_flush(sna, priv); 3489 3490 assert(priv->cpu_damage); 3491 region_set(&r, box); 3492 if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) { 3493 bool ok = false; 3494 int n; 3495 3496 n = sna_damage_get_boxes(priv->cpu_damage, &box); 3497 assert(n); 3498 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3499 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3500 ok = sna->render.copy_boxes(sna, GXcopy, 3501 &pixmap->drawable, priv->cpu_bo, 0, 0, 3502 &pixmap->drawable, priv->gpu_bo, 0, 0, 3503 box, n, 0); 3504 } 3505 if (!ok) { 3506 sna_pixmap_unmap(pixmap, priv); 3507 if (pixmap->devPrivate.ptr == NULL) 3508 return NULL; 3509 3510 assert(pixmap->devKind); 3511 if (n == 1 && !priv->pinned && 3512 box->x1 <= 0 && box->y1 <= 0 && 3513 box->x2 >= pixmap->drawable.width && 3514 box->y2 >= pixmap->drawable.height) { 3515 ok = sna_replace(sna, pixmap, 3516 pixmap->devPrivate.ptr, 3517 pixmap->devKind); 3518 } else { 3519 ok = sna_write_boxes(sna, pixmap, 3520 priv->gpu_bo, 0, 0, 3521 pixmap->devPrivate.ptr, 3522 pixmap->devKind, 3523 0, 0, 3524 box, n); 3525 } 3526 if (!ok) 3527 return NULL; 3528 } 3529 3530 sna_damage_destroy(&priv->cpu_damage); 3531 } else if (DAMAGE_IS_ALL(priv->cpu_damage) || 3532 sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) { 3533 bool ok = false; 3534 3535 assert(sna_damage_contains_box(&priv->gpu_damage, box) == PIXMAN_REGION_OUT); 3536 assert(sna_damage_contains_box(&priv->cpu_damage, box) == PIXMAN_REGION_IN); 3537 3538 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3539 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3540 ok = sna->render.copy_boxes(sna, GXcopy, 3541 &pixmap->drawable, priv->cpu_bo, 0, 0, 3542 &pixmap->drawable, priv->gpu_bo, 0, 0, 3543 box, 1, 0); 3544 } 3545 if (!ok) { 3546 sna_pixmap_unmap(pixmap, priv); 3547 if (pixmap->devPrivate.ptr != NULL) { 3548 assert(pixmap->devKind); 3549 ok = sna_write_boxes(sna, pixmap, 3550 priv->gpu_bo, 0, 0, 3551 pixmap->devPrivate.ptr, 3552 pixmap->devKind, 3553 0, 0, 3554 box, 1); 3555 } 3556 } 3557 if (!ok) 3558 return NULL; 3559 3560 sna_damage_subtract(&priv->cpu_damage, &r); 3561 } else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) { 3562 int n = region_num_rects(&i); 3563 bool ok; 3564 3565 box = region_rects(&i); 3566 ok = false; 3567 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3568 DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n)); 3569 ok = sna->render.copy_boxes(sna, GXcopy, 3570 &pixmap->drawable, priv->cpu_bo, 0, 0, 3571 &pixmap->drawable, priv->gpu_bo, 0, 0, 3572 box, n, 0); 3573 } 3574 if (!ok) { 3575 sna_pixmap_unmap(pixmap, priv); 3576 if (pixmap->devPrivate.ptr != NULL) { 3577 assert(pixmap->devKind); 3578 ok = sna_write_boxes(sna, pixmap, 3579 priv->gpu_bo, 0, 0, 3580 pixmap->devPrivate.ptr, 3581 pixmap->devKind, 3582 0, 0, 3583 box, n); 3584 } 3585 } 3586 if (!ok) 3587 return NULL; 3588 3589 sna_damage_subtract(&priv->cpu_damage, &r); 3590 RegionUninit(&i); 3591 } 3592 3593done: 3594 if (priv->cpu_damage == NULL && priv->flush) 3595 list_del(&priv->flush_list); 3596 if (flags & MOVE_WRITE) { 3597 priv->clear = false; 3598 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 3599 priv->cpu_damage == NULL && 3600 (box_covers_pixmap(pixmap, &r.extents) || 3601 box_inplace(pixmap, &r.extents))) { 3602 DBG(("%s: large operation on undamaged, discarding CPU shadow\n", 3603 __FUNCTION__)); 3604 assert(priv->gpu_bo); 3605 assert(priv->gpu_bo->proxy == NULL); 3606 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) { 3607 DBG(("%s: large operation on undamaged, promoting to full GPU\n", 3608 __FUNCTION__)); 3609 sna_damage_all(&priv->gpu_damage, pixmap); 3610 } 3611 } 3612 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3613 sna_pixmap_free_cpu(sna, priv, priv->cpu); 3614 sna_damage_destroy(&priv->cpu_damage); 3615 list_del(&priv->flush_list); 3616 } 3617 priv->cpu = false; 3618 } 3619 3620 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3621 return sna_pixmap_mark_active(sna, priv); 3622} 3623 3624struct kgem_bo * 3625sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box, 3626 struct sna_damage ***damage) 3627{ 3628 PixmapPtr pixmap = get_drawable_pixmap(drawable); 3629 struct sna_pixmap *priv = sna_pixmap(pixmap); 3630 struct sna *sna; 3631 RegionRec region; 3632 int16_t dx, dy; 3633 int ret; 3634 3635 DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n", 3636 __FUNCTION__, 3637 pixmap->drawable.serialNumber, 3638 box->x1, box->y1, box->x2, box->y2, 3639 flags)); 3640 3641 assert(box->x2 > box->x1 && box->y2 > box->y1); 3642 assert(pixmap->refcnt); 3643 assert_pixmap_damage(pixmap); 3644 assert_drawable_contains_box(drawable, box); 3645 3646 if (priv == NULL) { 3647 DBG(("%s: not attached\n", __FUNCTION__)); 3648 return NULL; 3649 } 3650 3651 if (priv->cow) { 3652 unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE; 3653 assert(cow); 3654 3655 if (flags & IGNORE_DAMAGE) { 3656 if (priv->gpu_damage) { 3657 region.extents = *box; 3658 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3659 region.extents.x1 += dx; 3660 region.extents.x2 += dx; 3661 region.extents.y1 += dy; 3662 region.extents.y2 += dy; 3663 } 3664 region.data = NULL; 3665 if (region_subsumes_damage(®ion, 3666 priv->gpu_damage)) 3667 cow &= ~MOVE_READ; 3668 } else 3669 cow &= ~MOVE_READ; 3670 } 3671 3672 if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow)) 3673 return NULL; 3674 3675 if (priv->gpu_bo == NULL) 3676 sna_damage_destroy(&priv->gpu_damage); 3677 } 3678 3679 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 3680 DBG(("%s: cached upload proxy, discard and revert to GPU\n", __FUNCTION__)); 3681 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 3682 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 3683 assert(!priv->pinned); 3684 assert(!priv->mapped); 3685 sna_damage_destroy(&priv->gpu_damage); 3686 kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem, 3687 priv->gpu_bo); 3688 priv->gpu_bo = NULL; 3689 goto use_cpu_bo; 3690 } 3691 3692 if (priv->flush) { 3693 DBG(("%s: exported target, set PREFER_GPU\n", __FUNCTION__)); 3694 flags |= PREFER_GPU; 3695 } 3696 if (priv->shm) { 3697 DBG(("%s: shm target, discard PREFER_GPU\n", __FUNCTION__)); 3698 flags &= ~PREFER_GPU; 3699 } 3700 if (priv->pinned) { 3701 DBG(("%s: pinned, never REPLACES\n", __FUNCTION__)); 3702 flags &= ~REPLACES; 3703 } 3704 if (priv->cpu && (flags & (FORCE_GPU | IGNORE_DAMAGE)) == 0) { 3705 DBG(("%s: last on cpu and needs damage, discard PREFER_GPU\n", __FUNCTION__)); 3706 flags &= ~PREFER_GPU; 3707 } 3708 3709 if ((flags & (PREFER_GPU | IGNORE_DAMAGE)) == IGNORE_DAMAGE) { 3710 if (priv->gpu_bo && (box_covers_pixmap(pixmap, box) || box_inplace(pixmap, box))) { 3711 DBG(("%s: not reading damage and large, set PREFER_GPU\n", __FUNCTION__)); 3712 flags |= PREFER_GPU; 3713 } 3714 } 3715 3716 DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n", 3717 __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags)); 3718 3719 if ((flags & PREFER_GPU) == 0 && 3720 (flags & (REPLACES | IGNORE_DAMAGE) || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) { 3721 DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__)); 3722 goto use_cpu_bo; 3723 } 3724 3725 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3726 DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__)); 3727 assert(priv->cpu_damage == NULL); 3728 assert(priv->gpu_bo); 3729 assert(priv->gpu_bo->proxy == NULL); 3730 goto use_gpu_bo; 3731 } 3732 3733 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3734 assert(priv->gpu_damage == NULL); 3735 if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) { 3736 DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n", 3737 __FUNCTION__)); 3738 goto use_cpu_bo; 3739 } 3740 } 3741 3742 DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__, 3743 priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL, 3744 priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL)); 3745 if (priv->gpu_bo == NULL) { 3746 unsigned int move; 3747 3748 if ((flags & FORCE_GPU) == 0 && 3749 (priv->create & KGEM_CAN_CREATE_GPU) == 0) { 3750 DBG(("%s: untiled, will not force allocation\n", 3751 __FUNCTION__)); 3752 goto use_cpu_bo; 3753 } 3754 3755 if ((flags & IGNORE_DAMAGE) == 0) { 3756 if (priv->cpu_bo) { 3757 if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) { 3758 if (kgem_bo_is_busy(priv->cpu_bo)) { 3759 DBG(("%s: already using CPU bo, will not force allocation\n", 3760 __FUNCTION__)); 3761 goto use_cpu_bo; 3762 } 3763 3764 if ((flags & RENDER_GPU) == 0) { 3765 DBG(("%s: prefer cpu", __FUNCTION__)); 3766 goto use_cpu_bo; 3767 } 3768 } else { 3769 if (kgem_bo_is_busy(priv->cpu_bo)) { 3770 DBG(("%s: CPU bo active, must force allocation\n", 3771 __FUNCTION__)); 3772 goto create_gpu_bo; 3773 } 3774 } 3775 } 3776 3777 if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) { 3778 if ((flags & PREFER_GPU) == 0) { 3779 DBG(("%s: already damaged and prefer cpu", 3780 __FUNCTION__)); 3781 goto use_cpu_bo; 3782 } 3783 3784 if (!box_inplace(pixmap, box)) { 3785 DBG(("%s: damaged with a small operation, will not force allocation\n", 3786 __FUNCTION__)); 3787 goto use_cpu_bo; 3788 } 3789 } 3790 } else if (priv->cpu_damage) { 3791 region.extents = *box; 3792 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3793 region.extents.x1 += dx; 3794 region.extents.x2 += dx; 3795 region.extents.y1 += dy; 3796 region.extents.y2 += dy; 3797 } 3798 region.data = NULL; 3799 3800 sna_damage_subtract(&priv->cpu_damage, ®ion); 3801 if (priv->cpu_damage == NULL) { 3802 list_del(&priv->flush_list); 3803 priv->cpu = false; 3804 } 3805 } 3806 3807create_gpu_bo: 3808 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3809 if (flags & FORCE_GPU) 3810 move |= __MOVE_FORCE; 3811 if (!sna_pixmap_move_to_gpu(pixmap, move)) 3812 goto use_cpu_bo; 3813 3814 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3815 goto done; 3816 } 3817 3818 3819 region.extents = *box; 3820 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3821 region.extents.x1 += dx; 3822 region.extents.x2 += dx; 3823 region.extents.y1 += dy; 3824 region.extents.y2 += dy; 3825 } 3826 region.data = NULL; 3827 3828 DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__, 3829 region.extents.x1, region.extents.y1, 3830 region.extents.x2, region.extents.y2)); 3831 3832 if (priv->gpu_damage) { 3833 assert(priv->gpu_bo); 3834 if (!priv->cpu_damage || flags & IGNORE_DAMAGE) { 3835 if (flags & REPLACES || box_covers_pixmap(pixmap, ®ion.extents)) { 3836 unsigned int move; 3837 3838 if (flags & IGNORE_DAMAGE) 3839 move = MOVE_WRITE; 3840 else 3841 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT; 3842 3843 if (sna_pixmap_move_to_gpu(pixmap, move)) { 3844 sna_damage_all(&priv->gpu_damage, 3845 pixmap); 3846 goto use_gpu_bo; 3847 } 3848 } 3849 3850 if (DAMAGE_IS_ALL(priv->gpu_damage) || 3851 sna_damage_contains_box__no_reduce(priv->gpu_damage, 3852 ®ion.extents)) { 3853 DBG(("%s: region wholly contained within GPU damage\n", 3854 __FUNCTION__)); 3855 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3856 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3857 goto use_gpu_bo; 3858 } else { 3859 DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n", 3860 __FUNCTION__)); 3861 goto move_to_gpu; 3862 } 3863 } 3864 3865 ret = sna_damage_contains_box(&priv->gpu_damage, ®ion.extents); 3866 if (ret == PIXMAN_REGION_IN) { 3867 DBG(("%s: region wholly contained within GPU damage\n", 3868 __FUNCTION__)); 3869 goto use_gpu_bo; 3870 } 3871 3872 if (ret != PIXMAN_REGION_OUT) { 3873 DBG(("%s: region partially contained within GPU damage\n", 3874 __FUNCTION__)); 3875 goto move_to_gpu; 3876 } 3877 } 3878 3879 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_damage) { 3880 ret = sna_damage_contains_box(&priv->cpu_damage, ®ion.extents); 3881 if (ret == PIXMAN_REGION_IN) { 3882 DBG(("%s: region wholly contained within CPU damage\n", 3883 __FUNCTION__)); 3884 goto use_cpu_bo; 3885 } 3886 3887 if (box_inplace(pixmap, box)) { 3888 DBG(("%s: forcing inplace\n", __FUNCTION__)); 3889 goto move_to_gpu; 3890 } 3891 3892 if (ret != PIXMAN_REGION_OUT) { 3893 DBG(("%s: region partially contained within CPU damage\n", 3894 __FUNCTION__)); 3895 goto use_cpu_bo; 3896 } 3897 } 3898 3899move_to_gpu: 3900 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion.extents, 3901 flags & IGNORE_DAMAGE ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) { 3902 DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__)); 3903 assert(priv->gpu_bo == NULL); 3904 goto use_cpu_bo; 3905 } 3906 3907done: 3908 assert(priv->move_to_gpu == NULL); 3909 assert(priv->gpu_bo != NULL); 3910 assert(priv->gpu_bo->refcnt); 3911 if (sna_damage_is_all(&priv->gpu_damage, 3912 pixmap->drawable.width, 3913 pixmap->drawable.height)) { 3914 sna_damage_destroy(&priv->cpu_damage); 3915 list_del(&priv->flush_list); 3916 *damage = NULL; 3917 } else 3918 *damage = &priv->gpu_damage; 3919 3920 DBG(("%s: using GPU bo with damage? %d\n", 3921 __FUNCTION__, *damage != NULL)); 3922 assert(*damage == NULL || !DAMAGE_IS_ALL(*damage)); 3923 assert(priv->gpu_bo->proxy == NULL); 3924 assert(priv->clear == false); 3925 assert(priv->cpu == false); 3926 assert(!priv->shm); 3927 return priv->gpu_bo; 3928 3929use_gpu_bo: 3930 if (priv->move_to_gpu) { 3931 unsigned hint = MOVE_READ | MOVE_WRITE; 3932 3933 sna = to_sna_from_pixmap(pixmap); 3934 3935 DBG(("%s: applying move-to-gpu override\n", __FUNCTION__)); 3936 if (flags & IGNORE_DAMAGE) { 3937 region.extents = *box; 3938 region.data = NULL; 3939 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3940 region.extents.x1 += dx; 3941 region.extents.x2 += dx; 3942 region.extents.y1 += dy; 3943 region.extents.y2 += dy; 3944 } 3945 sna_pixmap_discard_shadow_damage(priv, ®ion); 3946 if (region_subsumes_pixmap(®ion, pixmap)) { 3947 DBG(("%s: discarding move-to-gpu READ for subsumed pixmap\n", __FUNCTION__)); 3948 hint = MOVE_WRITE; 3949 } 3950 } 3951 3952 if (!priv->move_to_gpu(sna, priv, hint)) { 3953 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 3954 goto use_cpu_bo; 3955 } 3956 } 3957 3958 if (priv->shm) { 3959 assert(!priv->flush); 3960 list_move(&priv->flush_list, &sna->flush_pixmaps); 3961 } 3962 3963 DBG(("%s: using whole GPU bo\n", __FUNCTION__)); 3964 assert(priv->gpu_bo != NULL); 3965 assert(priv->gpu_bo->refcnt); 3966 assert(priv->gpu_bo->proxy == NULL); 3967 assert(priv->gpu_damage); 3968 priv->cpu = false; 3969 priv->clear = false; 3970 *damage = NULL; 3971 return priv->gpu_bo; 3972 3973use_cpu_bo: 3974 if (!USE_CPU_BO || priv->cpu_bo == NULL) { 3975 if ((flags & FORCE_GPU) == 0) { 3976 DBG(("%s: no CPU bo, and GPU not forced\n", __FUNCTION__)); 3977 return NULL; 3978 } 3979 3980 flags &= ~FORCE_GPU; 3981 3982 region.extents = *box; 3983 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3984 region.extents.x1 += dx; 3985 region.extents.x2 += dx; 3986 region.extents.y1 += dy; 3987 region.extents.y2 += dy; 3988 } 3989 region.data = NULL; 3990 3991 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3992 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT) || 3993 priv->cpu_bo == NULL) { 3994 DBG(("%s: did not create CPU bo\n", __FUNCTION__)); 3995cpu_fail: 3996 if (priv->gpu_bo) 3997 goto move_to_gpu; 3998 3999 return NULL; 4000 } 4001 } 4002 4003 assert(priv->cpu_bo->refcnt); 4004 4005 sna = to_sna_from_pixmap(pixmap); 4006 if ((flags & FORCE_GPU) == 0 && 4007 !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 4008 DBG(("%s: has CPU bo, but is idle and acceleration not forced\n", 4009 __FUNCTION__)); 4010 return NULL; 4011 } 4012 4013 region.extents = *box; 4014 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 4015 region.extents.x1 += dx; 4016 region.extents.x2 += dx; 4017 region.extents.y1 += dy; 4018 region.extents.y2 += dy; 4019 } 4020 region.data = NULL; 4021 4022 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 4023 DBG(("%s: both CPU and GPU are busy, prefer to use the GPU\n", 4024 __FUNCTION__)); 4025 goto move_to_gpu; 4026 } 4027 4028 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4029 4030 if (flags & RENDER_GPU) { 4031 flags &= ~RENDER_GPU; 4032 4033 if ((flags & IGNORE_DAMAGE) == 0 && priv->gpu_damage) { 4034 DBG(("%s: prefer to use GPU bo for rendering whilst reading from GPU damage\n", __FUNCTION__)); 4035 4036prefer_gpu_bo: 4037 if (priv->gpu_bo == NULL) { 4038 if ((flags & FORCE_GPU) == 0) { 4039 DBG(("%s: untiled, will not force allocation\n", 4040 __FUNCTION__)); 4041 return NULL; 4042 } 4043 4044 if (flags & IGNORE_DAMAGE) { 4045 sna_damage_subtract(&priv->cpu_damage, ®ion); 4046 if (priv->cpu_damage == NULL) { 4047 list_del(&priv->flush_list); 4048 priv->cpu = false; 4049 } 4050 } 4051 4052 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 4053 return NULL; 4054 4055 sna_damage_all(&priv->gpu_damage, pixmap); 4056 4057 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 4058 goto done; 4059 } 4060 goto move_to_gpu; 4061 } 4062 4063 if (!priv->shm) { 4064 if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) { 4065 if (priv->gpu_bo && priv->gpu_bo->tiling) { 4066 DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__)); 4067 goto prefer_gpu_bo; 4068 } 4069 4070 if (priv->cpu_bo->pitch >= 4096) { 4071 DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__)); 4072 goto prefer_gpu_bo; 4073 } 4074 } 4075 4076 if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) { 4077 DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__)); 4078 goto prefer_gpu_bo; 4079 } 4080 4081 if (!sna->kgem.can_blt_cpu) { 4082 DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__)); 4083 goto prefer_gpu_bo; 4084 } 4085 } 4086 } 4087 4088 if (!sna->kgem.can_blt_cpu) 4089 goto cpu_fail; 4090 4091 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 4092 (flags & IGNORE_DAMAGE ? 0 : MOVE_READ) | MOVE_WRITE | MOVE_ASYNC_HINT)) { 4093 DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__)); 4094 goto cpu_fail; 4095 } 4096 4097 if (priv->shm) { 4098 add_shm_flush(sna, priv); 4099 /* As we may have flushed and retired,, recheck for busy bo */ 4100 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo)) 4101 return NULL; 4102 } 4103 if (priv->flush) { 4104 assert(!priv->shm); 4105 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 4106 } 4107 4108 if (sna_damage_is_all(&priv->cpu_damage, 4109 pixmap->drawable.width, 4110 pixmap->drawable.height)) { 4111 sna_damage_destroy(&priv->gpu_damage); 4112 *damage = NULL; 4113 } else { 4114 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 4115 if (priv->cpu_damage && 4116 sna_damage_contains_box__no_reduce(priv->cpu_damage, 4117 ®ion.extents)) { 4118 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 4119 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 4120 *damage = NULL; 4121 } else 4122 *damage = &priv->cpu_damage; 4123 } 4124 4125 DBG(("%s: using CPU bo with damage? %d\n", 4126 __FUNCTION__, *damage != NULL)); 4127 assert(damage == NULL || !DAMAGE_IS_ALL(*damage)); 4128 assert(priv->clear == false); 4129 priv->cpu = false; 4130 return priv->cpu_bo; 4131} 4132 4133PixmapPtr 4134sna_pixmap_create_upload(ScreenPtr screen, 4135 int width, int height, int depth, 4136 unsigned flags) 4137{ 4138 struct sna *sna = to_sna_from_screen(screen); 4139 PixmapPtr pixmap; 4140 struct sna_pixmap *priv; 4141 void *ptr; 4142 4143 DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__, 4144 width, height, depth, flags)); 4145 assert(width); 4146 assert(height); 4147 4148 if (depth < 8) 4149 return create_pixmap(sna, screen, width, height, depth, 4150 CREATE_PIXMAP_USAGE_SCRATCH); 4151 4152 pixmap = create_pixmap_hdr(sna, screen, 4153 width, height, depth, CREATE_PIXMAP_USAGE_SCRATCH, 4154 &priv); 4155 if (!pixmap) 4156 return NullPixmap; 4157 4158 priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem, 4159 width, height, 4160 pixmap->drawable.bitsPerPixel, 4161 flags, &ptr); 4162 if (!priv->gpu_bo) { 4163 free(priv); 4164 FreePixmap(pixmap); 4165 return NullPixmap; 4166 } 4167 4168 /* Marking both the shadow and the GPU bo is a little dubious, 4169 * but will work so long as we always check before doing the 4170 * transfer. 4171 */ 4172 sna_damage_all(&priv->gpu_damage, pixmap); 4173 sna_damage_all(&priv->cpu_damage, pixmap); 4174 4175 pixmap->devKind = priv->gpu_bo->pitch; 4176 pixmap->devPrivate.ptr = ptr; 4177 priv->ptr = MAKE_STATIC_PTR(ptr); 4178 priv->stride = priv->gpu_bo->pitch; 4179 priv->create = 0; 4180 4181 pixmap->usage_hint = 0; 4182 if (!kgem_buffer_is_inplace(priv->gpu_bo)) 4183 pixmap->usage_hint = 1; 4184 4185 DBG(("%s: serial=%ld, %dx%d, usage=%d\n", 4186 __FUNCTION__, 4187 pixmap->drawable.serialNumber, 4188 pixmap->drawable.width, 4189 pixmap->drawable.height, 4190 pixmap->usage_hint)); 4191 return pixmap; 4192} 4193 4194static bool can_convert_to_gpu(struct sna_pixmap *priv, unsigned flags) 4195{ 4196 assert(priv->gpu_bo == NULL); 4197 4198 if (priv->cpu_bo == NULL) 4199 return false; 4200 4201 if (priv->shm) 4202 return false; 4203 4204 /* Linear scanout have a restriction that their pitch must be 4205 * 64 byte aligned. Force the creation of a proper GPU bo if 4206 * this CPU bo is not suitable for scanout. 4207 */ 4208 if (priv->pixmap->usage_hint == SNA_CREATE_FB || flags & __MOVE_SCANOUT) 4209 if (priv->cpu_bo->pitch & 63) 4210 return false; 4211 4212 if (flags & __MOVE_PRIME) 4213 if (priv->cpu_bo->pitch & 255) 4214 return false; 4215 4216 return true; 4217} 4218 4219struct sna_pixmap * 4220sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags) 4221{ 4222 struct sna *sna = to_sna_from_pixmap(pixmap); 4223 struct sna_pixmap *priv; 4224 const BoxRec *box; 4225 int n; 4226 4227 DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n", 4228 __FUNCTION__, 4229 pixmap->drawable.serialNumber, 4230 pixmap->usage_hint, 4231 flags)); 4232 4233 priv = __sna_pixmap_for_gpu(sna, pixmap, flags); 4234 if (priv == NULL) 4235 return NULL; 4236 4237 assert_pixmap_damage(pixmap); 4238 4239 if (priv->move_to_gpu && 4240 !priv->move_to_gpu(sna, priv, flags | ((priv->cpu_damage && (flags & MOVE_READ)) ? MOVE_WRITE : 0))) { 4241 DBG(("%s: move-to-gpu override failed\n", __FUNCTION__)); 4242 return NULL; 4243 } 4244 4245 if ((flags & MOVE_READ) == 0 && UNDO) 4246 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4247 4248 if (priv->cow) { 4249 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE); 4250 assert(cow); 4251 if (flags & MOVE_READ && priv->cpu_damage) 4252 cow |= MOVE_WRITE; 4253 if (!sna_pixmap_undo_cow(sna, priv, cow)) 4254 return NULL; 4255 4256 if (priv->gpu_bo == NULL) 4257 sna_damage_destroy(&priv->gpu_damage); 4258 } 4259 4260 if (sna_damage_is_all(&priv->gpu_damage, 4261 pixmap->drawable.width, 4262 pixmap->drawable.height)) { 4263 DBG(("%s: already all-damaged\n", __FUNCTION__)); 4264 sna_pixmap_unclean(sna, priv, flags); 4265 goto active; 4266 } 4267 4268 if ((flags & MOVE_READ) == 0) 4269 sna_damage_destroy(&priv->cpu_damage); 4270 4271 sna_damage_reduce(&priv->cpu_damage); 4272 assert_pixmap_damage(pixmap); 4273 DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL)); 4274 if (priv->gpu_bo == NULL || 4275 kgem_bo_discard_cache(priv->gpu_bo, flags & (MOVE_WRITE | __MOVE_FORCE))) { 4276 struct kgem_bo *proxy; 4277 4278 proxy = priv->gpu_bo; 4279 priv->gpu_bo = NULL; 4280 4281 DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n", 4282 __FUNCTION__, 4283 pixmap->drawable.width, 4284 pixmap->drawable.height, 4285 pixmap->drawable.bitsPerPixel, 4286 priv->create)); 4287 assert(!priv->mapped); 4288 assert(list_is_empty(&priv->flush_list)); 4289 4290 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) { 4291 bool is_linear; 4292 4293 assert(pixmap->drawable.width > 0); 4294 assert(pixmap->drawable.height > 0); 4295 assert(pixmap->drawable.bitsPerPixel >= 8); 4296 4297 if (flags & __MOVE_PRIME) { 4298 assert((flags & __MOVE_TILED) == 0); 4299 is_linear = true; 4300 } else { 4301 is_linear = sna_pixmap_default_tiling(sna, pixmap) == I915_TILING_NONE; 4302 if (is_linear && flags & __MOVE_TILED) { 4303 DBG(("%s: not creating linear GPU bo\n", 4304 __FUNCTION__)); 4305 return NULL; 4306 } 4307 } 4308 4309 if (is_linear && 4310 can_convert_to_gpu(priv, flags) && 4311 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4312 assert(!priv->mapped); 4313 assert(!IS_STATIC_PTR(priv->ptr)); 4314#ifdef DEBUG_MEMORY 4315 sna->debug_memory.cpu_bo_allocs--; 4316 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4317#endif 4318 priv->gpu_bo = priv->cpu_bo; 4319 priv->cpu_bo = NULL; 4320 priv->ptr = NULL; 4321 pixmap->devPrivate.ptr = NULL; 4322 sna_damage_all(&priv->gpu_damage, pixmap); 4323 sna_damage_destroy(&priv->cpu_damage); 4324 } else { 4325 unsigned create = 0; 4326 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL)) 4327 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4328 if (flags & __MOVE_PRIME) 4329 create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT; 4330 4331 sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4332 } 4333 } 4334 4335 if (priv->gpu_bo == NULL) { 4336 DBG(("%s: not creating GPU bo\n", __FUNCTION__)); 4337 assert(priv->gpu_damage == NULL); 4338 priv->gpu_bo = proxy; 4339 if (proxy) 4340 sna_damage_all(&priv->cpu_damage, pixmap); 4341 return NULL; 4342 } 4343 4344 if (proxy) { 4345 DBG(("%s: promoting upload proxy handle=%d to GPU\n", __FUNCTION__, proxy->handle)); 4346 4347 if (priv->cpu_damage && 4348 sna->render.copy_boxes(sna, GXcopy, 4349 &pixmap->drawable, proxy, 0, 0, 4350 &pixmap->drawable, priv->gpu_bo, 0, 0, 4351 region_rects(DAMAGE_REGION(priv->cpu_damage)), 4352 region_num_rects(DAMAGE_REGION(priv->cpu_damage)), 4353 0)) 4354 sna_damage_destroy(&priv->cpu_damage); 4355 4356 kgem_bo_destroy(&sna->kgem, proxy); 4357 } 4358 4359 if (flags & MOVE_WRITE && priv->cpu_damage == NULL) { 4360 /* Presume that we will only ever write to the GPU 4361 * bo. Readbacks are expensive but fairly constant 4362 * in cost for all sizes i.e. it is the act of 4363 * synchronisation that takes the most time. This is 4364 * mitigated by avoiding fallbacks in the first place. 4365 */ 4366 assert(priv->gpu_bo); 4367 assert(priv->gpu_bo->proxy == NULL); 4368 sna_damage_all(&priv->gpu_damage, pixmap); 4369 DBG(("%s: marking as all-damaged for GPU\n", 4370 __FUNCTION__)); 4371 goto active; 4372 } 4373 } 4374 4375 if (priv->gpu_bo->proxy) { 4376 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 4377 assert((flags & MOVE_WRITE) == 0); 4378 assert(priv->gpu_damage == NULL); 4379 return priv; 4380 } 4381 4382 if (priv->cpu_damage == NULL) 4383 goto done; 4384 4385 if (DAMAGE_IS_ALL(priv->cpu_damage) && priv->cpu_bo && 4386 !priv->pinned && !priv->shm && 4387 priv->gpu_bo->tiling == I915_TILING_NONE && 4388 kgem_bo_convert_to_gpu(&sna->kgem, priv->cpu_bo, flags)) { 4389 assert(!priv->mapped); 4390 assert(!IS_STATIC_PTR(priv->ptr)); 4391#ifdef DEBUG_MEMORY 4392 sna->debug_memory.cpu_bo_allocs--; 4393 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 4394#endif 4395 sna_pixmap_free_gpu(sna, priv); 4396 priv->gpu_bo = priv->cpu_bo; 4397 priv->cpu_bo = NULL; 4398 priv->ptr = NULL; 4399 pixmap->devPrivate.ptr = NULL; 4400 sna_damage_all(&priv->gpu_damage, pixmap); 4401 sna_damage_destroy(&priv->cpu_damage); 4402 goto done; 4403 } 4404 4405 add_shm_flush(sna, priv); 4406 4407 n = sna_damage_get_boxes(priv->cpu_damage, &box); 4408 assert(n); 4409 if (n) { 4410 bool ok; 4411 4412 assert_pixmap_contains_damage(pixmap, priv->cpu_damage); 4413 DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n)); 4414 4415 ok = false; 4416 if (use_cpu_bo_for_upload(sna, priv, flags)) { 4417 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 4418 ok = sna->render.copy_boxes(sna, GXcopy, 4419 &pixmap->drawable, priv->cpu_bo, 0, 0, 4420 &pixmap->drawable, priv->gpu_bo, 0, 0, 4421 box, n, 0); 4422 } 4423 if (!ok) { 4424 sna_pixmap_unmap(pixmap, priv); 4425 if (pixmap->devPrivate.ptr == NULL) 4426 return NULL; 4427 4428 assert(pixmap->devKind); 4429 if (n == 1 && !priv->pinned && 4430 (box->x2 - box->x1) >= pixmap->drawable.width && 4431 (box->y2 - box->y1) >= pixmap->drawable.height) { 4432 ok = sna_replace(sna, pixmap, 4433 pixmap->devPrivate.ptr, 4434 pixmap->devKind); 4435 } else { 4436 ok = sna_write_boxes(sna, pixmap, 4437 priv->gpu_bo, 0, 0, 4438 pixmap->devPrivate.ptr, 4439 pixmap->devKind, 4440 0, 0, 4441 box, n); 4442 } 4443 if (!ok) 4444 return NULL; 4445 } 4446 } 4447 4448 __sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage)); 4449 priv->cpu_damage = NULL; 4450 4451 /* For large bo, try to keep only a single copy around */ 4452 if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) { 4453 DBG(("%s: disposing of system copy for large/source\n", 4454 __FUNCTION__)); 4455 assert(!priv->shm); 4456 assert(priv->gpu_bo); 4457 assert(priv->gpu_bo->proxy == NULL); 4458 sna_damage_all(&priv->gpu_damage, pixmap); 4459 sna_pixmap_free_cpu(sna, priv, 4460 (priv->create & KGEM_CAN_CREATE_LARGE) ? false : priv->cpu); 4461 } 4462done: 4463 list_del(&priv->flush_list); 4464 4465 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 4466 if (DAMAGE_IS_ALL(priv->gpu_damage)) 4467 sna_pixmap_free_cpu(sna, priv, priv->cpu); 4468 4469active: 4470 if (flags & MOVE_WRITE) { 4471 priv->clear = false; 4472 priv->cpu = false; 4473 } 4474 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 4475 return sna_pixmap_mark_active(sna, priv); 4476} 4477 4478static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap) 4479{ 4480 DBG(("%s: target bpp=%d, source bpp=%d\n", 4481 __FUNCTION__, draw->bitsPerPixel, pixmap->drawable.bitsPerPixel)); 4482 4483 if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel && 4484 FbEvenTile(pixmap->drawable.width * 4485 pixmap->drawable.bitsPerPixel)) { 4486 DBG(("%s: flushing pixmap\n", __FUNCTION__)); 4487 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 4488 return false; 4489 4490 fbPadPixmap(pixmap); 4491 } 4492 4493 return true; 4494} 4495 4496static bool must_check sna_gc_move_to_cpu(GCPtr gc, 4497 DrawablePtr drawable, 4498 RegionPtr region) 4499{ 4500 struct sna_gc *sgc = sna_gc(gc); 4501 long changes = sgc->changes; 4502 4503 DBG(("%s(%p) changes=%lx\n", __FUNCTION__, gc, changes)); 4504 assert(drawable); 4505 assert(region); 4506 4507 assert(gc->ops == (GCOps *)&sna_gc_ops); 4508 gc->ops = (GCOps *)&sna_gc_ops__cpu; 4509 4510 assert(gc->funcs); 4511 sgc->old_funcs = gc->funcs; 4512 gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu; 4513 4514 assert(gc->pCompositeClip); 4515 sgc->priv = gc->pCompositeClip; 4516 gc->pCompositeClip = region; 4517 4518#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 4519 if (gc->clientClipType == CT_PIXMAP) { 4520 PixmapPtr clip = gc->clientClip; 4521 gc->clientClip = region_from_bitmap(gc->pScreen, clip); 4522 gc->pScreen->DestroyPixmap(clip); 4523 gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE; 4524 changes |= GCClipMask; 4525 } else 4526 changes &= ~GCClipMask; 4527#else 4528 changes &= ~GCClipMask; 4529#endif 4530 4531 if (changes || drawable->serialNumber != (sgc->serial & DRAWABLE_SERIAL_BITS)) { 4532 long tmp = gc->serialNumber; 4533 gc->serialNumber = sgc->serial; 4534 4535 if (fb_gc(gc)->bpp != drawable->bitsPerPixel) { 4536 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask; 4537 fb_gc(gc)->bpp = drawable->bitsPerPixel; 4538 } 4539 4540 if (changes & GCTile && !gc->tileIsPixel) { 4541 DBG(("%s: flushing tile pixmap\n", __FUNCTION__)); 4542 if (!sna_validate_pixmap(drawable, gc->tile.pixmap)) 4543 return false; 4544 } 4545 4546 if (changes & GCStipple && gc->stipple) { 4547 DBG(("%s: flushing stipple pixmap\n", __FUNCTION__)); 4548 if (!sna_validate_pixmap(drawable, gc->stipple)) 4549 return false; 4550 } 4551 4552 fbValidateGC(gc, changes, drawable); 4553 gc->serialNumber = tmp; 4554 } 4555 sgc->changes = 0; 4556 4557 switch (gc->fillStyle) { 4558 case FillTiled: 4559 DBG(("%s: moving tile to cpu\n", __FUNCTION__)); 4560 return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ); 4561 case FillStippled: 4562 case FillOpaqueStippled: 4563 DBG(("%s: moving stipple to cpu\n", __FUNCTION__)); 4564 return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ); 4565 default: 4566 return true; 4567 } 4568} 4569 4570static void sna_gc_move_to_gpu(GCPtr gc) 4571{ 4572 DBG(("%s(%p)\n", __FUNCTION__, gc)); 4573 4574 assert(gc->ops == (GCOps *)&sna_gc_ops__cpu); 4575 assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu); 4576 4577 gc->ops = (GCOps *)&sna_gc_ops; 4578 gc->funcs = (GCFuncs *)sna_gc(gc)->old_funcs; 4579 assert(gc->funcs); 4580 gc->pCompositeClip = sna_gc(gc)->priv; 4581 assert(gc->pCompositeClip); 4582} 4583 4584static inline bool clip_box(BoxPtr box, GCPtr gc) 4585{ 4586 const BoxRec *clip; 4587 bool clipped; 4588 4589 assert(gc->pCompositeClip); 4590 clip = &gc->pCompositeClip->extents; 4591 4592 clipped = !region_is_singular(gc->pCompositeClip); 4593 if (box->x1 < clip->x1) 4594 box->x1 = clip->x1, clipped = true; 4595 if (box->x2 > clip->x2) 4596 box->x2 = clip->x2, clipped = true; 4597 4598 if (box->y1 < clip->y1) 4599 box->y1 = clip->y1, clipped = true; 4600 if (box->y2 > clip->y2) 4601 box->y2 = clip->y2, clipped = true; 4602 4603 return clipped; 4604} 4605 4606static inline void translate_box(BoxPtr box, DrawablePtr d) 4607{ 4608 box->x1 += d->x; 4609 box->x2 += d->x; 4610 4611 box->y1 += d->y; 4612 box->y2 += d->y; 4613} 4614 4615static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc) 4616{ 4617 translate_box(box, d); 4618 return clip_box(box, gc); 4619} 4620 4621static inline bool box32_clip(Box32Rec *box, GCPtr gc) 4622{ 4623 bool clipped = !region_is_singular(gc->pCompositeClip); 4624 const BoxRec *clip = &gc->pCompositeClip->extents; 4625 4626 if (box->x1 < clip->x1) 4627 box->x1 = clip->x1, clipped = true; 4628 if (box->x2 > clip->x2) 4629 box->x2 = clip->x2, clipped = true; 4630 4631 if (box->y1 < clip->y1) 4632 box->y1 = clip->y1, clipped = true; 4633 if (box->y2 > clip->y2) 4634 box->y2 = clip->y2, clipped = true; 4635 4636 return clipped; 4637} 4638 4639static inline void box32_translate(Box32Rec *box, DrawablePtr d) 4640{ 4641 box->x1 += d->x; 4642 box->x2 += d->x; 4643 4644 box->y1 += d->y; 4645 box->y2 += d->y; 4646} 4647 4648static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc) 4649{ 4650 box32_translate(box, d); 4651 return box32_clip(box, gc); 4652} 4653 4654static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y) 4655{ 4656 if (box->x1 > x) 4657 box->x1 = x; 4658 else if (box->x2 < x) 4659 box->x2 = x; 4660 4661 if (box->y1 > y) 4662 box->y1 = y; 4663 else if (box->y2 < y) 4664 box->y2 = y; 4665} 4666 4667static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt) 4668{ 4669 box_add_xy(box, pt->x, pt->y); 4670} 4671 4672static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16) 4673{ 4674 b16->x1 = b32->x1; 4675 b16->y1 = b32->y1; 4676 b16->x2 = b32->x2; 4677 b16->y2 = b32->y2; 4678 4679 return b16->x2 > b16->x1 && b16->y2 > b16->y1; 4680} 4681 4682static inline void box32_add_rect(Box32Rec *box, const xRectangle *r) 4683{ 4684 int32_t v; 4685 4686 v = r->x; 4687 if (box->x1 > v) 4688 box->x1 = v; 4689 v += r->width; 4690 if (box->x2 < v) 4691 box->x2 = v; 4692 4693 v = r->y; 4694 if (box->y1 > v) 4695 box->y1 = v; 4696 v += r->height; 4697 if (box->y2 < v) 4698 box->y2 = v; 4699} 4700 4701static bool 4702can_create_upload_tiled_x(struct sna *sna, 4703 PixmapPtr pixmap, 4704 struct sna_pixmap *priv, 4705 bool replaces) 4706{ 4707 if (priv->shm || (priv->cpu && !replaces)) 4708 return false; 4709 4710 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 4711 return false; 4712 4713 if (sna->kgem.has_llc) 4714 return true; 4715 4716 if (!sna->kgem.has_wc_mmap && sna_pixmap_default_tiling(sna, pixmap)) 4717 return false; 4718 4719 return true; 4720} 4721 4722static bool 4723create_upload_tiled_x(struct sna *sna, 4724 PixmapPtr pixmap, 4725 struct sna_pixmap *priv, 4726 bool replaces) 4727{ 4728 unsigned create; 4729 4730 if (!can_create_upload_tiled_x(sna, pixmap, priv, replaces)) 4731 return false; 4732 4733 assert(priv->gpu_bo == NULL); 4734 assert(priv->gpu_damage == NULL); 4735 4736 if (sna->kgem.has_llc) 4737 create = CREATE_CPU_MAP | CREATE_INACTIVE; 4738 else if (sna->kgem.has_wc_mmap) 4739 create = CREATE_GTT_MAP | CREATE_INACTIVE; 4740 else 4741 create = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_CACHED; 4742 4743 return sna_pixmap_alloc_gpu(sna, pixmap, priv, create); 4744} 4745 4746static bool can_upload__tiled_x(struct kgem *kgem, struct kgem_bo *bo) 4747{ 4748 return kgem_bo_can_map__cpu(kgem, bo, true) || kgem->has_wc_mmap; 4749} 4750 4751static bool 4752try_upload__tiled_x(PixmapPtr pixmap, RegionRec *region, 4753 int x, int y, int w, int h, char *bits, int stride) 4754{ 4755 struct sna *sna = to_sna_from_pixmap(pixmap); 4756 struct sna_pixmap *priv = sna_pixmap(pixmap); 4757 const BoxRec *box; 4758 uint8_t *dst; 4759 int n; 4760 4761 if (!can_upload__tiled_x(&sna->kgem, priv->gpu_bo)) { 4762 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4763 return false; 4764 } 4765 4766 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4767 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4768 return false; 4769 4770 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4771 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4772 return false; 4773 4774 if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true)) { 4775 dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 4776 if (dst == NULL) 4777 return false; 4778 4779 kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo); 4780 } else { 4781 dst = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo); 4782 if (dst == NULL) 4783 return false; 4784 4785 kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo); 4786 } 4787 4788 box = region_rects(region); 4789 n = region_num_rects(region); 4790 4791 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4792 4793 if (sigtrap_get()) 4794 return false; 4795 4796 if (priv->gpu_bo->tiling) { 4797 do { 4798 DBG(("%s: copy tiled box (%d, %d)->(%d, %d)x(%d, %d)\n", 4799 __FUNCTION__, 4800 box->x1 - x, box->y1 - y, 4801 box->x1, box->y1, 4802 box->x2 - box->x1, box->y2 - box->y1)); 4803 4804 assert(box->x2 > box->x1); 4805 assert(box->y2 > box->y1); 4806 4807 assert(box->x1 >= 0); 4808 assert(box->y1 >= 0); 4809 assert(box->x2 <= pixmap->drawable.width); 4810 assert(box->y2 <= pixmap->drawable.height); 4811 4812 assert(box->x1 - x >= 0); 4813 assert(box->y1 - y >= 0); 4814 assert(box->x2 - x <= w); 4815 assert(box->y2 - y <= h); 4816 4817 memcpy_to_tiled_x(&sna->kgem, bits, dst, 4818 pixmap->drawable.bitsPerPixel, 4819 stride, priv->gpu_bo->pitch, 4820 box->x1 - x, box->y1 - y, 4821 box->x1, box->y1, 4822 box->x2 - box->x1, box->y2 - box->y1); 4823 box++; 4824 } while (--n); 4825 } else { 4826 do { 4827 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 4828 __FUNCTION__, 4829 box->x1 - x, box->y1 - y, 4830 box->x1, box->y1, 4831 box->x2 - box->x1, box->y2 - box->y1)); 4832 4833 assert(box->x2 > box->x1); 4834 assert(box->y2 > box->y1); 4835 4836 assert(box->x1 >= 0); 4837 assert(box->y1 >= 0); 4838 assert(box->x2 <= pixmap->drawable.width); 4839 assert(box->y2 <= pixmap->drawable.height); 4840 4841 assert(box->x1 - x >= 0); 4842 assert(box->y1 - y >= 0); 4843 assert(box->x2 - x <= w); 4844 assert(box->y2 - y <= h); 4845 4846 memcpy_blt(bits, dst, 4847 pixmap->drawable.bitsPerPixel, 4848 stride, priv->gpu_bo->pitch, 4849 box->x1 - x, box->y1 - y, 4850 box->x1, box->y1, 4851 box->x2 - box->x1, box->y2 - box->y1); 4852 box++; 4853 } while (--n); 4854 4855 if (!priv->shm) { 4856 pixmap->devPrivate.ptr = dst; 4857 pixmap->devKind = priv->gpu_bo->pitch; 4858 if (dst == MAP(priv->gpu_bo->map__cpu)) { 4859 priv->mapped = MAPPED_CPU; 4860 priv->cpu = true; 4861 } else 4862 priv->mapped = MAPPED_GTT; 4863 assert_pixmap_map(pixmap, priv); 4864 } 4865 } 4866 4867 sigtrap_put(); 4868 return true; 4869} 4870 4871static bool 4872try_upload__inplace(PixmapPtr pixmap, RegionRec *region, 4873 int x, int y, int w, int h, char *bits, int stride) 4874{ 4875 struct sna *sna = to_sna_from_pixmap(pixmap); 4876 struct sna_pixmap *priv = sna_pixmap(pixmap); 4877 bool ignore_cpu = false; 4878 bool replaces; 4879 const BoxRec *box; 4880 uint8_t *dst; 4881 int n; 4882 4883 if (!USE_INPLACE) 4884 return false; 4885 4886 assert(priv); 4887 4888 if (priv->shm && priv->gpu_damage == NULL) 4889 return false; 4890 4891 replaces = region_subsumes_pixmap(region, pixmap); 4892 4893 DBG(("%s: bo? %d, can map? %d, replaces? %d\n", __FUNCTION__, 4894 priv->gpu_bo != NULL, 4895 priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0, 4896 replaces)); 4897 4898 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 4899 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 4900 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 4901 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 4902 assert(!priv->pinned); 4903 assert(!priv->mapped); 4904 sna_damage_destroy(&priv->gpu_damage); 4905 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 4906 priv->gpu_bo = NULL; 4907 } 4908 4909 if (priv->gpu_bo && replaces) { 4910 if (UNDO) kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 4911 if (can_create_upload_tiled_x(sna, pixmap, priv, true) && 4912 (priv->cow || 4913 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4914 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4915 DBG(("%s: discarding unusable target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4916 kgem_bo_is_busy(priv->gpu_bo), 4917 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4918 sna_pixmap_free_gpu(sna, priv); 4919 ignore_cpu = true; 4920 } 4921 } 4922 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 4923 4924 if (priv->cow || 4925 (priv->move_to_gpu && !sna_pixmap_discard_shadow_damage(priv, replaces ? NULL : region))) { 4926 DBG(("%s: no, has pending COW? %d or move-to-gpu? %d\n", 4927 __FUNCTION__, priv->cow != NULL, priv->move_to_gpu != NULL)); 4928 return false; 4929 } 4930 4931 if (priv->gpu_damage && 4932 region_subsumes_damage(region, priv->gpu_damage)) { 4933 if (UNDO) kgem_bo_undo(&sna->kgem, priv->gpu_bo); 4934 if (can_create_upload_tiled_x(sna, pixmap, priv, priv->cpu_damage == NULL) && 4935 (__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo) || 4936 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))) { 4937 DBG(("%s: discarding unusable partial target bo (busy? %d, mappable? %d)\n", __FUNCTION__, 4938 kgem_bo_is_busy(priv->gpu_bo), 4939 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true))); 4940 sna_pixmap_free_gpu(sna, priv); 4941 ignore_cpu = priv->cpu_damage == NULL; 4942 if (priv->ptr) 4943 sna_damage_all(&priv->cpu_damage, pixmap); 4944 } 4945 } 4946 4947 if (priv->gpu_bo == NULL && 4948 !create_upload_tiled_x(sna, pixmap, priv, ignore_cpu)) 4949 return false; 4950 4951 DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling)); 4952 switch (priv->gpu_bo->tiling) { 4953 case I915_TILING_Y: 4954 break; 4955 case I915_TILING_X: 4956 if (!sna->kgem.memcpy_to_tiled_x) 4957 break; 4958 default: 4959 if (try_upload__tiled_x(pixmap, region, x, y, w, h, bits, stride)) 4960 goto done; 4961 break; 4962 } 4963 4964 if (priv->gpu_damage == NULL && !box_inplace(pixmap, ®ion->extents)) { 4965 DBG(("%s: no, too small to bother with using the GTT\n", __FUNCTION__)); 4966 return false; 4967 } 4968 4969 if (!kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 4970 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4971 return false; 4972 } 4973 4974 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 4975 MOVE_WRITE | (region->data ? MOVE_READ : 0))) 4976 return false; 4977 4978 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4979 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4980 return false; 4981 4982 dst = kgem_bo_map(&sna->kgem, priv->gpu_bo); 4983 if (dst == NULL) 4984 return false; 4985 4986 pixmap->devPrivate.ptr = dst; 4987 pixmap->devKind = priv->gpu_bo->pitch; 4988 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 4989 priv->cpu &= priv->mapped == MAPPED_CPU; 4990 assert(has_coherent_ptr(sna, priv, MOVE_WRITE)); 4991 4992 box = region_rects(region); 4993 n = region_num_rects(region); 4994 4995 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4996 4997 if (sigtrap_get()) 4998 return false; 4999 5000 do { 5001 DBG(("%s: copy lined box (%d, %d)->(%d, %d)x(%d, %d)\n", 5002 __FUNCTION__, 5003 box->x1 - x, box->y1 - y, 5004 box->x1, box->y1, 5005 box->x2 - box->x1, box->y2 - box->y1)); 5006 5007 assert(box->x2 > box->x1); 5008 assert(box->y2 > box->y1); 5009 5010 assert(box->x1 >= 0); 5011 assert(box->y1 >= 0); 5012 assert(box->x2 <= pixmap->drawable.width); 5013 assert(box->y2 <= pixmap->drawable.height); 5014 5015 assert(box->x1 - x >= 0); 5016 assert(box->y1 - y >= 0); 5017 assert(box->x2 - x <= w); 5018 assert(box->y2 - y <= h); 5019 5020 memcpy_blt(bits, dst, 5021 pixmap->drawable.bitsPerPixel, 5022 stride, priv->gpu_bo->pitch, 5023 box->x1 - x, box->y1 - y, 5024 box->x1, box->y1, 5025 box->x2 - box->x1, box->y2 - box->y1); 5026 box++; 5027 } while (--n); 5028 5029 sigtrap_put(); 5030 5031done: 5032 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5033 if (replaces) { 5034 sna_damage_all(&priv->gpu_damage, pixmap); 5035 } else { 5036 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5037 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 5038 } 5039 if (DAMAGE_IS_ALL(priv->gpu_damage)) 5040 sna_damage_destroy(&priv->cpu_damage); 5041 else 5042 sna_damage_subtract(&priv->cpu_damage, region); 5043 5044 if (priv->cpu_damage == NULL) { 5045 list_del(&priv->flush_list); 5046 sna_damage_all(&priv->gpu_damage, pixmap); 5047 } 5048 5049 add_shm_flush(sna, priv); 5050 } 5051 5052 assert(!priv->clear); 5053 return true; 5054} 5055 5056static bool 5057try_upload__blt(PixmapPtr pixmap, RegionRec *region, 5058 int x, int y, int w, int h, char *bits, int stride) 5059{ 5060 struct sna *sna = to_sna_from_pixmap(pixmap); 5061 struct sna_pixmap *priv; 5062 struct kgem_bo *src_bo; 5063 bool ok; 5064 5065 if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS) 5066 return false; 5067 5068 priv = sna_pixmap(pixmap); 5069 assert(priv); 5070 assert(priv->gpu_bo); 5071 assert(priv->gpu_bo->proxy == NULL); 5072 5073 if (priv->cpu_damage && 5074 (DAMAGE_IS_ALL(priv->cpu_damage) || 5075 sna_damage_contains_box__no_reduce(priv->cpu_damage, 5076 ®ion->extents)) && 5077 !box_inplace(pixmap, ®ion->extents)) { 5078 DBG(("%s: no, damage on CPU and too small\n", __FUNCTION__)); 5079 return false; 5080 } 5081 5082 src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true); 5083 if (src_bo == NULL) 5084 return false; 5085 5086 src_bo->pitch = stride; 5087 kgem_bo_mark_unreusable(src_bo); 5088 5089 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion->extents, 5090 MOVE_WRITE | MOVE_ASYNC_HINT | (region->data ? MOVE_READ : 0))) { 5091 kgem_bo_destroy(&sna->kgem, src_bo); 5092 return false; 5093 } 5094 5095 DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n", 5096 __FUNCTION__, x, y, w, h, region_num_rects(region))); 5097 5098 if (sigtrap_get() == 0) { 5099 ok = sna->render.copy_boxes(sna, GXcopy, 5100 &pixmap->drawable, src_bo, -x, -y, 5101 &pixmap->drawable, priv->gpu_bo, 0, 0, 5102 region_rects(region), 5103 region_num_rects(region), 5104 COPY_LAST); 5105 sigtrap_put(); 5106 } else 5107 ok = false; 5108 5109 kgem_bo_sync__cpu(&sna->kgem, src_bo); 5110 assert(src_bo->rq == NULL); 5111 kgem_bo_destroy(&sna->kgem, src_bo); 5112 5113 if (!ok) { 5114 DBG(("%s: copy failed!\n", __FUNCTION__)); 5115 return false; 5116 } 5117 5118 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5119 assert(!priv->clear); 5120 if (region_subsumes_drawable(region, &pixmap->drawable)) { 5121 sna_damage_all(&priv->gpu_damage, pixmap); 5122 } else { 5123 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5124 sna_damage_reduce_all(&priv->gpu_damage, pixmap); 5125 } 5126 if (DAMAGE_IS_ALL(priv->gpu_damage)) 5127 sna_damage_destroy(&priv->cpu_damage); 5128 else 5129 sna_damage_subtract(&priv->cpu_damage, region); 5130 if (priv->cpu_damage == NULL) { 5131 list_del(&priv->flush_list); 5132 if (sna_pixmap_free_cpu(sna, priv, priv->cpu)) 5133 sna_damage_all(&priv->gpu_damage, pixmap); 5134 } 5135 } 5136 priv->cpu = false; 5137 priv->clear = false; 5138 5139 return true; 5140} 5141 5142static bool ignore_cpu_damage(struct sna *sna, struct sna_pixmap *priv, const RegionRec *region) 5143{ 5144 if (region_subsumes_pixmap(region, priv->pixmap)) 5145 return true; 5146 5147 if (priv->cpu_damage != NULL) { 5148 if (DAMAGE_IS_ALL(priv->cpu_damage)) 5149 return false; 5150 5151 if (!box_inplace(priv->pixmap, ®ion->extents)) 5152 return false; 5153 5154 if (sna_damage_contains_box__no_reduce(priv->cpu_damage, ®ion->extents)) 5155 return false; 5156 } 5157 5158 return priv->gpu_bo == NULL || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo); 5159 5160} 5161 5162static bool 5163try_upload__fast(PixmapPtr pixmap, RegionRec *region, 5164 int x, int y, int w, int h, char *bits, int stride) 5165{ 5166 struct sna *sna = to_sna_from_pixmap(pixmap); 5167 struct sna_pixmap *priv; 5168 5169 if (wedged(sna)) 5170 return false; 5171 5172 priv = sna_pixmap(pixmap); 5173 if (priv == NULL) 5174 return false; 5175 5176 if (ignore_cpu_damage(sna, priv, region)) { 5177 DBG(("%s: ignore existing cpu damage (if any)\n", __FUNCTION__)); 5178 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5179 return true; 5180 } 5181 5182 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL || priv->cpu) { 5183 DBG(("%s: no, no gpu damage\n", __FUNCTION__)); 5184 return false; 5185 } 5186 5187 assert(priv->gpu_bo); 5188 assert(priv->gpu_bo->proxy == NULL); 5189 5190 if (try_upload__blt(pixmap, region, x, y, w, h, bits, stride)) 5191 return true; 5192 5193 if (try_upload__inplace(pixmap, region, x, y, w, h, bits, stride)) 5194 return true; 5195 5196 return false; 5197} 5198 5199static bool 5200sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5201 int x, int y, int w, int h, char *bits, int stride) 5202{ 5203 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5204 unsigned int hint; 5205 const BoxRec *box; 5206 int16_t dx, dy; 5207 int n; 5208 5209 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5210 5211 if (gc->alu != GXcopy) 5212 return false; 5213 5214 if (drawable->depth < 8) 5215 return false; 5216 5217 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5218 x += dx + drawable->x; 5219 y += dy + drawable->y; 5220 assert(region->extents.x1 >= x); 5221 assert(region->extents.y1 >= y); 5222 assert(region->extents.x2 <= x + w); 5223 assert(region->extents.y2 <= y + h); 5224 5225 if (try_upload__fast(pixmap, region, x, y, w, h, bits, stride)) 5226 return true; 5227 5228 hint = MOVE_WRITE; 5229 if (region_is_unclipped(region, pixmap->drawable.width, h) && 5230 (h+1)*stride > 65536) { 5231 DBG(("%s: segmented, unclipped large upload (%d bytes), marking WHOLE_HINT\n", 5232 __FUNCTION__, h*stride)); 5233 hint |= MOVE_WHOLE_HINT; 5234 } 5235 5236 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, region, hint)) 5237 return false; 5238 5239 if (sigtrap_get()) 5240 return false; 5241 5242 /* Region is pre-clipped and translated into pixmap space */ 5243 box = region_rects(region); 5244 n = region_num_rects(region); 5245 DBG(("%s: upload(%d, %d, %d, %d) x %d boxes\n", __FUNCTION__, x, y, w, h, n)); 5246 do { 5247 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 5248 __FUNCTION__, 5249 box->x1 - x, box->y1 - y, 5250 box->x1, box->y1, 5251 box->x2 - box->x1, box->y2 - box->y1)); 5252 5253 assert(box->x2 > box->x1); 5254 assert(box->y2 > box->y1); 5255 5256 assert(box->x1 >= 0); 5257 assert(box->y1 >= 0); 5258 assert(box->x2 <= pixmap->drawable.width); 5259 assert(box->y2 <= pixmap->drawable.height); 5260 5261 assert(box->x1 - x >= 0); 5262 assert(box->y1 - y >= 0); 5263 assert(box->x2 - x <= w); 5264 assert(box->y2 - y <= h); 5265 5266 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_WRITE)); 5267 assert(pixmap->devKind); 5268 memcpy_blt(bits, pixmap->devPrivate.ptr, 5269 pixmap->drawable.bitsPerPixel, 5270 stride, pixmap->devKind, 5271 box->x1 - x, box->y1 - y, 5272 box->x1, box->y1, 5273 box->x2 - box->x1, box->y2 - box->y1); 5274 box++; 5275 } while (--n); 5276 5277 sigtrap_put(); 5278 assert_pixmap_damage(pixmap); 5279 return true; 5280} 5281 5282static inline uint8_t byte_reverse(uint8_t b) 5283{ 5284 return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; 5285} 5286 5287static inline uint8_t blt_depth(int depth) 5288{ 5289 switch (depth) { 5290 case 8: return 0; 5291 case 15: return 0x2; 5292 case 16: return 0x1; 5293 default: return 0x3; 5294 } 5295} 5296 5297inline static void blt_done(struct sna *sna) 5298{ 5299 sna->blt_state.fill_bo = 0; 5300 if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) { 5301 DBG(("%s: flushing BLT operation on empty ring\n", 5302 __FUNCTION__)); 5303 _kgem_submit(&sna->kgem); 5304 } 5305} 5306 5307static bool 5308sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5309 int x, int y, int w, int h, char *bits) 5310{ 5311 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5312 struct sna *sna = to_sna_from_pixmap(pixmap); 5313 struct sna_damage **damage; 5314 struct kgem_bo *bo; 5315 const BoxRec *box; 5316 int16_t dx, dy; 5317 int n; 5318 uint8_t rop = copy_ROP[gc->alu]; 5319 5320 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5321 ®ion->extents, &damage); 5322 if (bo == NULL) 5323 return false; 5324 5325 if (bo->tiling == I915_TILING_Y) { 5326 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5327 assert(bo == __sna_pixmap_get_bo(pixmap)); 5328 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5329 if (bo == NULL) { 5330 DBG(("%s: fallback -- unable to change tiling\n", 5331 __FUNCTION__)); 5332 return false; 5333 } 5334 } 5335 5336 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5337 return false; 5338 5339 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5340 if (damage) 5341 sna_damage_add_to_pixmap(damage, region, pixmap); 5342 assert_pixmap_damage(pixmap); 5343 5344 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5345 5346 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5347 x += dx + drawable->x; 5348 y += dy + drawable->y; 5349 5350 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5351 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5352 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5353 5354 /* Region is pre-clipped and translated into pixmap space */ 5355 box = region_rects(region); 5356 n = region_num_rects(region); 5357 do { 5358 int bx1 = (box->x1 - x) & ~7; 5359 int bx2 = (box->x2 - x + 7) & ~7; 5360 int bw = (bx2 - bx1)/8; 5361 int bh = box->y2 - box->y1; 5362 int bstride = ALIGN(bw, 2); 5363 struct kgem_bo *upload; 5364 void *ptr; 5365 5366 if (!kgem_check_batch(&sna->kgem, 10) || 5367 !kgem_check_bo_fenced(&sna->kgem, bo) || 5368 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5369 kgem_submit(&sna->kgem); 5370 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5371 return false; 5372 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5373 } 5374 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5375 5376 upload = kgem_create_buffer(&sna->kgem, 5377 bstride*bh, 5378 KGEM_BUFFER_WRITE_INPLACE, 5379 &ptr); 5380 if (!upload) 5381 break; 5382 5383 5384 if (sigtrap_get() == 0) { 5385 int src_stride = BitmapBytePad(w); 5386 uint8_t *dst = ptr; 5387 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5388 uint32_t *b; 5389 5390 bstride -= bw; 5391 src_stride -= bw; 5392 5393 do { 5394 int i = bw; 5395 assert(src >= (uint8_t *)bits); 5396 do { 5397 *dst++ = byte_reverse(*src++); 5398 } while (--i); 5399 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5400 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5401 dst += bstride; 5402 src += src_stride; 5403 } while (--bh); 5404 5405 assert(sna->kgem.mode == KGEM_BLT); 5406 if (sna->kgem.gen >= 0100) { 5407 b = sna->kgem.batch + sna->kgem.nbatch; 5408 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 5409 b[0] |= ((box->x1 - x) & 7) << 17; 5410 b[1] = bo->pitch; 5411 if (bo->tiling) { 5412 b[0] |= BLT_DST_TILED; 5413 b[1] >>= 2; 5414 } 5415 b[1] |= blt_depth(drawable->depth) << 24; 5416 b[1] |= rop << 16; 5417 b[2] = box->y1 << 16 | box->x1; 5418 b[3] = box->y2 << 16 | box->x2; 5419 *(uint64_t *)(b+4) = 5420 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5421 I915_GEM_DOMAIN_RENDER << 16 | 5422 I915_GEM_DOMAIN_RENDER | 5423 KGEM_RELOC_FENCED, 5424 0); 5425 *(uint64_t *)(b+6) = 5426 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5427 I915_GEM_DOMAIN_RENDER << 16 | 5428 KGEM_RELOC_FENCED, 5429 0); 5430 b[8] = gc->bgPixel; 5431 b[9] = gc->fgPixel; 5432 5433 sna->kgem.nbatch += 10; 5434 } else { 5435 b = sna->kgem.batch + sna->kgem.nbatch; 5436 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 5437 b[0] |= ((box->x1 - x) & 7) << 17; 5438 b[1] = bo->pitch; 5439 if (sna->kgem.gen >= 040 && bo->tiling) { 5440 b[0] |= BLT_DST_TILED; 5441 b[1] >>= 2; 5442 } 5443 b[1] |= blt_depth(drawable->depth) << 24; 5444 b[1] |= rop << 16; 5445 b[2] = box->y1 << 16 | box->x1; 5446 b[3] = box->y2 << 16 | box->x2; 5447 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5448 I915_GEM_DOMAIN_RENDER << 16 | 5449 I915_GEM_DOMAIN_RENDER | 5450 KGEM_RELOC_FENCED, 5451 0); 5452 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5453 I915_GEM_DOMAIN_RENDER << 16 | 5454 KGEM_RELOC_FENCED, 5455 0); 5456 b[6] = gc->bgPixel; 5457 b[7] = gc->fgPixel; 5458 5459 sna->kgem.nbatch += 8; 5460 } 5461 sigtrap_put(); 5462 } 5463 kgem_bo_destroy(&sna->kgem, upload); 5464 5465 box++; 5466 } while (--n); 5467 5468 blt_done(sna); 5469 return true; 5470} 5471 5472static bool 5473sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 5474 int x, int y, int w, int h, int left,char *bits) 5475{ 5476 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5477 struct sna *sna = to_sna_from_pixmap(pixmap); 5478 struct sna_damage **damage; 5479 struct kgem_bo *bo; 5480 int16_t dx, dy; 5481 unsigned i, skip; 5482 5483 if (gc->alu != GXcopy) 5484 return false; 5485 5486 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 5487 ®ion->extents, &damage); 5488 if (bo == NULL) 5489 return false; 5490 5491 if (bo->tiling == I915_TILING_Y) { 5492 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 5493 assert(bo == __sna_pixmap_get_bo(pixmap)); 5494 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 5495 if (bo == NULL) { 5496 DBG(("%s: fallback -- unable to change tiling\n", 5497 __FUNCTION__)); 5498 return false; 5499 } 5500 } 5501 5502 if (!kgem_bo_can_blt(&sna->kgem, bo)) 5503 return false; 5504 5505 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 5506 if (damage) 5507 sna_damage_add_to_pixmap(damage, region, pixmap); 5508 assert_pixmap_damage(pixmap); 5509 5510 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 5511 5512 get_drawable_deltas(drawable, pixmap, &dx, &dy); 5513 x += dx + drawable->x; 5514 y += dy + drawable->y; 5515 5516 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 5517 assert(kgem_bo_can_blt(&sna->kgem, bo)); 5518 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5519 5520 skip = h * BitmapBytePad(w + left); 5521 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { 5522 const BoxRec *box = region_rects(region); 5523 int n = region_num_rects(region); 5524 5525 if ((gc->planemask & i) == 0) 5526 continue; 5527 5528 /* Region is pre-clipped and translated into pixmap space */ 5529 do { 5530 int bx1 = (box->x1 - x) & ~7; 5531 int bx2 = (box->x2 - x + 7) & ~7; 5532 int bw = (bx2 - bx1)/8; 5533 int bh = box->y2 - box->y1; 5534 int bstride = ALIGN(bw, 2); 5535 struct kgem_bo *upload; 5536 void *ptr; 5537 5538 if (!kgem_check_batch(&sna->kgem, 14) || 5539 !kgem_check_bo_fenced(&sna->kgem, bo) || 5540 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 5541 kgem_submit(&sna->kgem); 5542 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 5543 return false; 5544 _kgem_set_mode(&sna->kgem, KGEM_BLT); 5545 } 5546 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 5547 5548 upload = kgem_create_buffer(&sna->kgem, 5549 bstride*bh, 5550 KGEM_BUFFER_WRITE_INPLACE, 5551 &ptr); 5552 if (!upload) 5553 break; 5554 5555 if (sigtrap_get() == 0) { 5556 int src_stride = BitmapBytePad(w); 5557 uint8_t *src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 5558 uint8_t *dst = ptr; 5559 uint32_t *b; 5560 5561 bstride -= bw; 5562 src_stride -= bw; 5563 do { 5564 int j = bw; 5565 assert(src >= (uint8_t *)bits); 5566 do { 5567 *dst++ = byte_reverse(*src++); 5568 } while (--j); 5569 assert(src <= (uint8_t *)bits + BitmapBytePad(w) * h); 5570 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 5571 dst += bstride; 5572 src += src_stride; 5573 } while (--bh); 5574 5575 assert(sna->kgem.mode == KGEM_BLT); 5576 if (sna->kgem.gen >= 0100) { 5577 assert(sna->kgem.mode == KGEM_BLT); 5578 b = sna->kgem.batch + sna->kgem.nbatch; 5579 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 12; 5580 b[0] |= ((box->x1 - x) & 7) << 17; 5581 b[1] = bo->pitch; 5582 if (bo->tiling) { 5583 b[0] |= BLT_DST_TILED; 5584 b[1] >>= 2; 5585 } 5586 b[1] |= 1 << 31; /* solid pattern */ 5587 b[1] |= blt_depth(drawable->depth) << 24; 5588 b[1] |= 0xce << 16; /* S or (D and !P) */ 5589 b[2] = box->y1 << 16 | box->x1; 5590 b[3] = box->y2 << 16 | box->x2; 5591 *(uint64_t *)(b+4) = 5592 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 5593 I915_GEM_DOMAIN_RENDER << 16 | 5594 I915_GEM_DOMAIN_RENDER | 5595 KGEM_RELOC_FENCED, 5596 0); 5597 *(uint64_t *)(b+6) = 5598 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 5599 I915_GEM_DOMAIN_RENDER << 16 | 5600 KGEM_RELOC_FENCED, 5601 0); 5602 b[8] = 0; 5603 b[9] = i; 5604 b[10] = i; 5605 b[11] = i; 5606 b[12] = -1; 5607 b[13] = -1; 5608 sna->kgem.nbatch += 14; 5609 } else { 5610 b = sna->kgem.batch + sna->kgem.nbatch; 5611 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20 | 10; 5612 b[0] |= ((box->x1 - x) & 7) << 17; 5613 b[1] = bo->pitch; 5614 if (sna->kgem.gen >= 040 && bo->tiling) { 5615 b[0] |= BLT_DST_TILED; 5616 b[1] >>= 2; 5617 } 5618 b[1] |= 1 << 31; /* solid pattern */ 5619 b[1] |= blt_depth(drawable->depth) << 24; 5620 b[1] |= 0xce << 16; /* S or (D and !P) */ 5621 b[2] = box->y1 << 16 | box->x1; 5622 b[3] = box->y2 << 16 | box->x2; 5623 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 5624 I915_GEM_DOMAIN_RENDER << 16 | 5625 I915_GEM_DOMAIN_RENDER | 5626 KGEM_RELOC_FENCED, 5627 0); 5628 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 5629 I915_GEM_DOMAIN_RENDER << 16 | 5630 KGEM_RELOC_FENCED, 5631 0); 5632 b[6] = 0; 5633 b[7] = i; 5634 b[8] = i; 5635 b[9] = i; 5636 b[10] = -1; 5637 b[11] = -1; 5638 sna->kgem.nbatch += 12; 5639 } 5640 sigtrap_put(); 5641 } 5642 kgem_bo_destroy(&sna->kgem, upload); 5643 5644 box++; 5645 } while (--n); 5646 } 5647 5648 blt_done(sna); 5649 return true; 5650} 5651 5652static void 5653sna_put_image(DrawablePtr drawable, GCPtr gc, int depth, 5654 int x, int y, int w, int h, int left, int format, 5655 char *bits) 5656{ 5657 PixmapPtr pixmap = get_drawable_pixmap(drawable); 5658 struct sna *sna = to_sna_from_pixmap(pixmap); 5659 struct sna_pixmap *priv = sna_pixmap(pixmap); 5660 RegionRec region; 5661 int16_t dx, dy; 5662 5663 DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n", 5664 __FUNCTION__, x, y, w, h, depth, format)); 5665 5666 if (w == 0 || h == 0) 5667 return; 5668 5669 region.extents.x1 = x + drawable->x; 5670 region.extents.y1 = y + drawable->y; 5671 region.extents.x2 = region.extents.x1 + w; 5672 region.extents.y2 = region.extents.y1 + h; 5673 region.data = NULL; 5674 5675 if (!region_is_singular(gc->pCompositeClip) || 5676 gc->pCompositeClip->extents.x1 > region.extents.x1 || 5677 gc->pCompositeClip->extents.y1 > region.extents.y1 || 5678 gc->pCompositeClip->extents.x2 < region.extents.x2 || 5679 gc->pCompositeClip->extents.y2 < region.extents.y2) { 5680 if (!RegionIntersect(®ion, ®ion, gc->pCompositeClip) || 5681 box_empty(®ion.extents)) 5682 return; 5683 } 5684 5685 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 5686 RegionTranslate(®ion, dx, dy); 5687 5688 if (priv == NULL) { 5689 DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n", 5690 __FUNCTION__, x, y, w, h)); 5691 goto fallback; 5692 } 5693 5694 if (FORCE_FALLBACK) 5695 goto fallback; 5696 5697 if (wedged(sna)) 5698 goto fallback; 5699 5700 if (!ACCEL_PUT_IMAGE) 5701 goto fallback; 5702 5703 switch (format) { 5704 case ZPixmap: 5705 if (!PM_IS_SOLID(drawable, gc->planemask)) 5706 goto fallback; 5707 5708 if (sna_put_zpixmap_blt(drawable, gc, ®ion, 5709 x, y, w, h, 5710 bits, PixmapBytePad(w, depth))) 5711 return; 5712 break; 5713 5714 case XYBitmap: 5715 if (!PM_IS_SOLID(drawable, gc->planemask)) 5716 goto fallback; 5717 5718 if (sna_put_xybitmap_blt(drawable, gc, ®ion, 5719 x, y, w, h, 5720 bits)) 5721 return; 5722 break; 5723 5724 case XYPixmap: 5725 if (sna_put_xypixmap_blt(drawable, gc, ®ion, 5726 x, y, w, h, left, 5727 bits)) 5728 return; 5729 break; 5730 5731 default: 5732 return; 5733 } 5734 5735fallback: 5736 DBG(("%s: fallback\n", __FUNCTION__)); 5737 RegionTranslate(®ion, -dx, -dy); 5738 5739 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 5740 goto out; 5741 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 5742 format == XYPixmap ? 5743 MOVE_READ | MOVE_WRITE : 5744 drawable_gc_flags(drawable, gc, false))) 5745 goto out; 5746 5747 if (sigtrap_get() == 0) { 5748 DBG(("%s: fbPutImage(%d, %d, %d, %d)\n", 5749 __FUNCTION__, x, y, w, h)); 5750 fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits); 5751 FALLBACK_FLUSH(drawable); 5752 sigtrap_put(); 5753 } 5754out: 5755 sna_gc_move_to_gpu(gc); 5756 RegionUninit(®ion); 5757} 5758 5759static bool 5760source_contains_region(struct sna_damage *damage, 5761 const RegionRec *region, int16_t dx, int16_t dy) 5762{ 5763 BoxRec box; 5764 5765 if (DAMAGE_IS_ALL(damage)) 5766 return true; 5767 5768 if (damage == NULL) 5769 return false; 5770 5771 box = region->extents; 5772 box.x1 += dx; 5773 box.x2 += dx; 5774 box.y1 += dy; 5775 box.y2 += dy; 5776 return sna_damage_contains_box__no_reduce(damage, &box); 5777} 5778 5779static bool 5780move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv, 5781 RegionRec *region, int16_t dx, int16_t dy, 5782 uint8_t alu, bool dst_is_gpu) 5783{ 5784 int w = region->extents.x2 - region->extents.x1; 5785 int h = region->extents.y2 - region->extents.y1; 5786 int count; 5787 5788 assert_pixmap_map(pixmap, priv); 5789 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 5790 assert(priv->gpu_bo); 5791 return true; 5792 } 5793 5794 if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) { 5795 DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n", 5796 __FUNCTION__, 5797 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5798 priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0, 5799 priv->cpu)); 5800 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 5801 return false; 5802 5803 if (priv->cpu && 5804 source_contains_region(priv->cpu_damage, region, dx, dy)) 5805 return false; 5806 } 5807 5808 if (priv->gpu_bo) { 5809 DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n", 5810 __FUNCTION__, 5811 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 5812 priv->cpu, priv->gpu_bo->tiling)); 5813 5814 if (priv->cpu_damage == NULL) 5815 return true; 5816 5817 if (alu != GXcopy) 5818 return true; 5819 5820 if (!priv->cpu) 5821 return true; 5822 5823 if (priv->gpu_bo->tiling) 5824 return true; 5825 5826 RegionTranslate(region, dx, dy); 5827 count = region_subsumes_damage(region, priv->cpu_damage); 5828 RegionTranslate(region, -dx, -dy); 5829 if (count) 5830 return true; 5831 } else { 5832 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 5833 return false; 5834 if (priv->shm) 5835 return false; 5836 } 5837 5838 count = priv->source_count++; 5839 if (priv->cpu_bo) { 5840 if (priv->cpu_bo->flush && count > SOURCE_BIAS) 5841 return true; 5842 5843 if (sna_pixmap_default_tiling(to_sna_from_pixmap(pixmap), pixmap) == I915_TILING_NONE) 5844 return false; 5845 5846 if (priv->cpu) 5847 return false; 5848 5849 return count > SOURCE_BIAS; 5850 } else { 5851 if (w == pixmap->drawable.width && h == pixmap->drawable.height) 5852 return count > SOURCE_BIAS; 5853 5854 return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height; 5855 } 5856} 5857 5858static const BoxRec * 5859reorder_boxes(const BoxRec *box, int n, int dx, int dy) 5860{ 5861 const BoxRec *next, *base; 5862 BoxRec *new; 5863 5864 DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy)); 5865 5866 if (dy <= 0 && dx <= 0) { 5867 BoxRec *tmp; 5868 5869 new = malloc(sizeof(BoxRec) * n); 5870 if (new == NULL) 5871 return NULL; 5872 5873 tmp = new; 5874 next = box + n; 5875 do { 5876 *tmp++ = *--next; 5877 } while (next != box); 5878 } else if (dy < 0) { 5879 new = malloc(sizeof(BoxRec) * n); 5880 if (new == NULL) 5881 return NULL; 5882 5883 base = next = box + n - 1; 5884 while (base >= box) { 5885 const BoxRec *tmp; 5886 5887 while (next >= box && base->y1 == next->y1) 5888 next--; 5889 tmp = next + 1; 5890 while (tmp <= base) 5891 *new++ = *tmp++; 5892 base = next; 5893 } 5894 new -= n; 5895 } else { 5896 new = malloc(sizeof(BoxRec) * n); 5897 if (!new) 5898 return NULL; 5899 5900 base = next = box; 5901 while (base < box + n) { 5902 const BoxRec *tmp; 5903 5904 while (next < box + n && next->y1 == base->y1) 5905 next++; 5906 tmp = next; 5907 while (tmp != base) 5908 *new++ = *--tmp; 5909 base = next; 5910 } 5911 new -= n; 5912 } 5913 5914 return new; 5915} 5916 5917static void 5918sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5919 RegionPtr region,int dx, int dy, 5920 Pixel bitplane, void *closure) 5921{ 5922 PixmapPtr pixmap = get_drawable_pixmap(src); 5923 struct sna *sna = to_sna_from_pixmap(pixmap); 5924 struct sna_pixmap *priv = sna_pixmap(pixmap); 5925 const BoxRec *box = region_rects(region); 5926 int n = region_num_rects(region); 5927 int alu = gc ? gc->alu : GXcopy; 5928 int16_t tx, ty, sx, sy; 5929 5930 assert(pixmap == get_drawable_pixmap(dst)); 5931 5932 assert(region_num_rects(region)); 5933 if (((dx | dy) == 0 && alu == GXcopy)) 5934 return; 5935 5936 if (n > 1 && (dx | dy) < 0) { 5937 box = reorder_boxes(box, n, dx, dy); 5938 if (box == NULL) 5939 return; 5940 } 5941 5942 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n", 5943 __FUNCTION__, n, 5944 region->extents.x1, region->extents.y1, 5945 region->extents.x2, region->extents.y2, 5946 dx, dy, alu, 5947 pixmap->drawable.width, pixmap->drawable.height)); 5948 5949 get_drawable_deltas(dst, pixmap, &tx, &ty); 5950 get_drawable_deltas(src, pixmap, &sx, &sy); 5951 sx += dx; 5952 sy += dy; 5953 5954 if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage)) { 5955 DBG(("%s: unattached, or all damaged on CPU\n", __FUNCTION__)); 5956 goto fallback; 5957 } 5958 5959 if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) { 5960 assert(priv->gpu_bo); 5961 5962 if (alu == GXcopy && priv->clear) 5963 goto free_boxes; 5964 5965 assert(priv->gpu_bo->proxy == NULL); 5966 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) { 5967 DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n", 5968 __FUNCTION__)); 5969 goto fallback; 5970 } 5971 assert(priv->cpu_damage == NULL); 5972 5973 if (!sna->render.copy_boxes(sna, alu, 5974 &pixmap->drawable, priv->gpu_bo, sx, sy, 5975 &pixmap->drawable, priv->gpu_bo, tx, ty, 5976 box, n, small_copy(region))) { 5977 DBG(("%s: fallback - accelerated copy boxes failed\n", 5978 __FUNCTION__)); 5979 goto fallback; 5980 } 5981 5982 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 5983 assert(!priv->clear); 5984 if (sna_pixmap_free_cpu(sna, priv, false)) { 5985 sna_damage_all(&priv->gpu_damage, pixmap); 5986 } else { 5987 RegionTranslate(region, tx, ty); 5988 sna_damage_add_to_pixmap(&priv->gpu_damage, region, pixmap); 5989 } 5990 } 5991 assert_pixmap_damage(pixmap); 5992 } else { 5993fallback: 5994 DBG(("%s: fallback\n", __FUNCTION__)); 5995 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 5996 goto free_boxes; 5997 5998 if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) { 5999 assert(pixmap->devKind); 6000 if (sigtrap_get() == 0) { 6001 FbBits *dst_bits, *src_bits; 6002 int stride = pixmap->devKind; 6003 int bpp = pixmap->drawable.bitsPerPixel; 6004 int i; 6005 6006 dst_bits = (FbBits *) 6007 ((char *)pixmap->devPrivate.ptr + 6008 ty * stride + tx * bpp / 8); 6009 src_bits = (FbBits *) 6010 ((char *)pixmap->devPrivate.ptr + 6011 sy * stride + sx * bpp / 8); 6012 6013 for (i = 0; i < n; i++) 6014 memmove_box(src_bits, dst_bits, 6015 bpp, stride, box+i, 6016 dx, dy); 6017 sigtrap_put(); 6018 } 6019 } else { 6020 if (gc && !sna_gc_move_to_cpu(gc, dst, region)) 6021 goto out; 6022 6023 if (sigtrap_get() == 0) { 6024 miCopyRegion(src, dst, gc, 6025 region, dx, dy, 6026 fbCopyNtoN, 0, NULL); 6027 sigtrap_put(); 6028 } 6029 6030 if (gc) 6031out: 6032 sna_gc_move_to_gpu(gc); 6033 } 6034 } 6035 6036free_boxes: 6037 if (box != region_rects(region)) 6038 free((void *)box); 6039} 6040 6041static inline bool 6042sna_pixmap_is_gpu(PixmapPtr pixmap) 6043{ 6044 struct sna_pixmap *priv = sna_pixmap(pixmap); 6045 6046 if (priv == NULL || priv->clear) 6047 return false; 6048 6049 if (DAMAGE_IS_ALL(priv->gpu_damage) || 6050 (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy)) 6051 return true; 6052 6053 return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo); 6054} 6055 6056static int 6057copy_prefer_gpu(struct sna *sna, 6058 struct sna_pixmap *dst_priv, 6059 struct sna_pixmap *src_priv, 6060 RegionRec *region, 6061 int16_t dx, int16_t dy) 6062{ 6063 assert(dst_priv); 6064 6065 if (wedged(sna) && !dst_priv->pinned) 6066 return 0; 6067 6068 if (src_priv == NULL) { 6069 DBG(("%s: source unattached, use cpu\n", __FUNCTION__)); 6070 return 0; 6071 } 6072 6073 if (src_priv->clear) { 6074 DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__)); 6075 return 0; 6076 } 6077 6078 if (src_priv->gpu_damage && 6079 !source_contains_region(src_priv->cpu_damage, region, dx, dy)) { 6080 DBG(("%s: source has gpu damage, force gpu? %d\n", 6081 __FUNCTION__, src_priv->cpu_damage == NULL)); 6082 assert(src_priv->gpu_bo); 6083 return src_priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU; 6084 } 6085 6086 if (src_priv->cpu_bo && kgem_bo_is_busy(src_priv->cpu_bo)) { 6087 DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__)); 6088 return PREFER_GPU | FORCE_GPU; 6089 } 6090 6091 if (source_contains_region(src_priv->cpu_damage, region, dx, dy)) 6092 return src_priv->cpu_bo && kgem_is_idle(&sna->kgem); 6093 6094 DBG(("%s: source has GPU bo? %d\n", 6095 __FUNCTION__, src_priv->gpu_bo != NULL)); 6096 return src_priv->gpu_bo != NULL; 6097} 6098 6099static bool use_shm_bo(struct sna *sna, 6100 struct kgem_bo *bo, 6101 struct sna_pixmap *priv, 6102 int alu, bool replaces) 6103{ 6104 if (priv == NULL || priv->cpu_bo == NULL) { 6105 DBG(("%s: no, not attached\n", __FUNCTION__)); 6106 return false; 6107 } 6108 6109 if (!priv->shm && !priv->cpu) { 6110 DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__)); 6111 return true; 6112 } 6113 6114 if (alu != GXcopy) { 6115 DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu)); 6116 return true; 6117 } 6118 6119 if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) { 6120 DBG(("%s: yes, dst is busy\n", __FUNCTION__)); 6121 return true; 6122 } 6123 6124 if (priv->cpu_bo->needs_flush && 6125 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 6126 DBG(("%s: yes, src is busy\n", __FUNCTION__)); 6127 return true; 6128 } 6129 6130 return false; 6131} 6132 6133static bool 6134sna_damage_contains_box__no_reduce__offset(struct sna_damage *damage, 6135 const BoxRec *extents, 6136 int16_t dx, int16_t dy) 6137{ 6138 BoxRec _extents; 6139 6140 if (dx | dy) { 6141 _extents.x1 = extents->x1 + dx; 6142 _extents.x2 = extents->x2 + dx; 6143 _extents.y1 = extents->y1 + dy; 6144 _extents.y2 = extents->y2 + dy; 6145 extents = &_extents; 6146 } 6147 6148 return sna_damage_contains_box__no_reduce(damage, extents); 6149} 6150 6151static bool 6152sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu, 6153 PixmapPtr src_pixmap, struct sna_pixmap *src_priv, 6154 int dx, int dy, 6155 PixmapPtr dst_pixmap, struct sna_pixmap *dst_priv, 6156 bool replaces) 6157{ 6158 const BoxRec *box; 6159 char *ptr; 6160 int n; 6161 6162 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6163 6164 if (alu != GXcopy) { 6165 DBG(("%s - no, complex alu [%d]\n", __FUNCTION__, alu)); 6166 return false; 6167 } 6168 6169 if (!USE_INPLACE) { 6170 DBG(("%s - no, compile time disabled\n", __FUNCTION__)); 6171 return false; 6172 } 6173 6174 if (dst_priv == src_priv) { 6175 DBG(("%s - no, dst == src\n", __FUNCTION__)); 6176 return false; 6177 } 6178 6179 if (src_priv == NULL || src_priv->gpu_bo == NULL) { 6180 if (dst_priv && dst_priv->gpu_bo) 6181 goto upload_inplace; 6182 6183 DBG(("%s - no, no src or dst GPU bo\n", __FUNCTION__)); 6184 return false; 6185 } 6186 6187 switch (src_priv->gpu_bo->tiling) { 6188 case I915_TILING_Y: 6189 DBG(("%s - no, bad src tiling [Y]\n", __FUNCTION__)); 6190 return false; 6191 case I915_TILING_X: 6192 if (!sna->kgem.memcpy_from_tiled_x) { 6193 DBG(("%s - no, bad src tiling [X]\n", __FUNCTION__)); 6194 return false; 6195 } 6196 default: 6197 break; 6198 } 6199 6200 if (src_priv->move_to_gpu && !src_priv->move_to_gpu(sna, src_priv, MOVE_READ)) { 6201 DBG(("%s - no, pending src move-to-gpu failed\n", __FUNCTION__)); 6202 return false; 6203 } 6204 6205 if (!kgem_bo_can_map__cpu(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC)) { 6206 DBG(("%s - no, cannot map src for reads into the CPU\n", __FUNCTION__)); 6207 return false; 6208 } 6209 6210 if (src_priv->gpu_damage == NULL || 6211 !(DAMAGE_IS_ALL(src_priv->gpu_damage) || 6212 sna_damage_contains_box__no_reduce__offset(src_priv->gpu_damage, 6213 ®ion->extents, 6214 dx, dy))) { 6215 DBG(("%s - no, src is not damaged on the GPU\n", __FUNCTION__)); 6216 return false; 6217 } 6218 6219 assert(sna_damage_contains_box__offset(&src_priv->gpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_IN); 6220 assert(sna_damage_contains_box__offset(&src_priv->cpu_damage, ®ion->extents, dx, dy) == PIXMAN_REGION_OUT); 6221 6222 ptr = kgem_bo_map__cpu(&sna->kgem, src_priv->gpu_bo); 6223 if (ptr == NULL) { 6224 DBG(("%s - no, map failed\n", __FUNCTION__)); 6225 return false; 6226 } 6227 6228 if (dst_priv && 6229 !sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6230 region, MOVE_WRITE | MOVE_INPLACE_HINT)) { 6231 DBG(("%s - no, dst sync failed\n", __FUNCTION__)); 6232 return false; 6233 } 6234 6235 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC); 6236 6237 if (sigtrap_get()) 6238 return false; 6239 6240 box = region_rects(region); 6241 n = region_num_rects(region); 6242 if (src_priv->gpu_bo->tiling) { 6243 DBG(("%s: copy from a tiled CPU map\n", __FUNCTION__)); 6244 assert(dst_pixmap->devKind); 6245 do { 6246 memcpy_from_tiled_x(&sna->kgem, ptr, dst_pixmap->devPrivate.ptr, 6247 src_pixmap->drawable.bitsPerPixel, 6248 src_priv->gpu_bo->pitch, 6249 dst_pixmap->devKind, 6250 box->x1 + dx, box->y1 + dy, 6251 box->x1, box->y1, 6252 box->x2 - box->x1, box->y2 - box->y1); 6253 box++; 6254 } while (--n); 6255 } else { 6256 DBG(("%s: copy from a linear CPU map\n", __FUNCTION__)); 6257 assert(dst_pixmap->devKind); 6258 do { 6259 memcpy_blt(ptr, dst_pixmap->devPrivate.ptr, 6260 src_pixmap->drawable.bitsPerPixel, 6261 src_priv->gpu_bo->pitch, 6262 dst_pixmap->devKind, 6263 box->x1 + dx, box->y1 + dy, 6264 box->x1, box->y1, 6265 box->x2 - box->x1, box->y2 - box->y1); 6266 box++; 6267 } while (--n); 6268 6269 if (!src_priv->shm) { 6270 assert(ptr == MAP(src_priv->gpu_bo->map__cpu)); 6271 src_pixmap->devPrivate.ptr = ptr; 6272 src_pixmap->devKind = src_priv->gpu_bo->pitch; 6273 src_priv->mapped = MAPPED_CPU; 6274 assert_pixmap_map(src_pixmap, src_priv); 6275 src_priv->cpu = true; 6276 } 6277 } 6278 6279 sigtrap_put(); 6280 6281 return true; 6282 6283upload_inplace: 6284 switch (dst_priv->gpu_bo->tiling) { 6285 case I915_TILING_Y: 6286 DBG(("%s - no, bad dst tiling [Y]\n", __FUNCTION__)); 6287 return false; 6288 case I915_TILING_X: 6289 if (!sna->kgem.memcpy_to_tiled_x) { 6290 DBG(("%s - no, bad dst tiling [X]\n", __FUNCTION__)); 6291 return false; 6292 } 6293 default: 6294 break; 6295 } 6296 6297 if (dst_priv->move_to_gpu) { 6298 DBG(("%s - no, pending dst move-to-gpu\n", __FUNCTION__)); 6299 return false; 6300 } 6301 6302 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo) || 6303 __kgem_bo_is_busy(&sna->kgem, dst_priv->gpu_bo)) { 6304 if (replaces && !dst_priv->pinned) { 6305 unsigned create; 6306 struct kgem_bo *bo; 6307 6308 create = CREATE_CPU_MAP | CREATE_INACTIVE; 6309 if (dst_priv->gpu_bo->scanout) 6310 create |= CREATE_SCANOUT; 6311 6312 bo = kgem_create_2d(&sna->kgem, 6313 dst_pixmap->drawable.width, 6314 dst_pixmap->drawable.height, 6315 dst_pixmap->drawable.bitsPerPixel, 6316 dst_priv->gpu_bo->tiling, 6317 create); 6318 if (bo == NULL) 6319 return false; 6320 6321 sna_pixmap_unmap(dst_pixmap, dst_priv); 6322 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 6323 dst_priv->gpu_bo = bo; 6324 } else { 6325 DBG(("%s - no, dst is busy\n", __FUNCTION__)); 6326 return false; 6327 } 6328 6329 if (!can_upload__tiled_x(&sna->kgem, dst_priv->gpu_bo)) { 6330 DBG(("%s - no, cannot map dst for reads into the CPU\n", __FUNCTION__)); 6331 return false; 6332 } 6333 } 6334 6335 if (src_priv && 6336 !sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6337 region, MOVE_READ)) { 6338 DBG(("%s - no, src sync failed\n", __FUNCTION__)); 6339 return false; 6340 } 6341 6342 if (kgem_bo_can_map__cpu(&sna->kgem, dst_priv->gpu_bo, true)) { 6343 ptr = kgem_bo_map__cpu(&sna->kgem, dst_priv->gpu_bo); 6344 if (ptr == NULL) { 6345 DBG(("%s - no, map failed\n", __FUNCTION__)); 6346 return false; 6347 } 6348 6349 kgem_bo_sync__cpu(&sna->kgem, dst_priv->gpu_bo); 6350 } else { 6351 ptr = kgem_bo_map__wc(&sna->kgem, dst_priv->gpu_bo); 6352 if (ptr == NULL) { 6353 DBG(("%s - no, map failed\n", __FUNCTION__)); 6354 return false; 6355 } 6356 6357 kgem_bo_sync__gtt(&sna->kgem, dst_priv->gpu_bo); 6358 } 6359 6360 if (!DAMAGE_IS_ALL(dst_priv->gpu_damage)) { 6361 assert(!dst_priv->clear); 6362 sna_damage_add_to_pixmap(&dst_priv->gpu_damage, region, dst_pixmap); 6363 if (sna_damage_is_all(&dst_priv->gpu_damage, 6364 dst_pixmap->drawable.width, 6365 dst_pixmap->drawable.height)) { 6366 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 6367 __FUNCTION__)); 6368 sna_damage_destroy(&dst_priv->cpu_damage); 6369 list_del(&dst_priv->flush_list); 6370 } else 6371 sna_damage_subtract(&dst_priv->cpu_damage, 6372 region); 6373 } 6374 dst_priv->clear = false; 6375 6376 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 6377 6378 if (sigtrap_get()) 6379 return false; 6380 6381 box = region_rects(region); 6382 n = region_num_rects(region); 6383 if (dst_priv->gpu_bo->tiling) { 6384 DBG(("%s: copy to a tiled CPU map\n", __FUNCTION__)); 6385 assert(dst_priv->gpu_bo->tiling == I915_TILING_X); 6386 assert(src_pixmap->devKind); 6387 do { 6388 memcpy_to_tiled_x(&sna->kgem, src_pixmap->devPrivate.ptr, ptr, 6389 src_pixmap->drawable.bitsPerPixel, 6390 src_pixmap->devKind, 6391 dst_priv->gpu_bo->pitch, 6392 box->x1 + dx, box->y1 + dy, 6393 box->x1, box->y1, 6394 box->x2 - box->x1, box->y2 - box->y1); 6395 box++; 6396 } while (--n); 6397 } else { 6398 DBG(("%s: copy to a linear CPU map\n", __FUNCTION__)); 6399 assert(src_pixmap->devKind); 6400 do { 6401 memcpy_blt(src_pixmap->devPrivate.ptr, ptr, 6402 src_pixmap->drawable.bitsPerPixel, 6403 src_pixmap->devKind, 6404 dst_priv->gpu_bo->pitch, 6405 box->x1 + dx, box->y1 + dy, 6406 box->x1, box->y1, 6407 box->x2 - box->x1, box->y2 - box->y1); 6408 box++; 6409 } while (--n); 6410 6411 if (!dst_priv->shm) { 6412 dst_pixmap->devPrivate.ptr = ptr; 6413 dst_pixmap->devKind = dst_priv->gpu_bo->pitch; 6414 if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) { 6415 dst_priv->mapped = MAPPED_CPU; 6416 dst_priv->cpu = true; 6417 } else 6418 dst_priv->mapped = MAPPED_GTT; 6419 assert_pixmap_map(dst_pixmap, dst_priv); 6420 } 6421 } 6422 6423 sigtrap_put(); 6424 6425 return true; 6426} 6427 6428static void discard_cpu_damage(struct sna *sna, struct sna_pixmap *priv) 6429{ 6430 if (priv->cpu_damage == NULL && !priv->shm) 6431 return; 6432 6433 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 6434 6435 if (kgem_bo_discard_cache(priv->gpu_bo, true)) { 6436 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 6437 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 6438 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); /* magical upload buffer */ 6439 assert(!priv->pinned); 6440 assert(!priv->mapped); 6441 sna_damage_destroy(&priv->gpu_damage); 6442 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 6443 priv->gpu_bo = NULL; 6444 } 6445 6446 sna_damage_destroy(&priv->cpu_damage); 6447 list_del(&priv->flush_list); 6448 6449 if (priv->gpu_bo && sna_pixmap_free_cpu(sna, priv, priv->cpu)) 6450 sna_damage_all(&priv->gpu_damage, priv->pixmap); 6451 priv->cpu = false; 6452} 6453 6454static void 6455sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 6456 RegionPtr region, int dx, int dy, 6457 Pixel bitplane, void *closure) 6458{ 6459 PixmapPtr src_pixmap = get_drawable_pixmap(src); 6460 struct sna_pixmap *src_priv = sna_pixmap(src_pixmap); 6461 PixmapPtr dst_pixmap = get_drawable_pixmap(dst); 6462 struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap); 6463 struct sna *sna = to_sna_from_pixmap(src_pixmap); 6464 struct sna_damage **damage; 6465 struct kgem_bo *bo; 6466 int16_t src_dx, src_dy; 6467 int16_t dst_dx, dst_dy; 6468 const BoxRec *box = region_rects(region); 6469 int n = region_num_rects(region); 6470 int alu = gc->alu; 6471 int stride, bpp; 6472 char *bits; 6473 bool replaces; 6474 6475 assert(region_num_rects(region)); 6476 6477 if (src_priv && 6478 src_priv->gpu_bo == NULL && 6479 src_priv->cpu_bo == NULL && 6480 src_priv->ptr == NULL) { 6481 /* Rare but still happens, nothing to copy */ 6482 DBG(("%s: src pixmap=%ld is empty\n", 6483 __FUNCTION__, src_pixmap->drawable.serialNumber)); 6484 return; 6485 } 6486 6487 if (src_pixmap == dst_pixmap) 6488 return sna_self_copy_boxes(src, dst, gc, 6489 region, dx, dy, 6490 bitplane, closure); 6491 6492 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", 6493 __FUNCTION__, n, 6494 box[0].x1, box[0].y1, box[0].x2, box[0].y2, 6495 src_pixmap->drawable.serialNumber, dx, dy, 6496 dst_pixmap->drawable.serialNumber, get_drawable_dx(dst), get_drawable_dy(dst), 6497 alu, 6498 src_pixmap->drawable.width, src_pixmap->drawable.height, 6499 dst_pixmap->drawable.width, dst_pixmap->drawable.height)); 6500 6501 assert_pixmap_damage(dst_pixmap); 6502 assert_pixmap_damage(src_pixmap); 6503 6504 bpp = dst_pixmap->drawable.bitsPerPixel; 6505 6506 if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy)) 6507 RegionTranslate(region, dst_dx, dst_dy); 6508 get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy); 6509 src_dx += dx - dst_dx; 6510 src_dy += dy - dst_dy; 6511 6512 assert_pixmap_contains_box(dst_pixmap, RegionExtents(region)); 6513 assert_pixmap_contains_box_with_offset(src_pixmap, 6514 RegionExtents(region), 6515 src_dx, src_dy); 6516 6517 replaces = n == 1 && 6518 alu_overwrites(alu) && 6519 box->x1 <= 0 && 6520 box->y1 <= 0 && 6521 box->x2 >= dst_pixmap->drawable.width && 6522 box->y2 >= dst_pixmap->drawable.height; 6523 6524 DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n", 6525 __FUNCTION__, 6526 dst_priv, 6527 dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0, 6528 dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0, 6529 src_priv, 6530 src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0, 6531 src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0, 6532 replaces)); 6533 6534 if (dst_priv == NULL) { 6535 DBG(("%s: unattached dst failed, fallback\n", __FUNCTION__)); 6536 goto fallback; 6537 } 6538 6539 if (alu == GXcopy && 6540 src_priv && src_priv->cow && 6541 COW(src_priv->cow) == COW(dst_priv->cow)) { 6542 if ((dx | dy) == 0) { 6543 DBG(("%s: ignoring cow for no op\n", 6544 __FUNCTION__)); 6545 return; 6546 } else if (IS_COW_OWNER(dst_priv->cow)) { 6547 /* XXX hack for firefox -- subsequent uses of src will be corrupt! */ 6548 DBG(("%s: ignoring cow reference for cousin copy\n", 6549 __FUNCTION__)); 6550 assert(src_priv->cpu_damage == NULL); 6551 assert(dst_priv->move_to_gpu == NULL); 6552 bo = dst_priv->gpu_bo; 6553 damage = NULL; 6554 } else 6555 goto discard_cow; 6556 } else { 6557 unsigned hint; 6558discard_cow: 6559 hint = copy_prefer_gpu(sna, dst_priv, src_priv, region, src_dx, src_dy); 6560 if (replaces) { 6561 discard_cpu_damage(sna, dst_priv); 6562 hint |= REPLACES | IGNORE_DAMAGE; 6563 } else if (alu_overwrites(alu)) { 6564 if (region->data == NULL) 6565 hint |= IGNORE_DAMAGE; 6566 if (dst_priv->cpu_damage && 6567 region_subsumes_damage(region, 6568 dst_priv->cpu_damage)) 6569 discard_cpu_damage(sna, dst_priv); 6570 } 6571 bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint, 6572 ®ion->extents, &damage); 6573 } 6574 if (bo) { 6575 if (alu == GXset || alu == GXclear || (src_priv && src_priv->clear)) { 6576 uint32_t color; 6577 6578 if (alu == GXset) 6579 color = (1 << dst_pixmap->drawable.depth) - 1; 6580 else if (alu == GXclear) 6581 color = 0; 6582 else 6583 color = src_priv->clear_color; 6584 DBG(("%s: applying src clear [%08x] to dst\n", 6585 __FUNCTION__, src_priv->clear_color)); 6586 6587 if (n == 1) { 6588 if (replaces && UNDO) 6589 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6590 6591 if (!sna->render.fill_one(sna, 6592 dst_pixmap, bo, color, 6593 box->x1, box->y1, 6594 box->x2, box->y2, 6595 alu)) { 6596 DBG(("%s: unsupported fill\n", 6597 __FUNCTION__)); 6598 goto fallback; 6599 } 6600 6601 if (replaces && bo == dst_priv->gpu_bo) { 6602 DBG(("%s: marking dst handle=%d as all clear [%08x]\n", 6603 __FUNCTION__, 6604 dst_priv->gpu_bo->handle, 6605 src_priv->clear_color)); 6606 dst_priv->clear = true; 6607 dst_priv->clear_color = color; 6608 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6609 sna_damage_destroy(&dst_priv->cpu_damage); 6610 list_del(&dst_priv->flush_list); 6611 return; 6612 } 6613 } else { 6614 struct sna_fill_op fill; 6615 6616 if (!sna_fill_init_blt(&fill, sna, 6617 dst_pixmap, bo, 6618 alu, color, 6619 FILL_BOXES)) { 6620 DBG(("%s: unsupported fill\n", 6621 __FUNCTION__)); 6622 goto fallback; 6623 } 6624 6625 fill.boxes(sna, &fill, box, n); 6626 fill.done(sna, &fill); 6627 } 6628 6629 if (damage) 6630 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6631 return; 6632 } 6633 6634 if (src_priv && 6635 move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) && 6636 sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 6637 DBG(("%s: move whole src_pixmap to GPU and copy\n", 6638 __FUNCTION__)); 6639 if (replaces && UNDO) 6640 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6641 6642 if (replaces && 6643 src_pixmap->drawable.width == dst_pixmap->drawable.width && 6644 src_pixmap->drawable.height == dst_pixmap->drawable.height) { 6645 assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth); 6646 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 6647 if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) { 6648 assert(dst_priv->gpu_bo == src_priv->gpu_bo); 6649 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6650 sna_damage_destroy(&dst_priv->cpu_damage); 6651 list_del(&dst_priv->flush_list); 6652 add_shm_flush(sna, dst_priv); 6653 return; 6654 } 6655 } 6656 if (!sna->render.copy_boxes(sna, alu, 6657 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6658 &dst_pixmap->drawable, bo, 0, 0, 6659 box, n, small_copy(region))) { 6660 DBG(("%s: fallback - accelerated copy boxes failed\n", 6661 __FUNCTION__)); 6662 goto fallback; 6663 } 6664 6665 if (damage) 6666 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6667 return; 6668 } 6669 6670 if (src_priv && 6671 region_overlaps_damage(region, src_priv->gpu_damage, 6672 src_dx, src_dy)) { 6673 BoxRec area; 6674 6675 DBG(("%s: region overlaps GPU damage, upload and copy\n", 6676 __FUNCTION__)); 6677 6678 area = region->extents; 6679 area.x1 += src_dx; 6680 area.x2 += src_dx; 6681 area.y1 += src_dy; 6682 area.y2 += src_dy; 6683 6684 if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area, 6685 MOVE_READ | MOVE_ASYNC_HINT)) { 6686 DBG(("%s: move-to-gpu(src) failed, fallback\n", __FUNCTION__)); 6687 goto fallback; 6688 } 6689 6690 if (replaces && UNDO) 6691 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6692 6693 if (!sna->render.copy_boxes(sna, alu, 6694 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy, 6695 &dst_pixmap->drawable, bo, 0, 0, 6696 box, n, small_copy(region))) { 6697 DBG(("%s: fallback - accelerated copy boxes failed\n", 6698 __FUNCTION__)); 6699 goto fallback; 6700 } 6701 6702 if (damage) 6703 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6704 return; 6705 } 6706 6707 if (bo != dst_priv->gpu_bo) 6708 goto fallback; 6709 6710 if (use_shm_bo(sna, bo, src_priv, alu, replaces && !dst_priv->pinned)) { 6711 bool ret; 6712 6713 DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n", 6714 __FUNCTION__, src_priv->shm)); 6715 6716 assert(bo != dst_priv->cpu_bo); 6717 6718 RegionTranslate(region, src_dx, src_dy); 6719 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6720 region, 6721 MOVE_READ | MOVE_ASYNC_HINT); 6722 RegionTranslate(region, -src_dx, -src_dy); 6723 if (!ret) { 6724 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6725 goto fallback; 6726 } 6727 6728 if (replaces && UNDO) 6729 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo); 6730 6731 add_shm_flush(sna, src_priv); 6732 6733 if (!sna->render.copy_boxes(sna, alu, 6734 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy, 6735 &dst_pixmap->drawable, bo, 0, 0, 6736 box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) { 6737 DBG(("%s: fallback - accelerated copy boxes failed\n", 6738 __FUNCTION__)); 6739 goto fallback; 6740 } 6741 6742 if (damage) 6743 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6744 return; 6745 } 6746 6747 if (src_priv) { 6748 bool ret; 6749 6750 RegionTranslate(region, src_dx, src_dy); 6751 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6752 region, MOVE_READ); 6753 RegionTranslate(region, -src_dx, -src_dy); 6754 if (!ret) { 6755 DBG(("%s: move-to-cpu(src) failed, fallback\n", __FUNCTION__)); 6756 goto fallback; 6757 } 6758 6759 assert(!src_priv->mapped); 6760 if (src_pixmap->devPrivate.ptr == NULL) 6761 /* uninitialised!*/ 6762 return; 6763 } 6764 6765 if (USE_USERPTR_UPLOADS && 6766 sna->kgem.has_userptr && 6767 (alu != GXcopy || 6768 (box_inplace(src_pixmap, ®ion->extents) && 6769 __kgem_bo_is_busy(&sna->kgem, bo)))) { 6770 struct kgem_bo *src_bo; 6771 bool ok = false; 6772 6773 DBG(("%s: upload through a temporary map\n", 6774 __FUNCTION__)); 6775 6776 assert(src_pixmap->devKind); 6777 src_bo = kgem_create_map(&sna->kgem, 6778 src_pixmap->devPrivate.ptr, 6779 src_pixmap->devKind * src_pixmap->drawable.height, 6780 true); 6781 if (src_bo) { 6782 src_bo->pitch = src_pixmap->devKind; 6783 kgem_bo_mark_unreusable(src_bo); 6784 6785 ok = sna->render.copy_boxes(sna, alu, 6786 &src_pixmap->drawable, src_bo, src_dx, src_dy, 6787 &dst_pixmap->drawable, bo, 0, 0, 6788 box, n, small_copy(region) | COPY_LAST); 6789 kgem_bo_sync__cpu(&sna->kgem, src_bo); 6790 assert(src_bo->rq == NULL); 6791 kgem_bo_destroy(&sna->kgem, src_bo); 6792 } 6793 6794 if (ok) { 6795 if (damage) 6796 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6797 return; 6798 } 6799 } 6800 6801 if (alu != GXcopy) { 6802 PixmapPtr tmp; 6803 struct kgem_bo *src_bo; 6804 int i; 6805 6806 assert(src_pixmap->drawable.depth != 1); 6807 6808 DBG(("%s: creating temporary source upload for non-copy alu [%d]\n", 6809 __FUNCTION__, alu)); 6810 6811 tmp = sna_pixmap_create_upload(src->pScreen, 6812 region->extents.x2 - region->extents.x1, 6813 region->extents.y2 - region->extents.y1, 6814 src->depth, 6815 KGEM_BUFFER_WRITE_INPLACE); 6816 if (tmp == NullPixmap) 6817 return; 6818 6819 src_bo = __sna_pixmap_get_bo(tmp); 6820 assert(src_bo != NULL); 6821 6822 dx = -region->extents.x1; 6823 dy = -region->extents.y1; 6824 for (i = 0; i < n; i++) { 6825 assert(box[i].x1 + src_dx >= 0); 6826 assert(box[i].y1 + src_dy >= 0); 6827 assert(box[i].x2 + src_dx <= src_pixmap->drawable.width); 6828 assert(box[i].y2 + src_dy <= src_pixmap->drawable.height); 6829 6830 assert(box[i].x1 + dx >= 0); 6831 assert(box[i].y1 + dy >= 0); 6832 assert(box[i].x2 + dx <= tmp->drawable.width); 6833 assert(box[i].y2 + dy <= tmp->drawable.height); 6834 6835 assert(has_coherent_ptr(sna, sna_pixmap(src_pixmap), MOVE_READ)); 6836 assert(has_coherent_ptr(sna, sna_pixmap(tmp), MOVE_WRITE)); 6837 assert(src_pixmap->devKind); 6838 assert(tmp->devKind); 6839 memcpy_blt(src_pixmap->devPrivate.ptr, 6840 tmp->devPrivate.ptr, 6841 src_pixmap->drawable.bitsPerPixel, 6842 src_pixmap->devKind, 6843 tmp->devKind, 6844 box[i].x1 + src_dx, 6845 box[i].y1 + src_dy, 6846 box[i].x1 + dx, 6847 box[i].y1 + dy, 6848 box[i].x2 - box[i].x1, 6849 box[i].y2 - box[i].y1); 6850 } 6851 6852 if (n == 1 && 6853 tmp->drawable.width == src_pixmap->drawable.width && 6854 tmp->drawable.height == src_pixmap->drawable.height) { 6855 DBG(("%s: caching upload for src bo\n", 6856 __FUNCTION__)); 6857 assert(src_priv->gpu_damage == NULL); 6858 assert(src_priv->gpu_bo == NULL); 6859 kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo); 6860 } 6861 6862 if (!sna->render.copy_boxes(sna, alu, 6863 &tmp->drawable, src_bo, dx, dy, 6864 &dst_pixmap->drawable, bo, 0, 0, 6865 box, n, 0)) { 6866 DBG(("%s: fallback - accelerated copy boxes failed\n", 6867 __FUNCTION__)); 6868 tmp->drawable.pScreen->DestroyPixmap(tmp); 6869 goto fallback; 6870 } 6871 tmp->drawable.pScreen->DestroyPixmap(tmp); 6872 6873 if (damage) 6874 sna_damage_add_to_pixmap(damage, region, dst_pixmap); 6875 return; 6876 } else { 6877 DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n", 6878 __FUNCTION__)); 6879 6880 assert(src_pixmap->devKind); 6881 if (!dst_priv->pinned && replaces) { 6882 stride = src_pixmap->devKind; 6883 bits = src_pixmap->devPrivate.ptr; 6884 bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8; 6885 6886 if (!sna_replace(sna, dst_pixmap, bits, stride)) { 6887 DBG(("%s: replace failed, fallback\n", __FUNCTION__)); 6888 goto fallback; 6889 } 6890 } else { 6891 assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage)); 6892 if (!sna_write_boxes(sna, dst_pixmap, 6893 dst_priv->gpu_bo, 0, 0, 6894 src_pixmap->devPrivate.ptr, 6895 src_pixmap->devKind, 6896 src_dx, src_dy, 6897 box, n)) { 6898 DBG(("%s: write failed, fallback\n", __FUNCTION__)); 6899 goto fallback; 6900 } 6901 } 6902 6903 assert(dst_priv->clear == false); 6904 dst_priv->cpu = false; 6905 if (damage) { 6906 assert(!dst_priv->clear); 6907 assert(dst_priv->gpu_bo); 6908 assert(dst_priv->gpu_bo->proxy == NULL); 6909 assert(*damage == dst_priv->gpu_damage); 6910 if (replaces) { 6911 sna_damage_destroy(&dst_priv->cpu_damage); 6912 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap); 6913 list_del(&dst_priv->flush_list); 6914 } else 6915 sna_damage_add(&dst_priv->gpu_damage, 6916 region); 6917 assert_pixmap_damage(dst_pixmap); 6918 } 6919 } 6920 6921 return; 6922 } 6923 6924fallback: 6925 if (alu == GXcopy && src_priv && src_priv->clear) { 6926 DBG(("%s: copying clear [%08x]\n", 6927 __FUNCTION__, src_priv->clear_color)); 6928 6929 if (dst_priv) { 6930 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6931 region, 6932 MOVE_WRITE | MOVE_INPLACE_HINT)) 6933 return; 6934 } 6935 6936 if (sigtrap_get() == 0) { 6937 assert(dst_pixmap->devPrivate.ptr); 6938 assert(dst_pixmap->devKind); 6939 sigtrap_assert_active(); 6940 do { 6941 pixman_fill(dst_pixmap->devPrivate.ptr, 6942 dst_pixmap->devKind/sizeof(uint32_t), 6943 dst_pixmap->drawable.bitsPerPixel, 6944 box->x1, box->y1, 6945 box->x2 - box->x1, 6946 box->y2 - box->y1, 6947 src_priv->clear_color); 6948 box++; 6949 } while (--n); 6950 sigtrap_put(); 6951 } 6952 } else if (!sna_copy_boxes__inplace(sna, region, alu, 6953 src_pixmap, src_priv, 6954 src_dx, src_dy, 6955 dst_pixmap, dst_priv, 6956 replaces)) { 6957 FbBits *dst_bits, *src_bits; 6958 int dst_stride, src_stride; 6959 6960 DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", 6961 __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); 6962 if (src_priv) { 6963 unsigned mode; 6964 6965 RegionTranslate(region, src_dx, src_dy); 6966 6967 assert_pixmap_contains_box(src_pixmap, 6968 RegionExtents(region)); 6969 6970 mode = MOVE_READ; 6971 if (!sna->kgem.can_blt_cpu || 6972 (src_priv->cpu_bo == NULL && 6973 (src_priv->create & KGEM_CAN_CREATE_CPU) == 0)) 6974 mode |= MOVE_INPLACE_HINT; 6975 6976 if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 6977 region, mode)) 6978 return; 6979 6980 RegionTranslate(region, -src_dx, -src_dy); 6981 } 6982 assert(src_priv == sna_pixmap(src_pixmap)); 6983 6984 if (dst_priv) { 6985 unsigned mode; 6986 6987 if (alu_overwrites(alu)) 6988 mode = MOVE_WRITE | MOVE_INPLACE_HINT; 6989 else 6990 mode = MOVE_WRITE | MOVE_READ; 6991 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 6992 region, mode)) 6993 return; 6994 } 6995 assert(dst_priv == sna_pixmap(dst_pixmap)); 6996 6997 assert(dst_pixmap->devKind); 6998 assert(src_pixmap->devKind); 6999 dst_stride = dst_pixmap->devKind; 7000 src_stride = src_pixmap->devKind; 7001 7002 if (alu == GXcopy && bpp >= 8) { 7003 dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr; 7004 src_bits = (FbBits *) 7005 ((char *)src_pixmap->devPrivate.ptr + 7006 src_dy * src_stride + src_dx * bpp / 8); 7007 7008 if (sigtrap_get() == 0) { 7009 do { 7010 DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", 7011 __FUNCTION__, 7012 box->x1, box->y1, 7013 box->x2 - box->x1, 7014 box->y2 - box->y1, 7015 src_dx, src_dy, 7016 src_stride, dst_stride)); 7017 7018 assert(box->x1 >= 0); 7019 assert(box->y1 >= 0); 7020 assert(box->x2 <= dst_pixmap->drawable.width); 7021 assert(box->y2 <= dst_pixmap->drawable.height); 7022 7023 assert(box->x1 + src_dx >= 0); 7024 assert(box->y1 + src_dy >= 0); 7025 assert(box->x2 + src_dx <= src_pixmap->drawable.width); 7026 assert(box->y2 + src_dy <= src_pixmap->drawable.height); 7027 assert(has_coherent_ptr(sna, src_priv, MOVE_READ)); 7028 assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE)); 7029 assert(src_stride); 7030 assert(dst_stride); 7031 memcpy_blt(src_bits, dst_bits, bpp, 7032 src_stride, dst_stride, 7033 box->x1, box->y1, 7034 box->x1, box->y1, 7035 box->x2 - box->x1, 7036 box->y2 - box->y1); 7037 box++; 7038 } while (--n); 7039 sigtrap_put(); 7040 } 7041 } else { 7042 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); 7043 7044 RegionTranslate(region, -dst_dx, -dst_dy); 7045 7046 if (sna_gc_move_to_cpu(gc, dst, region) && 7047 sigtrap_get() == 0) { 7048 miCopyRegion(src, dst, gc, 7049 region, dx, dy, 7050 fbCopyNtoN, 0, NULL); 7051 sigtrap_put(); 7052 } 7053 7054 sna_gc_move_to_gpu(gc); 7055 } 7056 } 7057} 7058 7059typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7060 RegionPtr region, int dx, int dy, 7061 Pixel bitPlane, void *closure); 7062 7063static inline bool box_equal(const BoxRec *a, const BoxRec *b) 7064{ 7065 return *(const uint64_t *)a == *(const uint64_t *)b; 7066} 7067 7068static inline bool has_clip(GCPtr gc) 7069{ 7070#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0) 7071 return gc->clientClipType != CT_NONE; 7072#else 7073 return gc->clientClip != NULL; 7074#endif 7075} 7076 7077static RegionPtr 7078sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7079 int sx, int sy, 7080 int width, int height, 7081 int dx, int dy, 7082 sna_copy_func copy, Pixel bitPlane, void *closure) 7083{ 7084 RegionPtr clip; 7085 RegionRec region; 7086 BoxRec src_extents; 7087 bool expose; 7088 7089 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 7090 __FUNCTION__, sx, sy, dx, dy, width, height)); 7091 7092 /* Short cut for unmapped windows */ 7093 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) { 7094 DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n", 7095 __FUNCTION__, get_window_pixmap((WindowPtr)dst))); 7096 return NULL; 7097 } 7098 7099 SourceValidate(src, sx, sy, width, height, gc->subWindowMode); 7100 7101 sx += src->x; 7102 sy += src->y; 7103 7104 dx += dst->x; 7105 dy += dst->y; 7106 7107 DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 7108 __FUNCTION__, sx, sy, dx, dy, width, height)); 7109 7110 region.extents.x1 = dx; 7111 region.extents.y1 = dy; 7112 region.extents.x2 = bound(dx, width); 7113 region.extents.y2 = bound(dy, height); 7114 region.data = NULL; 7115 7116 DBG(("%s: dst extents (%d, %d), (%d, %d), dst clip extents (%d, %d), (%d, %d), dst size=%dx%d\n", __FUNCTION__, 7117 region.extents.x1, region.extents.y1, 7118 region.extents.x2, region.extents.y2, 7119 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 7120 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2, 7121 dst->width, dst->height)); 7122 7123 if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) { 7124 DBG(("%s: dst clipped out\n", __FUNCTION__)); 7125 return NULL; 7126 } 7127 7128 DBG(("%s: clipped dst extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7129 region.extents.x1, region.extents.y1, 7130 region.extents.x2, region.extents.y2)); 7131 assert_drawable_contains_box(dst, ®ion.extents); 7132 7133 region.extents.x1 = clamp(region.extents.x1, sx - dx); 7134 region.extents.x2 = clamp(region.extents.x2, sx - dx); 7135 region.extents.y1 = clamp(region.extents.y1, sy - dy); 7136 region.extents.y2 = clamp(region.extents.y2, sy - dy); 7137 7138 src_extents = region.extents; 7139 expose = true; 7140 7141 DBG(("%s: unclipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7142 region.extents.x1, region.extents.y1, 7143 region.extents.x2, region.extents.y2)); 7144 7145 if (region.extents.x1 < src->x) 7146 region.extents.x1 = src->x; 7147 if (region.extents.y1 < src->y) 7148 region.extents.y1 = src->y; 7149 if (region.extents.x2 > src->x + (int) src->width) 7150 region.extents.x2 = src->x + (int) src->width; 7151 if (region.extents.y2 > src->y + (int) src->height) 7152 region.extents.y2 = src->y + (int) src->height; 7153 7154 DBG(("%s: clipped src extents (%d, %d), (%d, %d)\n", __FUNCTION__, 7155 region.extents.x1, region.extents.y1, 7156 region.extents.x2, region.extents.y2)); 7157 if (box_empty(®ion.extents)) { 7158 DBG(("%s: src clipped out\n", __FUNCTION__)); 7159 return NULL; 7160 } 7161 7162 /* Compute source clip region */ 7163 if (src->type == DRAWABLE_PIXMAP) { 7164 if (src == dst && !has_clip(gc)) { 7165 DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__)); 7166 clip = gc->pCompositeClip; 7167 } else { 7168 DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__)); 7169 expose = false; 7170 clip = NULL; 7171 } 7172 } else { 7173 WindowPtr w = (WindowPtr)src; 7174 if (gc->subWindowMode == IncludeInferiors) { 7175 DBG(("%s: window -- include inferiors\n", __FUNCTION__)); 7176 7177 if (w->winSize.data) 7178 RegionIntersect(®ion, ®ion, &w->winSize); 7179 else 7180 box_intersect(®ion.extents, &w->winSize.extents); 7181 clip = &w->borderClip; 7182 } else { 7183 DBG(("%s: window -- clip by children\n", __FUNCTION__)); 7184 clip = &w->clipList; 7185 } 7186 } 7187 if (clip != NULL) { 7188 if (clip->data == NULL) { 7189 box_intersect(®ion.extents, &clip->extents); 7190 if (box_equal(&src_extents, ®ion.extents)) 7191 expose = false; 7192 } else 7193 RegionIntersect(®ion, ®ion, clip); 7194 } 7195 DBG(("%s: src extents (%d, %d), (%d, %d) x %d\n", __FUNCTION__, 7196 region.extents.x1, region.extents.y1, 7197 region.extents.x2, region.extents.y2, 7198 region_num_rects(®ion))); 7199 7200 RegionTranslate(®ion, dx-sx, dy-sy); 7201 if (gc->pCompositeClip->data) 7202 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 7203 DBG(("%s: copy region (%d, %d), (%d, %d) x %d + (%d, %d)\n", 7204 __FUNCTION__, 7205 region.extents.x1, region.extents.y1, 7206 region.extents.x2, region.extents.y2, 7207 region_num_rects(®ion), 7208 sx-dx, sy-dy)); 7209 7210 if (!box_empty(®ion.extents)) 7211 copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure); 7212 assert(gc->pCompositeClip != ®ion); 7213 RegionUninit(®ion); 7214 7215 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 7216 clip = NULL; 7217 if (expose && gc->fExpose) 7218 clip = miHandleExposures(src, dst, gc, 7219 sx - src->x, sy - src->y, 7220 width, height, 7221 dx - dst->x, dy - dst->y, 7222 (unsigned long) bitPlane); 7223 return clip; 7224} 7225 7226static void 7227sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7228 RegionPtr region, int dx, int dy, 7229 Pixel bitplane, void *closure) 7230{ 7231 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n", 7232 __FUNCTION__, region_num_rects(region), 7233 region->extents.x1, region->extents.y1, 7234 region->extents.x2, region->extents.y2, 7235 dx, dy, gc->alu)); 7236 7237 if (!sna_gc_move_to_cpu(gc, dst, region)) 7238 goto out; 7239 7240 RegionTranslate(region, dx, dy); 7241 if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ)) 7242 goto out; 7243 RegionTranslate(region, -dx, -dy); 7244 7245 if (src == dst || 7246 get_drawable_pixmap(src) == get_drawable_pixmap(dst)) { 7247 DBG(("%s: self-copy\n", __FUNCTION__)); 7248 if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ)) 7249 goto out; 7250 } else { 7251 if (!sna_drawable_move_region_to_cpu(dst, region, 7252 drawable_gc_flags(dst, gc, false))) 7253 goto out; 7254 } 7255 7256 if (sigtrap_get() == 0) { 7257 miCopyRegion(src, dst, gc, 7258 region, dx, dy, 7259 fbCopyNtoN, 0, NULL); 7260 FALLBACK_FLUSH(dst); 7261 sigtrap_put(); 7262 } 7263out: 7264 sna_gc_move_to_gpu(gc); 7265} 7266 7267static RegionPtr 7268sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7269 int src_x, int src_y, 7270 int width, int height, 7271 int dst_x, int dst_y) 7272{ 7273 struct sna *sna = to_sna_from_drawable(dst); 7274 sna_copy_func copy; 7275 7276 if (gc->planemask == 0) 7277 return NULL; 7278 7279 if (sna->ignore_copy_area) 7280 return NULL; 7281 7282 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", 7283 __FUNCTION__, 7284 get_drawable_pixmap(src)->drawable.serialNumber, 7285 src_x, src_y, width, height, src->x, src->y, 7286 get_drawable_pixmap(dst)->drawable.serialNumber, 7287 dst_x, dst_y, dst->x, dst->y, 7288 gc->alu, gc->planemask, gc->depth)); 7289 7290 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) || 7291 !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) { 7292 DBG(("%s: fallback copy\n", __FUNCTION__)); 7293 copy = sna_fallback_copy_boxes; 7294 } else if (src == dst) { 7295 DBG(("%s: self copy\n", __FUNCTION__)); 7296 copy = sna_self_copy_boxes; 7297 } else { 7298 DBG(("%s: normal copy\n", __FUNCTION__)); 7299 copy = sna_copy_boxes; 7300 } 7301 7302 return sna_do_copy(src, dst, gc, 7303 src_x, src_y, 7304 width, height, 7305 dst_x, dst_y, 7306 copy, 0, NULL); 7307} 7308 7309const BoxRec * 7310__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) 7311{ 7312 assert(end - begin > 1); 7313 do { 7314 const BoxRec *mid = begin + (end - begin) / 2; 7315 if (mid->y2 > y) 7316 end = mid; 7317 else 7318 begin = mid; 7319 } while (end > begin + 1); 7320 if (begin->y2 > y) 7321 return begin; 7322 else 7323 return end; 7324} 7325 7326struct sna_fill_spans { 7327 struct sna *sna; 7328 PixmapPtr pixmap; 7329 RegionRec region; 7330 unsigned flags; 7331 uint32_t phase; 7332 struct kgem_bo *bo; 7333 struct sna_damage **damage; 7334 int16_t dx, dy; 7335 void *op; 7336}; 7337 7338static void 7339sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc, 7340 int mode, int n, DDXPointPtr pt) 7341{ 7342 fbPolyPoint(drawable, gc, mode, n, pt, -1); 7343} 7344 7345static void 7346sna_poly_point__fill(DrawablePtr drawable, GCPtr gc, 7347 int mode, int n, DDXPointPtr pt) 7348{ 7349 struct sna_fill_spans *data = sna_gc(gc)->priv; 7350 struct sna_fill_op *op = data->op; 7351 BoxRec box[512]; 7352 DDXPointRec last; 7353 7354 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7355 if (n == 0) 7356 return; 7357 7358 last.x = drawable->x + data->dx; 7359 last.y = drawable->y + data->dy; 7360 if (op->points && mode != CoordModePrevious) { 7361 op->points(data->sna, op, last.x, last.y, pt, n); 7362 } else do { 7363 BoxRec *b = box; 7364 unsigned nbox = n; 7365 if (nbox > ARRAY_SIZE(box)) 7366 nbox = ARRAY_SIZE(box); 7367 n -= nbox; 7368 do { 7369 *(DDXPointRec *)b = *pt++; 7370 7371 b->x1 += last.x; 7372 b->y1 += last.y; 7373 if (mode == CoordModePrevious) 7374 last = *(DDXPointRec *)b; 7375 7376 b->x2 = b->x1 + 1; 7377 b->y2 = b->y1 + 1; 7378 b++; 7379 } while (--nbox); 7380 op->boxes(data->sna, op, box, b - box); 7381 } while (n); 7382} 7383 7384static void 7385sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc, 7386 int mode, int n, DDXPointPtr pt) 7387{ 7388 struct sna_fill_spans *data = sna_gc(gc)->priv; 7389 struct sna_fill_op fill; 7390 BoxRec box[512]; 7391 DDXPointRec last; 7392 7393 if (!sna_fill_init_blt(&fill, 7394 data->sna, data->pixmap, 7395 data->bo, gc->alu, gc->fgPixel, 7396 FILL_POINTS)) 7397 return; 7398 7399 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7400 7401 last.x = drawable->x; 7402 last.y = drawable->y; 7403 while (n) { 7404 BoxRec *b = box; 7405 unsigned nbox = n; 7406 if (nbox > ARRAY_SIZE(box)) 7407 nbox = ARRAY_SIZE(box); 7408 n -= nbox; 7409 do { 7410 *(DDXPointRec *)b = *pt++; 7411 7412 b->x1 += last.x; 7413 b->y1 += last.y; 7414 if (mode == CoordModePrevious) 7415 last = *(DDXPointRec *)b; 7416 7417 if (RegionContainsPoint(&data->region, 7418 b->x1, b->y1, NULL)) { 7419 b->x1 += data->dx; 7420 b->y1 += data->dy; 7421 b->x2 = b->x1 + 1; 7422 b->y2 = b->y1 + 1; 7423 b++; 7424 } 7425 } while (--nbox); 7426 if (b != box) 7427 fill.boxes(data->sna, &fill, box, b - box); 7428 } 7429 fill.done(data->sna, &fill); 7430} 7431 7432static void 7433sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc, 7434 int mode, int n, DDXPointPtr pt) 7435{ 7436 struct sna_fill_spans *data = sna_gc(gc)->priv; 7437 struct sna_fill_op *op = data->op; 7438 const BoxRec *extents = &data->region.extents; 7439 BoxRec box[512], *b = box; 7440 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7441 DDXPointRec last; 7442 7443 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7444 7445 last.x = drawable->x + data->dx; 7446 last.y = drawable->y + data->dy; 7447 while (n--) { 7448 *(DDXPointRec *)b = *pt++; 7449 7450 b->x1 += last.x; 7451 b->y1 += last.y; 7452 if (mode == CoordModePrevious) 7453 last = *(DDXPointRec *)b; 7454 7455 if (b->x1 >= extents->x1 && b->x1 < extents->x2 && 7456 b->y1 >= extents->y1 && b->y1 < extents->y2) { 7457 b->x2 = b->x1 + 1; 7458 b->y2 = b->y1 + 1; 7459 if (++b == last_box) { 7460 op->boxes(data->sna, op, box, last_box - box); 7461 b = box; 7462 } 7463 } 7464 } 7465 if (b != box) 7466 op->boxes(data->sna, op, box, b - box); 7467} 7468 7469static void 7470sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc, 7471 int mode, int n, DDXPointPtr pt) 7472{ 7473 struct sna_fill_spans *data = sna_gc(gc)->priv; 7474 struct sna_fill_op *op = data->op; 7475 RegionRec *clip = &data->region; 7476 BoxRec box[512], *b = box; 7477 const BoxRec *const last_box = b + ARRAY_SIZE(box); 7478 DDXPointRec last; 7479 7480 DBG(("%s: count=%d\n", __FUNCTION__, n)); 7481 7482 last.x = drawable->x + data->dx; 7483 last.y = drawable->y + data->dy; 7484 while (n--) { 7485 *(DDXPointRec *)b = *pt++; 7486 7487 b->x1 += last.x; 7488 b->y1 += last.y; 7489 if (mode == CoordModePrevious) 7490 last = *(DDXPointRec *)b; 7491 7492 if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) { 7493 b->x2 = b->x1 + 1; 7494 b->y2 = b->y1 + 1; 7495 if (++b == last_box) { 7496 op->boxes(data->sna, op, box, last_box - box); 7497 b = box; 7498 } 7499 } 7500 } 7501 if (b != box) 7502 op->boxes(data->sna, op, box, b - box); 7503} 7504 7505static void 7506sna_poly_point__dash(DrawablePtr drawable, GCPtr gc, 7507 int mode, int n, DDXPointPtr pt) 7508{ 7509 struct sna_fill_spans *data = sna_gc(gc)->priv; 7510 if (data->phase == gc->fgPixel) 7511 sna_poly_point__fill(drawable, gc, mode, n, pt); 7512} 7513 7514static void 7515sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc, 7516 int mode, int n, DDXPointPtr pt) 7517{ 7518 struct sna_fill_spans *data = sna_gc(gc)->priv; 7519 if (data->phase == gc->fgPixel) 7520 sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt); 7521} 7522 7523static void 7524sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc, 7525 int mode, int n, DDXPointPtr pt) 7526{ 7527 struct sna_fill_spans *data = sna_gc(gc)->priv; 7528 if (data->phase == gc->fgPixel) 7529 sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt); 7530} 7531 7532static void 7533sna_fill_spans__fill(DrawablePtr drawable, 7534 GCPtr gc, int n, 7535 DDXPointPtr pt, int *width, int sorted) 7536{ 7537 struct sna_fill_spans *data = sna_gc(gc)->priv; 7538 struct sna_fill_op *op = data->op; 7539 BoxRec box[512]; 7540 7541 DBG(("%s: alu=%d, fg=%08lx, count=%d\n", 7542 __FUNCTION__, gc->alu, gc->fgPixel, n)); 7543 7544 while (n) { 7545 BoxRec *b = box; 7546 int nbox = n; 7547 if (nbox > ARRAY_SIZE(box)) 7548 nbox = ARRAY_SIZE(box); 7549 n -= nbox; 7550 do { 7551 *(DDXPointRec *)b = *pt++; 7552 b->x2 = b->x1 + (int)*width++; 7553 b->y2 = b->y1 + 1; 7554 DBG(("%s: (%d, %d), (%d, %d)\n", 7555 __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); 7556 assert(b->x1 >= drawable->x); 7557 assert(b->x2 <= drawable->x + drawable->width); 7558 assert(b->y1 >= drawable->y); 7559 assert(b->y2 <= drawable->y + drawable->height); 7560 if (b->x2 > b->x1) { 7561 if (b != box && 7562 b->y1 == b[-1].y2 && 7563 b->x1 == b[-1].x1 && 7564 b->x2 == b[-1].x2) 7565 b[-1].y2 = b->y2; 7566 else 7567 b++; 7568 } 7569 } while (--nbox); 7570 if (b != box) 7571 op->boxes(data->sna, op, box, b - box); 7572 } 7573} 7574 7575static void 7576sna_fill_spans__dash(DrawablePtr drawable, 7577 GCPtr gc, int n, 7578 DDXPointPtr pt, int *width, int sorted) 7579{ 7580 struct sna_fill_spans *data = sna_gc(gc)->priv; 7581 if (data->phase == gc->fgPixel) 7582 sna_fill_spans__fill(drawable, gc, n, pt, width, sorted); 7583} 7584 7585static void 7586sna_fill_spans__fill_offset(DrawablePtr drawable, 7587 GCPtr gc, int n, 7588 DDXPointPtr pt, int *width, int sorted) 7589{ 7590 struct sna_fill_spans *data = sna_gc(gc)->priv; 7591 struct sna_fill_op *op = data->op; 7592 BoxRec box[512]; 7593 7594 DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); 7595 7596 while (n) { 7597 BoxRec *b = box; 7598 int nbox = n; 7599 if (nbox > ARRAY_SIZE(box)) 7600 nbox = ARRAY_SIZE(box); 7601 n -= nbox; 7602 do { 7603 *(DDXPointRec *)b = *pt++; 7604 b->x1 += data->dx; 7605 b->y1 += data->dy; 7606 b->x2 = b->x1 + (int)*width++; 7607 b->y2 = b->y1 + 1; 7608 if (b->x2 > b->x1) 7609 b++; 7610 } while (--nbox); 7611 if (b != box) 7612 op->boxes(data->sna, op, box, b - box); 7613 } 7614} 7615 7616static void 7617sna_fill_spans__dash_offset(DrawablePtr drawable, 7618 GCPtr gc, int n, 7619 DDXPointPtr pt, int *width, int sorted) 7620{ 7621 struct sna_fill_spans *data = sna_gc(gc)->priv; 7622 if (data->phase == gc->fgPixel) 7623 sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted); 7624} 7625 7626static void 7627sna_fill_spans__fill_clip_extents(DrawablePtr drawable, 7628 GCPtr gc, int n, 7629 DDXPointPtr pt, int *width, int sorted) 7630{ 7631 struct sna_fill_spans *data = sna_gc(gc)->priv; 7632 struct sna_fill_op *op = data->op; 7633 const BoxRec *extents = &data->region.extents; 7634 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7635 7636 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7637 __FUNCTION__, gc->alu, gc->fgPixel, n, 7638 extents->x1, extents->y1, 7639 extents->x2, extents->y2)); 7640 7641 while (n--) { 7642 DBG(("%s: [%d] pt=(%d, %d), width=%d\n", 7643 __FUNCTION__, n, pt->x, pt->y, *width)); 7644 *(DDXPointRec *)b = *pt++; 7645 b->x2 = b->x1 + (int)*width++; 7646 b->y2 = b->y1 + 1; 7647 if (box_intersect(b, extents)) { 7648 DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n", 7649 __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2)); 7650 if (data->dx|data->dy) { 7651 b->x1 += data->dx; b->x2 += data->dx; 7652 b->y1 += data->dy; b->y2 += data->dy; 7653 } 7654 if (b != box && 7655 b->y1 == b[-1].y2 && 7656 b->x1 == b[-1].x1 && 7657 b->x2 == b[-1].x2) { 7658 b[-1].y2 = b->y2; 7659 } else if (++b == last_box) { 7660 op->boxes(data->sna, op, box, last_box - box); 7661 b = box; 7662 } 7663 } 7664 } 7665 if (b != box) 7666 op->boxes(data->sna, op, box, b - box); 7667} 7668 7669static void 7670sna_fill_spans__dash_clip_extents(DrawablePtr drawable, 7671 GCPtr gc, int n, 7672 DDXPointPtr pt, int *width, int sorted) 7673{ 7674 struct sna_fill_spans *data = sna_gc(gc)->priv; 7675 if (data->phase == gc->fgPixel) 7676 sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted); 7677} 7678 7679static void 7680sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, 7681 GCPtr gc, int n, 7682 DDXPointPtr pt, int *width, int sorted) 7683{ 7684 struct sna_fill_spans *data = sna_gc(gc)->priv; 7685 struct sna_fill_op *op = data->op; 7686 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7687 const BoxRec * const clip_start = RegionBoxptr(&data->region); 7688 const BoxRec * const clip_end = clip_start + data->region.data->numRects; 7689 7690 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 7691 __FUNCTION__, gc->alu, gc->fgPixel, n, 7692 data->region.extents.x1, data->region.extents.y1, 7693 data->region.extents.x2, data->region.extents.y2)); 7694 7695 while (n--) { 7696 int16_t X1 = pt->x; 7697 int16_t y = pt->y; 7698 int16_t X2 = X1 + (int)*width; 7699 const BoxRec *c; 7700 7701 pt++; 7702 width++; 7703 7704 if (y < data->region.extents.y1 || data->region.extents.y2 <= y) 7705 continue; 7706 7707 if (X1 < data->region.extents.x1) 7708 X1 = data->region.extents.x1; 7709 7710 if (X2 > data->region.extents.x2) 7711 X2 = data->region.extents.x2; 7712 7713 if (X1 >= X2) 7714 continue; 7715 7716 c = find_clip_box_for_y(clip_start, clip_end, y); 7717 while (c != clip_end) { 7718 if (y + 1 <= c->y1 || X2 <= c->x1) 7719 break; 7720 7721 if (X1 >= c->x2) { 7722 c++; 7723 continue; 7724 } 7725 7726 b->x1 = c->x1; 7727 b->x2 = c->x2; 7728 c++; 7729 7730 if (b->x1 < X1) 7731 b->x1 = X1; 7732 if (b->x2 > X2) 7733 b->x2 = X2; 7734 if (b->x2 <= b->x1) 7735 continue; 7736 7737 b->x1 += data->dx; 7738 b->x2 += data->dx; 7739 b->y1 = y + data->dy; 7740 b->y2 = b->y1 + 1; 7741 if (++b == last_box) { 7742 op->boxes(data->sna, op, box, last_box - box); 7743 b = box; 7744 } 7745 } 7746 } 7747 if (b != box) 7748 op->boxes(data->sna, op, box, b - box); 7749} 7750 7751static void 7752sna_fill_spans__dash_clip_boxes(DrawablePtr drawable, 7753 GCPtr gc, int n, 7754 DDXPointPtr pt, int *width, int sorted) 7755{ 7756 struct sna_fill_spans *data = sna_gc(gc)->priv; 7757 if (data->phase == gc->fgPixel) 7758 sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted); 7759} 7760 7761static bool 7762sna_fill_spans_blt(DrawablePtr drawable, 7763 struct kgem_bo *bo, struct sna_damage **damage, 7764 GCPtr gc, uint32_t pixel, 7765 int n, DDXPointPtr pt, int *width, int sorted, 7766 const BoxRec *extents, unsigned clipped) 7767{ 7768 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7769 struct sna *sna = to_sna_from_pixmap(pixmap); 7770 int16_t dx, dy; 7771 struct sna_fill_op fill; 7772 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 7773 static void * const jump[] = { 7774 &&no_damage, 7775 &&damage, 7776 &&no_damage_clipped, 7777 &&damage_clipped, 7778 }; 7779 unsigned v; 7780 7781 DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n", 7782 __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped)); 7783 7784 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 7785 return false; 7786 7787 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7788 7789 v = (damage != NULL) | clipped; 7790 goto *jump[v]; 7791 7792no_damage: 7793 if (dx|dy) { 7794 do { 7795 int nbox = n; 7796 if (nbox > last_box - box) 7797 nbox = last_box - box; 7798 n -= nbox; 7799 do { 7800 *(DDXPointRec *)b = *pt++; 7801 b->x1 += dx; 7802 b->y1 += dy; 7803 b->x2 = b->x1 + (int)*width++; 7804 b->y2 = b->y1 + 1; 7805 b++; 7806 } while (--nbox); 7807 fill.boxes(sna, &fill, box, b - box); 7808 b = box; 7809 } while (n); 7810 } else { 7811 do { 7812 int nbox = n; 7813 if (nbox > last_box - box) 7814 nbox = last_box - box; 7815 n -= nbox; 7816 do { 7817 *(DDXPointRec *)b = *pt++; 7818 b->x2 = b->x1 + (int)*width++; 7819 b->y2 = b->y1 + 1; 7820 b++; 7821 } while (--nbox); 7822 fill.boxes(sna, &fill, box, b - box); 7823 b = box; 7824 } while (n); 7825 } 7826 goto done; 7827 7828damage: 7829 do { 7830 *(DDXPointRec *)b = *pt++; 7831 b->x1 += dx; 7832 b->y1 += dy; 7833 b->x2 = b->x1 + (int)*width++; 7834 b->y2 = b->y1 + 1; 7835 7836 if (++b == last_box) { 7837 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7838 fill.boxes(sna, &fill, box, last_box - box); 7839 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 7840 b = box; 7841 } 7842 } while (--n); 7843 if (b != box) { 7844 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7845 fill.boxes(sna, &fill, box, b - box); 7846 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7847 } 7848 goto done; 7849 7850no_damage_clipped: 7851 { 7852 RegionRec clip; 7853 7854 region_set(&clip, extents); 7855 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7856 return true; 7857 7858 assert(dx + clip.extents.x1 >= 0); 7859 assert(dy + clip.extents.y1 >= 0); 7860 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7861 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7862 7863 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7864 __FUNCTION__, 7865 region_num_rects(&clip), 7866 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7867 n, pt->x, pt->y)); 7868 7869 if (clip.data == NULL) { 7870 do { 7871 *(DDXPointRec *)b = *pt++; 7872 b->x2 = b->x1 + (int)*width++; 7873 b->y2 = b->y1 + 1; 7874 7875 if (box_intersect(b, &clip.extents)) { 7876 if (dx|dy) { 7877 b->x1 += dx; b->x2 += dx; 7878 b->y1 += dy; b->y2 += dy; 7879 } 7880 if (++b == last_box) { 7881 fill.boxes(sna, &fill, box, last_box - box); 7882 b = box; 7883 } 7884 } 7885 } while (--n); 7886 } else { 7887 const BoxRec * const clip_start = RegionBoxptr(&clip); 7888 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7889 do { 7890 int16_t X1 = pt->x; 7891 int16_t y = pt->y; 7892 int16_t X2 = X1 + (int)*width; 7893 const BoxRec *c; 7894 7895 pt++; 7896 width++; 7897 7898 if (y < extents->y1 || extents->y2 <= y) 7899 continue; 7900 7901 if (X1 < extents->x1) 7902 X1 = extents->x1; 7903 7904 if (X2 > extents->x2) 7905 X2 = extents->x2; 7906 7907 if (X1 >= X2) 7908 continue; 7909 7910 c = find_clip_box_for_y(clip_start, 7911 clip_end, 7912 y); 7913 while (c != clip_end) { 7914 if (y + 1 <= c->y1 || X2 <= c->x1) 7915 break; 7916 7917 if (X1 >= c->x2) { 7918 c++; 7919 continue; 7920 } 7921 7922 b->x1 = c->x1; 7923 b->x2 = c->x2; 7924 c++; 7925 7926 if (b->x1 < X1) 7927 b->x1 = X1; 7928 if (b->x2 > X2) 7929 b->x2 = X2; 7930 if (b->x2 <= b->x1) 7931 continue; 7932 7933 b->x1 += dx; 7934 b->x2 += dx; 7935 b->y1 = y + dy; 7936 b->y2 = b->y1 + 1; 7937 if (++b == last_box) { 7938 fill.boxes(sna, &fill, box, last_box - box); 7939 b = box; 7940 } 7941 } 7942 } while (--n); 7943 RegionUninit(&clip); 7944 } 7945 if (b != box) 7946 fill.boxes(sna, &fill, box, b - box); 7947 goto done; 7948 } 7949 7950damage_clipped: 7951 { 7952 RegionRec clip; 7953 7954 region_set(&clip, extents); 7955 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 7956 return true; 7957 7958 assert(dx + clip.extents.x1 >= 0); 7959 assert(dy + clip.extents.y1 >= 0); 7960 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 7961 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 7962 7963 DBG(("%s: clip %d x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 7964 __FUNCTION__, 7965 region_num_rects(&clip), 7966 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 7967 n, pt->x, pt->y)); 7968 7969 if (clip.data == NULL) { 7970 do { 7971 *(DDXPointRec *)b = *pt++; 7972 b->x2 = b->x1 + (int)*width++; 7973 b->y2 = b->y1 + 1; 7974 7975 if (box_intersect(b, &clip.extents)) { 7976 b->x1 += dx; 7977 b->x2 += dx; 7978 b->y1 += dy; 7979 b->y2 += dy; 7980 if (++b == last_box) { 7981 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7982 fill.boxes(sna, &fill, box, last_box - box); 7983 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7984 b = box; 7985 } 7986 } 7987 } while (--n); 7988 } else { 7989 const BoxRec * const clip_start = RegionBoxptr(&clip); 7990 const BoxRec * const clip_end = clip_start + clip.data->numRects; 7991 do { 7992 int16_t X1 = pt->x; 7993 int16_t y = pt->y; 7994 int16_t X2 = X1 + (int)*width; 7995 const BoxRec *c; 7996 7997 pt++; 7998 width++; 7999 8000 if (y < extents->y1 || extents->y2 <= y) 8001 continue; 8002 8003 if (X1 < extents->x1) 8004 X1 = extents->x1; 8005 8006 if (X2 > extents->x2) 8007 X2 = extents->x2; 8008 8009 if (X1 >= X2) 8010 continue; 8011 8012 c = find_clip_box_for_y(clip_start, 8013 clip_end, 8014 y); 8015 while (c != clip_end) { 8016 if (y + 1 <= c->y1 || X2 <= c->x1) 8017 break; 8018 8019 if (X1 >= c->x2) { 8020 c++; 8021 continue; 8022 } 8023 8024 b->x1 = c->x1; 8025 b->x2 = c->x2; 8026 c++; 8027 8028 if (b->x1 < X1) 8029 b->x1 = X1; 8030 if (b->x2 > X2) 8031 b->x2 = X2; 8032 if (b->x2 <= b->x1) 8033 continue; 8034 8035 b->x1 += dx; 8036 b->x2 += dx; 8037 b->y1 = y + dy; 8038 b->y2 = b->y1 + 1; 8039 if (++b == last_box) { 8040 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 8041 fill.boxes(sna, &fill, box, last_box - box); 8042 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 8043 b = box; 8044 } 8045 } 8046 } while (--n); 8047 RegionUninit(&clip); 8048 } 8049 if (b != box) { 8050 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 8051 fill.boxes(sna, &fill, box, b - box); 8052 sna_damage_add_boxes(damage, box, b - box, 0, 0); 8053 } 8054 goto done; 8055 } 8056 8057done: 8058 fill.done(sna, &fill); 8059 assert_pixmap_damage(pixmap); 8060 return true; 8061} 8062 8063static bool 8064sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 8065 struct kgem_bo *bo, 8066 struct sna_damage **damage, 8067 GCPtr gc, int n, xRectangle *rect, 8068 const BoxRec *extents, unsigned clipped); 8069 8070static bool 8071sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 8072 struct kgem_bo *bo, 8073 struct sna_damage **damage, 8074 GCPtr gc, int n, xRectangle *rect, 8075 const BoxRec *extents, unsigned clipped); 8076 8077static inline bool 8078gc_is_solid(GCPtr gc, uint32_t *color) 8079{ 8080 assert(FbFullMask(gc->depth) == (FbFullMask(gc->depth) & gc->planemask)); 8081 8082 if (gc->alu == GXclear) { 8083 *color = 0; 8084 return true; 8085 } 8086 if (gc->alu == GXset) { 8087 *color = (1 << gc->depth) - 1; 8088 return true; 8089 } 8090 8091 if (gc->fillStyle == FillSolid || 8092 (gc->fillStyle == FillTiled && gc->tileIsPixel) || 8093 (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { 8094 *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; 8095 return true; 8096 } 8097 8098 return false; 8099} 8100 8101static void 8102sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n, 8103 DDXPointPtr pt, int *width, int sorted) 8104{ 8105 struct sna_fill_spans *data = sna_gc(gc)->priv; 8106 uint32_t color; 8107 8108 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 8109 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 8110 8111 assert(PM_IS_SOLID(drawable, gc->planemask)); 8112 if (n == 0) 8113 return; 8114 8115 /* The mi routines do not attempt to keep the spans it generates 8116 * within the clip, so we must run them through the clipper. 8117 */ 8118 8119 if (gc_is_solid(gc, &color)) { 8120 sna_fill_spans_blt(drawable, 8121 data->bo, NULL, 8122 gc, color, n, pt, width, sorted, 8123 &data->region.extents, 2); 8124 } else { 8125 /* Try converting these to a set of rectangles instead */ 8126 xRectangle *rect; 8127 int i; 8128 8129 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8130 8131 rect = malloc (n * sizeof (xRectangle)); 8132 if (rect == NULL) 8133 return; 8134 8135 for (i = 0; i < n; i++) { 8136 rect[i].x = pt[i].x - drawable->x; 8137 rect[i].width = width[i]; 8138 rect[i].y = pt[i].y - drawable->y; 8139 rect[i].height = 1; 8140 } 8141 8142 if (gc->fillStyle == FillTiled) { 8143 (void)sna_poly_fill_rect_tiled_blt(drawable, 8144 data->bo, NULL, 8145 gc, n, rect, 8146 &data->region.extents, 2); 8147 } else { 8148 (void)sna_poly_fill_rect_stippled_blt(drawable, 8149 data->bo, NULL, 8150 gc, n, rect, 8151 &data->region.extents, 2); 8152 } 8153 free (rect); 8154 } 8155} 8156 8157static unsigned 8158sna_spans_extents(DrawablePtr drawable, GCPtr gc, 8159 int n, DDXPointPtr pt, int *width, 8160 BoxPtr out) 8161{ 8162 BoxRec box; 8163 bool clipped = false; 8164 8165 if (n == 0) 8166 return 0; 8167 8168 box.x1 = pt->x; 8169 box.x2 = box.x1 + *width; 8170 box.y2 = box.y1 = pt->y; 8171 8172 while (--n) { 8173 pt++; 8174 width++; 8175 if (box.x1 > pt->x) 8176 box.x1 = pt->x; 8177 if (box.x2 < pt->x + *width) 8178 box.x2 = pt->x + *width; 8179 8180 if (box.y1 > pt->y) 8181 box.y1 = pt->y; 8182 else if (box.y2 < pt->y) 8183 box.y2 = pt->y; 8184 } 8185 box.y2++; 8186 8187 if (gc) 8188 clipped = clip_box(&box, gc); 8189 if (box_empty(&box)) 8190 return 0; 8191 8192 *out = box; 8193 return 1 | clipped << 1; 8194} 8195 8196static void 8197sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n, 8198 DDXPointPtr pt, int *width, int sorted) 8199{ 8200 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8201 struct sna *sna = to_sna_from_pixmap(pixmap); 8202 struct sna_damage **damage; 8203 struct kgem_bo *bo; 8204 RegionRec region; 8205 unsigned flags; 8206 uint32_t color; 8207 8208 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 8209 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 8210 8211 flags = sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents); 8212 if (flags == 0) 8213 return; 8214 8215 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 8216 region.extents.x1, region.extents.y1, 8217 region.extents.x2, region.extents.y2)); 8218 8219 if (FORCE_FALLBACK) 8220 goto fallback; 8221 8222 if (!ACCEL_FILL_SPANS) 8223 goto fallback; 8224 8225 if (wedged(sna)) { 8226 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8227 goto fallback; 8228 } 8229 8230 DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__, 8231 gc->fillStyle, gc->fillStyle == FillSolid, 8232 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 8233 if (!PM_IS_SOLID(drawable, gc->planemask)) 8234 goto fallback; 8235 8236 bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8237 ®ion.extents, &damage); 8238 if (bo) { 8239 if (gc_is_solid(gc, &color)) { 8240 DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n", 8241 __FUNCTION__, gc->alu, gc->fgPixel)); 8242 8243 sna_fill_spans_blt(drawable, 8244 bo, damage, 8245 gc, color, n, pt, width, sorted, 8246 ®ion.extents, flags & IS_CLIPPED); 8247 } else { 8248 /* Try converting these to a set of rectangles instead */ 8249 xRectangle *rect; 8250 int i; 8251 8252 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8253 8254 rect = malloc (n * sizeof (xRectangle)); 8255 if (rect == NULL) 8256 return; 8257 8258 for (i = 0; i < n; i++) { 8259 rect[i].x = pt[i].x - drawable->x; 8260 rect[i].width = width[i]; 8261 rect[i].y = pt[i].y - drawable->y; 8262 rect[i].height = 1; 8263 } 8264 8265 if (gc->fillStyle == FillTiled) { 8266 i = sna_poly_fill_rect_tiled_blt(drawable, 8267 bo, damage, 8268 gc, n, rect, 8269 ®ion.extents, flags & IS_CLIPPED); 8270 } else { 8271 i = sna_poly_fill_rect_stippled_blt(drawable, 8272 bo, damage, 8273 gc, n, rect, 8274 ®ion.extents, flags & IS_CLIPPED); 8275 } 8276 free (rect); 8277 8278 if (i) 8279 return; 8280 } 8281 } 8282 8283fallback: 8284 DBG(("%s: fallback\n", __FUNCTION__)); 8285 region.data = NULL; 8286 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8287 return; 8288 8289 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8290 goto out; 8291 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8292 drawable_gc_flags(drawable, gc, n > 1))) 8293 goto out; 8294 8295 if (sigtrap_get() == 0) { 8296 DBG(("%s: fbFillSpans\n", __FUNCTION__)); 8297 fbFillSpans(drawable, gc, n, pt, width, sorted); 8298 FALLBACK_FLUSH(drawable); 8299 sigtrap_put(); 8300 } 8301out: 8302 sna_gc_move_to_gpu(gc); 8303 RegionUninit(®ion); 8304} 8305 8306static void 8307sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 8308 DDXPointPtr pt, int *width, int n, int sorted) 8309{ 8310 RegionRec region; 8311 8312 if (sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents) == 0) 8313 return; 8314 8315 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 8316 region.extents.x1, region.extents.y1, 8317 region.extents.x2, region.extents.y2)); 8318 8319 if (FORCE_FALLBACK) 8320 goto fallback; 8321 8322 if (!ACCEL_SET_SPANS) 8323 goto fallback; 8324 8325fallback: 8326 region.data = NULL; 8327 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 8328 return; 8329 8330 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 8331 goto out; 8332 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 8333 drawable_gc_flags(drawable, gc, n > 1))) 8334 goto out; 8335 8336 if (sigtrap_get() == 0) { 8337 DBG(("%s: fbSetSpans\n", __FUNCTION__)); 8338 fbSetSpans(drawable, gc, src, pt, width, n, sorted); 8339 FALLBACK_FLUSH(drawable); 8340 sigtrap_put(); 8341 } 8342out: 8343 sna_gc_move_to_gpu(gc); 8344 RegionUninit(®ion); 8345} 8346 8347struct sna_copy_plane { 8348 struct sna_damage **damage; 8349 struct kgem_bo *bo; 8350}; 8351 8352static void 8353sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, 8354 RegionRec *region, int sx, int sy, 8355 Pixel bitplane, void *closure) 8356{ 8357 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8358 struct sna *sna = to_sna_from_pixmap(pixmap); 8359 struct sna_copy_plane *arg = closure; 8360 PixmapPtr bitmap = (PixmapPtr)_bitmap; 8361 uint32_t br00, br13; 8362 int16_t dx, dy; 8363 const BoxRec *box; 8364 int n; 8365 8366 DBG(("%s: plane=%x (%d,%d),(%d,%d)xld\n", 8367 __FUNCTION__, (unsigned)bitplane, 8368 region->extents.x1, region->extents.y1, 8369 region->extents.x2, region->extents.y2, 8370 region_num_rects(region))); 8371 8372 box = region_rects(region); 8373 n = region_num_rects(region); 8374 assert(n); 8375 8376 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8377 assert_pixmap_contains_boxes(pixmap, box, n, dx, dy); 8378 8379 br00 = 3 << 20; 8380 br13 = arg->bo->pitch; 8381 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8382 br00 |= BLT_DST_TILED; 8383 br13 >>= 2; 8384 } 8385 br13 |= blt_depth(drawable->depth) << 24; 8386 br13 |= copy_ROP[gc->alu] << 16; 8387 DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n", 8388 __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel)); 8389 8390 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8391 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8392 do { 8393 int bx1 = (box->x1 + sx) & ~7; 8394 int bx2 = (box->x2 + sx + 7) & ~7; 8395 int bw = (bx2 - bx1)/8; 8396 int bh = box->y2 - box->y1; 8397 int bstride = ALIGN(bw, 2); 8398 int src_stride; 8399 uint8_t *dst, *src; 8400 uint32_t *b; 8401 8402 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8403 __FUNCTION__, 8404 box->x1, box->y1, 8405 box->x2, box->y2, 8406 sx, sy, bx1, bx2)); 8407 8408 src_stride = bstride*bh; 8409 assert(src_stride > 0); 8410 if (src_stride <= 128) { 8411 src_stride = ALIGN(src_stride, 8) / 4; 8412 assert(src_stride <= 32); 8413 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 8414 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8415 !kgem_check_reloc(&sna->kgem, 1)) { 8416 kgem_submit(&sna->kgem); 8417 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8418 return; /* XXX fallback? */ 8419 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8420 } 8421 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8422 8423 assert(sna->kgem.mode == KGEM_BLT); 8424 if (sna->kgem.gen >= 0100) { 8425 b = sna->kgem.batch + sna->kgem.nbatch; 8426 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 8427 b[0] |= ((box->x1 + sx) & 7) << 17; 8428 b[1] = br13; 8429 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8430 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8431 *(uint64_t *)(b+4) = 8432 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8433 I915_GEM_DOMAIN_RENDER << 16 | 8434 I915_GEM_DOMAIN_RENDER | 8435 KGEM_RELOC_FENCED, 8436 0); 8437 b[6] = gc->bgPixel; 8438 b[7] = gc->fgPixel; 8439 8440 dst = (uint8_t *)&b[8]; 8441 sna->kgem.nbatch += 8 + src_stride; 8442 } else { 8443 b = sna->kgem.batch + sna->kgem.nbatch; 8444 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 8445 b[0] |= ((box->x1 + sx) & 7) << 17; 8446 b[1] = br13; 8447 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8448 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8449 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8450 I915_GEM_DOMAIN_RENDER << 16 | 8451 I915_GEM_DOMAIN_RENDER | 8452 KGEM_RELOC_FENCED, 8453 0); 8454 b[5] = gc->bgPixel; 8455 b[6] = gc->fgPixel; 8456 8457 dst = (uint8_t *)&b[7]; 8458 sna->kgem.nbatch += 7 + src_stride; 8459 } 8460 8461 assert(bitmap->devKind); 8462 src_stride = bitmap->devKind; 8463 src = bitmap->devPrivate.ptr; 8464 src += (box->y1 + sy) * src_stride + bx1/8; 8465 src_stride -= bstride; 8466 do { 8467 int i = bstride; 8468 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8469 do { 8470 *dst++ = byte_reverse(*src++); 8471 *dst++ = byte_reverse(*src++); 8472 i -= 2; 8473 } while (i); 8474 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8475 src += src_stride; 8476 } while (--bh); 8477 } else { 8478 struct kgem_bo *upload; 8479 void *ptr; 8480 8481 if (!kgem_check_batch(&sna->kgem, 10) || 8482 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8483 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8484 kgem_submit(&sna->kgem); 8485 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8486 return; /* XXX fallback? */ 8487 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8488 } 8489 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8490 8491 upload = kgem_create_buffer(&sna->kgem, 8492 bstride*bh, 8493 KGEM_BUFFER_WRITE_INPLACE, 8494 &ptr); 8495 if (!upload) 8496 break; 8497 8498 if (sigtrap_get() == 0) { 8499 assert(sna->kgem.mode == KGEM_BLT); 8500 b = sna->kgem.batch + sna->kgem.nbatch; 8501 if (sna->kgem.gen >= 0100) { 8502 b[0] = XY_MONO_SRC_COPY | br00 | 8; 8503 b[0] |= ((box->x1 + sx) & 7) << 17; 8504 b[1] = br13; 8505 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8506 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8507 *(uint64_t *)(b+4) = 8508 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8509 I915_GEM_DOMAIN_RENDER << 16 | 8510 I915_GEM_DOMAIN_RENDER | 8511 KGEM_RELOC_FENCED, 8512 0); 8513 *(uint64_t *)(b+6) = 8514 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8515 I915_GEM_DOMAIN_RENDER << 16 | 8516 KGEM_RELOC_FENCED, 8517 0); 8518 b[8] = gc->bgPixel; 8519 b[9] = gc->fgPixel; 8520 8521 sna->kgem.nbatch += 10; 8522 } else { 8523 b[0] = XY_MONO_SRC_COPY | br00 | 6; 8524 b[0] |= ((box->x1 + sx) & 7) << 17; 8525 b[1] = br13; 8526 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8527 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8528 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8529 I915_GEM_DOMAIN_RENDER << 16 | 8530 I915_GEM_DOMAIN_RENDER | 8531 KGEM_RELOC_FENCED, 8532 0); 8533 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8534 I915_GEM_DOMAIN_RENDER << 16 | 8535 KGEM_RELOC_FENCED, 8536 0); 8537 b[6] = gc->bgPixel; 8538 b[7] = gc->fgPixel; 8539 8540 sna->kgem.nbatch += 8; 8541 } 8542 8543 dst = ptr; 8544 assert(bitmap->devKind); 8545 src_stride = bitmap->devKind; 8546 src = bitmap->devPrivate.ptr; 8547 src += (box->y1 + sy) * src_stride + bx1/8; 8548 src_stride -= bstride; 8549 do { 8550 int i = bstride; 8551 assert(src >= (uint8_t *)bitmap->devPrivate.ptr); 8552 do { 8553 *dst++ = byte_reverse(*src++); 8554 *dst++ = byte_reverse(*src++); 8555 i -= 2; 8556 } while (i); 8557 assert(src <= (uint8_t *)bitmap->devPrivate.ptr + bitmap->devKind * bitmap->drawable.height); 8558 assert(dst <= (uint8_t *)ptr + kgem_bo_size(upload)); 8559 src += src_stride; 8560 } while (--bh); 8561 8562 sigtrap_put(); 8563 } 8564 8565 kgem_bo_destroy(&sna->kgem, upload); 8566 } 8567 8568 box++; 8569 } while (--n); 8570 8571 if (arg->damage) { 8572 RegionTranslate(region, dx, dy); 8573 sna_damage_add_to_pixmap(arg->damage, region, pixmap); 8574 } 8575 assert_pixmap_damage(pixmap); 8576 blt_done(sna); 8577} 8578 8579static void 8580sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, 8581 RegionPtr region, int sx, int sy, 8582 Pixel bitplane, void *closure) 8583{ 8584 PixmapPtr dst_pixmap = get_drawable_pixmap(drawable); 8585 PixmapPtr src_pixmap = get_drawable_pixmap(source); 8586 struct sna *sna = to_sna_from_pixmap(dst_pixmap); 8587 struct sna_copy_plane *arg = closure; 8588 int16_t dx, dy; 8589 int bit = ffs(bitplane) - 1; 8590 uint32_t br00, br13; 8591 const BoxRec *box = region_rects(region); 8592 int n = region_num_rects(region); 8593 8594 DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__, 8595 (unsigned)bitplane, bit, n)); 8596 8597 if (n == 0) 8598 return; 8599 8600 if (get_drawable_deltas(source, src_pixmap, &dx, &dy)) 8601 sx += dx, sy += dy; 8602 8603 get_drawable_deltas(drawable, dst_pixmap, &dx, &dy); 8604 assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy); 8605 8606 br00 = XY_MONO_SRC_COPY | 3 << 20; 8607 br13 = arg->bo->pitch; 8608 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 8609 br00 |= BLT_DST_TILED; 8610 br13 >>= 2; 8611 } 8612 br13 |= blt_depth(drawable->depth) << 24; 8613 br13 |= copy_ROP[gc->alu] << 16; 8614 8615 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 8616 assert(kgem_bo_can_blt(&sna->kgem, arg->bo)); 8617 do { 8618 int bx1 = (box->x1 + sx) & ~7; 8619 int bx2 = (box->x2 + sx + 7) & ~7; 8620 int bw = (bx2 - bx1)/8; 8621 int bh = box->y2 - box->y1; 8622 int bstride = ALIGN(bw, 2); 8623 struct kgem_bo *upload; 8624 void *ptr; 8625 8626 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 8627 __FUNCTION__, 8628 box->x1, box->y1, 8629 box->x2, box->y2, 8630 sx, sy, bx1, bx2)); 8631 8632 if (!kgem_check_batch(&sna->kgem, 10) || 8633 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 8634 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 8635 kgem_submit(&sna->kgem); 8636 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 8637 return; /* XXX fallback? */ 8638 _kgem_set_mode(&sna->kgem, KGEM_BLT); 8639 } 8640 kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo); 8641 8642 upload = kgem_create_buffer(&sna->kgem, 8643 bstride*bh, 8644 KGEM_BUFFER_WRITE_INPLACE, 8645 &ptr); 8646 if (!upload) 8647 break; 8648 8649 if (sigtrap_get() == 0) { 8650 uint32_t *b; 8651 8652 assert(src_pixmap->devKind); 8653 switch (source->bitsPerPixel) { 8654 case 32: 8655 { 8656 uint32_t *src = src_pixmap->devPrivate.ptr; 8657 int src_stride = src_pixmap->devKind/sizeof(uint32_t); 8658 uint8_t *dst = ptr; 8659 8660 src += (box->y1 + sy) * src_stride; 8661 src += bx1; 8662 8663 src_stride -= bw * 8; 8664 bstride -= bw; 8665 8666 do { 8667 int i = bw; 8668 do { 8669 uint8_t v = 0; 8670 8671 v |= ((*src++ >> bit) & 1) << 7; 8672 v |= ((*src++ >> bit) & 1) << 6; 8673 v |= ((*src++ >> bit) & 1) << 5; 8674 v |= ((*src++ >> bit) & 1) << 4; 8675 v |= ((*src++ >> bit) & 1) << 3; 8676 v |= ((*src++ >> bit) & 1) << 2; 8677 v |= ((*src++ >> bit) & 1) << 1; 8678 v |= ((*src++ >> bit) & 1) << 0; 8679 8680 *dst++ = v; 8681 } while (--i); 8682 dst += bstride; 8683 src += src_stride; 8684 } while (--bh); 8685 break; 8686 } 8687 case 16: 8688 { 8689 uint16_t *src = src_pixmap->devPrivate.ptr; 8690 int src_stride = src_pixmap->devKind/sizeof(uint16_t); 8691 uint8_t *dst = ptr; 8692 8693 src += (box->y1 + sy) * src_stride; 8694 src += bx1; 8695 8696 src_stride -= bw * 8; 8697 bstride -= bw; 8698 8699 do { 8700 int i = bw; 8701 do { 8702 uint8_t v = 0; 8703 8704 v |= ((*src++ >> bit) & 1) << 7; 8705 v |= ((*src++ >> bit) & 1) << 6; 8706 v |= ((*src++ >> bit) & 1) << 5; 8707 v |= ((*src++ >> bit) & 1) << 4; 8708 v |= ((*src++ >> bit) & 1) << 3; 8709 v |= ((*src++ >> bit) & 1) << 2; 8710 v |= ((*src++ >> bit) & 1) << 1; 8711 v |= ((*src++ >> bit) & 1) << 0; 8712 8713 *dst++ = v; 8714 } while (--i); 8715 dst += bstride; 8716 src += src_stride; 8717 } while (--bh); 8718 break; 8719 } 8720 default: 8721 assert(0); 8722 case 8: 8723 { 8724 uint8_t *src = src_pixmap->devPrivate.ptr; 8725 int src_stride = src_pixmap->devKind/sizeof(uint8_t); 8726 uint8_t *dst = ptr; 8727 8728 src += (box->y1 + sy) * src_stride; 8729 src += bx1; 8730 8731 src_stride -= bw * 8; 8732 bstride -= bw; 8733 8734 do { 8735 int i = bw; 8736 do { 8737 uint8_t v = 0; 8738 8739 v |= ((*src++ >> bit) & 1) << 7; 8740 v |= ((*src++ >> bit) & 1) << 6; 8741 v |= ((*src++ >> bit) & 1) << 5; 8742 v |= ((*src++ >> bit) & 1) << 4; 8743 v |= ((*src++ >> bit) & 1) << 3; 8744 v |= ((*src++ >> bit) & 1) << 2; 8745 v |= ((*src++ >> bit) & 1) << 1; 8746 v |= ((*src++ >> bit) & 1) << 0; 8747 8748 *dst++ = v; 8749 } while (--i); 8750 dst += bstride; 8751 src += src_stride; 8752 } while (--bh); 8753 break; 8754 } 8755 } 8756 8757 kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo); 8758 8759 assert(sna->kgem.mode == KGEM_BLT); 8760 b = sna->kgem.batch + sna->kgem.nbatch; 8761 if (sna->kgem.gen >= 0100) { 8762 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 8; 8763 b[1] = br13; 8764 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8765 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8766 *(uint64_t *)(b+4) = 8767 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8768 I915_GEM_DOMAIN_RENDER << 16 | 8769 I915_GEM_DOMAIN_RENDER | 8770 KGEM_RELOC_FENCED, 8771 0); 8772 *(uint64_t *)(b+6) = 8773 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 8774 I915_GEM_DOMAIN_RENDER << 16 | 8775 KGEM_RELOC_FENCED, 8776 0); 8777 b[8] = gc->bgPixel; 8778 b[9] = gc->fgPixel; 8779 8780 sna->kgem.nbatch += 10; 8781 } else { 8782 b[0] = br00 | ((box->x1 + sx) & 7) << 17 | 6; 8783 b[1] = br13; 8784 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 8785 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 8786 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, arg->bo, 8787 I915_GEM_DOMAIN_RENDER << 16 | 8788 I915_GEM_DOMAIN_RENDER | 8789 KGEM_RELOC_FENCED, 8790 0); 8791 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 8792 I915_GEM_DOMAIN_RENDER << 16 | 8793 KGEM_RELOC_FENCED, 8794 0); 8795 b[6] = gc->bgPixel; 8796 b[7] = gc->fgPixel; 8797 8798 sna->kgem.nbatch += 8; 8799 } 8800 sigtrap_put(); 8801 } 8802 kgem_bo_destroy(&sna->kgem, upload); 8803 8804 box++; 8805 } while (--n); 8806 8807 if (arg->damage) { 8808 RegionTranslate(region, dx, dy); 8809 sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap); 8810 } 8811 assert_pixmap_damage(dst_pixmap); 8812 blt_done(sna); 8813} 8814 8815static RegionPtr 8816sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 8817 int src_x, int src_y, 8818 int w, int h, 8819 int dst_x, int dst_y, 8820 unsigned long bit) 8821{ 8822 PixmapPtr pixmap = get_drawable_pixmap(dst); 8823 struct sna *sna = to_sna_from_pixmap(pixmap); 8824 RegionRec region, *ret = NULL; 8825 struct sna_copy_plane arg; 8826 8827 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__, 8828 src_x, src_y, dst_x, dst_y, w, h)); 8829 8830 if (gc->planemask == 0) 8831 goto empty; 8832 8833 if (src->bitsPerPixel == 1 && (bit&1) == 0) 8834 goto empty; 8835 8836 region.extents.x1 = dst_x + dst->x; 8837 region.extents.y1 = dst_y + dst->y; 8838 region.extents.x2 = region.extents.x1 + w; 8839 region.extents.y2 = region.extents.y1 + h; 8840 region.data = NULL; 8841 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 8842 8843 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", 8844 __FUNCTION__, 8845 region.extents.x1, region.extents.y1, 8846 region.extents.x2, region.extents.y2)); 8847 8848 { 8849 RegionRec clip; 8850 8851 clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x); 8852 clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y); 8853 clip.extents.x2 = clip.extents.x1 + src->width; 8854 clip.extents.y2 = clip.extents.y1 + src->height; 8855 clip.data = NULL; 8856 8857 DBG(("%s: src extents (%d, %d), (%d, %d)\n", 8858 __FUNCTION__, 8859 clip.extents.x1, clip.extents.y1, 8860 clip.extents.x2, clip.extents.y2)); 8861 8862 RegionIntersect(®ion, ®ion, &clip); 8863 } 8864 DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n", 8865 __FUNCTION__, 8866 region.extents.x1, region.extents.y1, 8867 region.extents.x2, region.extents.y2)); 8868 if (box_empty(®ion.extents)) 8869 goto empty; 8870 8871 RegionTranslate(®ion, 8872 src_x - dst_x - dst->x + src->x, 8873 src_y - dst_y - dst->y + src->y); 8874 8875 if (!sna_drawable_move_region_to_cpu(src, ®ion, MOVE_READ)) 8876 goto out; 8877 8878 RegionTranslate(®ion, 8879 -(src_x - dst_x - dst->x + src->x), 8880 -(src_y - dst_y - dst->y + src->y)); 8881 8882 if (FORCE_FALLBACK) 8883 goto fallback; 8884 8885 if (!ACCEL_COPY_PLANE) 8886 goto fallback; 8887 8888 if (wedged(sna)) 8889 goto fallback; 8890 8891 if (!PM_IS_SOLID(dst, gc->planemask)) 8892 goto fallback; 8893 8894 arg.bo = sna_drawable_use_bo(dst, PREFER_GPU, 8895 ®ion.extents, &arg.damage); 8896 if (arg.bo) { 8897 if (arg.bo->tiling == I915_TILING_Y) { 8898 assert(arg.bo == __sna_pixmap_get_bo(pixmap)); 8899 arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 8900 if (arg.bo == NULL) { 8901 DBG(("%s: fallback -- unable to change tiling\n", 8902 __FUNCTION__)); 8903 goto fallback; 8904 } 8905 } 8906 8907 if (!kgem_bo_can_blt(&sna->kgem, arg.bo)) 8908 return false; 8909 8910 RegionUninit(®ion); 8911 return sna_do_copy(src, dst, gc, 8912 src_x, src_y, 8913 w, h, 8914 dst_x, dst_y, 8915 src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt, 8916 (Pixel)bit, &arg); 8917 } 8918 8919fallback: 8920 DBG(("%s: fallback\n", __FUNCTION__)); 8921 if (!sna_gc_move_to_cpu(gc, dst, ®ion)) 8922 goto out; 8923 if (!sna_drawable_move_region_to_cpu(dst, ®ion, 8924 drawable_gc_flags(dst, gc, false))) 8925 goto out; 8926 8927 if (sigtrap_get() == 0) { 8928 DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n", 8929 __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit)); 8930 ret = miDoCopy(src, dst, gc, 8931 src_x, src_y, w, h, dst_x, dst_y, 8932 src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN, 8933 bit, 0); 8934 FALLBACK_FLUSH(dst); 8935 sigtrap_put(); 8936 } 8937out: 8938 sna_gc_move_to_gpu(gc); 8939 RegionUninit(®ion); 8940 return ret; 8941empty: 8942 return miHandleExposures(src, dst, gc, 8943 src_x, src_y, 8944 w, h, 8945 dst_x, dst_y, bit); 8946} 8947 8948static bool 8949sna_poly_point_blt(DrawablePtr drawable, 8950 struct kgem_bo *bo, 8951 struct sna_damage **damage, 8952 GCPtr gc, int mode, int n, DDXPointPtr pt, 8953 bool clipped) 8954{ 8955 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8956 struct sna *sna = to_sna_from_pixmap(pixmap); 8957 BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box); 8958 struct sna_fill_op fill; 8959 DDXPointRec last; 8960 int16_t dx, dy; 8961 8962 DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n", 8963 __FUNCTION__, gc->alu, gc->fgPixel, clipped)); 8964 8965 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_POINTS)) 8966 return false; 8967 8968 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8969 8970 last.x = drawable->x; 8971 last.y = drawable->y; 8972 8973 if (!clipped) { 8974 last.x += dx; 8975 last.y += dy; 8976 8977 assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y); 8978 sna_damage_add_points(damage, pt, n, last.x, last.y); 8979 if (fill.points && mode != CoordModePrevious) { 8980 fill.points(sna, &fill, last.x, last.y, pt, n); 8981 } else { 8982 do { 8983 unsigned nbox = n; 8984 if (nbox > ARRAY_SIZE(box)) 8985 nbox = ARRAY_SIZE(box); 8986 n -= nbox; 8987 do { 8988 *(DDXPointRec *)b = *pt++; 8989 8990 b->x1 += last.x; 8991 b->y1 += last.y; 8992 if (mode == CoordModePrevious) 8993 last = *(DDXPointRec *)b; 8994 8995 b->x2 = b->x1 + 1; 8996 b->y2 = b->y1 + 1; 8997 b++; 8998 } while (--nbox); 8999 fill.boxes(sna, &fill, box, b - box); 9000 b = box; 9001 } while (n); 9002 } 9003 } else { 9004 RegionPtr clip = gc->pCompositeClip; 9005 9006 while (n--) { 9007 int x, y; 9008 9009 x = pt->x; 9010 y = pt->y; 9011 pt++; 9012 if (mode == CoordModePrevious) { 9013 x += last.x; 9014 y += last.y; 9015 last.x = x; 9016 last.y = y; 9017 } else { 9018 x += drawable->x; 9019 y += drawable->y; 9020 } 9021 9022 if (RegionContainsPoint(clip, x, y, NULL)) { 9023 b->x1 = x + dx; 9024 b->y1 = y + dy; 9025 b->x2 = b->x1 + 1; 9026 b->y2 = b->y1 + 1; 9027 if (++b == last_box){ 9028 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 9029 fill.boxes(sna, &fill, box, last_box - box); 9030 if (damage) 9031 sna_damage_add_boxes(damage, box, last_box-box, 0, 0); 9032 b = box; 9033 } 9034 } 9035 } 9036 if (b != box){ 9037 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9038 fill.boxes(sna, &fill, box, b - box); 9039 if (damage) 9040 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9041 } 9042 } 9043 fill.done(sna, &fill); 9044 assert_pixmap_damage(pixmap); 9045 return true; 9046} 9047 9048static unsigned 9049sna_poly_point_extents(DrawablePtr drawable, GCPtr gc, 9050 int mode, int n, DDXPointPtr pt, BoxPtr out) 9051{ 9052 BoxRec box; 9053 bool clipped; 9054 9055 if (n == 0) 9056 return 0; 9057 9058 box.x2 = box.x1 = pt->x; 9059 box.y2 = box.y1 = pt->y; 9060 if (mode == CoordModePrevious) { 9061 DDXPointRec last = *pt++; 9062 while (--n) { 9063 last.x += pt->x; 9064 last.y += pt->y; 9065 pt++; 9066 box_add_xy(&box, last.x, last.y); 9067 } 9068 } else { 9069 while (--n) 9070 box_add_pt(&box, ++pt); 9071 } 9072 box.x2++; 9073 box.y2++; 9074 9075 clipped = trim_and_translate_box(&box, drawable, gc); 9076 if (box_empty(&box)) 9077 return 0; 9078 9079 *out = box; 9080 return 1 | clipped << 1; 9081} 9082 9083static void 9084sna_poly_point(DrawablePtr drawable, GCPtr gc, 9085 int mode, int n, DDXPointPtr pt) 9086{ 9087 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9088 struct sna *sna = to_sna_from_pixmap(pixmap); 9089 RegionRec region; 9090 unsigned flags; 9091 9092 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n", 9093 __FUNCTION__, mode, n, pt[0].x, pt[0].y)); 9094 9095 flags = sna_poly_point_extents(drawable, gc, mode, n, pt, ®ion.extents); 9096 if (flags == 0) 9097 return; 9098 9099 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9100 region.extents.x1, region.extents.y1, 9101 region.extents.x2, region.extents.y2, 9102 flags)); 9103 9104 if (FORCE_FALLBACK) 9105 goto fallback; 9106 9107 if (!ACCEL_POLY_POINT) 9108 goto fallback; 9109 9110 if (wedged(sna)) { 9111 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9112 goto fallback; 9113 } 9114 9115 if (PM_IS_SOLID(drawable, gc->planemask)) { 9116 struct sna_damage **damage; 9117 struct kgem_bo *bo; 9118 9119 DBG(("%s: trying solid fill [%08lx] blt paths\n", 9120 __FUNCTION__, gc->fgPixel)); 9121 9122 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9123 ®ion.extents, &damage)) && 9124 sna_poly_point_blt(drawable, bo, damage, 9125 gc, mode, n, pt, flags & IS_CLIPPED)) 9126 return; 9127 } 9128 9129fallback: 9130 DBG(("%s: fallback\n", __FUNCTION__)); 9131 region.data = NULL; 9132 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 9133 return; 9134 9135 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 9136 goto out; 9137 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 9138 MOVE_READ | MOVE_WRITE)) 9139 goto out; 9140 9141 if (sigtrap_get() == 0) { 9142 DBG(("%s: fbPolyPoint\n", __FUNCTION__)); 9143 fbPolyPoint(drawable, gc, mode, n, pt, flags); 9144 FALLBACK_FLUSH(drawable); 9145 sigtrap_put(); 9146 } 9147out: 9148 sna_gc_move_to_gpu(gc); 9149 RegionUninit(®ion); 9150} 9151 9152static bool 9153sna_poly_zero_line_blt(DrawablePtr drawable, 9154 struct kgem_bo *bo, 9155 struct sna_damage **damage, 9156 GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt, 9157 const BoxRec *extents, unsigned clipped) 9158{ 9159 static void * const _jump[] = { 9160 &&no_damage, 9161 &&damage, 9162 9163 &&no_damage_offset, 9164 &&damage_offset, 9165 }; 9166 9167 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9168 struct sna *sna = to_sna_from_pixmap(pixmap); 9169 int x2, y2, xstart, ystart, oc2; 9170 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 9171 bool degenerate = true; 9172 struct sna_fill_op fill; 9173 RegionRec clip; 9174 BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box); 9175 const BoxRec *last_extents; 9176 int16_t dx, dy; 9177 void *jump, *ret; 9178 9179 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 9180 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 9181 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_SPANS)) 9182 return false; 9183 9184 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9185 9186 region_set(&clip, extents); 9187 if (clipped) { 9188 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9189 return true; 9190 } 9191 9192 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 9193 DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n", 9194 __FUNCTION__, clipped, 9195 clip.extents.x1, clip.extents.y1, 9196 clip.extents.x2, clip.extents.y2, 9197 dx, dy, damage)); 9198 9199 extents = region_rects(&clip); 9200 last_extents = extents + region_num_rects(&clip); 9201 9202 b = box; 9203 do { 9204 int n = _n; 9205 const DDXPointRec *pt = _pt; 9206 9207 xstart = pt->x + drawable->x; 9208 ystart = pt->y + drawable->y; 9209 9210 x2 = xstart; 9211 y2 = ystart; 9212 oc2 = 0; 9213 OUTCODES(oc2, x2, y2, extents); 9214 9215 while (--n) { 9216 int16_t sdx, sdy; 9217 int adx, ady, length; 9218 int e, e1, e2, e3; 9219 int x1 = x2, x; 9220 int y1 = y2, y; 9221 int oc1 = oc2; 9222 int octant; 9223 9224 ++pt; 9225 9226 x2 = pt->x; 9227 y2 = pt->y; 9228 if (mode == CoordModePrevious) { 9229 x2 += x1; 9230 y2 += y1; 9231 } else { 9232 x2 += drawable->x; 9233 y2 += drawable->y; 9234 } 9235 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 9236 __FUNCTION__, x1, y1, x2, y2)); 9237 if (x2 == x1 && y2 == y1) 9238 continue; 9239 9240 degenerate = false; 9241 9242 oc2 = 0; 9243 OUTCODES(oc2, x2, y2, extents); 9244 if (oc1 & oc2) 9245 continue; 9246 9247 CalcLineDeltas(x1, y1, x2, y2, 9248 adx, ady, sdx, sdy, 9249 1, 1, octant); 9250 9251 DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n", 9252 __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2)); 9253 if (adx == 0 || ady == 0) { 9254 if (x1 <= x2) { 9255 b->x1 = x1; 9256 b->x2 = x2; 9257 } else { 9258 b->x1 = x2; 9259 b->x2 = x1; 9260 } 9261 if (y1 <= y2) { 9262 b->y1 = y1; 9263 b->y2 = y2; 9264 } else { 9265 b->y1 = y2; 9266 b->y2 = y1; 9267 } 9268 b->x2++; 9269 b->y2++; 9270 if (oc1 | oc2) { 9271 bool intersects; 9272 9273 intersects = box_intersect(b, extents); 9274 assert(intersects); 9275 } 9276 if (++b == last_box) { 9277 ret = &&rectangle_continue; 9278 goto *jump; 9279rectangle_continue: 9280 b = box; 9281 } 9282 } else if (adx >= ady) { 9283 int x2_clipped = x2, y2_clipped = y2; 9284 bool dirty; 9285 9286 /* X-major segment */ 9287 e1 = ady << 1; 9288 e2 = e1 - (adx << 1); 9289 e = e1 - adx; 9290 length = adx; 9291 9292 FIXUP_ERROR(e, octant, bias); 9293 9294 x = x1; 9295 y = y1; 9296 9297 if (oc1 | oc2) { 9298 int pt1_clipped, pt2_clipped; 9299 9300 if (miZeroClipLine(extents->x1, extents->y1, 9301 extents->x2-1, extents->y2-1, 9302 &x, &y, &x2_clipped, &y2_clipped, 9303 adx, ady, 9304 &pt1_clipped, &pt2_clipped, 9305 octant, bias, oc1, oc2) == -1) 9306 continue; 9307 9308 length = abs(x2_clipped - x); 9309 if (length == 0) 9310 continue; 9311 9312 if (pt1_clipped) { 9313 int clipdx = abs(x - x1); 9314 int clipdy = abs(y - y1); 9315 e += clipdy * e2 + (clipdx - clipdy) * e1; 9316 } 9317 } 9318 9319 e3 = e2 - e1; 9320 e = e - e1; 9321 9322 b->x1 = x; 9323 b->y1 = y; 9324 dirty = false; 9325 while (length--) { 9326 e += e1; 9327 dirty = true; 9328 if (e >= 0) { 9329 e += e3; 9330 9331 if (sdx < 0) { 9332 b->x2 = b->x1 + 1; 9333 b->x1 = x; 9334 } else 9335 b->x2 = x + 1; 9336 b->y2 = b->y1 + 1; 9337 9338 if (++b == last_box) { 9339 ret = &&X_continue; 9340 goto *jump; 9341X_continue: 9342 b = box; 9343 } 9344 9345 b->x1 = x + sdx; 9346 b->y1 = y += sdy; 9347 dirty = false; 9348 } 9349 x += sdx; 9350 } 9351 if (dirty) { 9352 x -= sdx; 9353 if (sdx < 0) { 9354 b->x2 = b->x1 + 1; 9355 b->x1 = x; 9356 } else 9357 b->x2 = x + 1; 9358 b->y2 = b->y1 + 1; 9359 9360 if (++b == last_box) { 9361 ret = &&X2_continue; 9362 goto *jump; 9363X2_continue: 9364 b = box; 9365 } 9366 } 9367 } else { 9368 int x2_clipped = x2, y2_clipped = y2; 9369 bool dirty; 9370 9371 /* Y-major segment */ 9372 e1 = adx << 1; 9373 e2 = e1 - (ady << 1); 9374 e = e1 - ady; 9375 length = ady; 9376 9377 SetYMajorOctant(octant); 9378 FIXUP_ERROR(e, octant, bias); 9379 9380 x = x1; 9381 y = y1; 9382 9383 if (oc1 | oc2) { 9384 int pt1_clipped, pt2_clipped; 9385 9386 if (miZeroClipLine(extents->x1, extents->y1, 9387 extents->x2-1, extents->y2-1, 9388 &x, &y, &x2_clipped, &y2_clipped, 9389 adx, ady, 9390 &pt1_clipped, &pt2_clipped, 9391 octant, bias, oc1, oc2) == -1) 9392 continue; 9393 9394 length = abs(y2_clipped - y); 9395 if (length == 0) 9396 continue; 9397 9398 if (pt1_clipped) { 9399 int clipdx = abs(x - x1); 9400 int clipdy = abs(y - y1); 9401 e += clipdx * e2 + (clipdy - clipdx) * e1; 9402 } 9403 } 9404 9405 e3 = e2 - e1; 9406 e = e - e1; 9407 9408 b->x1 = x; 9409 b->y1 = y; 9410 dirty = false; 9411 while (length--) { 9412 e += e1; 9413 dirty = true; 9414 if (e >= 0) { 9415 e += e3; 9416 9417 if (sdy < 0) { 9418 b->y2 = b->y1 + 1; 9419 b->y1 = y; 9420 } else 9421 b->y2 = y + 1; 9422 b->x2 = x + 1; 9423 9424 if (++b == last_box) { 9425 ret = &&Y_continue; 9426 goto *jump; 9427Y_continue: 9428 b = box; 9429 } 9430 9431 b->x1 = x += sdx; 9432 b->y1 = y + sdy; 9433 dirty = false; 9434 } 9435 y += sdy; 9436 } 9437 9438 if (dirty) { 9439 y -= sdy; 9440 if (sdy < 0) { 9441 b->y2 = b->y1 + 1; 9442 b->y1 = y; 9443 } else 9444 b->y2 = y + 1; 9445 b->x2 = x + 1; 9446 9447 if (++b == last_box) { 9448 ret = &&Y2_continue; 9449 goto *jump; 9450Y2_continue: 9451 b = box; 9452 } 9453 } 9454 } 9455 } 9456 9457#if 0 9458 /* Only do the CapNotLast check on the last segment 9459 * and only if the endpoint wasn't clipped. And then, if the last 9460 * point is the same as the first point, do not draw it, unless the 9461 * line is degenerate 9462 */ 9463 if (!pt2_clipped && 9464 gc->capStyle != CapNotLast && 9465 !(xstart == x2 && ystart == y2 && !degenerate)) 9466 { 9467 b->x2 = x2; 9468 b->y2 = y2; 9469 if (b->x2 < b->x1) { 9470 int16_t t = b->x1; 9471 b->x1 = b->x2; 9472 b->x2 = t; 9473 } 9474 if (b->y2 < b->y1) { 9475 int16_t t = b->y1; 9476 b->y1 = b->y2; 9477 b->y2 = t; 9478 } 9479 b->x2++; 9480 b->y2++; 9481 b++; 9482 } 9483#endif 9484 } while (++extents != last_extents); 9485 9486 if (b != box) { 9487 ret = &&done; 9488 goto *jump; 9489 } 9490 9491done: 9492 fill.done(sna, &fill); 9493 assert_pixmap_damage(pixmap); 9494 RegionUninit(&clip); 9495 return true; 9496 9497damage: 9498 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9499 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9500no_damage: 9501 fill.boxes(sna, &fill, box, b-box); 9502 goto *ret; 9503 9504no_damage_offset: 9505 { 9506 BoxRec *bb = box; 9507 do { 9508 bb->x1 += dx; 9509 bb->x2 += dx; 9510 bb->y1 += dy; 9511 bb->y2 += dy; 9512 } while (++bb != b); 9513 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9514 fill.boxes(sna, &fill, box, b - box); 9515 } 9516 goto *ret; 9517 9518damage_offset: 9519 { 9520 BoxRec *bb = box; 9521 do { 9522 bb->x1 += dx; 9523 bb->x2 += dx; 9524 bb->y1 += dy; 9525 bb->y2 += dy; 9526 } while (++bb != b); 9527 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 9528 fill.boxes(sna, &fill, box, b - box); 9529 sna_damage_add_boxes(damage, box, b - box, 0, 0); 9530 } 9531 goto *ret; 9532} 9533 9534static bool 9535sna_poly_line_blt(DrawablePtr drawable, 9536 struct kgem_bo *bo, 9537 struct sna_damage **damage, 9538 GCPtr gc, uint32_t pixel, 9539 int mode, int n, DDXPointPtr pt, 9540 const BoxRec *extents, bool clipped) 9541{ 9542 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9543 struct sna *sna = to_sna_from_pixmap(pixmap); 9544 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 9545 struct sna_fill_op fill; 9546 DDXPointRec last; 9547 int16_t dx, dy; 9548 9549 DBG(("%s: alu=%d, fg=%08x, clipped=%d\n", __FUNCTION__, gc->alu, (unsigned)pixel, clipped)); 9550 9551 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) 9552 return false; 9553 9554 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9555 9556 if (!clipped) { 9557 dx += drawable->x; 9558 dy += drawable->y; 9559 9560 last.x = pt->x + dx; 9561 last.y = pt->y + dy; 9562 pt++; 9563 9564 while (--n) { 9565 DDXPointRec p; 9566 9567 p = *pt++; 9568 if (mode == CoordModePrevious) { 9569 p.x += last.x; 9570 p.y += last.y; 9571 } else { 9572 p.x += dx; 9573 p.y += dy; 9574 } 9575 DBG(("%s: line (%d, %d) -> (%d, %d)\n", __FUNCTION__, last.x, last.y, p.x, p.y)); 9576 9577 if (last.x == p.x) { 9578 b->x1 = last.x; 9579 b->x2 = last.x + 1; 9580 } else if (last.x < p.x) { 9581 b->x1 = last.x; 9582 b->x2 = p.x; 9583 } else { 9584 b->x1 = p.x; 9585 b->x2 = last.x; 9586 } 9587 9588 if (last.y == p.y) { 9589 b->y1 = last.y; 9590 b->y2 = last.y + 1; 9591 } else if (last.y < p.y) { 9592 b->y1 = last.y; 9593 b->y2 = p.y; 9594 } else { 9595 b->y1 = p.y; 9596 b->y2 = last.y; 9597 } 9598 b->y2 += last.x == p.x && last.y != p.y; 9599 b->x2 += last.y == p.y && last.x != p.x; 9600 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9601 __FUNCTION__, 9602 b->x1, b->y1, b->x2, b->y2)); 9603 9604 if (++b == last_box) { 9605 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9606 fill.boxes(sna, &fill, boxes, last_box - boxes); 9607 if (damage) 9608 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9609 b = boxes; 9610 } 9611 9612 last = p; 9613 } 9614 } else { 9615 RegionRec clip; 9616 9617 region_set(&clip, extents); 9618 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 9619 return true; 9620 9621 last.x = pt->x + drawable->x; 9622 last.y = pt->y + drawable->y; 9623 pt++; 9624 9625 if (clip.data == NULL) { 9626 while (--n) { 9627 DDXPointRec p; 9628 9629 p = *pt++; 9630 if (mode == CoordModePrevious) { 9631 p.x += last.x; 9632 p.y += last.y; 9633 } else { 9634 p.x += drawable->x; 9635 p.y += drawable->y; 9636 } 9637 if (last.x == p.x) { 9638 b->x1 = last.x; 9639 b->x2 = last.x + 1; 9640 } else if (last.x < p.x) { 9641 b->x1 = last.x; 9642 b->x2 = p.x; 9643 } else { 9644 b->x1 = p.x; 9645 b->x2 = last.x; 9646 } 9647 if (last.y == p.y) { 9648 b->y1 = last.y; 9649 b->y2 = last.y + 1; 9650 } else if (last.y < p.y) { 9651 b->y1 = last.y; 9652 b->y2 = p.y; 9653 } else { 9654 b->y1 = p.y; 9655 b->y2 = last.y; 9656 } 9657 b->y2 += last.x == p.x && last.y != p.y; 9658 b->x2 += last.y == p.y && last.x != p.x; 9659 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9660 __FUNCTION__, 9661 b->x1, b->y1, b->x2, b->y2)); 9662 if (box_intersect(b, &clip.extents)) { 9663 b->x1 += dx; 9664 b->x2 += dx; 9665 b->y1 += dy; 9666 b->y2 += dy; 9667 if (++b == last_box) { 9668 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9669 fill.boxes(sna, &fill, boxes, last_box - boxes); 9670 if (damage) 9671 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 9672 b = boxes; 9673 } 9674 } 9675 9676 last = p; 9677 } 9678 } else { 9679 const BoxRec * const clip_start = RegionBoxptr(&clip); 9680 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9681 const BoxRec *c; 9682 9683 while (--n) { 9684 DDXPointRec p; 9685 BoxRec box; 9686 9687 p = *pt++; 9688 if (mode == CoordModePrevious) { 9689 p.x += last.x; 9690 p.y += last.y; 9691 } else { 9692 p.x += drawable->x; 9693 p.y += drawable->y; 9694 } 9695 if (last.x == p.x) { 9696 box.x1 = last.x; 9697 box.x2 = last.x + 1; 9698 } else if (last.x < p.x) { 9699 box.x1 = last.x; 9700 box.x2 = p.x; 9701 } else { 9702 box.x1 = p.x; 9703 box.x2 = last.x; 9704 } 9705 if (last.y == p.y) { 9706 box.y1 = last.y; 9707 box.y2 = last.y + 1; 9708 } else if (last.y < p.y) { 9709 box.y1 = last.y; 9710 box.y2 = p.y; 9711 } else { 9712 box.y1 = p.y; 9713 box.y2 = last.y; 9714 } 9715 b->y2 += last.x == p.x && last.y != p.y; 9716 b->x2 += last.y == p.y && last.x != p.x; 9717 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9718 __FUNCTION__, 9719 box.x1, box.y1, box.x2, box.y2)); 9720 9721 c = find_clip_box_for_y(clip_start, 9722 clip_end, 9723 box.y1); 9724 while (c != clip_end) { 9725 if (box.y2 <= c->y1) 9726 break; 9727 9728 *b = box; 9729 if (box_intersect(b, c++)) { 9730 b->x1 += dx; 9731 b->x2 += dx; 9732 b->y1 += dy; 9733 b->y2 += dy; 9734 if (++b == last_box) { 9735 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 9736 fill.boxes(sna, &fill, boxes, last_box-boxes); 9737 if (damage) 9738 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9739 b = boxes; 9740 } 9741 } 9742 } 9743 9744 last = p; 9745 } 9746 } 9747 RegionUninit(&clip); 9748 } 9749 if (b != boxes) { 9750 assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0); 9751 fill.boxes(sna, &fill, boxes, b - boxes); 9752 if (damage) 9753 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 9754 } 9755 fill.done(sna, &fill); 9756 assert_pixmap_damage(pixmap); 9757 return true; 9758} 9759 9760static unsigned 9761sna_poly_line_extents(DrawablePtr drawable, GCPtr gc, 9762 int mode, int n, DDXPointPtr pt, 9763 BoxPtr out) 9764{ 9765 BoxRec box; 9766 bool clip, blt = true; 9767 9768 if (n == 0) 9769 return 0; 9770 9771 box.x2 = box.x1 = pt->x; 9772 box.y2 = box.y1 = pt->y; 9773 if (mode == CoordModePrevious) { 9774 int x = box.x1; 9775 int y = box.y1; 9776 while (--n) { 9777 pt++; 9778 x += pt->x; 9779 y += pt->y; 9780 if (blt) 9781 blt &= pt->x == 0 || pt->y == 0; 9782 box_add_xy(&box, x, y); 9783 } 9784 } else { 9785 int x = box.x1; 9786 int y = box.y1; 9787 while (--n) { 9788 pt++; 9789 if (blt) { 9790 blt &= pt->x == x || pt->y == y; 9791 x = pt->x; 9792 y = pt->y; 9793 } 9794 box_add_pt(&box, pt); 9795 } 9796 } 9797 box.x2++; 9798 box.y2++; 9799 9800 if (gc->lineWidth) { 9801 int extra = gc->lineWidth >> 1; 9802 if (n > 1) { 9803 if (gc->joinStyle == JoinMiter) 9804 extra = 6 * gc->lineWidth; 9805 else if (gc->capStyle == CapProjecting) 9806 extra = gc->lineWidth; 9807 } 9808 if (extra) { 9809 box.x1 -= extra; 9810 box.x2 += extra; 9811 box.y1 -= extra; 9812 box.y2 += extra; 9813 } 9814 } 9815 9816 clip = trim_and_translate_box(&box, drawable, gc); 9817 if (box_empty(&box)) 9818 return 0; 9819 9820 *out = box; 9821 return 1 | blt << 2 | clip << 1; 9822} 9823 9824inline static int 9825_use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9826{ 9827 uint32_t ignored; 9828 9829 if (USE_SPANS) 9830 return USE_SPANS > 0; 9831 9832 if (flags & RECTILINEAR) 9833 return PREFER_GPU; 9834 9835 if (gc->lineStyle != LineSolid && gc->lineWidth == 0) 9836 return 0; 9837 9838 if (gc_is_solid(gc, &ignored)) 9839 return PREFER_GPU; 9840 9841 return !drawable_gc_inplace_hint(drawable, gc); 9842} 9843 9844inline static int 9845use_line_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 9846{ 9847 int ret = _use_line_spans(drawable, gc, extents, flags); 9848 DBG(("%s? %d\n", __FUNCTION__, ret)); 9849 return ret; 9850} 9851 9852static void 9853sna_poly_line(DrawablePtr drawable, GCPtr gc, 9854 int mode, int n, DDXPointPtr pt) 9855{ 9856 struct sna_pixmap *priv; 9857 struct sna_fill_spans data; 9858 uint32_t color; 9859 9860 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n", 9861 __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth)); 9862 9863 data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt, 9864 &data.region.extents); 9865 if (data.flags == 0) 9866 return; 9867 9868 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9869 data.region.extents.x1, data.region.extents.y1, 9870 data.region.extents.x2, data.region.extents.y2, 9871 data.flags)); 9872 9873 data.region.data = NULL; 9874 9875 if (FORCE_FALLBACK) 9876 goto fallback; 9877 9878 if (!ACCEL_POLY_LINE) 9879 goto fallback; 9880 9881 data.pixmap = get_drawable_pixmap(drawable); 9882 data.sna = to_sna_from_pixmap(data.pixmap); 9883 if (wedged(data.sna)) { 9884 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9885 goto fallback; 9886 } 9887 9888 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lx [%d], rectlinear=%d\n", 9889 __FUNCTION__, 9890 gc->fillStyle, gc->fillStyle == FillSolid, 9891 gc->lineStyle, gc->lineStyle == LineSolid, 9892 gc->lineWidth, 9893 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 9894 data.flags & RECTILINEAR)); 9895 9896 if (!PM_IS_SOLID(drawable, gc->planemask)) 9897 goto fallback; 9898 9899 priv = sna_pixmap(data.pixmap); 9900 if (!priv) { 9901 DBG(("%s: not attached to pixmap %ld\n", 9902 __FUNCTION__, data.pixmap->drawable.serialNumber)); 9903 goto fallback; 9904 } 9905 9906 if (gc->lineStyle != LineSolid) { 9907 DBG(("%s: lineStyle, %d, is not solid\n", 9908 __FUNCTION__, gc->lineStyle)); 9909 goto spans_fallback; 9910 } 9911 if (!(gc->lineWidth == 0 || 9912 (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) { 9913 DBG(("%s: non-zero lineWidth %d\n", 9914 __FUNCTION__, gc->lineWidth)); 9915 goto spans_fallback; 9916 } 9917 9918 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9919 &data.region.extents, 9920 &data.damage); 9921 if (data.bo == NULL) 9922 goto fallback; 9923 9924 if (gc_is_solid(gc, &color)) { 9925 DBG(("%s: trying solid fill [%08x]\n", 9926 __FUNCTION__, (unsigned)color)); 9927 if (data.flags & RECTILINEAR) { 9928 if (sna_poly_line_blt(drawable, 9929 data.bo, data.damage, 9930 gc, color, mode, n, pt, 9931 &data.region.extents, 9932 data.flags & IS_CLIPPED)) 9933 return; 9934 } else { /* !rectilinear */ 9935 if (sna_poly_zero_line_blt(drawable, 9936 data.bo, data.damage, 9937 gc, mode, n, pt, 9938 &data.region.extents, 9939 data.flags & IS_CLIPPED)) 9940 return; 9941 9942 } 9943 } else if (data.flags & RECTILINEAR) { 9944 /* Try converting these to a set of rectangles instead */ 9945 DDXPointRec p1, p2; 9946 xRectangle *rect; 9947 int i; 9948 9949 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 9950 9951 rect = malloc (n * sizeof (xRectangle)); 9952 if (rect == NULL) 9953 return; 9954 9955 p1 = pt[0]; 9956 for (i = 1; i < n; i++) { 9957 if (mode == CoordModePrevious) { 9958 p2.x = p1.x + pt[i].x; 9959 p2.y = p1.y + pt[i].y; 9960 } else 9961 p2 = pt[i]; 9962 if (p1.x < p2.x) { 9963 rect[i].x = p1.x; 9964 rect[i].width = p2.x - p1.x + 1; 9965 } else if (p1.x > p2.x) { 9966 rect[i].x = p2.x; 9967 rect[i].width = p1.x - p2.x + 1; 9968 } else { 9969 rect[i].x = p1.x; 9970 rect[i].width = 1; 9971 } 9972 if (p1.y < p2.y) { 9973 rect[i].y = p1.y; 9974 rect[i].height = p2.y - p1.y + 1; 9975 } else if (p1.y > p2.y) { 9976 rect[i].y = p2.y; 9977 rect[i].height = p1.y - p2.y + 1; 9978 } else { 9979 rect[i].y = p1.y; 9980 rect[i].height = 1; 9981 } 9982 9983 /* don't paint last pixel */ 9984 if (gc->capStyle == CapNotLast) { 9985 if (p1.x == p2.x) 9986 rect[i].height--; 9987 else 9988 rect[i].width--; 9989 } 9990 p1 = p2; 9991 } 9992 9993 if (gc->fillStyle == FillTiled) { 9994 i = sna_poly_fill_rect_tiled_blt(drawable, 9995 data.bo, data.damage, 9996 gc, n - 1, rect + 1, 9997 &data.region.extents, 9998 data.flags & IS_CLIPPED); 9999 } else { 10000 i = sna_poly_fill_rect_stippled_blt(drawable, 10001 data.bo, data.damage, 10002 gc, n - 1, rect + 1, 10003 &data.region.extents, 10004 data.flags & IS_CLIPPED); 10005 } 10006 free (rect); 10007 10008 if (i) 10009 return; 10010 } 10011 10012spans_fallback: 10013 if ((data.bo = sna_drawable_use_bo(drawable, 10014 use_line_spans(drawable, gc, &data.region.extents, data.flags), 10015 &data.region.extents, &data.damage))) { 10016 DBG(("%s: converting line into spans\n", __FUNCTION__)); 10017 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10018 sna_gc(gc)->priv = &data; 10019 10020 if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) { 10021 struct sna_fill_op fill; 10022 10023 if (gc->lineStyle == LineSolid) { 10024 if (!sna_fill_init_blt(&fill, 10025 data.sna, data.pixmap, 10026 data.bo, gc->alu, color, 10027 FILL_POINTS | FILL_SPANS)) 10028 goto fallback; 10029 10030 data.op = &fill; 10031 10032 if ((data.flags & IS_CLIPPED) == 0) { 10033 if (data.dx | data.dy) 10034 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10035 else 10036 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10037 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10038 } else { 10039 if (!region_maybe_clip(&data.region, 10040 gc->pCompositeClip)) 10041 return; 10042 10043 if (region_is_singular(&data.region)) { 10044 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10045 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10046 } else { 10047 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10048 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10049 } 10050 } 10051 assert(gc->miTranslate); 10052 10053 gc->ops = &sna_gc_ops__tmp; 10054 DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__)); 10055 miZeroLine(drawable, gc, mode, n, pt); 10056 fill.done(data.sna, &fill); 10057 } else { 10058 data.op = &fill; 10059 10060 if ((data.flags & IS_CLIPPED) == 0) { 10061 if (data.dx | data.dy) 10062 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset; 10063 else 10064 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash; 10065 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash; 10066 } else { 10067 if (!region_maybe_clip(&data.region, 10068 gc->pCompositeClip)) 10069 return; 10070 10071 if (region_is_singular(&data.region)) { 10072 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents; 10073 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents; 10074 } else { 10075 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes; 10076 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes; 10077 } 10078 } 10079 assert(gc->miTranslate); 10080 10081 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), fg pass [%08x]\n", 10082 __FUNCTION__, 10083 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 10084 gc->fgPixel)); 10085 10086 if (!sna_fill_init_blt(&fill, 10087 data.sna, data.pixmap, 10088 data.bo, gc->alu, color, 10089 FILL_POINTS | FILL_SPANS)) 10090 goto fallback; 10091 10092 gc->ops = &sna_gc_ops__tmp; 10093 data.phase = gc->fgPixel; 10094 miZeroDashLine(drawable, gc, mode, n, pt); 10095 fill.done(data.sna, &fill); 10096 10097 DBG(("%s: miZeroLine (solid dash, clipped? %d (complex? %d)), bg pass [%08x]\n", 10098 __FUNCTION__, 10099 !!(data.flags & IS_CLIPPED), data.flags & IS_CLIPPED && !region_is_singular(&data.region), 10100 gc->bgPixel)); 10101 10102 if (sna_fill_init_blt(&fill, 10103 data.sna, data.pixmap, 10104 data.bo, gc->alu, 10105 gc->bgPixel, 10106 FILL_POINTS | FILL_SPANS)) { 10107 data.phase = gc->bgPixel; 10108 miZeroDashLine(drawable, gc, mode, n, pt); 10109 fill.done(data.sna, &fill); 10110 } 10111 } 10112 } else { 10113 /* Note that the WideDash functions alternate 10114 * between filling using fgPixel and bgPixel 10115 * so we need to reset state between FillSpans and 10116 * cannot use the fill fast paths. 10117 */ 10118 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10119 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 10120 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 10121 gc->ops = &sna_gc_ops__tmp; 10122 10123 switch (gc->lineStyle) { 10124 default: 10125 assert(0); 10126 case LineSolid: 10127 if (gc->lineWidth == 0) { 10128 DBG(("%s: miZeroLine\n", __FUNCTION__)); 10129 miZeroLine(drawable, gc, mode, n, pt); 10130 } else { 10131 DBG(("%s: miWideLine\n", __FUNCTION__)); 10132 miWideLine(drawable, gc, mode, n, pt); 10133 } 10134 break; 10135 case LineOnOffDash: 10136 case LineDoubleDash: 10137 if (gc->lineWidth == 0) { 10138 DBG(("%s: miZeroDashLine\n", __FUNCTION__)); 10139 miZeroDashLine(drawable, gc, mode, n, pt); 10140 } else { 10141 DBG(("%s: miWideDash\n", __FUNCTION__)); 10142 miWideDash(drawable, gc, mode, n, pt); 10143 } 10144 break; 10145 } 10146 } 10147 10148 gc->ops = (GCOps *)&sna_gc_ops; 10149 if (data.damage) { 10150 if (data.dx | data.dy) 10151 pixman_region_translate(&data.region, data.dx, data.dy); 10152 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10153 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 10154 assert_pixmap_damage(data.pixmap); 10155 } 10156 RegionUninit(&data.region); 10157 return; 10158 } 10159 10160fallback: 10161 DBG(("%s: fallback\n", __FUNCTION__)); 10162 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 10163 return; 10164 10165 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10166 goto out; 10167 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10168 drawable_gc_flags(drawable, gc, 10169 !(data.flags & RECTILINEAR && n == 2)))) 10170 goto out; 10171 10172 if (sigtrap_get() == 0) { 10173 DBG(("%s: fbPolyLine\n", __FUNCTION__)); 10174 fbPolyLine(drawable, gc, mode, n, pt); 10175 FALLBACK_FLUSH(drawable); 10176 sigtrap_put(); 10177 } 10178out: 10179 sna_gc_move_to_gpu(gc); 10180 RegionUninit(&data.region); 10181} 10182 10183static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc) 10184{ 10185 if (seg->x1 == seg->x2) { 10186 if (seg->y1 > seg->y2) { 10187 b->y2 = seg->y1 + 1; 10188 b->y1 = seg->y2 + 1; 10189 if (gc->capStyle != CapNotLast) 10190 b->y1--; 10191 } else { 10192 b->y1 = seg->y1; 10193 b->y2 = seg->y2; 10194 if (gc->capStyle != CapNotLast) 10195 b->y2++; 10196 } 10197 if (b->y1 >= b->y2) 10198 return false; 10199 10200 b->x1 = seg->x1; 10201 b->x2 = seg->x1 + 1; 10202 } else { 10203 if (seg->x1 > seg->x2) { 10204 b->x2 = seg->x1 + 1; 10205 b->x1 = seg->x2 + 1; 10206 if (gc->capStyle != CapNotLast) 10207 b->x1--; 10208 } else { 10209 b->x1 = seg->x1; 10210 b->x2 = seg->x2; 10211 if (gc->capStyle != CapNotLast) 10212 b->x2++; 10213 } 10214 if (b->x1 >= b->x2) 10215 return false; 10216 10217 b->y1 = seg->y1; 10218 b->y2 = seg->y1 + 1; 10219 } 10220 10221 DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n", 10222 __FUNCTION__, 10223 seg->x1, seg->y1, seg->x2, seg->y2, 10224 b->x1, b->y1, b->x2, b->y2)); 10225 return true; 10226} 10227 10228static bool 10229sna_poly_segment_blt(DrawablePtr drawable, 10230 struct kgem_bo *bo, 10231 struct sna_damage **damage, 10232 GCPtr gc, uint32_t pixel, 10233 int n, xSegment *seg, 10234 const BoxRec *extents, unsigned clipped) 10235{ 10236 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10237 struct sna *sna = to_sna_from_pixmap(pixmap); 10238 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 10239 struct sna_fill_op fill; 10240 int16_t dx, dy; 10241 10242 DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n", 10243 __FUNCTION__, n, gc->alu, gc->fgPixel, clipped)); 10244 10245 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_SPANS)) 10246 return false; 10247 10248 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10249 10250 if (!clipped) { 10251 dx += drawable->x; 10252 dy += drawable->y; 10253 if (dx|dy) { 10254 do { 10255 unsigned nbox = n; 10256 if (nbox > ARRAY_SIZE(boxes)) 10257 nbox = ARRAY_SIZE(boxes); 10258 n -= nbox; 10259 do { 10260 if (box_from_seg(b, seg++, gc)) { 10261 assert(!box_empty(b)); 10262 b->x1 += dx; 10263 b->x2 += dx; 10264 b->y1 += dy; 10265 b->y2 += dy; 10266 assert(!box_empty(b)); 10267 b++; 10268 } 10269 } while (--nbox); 10270 10271 if (b != boxes) { 10272 fill.boxes(sna, &fill, boxes, b-boxes); 10273 if (damage) 10274 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10275 b = boxes; 10276 } 10277 } while (n); 10278 } else { 10279 do { 10280 unsigned nbox = n; 10281 if (nbox > ARRAY_SIZE(boxes)) 10282 nbox = ARRAY_SIZE(boxes); 10283 n -= nbox; 10284 do { 10285 if (box_from_seg(b, seg++, gc)) { 10286 assert(!box_empty(b)); 10287 b++; 10288 } 10289 } while (--nbox); 10290 10291 if (b != boxes) { 10292 fill.boxes(sna, &fill, boxes, b-boxes); 10293 if (damage) 10294 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10295 b = boxes; 10296 } 10297 } while (n); 10298 } 10299 } else { 10300 RegionRec clip; 10301 10302 region_set(&clip, extents); 10303 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10304 goto done; 10305 10306 if (clip.data) { 10307 const BoxRec * const clip_start = RegionBoxptr(&clip); 10308 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10309 const BoxRec *c; 10310 do { 10311 BoxRec box; 10312 10313 if (!box_from_seg(&box, seg++, gc)) 10314 continue; 10315 10316 assert(!box_empty(&box)); 10317 box.x1 += drawable->x; 10318 box.x2 += drawable->x; 10319 box.y1 += drawable->y; 10320 box.y2 += drawable->y; 10321 c = find_clip_box_for_y(clip_start, 10322 clip_end, 10323 box.y1); 10324 while (c != clip_end) { 10325 if (box.y2 <= c->y1) 10326 break; 10327 10328 *b = box; 10329 if (box_intersect(b, c++)) { 10330 b->x1 += dx; 10331 b->x2 += dx; 10332 b->y1 += dy; 10333 b->y2 += dy; 10334 assert(!box_empty(b)); 10335 if (++b == last_box) { 10336 fill.boxes(sna, &fill, boxes, last_box-boxes); 10337 if (damage) 10338 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10339 b = boxes; 10340 } 10341 } 10342 } 10343 } while (--n); 10344 } else { 10345 do { 10346 if (!box_from_seg(b, seg++, gc)) 10347 continue; 10348 10349 assert(!box_empty(b)); 10350 b->x1 += drawable->x; 10351 b->x2 += drawable->x; 10352 b->y1 += drawable->y; 10353 b->y2 += drawable->y; 10354 if (box_intersect(b, &clip.extents)) { 10355 b->x1 += dx; 10356 b->x2 += dx; 10357 b->y1 += dy; 10358 b->y2 += dy; 10359 assert(!box_empty(b)); 10360 if (++b == last_box) { 10361 fill.boxes(sna, &fill, boxes, last_box-boxes); 10362 if (damage) 10363 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10364 b = boxes; 10365 } 10366 } 10367 } while (--n); 10368 } 10369 RegionUninit(&clip); 10370 } 10371 if (b != boxes) { 10372 fill.boxes(sna, &fill, boxes, b - boxes); 10373 if (damage) 10374 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 10375 } 10376done: 10377 fill.done(sna, &fill); 10378 assert_pixmap_damage(pixmap); 10379 return true; 10380} 10381 10382static bool 10383sna_poly_zero_segment_blt(DrawablePtr drawable, 10384 struct kgem_bo *bo, 10385 struct sna_damage **damage, 10386 GCPtr gc, const int _n, const xSegment *_s, 10387 const BoxRec *extents, unsigned clipped) 10388{ 10389 static void * const _jump[] = { 10390 &&no_damage, 10391 &&damage, 10392 10393 &&no_damage_offset, 10394 &&damage_offset, 10395 }; 10396 10397 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10398 struct sna *sna = to_sna_from_pixmap(pixmap); 10399 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 10400 struct sna_fill_op fill; 10401 RegionRec clip; 10402 const BoxRec *last_extents; 10403 BoxRec box[512], *b; 10404 BoxRec *const last_box = box + ARRAY_SIZE(box); 10405 int16_t dx, dy; 10406 void *jump, *ret; 10407 10408 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 10409 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 10410 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 10411 return false; 10412 10413 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10414 10415 region_set(&clip, extents); 10416 if (clipped) { 10417 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 10418 return true; 10419 } 10420 DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n", 10421 __FUNCTION__, 10422 clip.extents.x1, clip.extents.y1, 10423 clip.extents.x2, clip.extents.y2, 10424 dx, dy)); 10425 10426 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 10427 10428 b = box; 10429 extents = region_rects(&clip); 10430 last_extents = extents + region_num_rects(&clip); 10431 do { 10432 int n = _n; 10433 const xSegment *s = _s; 10434 do { 10435 int16_t sdx, sdy; 10436 int adx, ady, length; 10437 int e, e1, e2, e3; 10438 int x1, x2; 10439 int y1, y2; 10440 int oc1, oc2; 10441 int octant; 10442 10443 x1 = s->x1 + drawable->x; 10444 y1 = s->y1 + drawable->y; 10445 x2 = s->x2 + drawable->x; 10446 y2 = s->y2 + drawable->y; 10447 s++; 10448 10449 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 10450 __FUNCTION__, x1, y1, x2, y2)); 10451 if (x2 == x1 && y2 == y1) 10452 continue; 10453 10454 oc1 = 0; 10455 OUTCODES(oc1, x1, y1, extents); 10456 oc2 = 0; 10457 OUTCODES(oc2, x2, y2, extents); 10458 if (oc1 & oc2) 10459 continue; 10460 10461 CalcLineDeltas(x1, y1, x2, y2, 10462 adx, ady, sdx, sdy, 10463 1, 1, octant); 10464 10465 DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n", 10466 __FUNCTION__, adx, ady, sdx, sdy)); 10467 if (adx == 0 || ady == 0) { 10468 if (x1 <= x2) { 10469 b->x1 = x1; 10470 b->x2 = x2; 10471 } else { 10472 b->x1 = x2; 10473 b->x2 = x1; 10474 } 10475 if (y1 <= y2) { 10476 b->y1 = y1; 10477 b->y2 = y2; 10478 } else { 10479 b->y1 = y2; 10480 b->y2 = y1; 10481 } 10482 b->x2++; 10483 b->y2++; 10484 10485 if ((oc1 | oc2) && !box_intersect(b, extents)) 10486 continue; 10487 10488 assert(!box_empty(b)); 10489 if (++b == last_box) { 10490 ret = &&rectangle_continue; 10491 goto *jump; 10492rectangle_continue: 10493 b = box; 10494 } 10495 } else if (adx >= ady) { 10496 bool dirty; 10497 10498 /* X-major segment */ 10499 e1 = ady << 1; 10500 e2 = e1 - (adx << 1); 10501 e = e1 - adx; 10502 length = adx; /* don't draw endpoint in main loop */ 10503 10504 FIXUP_ERROR(e, octant, bias); 10505 10506 if (oc1 | oc2) { 10507 int pt1_clipped, pt2_clipped; 10508 int x = x1, y = y1; 10509 10510 if (miZeroClipLine(extents->x1, extents->y1, 10511 extents->x2-1, extents->y2-1, 10512 &x1, &y1, &x2, &y2, 10513 adx, ady, 10514 &pt1_clipped, &pt2_clipped, 10515 octant, bias, oc1, oc2) == -1) 10516 continue; 10517 10518 length = abs(x2 - x1); 10519 if (length == 0) 10520 continue; 10521 10522 if (pt1_clipped) { 10523 int clipdx = abs(x1 - x); 10524 int clipdy = abs(y1 - y); 10525 e += clipdy * e2 + (clipdx - clipdy) * e1; 10526 } 10527 } 10528 e3 = e2 - e1; 10529 e = e - e1; 10530 10531 b->x1 = x1; 10532 b->y1 = y1; 10533 dirty = false; 10534 while (length--) { 10535 dirty = true; 10536 e += e1; 10537 if (e >= 0) { 10538 e += e3; 10539 10540 if (sdx < 0) { 10541 b->x2 = b->x1 + 1; 10542 b->x1 = x1; 10543 } else 10544 b->x2 = x1 + 1; 10545 b->y2 = b->y1 + 1; 10546 10547 DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n", 10548 __FUNCTION__, x1, y1, 10549 b->x1, b->y1, b->x2, b->y2)); 10550 10551 assert(!box_empty(b)); 10552 if (++b == last_box) { 10553 ret = &&X_continue; 10554 goto *jump; 10555X_continue: 10556 b = box; 10557 } 10558 10559 b->x1 = x1 + sdx; 10560 b->y1 = y1 += sdy; 10561 dirty = false; 10562 } 10563 x1 += sdx; 10564 } 10565 if (dirty) { 10566 x1 -= sdx; 10567 DBG(("%s: horizontal tail: (%d, %d)\n", 10568 __FUNCTION__, x1, y1)); 10569 if (sdx < 0) { 10570 b->x2 = b->x1 + 1; 10571 b->x1 = x1; 10572 } else 10573 b->x2 = x1 + 1; 10574 b->y2 = b->y1 + 1; 10575 10576 assert(!box_empty(b)); 10577 if (++b == last_box) { 10578 ret = &&X2_continue; 10579 goto *jump; 10580X2_continue: 10581 b = box; 10582 } 10583 } 10584 } else { 10585 bool dirty; 10586 10587 /* Y-major segment */ 10588 e1 = adx << 1; 10589 e2 = e1 - (ady << 1); 10590 e = e1 - ady; 10591 length = ady; /* don't draw endpoint in main loop */ 10592 10593 SetYMajorOctant(octant); 10594 FIXUP_ERROR(e, octant, bias); 10595 10596 if (oc1 | oc2) { 10597 int pt1_clipped, pt2_clipped; 10598 int x = x1, y = y1; 10599 10600 if (miZeroClipLine(extents->x1, extents->y1, 10601 extents->x2-1, extents->y2-1, 10602 &x1, &y1, &x2, &y2, 10603 adx, ady, 10604 &pt1_clipped, &pt2_clipped, 10605 octant, bias, oc1, oc2) == -1) 10606 continue; 10607 10608 length = abs(y2 - y1); 10609 if (length == 0) 10610 continue; 10611 10612 if (pt1_clipped) { 10613 int clipdx = abs(x1 - x); 10614 int clipdy = abs(y1 - y); 10615 e += clipdx * e2 + (clipdy - clipdx) * e1; 10616 } 10617 } 10618 10619 e3 = e2 - e1; 10620 e = e - e1; 10621 10622 b->x1 = x1; 10623 b->y1 = y1; 10624 dirty = false; 10625 while (length--) { 10626 e += e1; 10627 dirty = true; 10628 if (e >= 0) { 10629 e += e3; 10630 10631 if (sdy < 0) { 10632 b->y2 = b->y1 + 1; 10633 b->y1 = y1; 10634 } else 10635 b->y2 = y1 + 1; 10636 b->x2 = x1 + 1; 10637 10638 assert(!box_empty(b)); 10639 if (++b == last_box) { 10640 ret = &&Y_continue; 10641 goto *jump; 10642Y_continue: 10643 b = box; 10644 } 10645 10646 b->x1 = x1 += sdx; 10647 b->y1 = y1 + sdy; 10648 dirty = false; 10649 } 10650 y1 += sdy; 10651 } 10652 10653 if (dirty) { 10654 y1 -= sdy; 10655 if (sdy < 0) { 10656 b->y2 = b->y1 + 1; 10657 b->y1 = y1; 10658 } else 10659 b->y2 = y1 + 1; 10660 b->x2 = x1 + 1; 10661 10662 assert(!box_empty(b)); 10663 if (++b == last_box) { 10664 ret = &&Y2_continue; 10665 goto *jump; 10666Y2_continue: 10667 b = box; 10668 } 10669 } 10670 } 10671 } while (--n); 10672 } while (++extents != last_extents); 10673 10674 if (b != box) { 10675 ret = &&done; 10676 goto *jump; 10677 } 10678 10679done: 10680 fill.done(sna, &fill); 10681 assert_pixmap_damage(pixmap); 10682 RegionUninit(&clip); 10683 return true; 10684 10685damage: 10686 sna_damage_add_boxes(damage, box, b-box, 0, 0); 10687no_damage: 10688 fill.boxes(sna, &fill, box, b-box); 10689 goto *ret; 10690 10691no_damage_offset: 10692 { 10693 BoxRec *bb = box; 10694 do { 10695 bb->x1 += dx; 10696 bb->x2 += dx; 10697 bb->y1 += dy; 10698 bb->y2 += dy; 10699 } while (++bb != b); 10700 fill.boxes(sna, &fill, box, b - box); 10701 } 10702 goto *ret; 10703 10704damage_offset: 10705 { 10706 BoxRec *bb = box; 10707 do { 10708 bb->x1 += dx; 10709 bb->x2 += dx; 10710 bb->y1 += dy; 10711 bb->y2 += dy; 10712 } while (++bb != b); 10713 fill.boxes(sna, &fill, box, b - box); 10714 sna_damage_add_boxes(damage, box, b - box, 0, 0); 10715 } 10716 goto *ret; 10717} 10718 10719static unsigned 10720sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc, 10721 int n, xSegment *seg, 10722 BoxPtr out) 10723{ 10724 BoxRec box; 10725 bool clipped, can_blit; 10726 10727 if (n == 0) 10728 return 0; 10729 10730 if (seg->x2 >= seg->x1) { 10731 box.x1 = seg->x1; 10732 box.x2 = seg->x2; 10733 } else { 10734 box.x2 = seg->x1; 10735 box.x1 = seg->x2; 10736 } 10737 10738 if (seg->y2 >= seg->y1) { 10739 box.y1 = seg->y1; 10740 box.y2 = seg->y2; 10741 } else { 10742 box.y2 = seg->y1; 10743 box.y1 = seg->y2; 10744 } 10745 10746 can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2; 10747 while (--n) { 10748 seg++; 10749 if (seg->x2 > seg->x1) { 10750 if (seg->x1 < box.x1) box.x1 = seg->x1; 10751 if (seg->x2 > box.x2) box.x2 = seg->x2; 10752 } else { 10753 if (seg->x2 < box.x1) box.x1 = seg->x2; 10754 if (seg->x1 > box.x2) box.x2 = seg->x1; 10755 } 10756 10757 if (seg->y2 > seg->y1) { 10758 if (seg->y1 < box.y1) box.y1 = seg->y1; 10759 if (seg->y2 > box.y2) box.y2 = seg->y2; 10760 } else { 10761 if (seg->y2 < box.y1) box.y1 = seg->y2; 10762 if (seg->y1 > box.y2) box.y2 = seg->y1; 10763 } 10764 10765 if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2)) 10766 can_blit = false; 10767 } 10768 10769 box.x2++; 10770 box.y2++; 10771 10772 if (gc->lineWidth) { 10773 int extra = gc->lineWidth; 10774 if (gc->capStyle != CapProjecting) 10775 extra >>= 1; 10776 if (extra) { 10777 box.x1 -= extra; 10778 box.x2 += extra; 10779 box.y1 -= extra; 10780 box.y2 += extra; 10781 } 10782 } 10783 10784 DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n", 10785 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 10786 10787 clipped = trim_and_translate_box(&box, drawable, gc); 10788 if (box_empty(&box)) 10789 return 0; 10790 10791 *out = box; 10792 return 1 | clipped << 1 | can_blit << 2; 10793} 10794 10795static void 10796sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg) 10797{ 10798 struct sna_pixmap *priv; 10799 struct sna_fill_spans data; 10800 uint32_t color; 10801 10802 DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n", 10803 __FUNCTION__, 10804 n, seg->x1, seg->y1, seg->x2, seg->y2, 10805 gc->lineWidth)); 10806 10807 data.flags = sna_poly_segment_extents(drawable, gc, n, seg, 10808 &data.region.extents); 10809 if (data.flags == 0) 10810 return; 10811 10812 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 10813 data.region.extents.x1, data.region.extents.y1, 10814 data.region.extents.x2, data.region.extents.y2)); 10815 10816 data.region.data = NULL; 10817 10818 if (FORCE_FALLBACK) 10819 goto fallback; 10820 10821 if (!ACCEL_POLY_SEGMENT) 10822 goto fallback; 10823 10824 data.pixmap = get_drawable_pixmap(drawable); 10825 data.sna = to_sna_from_pixmap(data.pixmap); 10826 priv = sna_pixmap(data.pixmap); 10827 if (priv == NULL) { 10828 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10829 goto fallback; 10830 } 10831 10832 if (wedged(data.sna)) { 10833 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10834 goto fallback; 10835 } 10836 10837 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 10838 __FUNCTION__, 10839 gc->fillStyle, gc->fillStyle == FillSolid, 10840 gc->lineStyle, gc->lineStyle == LineSolid, 10841 gc->lineWidth, 10842 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 10843 data.flags & RECTILINEAR)); 10844 if (!PM_IS_SOLID(drawable, gc->planemask)) 10845 goto fallback; 10846 10847 if (gc->lineStyle != LineSolid || gc->lineWidth > 1) 10848 goto spans_fallback; 10849 10850 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 10851 &data.region.extents, 10852 &data.damage); 10853 if (data.bo == NULL) 10854 goto fallback; 10855 10856 if (gc_is_solid(gc, &color)) { 10857 DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n", 10858 __FUNCTION__, (unsigned)color, data.flags)); 10859 10860 if (data.flags & RECTILINEAR) { 10861 if (sna_poly_segment_blt(drawable, 10862 data.bo, data.damage, 10863 gc, color, n, seg, 10864 &data.region.extents, 10865 data.flags & IS_CLIPPED)) 10866 return; 10867 } else { 10868 if (sna_poly_zero_segment_blt(drawable, 10869 data.bo, data.damage, 10870 gc, n, seg, 10871 &data.region.extents, 10872 data.flags & IS_CLIPPED)) 10873 return; 10874 } 10875 } else if (data.flags & RECTILINEAR) { 10876 /* Try converting these to a set of rectangles instead */ 10877 xRectangle *rect; 10878 int i; 10879 10880 DBG(("%s: converting to rectangles\n", __FUNCTION__)); 10881 10882 rect = malloc (n * sizeof (xRectangle)); 10883 if (rect == NULL) 10884 return; 10885 10886 for (i = 0; i < n; i++) { 10887 if (seg[i].x1 < seg[i].x2) { 10888 rect[i].x = seg[i].x1; 10889 rect[i].width = seg[i].x2 - seg[i].x1 + 1; 10890 } else if (seg[i].x1 > seg[i].x2) { 10891 rect[i].x = seg[i].x2; 10892 rect[i].width = seg[i].x1 - seg[i].x2 + 1; 10893 } else { 10894 rect[i].x = seg[i].x1; 10895 rect[i].width = 1; 10896 } 10897 if (seg[i].y1 < seg[i].y2) { 10898 rect[i].y = seg[i].y1; 10899 rect[i].height = seg[i].y2 - seg[i].y1 + 1; 10900 } else if (seg[i].y1 > seg[i].y2) { 10901 rect[i].y = seg[i].y2; 10902 rect[i].height = seg[i].y1 - seg[i].y2 + 1; 10903 } else { 10904 rect[i].y = seg[i].y1; 10905 rect[i].height = 1; 10906 } 10907 10908 /* don't paint last pixel */ 10909 if (gc->capStyle == CapNotLast) { 10910 if (seg[i].x1 == seg[i].x2) 10911 rect[i].height--; 10912 else 10913 rect[i].width--; 10914 } 10915 } 10916 10917 if (gc->fillStyle == FillTiled) { 10918 i = sna_poly_fill_rect_tiled_blt(drawable, 10919 data.bo, data.damage, 10920 gc, n, rect, 10921 &data.region.extents, 10922 data.flags); 10923 } else { 10924 i = sna_poly_fill_rect_stippled_blt(drawable, 10925 data.bo, data.damage, 10926 gc, n, rect, 10927 &data.region.extents, 10928 data.flags); 10929 } 10930 free (rect); 10931 10932 if (i) 10933 return; 10934 } 10935 10936spans_fallback: 10937 if ((data.bo = sna_drawable_use_bo(drawable, 10938 use_line_spans(drawable, gc, &data.region.extents, data.flags), 10939 &data.region.extents, 10940 &data.damage))) { 10941 void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr); 10942 int i; 10943 10944 DBG(("%s: converting segments into spans\n", __FUNCTION__)); 10945 10946 switch (gc->lineStyle) { 10947 default: 10948 case LineSolid: 10949 if (gc->lineWidth == 0) 10950 line = miZeroLine; 10951 else 10952 line = miWideLine; 10953 break; 10954 case LineOnOffDash: 10955 case LineDoubleDash: 10956 if (gc->lineWidth == 0) 10957 line = miZeroDashLine; 10958 else 10959 line = miWideDash; 10960 break; 10961 } 10962 10963 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10964 sna_gc(gc)->priv = &data; 10965 10966 if (gc->lineWidth == 0 && 10967 gc->lineStyle == LineSolid && 10968 gc_is_solid(gc, &color)) { 10969 struct sna_fill_op fill; 10970 10971 if (!sna_fill_init_blt(&fill, 10972 data.sna, data.pixmap, 10973 data.bo, gc->alu, color, 10974 FILL_POINTS | FILL_SPANS)) 10975 goto fallback; 10976 10977 data.op = &fill; 10978 10979 if ((data.flags & IS_CLIPPED) == 0) { 10980 if (data.dx | data.dy) 10981 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10982 else 10983 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10984 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10985 } else { 10986 if (!region_maybe_clip(&data.region, 10987 gc->pCompositeClip)) 10988 return; 10989 10990 if (region_is_singular(&data.region)) { 10991 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10992 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10993 } else { 10994 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10995 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10996 } 10997 } 10998 assert(gc->miTranslate); 10999 gc->ops = &sna_gc_ops__tmp; 11000 for (i = 0; i < n; i++) 11001 line(drawable, gc, CoordModeOrigin, 2, 11002 (DDXPointPtr)&seg[i]); 11003 11004 fill.done(data.sna, &fill); 11005 } else { 11006 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11007 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 11008 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11009 gc->ops = &sna_gc_ops__tmp; 11010 11011 for (i = 0; i < n; i++) 11012 line(drawable, gc, CoordModeOrigin, 2, 11013 (DDXPointPtr)&seg[i]); 11014 } 11015 11016 gc->ops = (GCOps *)&sna_gc_ops; 11017 if (data.damage) { 11018 if (data.dx | data.dy) 11019 pixman_region_translate(&data.region, data.dx, data.dy); 11020 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11021 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 11022 } 11023 assert_pixmap_damage(data.pixmap); 11024 RegionUninit(&data.region); 11025 return; 11026 } 11027 11028fallback: 11029 DBG(("%s: fallback\n", __FUNCTION__)); 11030 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11031 return; 11032 11033 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11034 goto out; 11035 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11036 drawable_gc_flags(drawable, gc, 11037 !(data.flags & RECTILINEAR && n == 1)))) 11038 goto out; 11039 11040 if (sigtrap_get() == 0) { 11041 DBG(("%s: fbPolySegment\n", __FUNCTION__)); 11042 fbPolySegment(drawable, gc, n, seg); 11043 FALLBACK_FLUSH(drawable); 11044 sigtrap_put(); 11045 } 11046out: 11047 sna_gc_move_to_gpu(gc); 11048 RegionUninit(&data.region); 11049} 11050 11051static unsigned 11052sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, 11053 int n, xRectangle *r, 11054 BoxPtr out) 11055{ 11056 Box32Rec box; 11057 int extra = gc->lineWidth >> 1; 11058 bool clipped; 11059 bool zero = false; 11060 11061 if (n == 0) 11062 return 0; 11063 11064 box.x1 = r->x; 11065 box.y1 = r->y; 11066 box.x2 = box.x1 + r->width; 11067 box.y2 = box.y1 + r->height; 11068 zero |= (r->width | r->height) == 0; 11069 11070 while (--n) { 11071 r++; 11072 zero |= (r->width | r->height) == 0; 11073 box32_add_rect(&box, r); 11074 } 11075 11076 box.x2++; 11077 box.y2++; 11078 11079 if (extra) { 11080 box.x1 -= extra; 11081 box.x2 += extra; 11082 box.y1 -= extra; 11083 box.y2 += extra; 11084 zero = !zero; 11085 } else 11086 zero = true; 11087 11088 DBG(("%s: unclipped original extents: (%d, %d), (%d, %d)\n", 11089 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 11090 clipped = box32_trim_and_translate(&box, drawable, gc); 11091 if (!box32_to_box16(&box, out)) 11092 return 0; 11093 11094 DBG(("%s: extents: (%d, %d), (%d, %d), clipped? %d\n", 11095 __FUNCTION__, out->x1, out->y1, out->x2, out->y2, clipped)); 11096 return 1 | clipped << 1 | zero << 2; 11097} 11098 11099static bool 11100sna_poly_rectangle_blt(DrawablePtr drawable, 11101 struct kgem_bo *bo, 11102 struct sna_damage **damage, 11103 GCPtr gc, int n, xRectangle *r, 11104 const BoxRec *extents, unsigned clipped) 11105{ 11106 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11107 struct sna *sna = to_sna_from_pixmap(pixmap); 11108 struct sna_fill_op fill; 11109 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11110 int16_t dx, dy; 11111 static void * const jump[] = { 11112 &&wide, 11113 &&zero, 11114 &&wide_clipped, 11115 &&zero_clipped, 11116 }; 11117 11118 DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", 11119 __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); 11120 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel, FILL_BOXES)) 11121 return false; 11122 11123 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11124 11125 goto *jump[(gc->lineWidth <= 1) | clipped]; 11126 11127zero: 11128 dx += drawable->x; 11129 dy += drawable->y; 11130 11131 do { 11132 xRectangle rr = *r++; 11133 11134 if ((rr.width | rr.height) == 0) 11135 continue; /* XXX -> PolyLine */ 11136 11137 DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11138 n, rr.x, rr.y, rr.width, rr.height)); 11139 rr.x += dx; 11140 rr.y += dy; 11141 11142 if (b+4 > last_box) { 11143 fill.boxes(sna, &fill, boxes, b-boxes); 11144 if (damage) 11145 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11146 b = boxes; 11147 } 11148 11149 if (rr.width <= 1 || rr.height <= 1) { 11150 b->x1 = rr.x; 11151 b->y1 = rr.y; 11152 b->x2 = rr.x + rr.width + (rr.height != 0); 11153 b->y2 = rr.y + rr.height + (rr.width != 0); 11154 DBG(("%s: blt (%d, %d), (%d, %d)\n", 11155 __FUNCTION__, 11156 b->x1, b->y1, b->x2,b->y2)); 11157 b++; 11158 } else { 11159 b[0].x1 = rr.x; 11160 b[0].y1 = rr.y; 11161 b[0].x2 = rr.x + rr.width + 1; 11162 b[0].y2 = rr.y + 1; 11163 11164 b[1] = b[0]; 11165 b[1].y1 += rr.height; 11166 b[1].y2 += rr.height; 11167 11168 b[2].y1 = rr.y + 1; 11169 b[2].y2 = rr.y + rr.height; 11170 b[2].x1 = rr.x; 11171 b[2].x2 = rr.x + 1; 11172 11173 b[3] = b[2]; 11174 b[3].x1 += rr.width; 11175 b[3].x2 += rr.width; 11176 11177 b += 4; 11178 } 11179 } while (--n); 11180 goto done; 11181 11182zero_clipped: 11183 { 11184 RegionRec clip; 11185 BoxRec box[4]; 11186 int count; 11187 11188 region_set(&clip, extents); 11189 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11190 goto done; 11191 11192 if (clip.data) { 11193 const BoxRec * const clip_start = RegionBoxptr(&clip); 11194 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11195 const BoxRec *c; 11196 do { 11197 xRectangle rr = *r++; 11198 11199 DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11200 n, rr.x, rr.y, rr.width, rr.height)); 11201 11202 if ((rr.width | rr.height) == 0) 11203 continue; /* XXX -> PolyLine */ 11204 11205 rr.x += drawable->x; 11206 rr.y += drawable->y; 11207 11208 if (rr.width <= 1 || rr.height <= 1) { 11209 box[0].x1 = rr.x; 11210 box[0].y1 = rr.y; 11211 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11212 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11213 count = 1; 11214 } else { 11215 box[0].x1 = rr.x; 11216 box[0].y1 = rr.y; 11217 box[0].x2 = rr.x + rr.width + 1; 11218 box[0].y2 = rr.y + 1; 11219 11220 box[1] = box[0]; 11221 box[1].y1 += rr.height; 11222 box[1].y2 += rr.height; 11223 11224 box[2].y1 = rr.y + 1; 11225 box[2].y2 = rr.y + rr.height; 11226 box[2].x1 = rr.x; 11227 box[2].x2 = rr.x + 1; 11228 11229 box[3] = box[2]; 11230 box[3].x1 += rr.width; 11231 box[3].x2 += rr.width; 11232 count = 4; 11233 } 11234 11235 while (count--) { 11236 c = find_clip_box_for_y(clip_start, 11237 clip_end, 11238 box[count].y1); 11239 while (c != clip_end) { 11240 if (box[count].y2 <= c->y1) 11241 break; 11242 11243 *b = box[count]; 11244 if (box_intersect(b, c++)) { 11245 b->x1 += dx; 11246 b->x2 += dx; 11247 b->y1 += dy; 11248 b->y2 += dy; 11249 if (++b == last_box) { 11250 fill.boxes(sna, &fill, boxes, last_box-boxes); 11251 if (damage) 11252 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11253 b = boxes; 11254 } 11255 } 11256 11257 } 11258 } 11259 } while (--n); 11260 } else { 11261 do { 11262 xRectangle rr = *r++; 11263 DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 11264 n, rr.x, rr.y, rr.width, rr.height)); 11265 11266 if ((rr.width | rr.height) == 0) 11267 continue; /* XXX -> PolyLine */ 11268 11269 rr.x += drawable->x; 11270 rr.y += drawable->y; 11271 11272 if (rr.width <= 1 || rr.height <= 1) { 11273 box[0].x1 = rr.x; 11274 box[0].y1 = rr.y; 11275 box[0].x2 = rr.x + rr.width + (rr.height != 0); 11276 box[0].y2 = rr.y + rr.height + (rr.width != 0); 11277 count = 1; 11278 } else { 11279 box[0].x1 = rr.x; 11280 box[0].y1 = rr.y; 11281 box[0].x2 = rr.x + rr.width + 1; 11282 box[0].y2 = rr.y + 1; 11283 11284 box[1] = box[0]; 11285 box[1].y1 += rr.height; 11286 box[1].y2 += rr.height; 11287 11288 box[2].y1 = rr.y + 1; 11289 box[2].y2 = rr.y + rr.height; 11290 box[2].x1 = rr.x; 11291 box[2].x2 = rr.x + 1; 11292 11293 box[3] = box[2]; 11294 box[3].x1 += rr.width; 11295 box[3].x2 += rr.width; 11296 count = 4; 11297 } 11298 11299 while (count--) { 11300 *b = box[count]; 11301 if (box_intersect(b, &clip.extents)) { 11302 b->x1 += dx; 11303 b->x2 += dx; 11304 b->y1 += dy; 11305 b->y2 += dy; 11306 if (++b == last_box) { 11307 fill.boxes(sna, &fill, boxes, last_box-boxes); 11308 if (damage) 11309 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11310 b = boxes; 11311 } 11312 } 11313 11314 } 11315 } while (--n); 11316 } 11317 RegionUninit(&clip); 11318 } 11319 goto done; 11320 11321wide_clipped: 11322 { 11323 RegionRec clip; 11324 BoxRec box[4]; 11325 int16_t offset2 = gc->lineWidth; 11326 int16_t offset1 = offset2 >> 1; 11327 int16_t offset3 = offset2 - offset1; 11328 11329 region_set(&clip, extents); 11330 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 11331 goto done; 11332 11333 DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n", 11334 __FUNCTION__, 11335 clip.extents.x1, clip.extents.y1, 11336 clip.extents.x2, clip.extents.y2)); 11337 11338 if (clip.data) { 11339 const BoxRec * const clip_start = RegionBoxptr(&clip); 11340 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11341 const BoxRec *c; 11342 do { 11343 xRectangle rr = *r++; 11344 int count; 11345 11346 if ((rr.width | rr.height) == 0) 11347 continue; /* XXX -> PolyLine */ 11348 11349 rr.x += drawable->x; 11350 rr.y += drawable->y; 11351 11352 if (rr.height <= offset2 || rr.width <= offset2) { 11353 if (rr.height == 0) { 11354 box[0].x1 = rr.x; 11355 box[0].x2 = rr.x + rr.width; 11356 } else { 11357 box[0].x1 = rr.x - offset1; 11358 box[0].x2 = rr.x + rr.width + offset3; 11359 } 11360 if (rr.width == 0) { 11361 box[0].y1 = rr.y; 11362 box[0].y2 = rr.y + rr.height; 11363 } else { 11364 box[0].y1 = rr.y - offset1; 11365 box[0].y2 = rr.y + rr.height + offset3; 11366 } 11367 count = 1; 11368 } else { 11369 box[0].x1 = rr.x - offset1; 11370 box[0].x2 = box[0].x1 + rr.width + offset2; 11371 box[0].y1 = rr.y - offset1; 11372 box[0].y2 = box[0].y1 + offset2; 11373 11374 box[1].x1 = rr.x - offset1; 11375 box[1].x2 = box[1].x1 + offset2; 11376 box[1].y1 = rr.y + offset3; 11377 box[1].y2 = rr.y + rr.height - offset1; 11378 11379 box[2] = box[1]; 11380 box[2].x1 += rr.width; 11381 box[2].x2 += rr.width; 11382 11383 box[3] = box[0]; 11384 box[3].y1 += rr.height; 11385 box[3].y2 += rr.height; 11386 count = 4; 11387 } 11388 11389 while (count--) { 11390 c = find_clip_box_for_y(clip_start, 11391 clip_end, 11392 box[count].y1); 11393 while (c != clip_end) { 11394 if (box[count].y2 <= c->y1) 11395 break; 11396 11397 *b = box[count]; 11398 if (box_intersect(b, c++)) { 11399 b->x1 += dx; 11400 b->x2 += dx; 11401 b->y1 += dy; 11402 b->y2 += dy; 11403 if (++b == last_box) { 11404 fill.boxes(sna, &fill, boxes, last_box-boxes); 11405 if (damage) 11406 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11407 b = boxes; 11408 } 11409 } 11410 } 11411 } 11412 } while (--n); 11413 } else { 11414 DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n", 11415 __FUNCTION__, offset1, offset2, offset3)); 11416 do { 11417 xRectangle rr = *r++; 11418 int count; 11419 rr.x += drawable->x; 11420 rr.y += drawable->y; 11421 11422 DBG(("%s: r=(%d, %d)x(%d, %d)\n", 11423 __FUNCTION__, rr.x, rr.y, rr.width, rr.height)); 11424 if (rr.height <= offset2 || rr.width <= offset2) { 11425 if (rr.height == 0) { 11426 box[0].x1 = rr.x; 11427 box[0].x2 = rr.x + rr.width; 11428 } else { 11429 box[0].x1 = rr.x - offset1; 11430 box[0].x2 = box[0].x1 + rr.width + offset2; 11431 } 11432 if (rr.width == 0) { 11433 box[0].y1 = rr.y; 11434 box[0].y2 = rr.y + rr.height; 11435 } else { 11436 box[0].y1 = rr.y - offset1; 11437 box[0].y2 = box[0].y1 + rr.height + offset2; 11438 } 11439 count = 1; 11440 } else { 11441 box[0].x1 = rr.x - offset1; 11442 box[0].x2 = box[0].x1 + rr.width + offset2; 11443 box[0].y1 = rr.y - offset1; 11444 box[0].y2 = box[0].y1 + offset2; 11445 DBG(("%s: box[0]=(%d, %d), (%d, %d)\n", 11446 __FUNCTION__, 11447 box[0].x1, box[0].y1, 11448 box[0].x2, box[0].y2)); 11449 11450 box[1].x1 = rr.x - offset1; 11451 box[1].x2 = box[1].x1 + offset2; 11452 box[1].y1 = rr.y + offset3; 11453 box[1].y2 = rr.y + rr.height - offset1; 11454 DBG(("%s: box[1]=(%d, %d), (%d, %d)\n", 11455 __FUNCTION__, 11456 box[1].x1, box[1].y1, 11457 box[1].x2, box[1].y2)); 11458 11459 box[2] = box[1]; 11460 box[2].x1 += rr.width; 11461 box[2].x2 += rr.width; 11462 DBG(("%s: box[2]=(%d, %d), (%d, %d)\n", 11463 __FUNCTION__, 11464 box[2].x1, box[2].y1, 11465 box[2].x2, box[2].y2)); 11466 11467 box[3] = box[0]; 11468 box[3].y1 += rr.height; 11469 box[3].y2 += rr.height; 11470 DBG(("%s: box[3]=(%d, %d), (%d, %d)\n", 11471 __FUNCTION__, 11472 box[3].x1, box[3].y1, 11473 box[3].x2, box[3].y2)); 11474 11475 count = 4; 11476 } 11477 11478 while (count--) { 11479 *b = box[count]; 11480 if (box_intersect(b, &clip.extents)) { 11481 b->x1 += dx; 11482 b->x2 += dx; 11483 b->y1 += dy; 11484 b->y2 += dy; 11485 if (++b == last_box) { 11486 fill.boxes(sna, &fill, boxes, last_box-boxes); 11487 if (damage) 11488 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11489 b = boxes; 11490 } 11491 } 11492 } 11493 } while (--n); 11494 } 11495 RegionUninit(&clip); 11496 } 11497 goto done; 11498 11499wide: 11500 { 11501 int offset2 = gc->lineWidth; 11502 int offset1 = offset2 >> 1; 11503 int offset3 = offset2 - offset1; 11504 11505 dx += drawable->x; 11506 dy += drawable->y; 11507 11508 do { 11509 xRectangle rr = *r++; 11510 11511 if ((rr.width | rr.height) == 0) 11512 continue; /* XXX -> PolyLine */ 11513 11514 rr.x += dx; 11515 rr.y += dy; 11516 11517 if (b+4 > last_box) { 11518 fill.boxes(sna, &fill, boxes, last_box-boxes); 11519 if (damage) 11520 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 11521 b = boxes; 11522 } 11523 11524 if (rr.height <= offset2 || rr.width <= offset2) { 11525 if (rr.height == 0) { 11526 b->x1 = rr.x; 11527 b->x2 = rr.x + rr.width; 11528 } else { 11529 b->x1 = rr.x - offset1; 11530 b->x2 = rr.x + rr.width + offset3; 11531 } 11532 if (rr.width == 0) { 11533 b->y1 = rr.y; 11534 b->y2 = rr.y + rr.height; 11535 } else { 11536 b->y1 = rr.y - offset1; 11537 b->y2 = rr.y + rr.height + offset3; 11538 } 11539 b++; 11540 } else { 11541 b[0].x1 = rr.x - offset1; 11542 b[0].x2 = b[0].x1 + rr.width + offset2; 11543 b[0].y1 = rr.y - offset1; 11544 b[0].y2 = b[0].y1 + offset2; 11545 11546 b[1].x1 = rr.x - offset1; 11547 b[1].x2 = b[1].x1 + offset2; 11548 b[1].y1 = rr.y + offset3; 11549 b[1].y2 = rr.y + rr.height - offset1; 11550 11551 b[2] = b[1]; 11552 b[2].x1 += rr.width; 11553 b[2].x2 += rr.width; 11554 11555 b[3] = b[0]; 11556 b[3].y1 += rr.height; 11557 b[3].y2 += rr.height; 11558 b += 4; 11559 } 11560 } while (--n); 11561 } 11562 goto done; 11563 11564done: 11565 if (b != boxes) { 11566 fill.boxes(sna, &fill, boxes, b-boxes); 11567 if (damage) 11568 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 11569 } 11570 fill.done(sna, &fill); 11571 assert_pixmap_damage(pixmap); 11572 return true; 11573} 11574 11575static void 11576sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) 11577{ 11578 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11579 struct sna *sna = to_sna_from_pixmap(pixmap); 11580 struct sna_damage **damage; 11581 struct kgem_bo *bo; 11582 RegionRec region; 11583 unsigned flags; 11584 11585 DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", 11586 __FUNCTION__, 11587 n, r->x, r->y, r->width, r->height, 11588 gc->lineWidth)); 11589 11590 flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); 11591 if (flags == 0) 11592 return; 11593 11594 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11595 region.extents.x1, region.extents.y1, 11596 region.extents.x2, region.extents.y2, 11597 flags)); 11598 11599 if (FORCE_FALLBACK) 11600 goto fallback; 11601 11602 if (!ACCEL_POLY_RECTANGLE) 11603 goto fallback; 11604 11605 if (wedged(sna)) { 11606 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11607 goto fallback; 11608 } 11609 11610 DBG(("%s: fill=%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n", 11611 __FUNCTION__, 11612 gc->fillStyle, gc->fillStyle == FillSolid, 11613 gc->lineStyle, gc->lineStyle == LineSolid, 11614 gc->joinStyle, gc->joinStyle == JoinMiter, 11615 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 11616 11617 if (!PM_IS_SOLID(drawable, gc->planemask)) 11618 goto fallback; 11619 11620 if (flags & RECTILINEAR && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) { 11621 DBG(("%s: trying blt solid fill [%08lx] paths\n", 11622 __FUNCTION__, gc->fgPixel)); 11623 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11624 ®ion.extents, &damage)) && 11625 sna_poly_rectangle_blt(drawable, bo, damage, 11626 gc, n, r, ®ion.extents, flags&2)) 11627 return; 11628 } else { 11629 /* Not a trivial outline, but we still maybe able to break it 11630 * down into simpler operations that we can accelerate. 11631 */ 11632 if (sna_drawable_use_bo(drawable, PREFER_GPU, 11633 ®ion.extents, &damage)) { 11634 miPolyRectangle(drawable, gc, n, r); 11635 return; 11636 } 11637 } 11638 11639fallback: 11640 DBG(("%s: fallback, clip=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11641 region_num_rects(gc->pCompositeClip), 11642 gc->pCompositeClip->extents.x1, gc->pCompositeClip->extents.y1, 11643 gc->pCompositeClip->extents.x2, gc->pCompositeClip->extents.y2)); 11644 11645 region.data = NULL; 11646 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 11647 return; 11648 11649 DBG(("%s: CPU region=%dx[(%d, %d), (%d, %d)]\n", __FUNCTION__, 11650 region_num_rects(®ion), 11651 region.extents.x1, region.extents.y1, 11652 region.extents.x2, region.extents.y2)); 11653 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 11654 goto out; 11655 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 11656 drawable_gc_flags(drawable, gc, true))) 11657 goto out; 11658 11659 if (sigtrap_get() == 0) { 11660 DBG(("%s: miPolyRectangle\n", __FUNCTION__)); 11661 miPolyRectangle(drawable, gc, n, r); 11662 FALLBACK_FLUSH(drawable); 11663 sigtrap_put(); 11664 } 11665out: 11666 sna_gc_move_to_gpu(gc); 11667 RegionUninit(®ion); 11668} 11669 11670static unsigned 11671sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, 11672 int n, xArc *arc, 11673 BoxPtr out) 11674{ 11675 BoxRec box; 11676 bool clipped; 11677 int v; 11678 11679 if (n == 0) 11680 return 0; 11681 11682 box.x1 = arc->x; 11683 box.x2 = bound(box.x1, arc->width); 11684 box.y1 = arc->y; 11685 box.y2 = bound(box.y1, arc->height); 11686 11687 while (--n) { 11688 arc++; 11689 if (box.x1 > arc->x) 11690 box.x1 = arc->x; 11691 v = bound(arc->x, arc->width); 11692 if (box.x2 < v) 11693 box.x2 = v; 11694 if (box.y1 > arc->y) 11695 box.y1 = arc->y; 11696 v = bound(arc->y, arc->height); 11697 if (box.y2 < v) 11698 box.y2 = v; 11699 } 11700 11701 v = gc->lineWidth >> 1; 11702 if (v) { 11703 box.x1 -= v; 11704 box.x2 += v; 11705 box.y1 -= v; 11706 box.y2 += v; 11707 } 11708 11709 box.x2++; 11710 box.y2++; 11711 11712 clipped = trim_and_translate_box(&box, drawable, gc); 11713 if (box_empty(&box)) 11714 return 0; 11715 11716 *out = box; 11717 return 1 | clipped << 1; 11718} 11719 11720static void 11721sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc) 11722{ 11723 struct sna_fill_spans data; 11724 struct sna_pixmap *priv; 11725 11726 DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth)); 11727 11728 data.flags = sna_poly_arc_extents(drawable, gc, n, arc, 11729 &data.region.extents); 11730 if (data.flags == 0) 11731 return; 11732 11733 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 11734 data.region.extents.x1, data.region.extents.y1, 11735 data.region.extents.x2, data.region.extents.y2, 11736 data.flags)); 11737 11738 data.region.data = NULL; 11739 11740 if (FORCE_FALLBACK) 11741 goto fallback; 11742 11743 if (!ACCEL_POLY_ARC) 11744 goto fallback; 11745 11746 data.pixmap = get_drawable_pixmap(drawable); 11747 data.sna = to_sna_from_pixmap(data.pixmap); 11748 priv = sna_pixmap(data.pixmap); 11749 if (priv == NULL) { 11750 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 11751 goto fallback; 11752 } 11753 11754 if (wedged(data.sna)) { 11755 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 11756 goto fallback; 11757 } 11758 11759 if (!PM_IS_SOLID(drawable, gc->planemask)) 11760 goto fallback; 11761 11762 if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 11763 &data.region.extents, &data.damage))) { 11764 uint32_t color; 11765 11766 DBG(("%s: converting arcs into spans\n", __FUNCTION__)); 11767 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 11768 11769 if (gc_is_solid(gc, &color)) { 11770 sna_gc(gc)->priv = &data; 11771 11772 assert(gc->miTranslate); 11773 if (gc->lineStyle == LineSolid) { 11774 struct sna_fill_op fill; 11775 11776 if (!sna_fill_init_blt(&fill, 11777 data.sna, data.pixmap, 11778 data.bo, gc->alu, color, 11779 FILL_POINTS | FILL_SPANS)) 11780 goto fallback; 11781 11782 if ((data.flags & IS_CLIPPED) == 0) { 11783 if (data.dx | data.dy) 11784 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 11785 else 11786 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 11787 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 11788 } else { 11789 if (!region_maybe_clip(&data.region, 11790 gc->pCompositeClip)) 11791 return; 11792 11793 if (region_is_singular(&data.region)) { 11794 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 11795 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 11796 } else { 11797 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 11798 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 11799 } 11800 } 11801 11802 data.op = &fill; 11803 gc->ops = &sna_gc_ops__tmp; 11804 if (gc->lineWidth == 0) 11805 miZeroPolyArc(drawable, gc, n, arc); 11806 else 11807 miPolyArc(drawable, gc, n, arc); 11808 gc->ops = (GCOps *)&sna_gc_ops; 11809 11810 fill.done(data.sna, &fill); 11811 } else { 11812 if (!region_maybe_clip(&data.region, 11813 gc->pCompositeClip)) 11814 return; 11815 11816 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 11817 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 11818 11819 gc->ops = &sna_gc_ops__tmp; 11820 if (gc->lineWidth == 0) 11821 miZeroPolyArc(drawable, gc, n, arc); 11822 else 11823 miPolyArc(drawable, gc, n, arc); 11824 gc->ops = (GCOps *)&sna_gc_ops; 11825 } 11826 11827 if (data.damage) { 11828 if (data.dx | data.dy) 11829 pixman_region_translate(&data.region, data.dx, data.dy); 11830 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 11831 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 11832 } 11833 assert_pixmap_damage(data.pixmap); 11834 RegionUninit(&data.region); 11835 return; 11836 } 11837 11838 /* XXX still around 10x slower for x11perf -ellipse */ 11839 if (gc->lineWidth == 0) 11840 miZeroPolyArc(drawable, gc, n, arc); 11841 else 11842 miPolyArc(drawable, gc, n, arc); 11843 return; 11844 } 11845 11846fallback: 11847 DBG(("%s -- fallback\n", __FUNCTION__)); 11848 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) 11849 return; 11850 11851 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 11852 goto out; 11853 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 11854 drawable_gc_flags(drawable, gc, true))) 11855 goto out; 11856 11857 if (sigtrap_get() == 0) { 11858 DBG(("%s -- fbPolyArc\n", __FUNCTION__)); 11859 fbPolyArc(drawable, gc, n, arc); 11860 FALLBACK_FLUSH(drawable); 11861 sigtrap_put(); 11862 } 11863out: 11864 sna_gc_move_to_gpu(gc); 11865 RegionUninit(&data.region); 11866} 11867 11868static bool 11869sna_poly_fill_rect_blt(DrawablePtr drawable, 11870 struct kgem_bo *bo, 11871 struct sna_damage **damage, 11872 GCPtr gc, uint32_t pixel, 11873 int n, const xRectangle *rect, 11874 const BoxRec *extents, 11875 unsigned flags) 11876{ 11877 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11878 struct sna *sna = to_sna_from_pixmap(pixmap); 11879 struct sna_fill_op fill; 11880 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 11881 int16_t dx, dy; 11882 11883 DBG(("%s pixmap=%ld x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n", 11884 __FUNCTION__, pixmap->drawable.serialNumber, n, 11885 rect->x, rect->y, rect->width, rect->height, 11886 drawable->x, drawable->y, 11887 flags&2)); 11888 11889 if (n == 1 && region_is_singular(gc->pCompositeClip)) { 11890 BoxRec r; 11891 bool success = true; 11892 11893 r.x1 = rect->x + drawable->x; 11894 r.y1 = rect->y + drawable->y; 11895 r.x2 = bound(r.x1, rect->width); 11896 r.y2 = bound(r.y1, rect->height); 11897 if (box_intersect(&r, &gc->pCompositeClip->extents)) { 11898 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 11899 r.x1 += dx; r.y1 += dy; 11900 r.x2 += dx; r.y2 += dy; 11901 } 11902 DBG(("%s: using fill_one() fast path: (%d, %d), (%d, %d). alu=%d, pixel=%08x, damage?=%d\n", 11903 __FUNCTION__, r.x1, r.y1, r.x2, r.y2, gc->alu, pixel, damage != NULL)); 11904 11905 assert_pixmap_contains_box(pixmap, &r); 11906 if (sna->render.fill_one(sna, pixmap, bo, pixel, 11907 r.x1, r.y1, r.x2, r.y2, 11908 gc->alu)) { 11909 if (r.x2 - r.x1 == pixmap->drawable.width && 11910 r.y2 - r.y1 == pixmap->drawable.height) { 11911 if (damage) { 11912 sna_damage_all(damage, pixmap); 11913 damage = NULL; 11914 } 11915 if (flags & OVERWRITES) { 11916 struct sna_pixmap *priv = sna_pixmap(pixmap); 11917 if (bo == priv->gpu_bo) { 11918 assert(damage == NULL || damage == &priv->gpu_damage); 11919 assert(priv->gpu_bo->proxy == NULL); 11920 sna_damage_destroy(&priv->cpu_damage); 11921 list_del(&priv->flush_list); 11922 priv->clear = true; 11923 priv->clear_color = gc->alu == GXcopyInverted ? ~pixel & ((1 << gc->depth) - 1) : pixel; 11924 11925 DBG(("%s: pixmap=%ld, marking clear [%08x]\n", 11926 __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); 11927 } 11928 } 11929 } 11930 if (damage) 11931 sna_damage_add_box(damage, &r); 11932 assert_pixmap_damage(pixmap); 11933 } else 11934 success = false; 11935 } 11936 11937 return success; 11938 } 11939 11940 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel, FILL_BOXES)) { 11941 DBG(("%s: unsupported blt\n", __FUNCTION__)); 11942 return false; 11943 } 11944 11945 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11946 if ((flags & IS_CLIPPED) == 0) { 11947 dx += drawable->x; 11948 dy += drawable->y; 11949 11950 sna_damage_add_rectangles(damage, rect, n, dx, dy); 11951 if (dx|dy) { 11952 do { 11953 unsigned nbox = n; 11954 if (nbox > ARRAY_SIZE(boxes)) 11955 nbox = ARRAY_SIZE(boxes); 11956 n -= nbox; 11957 while (nbox >= 2) { 11958 b[0].x1 = rect[0].x + dx; 11959 b[0].y1 = rect[0].y + dy; 11960 b[0].x2 = b[0].x1 + rect[0].width; 11961 b[0].y2 = b[0].y1 + rect[0].height; 11962 11963 b[1].x1 = rect[1].x + dx; 11964 b[1].y1 = rect[1].y + dy; 11965 b[1].x2 = b[1].x1 + rect[1].width; 11966 b[1].y2 = b[1].y1 + rect[1].height; 11967 11968 b += 2; 11969 rect += 2; 11970 nbox -= 2; 11971 } 11972 if (nbox) { 11973 b->x1 = rect->x + dx; 11974 b->y1 = rect->y + dy; 11975 b->x2 = b->x1 + rect->width; 11976 b->y2 = b->y1 + rect->height; 11977 b++; 11978 rect++; 11979 } 11980 fill.boxes(sna, &fill, boxes, b-boxes); 11981 b = boxes; 11982 } while (n); 11983 } else { 11984 do { 11985 unsigned nbox = n; 11986 if (nbox > ARRAY_SIZE(boxes)) 11987 nbox = ARRAY_SIZE(boxes); 11988 n -= nbox; 11989 while (nbox >= 2) { 11990 b[0].x1 = rect[0].x; 11991 b[0].y1 = rect[0].y; 11992 b[0].x2 = b[0].x1 + rect[0].width; 11993 b[0].y2 = b[0].y1 + rect[0].height; 11994 11995 b[1].x1 = rect[1].x; 11996 b[1].y1 = rect[1].y; 11997 b[1].x2 = b[1].x1 + rect[1].width; 11998 b[1].y2 = b[1].y1 + rect[1].height; 11999 12000 b += 2; 12001 rect += 2; 12002 nbox -= 2; 12003 } 12004 if (nbox) { 12005 b->x1 = rect->x; 12006 b->y1 = rect->y; 12007 b->x2 = b->x1 + rect->width; 12008 b->y2 = b->y1 + rect->height; 12009 b++; 12010 rect++; 12011 } 12012 fill.boxes(sna, &fill, boxes, b-boxes); 12013 b = boxes; 12014 } while (n); 12015 } 12016 } else { 12017 RegionRec clip; 12018 12019 region_set(&clip, extents); 12020 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12021 goto done; 12022 12023 if (clip.data == NULL) { 12024 do { 12025 b->x1 = rect->x + drawable->x; 12026 b->y1 = rect->y + drawable->y; 12027 b->x2 = bound(b->x1, rect->width); 12028 b->y2 = bound(b->y1, rect->height); 12029 rect++; 12030 12031 if (box_intersect(b, &clip.extents)) { 12032 b->x1 += dx; 12033 b->x2 += dx; 12034 b->y1 += dy; 12035 b->y2 += dy; 12036 if (++b == last_box) { 12037 fill.boxes(sna, &fill, boxes, last_box-boxes); 12038 if (damage) 12039 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 12040 b = boxes; 12041 } 12042 } 12043 } while (--n); 12044 } else { 12045 const BoxRec * const clip_start = RegionBoxptr(&clip); 12046 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12047 const BoxRec *c; 12048 12049 do { 12050 BoxRec box; 12051 12052 box.x1 = rect->x + drawable->x; 12053 box.y1 = rect->y + drawable->y; 12054 box.x2 = bound(box.x1, rect->width); 12055 box.y2 = bound(box.y1, rect->height); 12056 rect++; 12057 12058 c = find_clip_box_for_y(clip_start, 12059 clip_end, 12060 box.y1); 12061 while (c != clip_end) { 12062 if (box.y2 <= c->y1) 12063 break; 12064 12065 *b = box; 12066 if (box_intersect(b, c++)) { 12067 b->x1 += dx; 12068 b->x2 += dx; 12069 b->y1 += dy; 12070 b->y2 += dy; 12071 if (++b == last_box) { 12072 fill.boxes(sna, &fill, boxes, last_box-boxes); 12073 if (damage) 12074 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 12075 b = boxes; 12076 } 12077 } 12078 12079 } 12080 } while (--n); 12081 } 12082 12083 RegionUninit(&clip); 12084 if (b != boxes) { 12085 fill.boxes(sna, &fill, boxes, b-boxes); 12086 if (damage) 12087 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 12088 } 12089 } 12090done: 12091 fill.done(sna, &fill); 12092 assert_pixmap_damage(pixmap); 12093 return true; 12094} 12095 12096static uint32_t 12097get_pixel(PixmapPtr pixmap) 12098{ 12099 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber)); 12100 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12101 return 0; 12102 12103 switch (pixmap->drawable.bitsPerPixel) { 12104 case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 12105 case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 12106 default: return *(uint8_t *)pixmap->devPrivate.ptr; 12107 } 12108} 12109 12110inline static int 12111_use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 12112{ 12113 if (USE_SPANS) 12114 return USE_SPANS > 0; 12115 12116 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 12117 sna_pixmap_is_gpu(gc->tile.pixmap)) { 12118 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 12119 return PREFER_GPU | FORCE_GPU; 12120 } 12121 12122 return PREFER_GPU; 12123} 12124 12125static int 12126use_fill_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents, unsigned flags) 12127{ 12128 int ret = _use_fill_spans(drawable, gc, extents, flags); 12129 DBG(("%s? %d\n", __FUNCTION__, ret)); 12130 return ret; 12131} 12132 12133static void 12134sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, 12135 int shape, int mode, 12136 int n, DDXPointPtr pt) 12137{ 12138 struct sna_fill_spans data; 12139 struct sna_pixmap *priv; 12140 12141 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 12142 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 12143 (gc->fillStyle == FillSolid || 12144 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 12145 gc->fillStyle, gc->tileIsPixel, 12146 gc->alu)); 12147 DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n", 12148 __FUNCTION__, draw->serialNumber, 12149 draw->x, draw->y, draw->width, draw->height)); 12150 12151 data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, 12152 &data.region.extents); 12153 if (data.flags == 0) { 12154 DBG(("%s, nothing to do\n", __FUNCTION__)); 12155 return; 12156 } 12157 12158 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 12159 data.region.extents.x1, data.region.extents.y1, 12160 data.region.extents.x2, data.region.extents.y2, 12161 data.flags)); 12162 12163 data.region.data = NULL; 12164 12165 if (FORCE_FALLBACK) 12166 goto fallback; 12167 12168 if (!ACCEL_POLY_FILL_POLYGON) 12169 goto fallback; 12170 12171 data.pixmap = get_drawable_pixmap(draw); 12172 data.sna = to_sna_from_pixmap(data.pixmap); 12173 priv = sna_pixmap(data.pixmap); 12174 if (priv == NULL) { 12175 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 12176 goto fallback; 12177 } 12178 12179 if (wedged(data.sna)) { 12180 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 12181 goto fallback; 12182 } 12183 12184 if (!PM_IS_SOLID(draw, gc->planemask)) 12185 goto fallback; 12186 12187 if ((data.bo = sna_drawable_use_bo(draw, 12188 use_fill_spans(draw, gc, &data.region.extents, data.flags), 12189 &data.region.extents, 12190 &data.damage))) { 12191 uint32_t color; 12192 12193 sna_gc(gc)->priv = &data; 12194 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 12195 12196 if (gc_is_solid(gc, &color)) { 12197 struct sna_fill_op fill; 12198 12199 if (!sna_fill_init_blt(&fill, 12200 data.sna, data.pixmap, 12201 data.bo, gc->alu, color, 12202 FILL_SPANS)) 12203 goto fallback; 12204 12205 data.op = &fill; 12206 12207 if ((data.flags & IS_CLIPPED) == 0) { 12208 if (data.dx | data.dy) 12209 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 12210 else 12211 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 12212 } else { 12213 if (!region_maybe_clip(&data.region, 12214 gc->pCompositeClip)) 12215 return; 12216 12217 if (region_is_singular(&data.region)) 12218 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 12219 else 12220 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 12221 } 12222 assert(gc->miTranslate); 12223 gc->ops = &sna_gc_ops__tmp; 12224 12225 miFillPolygon(draw, gc, shape, mode, n, pt); 12226 fill.done(data.sna, &fill); 12227 } else { 12228 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 12229 gc->ops = &sna_gc_ops__tmp; 12230 12231 miFillPolygon(draw, gc, shape, mode, n, pt); 12232 } 12233 12234 gc->ops = (GCOps *)&sna_gc_ops; 12235 if (data.damage) { 12236 if (data.dx | data.dy) 12237 pixman_region_translate(&data.region, data.dx, data.dy); 12238 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 12239 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 12240 } 12241 assert_pixmap_damage(data.pixmap); 12242 RegionUninit(&data.region); 12243 return; 12244 } 12245 12246fallback: 12247 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 12248 data.region.extents.x1, data.region.extents.y1, 12249 data.region.extents.x2, data.region.extents.y2)); 12250 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 12251 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 12252 return; 12253 } 12254 12255 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 12256 goto out; 12257 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 12258 drawable_gc_flags(draw, gc, true))) 12259 goto out; 12260 12261 if (sigtrap_get() == 0) { 12262 DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", 12263 __FUNCTION__)); 12264 miFillPolygon(draw, gc, shape, mode, n, pt); 12265 sigtrap_put(); 12266 } 12267out: 12268 sna_gc_move_to_gpu(gc); 12269 RegionUninit(&data.region); 12270} 12271 12272static struct kgem_bo * 12273sna_pixmap_get_source_bo(PixmapPtr pixmap) 12274{ 12275 struct sna_pixmap *priv = sna_pixmap(pixmap); 12276 unsigned flags; 12277 BoxRec box; 12278 12279 box.x1 = box.y1 = 0; 12280 box.x2 = pixmap->drawable.width; 12281 box.y2 = pixmap->drawable.height; 12282 12283 DBG(("%s(pixmap=%ld, size=%dx%d)\n", __FUNCTION__, 12284 pixmap->drawable.serialNumber, pixmap->drawable.width, pixmap->drawable.height)); 12285 12286 if (priv == NULL) { 12287 DBG(("%s: unattached, uploading data into temporary\n", __FUNCTION__)); 12288 return kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12289 pixmap->devPrivate.ptr, &box, 12290 pixmap->devKind, 12291 pixmap->drawable.bitsPerPixel); 12292 } 12293 12294 if (priv->gpu_damage) { 12295 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) 12296 return kgem_bo_reference(priv->gpu_bo); 12297 } else if (priv->cpu_damage) { 12298 if (priv->cpu_bo) 12299 return kgem_bo_reference(priv->cpu_bo); 12300 } else { 12301 if (priv->gpu_bo) 12302 return kgem_bo_reference(priv->gpu_bo); 12303 if (priv->cpu_bo) 12304 return kgem_bo_reference(priv->cpu_bo); 12305 } 12306 12307 flags = MOVE_READ | MOVE_ASYNC_HINT; 12308 if (priv->gpu_bo && priv->gpu_bo->proxy) { 12309 struct kgem_bo *bo = priv->gpu_bo; 12310 if (bo->rq == NULL && (bo->snoop || bo->pitch >= 4096)) 12311 flags |= __MOVE_FORCE; 12312 } 12313 if (priv->gpu_bo == NULL) { 12314 if (++priv->source_count > SOURCE_BIAS) 12315 flags |= __MOVE_FORCE; 12316 } 12317 12318 if (!sna_pixmap_move_to_gpu(pixmap, flags)) { 12319 struct kgem_bo *upload; 12320 12321 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 12322 return NULL; 12323 12324 upload = kgem_upload_source_image(&to_sna_from_pixmap(pixmap)->kgem, 12325 pixmap->devPrivate.ptr, &box, 12326 pixmap->devKind, 12327 pixmap->drawable.bitsPerPixel); 12328 if (upload == NULL) 12329 return NULL; 12330 12331 if (priv->gpu_bo == NULL) { 12332 DBG(("%s: adding upload cache to pixmap=%ld\n", 12333 __FUNCTION__, pixmap->drawable.serialNumber)); 12334 assert(upload->proxy != NULL); 12335 kgem_proxy_bo_attach(upload, &priv->gpu_bo); 12336 } 12337 12338 return upload; 12339 } 12340 12341 return kgem_bo_reference(priv->gpu_bo); 12342} 12343 12344/* 12345static bool 12346tile(DrawablePtr drawable, 12347 struct kgem_bo *bo, struct sna_damage **damage, 12348 PixmapPtr tile, const DDXPointRec * const origin, int alu, 12349 int n, xRectangle *rect, 12350 const BoxRec *extents, unsigned clipped) 12351 */ 12352 12353static bool 12354sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, 12355 struct kgem_bo *bo, struct sna_damage **damage, 12356 struct kgem_bo *tile_bo, GCPtr gc, 12357 int n, const xRectangle *r, 12358 const BoxRec *extents, unsigned clipped) 12359{ 12360 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12361 struct sna *sna = to_sna_from_pixmap(pixmap); 12362 const DDXPointRec * const origin = &gc->patOrg; 12363 uint32_t br00, br13; 12364 int tx, ty; 12365 int16_t dx, dy; 12366 uint32_t *b; 12367 12368 if (NO_TILE_8x8) 12369 return false; 12370 12371 DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x, origin=(%d, %d)\n", 12372 __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped, origin->x, origin->y)); 12373 12374 DBG(("%s: tile_bo tiling=%d, pitch=%d\n", __FUNCTION__, tile_bo->tiling, tile_bo->pitch)); 12375 if (tile_bo->tiling) 12376 return false; 12377 12378 if (!kgem_bo_can_blt(&sna->kgem, bo) || 12379 !kgem_bo_can_blt(&sna->kgem, tile_bo)) 12380 return false; 12381 12382 assert(tile_bo->pitch == 8 * drawable->bitsPerPixel >> 3); 12383 12384 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12385 assert(kgem_bo_can_blt(&sna->kgem, bo)); 12386 if (!kgem_check_batch(&sna->kgem, 10+2*3) || 12387 !kgem_check_reloc(&sna->kgem, 2) || 12388 !kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) { 12389 kgem_submit(&sna->kgem); 12390 if (!kgem_check_many_bo_fenced(&sna->kgem, bo, tile_bo, NULL)) 12391 return false; 12392 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12393 } 12394 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12395 12396 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12397 assert(extents->x1 + dx >= 0); 12398 assert(extents->y1 + dy >= 0); 12399 assert(extents->x2 + dx <= pixmap->drawable.width); 12400 assert(extents->y2 + dy <= pixmap->drawable.height); 12401 12402 br00 = XY_SCANLINE_BLT; 12403 tx = (-drawable->x - dx - origin->x) % 8; 12404 if (tx < 0) 12405 tx += 8; 12406 ty = (-drawable->y - dy - origin->y) % 8; 12407 if (ty < 0) 12408 ty += 8; 12409 br00 |= tx << 12 | ty << 8; 12410 12411 br13 = bo->pitch; 12412 if (sna->kgem.gen >= 040 && bo->tiling) { 12413 br00 |= BLT_DST_TILED; 12414 br13 >>= 2; 12415 } 12416 br13 |= blt_depth(drawable->depth) << 24; 12417 br13 |= fill_ROP[gc->alu] << 16; 12418 12419 if (!clipped) { 12420 dx += drawable->x; 12421 dy += drawable->y; 12422 12423 sna_damage_add_rectangles(damage, r, n, dx, dy); 12424 if (n == 1) { 12425 DBG(("%s: rect=(%d, %d)x(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12426 __FUNCTION__, r->x, r->y, r->width, r->height, dx, dy, tx, ty)); 12427 12428 assert(r->x + dx >= 0); 12429 assert(r->y + dy >= 0); 12430 assert(r->x + dx + r->width <= pixmap->drawable.width); 12431 assert(r->y + dy + r->height <= pixmap->drawable.height); 12432 12433 assert(sna->kgem.mode == KGEM_BLT); 12434 b = sna->kgem.batch + sna->kgem.nbatch; 12435 if (sna->kgem.gen >= 0100) { 12436 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 6; 12437 b[1] = br13; 12438 b[2] = (r->y + dy) << 16 | (r->x + dx); 12439 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12440 *(uint64_t *)(b+4) = 12441 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12442 I915_GEM_DOMAIN_RENDER << 16 | 12443 I915_GEM_DOMAIN_RENDER | 12444 KGEM_RELOC_FENCED, 12445 0); 12446 *(uint64_t *)(b+6) = 12447 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, tile_bo, 12448 I915_GEM_DOMAIN_RENDER << 16 | 12449 KGEM_RELOC_FENCED, 12450 0); 12451 sna->kgem.nbatch += 8; 12452 } else { 12453 b[0] = XY_PAT_BLT | 3 << 20 | (br00 & 0x7f00) | 4; 12454 b[1] = br13; 12455 b[2] = (r->y + dy) << 16 | (r->x + dx); 12456 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12457 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12458 I915_GEM_DOMAIN_RENDER << 16 | 12459 I915_GEM_DOMAIN_RENDER | 12460 KGEM_RELOC_FENCED, 12461 0); 12462 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo, 12463 I915_GEM_DOMAIN_RENDER << 16 | 12464 KGEM_RELOC_FENCED, 12465 0); 12466 sna->kgem.nbatch += 6; 12467 } 12468 } else do { 12469 int n_this_time, rem; 12470 12471 assert(sna->kgem.mode == KGEM_BLT); 12472 b = sna->kgem.batch + sna->kgem.nbatch; 12473 if (sna->kgem.gen >= 0100) { 12474 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12475 b[1] = br13; 12476 b[2] = 0; 12477 b[3] = 0; 12478 *(uint64_t *)(b+4) = 12479 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12480 I915_GEM_DOMAIN_RENDER << 16 | 12481 I915_GEM_DOMAIN_RENDER | 12482 KGEM_RELOC_FENCED, 12483 0); 12484 b[6] = gc->bgPixel; 12485 b[7] = gc->fgPixel; 12486 *(uint64_t *)(b+8) = 12487 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12488 I915_GEM_DOMAIN_RENDER << 16 | 12489 KGEM_RELOC_FENCED, 12490 0); 12491 sna->kgem.nbatch += 10; 12492 } else { 12493 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12494 b[1] = br13; 12495 b[2] = 0; 12496 b[3] = 0; 12497 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12498 I915_GEM_DOMAIN_RENDER << 16 | 12499 I915_GEM_DOMAIN_RENDER | 12500 KGEM_RELOC_FENCED, 12501 0); 12502 b[5] = gc->bgPixel; 12503 b[6] = gc->fgPixel; 12504 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12505 I915_GEM_DOMAIN_RENDER << 16 | 12506 KGEM_RELOC_FENCED, 12507 0); 12508 sna->kgem.nbatch += 8; 12509 } 12510 12511 n_this_time = n; 12512 rem = kgem_batch_space(&sna->kgem); 12513 if (3*n_this_time > rem) 12514 n_this_time = rem / 3; 12515 assert(n_this_time); 12516 n -= n_this_time; 12517 12518 assert(sna->kgem.mode == KGEM_BLT); 12519 b = sna->kgem.batch + sna->kgem.nbatch; 12520 sna->kgem.nbatch += 3*n_this_time; 12521 do { 12522 assert(r->x + dx >= 0); 12523 assert(r->y + dy >= 0); 12524 assert(r->x + dx + r->width <= pixmap->drawable.width); 12525 assert(r->y + dy + r->height <= pixmap->drawable.height); 12526 12527 b[0] = br00; 12528 b[1] = (r->y + dy) << 16 | (r->x + dx); 12529 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 12530 b += 3; r++; 12531 } while (--n_this_time); 12532 12533 if (!n) 12534 break; 12535 12536 _kgem_submit(&sna->kgem); 12537 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12538 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12539 } while (1); 12540 } else { 12541 RegionRec clip; 12542 uint16_t unwind_batch, unwind_reloc; 12543 12544 region_set(&clip, extents); 12545 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 12546 goto done; 12547 12548 unwind_batch = sna->kgem.nbatch; 12549 unwind_reloc = sna->kgem.nreloc; 12550 12551 assert(sna->kgem.mode == KGEM_BLT); 12552 b = sna->kgem.batch + sna->kgem.nbatch; 12553 if (sna->kgem.gen >= 0100) { 12554 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12555 b[1] = br13; 12556 b[2] = 0; 12557 b[3] = 0; 12558 *(uint64_t *)(b+4) = 12559 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12560 I915_GEM_DOMAIN_RENDER << 16 | 12561 I915_GEM_DOMAIN_RENDER | 12562 KGEM_RELOC_FENCED, 12563 0); 12564 b[6] = gc->bgPixel; 12565 b[7] = gc->fgPixel; 12566 *(uint64_t *)(b+8) = 12567 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12568 I915_GEM_DOMAIN_RENDER << 16 | 12569 KGEM_RELOC_FENCED, 12570 0); 12571 sna->kgem.nbatch += 10; 12572 } else { 12573 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12574 b[1] = br13; 12575 b[2] = 0; 12576 b[3] = 0; 12577 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12578 I915_GEM_DOMAIN_RENDER << 16 | 12579 I915_GEM_DOMAIN_RENDER | 12580 KGEM_RELOC_FENCED, 12581 0); 12582 b[5] = gc->bgPixel; 12583 b[6] = gc->fgPixel; 12584 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12585 I915_GEM_DOMAIN_RENDER << 16 | 12586 KGEM_RELOC_FENCED, 12587 0); 12588 sna->kgem.nbatch += 8; 12589 } 12590 12591 if (clip.data == NULL) { 12592 const BoxRec *c = &clip.extents; 12593 DBG(("%s: simple clip, %d boxes\n", __FUNCTION__, n)); 12594 while (n--) { 12595 BoxRec box; 12596 12597 box.x1 = r->x + drawable->x; 12598 box.y1 = r->y + drawable->y; 12599 box.x2 = bound(box.x1, r->width); 12600 box.y2 = bound(box.y1, r->height); 12601 r++; 12602 12603 if (box_intersect(&box, c)) { 12604 if (!kgem_check_batch(&sna->kgem, 3)) { 12605 _kgem_submit(&sna->kgem); 12606 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12607 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12608 12609 unwind_batch = sna->kgem.nbatch; 12610 unwind_reloc = sna->kgem.nreloc; 12611 12612 assert(sna->kgem.mode == KGEM_BLT); 12613 b = sna->kgem.batch + sna->kgem.nbatch; 12614 if (sna->kgem.gen >= 0100) { 12615 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12616 b[1] = br13; 12617 b[2] = 0; 12618 b[3] = 0; 12619 *(uint64_t *)(b+4) = 12620 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12621 I915_GEM_DOMAIN_RENDER << 16 | 12622 I915_GEM_DOMAIN_RENDER | 12623 KGEM_RELOC_FENCED, 12624 0); 12625 b[6] = gc->bgPixel; 12626 b[7] = gc->fgPixel; 12627 *(uint64_t *)(b+8) = 12628 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12629 I915_GEM_DOMAIN_RENDER << 16 | 12630 KGEM_RELOC_FENCED, 12631 0); 12632 sna->kgem.nbatch += 10; 12633 } else { 12634 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12635 b[1] = br13; 12636 b[2] = 0; 12637 b[3] = 0; 12638 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12639 I915_GEM_DOMAIN_RENDER << 16 | 12640 I915_GEM_DOMAIN_RENDER | 12641 KGEM_RELOC_FENCED, 12642 0); 12643 b[5] = gc->bgPixel; 12644 b[6] = gc->fgPixel; 12645 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12646 I915_GEM_DOMAIN_RENDER << 16 | 12647 KGEM_RELOC_FENCED, 12648 0); 12649 sna->kgem.nbatch += 8; 12650 } 12651 } 12652 12653 assert(box.x1 + dx >= 0); 12654 assert(box.y1 + dy >= 0); 12655 assert(box.x2 + dx <= pixmap->drawable.width); 12656 assert(box.y2 + dy <= pixmap->drawable.height); 12657 12658 DBG(("%s: box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d)\n", 12659 __FUNCTION__, box.x1, box.y1, box.x2, box.y2, dx, dy, tx, ty)); 12660 12661 assert(sna->kgem.mode == KGEM_BLT); 12662 b = sna->kgem.batch + sna->kgem.nbatch; 12663 b[0] = br00; 12664 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 12665 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 12666 sna->kgem.nbatch += 3; 12667 } 12668 } 12669 } else { 12670 const BoxRec * const clip_start = RegionBoxptr(&clip); 12671 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12672 const BoxRec *c; 12673 12674 DBG(("%s: complex clip (%ld cliprects), %d boxes\n", __FUNCTION__, (long)clip.data->numRects, n)); 12675 do { 12676 BoxRec box; 12677 12678 box.x1 = r->x + drawable->x; 12679 box.y1 = r->y + drawable->y; 12680 box.x2 = bound(box.x1, r->width); 12681 box.y2 = bound(box.y1, r->height); 12682 DBG(("%s: rect=(%d, %d), (%d, %d), box=(%d, %d), (%d, %d)\n", __FUNCTION__, 12683 r->x, r->y, r->width, r->height, 12684 box.x1, box.y1, box.x2, box.y2)); 12685 r++; 12686 12687 c = find_clip_box_for_y(clip_start, 12688 clip_end, 12689 box.y1); 12690 while (c != clip_end) { 12691 BoxRec bb; 12692 12693 DBG(("%s: clip=(%d, %d), (%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2)); 12694 12695 if (box.y2 <= c->y1) 12696 break; 12697 12698 bb = box; 12699 if (box_intersect(&bb, c++)) { 12700 if (!kgem_check_batch(&sna->kgem, 3)) { 12701 DBG(("%s: emitting split batch\n", __FUNCTION__)); 12702 _kgem_submit(&sna->kgem); 12703 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12704 kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo); 12705 12706 unwind_batch = sna->kgem.nbatch; 12707 unwind_reloc = sna->kgem.nreloc; 12708 12709 assert(sna->kgem.mode == KGEM_BLT); 12710 b = sna->kgem.batch + sna->kgem.nbatch; 12711 if (sna->kgem.gen >= 0100) { 12712 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 12713 b[1] = br13; 12714 b[2] = 0; 12715 b[3] = 0; 12716 *(uint64_t *)(b+4) = 12717 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 12718 I915_GEM_DOMAIN_RENDER << 16 | 12719 I915_GEM_DOMAIN_RENDER | 12720 KGEM_RELOC_FENCED, 12721 0); 12722 b[6] = gc->bgPixel; 12723 b[7] = gc->fgPixel; 12724 *(uint64_t *)(b+8) = 12725 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 8, tile_bo, 12726 I915_GEM_DOMAIN_RENDER << 16 | 12727 KGEM_RELOC_FENCED, 12728 0); 12729 sna->kgem.nbatch += 10; 12730 } else { 12731 b[0] = XY_SETUP_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 6; 12732 b[1] = br13; 12733 b[2] = 0; 12734 b[3] = 0; 12735 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 12736 I915_GEM_DOMAIN_RENDER << 16 | 12737 I915_GEM_DOMAIN_RENDER | 12738 KGEM_RELOC_FENCED, 12739 0); 12740 b[5] = gc->bgPixel; 12741 b[6] = gc->fgPixel; 12742 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 12743 I915_GEM_DOMAIN_RENDER << 16 | 12744 KGEM_RELOC_FENCED, 12745 0); 12746 sna->kgem.nbatch += 8; 12747 } 12748 } 12749 12750 assert(bb.x1 + dx >= 0); 12751 assert(bb.y1 + dy >= 0); 12752 assert(bb.x2 + dx <= pixmap->drawable.width); 12753 assert(bb.y2 + dy <= pixmap->drawable.height); 12754 12755 DBG(("%s: emit box=(%d, %d),(%d, %d) + (%d, %d), tile=(%d, %d) [relative to drawable: (%d, %d)]\n", 12756 __FUNCTION__, bb.x1, bb.y1, bb.x2, bb.y2, dx, dy, tx, ty, bb.x1 - drawable->x, bb.y1 - drawable->y)); 12757 12758 assert(sna->kgem.mode == KGEM_BLT); 12759 b = sna->kgem.batch + sna->kgem.nbatch; 12760 b[0] = br00; 12761 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 12762 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 12763 sna->kgem.nbatch += 3; 12764 } 12765 } 12766 } while (--n); 12767 } 12768 12769 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 12770 sna->kgem.nbatch = unwind_batch; 12771 sna->kgem.nreloc = unwind_reloc; 12772 if (sna->kgem.nbatch == 0) 12773 kgem_bo_pair_undo(&sna->kgem, bo, tile_bo); 12774 } 12775 } 12776done: 12777 assert_pixmap_damage(pixmap); 12778 blt_done(sna); 12779 return true; 12780} 12781 12782static bool tile8(int x) 12783{ 12784 switch(x) { 12785 case 1: 12786 case 2: 12787 case 4: 12788 case 8: 12789 return true; 12790 default: 12791 return false; 12792 } 12793} 12794 12795static int next8(int x, int max) 12796{ 12797 if (x > 2 && x <= 4) 12798 x = 4; 12799 else if (x < 8) 12800 x = 8; 12801 return MIN(x, max); 12802} 12803 12804static bool 12805sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable, 12806 struct kgem_bo *bo, 12807 struct sna_damage **damage, 12808 GCPtr gc, int n, const xRectangle *rect, 12809 const BoxRec *extents, unsigned clipped) 12810{ 12811 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12812 struct sna *sna = to_sna_from_pixmap(pixmap); 12813 PixmapPtr tile = gc->tile.pixmap; 12814 int w, h, tx, ty, tw, th, bpp = tile->drawable.bitsPerPixel; 12815 const DDXPointRec origin = gc->patOrg; 12816 struct kgem_bo *upload; 12817 bool ret = false; 12818 uint8_t *src; 12819 void *ptr; 12820 12821 tx = 0, tw = tile->drawable.width; 12822 if (!tile8(tw) && tw > extents->x2 - extents->x1) { 12823 tx = (extents->x1 - gc->patOrg.x - drawable->x) % tw; 12824 if (tx < 0) 12825 tx += tw; 12826 tw = next8(extents->x2 - extents->x1, tw); 12827 gc->patOrg.x = extents->x1 - drawable->x; 12828 } 12829 12830 ty = 0, th = tile->drawable.height; 12831 if (!tile8(th) && th > extents->y2 - extents->y1) { 12832 ty = (extents->y1 - gc->patOrg.y - drawable->y) % th; 12833 if (ty < 0) 12834 ty += th; 12835 th = next8(extents->y2 - extents->y1, th); 12836 gc->patOrg.y = extents->y1 - drawable->y; 12837 } 12838 12839 DBG(("%s: %dx%d+%d+%d (full tile size %dx%d)\n", __FUNCTION__, 12840 tw, th, tx, ty, tile->drawable.width, tile->drawable.height)); 12841 assert(tx < tile->drawable.width && tx >= 0); 12842 assert(ty < tile->drawable.height && ty >= 0); 12843 assert(tw && tw <= 8 && tw <= tile->drawable.width); 12844 assert(is_power_of_two(tw)); 12845 assert(th && th <= 8 && th <= tile->drawable.height); 12846 assert(is_power_of_two(th)); 12847 12848 if (!sna_pixmap_move_to_cpu(tile, MOVE_READ)) 12849 goto out_gc; 12850 12851 assert(tile->devKind); 12852 assert(has_coherent_ptr(sna, sna_pixmap(tile), MOVE_READ)); 12853 12854 src = tile->devPrivate.ptr; 12855 src += tile->devKind * ty; 12856 src += tx * bpp/8; 12857 12858 if ((tw | th) == 1) { 12859 uint32_t pixel; 12860 switch (bpp) { 12861 case 32: pixel = *(uint32_t *)src; break; 12862 case 16: pixel = *(uint16_t *)src; break; 12863 default: pixel = *(uint8_t *)src; break; 12864 } 12865 return sna_poly_fill_rect_blt(drawable, bo, damage, 12866 gc, pixel, n, rect, 12867 extents, clipped); 12868 } 12869 12870 upload = kgem_create_buffer(&sna->kgem, 8*bpp, KGEM_BUFFER_WRITE, &ptr); 12871 if (upload == NULL) 12872 goto out_gc; 12873 12874 upload->pitch = bpp; /* for sanity checks */ 12875 12876 if (sigtrap_get() == 0) { 12877 uint8_t *dst = ptr; 12878 if (tx + tw > tile->drawable.width || 12879 ty + th > tile->drawable.height) { 12880 int sy = ty; 12881 src = tile->devPrivate.ptr; 12882 for (h = 0; h < th; h++) { 12883 int sx = tx; 12884 for (w = 0; w < tw; w++) { 12885 memcpy(dst + w*bpp/8, src + sy * tile->devKind + sx*bpp/8, bpp/8); 12886 if (++sx == tile->drawable.width) 12887 sx = 0; 12888 } 12889 w *= bpp/8; 12890 while (w < bpp) { 12891 memcpy(dst+w, dst, w); 12892 w *= 2; 12893 } 12894 if (++sy == tile->drawable.height) 12895 sy = 0; 12896 dst += bpp; 12897 } 12898 while (h < 8) { 12899 memcpy(dst, ptr, bpp*h); 12900 dst += bpp * h; 12901 h *= 2; 12902 } 12903 } else { 12904 for (h = 0; h < th; h++) { 12905 w = tw*bpp/8; 12906 memcpy(dst, src, w); 12907 while (w < bpp) { 12908 memcpy(dst+w, dst, w); 12909 w *= 2; 12910 } 12911 assert(w == bpp); 12912 12913 src += tile->devKind; 12914 dst += bpp; 12915 } 12916 while (h < 8) { 12917 memcpy(dst, ptr, bpp*h); 12918 dst += bpp * h; 12919 h *= 2; 12920 } 12921 assert(h == 8); 12922 } 12923 12924 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 12925 upload, gc, n, rect, 12926 extents, clipped); 12927 sigtrap_put(); 12928 } 12929 12930 kgem_bo_destroy(&sna->kgem, upload); 12931out_gc: 12932 gc->patOrg = origin; 12933 return ret; 12934} 12935 12936inline static bool tile_is_solid(GCPtr gc, uint32_t *pixel) 12937{ 12938 PixmapPtr tile = gc->tile.pixmap; 12939 struct sna_pixmap *priv; 12940 12941 if ((tile->drawable.width | tile->drawable.height) == 1) { 12942 DBG(("%s: single pixel tile pixmap, converting to solid fill\n", __FUNCTION__)); 12943 *pixel = get_pixel(tile); 12944 return true; 12945 } 12946 12947 priv = sna_pixmap(tile); 12948 if (priv == NULL || !priv->clear) 12949 return false; 12950 12951 DBG(("%s: tile is clear, converting to solid fill\n", __FUNCTION__)); 12952 *pixel = priv->clear_color; 12953 return true; 12954} 12955 12956static bool 12957sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 12958 struct kgem_bo *bo, 12959 struct sna_damage **damage, 12960 GCPtr gc, int n, xRectangle *rect, 12961 const BoxRec *extents, unsigned clipped) 12962{ 12963 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12964 struct sna *sna = to_sna_from_pixmap(pixmap); 12965 PixmapPtr tile = gc->tile.pixmap; 12966 struct kgem_bo *tile_bo; 12967 const DDXPointRec * const origin = &gc->patOrg; 12968 struct sna_copy_op copy; 12969 CARD32 alu = gc->alu; 12970 int tile_width, tile_height; 12971 int16_t dx, dy; 12972 uint32_t pixel; 12973 12974 DBG(("%s pixmap=%ld, x %d [(%d, %d)x(%d, %d)...], clipped? %d\n", 12975 __FUNCTION__, pixmap->drawable.serialNumber, 12976 n, rect->x, rect->y, rect->width, rect->height, 12977 clipped)); 12978 12979 assert(tile->drawable.depth == drawable->depth); 12980 assert(bo); 12981 12982 if (tile_is_solid(gc, &pixel)) 12983 return sna_poly_fill_rect_blt(drawable, bo, damage, 12984 gc, pixel, 12985 n, rect, 12986 extents, clipped); 12987 12988 /* XXX [248]x[238] tiling can be reduced to a pattern fill. 12989 * Also we can do the lg2 reduction for BLT and use repeat modes for 12990 * RENDER. 12991 */ 12992 12993 tile_width = tile->drawable.width; 12994 tile_height = tile->drawable.height; 12995 if ((tile_width | tile_height) == 8) { 12996 bool ret; 12997 12998 DBG(("%s: have 8x8 tile, using BLT fast path\n", __FUNCTION__)); 12999 13000 tile_bo = sna_pixmap_get_source_bo(tile); 13001 if (tile_bo == NULL) { 13002 DBG(("%s: unable to move tile go GPU, fallback\n", 13003 __FUNCTION__)); 13004 return false; 13005 } 13006 13007 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 13008 tile_bo, gc, n, rect, 13009 extents, clipped); 13010 if (ret) { 13011 kgem_bo_destroy(&sna->kgem, tile_bo); 13012 return true; 13013 } 13014 } else { 13015 int w = tile_width, h = tile_height; 13016 struct sna_pixmap *priv = sna_pixmap(tile); 13017 13018 if (priv == NULL || priv->gpu_damage == NULL) { 13019 w = next8(extents->x2 - extents->x1, w); 13020 h = next8(extents->y2 - extents->y1, h); 13021 } 13022 13023 DBG(("%s: not 8x8, triming size for tile: %dx%d from %dx%d (area %dx%d)\n", 13024 __FUNCTION__, w, h, tile_width, tile_height, extents->x2-extents->x1, extents->y2-extents->y1)); 13025 13026 if ((w|h) < 0x10 && is_power_of_two(w) && is_power_of_two(h) && 13027 sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage, 13028 gc, n, rect, 13029 extents, clipped)) 13030 return true; 13031 13032 tile_bo = sna_pixmap_get_source_bo(tile); 13033 if (tile_bo == NULL) { 13034 DBG(("%s: unable to move tile go GPU, fallback\n", 13035 __FUNCTION__)); 13036 return false; 13037 } 13038 } 13039 13040 if (!sna_copy_init_blt(©, sna, tile, tile_bo, pixmap, bo, alu)) { 13041 DBG(("%s: unsupported blt\n", __FUNCTION__)); 13042 kgem_bo_destroy(&sna->kgem, tile_bo); 13043 return false; 13044 } 13045 13046 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13047 DBG(("%s: drawable offset into pixmap(%ld) = (%d, %d)\n", 13048 __FUNCTION__, pixmap->drawable.serialNumber, dx, dy)); 13049 if (!clipped) { 13050 dx += drawable->x; 13051 dy += drawable->y; 13052 13053 sna_damage_add_rectangles(damage, rect, n, dx, dy); 13054 do { 13055 xRectangle r = *rect++; 13056 int16_t tile_y = (r.y - origin->y) % tile_height; 13057 if (tile_y < 0) 13058 tile_y += tile_height; 13059 13060 assert(r.x + dx >= 0); 13061 assert(r.y + dy >= 0); 13062 assert(r.x + dx + r.width <= pixmap->drawable.width); 13063 assert(r.y + dy + r.height <= pixmap->drawable.height); 13064 13065 r.y += dy; 13066 do { 13067 int16_t width = r.width; 13068 int16_t x = r.x + dx, tile_x; 13069 int16_t h = tile_height - tile_y; 13070 if (h > r.height) 13071 h = r.height; 13072 r.height -= h; 13073 13074 tile_x = (r.x - origin->x) % tile_width; 13075 if (tile_x < 0) 13076 tile_x += tile_width; 13077 13078 do { 13079 int16_t w = tile_width - tile_x; 13080 if (w > width) 13081 w = width; 13082 width -= w; 13083 13084 copy.blt(sna, ©, 13085 tile_x, tile_y, 13086 w, h, 13087 x, r.y); 13088 13089 x += w; 13090 tile_x = 0; 13091 } while (width); 13092 r.y += h; 13093 tile_y = 0; 13094 } while (r.height); 13095 } while (--n); 13096 } else { 13097 RegionRec clip; 13098 13099 region_set(&clip, extents); 13100 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13101 goto done; 13102 13103 if (clip.data == NULL) { 13104 const BoxRec *box = &clip.extents; 13105 DBG(("%s: single clip box [(%d, %d), (%d, %d)]\n", 13106 __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 13107 while (n--) { 13108 BoxRec r; 13109 13110 r.x1 = rect->x + drawable->x; 13111 r.y1 = rect->y + drawable->y; 13112 r.x2 = bound(r.x1, rect->width); 13113 r.y2 = bound(r.y1, rect->height); 13114 rect++; 13115 13116 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 13117 __FUNCTION__, r.x1, r.y1, r.x2, r.y2)); 13118 13119 if (box_intersect(&r, box)) { 13120 int height = r.y2 - r.y1; 13121 int dst_y = r.y1; 13122 int tile_y = (r.y1 - drawable->y - origin->y) % tile_height; 13123 if (tile_y < 0) 13124 tile_y += tile_height; 13125 13126 assert(r.x1 + dx >= 0); 13127 assert(r.y1 + dy >= 0); 13128 assert(r.x2 + dx <= pixmap->drawable.width); 13129 assert(r.y2 + dy <= pixmap->drawable.height); 13130 13131 while (height) { 13132 int width = r.x2 - r.x1; 13133 int dst_x = r.x1, tile_x; 13134 int h = tile_height - tile_y; 13135 if (h > height) 13136 h = height; 13137 height -= h; 13138 13139 tile_x = (r.x1 - drawable->x - origin->x) % tile_width; 13140 if (tile_x < 0) 13141 tile_x += tile_width; 13142 13143 while (width > 0) { 13144 int w = tile_width - tile_x; 13145 if (w > width) 13146 w = width; 13147 width -= w; 13148 13149 copy.blt(sna, ©, 13150 tile_x, tile_y, 13151 w, h, 13152 dst_x + dx, dst_y + dy); 13153 if (damage) { 13154 BoxRec b; 13155 13156 b.x1 = dst_x + dx; 13157 b.y1 = dst_y + dy; 13158 b.x2 = b.x1 + w; 13159 b.y2 = b.y1 + h; 13160 13161 assert_pixmap_contains_box(pixmap, &b); 13162 sna_damage_add_box(damage, &b); 13163 } 13164 13165 dst_x += w; 13166 tile_x = 0; 13167 } 13168 dst_y += h; 13169 tile_y = 0; 13170 } 13171 } 13172 } 13173 } else { 13174 while (n--) { 13175 RegionRec region; 13176 const BoxRec *box; 13177 int nbox; 13178 13179 region.extents.x1 = rect->x + drawable->x; 13180 region.extents.y1 = rect->y + drawable->y; 13181 region.extents.x2 = bound(region.extents.x1, rect->width); 13182 region.extents.y2 = bound(region.extents.y1, rect->height); 13183 rect++; 13184 13185 DBG(("%s: rectangle [(%d, %d), (%d, %d)]\n", 13186 __FUNCTION__, 13187 region.extents.x1, 13188 region.extents.y1, 13189 region.extents.x2, 13190 region.extents.y2)); 13191 13192 region.data = NULL; 13193 RegionIntersect(®ion, ®ion, &clip); 13194 13195 assert(region.extents.x1 + dx >= 0); 13196 assert(region.extents.y1 + dy >= 0); 13197 assert(region.extents.x2 + dx <= pixmap->drawable.width); 13198 assert(region.extents.y2 + dy <= pixmap->drawable.height); 13199 13200 nbox = region_num_rects(®ion); 13201 box = region_rects(®ion); 13202 DBG(("%s: split into %d boxes after clipping\n", __FUNCTION__, nbox)); 13203 while (nbox--) { 13204 int height = box->y2 - box->y1; 13205 int dst_y = box->y1; 13206 int tile_y = (box->y1 - drawable->y - origin->y) % tile_height; 13207 if (tile_y < 0) 13208 tile_y += tile_height; 13209 13210 while (height) { 13211 int width = box->x2 - box->x1; 13212 int dst_x = box->x1, tile_x; 13213 int h = tile_height - tile_y; 13214 if (h > height) 13215 h = height; 13216 height -= h; 13217 13218 tile_x = (box->x1 - drawable->x - origin->x) % tile_width; 13219 if (tile_x < 0) 13220 tile_x += tile_width; 13221 13222 while (width > 0) { 13223 int w = tile_width - tile_x; 13224 if (w > width) 13225 w = width; 13226 width -= w; 13227 13228 copy.blt(sna, ©, 13229 tile_x, tile_y, 13230 w, h, 13231 dst_x + dx, dst_y + dy); 13232 if (damage) { 13233 BoxRec b; 13234 13235 b.x1 = dst_x + dx; 13236 b.y1 = dst_y + dy; 13237 b.x2 = b.x1 + w; 13238 b.y2 = b.y1 + h; 13239 13240 assert_pixmap_contains_box(pixmap, &b); 13241 sna_damage_add_box(damage, &b); 13242 } 13243 13244 dst_x += w; 13245 tile_x = 0; 13246 } 13247 dst_y += h; 13248 tile_y = 0; 13249 } 13250 box++; 13251 } 13252 13253 RegionUninit(®ion); 13254 } 13255 } 13256 13257 RegionUninit(&clip); 13258 } 13259done: 13260 copy.done(sna, ©); 13261 assert_pixmap_damage(pixmap); 13262 kgem_bo_destroy(&sna->kgem, tile_bo); 13263 return true; 13264} 13265 13266static bool 13267sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, 13268 struct kgem_bo *bo, 13269 struct sna_damage **damage, 13270 GCPtr gc, int n, xRectangle *r, 13271 const BoxRec *extents, unsigned clipped) 13272{ 13273 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13274 struct sna *sna = to_sna_from_pixmap(pixmap); 13275 uint32_t pat[2] = {0, 0}, br00, br13; 13276 int16_t dx, dy; 13277 uint32_t *b; 13278 13279 if (NO_STIPPLE_8x8) 13280 return false; 13281 13282 DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n", 13283 __FUNCTION__, gc->alu, 13284 extents->x1, extents->y1, 13285 extents->x2, extents->y2, 13286 gc->patOrg.x, gc->patOrg.y)); 13287 13288 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13289 { 13290 int px, py; 13291 13292 px = (0 - gc->patOrg.x - drawable->x - dx) % 8; 13293 if (px < 0) 13294 px += 8; 13295 13296 py = (0 - gc->patOrg.y - drawable->y - dy) % 8; 13297 if (py < 0) 13298 py += 8; 13299 DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py)); 13300 13301 br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20; 13302 br13 = bo->pitch; 13303 if (sna->kgem.gen >= 040 && bo->tiling) { 13304 br00 |= BLT_DST_TILED; 13305 br13 >>= 2; 13306 } 13307 br13 |= (gc->fillStyle == FillStippled) << 28; 13308 br13 |= blt_depth(drawable->depth) << 24; 13309 br13 |= fill_ROP[gc->alu] << 16; 13310 } 13311 13312 assert(gc->stipple->devKind); 13313 { 13314 uint8_t *dst = (uint8_t *)pat; 13315 const uint8_t *src = gc->stipple->devPrivate.ptr; 13316 int stride = gc->stipple->devKind; 13317 int j = gc->stipple->drawable.height; 13318 do { 13319 *dst++ = byte_reverse(*src); 13320 src += stride; 13321 } while (--j); 13322 } 13323 13324 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13325 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13326 if (!kgem_check_batch(&sna->kgem, 10 + 2*3) || 13327 !kgem_check_bo_fenced(&sna->kgem, bo) || 13328 !kgem_check_reloc(&sna->kgem, 1)) { 13329 kgem_submit(&sna->kgem); 13330 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13331 return false; 13332 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13333 } 13334 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13335 13336 if (!clipped) { 13337 dx += drawable->x; 13338 dy += drawable->y; 13339 13340 sna_damage_add_rectangles(damage, r, n, dx, dy); 13341 if (n == 1) { 13342 DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n", 13343 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13344 13345 assert(sna->kgem.mode == KGEM_BLT); 13346 b = sna->kgem.batch + sna->kgem.nbatch; 13347 if (sna->kgem.gen >= 0100) { 13348 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 8; 13349 b[1] = br13; 13350 b[2] = (r->y + dy) << 16 | (r->x + dx); 13351 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13352 *(uint64_t *)(b+4) = 13353 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13354 I915_GEM_DOMAIN_RENDER << 16 | 13355 I915_GEM_DOMAIN_RENDER | 13356 KGEM_RELOC_FENCED, 13357 0); 13358 b[6] = gc->bgPixel; 13359 b[7] = gc->fgPixel; 13360 b[8] = pat[0]; 13361 b[9] = pat[1]; 13362 sna->kgem.nbatch += 10; 13363 } else { 13364 b[0] = XY_MONO_PAT | (br00 & 0x7f00) | 3<<20 | 7; 13365 b[1] = br13; 13366 b[2] = (r->y + dy) << 16 | (r->x + dx); 13367 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13368 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13369 I915_GEM_DOMAIN_RENDER << 16 | 13370 I915_GEM_DOMAIN_RENDER | 13371 KGEM_RELOC_FENCED, 13372 0); 13373 b[5] = gc->bgPixel; 13374 b[6] = gc->fgPixel; 13375 b[7] = pat[0]; 13376 b[8] = pat[1]; 13377 sna->kgem.nbatch += 9; 13378 } 13379 } else do { 13380 int n_this_time, rem; 13381 13382 assert(sna->kgem.mode == KGEM_BLT); 13383 b = sna->kgem.batch + sna->kgem.nbatch; 13384 if (sna->kgem.gen >= 0100) { 13385 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13386 b[1] = br13; 13387 b[2] = 0; 13388 b[3] = 0; 13389 *(uint64_t *)(b+4) = 13390 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13391 I915_GEM_DOMAIN_RENDER << 16 | 13392 I915_GEM_DOMAIN_RENDER | 13393 KGEM_RELOC_FENCED, 13394 0); 13395 b[6] = gc->bgPixel; 13396 b[7] = gc->fgPixel; 13397 b[8] = pat[0]; 13398 b[9] = pat[1]; 13399 sna->kgem.nbatch += 10; 13400 } else { 13401 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13402 b[1] = br13; 13403 b[2] = 0; 13404 b[3] = 0; 13405 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13406 I915_GEM_DOMAIN_RENDER << 16 | 13407 I915_GEM_DOMAIN_RENDER | 13408 KGEM_RELOC_FENCED, 13409 0); 13410 b[5] = gc->bgPixel; 13411 b[6] = gc->fgPixel; 13412 b[7] = pat[0]; 13413 b[8] = pat[1]; 13414 sna->kgem.nbatch += 9; 13415 } 13416 13417 n_this_time = n; 13418 rem = kgem_batch_space(&sna->kgem); 13419 if (3*n_this_time > rem) 13420 n_this_time = rem / 3; 13421 assert(n_this_time); 13422 n -= n_this_time; 13423 13424 assert(sna->kgem.mode == KGEM_BLT); 13425 b = sna->kgem.batch + sna->kgem.nbatch; 13426 sna->kgem.nbatch += 3 * n_this_time; 13427 do { 13428 DBG(("%s: rect (%d, %d)x(%d, %d)\n", 13429 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 13430 assert(r->x + dx >= 0); 13431 assert(r->y + dy >= 0); 13432 assert(r->x + dx + r->width <= pixmap->drawable.width); 13433 assert(r->y + dy + r->height <= pixmap->drawable.height); 13434 13435 b[0] = br00; 13436 b[1] = (r->y + dy) << 16 | (r->x + dx); 13437 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13438 13439 b += 3; r++; 13440 } while(--n_this_time); 13441 13442 if (!n) 13443 break; 13444 13445 _kgem_submit(&sna->kgem); 13446 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13447 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13448 } while (1); 13449 } else { 13450 RegionRec clip; 13451 13452 region_set(&clip, extents); 13453 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13454 return true; 13455 13456 assert(sna->kgem.mode == KGEM_BLT); 13457 b = sna->kgem.batch + sna->kgem.nbatch; 13458 if (sna->kgem.gen >= 0100) { 13459 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13460 b[1] = br13; 13461 b[2] = 0; 13462 b[3] = 0; 13463 *(uint64_t *)(b+4) = 13464 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13465 I915_GEM_DOMAIN_RENDER << 16 | 13466 I915_GEM_DOMAIN_RENDER | 13467 KGEM_RELOC_FENCED, 13468 0); 13469 b[6] = gc->bgPixel; 13470 b[7] = gc->fgPixel; 13471 b[8] = pat[0]; 13472 b[9] = pat[1]; 13473 sna->kgem.nbatch += 10; 13474 } else { 13475 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13476 b[1] = br13; 13477 b[2] = 0; 13478 b[3] = 0; 13479 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13480 I915_GEM_DOMAIN_RENDER << 16 | 13481 I915_GEM_DOMAIN_RENDER | 13482 KGEM_RELOC_FENCED, 13483 0); 13484 b[5] = gc->bgPixel; 13485 b[6] = gc->fgPixel; 13486 b[7] = pat[0]; 13487 b[8] = pat[1]; 13488 sna->kgem.nbatch += 9; 13489 } 13490 13491 if (clip.data == NULL) { 13492 do { 13493 BoxRec box; 13494 13495 box.x1 = r->x + drawable->x; 13496 box.y1 = r->y + drawable->y; 13497 box.x2 = bound(box.x1, r->width); 13498 box.y2 = bound(box.y1, r->height); 13499 r++; 13500 13501 if (box_intersect(&box, &clip.extents)) { 13502 if (!kgem_check_batch(&sna->kgem, 3)) { 13503 _kgem_submit(&sna->kgem); 13504 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13505 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13506 13507 assert(sna->kgem.mode == KGEM_BLT); 13508 b = sna->kgem.batch + sna->kgem.nbatch; 13509 if (sna->kgem.gen >= 0100) { 13510 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13511 b[1] = br13; 13512 b[2] = 0; 13513 b[3] = 0; 13514 *(uint64_t *)(b+4) = 13515 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13516 I915_GEM_DOMAIN_RENDER << 16 | 13517 I915_GEM_DOMAIN_RENDER | 13518 KGEM_RELOC_FENCED, 13519 0); 13520 b[6] = gc->bgPixel; 13521 b[7] = gc->fgPixel; 13522 b[8] = pat[0]; 13523 b[9] = pat[1]; 13524 sna->kgem.nbatch += 10; 13525 } else { 13526 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13527 b[1] = br13; 13528 b[2] = 0; 13529 b[3] = 0; 13530 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13531 I915_GEM_DOMAIN_RENDER << 16 | 13532 I915_GEM_DOMAIN_RENDER | 13533 KGEM_RELOC_FENCED, 13534 0); 13535 b[5] = gc->bgPixel; 13536 b[6] = gc->fgPixel; 13537 b[7] = pat[0]; 13538 b[8] = pat[1]; 13539 sna->kgem.nbatch += 9; 13540 } 13541 } 13542 13543 assert(sna->kgem.mode == KGEM_BLT); 13544 b = sna->kgem.batch + sna->kgem.nbatch; 13545 sna->kgem.nbatch += 3; 13546 b[0] = br00; 13547 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 13548 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 13549 } 13550 } while (--n); 13551 } else { 13552 const BoxRec * const clip_start = RegionBoxptr(&clip); 13553 const BoxRec * const clip_end = clip_start + clip.data->numRects; 13554 const BoxRec *c; 13555 13556 do { 13557 BoxRec box; 13558 13559 box.x1 = r->x + drawable->x; 13560 box.y1 = r->y + drawable->y; 13561 box.x2 = bound(box.x1, r->width); 13562 box.y2 = bound(box.y1, r->height); 13563 r++; 13564 13565 c = find_clip_box_for_y(clip_start, 13566 clip_end, 13567 box.y1); 13568 while (c != clip_end) { 13569 BoxRec bb; 13570 if (box.y2 <= c->y1) 13571 break; 13572 13573 bb = box; 13574 if (box_intersect(&bb, c++)) { 13575 if (!kgem_check_batch(&sna->kgem, 3)) { 13576 _kgem_submit(&sna->kgem); 13577 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13578 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13579 13580 assert(sna->kgem.mode == KGEM_BLT); 13581 b = sna->kgem.batch + sna->kgem.nbatch; 13582 if (sna->kgem.gen >= 0100) { 13583 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 8; 13584 b[1] = br13; 13585 b[2] = 0; 13586 b[3] = 0; 13587 *(uint64_t *)(b+4) = 13588 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13589 I915_GEM_DOMAIN_RENDER << 16 | 13590 I915_GEM_DOMAIN_RENDER | 13591 KGEM_RELOC_FENCED, 13592 0); 13593 b[6] = gc->bgPixel; 13594 b[7] = gc->fgPixel; 13595 b[8] = pat[0]; 13596 b[9] = pat[1]; 13597 sna->kgem.nbatch += 10; 13598 } else { 13599 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20 | (br00 & BLT_DST_TILED) | 7; 13600 b[1] = br13; 13601 b[2] = 0; 13602 b[3] = 0; 13603 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13604 I915_GEM_DOMAIN_RENDER << 16 | 13605 I915_GEM_DOMAIN_RENDER | 13606 KGEM_RELOC_FENCED, 13607 0); 13608 b[5] = gc->bgPixel; 13609 b[6] = gc->fgPixel; 13610 b[7] = pat[0]; 13611 b[8] = pat[1]; 13612 sna->kgem.nbatch += 9; 13613 } 13614 } 13615 13616 assert(sna->kgem.mode == KGEM_BLT); 13617 b = sna->kgem.batch + sna->kgem.nbatch; 13618 sna->kgem.nbatch += 3; 13619 b[0] = br00; 13620 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 13621 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 13622 } 13623 } 13624 } while (--n); 13625 } 13626 } 13627 13628 assert_pixmap_damage(pixmap); 13629 blt_done(sna); 13630 return true; 13631} 13632 13633static bool 13634sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable, 13635 struct kgem_bo *bo, 13636 struct sna_damage **damage, 13637 GCPtr gc, int n, xRectangle *r, 13638 const BoxRec *extents, unsigned clipped) 13639{ 13640 PixmapPtr scratch, stipple; 13641 uint8_t bytes[8], *dst = bytes; 13642 const uint8_t *src, *end; 13643 int j, stride; 13644 bool ret; 13645 13646 DBG(("%s: expanding %dx%d stipple to 8x8\n", 13647 __FUNCTION__, 13648 gc->stipple->drawable.width, 13649 gc->stipple->drawable.height)); 13650 13651 scratch = GetScratchPixmapHeader(drawable->pScreen, 13652 8, 8, 1, 1, 1, bytes); 13653 if (scratch == NullPixmap) 13654 return false; 13655 13656 stipple = gc->stipple; 13657 gc->stipple = scratch; 13658 13659 assert(stipple->devKind); 13660 stride = stipple->devKind; 13661 src = stipple->devPrivate.ptr; 13662 end = src + stride * stipple->drawable.height; 13663 for(j = 0; j < 8; j++) { 13664 switch (stipple->drawable.width) { 13665 case 1: *dst = (*src & 1) * 0xff; break; 13666 case 2: *dst = (*src & 3) * 0x55; break; 13667 case 4: *dst = (*src & 15) * 0x11; break; 13668 case 8: *dst = *src; break; 13669 default: assert(0); break; 13670 } 13671 dst++; 13672 src += stride; 13673 if (src == end) 13674 src = stipple->devPrivate.ptr; 13675 } 13676 13677 ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 13678 gc, n, r, extents, clipped); 13679 13680 gc->stipple = stipple; 13681 FreeScratchPixmapHeader(scratch); 13682 13683 return ret; 13684} 13685 13686static bool 13687sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, 13688 struct kgem_bo *bo, 13689 struct sna_damage **damage, 13690 GCPtr gc, int n, xRectangle *r, 13691 const BoxRec *extents, unsigned clipped) 13692{ 13693 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13694 struct sna *sna = to_sna_from_pixmap(pixmap); 13695 PixmapPtr stipple = gc->stipple; 13696 const DDXPointRec *origin = &gc->patOrg; 13697 int16_t dx, dy; 13698 uint32_t br00, br13; 13699 13700 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__, 13701 extents->x1, extents->y1, 13702 extents->x2, extents->y2, 13703 origin->x, origin->y, 13704 clipped)); 13705 13706 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13707 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13708 assert(kgem_bo_can_blt(&sna->kgem, bo)); 13709 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13710 13711 br00 = 3 << 20; 13712 br13 = bo->pitch; 13713 if (sna->kgem.gen >= 040 && bo->tiling) { 13714 br00 |= BLT_DST_TILED; 13715 br13 >>= 2; 13716 } 13717 br13 |= (gc->fillStyle == FillStippled) << 29; 13718 br13 |= blt_depth(drawable->depth) << 24; 13719 br13 |= copy_ROP[gc->alu] << 16; 13720 13721 if (!clipped) { 13722 dx += drawable->x; 13723 dy += drawable->y; 13724 13725 sna_damage_add_rectangles(damage, r, n, dx, dy); 13726 do { 13727 int bx1 = (r->x - origin->x) & ~7; 13728 int bx2 = (r->x + r->width - origin->x + 7) & ~7; 13729 int bw = (bx2 - bx1)/8; 13730 int bh = r->height; 13731 int bstride = ALIGN(bw, 2); 13732 int src_stride; 13733 uint8_t *dst, *src; 13734 uint32_t *b; 13735 13736 DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d, src_stride=%d]\n", 13737 __FUNCTION__, 13738 r->x, r->y, r->width, r->height, 13739 bx1, bx2, bstride*bh)); 13740 13741 src_stride = bstride*bh; 13742 assert(src_stride > 0); 13743 if (src_stride <= 128) { 13744 src_stride = ALIGN(src_stride, 8) / 4; 13745 assert(src_stride <= 32); 13746 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13747 !kgem_check_bo_fenced(&sna->kgem, bo) || 13748 !kgem_check_reloc(&sna->kgem, 1)) { 13749 kgem_submit(&sna->kgem); 13750 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13751 return false; 13752 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13753 } 13754 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13755 13756 assert(sna->kgem.mode == KGEM_BLT); 13757 b = sna->kgem.batch + sna->kgem.nbatch; 13758 if (sna->kgem.gen >= 0100) { 13759 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13760 b[0] |= ((r->x - origin->x) & 7) << 17; 13761 b[1] = br13; 13762 b[2] = (r->y + dy) << 16 | (r->x + dx); 13763 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13764 *(uint64_t *)(b+4) = 13765 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13766 I915_GEM_DOMAIN_RENDER << 16 | 13767 I915_GEM_DOMAIN_RENDER | 13768 KGEM_RELOC_FENCED, 13769 0); 13770 b[6] = gc->bgPixel; 13771 b[7] = gc->fgPixel; 13772 13773 dst = (uint8_t *)&b[8]; 13774 sna->kgem.nbatch += 8 + src_stride; 13775 } else { 13776 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13777 b[0] |= ((r->x - origin->x) & 7) << 17; 13778 b[1] = br13; 13779 b[2] = (r->y + dy) << 16 | (r->x + dx); 13780 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13781 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13782 I915_GEM_DOMAIN_RENDER << 16 | 13783 I915_GEM_DOMAIN_RENDER | 13784 KGEM_RELOC_FENCED, 13785 0); 13786 b[5] = gc->bgPixel; 13787 b[6] = gc->fgPixel; 13788 13789 dst = (uint8_t *)&b[7]; 13790 sna->kgem.nbatch += 7 + src_stride; 13791 } 13792 assert(stipple->devKind); 13793 src_stride = stipple->devKind; 13794 src = stipple->devPrivate.ptr; 13795 src += (r->y - origin->y) * src_stride + bx1/8; 13796 src_stride -= bstride; 13797 do { 13798 int i = bstride; 13799 do { 13800 *dst++ = byte_reverse(*src++); 13801 *dst++ = byte_reverse(*src++); 13802 i -= 2; 13803 } while (i); 13804 src += src_stride; 13805 } while (--bh); 13806 } else { 13807 struct kgem_bo *upload; 13808 void *ptr; 13809 13810 if (!kgem_check_batch(&sna->kgem, 10) || 13811 !kgem_check_bo_fenced(&sna->kgem, bo) || 13812 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 13813 kgem_submit(&sna->kgem); 13814 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13815 return false; 13816 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13817 } 13818 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13819 13820 upload = kgem_create_buffer(&sna->kgem, 13821 bstride*bh, 13822 KGEM_BUFFER_WRITE_INPLACE, 13823 &ptr); 13824 if (!upload) 13825 break; 13826 13827 if (sigtrap_get() == 0) { 13828 dst = ptr; 13829 assert(stipple->devKind); 13830 src_stride = stipple->devKind; 13831 src = stipple->devPrivate.ptr; 13832 src += (r->y - origin->y) * src_stride + bx1/8; 13833 src_stride -= bstride; 13834 do { 13835 int i = bstride; 13836 do { 13837 *dst++ = byte_reverse(*src++); 13838 *dst++ = byte_reverse(*src++); 13839 i -= 2; 13840 } while (i); 13841 src += src_stride; 13842 } while (--bh); 13843 13844 assert(sna->kgem.mode == KGEM_BLT); 13845 b = sna->kgem.batch + sna->kgem.nbatch; 13846 if (sna->kgem.gen >= 0100) { 13847 b[0] = XY_MONO_SRC_COPY | br00 | 8; 13848 b[0] |= ((r->x - origin->x) & 7) << 17; 13849 b[1] = br13; 13850 b[2] = (r->y + dy) << 16 | (r->x + dx); 13851 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13852 *(uint64_t *)(b+4) = 13853 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13854 I915_GEM_DOMAIN_RENDER << 16 | 13855 I915_GEM_DOMAIN_RENDER | 13856 KGEM_RELOC_FENCED, 13857 0); 13858 *(uint64_t *)(b+6) = 13859 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 13860 I915_GEM_DOMAIN_RENDER << 16 | 13861 KGEM_RELOC_FENCED, 13862 0); 13863 b[8] = gc->bgPixel; 13864 b[9] = gc->fgPixel; 13865 sna->kgem.nbatch += 10; 13866 } else { 13867 b[0] = XY_MONO_SRC_COPY | br00 | 6; 13868 b[0] |= ((r->x - origin->x) & 7) << 17; 13869 b[1] = br13; 13870 b[2] = (r->y + dy) << 16 | (r->x + dx); 13871 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 13872 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13873 I915_GEM_DOMAIN_RENDER << 16 | 13874 I915_GEM_DOMAIN_RENDER | 13875 KGEM_RELOC_FENCED, 13876 0); 13877 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 13878 I915_GEM_DOMAIN_RENDER << 16 | 13879 KGEM_RELOC_FENCED, 13880 0); 13881 b[6] = gc->bgPixel; 13882 b[7] = gc->fgPixel; 13883 13884 sna->kgem.nbatch += 8; 13885 } 13886 sigtrap_put(); 13887 } 13888 13889 kgem_bo_destroy(&sna->kgem, upload); 13890 } 13891 13892 r++; 13893 } while (--n); 13894 } else { 13895 RegionRec clip; 13896 DDXPointRec pat; 13897 13898 region_set(&clip, extents); 13899 if (!region_maybe_clip(&clip, gc->pCompositeClip)) 13900 return true; 13901 13902 DBG(("%s: clip.extents=[(%d, %d), (%d, %d)] region?=%d\n", 13903 __FUNCTION__, 13904 clip.extents.x1, clip.extents.y1, 13905 clip.extents.x2, clip.extents.y2, 13906 clip.data ? clip.data->numRects : 0)); 13907 13908 pat.x = origin->x + drawable->x; 13909 pat.y = origin->y + drawable->y; 13910 13911 if (clip.data == NULL) { 13912 do { 13913 BoxRec box; 13914 int bx1, bx2, bw, bh, bstride; 13915 int src_stride; 13916 uint8_t *dst, *src; 13917 uint32_t *b; 13918 struct kgem_bo *upload; 13919 void *ptr; 13920 13921 box.x1 = r->x + drawable->x; 13922 box.x2 = bound(box.x1, r->width); 13923 box.y1 = r->y + drawable->y; 13924 box.y2 = bound(box.y1, r->height); 13925 r++; 13926 13927 if (!box_intersect(&box, &clip.extents)) 13928 continue; 13929 13930 bx1 = (box.x1 - pat.x) & ~7; 13931 bx2 = (box.x2 - pat.x + 7) & ~7; 13932 bw = (bx2 - bx1)/8; 13933 bh = box.y2 - box.y1; 13934 bstride = ALIGN(bw, 2); 13935 13936 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d, len=%d\n", 13937 __FUNCTION__, 13938 r->x, r->y, r->width, r->height, 13939 box.x1, box.y1, box.x2, box.y2, 13940 bx1, bx2, bw, bstride, bstride*bh)); 13941 13942 src_stride = bstride*bh; 13943 assert(src_stride > 0); 13944 if (src_stride <= 128) { 13945 src_stride = ALIGN(src_stride, 8) / 4; 13946 assert(src_stride <= 32); 13947 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 13948 !kgem_check_bo_fenced(&sna->kgem, bo) || 13949 !kgem_check_reloc(&sna->kgem, 1)) { 13950 kgem_submit(&sna->kgem); 13951 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13952 return false; 13953 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13954 } 13955 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 13956 13957 assert(sna->kgem.mode == KGEM_BLT); 13958 b = sna->kgem.batch + sna->kgem.nbatch; 13959 if (sna->kgem.gen >= 0100) { 13960 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 13961 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13962 b[1] = br13; 13963 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13964 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13965 *(uint64_t *)(b+4) = 13966 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 13967 I915_GEM_DOMAIN_RENDER << 16 | 13968 I915_GEM_DOMAIN_RENDER | 13969 KGEM_RELOC_FENCED, 13970 0); 13971 b[6] = gc->bgPixel; 13972 b[7] = gc->fgPixel; 13973 13974 dst = (uint8_t *)&b[8]; 13975 sna->kgem.nbatch += 8 + src_stride; 13976 } else { 13977 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 13978 b[0] |= ((box.x1 - pat.x) & 7) << 17; 13979 b[1] = br13; 13980 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 13981 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 13982 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13983 I915_GEM_DOMAIN_RENDER << 16 | 13984 I915_GEM_DOMAIN_RENDER | 13985 KGEM_RELOC_FENCED, 13986 0); 13987 b[5] = gc->bgPixel; 13988 b[6] = gc->fgPixel; 13989 13990 dst = (uint8_t *)&b[7]; 13991 sna->kgem.nbatch += 7 + src_stride; 13992 } 13993 13994 assert(stipple->devKind); 13995 src_stride = stipple->devKind; 13996 src = stipple->devPrivate.ptr; 13997 src += (box.y1 - pat.y) * src_stride + bx1/8; 13998 src_stride -= bstride; 13999 do { 14000 int i = bstride; 14001 do { 14002 *dst++ = byte_reverse(*src++); 14003 *dst++ = byte_reverse(*src++); 14004 i -= 2; 14005 } while (i); 14006 src += src_stride; 14007 } while (--bh); 14008 } else { 14009 if (!kgem_check_batch(&sna->kgem, 10) || 14010 !kgem_check_bo_fenced(&sna->kgem, bo) || 14011 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 14012 kgem_submit(&sna->kgem); 14013 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14014 return false; 14015 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14016 } 14017 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14018 14019 upload = kgem_create_buffer(&sna->kgem, 14020 bstride*bh, 14021 KGEM_BUFFER_WRITE_INPLACE, 14022 &ptr); 14023 if (!upload) 14024 break; 14025 14026 if (sigtrap_get() == 0) { 14027 dst = ptr; 14028 assert(stipple->devKind); 14029 src_stride = stipple->devKind; 14030 src = stipple->devPrivate.ptr; 14031 src += (box.y1 - pat.y) * src_stride + bx1/8; 14032 src_stride -= bstride; 14033 do { 14034 int i = bstride; 14035 do { 14036 *dst++ = byte_reverse(*src++); 14037 *dst++ = byte_reverse(*src++); 14038 i -= 2; 14039 } while (i); 14040 src += src_stride; 14041 } while (--bh); 14042 14043 assert(sna->kgem.mode == KGEM_BLT); 14044 b = sna->kgem.batch + sna->kgem.nbatch; 14045 if (sna->kgem.gen >= 0100) { 14046 b[0] = XY_MONO_SRC_COPY | br00 | 8; 14047 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14048 b[1] = br13; 14049 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14050 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14051 *(uint64_t *)(b+4) = 14052 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14053 I915_GEM_DOMAIN_RENDER << 16 | 14054 I915_GEM_DOMAIN_RENDER | 14055 KGEM_RELOC_FENCED, 14056 0); 14057 *(uint64_t *)(b+6) = 14058 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14059 I915_GEM_DOMAIN_RENDER << 16 | 14060 KGEM_RELOC_FENCED, 14061 0); 14062 b[8] = gc->bgPixel; 14063 b[9] = gc->fgPixel; 14064 sna->kgem.nbatch += 10; 14065 } else { 14066 b[0] = XY_MONO_SRC_COPY | br00 | 6; 14067 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14068 b[1] = br13; 14069 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14070 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14071 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14072 I915_GEM_DOMAIN_RENDER << 16 | 14073 I915_GEM_DOMAIN_RENDER | 14074 KGEM_RELOC_FENCED, 14075 0); 14076 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14077 I915_GEM_DOMAIN_RENDER << 16 | 14078 KGEM_RELOC_FENCED, 14079 0); 14080 b[6] = gc->bgPixel; 14081 b[7] = gc->fgPixel; 14082 14083 sna->kgem.nbatch += 8; 14084 } 14085 sigtrap_put(); 14086 } 14087 kgem_bo_destroy(&sna->kgem, upload); 14088 } 14089 } while (--n); 14090 } else { 14091 const BoxRec * const clip_start = RegionBoxptr(&clip); 14092 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14093 const BoxRec *c; 14094 14095 do { 14096 BoxRec unclipped; 14097 int bx1, bx2, bw, bh, bstride; 14098 int src_stride; 14099 uint8_t *dst, *src; 14100 uint32_t *b; 14101 struct kgem_bo *upload; 14102 void *ptr; 14103 14104 unclipped.x1 = r->x + drawable->x; 14105 unclipped.x2 = bound(unclipped.x1, r->width); 14106 unclipped.y1 = r->y + drawable->y; 14107 unclipped.y2 = bound(unclipped.y1, r->height); 14108 r++; 14109 14110 c = find_clip_box_for_y(clip_start, 14111 clip_end, 14112 unclipped.y1); 14113 while (c != clip_end) { 14114 BoxRec box; 14115 14116 if (unclipped.y2 <= c->y1) 14117 break; 14118 14119 box = unclipped; 14120 if (!box_intersect(&box, c++)) 14121 continue; 14122 14123 bx1 = (box.x1 - pat.x) & ~7; 14124 bx2 = (box.x2 - pat.x + 7) & ~7; 14125 bw = (bx2 - bx1)/8; 14126 bh = box.y2 - box.y1; 14127 bstride = ALIGN(bw, 2); 14128 14129 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n", 14130 __FUNCTION__, 14131 r->x, r->y, r->width, r->height, 14132 box.x1, box.y1, box.x2, box.y2, 14133 bx1, bx2)); 14134 14135 src_stride = bstride*bh; 14136 assert(src_stride > 0); 14137 if (src_stride <= 128) { 14138 src_stride = ALIGN(src_stride, 8) / 4; 14139 assert(src_stride <= 32); 14140 if (!kgem_check_batch(&sna->kgem, 8+src_stride) || 14141 !kgem_check_bo_fenced(&sna->kgem, bo) || 14142 !kgem_check_reloc(&sna->kgem, 1)) { 14143 kgem_submit(&sna->kgem); 14144 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14145 return false; 14146 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14147 } 14148 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14149 14150 assert(sna->kgem.mode == KGEM_BLT); 14151 b = sna->kgem.batch + sna->kgem.nbatch; 14152 if (sna->kgem.gen >= 0100) { 14153 b[0] = XY_MONO_SRC_COPY_IMM | (6 + src_stride) | br00; 14154 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14155 b[1] = br13; 14156 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14157 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14158 *(uint64_t *)(b+4) = 14159 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14160 I915_GEM_DOMAIN_RENDER << 16 | 14161 I915_GEM_DOMAIN_RENDER | 14162 KGEM_RELOC_FENCED, 14163 0); 14164 b[6] = gc->bgPixel; 14165 b[7] = gc->fgPixel; 14166 14167 dst = (uint8_t *)&b[8]; 14168 sna->kgem.nbatch += 8 + src_stride; 14169 } else { 14170 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 14171 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14172 b[1] = br13; 14173 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14174 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14175 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14176 I915_GEM_DOMAIN_RENDER << 16 | 14177 I915_GEM_DOMAIN_RENDER | 14178 KGEM_RELOC_FENCED, 14179 0); 14180 b[5] = gc->bgPixel; 14181 b[6] = gc->fgPixel; 14182 14183 dst = (uint8_t *)&b[7]; 14184 sna->kgem.nbatch += 7 + src_stride; 14185 } 14186 assert(stipple->devKind); 14187 src_stride = stipple->devKind; 14188 src = stipple->devPrivate.ptr; 14189 src += (box.y1 - pat.y) * src_stride + bx1/8; 14190 src_stride -= bstride; 14191 do { 14192 int i = bstride; 14193 do { 14194 *dst++ = byte_reverse(*src++); 14195 *dst++ = byte_reverse(*src++); 14196 i -= 2; 14197 } while (i); 14198 src += src_stride; 14199 } while (--bh); 14200 } else { 14201 if (!kgem_check_batch(&sna->kgem, 10) || 14202 !kgem_check_bo_fenced(&sna->kgem, bo) || 14203 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 14204 kgem_submit(&sna->kgem); 14205 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14206 return false; 14207 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14208 } 14209 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14210 14211 upload = kgem_create_buffer(&sna->kgem, 14212 bstride*bh, 14213 KGEM_BUFFER_WRITE_INPLACE, 14214 &ptr); 14215 if (!upload) 14216 break; 14217 14218 if (sigtrap_get() == 0) { 14219 dst = ptr; 14220 assert(stipple->devKind); 14221 src_stride = stipple->devKind; 14222 src = stipple->devPrivate.ptr; 14223 src += (box.y1 - pat.y) * src_stride + bx1/8; 14224 src_stride -= bstride; 14225 do { 14226 int i = bstride; 14227 do { 14228 *dst++ = byte_reverse(*src++); 14229 *dst++ = byte_reverse(*src++); 14230 i -= 2; 14231 } while (i); 14232 src += src_stride; 14233 } while (--bh); 14234 14235 assert(sna->kgem.mode == KGEM_BLT); 14236 b = sna->kgem.batch + sna->kgem.nbatch; 14237 if (sna->kgem.gen >= 0100) { 14238 b[0] = XY_MONO_SRC_COPY | br00 | 8; 14239 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14240 b[1] = br13; 14241 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14242 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14243 *(uint64_t *)(b+4) = 14244 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14245 I915_GEM_DOMAIN_RENDER << 16 | 14246 I915_GEM_DOMAIN_RENDER | 14247 KGEM_RELOC_FENCED, 14248 0); 14249 *(uint64_t *)(b+6) = 14250 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14251 I915_GEM_DOMAIN_RENDER << 16 | 14252 KGEM_RELOC_FENCED, 14253 0); 14254 b[8] = gc->bgPixel; 14255 b[9] = gc->fgPixel; 14256 sna->kgem.nbatch += 10; 14257 } else { 14258 b[0] = XY_MONO_SRC_COPY | br00 | 6; 14259 b[0] |= ((box.x1 - pat.x) & 7) << 17; 14260 b[1] = br13; 14261 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 14262 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 14263 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14264 I915_GEM_DOMAIN_RENDER << 16 | 14265 I915_GEM_DOMAIN_RENDER | 14266 KGEM_RELOC_FENCED, 14267 0); 14268 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14269 I915_GEM_DOMAIN_RENDER << 16 | 14270 KGEM_RELOC_FENCED, 14271 0); 14272 b[6] = gc->bgPixel; 14273 b[7] = gc->fgPixel; 14274 14275 sna->kgem.nbatch += 8; 14276 } 14277 sigtrap_put(); 14278 } 14279 kgem_bo_destroy(&sna->kgem, upload); 14280 } 14281 } 14282 } while (--n); 14283 14284 } 14285 } 14286 14287 blt_done(sna); 14288 return true; 14289} 14290 14291static void 14292sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, 14293 struct kgem_bo *bo, 14294 uint32_t br00, uint32_t br13, 14295 const GC *gc, 14296 const BoxRec *box, 14297 const DDXPointRec *origin) 14298{ 14299 int x1, x2, y1, y2; 14300 uint32_t *b; 14301 14302 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14303 int oy = (y1 - origin->y) % gc->stipple->drawable.height; 14304 if (oy < 0) 14305 oy += gc->stipple->drawable.height; 14306 14307 y2 = box->y2; 14308 if (y2 - y1 > gc->stipple->drawable.height - oy) 14309 y2 = y1 + gc->stipple->drawable.height - oy; 14310 14311 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14312 int bx1, bx2, bw, bh, len, ox; 14313 uint8_t *dst, *src; 14314 14315 x2 = box->x2; 14316 ox = (x1 - origin->x) % gc->stipple->drawable.width; 14317 if (ox < 0) 14318 ox += gc->stipple->drawable.width; 14319 bx1 = ox & ~7; 14320 bx2 = ox + (x2 - x1); 14321 if (bx2 > gc->stipple->drawable.width) { 14322 bx2 = gc->stipple->drawable.width; 14323 x2 = x1 + bx2-ox; 14324 } 14325 bw = (bx2 - bx1 + 7)/8; 14326 bw = ALIGN(bw, 2); 14327 bh = y2 - y1; 14328 14329 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n", 14330 __FUNCTION__, 14331 x1, y1, x2-x1, y2-y1, 14332 origin->x, origin->y, 14333 ox, oy, bx1, bx2, 14334 gc->stipple->drawable.width, 14335 gc->stipple->drawable.height)); 14336 14337 len = bw*bh; 14338 len = ALIGN(len, 8) / 4; 14339 assert(len > 0); 14340 assert(len <= 32); 14341 if (!kgem_check_batch(&sna->kgem, 8+len) || 14342 !kgem_check_bo_fenced(&sna->kgem, bo) || 14343 !kgem_check_reloc(&sna->kgem, 1)) { 14344 kgem_submit(&sna->kgem); 14345 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14346 return; /* XXX fallback? */ 14347 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14348 } 14349 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14350 14351 assert(sna->kgem.mode == KGEM_BLT); 14352 b = sna->kgem.batch + sna->kgem.nbatch; 14353 if (sna->kgem.gen >= 0100) { 14354 b[0] = br00 | (6 + len) | (ox & 7) << 17; 14355 b[1] = br13; 14356 b[2] = y1 << 16 | x1; 14357 b[3] = y2 << 16 | x2; 14358 *(uint64_t *)(b+4) = 14359 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14360 I915_GEM_DOMAIN_RENDER << 16 | 14361 I915_GEM_DOMAIN_RENDER | 14362 KGEM_RELOC_FENCED, 14363 0); 14364 b[6] = gc->bgPixel; 14365 b[7] = gc->fgPixel; 14366 dst = (uint8_t *)&b[8]; 14367 sna->kgem.nbatch += 8 + len; 14368 } else { 14369 b[0] = br00 | (5 + len) | (ox & 7) << 17; 14370 b[1] = br13; 14371 b[2] = y1 << 16 | x1; 14372 b[3] = y2 << 16 | x2; 14373 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14374 I915_GEM_DOMAIN_RENDER << 16 | 14375 I915_GEM_DOMAIN_RENDER | 14376 KGEM_RELOC_FENCED, 14377 0); 14378 b[5] = gc->bgPixel; 14379 b[6] = gc->fgPixel; 14380 dst = (uint8_t *)&b[7]; 14381 sna->kgem.nbatch += 7 + len; 14382 } 14383 14384 assert(gc->stipple->devKind); 14385 len = gc->stipple->devKind; 14386 src = gc->stipple->devPrivate.ptr; 14387 src += oy*len + ox/8; 14388 len -= bw; 14389 do { 14390 int i = bw; 14391 do { 14392 *dst++ = byte_reverse(*src++); 14393 *dst++ = byte_reverse(*src++); 14394 i -= 2; 14395 } while (i); 14396 src += len; 14397 } while (--bh); 14398 } 14399 } 14400} 14401 14402static void 14403sna_poly_fill_rect_stippled_n_box(struct sna *sna, 14404 struct kgem_bo *bo, 14405 struct kgem_bo **tile, 14406 uint32_t br00, uint32_t br13, 14407 const GC *gc, 14408 const BoxRec *box, 14409 const DDXPointRec *origin) 14410{ 14411 int x1, x2, y1, y2; 14412 int w = gc->stipple->drawable.width; 14413 int h = gc->stipple->drawable.height; 14414 int stride = gc->stipple->devKind; 14415 uint32_t *b; 14416 14417 assert(stride); 14418 if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) { 14419 br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20)); 14420 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14421 br00, br13, gc, 14422 box, origin); 14423 return; 14424 } 14425 14426 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 14427 int row, oy = (y1 - origin->y) % gc->stipple->drawable.height; 14428 if (oy < 0) 14429 oy += h; 14430 14431 y2 = box->y2; 14432 if (y2 - y1 > h - oy) 14433 y2 = y1 + h - oy; 14434 14435 row = oy * stride; 14436 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 14437 int bx1, bx2, bw, bh, len, ox; 14438 bool use_tile; 14439 14440 x2 = box->x2; 14441 ox = (x1 - origin->x) % w; 14442 if (ox < 0) 14443 ox += w; 14444 bx1 = ox & ~7; 14445 bx2 = ox + (x2 - x1); 14446 if (bx2 > w) { 14447 bx2 = w; 14448 x2 = x1 + bx2-ox; 14449 } 14450 14451 use_tile = y2-y1 == h && x2-x1 == w; 14452 14453 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n", 14454 __FUNCTION__, 14455 x1, y1, x2-x1, y2-y1, 14456 origin->x, origin->y, 14457 ox, oy, bx1, bx2, w, h, 14458 use_tile)); 14459 14460 bw = (bx2 - bx1 + 7)/8; 14461 bw = ALIGN(bw, 2); 14462 bh = y2 - y1; 14463 14464 len = bw*bh; 14465 len = ALIGN(len, 8) / 4; 14466 assert(len > 0); 14467 if (!kgem_check_batch(&sna->kgem, 8+len) || 14468 !kgem_check_bo_fenced(&sna->kgem, bo) || 14469 !kgem_check_reloc(&sna->kgem, 2)) { 14470 kgem_submit(&sna->kgem); 14471 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14472 return; /* XXX fallback? */ 14473 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14474 } 14475 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14476 14477 assert(sna->kgem.mode == KGEM_BLT); 14478 b = sna->kgem.batch + sna->kgem.nbatch; 14479 14480 if (!use_tile && len <= 32) { 14481 uint8_t *dst, *src; 14482 14483 if (sna->kgem.gen >= 0100) { 14484 b[0] = XY_MONO_SRC_COPY_IMM; 14485 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14486 b[0] |= (ox & 7) << 17; 14487 b[0] |= (6 + len); 14488 b[1] = br13; 14489 b[2] = y1 << 16 | x1; 14490 b[3] = y2 << 16 | x2; 14491 *(uint64_t *)(b+4) = 14492 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14493 I915_GEM_DOMAIN_RENDER << 16 | 14494 I915_GEM_DOMAIN_RENDER | 14495 KGEM_RELOC_FENCED, 14496 0); 14497 b[6] = gc->bgPixel; 14498 b[7] = gc->fgPixel; 14499 14500 dst = (uint8_t *)&b[8]; 14501 sna->kgem.nbatch += 8 + len; 14502 } else { 14503 b[0] = XY_MONO_SRC_COPY_IMM; 14504 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 14505 b[0] |= (ox & 7) << 17; 14506 b[0] |= (5 + len); 14507 b[1] = br13; 14508 b[2] = y1 << 16 | x1; 14509 b[3] = y2 << 16 | x2; 14510 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14511 I915_GEM_DOMAIN_RENDER << 16 | 14512 I915_GEM_DOMAIN_RENDER | 14513 KGEM_RELOC_FENCED, 14514 0); 14515 b[5] = gc->bgPixel; 14516 b[6] = gc->fgPixel; 14517 14518 dst = (uint8_t *)&b[7]; 14519 sna->kgem.nbatch += 7 + len; 14520 } 14521 14522 assert(gc->stipple->devKind); 14523 len = gc->stipple->devKind; 14524 src = gc->stipple->devPrivate.ptr; 14525 src += oy*len + ox/8; 14526 len -= bw; 14527 do { 14528 int i = bw; 14529 do { 14530 *dst++ = byte_reverse(*src++); 14531 *dst++ = byte_reverse(*src++); 14532 i -= 2; 14533 } while (i); 14534 src += len; 14535 } while (--bh); 14536 } else { 14537 bool has_tile = use_tile && *tile; 14538 struct kgem_bo *upload; 14539 uint8_t *dst, *src; 14540 void *ptr; 14541 14542 if (has_tile) { 14543 upload = kgem_bo_reference(*tile); 14544 } else { 14545 upload = kgem_create_buffer(&sna->kgem, bw*bh, 14546 KGEM_BUFFER_WRITE_INPLACE, 14547 &ptr); 14548 if (!upload) 14549 return; 14550 } 14551 14552 assert(sna->kgem.mode == KGEM_BLT); 14553 b = sna->kgem.batch + sna->kgem.nbatch; 14554 if (sna->kgem.gen >= 0100) { 14555 b[0] = br00 | (ox & 7) << 17 | 8; 14556 b[1] = br13; 14557 b[2] = y1 << 16 | x1; 14558 b[3] = y2 << 16 | x2; 14559 *(uint64_t *)(b+4) = 14560 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 14561 I915_GEM_DOMAIN_RENDER << 16 | 14562 I915_GEM_DOMAIN_RENDER | 14563 KGEM_RELOC_FENCED, 14564 0); 14565 *(uint64_t *)(b+6) = 14566 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 14567 I915_GEM_DOMAIN_RENDER << 16 | 14568 KGEM_RELOC_FENCED, 14569 0); 14570 b[8] = gc->bgPixel; 14571 b[9] = gc->fgPixel; 14572 sna->kgem.nbatch += 10; 14573 } else { 14574 b[0] = br00 | (ox & 7) << 17 | 6; 14575 b[1] = br13; 14576 b[2] = y1 << 16 | x1; 14577 b[3] = y2 << 16 | x2; 14578 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14579 I915_GEM_DOMAIN_RENDER << 16 | 14580 I915_GEM_DOMAIN_RENDER | 14581 KGEM_RELOC_FENCED, 14582 0); 14583 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 14584 I915_GEM_DOMAIN_RENDER << 16 | 14585 KGEM_RELOC_FENCED, 14586 0); 14587 b[6] = gc->bgPixel; 14588 b[7] = gc->fgPixel; 14589 sna->kgem.nbatch += 8; 14590 } 14591 14592 if (!has_tile) { 14593 dst = ptr; 14594 len = stride; 14595 src = gc->stipple->devPrivate.ptr; 14596 src += row + (ox >> 3); 14597 len -= bw; 14598 do { 14599 int i = bw; 14600 do { 14601 *dst++ = byte_reverse(*src++); 14602 *dst++ = byte_reverse(*src++); 14603 i -= 2; 14604 } while (i); 14605 src += len; 14606 } while (--bh); 14607 if (use_tile) 14608 *tile = kgem_bo_reference(upload); 14609 } 14610 14611 kgem_bo_destroy(&sna->kgem, upload); 14612 } 14613 } 14614 } 14615} 14616 14617static bool 14618sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, 14619 struct kgem_bo *bo, 14620 struct sna_damage **damage, 14621 GCPtr gc, int n, xRectangle *r, 14622 const BoxRec *extents, unsigned clipped) 14623{ 14624 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14625 struct sna *sna = to_sna_from_pixmap(pixmap); 14626 DDXPointRec origin = gc->patOrg; 14627 int16_t dx, dy; 14628 uint32_t br00, br13; 14629 14630 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14631 extents->x1, extents->y1, 14632 extents->x2, extents->y2, 14633 origin.x, origin.y, 14634 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14635 14636 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14637 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14638 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14639 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14640 14641 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; 14642 br13 = bo->pitch; 14643 if (sna->kgem.gen >= 040 && bo->tiling) { 14644 br00 |= BLT_DST_TILED; 14645 br13 >>= 2; 14646 } 14647 br13 |= (gc->fillStyle == FillStippled) << 29; 14648 br13 |= blt_depth(drawable->depth) << 24; 14649 br13 |= copy_ROP[gc->alu] << 16; 14650 14651 origin.x += dx + drawable->x; 14652 origin.y += dy + drawable->y; 14653 14654 if (!clipped) { 14655 dx += drawable->x; 14656 dy += drawable->y; 14657 14658 sna_damage_add_rectangles(damage, r, n, dx, dy); 14659 do { 14660 BoxRec box; 14661 14662 box.x1 = r->x + dx; 14663 box.y1 = r->y + dy; 14664 box.x2 = box.x1 + r->width; 14665 box.y2 = box.y1 + r->height; 14666 14667 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14668 br00, br13, gc, 14669 &box, &origin); 14670 r++; 14671 } while (--n); 14672 } else { 14673 RegionRec clip; 14674 14675 region_set(&clip, extents); 14676 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14677 DBG(("%s: all clipped\n", __FUNCTION__)); 14678 return true; 14679 } 14680 14681 if (clip.data == NULL) { 14682 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14683 __FUNCTION__, 14684 clip.extents.x1, clip.extents.y1, 14685 clip.extents.x2, clip.extents.y2)); 14686 do { 14687 BoxRec box; 14688 14689 box.x1 = r->x + drawable->x; 14690 box.x2 = bound(box.x1, r->width); 14691 box.y1 = r->y + drawable->y; 14692 box.y2 = bound(box.y1, r->height); 14693 r++; 14694 14695 DBG(("%s: box (%d, %d), (%d, %d)\n", 14696 __FUNCTION__, 14697 box.x1, box.y1, box.x2, box.y2)); 14698 if (!box_intersect(&box, &clip.extents)) 14699 continue; 14700 14701 box.x1 += dx; box.x2 += dx; 14702 box.y1 += dy; box.y2 += dy; 14703 14704 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14705 br00, br13, gc, 14706 &box, &origin); 14707 } while (--n); 14708 } else { 14709 const BoxRec * const clip_start = RegionBoxptr(&clip); 14710 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14711 const BoxRec *c; 14712 14713 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14714 clip_start->x1, clip_start->y1, 14715 clip_start->x2, clip_start->y2, 14716 clip_end->x1, clip_end->y1, 14717 clip_end->x2, clip_end->y2)); 14718 do { 14719 BoxRec unclipped; 14720 14721 unclipped.x1 = r->x + drawable->x; 14722 unclipped.x2 = bound(unclipped.x1, r->width); 14723 unclipped.y1 = r->y + drawable->y; 14724 unclipped.y2 = bound(unclipped.y1, r->height); 14725 r++; 14726 14727 c = find_clip_box_for_y(clip_start, 14728 clip_end, 14729 unclipped.y1); 14730 while (c != clip_end) { 14731 BoxRec box; 14732 14733 if (unclipped.y2 <= c->y1) 14734 break; 14735 14736 box = unclipped; 14737 if (!box_intersect(&box, c++)) 14738 continue; 14739 14740 box.x1 += dx; box.x2 += dx; 14741 box.y1 += dy; box.y2 += dy; 14742 14743 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 14744 br00, br13, gc, 14745 &box, &origin); 14746 } 14747 } while (--n); 14748 } 14749 } 14750 14751 assert_pixmap_damage(pixmap); 14752 blt_done(sna); 14753 return true; 14754} 14755 14756static bool 14757sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, 14758 struct kgem_bo *bo, 14759 struct sna_damage **damage, 14760 GCPtr gc, int n, xRectangle *r, 14761 const BoxRec *extents, unsigned clipped) 14762{ 14763 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14764 struct sna *sna = to_sna_from_pixmap(pixmap); 14765 DDXPointRec origin = gc->patOrg; 14766 struct kgem_bo *tile = NULL; 14767 int16_t dx, dy; 14768 uint32_t br00, br13; 14769 14770 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 14771 extents->x1, extents->y1, 14772 extents->x2, extents->y2, 14773 origin.x, origin.y, 14774 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 14775 14776 if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0) 14777 return sna_poly_fill_rect_stippled_n_blt__imm(drawable, 14778 bo, damage, 14779 gc, n, r, 14780 extents, clipped); 14781 14782 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14783 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14784 assert(kgem_bo_can_blt(&sna->kgem, bo)); 14785 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 14786 14787 br00 = XY_MONO_SRC_COPY | 3 << 20; 14788 br13 = bo->pitch; 14789 if (sna->kgem.gen >= 040 && bo->tiling) { 14790 br00 |= BLT_DST_TILED; 14791 br13 >>= 2; 14792 } 14793 br13 |= (gc->fillStyle == FillStippled) << 29; 14794 br13 |= blt_depth(drawable->depth) << 24; 14795 br13 |= copy_ROP[gc->alu] << 16; 14796 14797 origin.x += dx + drawable->x; 14798 origin.y += dy + drawable->y; 14799 14800 if (!clipped) { 14801 dx += drawable->x; 14802 dy += drawable->y; 14803 14804 sna_damage_add_rectangles(damage, r, n, dx, dy); 14805 do { 14806 BoxRec box; 14807 14808 box.x1 = r->x + dx; 14809 box.y1 = r->y + dy; 14810 box.x2 = box.x1 + r->width; 14811 box.y2 = box.y1 + r->height; 14812 14813 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14814 br00, br13, gc, 14815 &box, &origin); 14816 r++; 14817 } while (--n); 14818 } else { 14819 RegionRec clip; 14820 14821 region_set(&clip, extents); 14822 if (!region_maybe_clip(&clip, gc->pCompositeClip)) { 14823 DBG(("%s: all clipped\n", __FUNCTION__)); 14824 return true; 14825 } 14826 14827 if (clip.data == NULL) { 14828 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 14829 __FUNCTION__, 14830 clip.extents.x1, clip.extents.y1, 14831 clip.extents.x2, clip.extents.y2)); 14832 do { 14833 BoxRec box; 14834 14835 box.x1 = r->x + drawable->x; 14836 box.x2 = bound(box.x1, r->width); 14837 box.y1 = r->y + drawable->y; 14838 box.y2 = bound(box.y1, r->height); 14839 r++; 14840 14841 DBG(("%s: box (%d, %d), (%d, %d)\n", 14842 __FUNCTION__, 14843 box.x1, box.y1, box.x2, box.y2)); 14844 if (!box_intersect(&box, &clip.extents)) 14845 continue; 14846 14847 box.x1 += dx; box.x2 += dx; 14848 box.y1 += dy; box.y2 += dy; 14849 14850 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14851 br00, br13, gc, 14852 &box, &origin); 14853 } while (--n); 14854 } else { 14855 const BoxRec * const clip_start = RegionBoxptr(&clip); 14856 const BoxRec * const clip_end = clip_start + clip.data->numRects; 14857 const BoxRec *c; 14858 14859 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 14860 clip_start->x1, clip_start->y1, 14861 clip_start->x2, clip_start->y2, 14862 clip_end->x1, clip_end->y1, 14863 clip_end->x2, clip_end->y2)); 14864 do { 14865 BoxRec unclipped; 14866 14867 unclipped.x1 = r->x + drawable->x; 14868 unclipped.x2 = bound(unclipped.x1, r->width); 14869 unclipped.y1 = r->y + drawable->y; 14870 unclipped.y2 = bound(unclipped.y1, r->height); 14871 r++; 14872 14873 c = find_clip_box_for_y(clip_start, 14874 clip_end, 14875 unclipped.y1); 14876 while (c != clip_end) { 14877 BoxRec box; 14878 14879 if (unclipped.y2 <= c->y1) 14880 break; 14881 14882 box = unclipped; 14883 if (!box_intersect(&box, c++)) 14884 continue; 14885 14886 box.x1 += dx; box.x2 += dx; 14887 box.y1 += dy; box.y2 += dy; 14888 14889 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 14890 br00, br13, gc, 14891 &box, &origin); 14892 } 14893 } while (--n); 14894 } 14895 } 14896 14897 assert_pixmap_damage(pixmap); 14898 if (tile) 14899 kgem_bo_destroy(&sna->kgem, tile); 14900 blt_done(sna); 14901 return true; 14902} 14903 14904static bool 14905sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 14906 struct kgem_bo *bo, 14907 struct sna_damage **damage, 14908 GCPtr gc, int n, xRectangle *rect, 14909 const BoxRec *extents, unsigned clipped) 14910{ 14911 14912 PixmapPtr stipple = gc->stipple; 14913 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14914 14915 if (bo->tiling == I915_TILING_Y) { 14916 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 14917 /* This is cheating, but only the gpu_bo can be tiled */ 14918 assert(bo == __sna_pixmap_get_bo(pixmap)); 14919 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 14920 if (bo == NULL) { 14921 DBG(("%s: fallback -- unable to change tiling\n", 14922 __FUNCTION__)); 14923 return false; 14924 } 14925 } 14926 14927 if (!kgem_bo_can_blt(&to_sna_from_pixmap(pixmap)->kgem, bo)) 14928 return false; 14929 14930 if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ)) 14931 return false; 14932 14933 DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n", 14934 __FUNCTION__, gc->patOrg.x, gc->patOrg.y, 14935 extents->x2 - gc->patOrg.x - drawable->x, 14936 extents->y2 - gc->patOrg.y - drawable->y, 14937 stipple->drawable.width, stipple->drawable.height)); 14938 14939 if ((stipple->drawable.width | stipple->drawable.height) == 8) 14940 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14941 gc, n, rect, 14942 extents, clipped); 14943 14944 if ((stipple->drawable.width | stipple->drawable.height) <= 0xc && 14945 is_power_of_two(stipple->drawable.width) && 14946 is_power_of_two(stipple->drawable.height)) 14947 return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage, 14948 gc, n, rect, 14949 extents, clipped); 14950 14951 if (extents->x1 - gc->patOrg.x - drawable->x >= 0 && 14952 extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width && 14953 extents->y1 - gc->patOrg.y - drawable->y >= 0 && 14954 extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) { 14955 if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8) 14956 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 14957 gc, n, rect, 14958 extents, clipped); 14959 else 14960 return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage, 14961 gc, n, rect, 14962 extents, clipped); 14963 } else { 14964 return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage, 14965 gc, n, rect, 14966 extents, clipped); 14967 } 14968} 14969 14970static unsigned 14971sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc, 14972 int *_n, xRectangle **_r, 14973 BoxPtr out) 14974{ 14975 int n; 14976 xRectangle *r; 14977 Box32Rec box; 14978 bool clipped; 14979 14980 if (*_n == 0) 14981 return 0; 14982 14983 DBG(("%s: [0] = (%d, %d)x(%d, %d)\n", 14984 __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height)); 14985 14986 /* Remove any zero-size rectangles from the array */ 14987 while (*_n && ((*_r)->width == 0 || (*_r)->height == 0)) 14988 --*_n, ++*_r; 14989 14990 if (*_n == 0) 14991 return 0; 14992 14993 n = *_n; 14994 r = *_r; 14995 14996 box.x1 = r->x; 14997 box.x2 = box.x1 + r->width; 14998 box.y1 = r->y; 14999 box.y2 = box.y1 + r->height; 15000 r++; 15001 15002 while (--n) { 15003 if (r->width == 0 || r->height == 0) 15004 goto slow; 15005 15006 box32_add_rect(&box, r++); 15007 } 15008 goto done; 15009slow: 15010 { 15011 xRectangle *rr = r; 15012 do { 15013 do { 15014 --*_n, r++; 15015 } while (--n && (r->width == 0 || r->height == 0)); 15016 while (n && r->width && r->height) { 15017 box32_add_rect(&box, r); 15018 *rr++ = *r++; 15019 n--; 15020 } 15021 } while (n); 15022 } 15023done: 15024 15025 clipped = box32_trim_and_translate(&box, drawable, gc); 15026 if (!box32_to_box16(&box, out)) 15027 return 0; 15028 15029 return 1 | clipped << 1; 15030} 15031 15032static void 15033sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect) 15034{ 15035 PixmapPtr pixmap = get_drawable_pixmap(draw); 15036 struct sna *sna = to_sna_from_pixmap(pixmap); 15037 struct sna_pixmap *priv = sna_pixmap(pixmap); 15038 struct sna_damage **damage; 15039 struct kgem_bo *bo; 15040 RegionRec region; 15041 unsigned flags, hint; 15042 uint32_t color; 15043 15044 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15045 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15046 (gc->fillStyle == FillSolid || 15047 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15048 gc->fillStyle, gc->tileIsPixel, 15049 gc->alu)); 15050 15051 flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, ®ion.extents); 15052 if (flags == 0) { 15053 DBG(("%s, nothing to do\n", __FUNCTION__)); 15054 return; 15055 } 15056 15057 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 15058 region.extents.x1, region.extents.y1, 15059 region.extents.x2, region.extents.y2, 15060 flags)); 15061 15062 if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) { 15063 DBG(("%s: fallback forced\n", __FUNCTION__)); 15064 goto fallback; 15065 } 15066 15067 if (priv == NULL) { 15068 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 15069 goto fallback; 15070 } 15071 15072 if (wedged(sna)) { 15073 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15074 goto fallback; 15075 } 15076 15077 if (!PM_IS_SOLID(draw, gc->planemask)) { 15078 DBG(("%s: fallback -- planemask=0x%lx (not-solid)\n", 15079 __FUNCTION__, gc->planemask)); 15080 goto fallback; 15081 } 15082 15083 if (alu_overwrites(gc->alu)) 15084 flags |= OVERWRITES; 15085 15086 /* Clear the cpu damage so that we refresh the GPU status of the 15087 * pixmap upon a redraw after a period of inactivity. 15088 */ 15089 hint = PREFER_GPU; 15090 if (n == 1 && gc->fillStyle != FillStippled && flags & OVERWRITES) { 15091 int16_t dx, dy; 15092 15093 region.data = NULL; 15094 15095 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) { 15096 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 15097 RegionTranslate(®ion, dx, dy); 15098 } 15099 15100 if ((flags & IS_CLIPPED) == 0) { 15101 hint |= IGNORE_DAMAGE; 15102 if (region_subsumes_drawable(®ion, &pixmap->drawable)) { 15103 discard_cpu_damage(sna, priv); 15104 hint |= REPLACES; 15105 } else { 15106 if (priv->cpu_damage && 15107 region_subsumes_damage(®ion, priv->cpu_damage)) 15108 discard_cpu_damage(sna, priv); 15109 } 15110 } 15111 if (priv->cpu_damage == NULL) { 15112 if (priv->gpu_bo && 15113 (hint & REPLACES || 15114 box_covers_pixmap(pixmap, ®ion.extents) || 15115 box_inplace(pixmap, ®ion.extents))) { 15116 DBG(("%s: promoting to full GPU\n", 15117 __FUNCTION__)); 15118 assert(priv->gpu_bo->proxy == NULL); 15119 sna_damage_all(&priv->gpu_damage, pixmap); 15120 } 15121 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 15122 priv->cpu = false; 15123 } 15124 15125 if (dx | dy) 15126 RegionTranslate(®ion, -dx, -dy); 15127 } 15128 15129 /* If the source is already on the GPU, keep the operation on the GPU */ 15130 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 15131 sna_pixmap_is_gpu(gc->tile.pixmap)) { 15132 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 15133 hint |= FORCE_GPU; 15134 } 15135 15136 bo = sna_drawable_use_bo(draw, hint, ®ion.extents, &damage); 15137 if (bo == NULL) { 15138 DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint)); 15139 goto fallback; 15140 } 15141 if (hint & REPLACES && UNDO) 15142 kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo); 15143 15144 if (gc_is_solid(gc, &color)) { 15145 DBG(("%s: solid fill [%08x], testing for blt\n", 15146 __FUNCTION__, color)); 15147 15148 if (sna_poly_fill_rect_blt(draw, 15149 bo, damage, 15150 gc, color, n, rect, 15151 ®ion.extents, flags)) 15152 return; 15153 } else if (gc->fillStyle == FillTiled) { 15154 DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__)); 15155 15156 if (sna_poly_fill_rect_tiled_blt(draw, bo, damage, 15157 gc, n, rect, 15158 ®ion.extents, flags)) 15159 return; 15160 } else { 15161 DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__)); 15162 15163 if (sna_poly_fill_rect_stippled_blt(draw, bo, damage, 15164 gc, n, rect, 15165 ®ion.extents, flags)) 15166 return; 15167 } 15168 15169fallback: 15170 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 15171 region.extents.x1, region.extents.y1, 15172 region.extents.x2, region.extents.y2)); 15173 region.data = NULL; 15174 if (!region_maybe_clip(®ion, gc->pCompositeClip)) { 15175 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15176 return; 15177 } 15178 15179 if (!sna_gc_move_to_cpu(gc, draw, ®ion)) 15180 goto out; 15181 if (!sna_drawable_move_region_to_cpu(draw, ®ion, 15182 drawable_gc_flags(draw, gc, n > 1))) 15183 goto out; 15184 15185 if (sigtrap_get() == 0) { 15186 DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__)); 15187 fbPolyFillRect(draw, gc, n, rect); 15188 FALLBACK_FLUSH(draw); 15189 sigtrap_put(); 15190 } 15191out: 15192 sna_gc_move_to_gpu(gc); 15193 RegionUninit(®ion); 15194} 15195 15196static void 15197sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r) 15198{ 15199 struct sna_fill_spans *data = sna_gc(gc)->priv; 15200 uint32_t color; 15201 15202 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15203 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15204 (gc->fillStyle == FillSolid || 15205 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15206 gc->fillStyle, gc->tileIsPixel, 15207 gc->alu)); 15208 15209 assert(PM_IS_SOLID(draw, gc->planemask)); 15210 if (n == 0) 15211 return; 15212 15213 /* The mi routines do not attempt to keep the spans it generates 15214 * within the clip, so we must run them through the clipper. 15215 */ 15216 15217 if (gc_is_solid(gc, &color)) { 15218 (void)sna_poly_fill_rect_blt(draw, 15219 data->bo, NULL, 15220 gc, color, n, r, 15221 &data->region.extents, 15222 IS_CLIPPED); 15223 } else if (gc->fillStyle == FillTiled) { 15224 (void)sna_poly_fill_rect_tiled_blt(draw, 15225 data->bo, NULL, 15226 gc, n, r, 15227 &data->region.extents, 15228 IS_CLIPPED); 15229 } else { 15230 (void)sna_poly_fill_rect_stippled_blt(draw, 15231 data->bo, NULL, 15232 gc, n, r, 15233 &data->region.extents, 15234 IS_CLIPPED); 15235 } 15236} 15237 15238static void 15239sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc) 15240{ 15241 struct sna_fill_spans data; 15242 struct sna_pixmap *priv; 15243 15244 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 15245 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 15246 (gc->fillStyle == FillSolid || 15247 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 15248 gc->fillStyle, gc->tileIsPixel, 15249 gc->alu)); 15250 15251 data.flags = sna_poly_arc_extents(draw, gc, n, arc, 15252 &data.region.extents); 15253 if (data.flags == 0) 15254 return; 15255 15256 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 15257 data.region.extents.x1, data.region.extents.y1, 15258 data.region.extents.x2, data.region.extents.y2, 15259 data.flags)); 15260 15261 data.region.data = NULL; 15262 15263 if (FORCE_FALLBACK) 15264 goto fallback; 15265 15266 if (!ACCEL_POLY_FILL_ARC) 15267 goto fallback; 15268 15269 data.pixmap = get_drawable_pixmap(draw); 15270 data.sna = to_sna_from_pixmap(data.pixmap); 15271 priv = sna_pixmap(data.pixmap); 15272 if (priv == NULL) { 15273 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 15274 goto fallback; 15275 } 15276 15277 if (wedged(data.sna)) { 15278 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15279 goto fallback; 15280 } 15281 15282 if (!PM_IS_SOLID(draw, gc->planemask)) 15283 goto fallback; 15284 15285 if ((data.bo = sna_drawable_use_bo(draw, 15286 use_fill_spans(draw, gc, &data.region.extents, data.flags), 15287 &data.region.extents, 15288 &data.damage))) { 15289 uint32_t color; 15290 15291 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 15292 sna_gc(gc)->priv = &data; 15293 15294 if (gc_is_solid(gc, &color)) { 15295 struct sna_fill_op fill; 15296 15297 if (!sna_fill_init_blt(&fill, 15298 data.sna, data.pixmap, 15299 data.bo, gc->alu, color, 15300 FILL_SPANS)) 15301 goto fallback; 15302 15303 data.op = &fill; 15304 15305 if ((data.flags & IS_CLIPPED) == 0) { 15306 if (data.dx | data.dy) 15307 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 15308 else 15309 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 15310 } else { 15311 if (!region_maybe_clip(&data.region, 15312 gc->pCompositeClip)) 15313 return; 15314 15315 if (region_is_singular(&data.region)) 15316 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 15317 else 15318 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 15319 } 15320 assert(gc->miTranslate); 15321 gc->ops = &sna_gc_ops__tmp; 15322 15323 miPolyFillArc(draw, gc, n, arc); 15324 fill.done(data.sna, &fill); 15325 } else { 15326 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 15327 gc->ops = &sna_gc_ops__tmp; 15328 15329 miPolyFillArc(draw, gc, n, arc); 15330 } 15331 15332 gc->ops = (GCOps *)&sna_gc_ops; 15333 if (data.damage) { 15334 if (data.dx | data.dy) 15335 pixman_region_translate(&data.region, data.dx, data.dy); 15336 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 15337 sna_damage_add_to_pixmap(data.damage, &data.region, data.pixmap); 15338 } 15339 assert_pixmap_damage(data.pixmap); 15340 RegionUninit(&data.region); 15341 return; 15342 } 15343 15344fallback: 15345 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 15346 data.region.extents.x1, data.region.extents.y1, 15347 data.region.extents.x2, data.region.extents.y2)); 15348 if (!region_maybe_clip(&data.region, gc->pCompositeClip)) { 15349 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 15350 return; 15351 } 15352 15353 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 15354 goto out; 15355 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 15356 drawable_gc_flags(draw, gc, true))) 15357 goto out; 15358 15359 if (sigtrap_get() == 0) { 15360 DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n", 15361 __FUNCTION__)); 15362 miPolyFillArc(draw, gc, n, arc); 15363 sigtrap_put(); 15364 } 15365out: 15366 sna_gc_move_to_gpu(gc); 15367 RegionUninit(&data.region); 15368} 15369 15370struct sna_font { 15371 CharInfoRec glyphs8[256]; 15372 CharInfoRec *glyphs16[256]; 15373}; 15374#define GLYPH_INVALID (void *)1 15375#define GLYPH_EMPTY (void *)2 15376 15377static Bool 15378sna_realize_font(ScreenPtr screen, FontPtr font) 15379{ 15380 struct sna_font *priv; 15381 15382 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15383 15384 priv = calloc(1, sizeof(struct sna_font)); 15385 if (priv == NULL) 15386 return FALSE; 15387 15388 if (!FontSetPrivate(font, sna_font_key, priv)) { 15389 free(priv); 15390 return FALSE; 15391 } 15392 15393 return TRUE; 15394} 15395 15396static Bool 15397sna_unrealize_font(ScreenPtr screen, FontPtr font) 15398{ 15399 struct sna_font *priv = FontGetPrivate(font, sna_font_key); 15400 int i, j; 15401 15402 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 15403 15404 if (priv == NULL) 15405 return TRUE; 15406 15407 for (i = 0; i < 256; i++) { 15408 if ((uintptr_t)priv->glyphs8[i].bits & ~3) 15409 free(priv->glyphs8[i].bits); 15410 } 15411 for (j = 0; j < 256; j++) { 15412 if (priv->glyphs16[j] == NULL) 15413 continue; 15414 15415 for (i = 0; i < 256; i++) { 15416 if ((uintptr_t)priv->glyphs16[j][i].bits & ~3) 15417 free(priv->glyphs16[j][i].bits); 15418 } 15419 free(priv->glyphs16[j]); 15420 } 15421 free(priv); 15422 15423 FontSetPrivate(font, sna_font_key, NULL); 15424 return TRUE; 15425} 15426 15427static bool 15428sna_glyph_blt(DrawablePtr drawable, GCPtr gc, 15429 int _x, int _y, unsigned int _n, 15430 CharInfoPtr *_info, 15431 RegionRec *clip, 15432 uint32_t fg, uint32_t bg, 15433 bool transparent) 15434{ 15435 PixmapPtr pixmap = get_drawable_pixmap(drawable); 15436 struct sna *sna = to_sna_from_pixmap(pixmap); 15437 struct kgem_bo *bo; 15438 struct sna_damage **damage; 15439 const BoxRec *extents, *last_extents; 15440 uint32_t *b; 15441 int16_t dx, dy; 15442 uint32_t br00; 15443 uint16_t unwind_batch, unwind_reloc; 15444 unsigned hint; 15445 15446 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 15447 15448 DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n", 15449 __FUNCTION__, _x, _y, _n, fg, bg, rop)); 15450 15451 if (wedged(sna)) { 15452 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 15453 return false; 15454 } 15455 15456 if (!transparent && clip->data == NULL) 15457 hint = PREFER_GPU | IGNORE_DAMAGE; 15458 else 15459 hint = PREFER_GPU; 15460 15461 bo = sna_drawable_use_bo(drawable, hint, &clip->extents, &damage); 15462 if (bo == NULL) 15463 return false; 15464 15465 if (bo->tiling == I915_TILING_Y) { 15466 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 15467 assert(bo == __sna_pixmap_get_bo(pixmap)); 15468 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 15469 if (bo == NULL) { 15470 DBG(("%s: fallback -- unable to change tiling\n", 15471 __FUNCTION__)); 15472 return false; 15473 } 15474 } 15475 15476 if (!kgem_bo_can_blt(&sna->kgem, bo)) 15477 return false; 15478 15479 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 15480 RegionTranslate(clip, dx, dy); 15481 _x += drawable->x + dx; 15482 _y += drawable->y + dy; 15483 15484 extents = region_rects(clip); 15485 last_extents = extents + region_num_rects(clip); 15486 15487 if (!transparent) { /* emulate miImageGlyphBlt */ 15488 if (!sna_blt_fill_boxes(sna, GXcopy, 15489 bo, drawable->bitsPerPixel, 15490 bg, extents, last_extents - extents)) { 15491 RegionTranslate(clip, -dx, -dy); 15492 return false; 15493 } 15494 } 15495 15496 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 15497 assert(kgem_bo_can_blt(&sna->kgem, bo)); 15498 if (!kgem_check_batch(&sna->kgem, 20) || 15499 !kgem_check_bo_fenced(&sna->kgem, bo) || 15500 !kgem_check_reloc(&sna->kgem, 1)) { 15501 kgem_submit(&sna->kgem); 15502 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 15503 RegionTranslate(clip, -dx, -dy); 15504 return false; 15505 } 15506 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15507 } 15508 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 15509 15510 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15511 __FUNCTION__, 15512 extents->x1, extents->y1, 15513 extents->x2, extents->y2)); 15514 15515 unwind_batch = sna->kgem.nbatch; 15516 unwind_reloc = sna->kgem.nreloc; 15517 15518 assert(sna->kgem.mode == KGEM_BLT); 15519 b = sna->kgem.batch + sna->kgem.nbatch; 15520 if (sna->kgem.gen >= 0100) { 15521 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15522 b[1] = bo->pitch; 15523 if (sna->kgem.gen >= 040 && bo->tiling) { 15524 b[0] |= BLT_DST_TILED; 15525 b[1] >>= 2; 15526 } 15527 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15528 b[2] = extents->y1 << 16 | extents->x1; 15529 b[3] = extents->y2 << 16 | extents->x2; 15530 *(uint64_t *)(b+4) = 15531 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15532 I915_GEM_DOMAIN_RENDER << 16 | 15533 I915_GEM_DOMAIN_RENDER | 15534 KGEM_RELOC_FENCED, 15535 0); 15536 b[6] = bg; 15537 b[7] = fg; 15538 b[8] = 0; 15539 b[9] = 0; 15540 sna->kgem.nbatch += 10; 15541 } else { 15542 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15543 b[1] = bo->pitch; 15544 if (sna->kgem.gen >= 040 && bo->tiling) { 15545 b[0] |= BLT_DST_TILED; 15546 b[1] >>= 2; 15547 } 15548 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15549 b[2] = extents->y1 << 16 | extents->x1; 15550 b[3] = extents->y2 << 16 | extents->x2; 15551 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15552 I915_GEM_DOMAIN_RENDER << 16 | 15553 I915_GEM_DOMAIN_RENDER | 15554 KGEM_RELOC_FENCED, 15555 0); 15556 b[5] = bg; 15557 b[6] = fg; 15558 b[7] = 0; 15559 sna->kgem.nbatch += 8; 15560 } 15561 15562 br00 = XY_TEXT_IMMEDIATE_BLT; 15563 if (bo->tiling && sna->kgem.gen >= 040) 15564 br00 |= BLT_DST_TILED; 15565 15566 do { 15567 CharInfoPtr *info = _info; 15568 int x = _x, y = _y, n = _n; 15569 15570 do { 15571 CharInfoPtr c = *info++; 15572 int w = GLYPHWIDTHPIXELS(c); 15573 int h = GLYPHHEIGHTPIXELS(c); 15574 int w8 = (w + 7) >> 3; 15575 int x1, y1, len; 15576 15577 if (c->bits == GLYPH_EMPTY) 15578 goto skip; 15579 15580 len = (w8 * h + 7) >> 3 << 1; 15581 x1 = x + c->metrics.leftSideBearing; 15582 y1 = y - c->metrics.ascent; 15583 15584 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 15585 x,y, x1, y1, w, w8, h, len)); 15586 15587 if (x1 >= extents->x2 || y1 >= extents->y2) 15588 goto skip; 15589 if (x1 + w <= extents->x1 || y1 + h <= extents->y1) 15590 goto skip; 15591 15592 assert(len > 0); 15593 if (!kgem_check_batch(&sna->kgem, 3+len)) { 15594 _kgem_submit(&sna->kgem); 15595 _kgem_set_mode(&sna->kgem, KGEM_BLT); 15596 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 15597 15598 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 15599 __FUNCTION__, 15600 extents->x1, extents->y1, 15601 extents->x2, extents->y2)); 15602 15603 unwind_batch = sna->kgem.nbatch; 15604 unwind_reloc = sna->kgem.nreloc; 15605 15606 assert(sna->kgem.mode == KGEM_BLT); 15607 b = sna->kgem.batch + sna->kgem.nbatch; 15608 if (sna->kgem.gen >= 0100) { 15609 b[0] = XY_SETUP_BLT | 3 << 20 | 8; 15610 b[1] = bo->pitch; 15611 if (bo->tiling) { 15612 b[0] |= BLT_DST_TILED; 15613 b[1] >>= 2; 15614 } 15615 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15616 b[2] = extents->y1 << 16 | extents->x1; 15617 b[3] = extents->y2 << 16 | extents->x2; 15618 *(uint64_t *)(b+4) = 15619 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 15620 I915_GEM_DOMAIN_RENDER << 16 | 15621 I915_GEM_DOMAIN_RENDER | 15622 KGEM_RELOC_FENCED, 15623 0); 15624 b[6] = bg; 15625 b[7] = fg; 15626 b[8] = 0; 15627 b[9] = 0; 15628 sna->kgem.nbatch += 10; 15629 } else { 15630 b[0] = XY_SETUP_BLT | 3 << 20 | 6; 15631 b[1] = bo->pitch; 15632 if (sna->kgem.gen >= 040 && bo->tiling) { 15633 b[0] |= BLT_DST_TILED; 15634 b[1] >>= 2; 15635 } 15636 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 15637 b[2] = extents->y1 << 16 | extents->x1; 15638 b[3] = extents->y2 << 16 | extents->x2; 15639 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 15640 I915_GEM_DOMAIN_RENDER << 16 | 15641 I915_GEM_DOMAIN_RENDER | 15642 KGEM_RELOC_FENCED, 15643 0); 15644 b[5] = bg; 15645 b[6] = fg; 15646 b[7] = 0; 15647 sna->kgem.nbatch += 8; 15648 } 15649 } 15650 15651 assert(sna->kgem.mode == KGEM_BLT); 15652 b = sna->kgem.batch + sna->kgem.nbatch; 15653 sna->kgem.nbatch += 3 + len; 15654 15655 b[0] = br00 | (1 + len); 15656 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 15657 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 15658 { 15659 uint64_t *src = (uint64_t *)c->bits; 15660 uint64_t *dst = (uint64_t *)(b + 3); 15661 do { 15662 *dst++ = *src++; 15663 len -= 2; 15664 } while (len); 15665 } 15666 15667 if (damage) { 15668 BoxRec r; 15669 15670 r.x1 = x1; 15671 r.y1 = y1; 15672 r.x2 = x1 + w; 15673 r.y2 = y1 + h; 15674 if (box_intersect(&r, extents)) 15675 sna_damage_add_box(damage, &r); 15676 } 15677skip: 15678 x += c->metrics.characterWidth; 15679 } while (--n); 15680 15681 if (++extents == last_extents) 15682 break; 15683 15684 if (kgem_check_batch(&sna->kgem, 3)) { 15685 assert(sna->kgem.mode == KGEM_BLT); 15686 b = sna->kgem.batch + sna->kgem.nbatch; 15687 sna->kgem.nbatch += 3; 15688 15689 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 15690 __FUNCTION__, 15691 extents->x1, extents->y1, 15692 extents->x2, extents->y2)); 15693 15694 b[0] = XY_SETUP_CLIP; 15695 b[1] = extents->y1 << 16 | extents->x1; 15696 b[2] = extents->y2 << 16 | extents->x2; 15697 } 15698 } while (1); 15699 15700 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 15701 sna->kgem.nbatch = unwind_batch; 15702 sna->kgem.nreloc = unwind_reloc; 15703 if (sna->kgem.nbatch == 0) 15704 kgem_bo_undo(&sna->kgem, bo); 15705 } 15706 15707 assert_pixmap_damage(pixmap); 15708 blt_done(sna); 15709 return true; 15710} 15711 15712static void 15713sna_glyph_extents(FontPtr font, 15714 CharInfoPtr *info, 15715 unsigned long count, 15716 ExtentInfoRec *extents) 15717{ 15718 extents->drawDirection = font->info.drawDirection; 15719 extents->fontAscent = font->info.fontAscent; 15720 extents->fontDescent = font->info.fontDescent; 15721 15722 extents->overallAscent = info[0]->metrics.ascent; 15723 extents->overallDescent = info[0]->metrics.descent; 15724 extents->overallLeft = info[0]->metrics.leftSideBearing; 15725 extents->overallRight = info[0]->metrics.rightSideBearing; 15726 extents->overallWidth = info[0]->metrics.characterWidth; 15727 15728 while (--count) { 15729 CharInfoPtr p =*++info; 15730 int v; 15731 15732 if (p->metrics.ascent > extents->overallAscent) 15733 extents->overallAscent = p->metrics.ascent; 15734 if (p->metrics.descent > extents->overallDescent) 15735 extents->overallDescent = p->metrics.descent; 15736 15737 v = extents->overallWidth + p->metrics.leftSideBearing; 15738 if (v < extents->overallLeft) 15739 extents->overallLeft = v; 15740 15741 v = extents->overallWidth + p->metrics.rightSideBearing; 15742 if (v > extents->overallRight) 15743 extents->overallRight = v; 15744 15745 extents->overallWidth += p->metrics.characterWidth; 15746 } 15747} 15748 15749static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out) 15750{ 15751 int w = GLYPHWIDTHPIXELS(in); 15752 int h = GLYPHHEIGHTPIXELS(in); 15753 int stride = GLYPHWIDTHBYTESPADDED(in); 15754 uint8_t *dst, *src; 15755 int clear = 1; 15756 15757 out->metrics = in->metrics; 15758 15759 /* Skip empty glyphs */ 15760 if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) { 15761 out->bits = GLYPH_EMPTY; 15762 return true; 15763 } 15764 15765 w = (w + 7) >> 3; 15766 15767 out->bits = malloc((w*h + 7) & ~7); 15768 if (out->bits == NULL) 15769 return false; 15770 15771 VG(memset(out->bits, 0, (w*h + 7) & ~7)); 15772 src = (uint8_t *)in->bits; 15773 dst = (uint8_t *)out->bits; 15774 stride -= w; 15775 do { 15776 int i = w; 15777 do { 15778 clear &= *src == 0; 15779 *dst++ = byte_reverse(*src++); 15780 } while (--i); 15781 src += stride; 15782 } while (--h); 15783 15784 if (clear) { 15785 free(out->bits); 15786 out->bits = GLYPH_EMPTY; 15787 } 15788 15789 return true; 15790} 15791 15792inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv, 15793 uint8_t g, CharInfoPtr *out) 15794{ 15795 unsigned long n; 15796 CharInfoPtr p, ret; 15797 15798 p = &priv->glyphs8[g]; 15799 if (p->bits) { 15800 *out = p; 15801 return p->bits != GLYPH_INVALID; 15802 } 15803 15804 font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret); 15805 if (n == 0) { 15806 p->bits = GLYPH_INVALID; 15807 return false; 15808 } 15809 15810 return sna_set_glyph(ret, *out = p); 15811} 15812 15813inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv, 15814 uint16_t g, CharInfoPtr *out) 15815{ 15816 unsigned long n; 15817 CharInfoPtr page, p, ret; 15818 15819 page = priv->glyphs16[g>>8]; 15820 if (page == NULL) 15821 page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec)); 15822 15823 p = &page[g&0xff]; 15824 if (p->bits) { 15825 *out = p; 15826 return p->bits != GLYPH_INVALID; 15827 } 15828 15829 font->get_glyphs(font, 1, (unsigned char *)&g, 15830 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit, 15831 &n, &ret); 15832 if (n == 0) { 15833 p->bits = GLYPH_INVALID; 15834 return false; 15835 } 15836 15837 return sna_set_glyph(ret, *out = p); 15838} 15839 15840static inline bool sna_font_too_large(FontPtr font) 15841{ 15842 int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font)); 15843 int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font)); 15844 int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth)); 15845 DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__, 15846 top, bot, width, (top + bot) * (width + 7)/8)); 15847 return (top + bot) * (width + 7)/8 > 124; 15848} 15849 15850static int 15851sna_poly_text8(DrawablePtr drawable, GCPtr gc, 15852 int x, int y, 15853 int count, char *chars) 15854{ 15855 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15856 CharInfoPtr info[255]; 15857 ExtentInfoRec extents; 15858 RegionRec region; 15859 long unsigned i, n; 15860 uint32_t fg; 15861 15862 for (i = n = 0; i < count; i++) { 15863 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 15864 n++; 15865 } 15866 if (n == 0) 15867 return x; 15868 15869 sna_glyph_extents(gc->font, info, n, &extents); 15870 region.extents.x1 = x + extents.overallLeft; 15871 region.extents.y1 = y - extents.overallAscent; 15872 region.extents.x2 = x + extents.overallRight; 15873 region.extents.y2 = y + extents.overallDescent; 15874 15875 translate_box(®ion.extents, drawable); 15876 clip_box(®ion.extents, gc); 15877 if (box_empty(®ion.extents)) 15878 return x + extents.overallRight; 15879 15880 region.data = NULL; 15881 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15882 return x + extents.overallRight; 15883 15884 if (FORCE_FALLBACK) 15885 goto fallback; 15886 15887 if (!ACCEL_POLY_TEXT8) 15888 goto fallback; 15889 15890 if (sna_font_too_large(gc->font)) 15891 goto fallback; 15892 15893 if (!PM_IS_SOLID(drawable, gc->planemask)) 15894 goto fallback; 15895 15896 if (!gc_is_solid(gc, &fg)) 15897 goto fallback; 15898 15899 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15900fallback: 15901 DBG(("%s: fallback\n", __FUNCTION__)); 15902 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15903 Linear8Bit, &n, info); 15904 15905 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15906 goto out; 15907 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15908 MOVE_READ | MOVE_WRITE)) 15909 goto out; 15910 15911 if (sigtrap_get() == 0) { 15912 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15913 fbPolyGlyphBlt(drawable, gc, x, y, n, 15914 info, FONTGLYPHS(gc->font)); 15915 FALLBACK_FLUSH(drawable); 15916 sigtrap_put(); 15917 } 15918out: 15919 sna_gc_move_to_gpu(gc); 15920 } 15921 RegionUninit(®ion); 15922 return x + extents.overallRight; 15923} 15924 15925static int 15926sna_poly_text16(DrawablePtr drawable, GCPtr gc, 15927 int x, int y, 15928 int count, unsigned short *chars) 15929{ 15930 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 15931 CharInfoPtr info[255]; 15932 ExtentInfoRec extents; 15933 RegionRec region; 15934 long unsigned i, n; 15935 uint32_t fg; 15936 15937 for (i = n = 0; i < count; i++) { 15938 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 15939 n++; 15940 } 15941 if (n == 0) 15942 return x; 15943 15944 sna_glyph_extents(gc->font, info, n, &extents); 15945 region.extents.x1 = x + extents.overallLeft; 15946 region.extents.y1 = y - extents.overallAscent; 15947 region.extents.x2 = x + extents.overallRight; 15948 region.extents.y2 = y + extents.overallDescent; 15949 15950 translate_box(®ion.extents, drawable); 15951 clip_box(®ion.extents, gc); 15952 if (box_empty(®ion.extents)) 15953 return x + extents.overallRight; 15954 15955 region.data = NULL; 15956 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 15957 return x + extents.overallRight; 15958 15959 if (FORCE_FALLBACK) 15960 goto fallback; 15961 15962 if (!ACCEL_POLY_TEXT16) 15963 goto fallback; 15964 15965 if (sna_font_too_large(gc->font)) 15966 goto fallback; 15967 15968 if (!PM_IS_SOLID(drawable, gc->planemask)) 15969 goto fallback; 15970 15971 if (!gc_is_solid(gc, &fg)) 15972 goto fallback; 15973 15974 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 15975fallback: 15976 DBG(("%s: fallback\n", __FUNCTION__)); 15977 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 15978 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 15979 &n, info); 15980 15981 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 15982 goto out; 15983 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 15984 MOVE_READ | MOVE_WRITE)) 15985 goto out; 15986 15987 if (sigtrap_get() == 0) { 15988 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 15989 fbPolyGlyphBlt(drawable, gc, x, y, n, 15990 info, FONTGLYPHS(gc->font)); 15991 FALLBACK_FLUSH(drawable); 15992 sigtrap_put(); 15993 } 15994out: 15995 sna_gc_move_to_gpu(gc); 15996 } 15997 RegionUninit(®ion); 15998 return x + extents.overallRight; 15999} 16000 16001static void 16002sna_image_text8(DrawablePtr drawable, GCPtr gc, 16003 int x, int y, 16004 int count, char *chars) 16005{ 16006 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 16007 CharInfoPtr info[255]; 16008 ExtentInfoRec extents; 16009 RegionRec region; 16010 long unsigned i, n; 16011 16012 for (i = n = 0; i < count; i++) { 16013 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 16014 n++; 16015 } 16016 if (n == 0) 16017 return; 16018 16019 sna_glyph_extents(gc->font, info, n, &extents); 16020 region.extents.x1 = x + MIN(0, extents.overallLeft); 16021 region.extents.y1 = y - extents.fontAscent; 16022 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16023 region.extents.y2 = y + extents.fontDescent; 16024 16025 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16026 __FUNCTION__, n, count, 16027 extents.overallLeft, extents.overallRight, extents.overallWidth, 16028 extents.fontAscent, extents.fontDescent, 16029 region.extents.x1, region.extents.y1, 16030 region.extents.x2, region.extents.y2)); 16031 16032 translate_box(®ion.extents, drawable); 16033 clip_box(®ion.extents, gc); 16034 if (box_empty(®ion.extents)) 16035 return; 16036 16037 region.data = NULL; 16038 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16039 return; 16040 16041 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 16042 __FUNCTION__, 16043 region.extents.x1, region.extents.y1, 16044 region.extents.x2, region.extents.y2)); 16045 16046 if (FORCE_FALLBACK) 16047 goto fallback; 16048 16049 if (!ACCEL_IMAGE_TEXT8) 16050 goto fallback; 16051 16052 if (sna_font_too_large(gc->font)) 16053 goto fallback; 16054 16055 if (!PM_IS_SOLID(drawable, gc->planemask)) 16056 goto fallback; 16057 16058 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 16059 gc->fgPixel, gc->bgPixel, false)) { 16060fallback: 16061 DBG(("%s: fallback\n", __FUNCTION__)); 16062 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 16063 Linear8Bit, &n, info); 16064 16065 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16066 goto out; 16067 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16068 goto out; 16069 16070 if (sigtrap_get() == 0) { 16071 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16072 fbImageGlyphBlt(drawable, gc, x, y, n, 16073 info, FONTGLYPHS(gc->font)); 16074 FALLBACK_FLUSH(drawable); 16075 sigtrap_put(); 16076 } 16077out: 16078 sna_gc_move_to_gpu(gc); 16079 } 16080 RegionUninit(®ion); 16081} 16082 16083static void 16084sna_image_text16(DrawablePtr drawable, GCPtr gc, 16085 int x, int y, 16086 int count, unsigned short *chars) 16087{ 16088 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 16089 CharInfoPtr info[255]; 16090 ExtentInfoRec extents; 16091 RegionRec region; 16092 long unsigned i, n; 16093 16094 for (i = n = 0; i < count; i++) { 16095 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 16096 n++; 16097 } 16098 if (n == 0) 16099 return; 16100 16101 sna_glyph_extents(gc->font, info, n, &extents); 16102 region.extents.x1 = x + MIN(0, extents.overallLeft); 16103 region.extents.y1 = y - extents.fontAscent; 16104 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16105 region.extents.y2 = y + extents.fontDescent; 16106 16107 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16108 __FUNCTION__, n, count, 16109 extents.overallLeft, extents.overallRight, extents.overallWidth, 16110 extents.fontAscent, extents.fontDescent, 16111 region.extents.x1, region.extents.y1, 16112 region.extents.x2, region.extents.y2)); 16113 16114 translate_box(®ion.extents, drawable); 16115 clip_box(®ion.extents, gc); 16116 if (box_empty(®ion.extents)) 16117 return; 16118 16119 region.data = NULL; 16120 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16121 return; 16122 16123 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 16124 __FUNCTION__, 16125 region.extents.x1, region.extents.y1, 16126 region.extents.x2, region.extents.y2)); 16127 16128 if (FORCE_FALLBACK) 16129 goto fallback; 16130 16131 if (!ACCEL_IMAGE_TEXT16) 16132 goto fallback; 16133 16134 if (sna_font_too_large(gc->font)) 16135 goto fallback; 16136 16137 if (!PM_IS_SOLID(drawable, gc->planemask)) 16138 goto fallback; 16139 16140 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 16141 gc->fgPixel, gc->bgPixel, false)) { 16142fallback: 16143 DBG(("%s: fallback\n", __FUNCTION__)); 16144 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 16145 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 16146 &n, info); 16147 16148 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16149 goto out; 16150 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16151 goto out; 16152 16153 if (sigtrap_get() == 0) { 16154 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16155 fbImageGlyphBlt(drawable, gc, x, y, n, 16156 info, FONTGLYPHS(gc->font)); 16157 FALLBACK_FLUSH(drawable); 16158 sigtrap_put(); 16159 } 16160out: 16161 sna_gc_move_to_gpu(gc); 16162 } 16163 RegionUninit(®ion); 16164} 16165 16166/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ 16167static bool 16168sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, 16169 int _x, int _y, unsigned int _n, 16170 CharInfoPtr *_info, pointer _base, 16171 struct kgem_bo *bo, 16172 struct sna_damage **damage, 16173 RegionPtr clip, 16174 uint32_t fg, uint32_t bg, 16175 bool transparent) 16176{ 16177 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16178 struct sna *sna = to_sna_from_pixmap(pixmap); 16179 const BoxRec *extents, *last_extents; 16180 uint32_t *b; 16181 int16_t dx, dy; 16182 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 16183 uint16_t unwind_batch, unwind_reloc; 16184 16185 DBG(("%s: pixmap=%ld, bo=%d, damage=%p, fg=%08x, bg=%08x\n", 16186 __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, damage, fg, bg)); 16187 16188 if (bo->tiling == I915_TILING_Y) { 16189 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16190 assert(bo == __sna_pixmap_get_bo(pixmap)); 16191 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16192 if (bo == NULL) { 16193 DBG(("%s: fallback -- unable to change tiling\n", 16194 __FUNCTION__)); 16195 return false; 16196 } 16197 } 16198 16199 if (!kgem_bo_can_blt(&sna->kgem, bo)) 16200 return false; 16201 16202 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16203 RegionTranslate(clip, dx, dy); 16204 _x += drawable->x + dx; 16205 _y += drawable->y + dy; 16206 16207 extents = region_rects(clip); 16208 last_extents = extents + region_num_rects(clip); 16209 16210 if (!transparent) { /* emulate miImageGlyphBlt */ 16211 if (!sna_blt_fill_boxes(sna, GXcopy, 16212 bo, drawable->bitsPerPixel, 16213 bg, extents, last_extents - extents)) { 16214 RegionTranslate(clip, -dx, -dy); 16215 return false; 16216 } 16217 } 16218 16219 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16220 assert(kgem_bo_can_blt(&sna->kgem, bo)); 16221 if (!kgem_check_batch(&sna->kgem, 20) || 16222 !kgem_check_bo_fenced(&sna->kgem, bo) || 16223 !kgem_check_reloc(&sna->kgem, 1)) { 16224 kgem_submit(&sna->kgem); 16225 if (!kgem_check_bo_fenced(&sna->kgem, bo)) { 16226 RegionTranslate(clip, -dx, -dy); 16227 return false; 16228 } 16229 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16230 } 16231 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16232 16233 unwind_batch = sna->kgem.nbatch; 16234 unwind_reloc = sna->kgem.nreloc; 16235 16236 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16237 __FUNCTION__, 16238 extents->x1, extents->y1, 16239 extents->x2, extents->y2)); 16240 16241 assert(sna->kgem.mode == KGEM_BLT); 16242 b = sna->kgem.batch + sna->kgem.nbatch; 16243 if (sna->kgem.gen >= 0100) { 16244 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16245 b[1] = bo->pitch; 16246 if (sna->kgem.gen >= 040 && bo->tiling) { 16247 b[0] |= BLT_DST_TILED; 16248 b[1] >>= 2; 16249 } 16250 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16251 b[2] = extents->y1 << 16 | extents->x1; 16252 b[3] = extents->y2 << 16 | extents->x2; 16253 *(uint64_t *)(b+4) = 16254 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16255 I915_GEM_DOMAIN_RENDER << 16 | 16256 I915_GEM_DOMAIN_RENDER | 16257 KGEM_RELOC_FENCED, 16258 0); 16259 b[6] = bg; 16260 b[7] = fg; 16261 b[8] = 0; 16262 b[9] = 0; 16263 sna->kgem.nbatch += 10; 16264 } else { 16265 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16266 b[1] = bo->pitch; 16267 if (sna->kgem.gen >= 040 && bo->tiling) { 16268 b[0] |= BLT_DST_TILED; 16269 b[1] >>= 2; 16270 } 16271 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16272 b[2] = extents->y1 << 16 | extents->x1; 16273 b[3] = extents->y2 << 16 | extents->x2; 16274 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16275 I915_GEM_DOMAIN_RENDER << 16 | 16276 I915_GEM_DOMAIN_RENDER | 16277 KGEM_RELOC_FENCED, 16278 0); 16279 b[5] = bg; 16280 b[6] = fg; 16281 b[7] = 0; 16282 sna->kgem.nbatch += 8; 16283 } 16284 16285 do { 16286 CharInfoPtr *info = _info; 16287 int x = _x, y = _y, n = _n; 16288 16289 do { 16290 CharInfoPtr c = *info++; 16291 uint8_t *glyph = FONTGLYPHBITS(base, c); 16292 int w = GLYPHWIDTHPIXELS(c); 16293 int h = GLYPHHEIGHTPIXELS(c); 16294 int stride = GLYPHWIDTHBYTESPADDED(c); 16295 int w8 = (w + 7) >> 3; 16296 int x1, y1, len, i; 16297 uint8_t *byte; 16298 16299 if (w == 0 || h == 0) 16300 goto skip; 16301 16302 len = (w8 * h + 7) >> 3 << 1; 16303 x1 = x + c->metrics.leftSideBearing; 16304 y1 = y - c->metrics.ascent; 16305 16306 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 16307 x,y, x1, y1, w, w8, h, len)); 16308 16309 if (x1 >= extents->x2 || y1 >= extents->y2 || 16310 x1 + w <= extents->x1 || y1 + h <= extents->y1) { 16311 DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n", 16312 __FUNCTION__, 16313 x1, y1, w, h, 16314 extents->x1, extents->y1, 16315 extents->x2, extents->y2)); 16316 goto skip; 16317 } 16318 16319 { 16320 int clear = 1, j = h; 16321 uint8_t *g = glyph; 16322 16323 do { 16324 i = w8; 16325 do { 16326 clear = *g++ == 0; 16327 } while (clear && --i); 16328 g += stride - w8; 16329 } while (clear && --j); 16330 if (clear) { 16331 DBG(("%s: skipping clear glyph for ImageGlyph\n", 16332 __FUNCTION__)); 16333 goto skip; 16334 } 16335 } 16336 16337 assert(len > 0); 16338 if (!kgem_check_batch(&sna->kgem, 3+len)) { 16339 _kgem_submit(&sna->kgem); 16340 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16341 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16342 16343 unwind_batch = sna->kgem.nbatch; 16344 unwind_reloc = sna->kgem.nreloc; 16345 16346 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 16347 __FUNCTION__, 16348 extents->x1, extents->y1, 16349 extents->x2, extents->y2)); 16350 16351 assert(sna->kgem.mode == KGEM_BLT); 16352 b = sna->kgem.batch + sna->kgem.nbatch; 16353 if (sna->kgem.gen >= 0100) { 16354 b[0] = XY_SETUP_BLT | 1 << 20 | 8; 16355 b[1] = bo->pitch; 16356 if (bo->tiling) { 16357 b[0] |= BLT_DST_TILED; 16358 b[1] >>= 2; 16359 } 16360 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16361 b[2] = extents->y1 << 16 | extents->x1; 16362 b[3] = extents->y2 << 16 | extents->x2; 16363 *(uint64_t *)(b+4) = 16364 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16365 I915_GEM_DOMAIN_RENDER << 16 | 16366 I915_GEM_DOMAIN_RENDER | 16367 KGEM_RELOC_FENCED, 16368 0); 16369 b[6] = bg; 16370 b[7] = fg; 16371 b[8] = 0; 16372 b[9] = 0; 16373 sna->kgem.nbatch += 10; 16374 } else { 16375 b[0] = XY_SETUP_BLT | 1 << 20 | 6; 16376 b[1] = bo->pitch; 16377 if (sna->kgem.gen >= 040 && bo->tiling) { 16378 b[0] |= BLT_DST_TILED; 16379 b[1] >>= 2; 16380 } 16381 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 16382 b[2] = extents->y1 << 16 | extents->x1; 16383 b[3] = extents->y2 << 16 | extents->x2; 16384 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16385 I915_GEM_DOMAIN_RENDER << 16 | 16386 I915_GEM_DOMAIN_RENDER | 16387 KGEM_RELOC_FENCED, 16388 0); 16389 b[5] = bg; 16390 b[6] = fg; 16391 b[7] = 0; 16392 sna->kgem.nbatch += 8; 16393 } 16394 } 16395 16396 assert(sna->kgem.mode == KGEM_BLT); 16397 b = sna->kgem.batch + sna->kgem.nbatch; 16398 sna->kgem.nbatch += 3 + len; 16399 16400 b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); 16401 if (bo->tiling && sna->kgem.gen >= 040) 16402 b[0] |= BLT_DST_TILED; 16403 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 16404 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 16405 16406 byte = (uint8_t *)&b[3]; 16407 stride -= w8; 16408 do { 16409 i = w8; 16410 do { 16411 *byte++ = byte_reverse(*glyph++); 16412 } while (--i); 16413 glyph += stride; 16414 } while (--h); 16415 while ((byte - (uint8_t *)&b[3]) & 7) 16416 *byte++ = 0; 16417 assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); 16418 16419 if (damage) { 16420 BoxRec r; 16421 16422 r.x1 = x1; 16423 r.y1 = y1; 16424 r.x2 = x1 + w; 16425 r.y2 = y1 + h; 16426 if (box_intersect(&r, extents)) 16427 sna_damage_add_box(damage, &r); 16428 } 16429skip: 16430 x += c->metrics.characterWidth; 16431 } while (--n); 16432 16433 if (++extents == last_extents) 16434 break; 16435 16436 if (kgem_check_batch(&sna->kgem, 3 + 5)) { 16437 assert(sna->kgem.mode == KGEM_BLT); 16438 b = sna->kgem.batch + sna->kgem.nbatch; 16439 sna->kgem.nbatch += 3; 16440 16441 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 16442 __FUNCTION__, 16443 extents->x1, extents->y1, 16444 extents->x2, extents->y2)); 16445 16446 b[0] = XY_SETUP_CLIP; 16447 b[1] = extents->y1 << 16 | extents->x1; 16448 b[2] = extents->y2 << 16 | extents->x2; 16449 } 16450 } while (1); 16451 16452 if (sna->kgem.nbatch == unwind_batch + (sna->kgem.gen >= 0100 ? 10 : 8)) { 16453 sna->kgem.nbatch = unwind_batch; 16454 sna->kgem.nreloc = unwind_reloc; 16455 if (sna->kgem.nbatch == 0) 16456 kgem_bo_undo(&sna->kgem, bo); 16457 } 16458 16459 assert_pixmap_damage(pixmap); 16460 blt_done(sna); 16461 return true; 16462} 16463 16464static void 16465sna_image_glyph(DrawablePtr drawable, GCPtr gc, 16466 int x, int y, unsigned int n, 16467 CharInfoPtr *info, pointer base) 16468{ 16469 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16470 struct sna *sna = to_sna_from_pixmap(pixmap); 16471 ExtentInfoRec extents; 16472 RegionRec region; 16473 struct sna_damage **damage; 16474 struct kgem_bo *bo; 16475 unsigned hint; 16476 16477 if (n == 0) 16478 return; 16479 16480 sna_glyph_extents(gc->font, info, n, &extents); 16481 region.extents.x1 = x + MIN(0, extents.overallLeft); 16482 region.extents.y1 = y - extents.fontAscent; 16483 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 16484 region.extents.y2 = y + extents.fontDescent; 16485 16486 DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 16487 __FUNCTION__, n, 16488 extents.overallLeft, extents.overallRight, extents.overallWidth, 16489 extents.fontAscent, extents.fontDescent, 16490 region.extents.x1, region.extents.y1, 16491 region.extents.x2, region.extents.y2)); 16492 16493 translate_box(®ion.extents, drawable); 16494 clip_box(®ion.extents, gc); 16495 if (box_empty(®ion.extents)) 16496 return; 16497 16498 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16499 region.extents.x1, region.extents.y1, 16500 region.extents.x2, region.extents.y2)); 16501 16502 region.data = NULL; 16503 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16504 return; 16505 16506 if (FORCE_FALLBACK) 16507 goto fallback; 16508 16509 if (!ACCEL_IMAGE_GLYPH) 16510 goto fallback; 16511 16512 if (wedged(sna)) { 16513 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16514 goto fallback; 16515 } 16516 16517 if (!PM_IS_SOLID(drawable, gc->planemask)) 16518 goto fallback; 16519 16520 if (sna_font_too_large(gc->font)) 16521 goto fallback; 16522 16523 if (region.data == NULL) 16524 hint = IGNORE_DAMAGE | PREFER_GPU; 16525 else 16526 hint = PREFER_GPU; 16527 if ((bo = sna_drawable_use_bo(drawable, hint, 16528 ®ion.extents, &damage)) && 16529 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16530 bo, damage, ®ion, 16531 gc->fgPixel, gc->bgPixel, false)) 16532 goto out; 16533 16534fallback: 16535 DBG(("%s: fallback\n", __FUNCTION__)); 16536 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16537 goto out_gc; 16538 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_WRITE)) 16539 goto out_gc; 16540 16541 if (sigtrap_get() == 0) { 16542 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 16543 fbImageGlyphBlt(drawable, gc, x, y, n, info, base); 16544 FALLBACK_FLUSH(drawable); 16545 sigtrap_put(); 16546 } 16547out_gc: 16548 sna_gc_move_to_gpu(gc); 16549out: 16550 RegionUninit(®ion); 16551} 16552 16553static void 16554sna_poly_glyph(DrawablePtr drawable, GCPtr gc, 16555 int x, int y, unsigned int n, 16556 CharInfoPtr *info, pointer base) 16557{ 16558 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16559 struct sna *sna = to_sna_from_pixmap(pixmap); 16560 ExtentInfoRec extents; 16561 RegionRec region; 16562 struct sna_damage **damage; 16563 struct kgem_bo *bo; 16564 uint32_t fg; 16565 16566 if (n == 0) 16567 return; 16568 16569 sna_glyph_extents(gc->font, info, n, &extents); 16570 region.extents.x1 = x + extents.overallLeft; 16571 region.extents.y1 = y - extents.overallAscent; 16572 region.extents.x2 = x + extents.overallRight; 16573 region.extents.y2 = y + extents.overallDescent; 16574 16575 translate_box(®ion.extents, drawable); 16576 clip_box(®ion.extents, gc); 16577 if (box_empty(®ion.extents)) 16578 return; 16579 16580 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16581 region.extents.x1, region.extents.y1, 16582 region.extents.x2, region.extents.y2)); 16583 16584 region.data = NULL; 16585 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16586 return; 16587 16588 if (FORCE_FALLBACK) 16589 goto fallback; 16590 16591 if (!ACCEL_POLY_GLYPH) 16592 goto fallback; 16593 16594 if (wedged(sna)) { 16595 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 16596 goto fallback; 16597 } 16598 16599 if (!PM_IS_SOLID(drawable, gc->planemask)) 16600 goto fallback; 16601 16602 if (!gc_is_solid(gc, &fg)) 16603 goto fallback; 16604 16605 if (sna_font_too_large(gc->font)) 16606 goto fallback; 16607 16608 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 16609 ®ion.extents, &damage)) && 16610 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 16611 bo, damage, ®ion, fg, -1, true)) 16612 goto out; 16613 16614fallback: 16615 DBG(("%s: fallback\n", __FUNCTION__)); 16616 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16617 goto out_gc; 16618 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16619 MOVE_READ | MOVE_WRITE)) 16620 goto out_gc; 16621 16622 if (sigtrap_get() == 0) { 16623 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 16624 fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); 16625 FALLBACK_FLUSH(drawable); 16626 sigtrap_put(); 16627 } 16628out_gc: 16629 sna_gc_move_to_gpu(gc); 16630out: 16631 RegionUninit(®ion); 16632} 16633 16634static bool 16635sna_push_pixels_solid_blt(GCPtr gc, 16636 PixmapPtr bitmap, 16637 DrawablePtr drawable, 16638 RegionPtr region) 16639{ 16640 PixmapPtr pixmap = get_drawable_pixmap(drawable); 16641 struct sna *sna = to_sna_from_pixmap(pixmap); 16642 struct sna_damage **damage; 16643 struct kgem_bo *bo; 16644 const BoxRec *box; 16645 int16_t dx, dy; 16646 int n; 16647 uint8_t rop = copy_ROP[gc->alu]; 16648 16649 bo = sna_drawable_use_bo(drawable, PREFER_GPU, ®ion->extents, &damage); 16650 if (bo == NULL) 16651 return false; 16652 16653 if (bo->tiling == I915_TILING_Y) { 16654 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 16655 assert(bo == __sna_pixmap_get_bo(pixmap)); 16656 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 16657 if (bo == NULL) { 16658 DBG(("%s: fallback -- unable to change tiling\n", 16659 __FUNCTION__)); 16660 return false; 16661 } 16662 } 16663 16664 if (!kgem_bo_can_blt(&sna->kgem, bo)) 16665 return false; 16666 16667 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 16668 RegionTranslate(region, dx, dy); 16669 16670 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 16671 if (damage) 16672 sna_damage_add_to_pixmap(damage, region, pixmap); 16673 assert_pixmap_damage(pixmap); 16674 16675 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, 16676 region->extents.x1, region->extents.y1, 16677 region->extents.x2, region->extents.y2)); 16678 16679 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 16680 assert(kgem_bo_can_blt(&sna->kgem, bo)); 16681 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16682 16683 /* Region is pre-clipped and translated into pixmap space */ 16684 box = region_rects(region); 16685 n = region_num_rects(region); 16686 do { 16687 int bx1 = (box->x1 - region->extents.x1) & ~7; 16688 int bx2 = (box->x2 - region->extents.x1 + 7) & ~7; 16689 int bw = (bx2 - bx1)/8; 16690 int bh = box->y2 - box->y1; 16691 int bstride = ALIGN(bw, 2); 16692 struct kgem_bo *upload; 16693 void *ptr; 16694 16695 if (!kgem_check_batch(&sna->kgem, 10) || 16696 !kgem_check_bo_fenced(&sna->kgem, bo) || 16697 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 16698 kgem_submit(&sna->kgem); 16699 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 16700 return false; 16701 _kgem_set_mode(&sna->kgem, KGEM_BLT); 16702 } 16703 kgem_bcs_set_tiling(&sna->kgem, NULL, bo); 16704 16705 upload = kgem_create_buffer(&sna->kgem, 16706 bstride*bh, 16707 KGEM_BUFFER_WRITE_INPLACE, 16708 &ptr); 16709 if (!upload) 16710 break; 16711 16712 if (sigtrap_get() == 0) { 16713 uint8_t *dst = ptr; 16714 16715 int src_stride = bitmap->devKind; 16716 uint8_t *src; 16717 uint32_t *b; 16718 16719 assert(src_stride); 16720 src = (uint8_t*)bitmap->devPrivate.ptr; 16721 src += (box->y1 - region->extents.y1) * src_stride + bx1/8; 16722 src_stride -= bstride; 16723 do { 16724 int i = bstride; 16725 do { 16726 *dst++ = byte_reverse(*src++); 16727 *dst++ = byte_reverse(*src++); 16728 i -= 2; 16729 } while (i); 16730 src += src_stride; 16731 } while (--bh); 16732 16733 assert(sna->kgem.mode == KGEM_BLT); 16734 b = sna->kgem.batch + sna->kgem.nbatch; 16735 if (sna->kgem.gen >= 0100) { 16736 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 8; 16737 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16738 b[1] = bo->pitch; 16739 if (sna->kgem.gen >= 040 && bo->tiling) { 16740 b[0] |= BLT_DST_TILED; 16741 b[1] >>= 2; 16742 } 16743 b[1] |= 1 << 29; 16744 b[1] |= blt_depth(drawable->depth) << 24; 16745 b[1] |= rop << 16; 16746 b[2] = box->y1 << 16 | box->x1; 16747 b[3] = box->y2 << 16 | box->x2; 16748 *(uint64_t *)(b+4) = 16749 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 4, bo, 16750 I915_GEM_DOMAIN_RENDER << 16 | 16751 I915_GEM_DOMAIN_RENDER | 16752 KGEM_RELOC_FENCED, 16753 0); 16754 *(uint64_t *)(b+6) = 16755 kgem_add_reloc64(&sna->kgem, sna->kgem.nbatch + 6, upload, 16756 I915_GEM_DOMAIN_RENDER << 16 | 16757 KGEM_RELOC_FENCED, 16758 0); 16759 b[8] = gc->bgPixel; 16760 b[9] = gc->fgPixel; 16761 sna->kgem.nbatch += 10; 16762 } else { 16763 b[0] = XY_MONO_SRC_COPY | 3 << 20 | 6; 16764 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 16765 b[1] = bo->pitch; 16766 if (sna->kgem.gen >= 040 && bo->tiling) { 16767 b[0] |= BLT_DST_TILED; 16768 b[1] >>= 2; 16769 } 16770 b[1] |= 1 << 29; 16771 b[1] |= blt_depth(drawable->depth) << 24; 16772 b[1] |= rop << 16; 16773 b[2] = box->y1 << 16 | box->x1; 16774 b[3] = box->y2 << 16 | box->x2; 16775 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 16776 I915_GEM_DOMAIN_RENDER << 16 | 16777 I915_GEM_DOMAIN_RENDER | 16778 KGEM_RELOC_FENCED, 16779 0); 16780 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, upload, 16781 I915_GEM_DOMAIN_RENDER << 16 | 16782 KGEM_RELOC_FENCED, 16783 0); 16784 b[6] = gc->bgPixel; 16785 b[7] = gc->fgPixel; 16786 16787 sna->kgem.nbatch += 8; 16788 } 16789 sigtrap_put(); 16790 } 16791 16792 kgem_bo_destroy(&sna->kgem, upload); 16793 16794 box++; 16795 } while (--n); 16796 16797 blt_done(sna); 16798 return true; 16799} 16800 16801static void 16802sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable, 16803 int w, int h, 16804 int x, int y) 16805{ 16806 RegionRec region; 16807 16808 if (w == 0 || h == 0) 16809 return; 16810 16811 DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 16812 16813 region.extents.x1 = x; 16814 region.extents.y1 = y; 16815 region.extents.x2 = region.extents.x1 + w; 16816 region.extents.y2 = region.extents.y1 + h; 16817 16818 clip_box(®ion.extents, gc); 16819 if (box_empty(®ion.extents)) 16820 return; 16821 16822 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 16823 region.extents.x1, region.extents.y1, 16824 region.extents.x2, region.extents.y2)); 16825 16826 region.data = NULL; 16827 if (!region_maybe_clip(®ion, gc->pCompositeClip)) 16828 return; 16829 16830 switch (gc->fillStyle) { 16831 case FillSolid: 16832 if (sna_push_pixels_solid_blt(gc, bitmap, drawable, ®ion)) 16833 return; 16834 break; 16835 default: 16836 break; 16837 } 16838 16839 DBG(("%s: fallback\n", __FUNCTION__)); 16840 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 16841 goto out; 16842 if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ)) 16843 goto out; 16844 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 16845 drawable_gc_flags(drawable, gc, false))) 16846 goto out; 16847 16848 if (sigtrap_get() == 0) { 16849 DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n", 16850 __FUNCTION__, w, h, x, y)); 16851 fbPushPixels(gc, bitmap, drawable, w, h, x, y); 16852 FALLBACK_FLUSH(drawable); 16853 sigtrap_put(); 16854 } 16855out: 16856 sna_gc_move_to_gpu(gc); 16857 RegionUninit(®ion); 16858} 16859 16860static const GCOps sna_gc_ops = { 16861 sna_fill_spans, 16862 sna_set_spans, 16863 sna_put_image, 16864 sna_copy_area, 16865 sna_copy_plane, 16866 sna_poly_point, 16867 sna_poly_line, 16868 sna_poly_segment, 16869 sna_poly_rectangle, 16870 sna_poly_arc, 16871 sna_poly_fill_polygon, 16872 sna_poly_fill_rect, 16873 sna_poly_fill_arc, 16874 sna_poly_text8, 16875 sna_poly_text16, 16876 sna_image_text8, 16877 sna_image_text16, 16878 sna_image_glyph, 16879 sna_poly_glyph, 16880 sna_push_pixels, 16881}; 16882 16883static const GCOps sna_gc_ops__cpu = { 16884 fbFillSpans, 16885 fbSetSpans, 16886 fbPutImage, 16887 fbCopyArea, 16888 fbCopyPlane, 16889 sna_poly_point__cpu, 16890 fbPolyLine, 16891 fbPolySegment, 16892 miPolyRectangle, 16893 fbPolyArc, 16894 miFillPolygon, 16895 fbPolyFillRect, 16896 miPolyFillArc, 16897 miPolyText8, 16898 miPolyText16, 16899 miImageText8, 16900 miImageText16, 16901 fbImageGlyphBlt, 16902 fbPolyGlyphBlt, 16903 fbPushPixels 16904}; 16905 16906static GCOps sna_gc_ops__tmp = { 16907 sna_fill_spans, 16908 sna_set_spans, 16909 sna_put_image, 16910 sna_copy_area, 16911 sna_copy_plane, 16912 sna_poly_point, 16913 sna_poly_line, 16914 sna_poly_segment, 16915 sna_poly_rectangle, 16916 sna_poly_arc, 16917 sna_poly_fill_polygon, 16918 sna_poly_fill_rect, 16919 sna_poly_fill_arc, 16920 sna_poly_text8, 16921 sna_poly_text16, 16922 sna_image_text8, 16923 sna_image_text16, 16924 sna_image_glyph, 16925 sna_poly_glyph, 16926 sna_push_pixels, 16927}; 16928 16929static void 16930sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) 16931{ 16932 DBG(("%s(%p) changes=%lx, previous serial=%lx, drawable=%lx\n", __FUNCTION__, gc, 16933 changes, gc->serialNumber, drawable->serialNumber)); 16934 16935 if (changes & (GCClipMask|GCSubwindowMode) || 16936 drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) || 16937 (has_clip(gc) && (changes & (GCClipXOrigin | GCClipYOrigin)))) { 16938 DBG(("%s: recomputing clip\n", __FUNCTION__)); 16939 miComputeCompositeClip(gc, drawable); 16940 DBG(("%s: composite clip=%dx[(%d, %d), (%d, %d)] [%p]\n", 16941 __FUNCTION__, 16942 region_num_rects(gc->pCompositeClip), 16943 gc->pCompositeClip->extents.x1, 16944 gc->pCompositeClip->extents.y1, 16945 gc->pCompositeClip->extents.x2, 16946 gc->pCompositeClip->extents.y2, 16947 gc->pCompositeClip)); 16948 } 16949 16950 assert(gc->pCompositeClip); 16951 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x1 >= drawable->x); 16952 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y1 >= drawable->y); 16953 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.x2 - drawable->x <= drawable->width); 16954 assert(RegionNil(gc->pCompositeClip) || gc->pCompositeClip->extents.y2 - drawable->y <= drawable->height); 16955 16956 sna_gc(gc)->changes |= changes; 16957 sna_gc(gc)->serial = gc->serialNumber; 16958} 16959 16960static const GCFuncs sna_gc_funcs = { 16961 sna_validate_gc, 16962 miChangeGC, 16963 miCopyGC, 16964 miDestroyGC, 16965 miChangeClip, 16966 miDestroyClip, 16967 miCopyClip 16968}; 16969 16970static const GCFuncs sna_gc_funcs__cpu = { 16971 fbValidateGC, 16972 miChangeGC, 16973 miCopyGC, 16974 miDestroyGC, 16975 miChangeClip, 16976 miDestroyClip, 16977 miCopyClip 16978}; 16979 16980static int sna_create_gc(GCPtr gc) 16981{ 16982 gc->miTranslate = 1; 16983 gc->fExpose = 1; 16984 16985 gc->freeCompClip = 0; 16986 gc->pCompositeClip = 0; 16987#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0) 16988 gc->pRotatedPixmap = 0; 16989#endif 16990 16991 fb_gc(gc)->bpp = bits_per_pixel(gc->depth); 16992 16993 gc->funcs = (GCFuncs *)&sna_gc_funcs; 16994 gc->ops = (GCOps *)&sna_gc_ops; 16995 return true; 16996} 16997 16998static bool 16999sna_get_image__inplace(PixmapPtr pixmap, 17000 RegionPtr region, 17001 char *dst, 17002 unsigned flags, 17003 bool idle) 17004{ 17005 struct sna_pixmap *priv = sna_pixmap(pixmap); 17006 struct sna *sna = to_sna_from_pixmap(pixmap); 17007 char *src; 17008 17009 if (!USE_INPLACE) 17010 return false; 17011 17012 assert(priv && priv->gpu_bo); 17013 17014 switch (priv->gpu_bo->tiling) { 17015 case I915_TILING_Y: 17016 return false; 17017 case I915_TILING_X: 17018 if (!sna->kgem.memcpy_from_tiled_x) 17019 return false; 17020 default: 17021 break; 17022 } 17023 17024 if ((flags & MOVE_INPLACE_HINT) == 0 && 17025 !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) 17026 return false; 17027 17028 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 17029 return false; 17030 17031 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 17032 return false; 17033 17034 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 17035 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 17036 17037 if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) { 17038 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 17039 if (src == NULL) 17040 return false; 17041 17042 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 17043 } else { 17044 src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo); 17045 if (src == NULL) 17046 return false; 17047 17048 kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo); 17049 } 17050 17051 if (sigtrap_get()) 17052 return false; 17053 17054 if (priv->gpu_bo->tiling) { 17055 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 17056 memcpy_from_tiled_x(&sna->kgem, src, dst, 17057 pixmap->drawable.bitsPerPixel, 17058 priv->gpu_bo->pitch, 17059 PixmapBytePad(region->extents.x2 - region->extents.x1, 17060 pixmap->drawable.depth), 17061 region->extents.x1, region->extents.y1, 17062 0, 0, 17063 region->extents.x2 - region->extents.x1, 17064 region->extents.y2 - region->extents.y1); 17065 } else { 17066 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 17067 memcpy_blt(src, dst, 17068 pixmap->drawable.bitsPerPixel, 17069 priv->gpu_bo->pitch, 17070 PixmapBytePad(region->extents.x2 - region->extents.x1, 17071 pixmap->drawable.depth), 17072 region->extents.x1, region->extents.y1, 17073 0, 0, 17074 region->extents.x2 - region->extents.x1, 17075 region->extents.y2 - region->extents.y1); 17076 if (!priv->shm) { 17077 pixmap->devPrivate.ptr = src; 17078 pixmap->devKind = priv->gpu_bo->pitch; 17079 priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT; 17080 assert_pixmap_map(pixmap, priv); 17081 priv->cpu &= priv->mapped == MAPPED_CPU; 17082 } 17083 } 17084 17085 sigtrap_put(); 17086 return true; 17087} 17088 17089static bool 17090sna_get_image__blt(PixmapPtr pixmap, 17091 RegionPtr region, 17092 char *dst, 17093 unsigned flags) 17094{ 17095 struct sna_pixmap *priv = sna_pixmap(pixmap); 17096 struct sna *sna = to_sna_from_pixmap(pixmap); 17097 struct kgem_bo *dst_bo; 17098 bool ok = false; 17099 int pitch; 17100 17101 assert(priv && priv->gpu_bo); 17102 17103 if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS) 17104 return false; 17105 17106 if (!sna->kgem.can_blt_cpu) 17107 return false; 17108 17109 if ((priv->create & (KGEM_CAN_CREATE_GTT | KGEM_CAN_CREATE_LARGE)) == KGEM_CAN_CREATE_GTT && 17110 kgem_bo_can_map(&sna->kgem, priv->gpu_bo)) { 17111 if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT)) 17112 return false; 17113 17114 if (priv->gpu_damage == NULL) 17115 return false; 17116 17117 assert(priv->gpu_bo); 17118 if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 17119 return false; 17120 } else { 17121 if (priv->gpu_damage == NULL) 17122 return false; 17123 17124 assert(priv->gpu_bo); 17125 } 17126 17127 if (priv->move_to_gpu && !priv->move_to_gpu(sna, priv, MOVE_READ)) 17128 return false; 17129 17130 DBG(("%s: download through a temporary map\n", __FUNCTION__)); 17131 17132 assert(sna_damage_contains_box(&priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 17133 assert(sna_damage_contains_box(&priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 17134 17135 pitch = PixmapBytePad(region->extents.x2 - region->extents.x1, 17136 pixmap->drawable.depth); 17137 dst_bo = kgem_create_map(&sna->kgem, dst, 17138 pitch * (region->extents.y2 - region->extents.y1), 17139 false); 17140 if (dst_bo) { 17141 dst_bo->pitch = pitch; 17142 kgem_bo_mark_unreusable(dst_bo); 17143 17144 ok = sna->render.copy_boxes(sna, GXcopy, 17145 &pixmap->drawable, priv->gpu_bo, 0, 0, 17146 &pixmap->drawable, dst_bo, 17147 -region->extents.x1, 17148 -region->extents.y1, 17149 ®ion->extents, 1, 17150 COPY_LAST); 17151 17152 kgem_bo_sync__cpu(&sna->kgem, dst_bo); 17153 assert(dst_bo->rq == NULL); 17154 kgem_bo_destroy(&sna->kgem, dst_bo); 17155 } 17156 17157 return ok; 17158} 17159 17160static bool 17161sna_get_image__fast(PixmapPtr pixmap, 17162 RegionPtr region, 17163 char *dst, 17164 unsigned flags) 17165{ 17166 struct sna_pixmap *priv = sna_pixmap(pixmap); 17167 17168 DBG(("%s: attached?=%d, has gpu damage?=%d\n", 17169 __FUNCTION__, priv != NULL, priv && priv->gpu_damage)); 17170 if (priv == NULL || priv->gpu_damage == NULL) 17171 return false; 17172 17173 if (priv->clear && sigtrap_get() == 0) { 17174 int w = region->extents.x2 - region->extents.x1; 17175 int h = region->extents.y2 - region->extents.y1; 17176 int pitch = PixmapBytePad(w, pixmap->drawable.depth); 17177 17178 DBG(("%s: applying clear [%08x]\n", 17179 __FUNCTION__, priv->clear_color)); 17180 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 17181 assert(priv->cpu_damage == NULL); 17182 sigtrap_assert_active(); 17183 17184 if (priv->clear_color == 0 || 17185 pixmap->drawable.bitsPerPixel == 8 || 17186 priv->clear_color == (1U << pixmap->drawable.depth) - 1) { 17187 DBG(("%s: memset clear [%02x]\n", 17188 __FUNCTION__, priv->clear_color & 0xff)); 17189 memset(dst, priv->clear_color, pitch * h); 17190 } else { 17191 pixman_fill((uint32_t *)dst, 17192 pitch/sizeof(uint32_t), 17193 pixmap->drawable.bitsPerPixel, 17194 0, 0, 17195 w, h, 17196 priv->clear_color); 17197 } 17198 17199 sigtrap_put(); 17200 return true; 17201 } 17202 17203 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 17204 !sna_damage_contains_box__no_reduce(priv->gpu_damage, 17205 ®ion->extents)) 17206 return false; 17207 17208 if (sna_get_image__inplace(pixmap, region, dst, flags, true)) 17209 return true; 17210 17211 if (sna_get_image__blt(pixmap, region, dst, flags)) 17212 return true; 17213 17214 if (sna_get_image__inplace(pixmap, region, dst, flags, false)) 17215 return true; 17216 17217 return false; 17218} 17219 17220static void 17221sna_get_image(DrawablePtr drawable, 17222 int x, int y, int w, int h, 17223 unsigned int format, unsigned long mask, 17224 char *dst) 17225{ 17226 RegionRec region; 17227 unsigned int flags; 17228 17229 if (!fbDrawableEnabled(drawable)) 17230 return; 17231 17232 DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n", 17233 __FUNCTION__, 17234 (long)get_drawable_pixmap(drawable)->drawable.serialNumber, 17235 x, y, w, h, format, mask, drawable->depth)); 17236 17237 flags = MOVE_READ; 17238 if ((w | h) == 1) 17239 flags |= MOVE_INPLACE_HINT; 17240 if (w == drawable->width) 17241 flags |= MOVE_WHOLE_HINT; 17242 17243 if (ACCEL_GET_IMAGE && 17244 !FORCE_FALLBACK && 17245 format == ZPixmap && 17246 drawable->bitsPerPixel >= 8) { 17247 PixmapPtr pixmap = get_drawable_pixmap(drawable); 17248 int16_t dx, dy; 17249 17250 get_drawable_deltas(drawable, pixmap, &dx, &dy); 17251 region.extents.x1 = x + drawable->x + dx; 17252 region.extents.y1 = y + drawable->y + dy; 17253 region.extents.x2 = region.extents.x1 + w; 17254 region.extents.y2 = region.extents.y1 + h; 17255 region.data = NULL; 17256 17257 if (sna_get_image__fast(pixmap, ®ion, dst, flags)) 17258 goto apply_planemask; 17259 17260 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 17261 ®ion, flags)) 17262 return; 17263 17264 DBG(("%s: copy box (%d, %d), (%d, %d)\n", 17265 __FUNCTION__, 17266 region.extents.x1, region.extents.y1, 17267 region.extents.x2, region.extents.y2)); 17268 assert(has_coherent_ptr(to_sna_from_pixmap(pixmap), sna_pixmap(pixmap), MOVE_READ)); 17269 if (sigtrap_get() == 0) { 17270 assert(pixmap->devKind); 17271 memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel, 17272 pixmap->devKind, PixmapBytePad(w, drawable->depth), 17273 region.extents.x1, region.extents.y1, 0, 0, w, h); 17274 sigtrap_put(); 17275 } 17276 17277apply_planemask: 17278 if (!PM_IS_SOLID(drawable, mask)) { 17279 FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel); 17280 FbStip *d = (FbStip *)dst; 17281 int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h; 17282 17283 for (i = 0; i < n; i++) 17284 d[i] &= pm; 17285 } 17286 } else { 17287 region.extents.x1 = x + drawable->x; 17288 region.extents.y1 = y + drawable->y; 17289 region.extents.x2 = region.extents.x1 + w; 17290 region.extents.y2 = region.extents.y1 + h; 17291 region.data = NULL; 17292 17293 if (sna_drawable_move_region_to_cpu(drawable, ®ion, flags)) 17294 fbGetImage(drawable, x, y, w, h, format, mask, dst); 17295 } 17296} 17297 17298static void 17299sna_get_spans(DrawablePtr drawable, int wMax, 17300 DDXPointPtr pt, int *width, int n, char *start) 17301{ 17302 RegionRec region; 17303 17304 if (!fbDrawableEnabled(drawable)) 17305 return; 17306 17307 if (sna_spans_extents(drawable, NULL, n, pt, width, ®ion.extents) == 0) 17308 return; 17309 17310 region.data = NULL; 17311 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_READ)) 17312 return; 17313 17314 fbGetSpans(drawable, wMax, pt, width, n, start); 17315} 17316 17317static void 17318sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src) 17319{ 17320 PixmapPtr pixmap = get_window_pixmap(win); 17321 struct sna *sna = to_sna_from_pixmap(pixmap); 17322 RegionRec dst; 17323 int dx, dy; 17324 17325 DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y)); 17326 if (!fbWindowEnabled(win)) 17327 return; 17328 17329 dx = origin.x - win->drawable.x; 17330 dy = origin.y - win->drawable.y; 17331 RegionTranslate(src, -dx, -dy); 17332 17333 RegionNull(&dst); 17334 RegionIntersect(&dst, &win->borderClip, src); 17335 if (box_empty(&dst.extents)) 17336 return; 17337 17338#ifdef COMPOSITE 17339 if (pixmap->screen_x | pixmap->screen_y) 17340 RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y); 17341#endif 17342 17343 if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) { 17344 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 17345 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 17346 return; 17347 17348 if (sigtrap_get() == 0) { 17349 miCopyRegion(&pixmap->drawable, &pixmap->drawable, 17350 0, &dst, dx, dy, fbCopyNtoN, 0, NULL); 17351 sigtrap_put(); 17352 } 17353 } else { 17354 sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL, 17355 &dst, dx, dy, 0, NULL); 17356 } 17357 17358 RegionUninit(&dst); 17359} 17360 17361static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) 17362{ 17363 bool ret = true; 17364 17365 DBG(("%s\n", __FUNCTION__)); 17366 17367 /* Check if the fb layer wishes to modify the attached pixmaps, 17368 * to fix up mismatches between the window and pixmap depths. 17369 */ 17370 if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) { 17371 DBG(("%s: flushing background pixmap\n", __FUNCTION__)); 17372 ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap); 17373 } 17374 17375 if (mask & CWBorderPixmap && win->borderIsPixel == false) { 17376 DBG(("%s: flushing border pixmap\n", __FUNCTION__)); 17377 ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap); 17378 } 17379 17380 return ret; 17381} 17382 17383void sna_accel_flush(struct sna *sna) 17384{ 17385 struct sna_pixmap *priv; 17386 17387 /* XXX we should be able to reduce the frequency of flushes further 17388 * by checking for outgoing damage events or sync replies. Tricky, 17389 * and doesn't appear to mitigate the performance loss. 17390 */ 17391 DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__, 17392 sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps))); 17393 17394 /* flush any pending damage from shadow copies to tfp clients */ 17395 while (!list_is_empty(&sna->flush_pixmaps)) { 17396 bool ret; 17397 17398 priv = list_first_entry(&sna->flush_pixmaps, 17399 struct sna_pixmap, flush_list); 17400 17401 list_del(&priv->flush_list); 17402 if (priv->shm) { 17403 DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n", 17404 __FUNCTION__, 17405 priv->pixmap->drawable.serialNumber, 17406 priv->pixmap->refcnt)); 17407 assert(!priv->flush); 17408 ret = sna_pixmap_move_to_cpu(priv->pixmap, 17409 MOVE_READ | MOVE_WRITE); 17410 assert(!ret || priv->gpu_bo == NULL); 17411 if (priv->pixmap->refcnt == 0) { 17412 sna_damage_destroy(&priv->cpu_damage); 17413 __sna_free_pixmap(sna, priv->pixmap, priv); 17414 } 17415 } else { 17416 unsigned hints; 17417 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__, 17418 priv->pixmap->drawable.serialNumber)); 17419 assert(priv->flush); 17420 hints = MOVE_READ | __MOVE_FORCE; 17421 if (priv->flush & FLUSH_WRITE) 17422 hints |= MOVE_WRITE; 17423 if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) { 17424 if (priv->flush & FLUSH_WRITE) { 17425 kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 17426 sna_damage_all(&priv->gpu_damage, priv->pixmap); 17427 assert(priv->cpu_damage == NULL); 17428 assert(priv->clear == false); 17429 } 17430 } 17431 } 17432 (void)ret; 17433 } 17434 17435 if (sna->kgem.flush) 17436 kgem_submit(&sna->kgem); 17437} 17438 17439static void 17440sna_shm_flush_callback(CallbackListPtr *list, 17441 pointer user_data, pointer call_data) 17442{ 17443 struct sna *sna = user_data; 17444 17445 if (!sna->needs_shm_flush) 17446 return; 17447 17448 sna_accel_flush(sna); 17449 sna->needs_shm_flush = false; 17450} 17451 17452static void 17453sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data) 17454{ 17455 struct sna *sna = user_data; 17456 17457#if 0 /* XXX requires mesa to implement glXWaitX()! */ 17458 if (!sna->needs_dri_flush) 17459 return; 17460 17461 sna_accel_flush(sna); 17462 sna->needs_dri_flush = false; 17463#else 17464 sna_accel_flush(sna); 17465#endif 17466} 17467 17468static void 17469sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data) 17470{ 17471 EventInfoRec *eventinfo = call_data; 17472 struct sna *sna = user_data; 17473 int i; 17474 17475 if (sna->needs_dri_flush) 17476 return; 17477 17478 for (i = 0; i < eventinfo->count; i++) { 17479 if (eventinfo->events[i].u.u.type == sna->damage_event) { 17480 sna->needs_dri_flush = true; 17481 return; 17482 } 17483 } 17484} 17485 17486static struct sna_pixmap *sna_accel_scanout(struct sna *sna) 17487{ 17488 struct sna_pixmap *priv; 17489 17490 if (sna->mode.front_active == 0) 17491 return NULL; 17492 17493 assert(sna->vblank_interval); 17494 assert(sna->front); 17495 assert(!sna->mode.hidden); 17496 17497 priv = sna_pixmap(sna->front); 17498 if (priv->gpu_bo == NULL) 17499 return NULL; 17500 17501 return priv; 17502} 17503 17504#define TIME currentTime.milliseconds 17505static void sna_accel_disarm_timer(struct sna *sna, int id) 17506{ 17507 DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME)); 17508 sna->timer_active &= ~(1<<id); 17509} 17510 17511static bool has_offload_slaves(struct sna *sna) 17512{ 17513#if HAS_PIXMAP_SHARING 17514 ScreenPtr screen = to_screen_from_sna(sna); 17515 PixmapDirtyUpdatePtr dirty; 17516 17517 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17518 assert(dirty->src == sna->front); 17519 if (RegionNotEmpty(DamageRegion(dirty->damage))) 17520 return true; 17521 } 17522#endif 17523 return false; 17524} 17525 17526static bool has_shadow(struct sna *sna) 17527{ 17528 DamagePtr damage; 17529 17530 if (!sna->mode.shadow_enabled) 17531 return false; 17532 17533 damage = sna->mode.shadow_damage; 17534 assert(damage); 17535 17536 DBG(("%s: has pending damage? %d, outstanding flips: %d\n", 17537 __FUNCTION__, 17538 RegionNotEmpty(DamageRegion(damage)), 17539 sna->mode.flip_active)); 17540 17541 return RegionNotEmpty(DamageRegion(damage)); 17542} 17543 17544static bool start_flush(struct sna *sna) 17545{ 17546 struct sna_pixmap *scanout; 17547 17548 if (has_offload_slaves(sna)) { 17549 DBG(("%s: has offload slaves\n", __FUNCTION__)); 17550 return true; 17551 } 17552 17553 if (has_shadow(sna)) { 17554 DBG(("%s: has dirty shadow\n", __FUNCTION__)); 17555 return true; 17556 } 17557 17558 scanout = sna_accel_scanout(sna); 17559 if (!scanout) 17560 return false; 17561 17562 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17563 scanout->gpu_bo->needs_flush = true; 17564 return true; 17565 } 17566 17567 if (scanout->cpu_damage || scanout->gpu_bo->needs_flush) 17568 return true; 17569 17570 kgem_scanout_flush(&sna->kgem, scanout->gpu_bo); 17571 return false; 17572} 17573 17574static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout) 17575{ 17576 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 17577 __FUNCTION__, 17578 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 17579 has_shadow(sna), has_offload_slaves(sna), 17580 scanout && scanout->cpu_damage != NULL, 17581 scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL)); 17582 17583 if (has_offload_slaves(sna)) 17584 return true; 17585 17586 if (has_shadow(sna)) 17587 return true; 17588 17589 if (!scanout) 17590 return false; 17591 17592 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 17593 scanout->gpu_bo->needs_flush = true; 17594 return true; 17595 } 17596 17597 return scanout->cpu_damage || scanout->gpu_bo->needs_flush; 17598} 17599 17600static void timer_enable(struct sna *sna, int whom, int interval) 17601{ 17602 if (!sna->timer_active) 17603 UpdateCurrentTimeIf(); 17604 sna->timer_active |= 1 << whom; 17605 sna->timer_expire[whom] = TIME + interval; 17606 DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); 17607} 17608 17609static bool sna_scanout_do_flush(struct sna *sna) 17610{ 17611 int interval = sna->vblank_interval ?: 50; 17612 if (sna->timer_active & (1<<(FLUSH_TIMER))) { 17613 int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME; 17614 DBG(("%s: flush timer active: delta=%d\n", 17615 __FUNCTION__, delta)); 17616 if (delta <= 3) { 17617 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17618 sna->timer_expire[FLUSH_TIMER] = TIME + interval; 17619 return true; 17620 } 17621 } else { 17622 if (start_flush(sna)) 17623 timer_enable(sna, FLUSH_TIMER, interval/2); 17624 } 17625 17626 return false; 17627} 17628 17629static bool sna_accel_do_throttle(struct sna *sna) 17630{ 17631 if (sna->timer_active & (1<<(THROTTLE_TIMER))) { 17632 int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME; 17633 if (delta <= 3) { 17634 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17635 sna->timer_expire[THROTTLE_TIMER] = TIME + 20; 17636 return true; 17637 } 17638 } else if (!sna->kgem.need_retire) { 17639 DBG(("%s -- no pending activity\n", __FUNCTION__)); 17640 } else 17641 timer_enable(sna, THROTTLE_TIMER, 20); 17642 17643 return false; 17644} 17645 17646static bool sna_accel_do_expire(struct sna *sna) 17647{ 17648 if (sna->timer_active & (1<<(EXPIRE_TIMER))) { 17649 int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME; 17650 if (delta <= 3) { 17651 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 17652 sna->timer_expire[EXPIRE_TIMER] = 17653 TIME + MAX_INACTIVE_TIME * 1000; 17654 return true; 17655 } 17656 } else if (sna->kgem.need_expire) 17657 timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000); 17658 17659 return false; 17660} 17661 17662static void sna_accel_post_damage(struct sna *sna) 17663{ 17664#if HAS_PIXMAP_SHARING 17665#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 25 17666#define slave_dst secondary_dst 17667#define master_pixmap primary_pixmap 17668#endif 17669 ScreenPtr screen = to_screen_from_sna(sna); 17670 PixmapDirtyUpdatePtr dirty; 17671 17672 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 17673 RegionRec region, *damage; 17674 PixmapPtr src, dst; 17675 const BoxRec *box; 17676 int16_t dx, dy; 17677 int n; 17678 17679 damage = DamageRegion(dirty->damage); 17680 if (RegionNil(damage)) 17681 continue; 17682 17683 src = (PixmapPtr)dirty->src; 17684 dst = dirty->slave_dst->master_pixmap; 17685 17686 region.extents.x1 = dirty->x; 17687 region.extents.x2 = dirty->x + dst->drawable.width; 17688 region.extents.y1 = dirty->y; 17689 region.extents.y2 = dirty->y + dst->drawable.height; 17690 region.data = NULL; 17691 17692 DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%d, ((%d, %d), (%d, %d))\n", __FUNCTION__, 17693 damage->extents.x1, damage->extents.y1, 17694 damage->extents.x2, damage->extents.y2, 17695 region_num_rects(damage), 17696 dst->drawable.serialNumber, 17697 region.extents.x1, region.extents.y1, 17698 region.extents.x2, region.extents.y2)); 17699 17700 RegionIntersect(®ion, ®ion, damage); 17701 if (RegionNil(®ion)) 17702 goto skip; 17703 17704 dx = -dirty->x; 17705 dy = -dirty->y; 17706#if HAS_DIRTYTRACKING2 17707 dx += dirty->dst_x; 17708 dy += dirty->dst_y; 17709#endif 17710 RegionTranslate(®ion, dx, dy); 17711 DamageRegionAppend(&dirty->slave_dst->drawable, ®ion); 17712 17713 DBG(("%s: slave: ((%d, %d), (%d, %d))x%d\n", __FUNCTION__, 17714 region.extents.x1, region.extents.y1, 17715 region.extents.x2, region.extents.y2, 17716 region_num_rects(®ion))); 17717 17718 box = region_rects(®ion); 17719 n = region_num_rects(®ion); 17720 if (wedged(sna)) { 17721fallback: 17722 if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) 17723 goto skip; 17724 17725 if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT)) 17726 goto skip; 17727 17728 if (sigtrap_get() == 0) { 17729 assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel); 17730 do { 17731 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 17732 __FUNCTION__, 17733 box->x1 - dx, box->y1 - dy, 17734 box->x1, box->y1, 17735 box->x2 - box->x1, box->y2 - box->y1)); 17736 17737 assert(box->x2 > box->x1); 17738 assert(box->y2 > box->y1); 17739 17740 assert(box->x1 - dx >= 0); 17741 assert(box->y1 - dy >= 0); 17742 assert(box->x2 - dx <= src->drawable.width); 17743 assert(box->y2 - dy <= src->drawable.height); 17744 17745 assert(box->x1 >= 0); 17746 assert(box->y1 >= 0); 17747 assert(box->x2 <= src->drawable.width); 17748 assert(box->y2 <= src->drawable.height); 17749 17750 assert(has_coherent_ptr(sna, sna_pixmap(src), MOVE_READ)); 17751 assert(has_coherent_ptr(sna, sna_pixmap(dst), MOVE_WRITE)); 17752 assert(src->devKind); 17753 assert(dst->devKind); 17754 memcpy_blt(src->devPrivate.ptr, 17755 dst->devPrivate.ptr, 17756 src->drawable.bitsPerPixel, 17757 src->devKind, dst->devKind, 17758 box->x1 - dx, box->y1 - dy, 17759 box->x1, box->y1, 17760 box->x2 - box->x1, box->y2 - box->y1); 17761 box++; 17762 } while (--n); 17763 sigtrap_put(); 17764 } 17765 } else { 17766 if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17767 goto fallback; 17768 17769 if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) 17770 goto fallback; 17771 17772 if (!sna->render.copy_boxes(sna, GXcopy, 17773 &src->drawable, __sna_pixmap_get_bo(src), -dx, -dy, 17774 &dst->drawable, __sna_pixmap_get_bo(dst), 0, 0, 17775 box, n, COPY_LAST)) 17776 goto fallback; 17777 17778 /* Before signalling the slave via ProcessPending, 17779 * ensure not only the batch is submitted as the 17780 * slave may be using the Damage callback to perform 17781 * its copy, but also that the memory must be coherent 17782 * - we need to treat it as uncached for the PCI slave 17783 * will bypass LLC. 17784 */ 17785 kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst)); 17786 } 17787 17788 DamageRegionProcessPending(&dirty->slave_dst->drawable); 17789skip: 17790 RegionUninit(®ion); 17791 DamageEmpty(dirty->damage); 17792 } 17793#endif 17794} 17795 17796static void sna_scanout_flush(struct sna *sna) 17797{ 17798 struct sna_pixmap *priv = sna_accel_scanout(sna); 17799 bool busy; 17800 17801 DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n", 17802 __FUNCTION__, (long)TIME, 17803 priv && priv->cpu_damage, 17804 priv && priv->gpu_bo->exec != NULL, 17805 sna->kgem.nbatch, 17806 sna->kgem.busy)); 17807 17808 busy = stop_flush(sna, priv); 17809 if (!sna->kgem.busy && !busy) 17810 sna_accel_disarm_timer(sna, FLUSH_TIMER); 17811 sna->kgem.busy = busy; 17812 17813 if (priv && 17814 sna->mode.shadow_damage == NULL && 17815 sna_pixmap_force_to_gpu(priv->pixmap, 17816 MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) 17817 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 17818 17819 sna_mode_redisplay(sna); 17820 sna_accel_post_damage(sna); 17821} 17822 17823static void sna_accel_throttle(struct sna *sna) 17824{ 17825 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17826 17827 if (sna->kgem.need_throttle) { 17828 kgem_submit(&sna->kgem); 17829 kgem_throttle(&sna->kgem); 17830 } 17831 17832 if (!sna->kgem.need_retire) 17833 sna_accel_disarm_timer(sna, THROTTLE_TIMER); 17834} 17835 17836static void sna_pixmap_expire(struct sna *sna) 17837{ 17838 while (sna->freed_pixmap) { 17839 PixmapPtr pixmap = __pop_freed_pixmap(sna); 17840 free(sna_pixmap(pixmap)); 17841 FreePixmap(pixmap); 17842 } 17843} 17844 17845static void sna_accel_expire(struct sna *sna) 17846{ 17847 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 17848 17849 kgem_expire_cache(&sna->kgem); 17850 sna_pixmap_expire(sna); 17851 17852 if (!sna->kgem.need_expire) 17853 sna_accel_disarm_timer(sna, EXPIRE_TIMER); 17854} 17855 17856#ifdef DEBUG_MEMORY 17857static bool sna_accel_do_debug_memory(struct sna *sna) 17858{ 17859 int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME; 17860 17861 if (delta <= 3) { 17862 sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000; 17863 return true; 17864 } else 17865 return false; 17866} 17867 17868static void sna_accel_debug_memory(struct sna *sna) 17869{ 17870 ErrorF("Allocated pixmaps: %d (cached: %d), bo: %d, %lu bytes (CPU bo: %d, %lu bytes)\n", 17871 sna->debug_memory.pixmap_allocs, 17872 sna->debug_memory.pixmap_cached, 17873 sna->kgem.debug_memory.bo_allocs, 17874 (unsigned long)sna->kgem.debug_memory.bo_bytes, 17875 sna->debug_memory.cpu_bo_allocs, 17876 (unsigned long)sna->debug_memory.cpu_bo_bytes); 17877 17878#ifdef VALGRIND_DO_ADDED_LEAK_CHECK 17879 VG(VALGRIND_DO_ADDED_LEAK_CHECK); 17880#endif 17881} 17882 17883#else 17884#define sna_accel_do_debug_memory(x) 0 17885static void sna_accel_debug_memory(struct sna *sna) { } 17886#endif 17887 17888static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL }; 17889 17890static PixmapPtr 17891sna_get_window_pixmap(WindowPtr window) 17892{ 17893 return get_window_pixmap(window); 17894} 17895 17896static void 17897sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) 17898{ 17899 DBG(("%s: window=%ld, old pixmap=%ld new pixmap=%ld\n", 17900 __FUNCTION__, window->drawable.id, 17901 get_window_pixmap(window) ? get_window_pixmap(window)->drawable.serialNumber : 0, 17902 pixmap->drawable.serialNumber)); 17903 17904 sna_dri2_decouple_window(window); 17905 17906 *(PixmapPtr *)__get_private(window, sna_window_key) = pixmap; 17907} 17908 17909struct sna_visit_set_pixmap_window { 17910 PixmapPtr old, new; 17911}; 17912 17913static int 17914sna_visit_set_window_pixmap(WindowPtr window, pointer data) 17915{ 17916 struct sna_visit_set_pixmap_window *visit = data; 17917 17918 if (sna_get_window_pixmap(window) == visit->old) { 17919 window->drawable.pScreen->SetWindowPixmap(window, visit->new); 17920 return WT_WALKCHILDREN; 17921 } 17922 17923 return WT_DONTWALKCHILDREN; 17924} 17925 17926static void 17927migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front) 17928{ 17929#if HAS_PIXMAP_SHARING 17930 ScreenPtr screen = old_front->drawable.pScreen; 17931 PixmapDirtyUpdatePtr dirty, safe; 17932 17933 xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) { 17934 assert(dirty->src == old_front); 17935 if ((PixmapPtr)dirty->src != old_front) 17936 continue; 17937 17938 DamageUnregister(&dirty->src->drawable, dirty->damage); 17939 DamageDestroy(dirty->damage); 17940 17941 dirty->damage = DamageCreate(NULL, NULL, 17942 DamageReportNone, 17943 TRUE, screen, screen); 17944 if (!dirty->damage) { 17945 xorg_list_del(&dirty->ent); 17946 free(dirty); 17947 continue; 17948 } 17949 17950 DamageRegister(&new_front->drawable, dirty->damage); 17951 dirty->src = (DrawablePtr)new_front; 17952 } 17953#endif 17954} 17955 17956static void 17957sna_set_screen_pixmap(PixmapPtr pixmap) 17958{ 17959 ScreenPtr screen = pixmap->drawable.pScreen; 17960 PixmapPtr old_front = screen->devPrivate; 17961 WindowPtr root; 17962 17963 DBG(("%s: changing from pixmap=%ld to pixmap=%ld, (sna->front=%ld)\n", 17964 __FUNCTION__, 17965 old_front ? (long)old_front->drawable.serialNumber : 0, 17966 pixmap ? (long)pixmap->drawable.serialNumber : 0, 17967 to_sna_from_pixmap(pixmap)->front ? (long)to_sna_from_pixmap(pixmap)->front->drawable.serialNumber : 0)); 17968 17969 assert(to_sna_from_pixmap(pixmap) == to_sna_from_screen(screen)); 17970 assert(to_sna_from_pixmap(pixmap)->front == old_front); 17971 17972 if (old_front) { 17973 assert(to_sna_from_pixmap(old_front)->front == old_front); 17974 migrate_dirty_tracking(old_front, pixmap); 17975 } 17976 17977 root = get_root_window(screen); 17978 if (root) { 17979 struct sna_visit_set_pixmap_window visit = { old_front, pixmap }; 17980 TraverseTree(root, sna_visit_set_window_pixmap, &visit); 17981 assert(fbGetWindowPixmap(root) == pixmap); 17982 } 17983 17984 to_sna_from_pixmap(pixmap)->front = pixmap; 17985 screen->devPrivate = pixmap; 17986 pixmap->refcnt++; 17987 17988 if (old_front) 17989 screen->DestroyPixmap(old_front); 17990} 17991 17992static Bool 17993sna_create_window(WindowPtr win) 17994{ 17995 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 17996 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate); 17997 return TRUE; 17998} 17999 18000static Bool 18001sna_map_window(WindowPtr win) 18002{ 18003 return TRUE; 18004} 18005 18006static Bool 18007sna_position_window(WindowPtr win, int x, int y) 18008{ 18009 return TRUE; 18010} 18011 18012static Bool 18013sna_unmap_window(WindowPtr win) 18014{ 18015 return TRUE; 18016} 18017 18018static Bool 18019sna_destroy_window(WindowPtr win) 18020{ 18021 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id)); 18022 sna_video_destroy_window(win); 18023 sna_dri2_destroy_window(win); 18024 return TRUE; 18025} 18026 18027static void 18028sna_query_best_size(int class, 18029 unsigned short *width, unsigned short *height, 18030 ScreenPtr screen) 18031{ 18032 unsigned short w; 18033 18034 switch (class) { 18035 case CursorShape: 18036 if (*width > screen->width) 18037 *width = screen->width; 18038 if (*height > screen->height) 18039 *height = screen->height; 18040 break; 18041 18042 case TileShape: 18043 case StippleShape: 18044 w = *width; 18045 if ((w & (w - 1)) && w < FB_UNIT) { 18046 for (w = 1; w < *width; w <<= 1) 18047 ; 18048 *width = w; 18049 } 18050 break; 18051 } 18052} 18053 18054static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def) 18055{ 18056} 18057 18058static bool sna_picture_init(ScreenPtr screen) 18059{ 18060 PictureScreenPtr ps; 18061 18062 DBG(("%s\n", __FUNCTION__)); 18063 18064 if (!miPictureInit(screen, NULL, 0)) 18065 return false; 18066 18067 ps = GetPictureScreen(screen); 18068 assert(ps != NULL); 18069 assert(ps->CreatePicture != NULL); 18070 assert(ps->DestroyPicture != NULL); 18071 18072 ps->Composite = sna_composite; 18073 ps->CompositeRects = sna_composite_rectangles; 18074 ps->Glyphs = sna_glyphs; 18075 if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0])) 18076 ps->Glyphs = sna_glyphs__shared; 18077 ps->UnrealizeGlyph = sna_glyph_unrealize; 18078 ps->AddTraps = sna_add_traps; 18079 ps->Trapezoids = sna_composite_trapezoids; 18080#if HAS_PIXMAN_TRIANGLES 18081 ps->Triangles = sna_composite_triangles; 18082#if PICTURE_SCREEN_VERSION >= 2 18083 ps->TriStrip = sna_composite_tristrip; 18084 ps->TriFan = sna_composite_trifan; 18085#endif 18086#endif 18087 18088 return true; 18089} 18090 18091static bool sna_option_accel_none(struct sna *sna) 18092{ 18093 const char *s; 18094 18095 if (wedged(sna)) 18096 return true; 18097 18098 if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE)) 18099 return true; 18100 18101 if (sna->kgem.gen >= 0120) 18102 return true; 18103 18104 if (!intel_option_cast_to_bool(sna->Options, 18105 OPTION_ACCEL_METHOD, 18106 !IS_DEFAULT_ACCEL_METHOD(NOACCEL))) 18107 return false; 18108 18109#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0) 18110 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 18111 if (s == NULL) 18112 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 18113 18114 return strcasecmp(s, "none") == 0; 18115#else 18116 return IS_DEFAULT_ACCEL_METHOD(NOACCEL); 18117#endif 18118} 18119 18120static bool sna_option_accel_blt(struct sna *sna) 18121{ 18122 const char *s; 18123 18124 assert(sna->kgem.gen < 0120); 18125 18126 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 18127 if (s == NULL) 18128 return false; 18129 18130 return strcasecmp(s, "blt") == 0; 18131} 18132 18133#if HAVE_NOTIFY_FD 18134static void sna_accel_notify(int fd, int ready, void *data) 18135{ 18136 sna_mode_wakeup(data); 18137} 18138#endif 18139 18140bool sna_accel_init(ScreenPtr screen, struct sna *sna) 18141{ 18142 const char *backend; 18143 18144 DBG(("%s\n", __FUNCTION__)); 18145 18146 sna_font_key = AllocateFontPrivateIndex(); 18147 18148 list_init(&sna->flush_pixmaps); 18149 list_init(&sna->active_pixmaps); 18150 18151 SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna); 18152 18153#ifdef DEBUG_MEMORY 18154 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000; 18155#endif 18156 18157 screen->defColormap = FakeClientID(0); 18158 /* let CreateDefColormap do whatever it wants for pixels */ 18159 screen->blackPixel = screen->whitePixel = (Pixel) 0; 18160 screen->QueryBestSize = sna_query_best_size; 18161 assert(screen->GetImage == NULL); 18162 screen->GetImage = sna_get_image; 18163 assert(screen->GetSpans == NULL); 18164 screen->GetSpans = sna_get_spans; 18165 assert(screen->CreateWindow == NULL); 18166 screen->CreateWindow = sna_create_window; 18167 assert(screen->DestroyWindow == NULL); 18168 screen->DestroyWindow = sna_destroy_window; 18169 screen->PositionWindow = sna_position_window; 18170 screen->ChangeWindowAttributes = sna_change_window_attributes; 18171 screen->RealizeWindow = sna_map_window; 18172 screen->UnrealizeWindow = sna_unmap_window; 18173 screen->CopyWindow = sna_copy_window; 18174 assert(screen->CreatePixmap == NULL); 18175 screen->CreatePixmap = sna_create_pixmap; 18176 assert(screen->DestroyPixmap == NULL); 18177 screen->DestroyPixmap = sna_destroy_pixmap; 18178#ifdef CREATE_PIXMAP_USAGE_SHARED 18179 screen->SharePixmapBacking = sna_share_pixmap_backing; 18180 screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing; 18181#endif 18182 screen->RealizeFont = sna_realize_font; 18183 screen->UnrealizeFont = sna_unrealize_font; 18184 assert(screen->CreateGC == NULL); 18185 screen->CreateGC = sna_create_gc; 18186 screen->CreateColormap = miInitializeColormap; 18187 screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA; 18188 screen->InstallColormap = miInstallColormap; 18189 screen->UninstallColormap = miUninstallColormap; 18190 screen->ListInstalledColormaps = miListInstalledColormaps; 18191 screen->ResolveColor = miResolveColor; 18192 assert(screen->StoreColors == NULL); 18193 screen->StoreColors = sna_store_colors; 18194 screen->BitmapToRegion = fbBitmapToRegion; 18195 18196#if HAS_PIXMAP_SHARING 18197 screen->StartPixmapTracking = PixmapStartDirtyTracking; 18198 screen->StopPixmapTracking = PixmapStopDirtyTracking; 18199#endif 18200 18201 assert(screen->GetWindowPixmap == NULL); 18202 screen->GetWindowPixmap = sna_get_window_pixmap; 18203 assert(screen->SetWindowPixmap == NULL); 18204 screen->SetWindowPixmap = sna_set_window_pixmap; 18205 18206 screen->SetScreenPixmap = sna_set_screen_pixmap; 18207 18208 if (sna->kgem.has_userptr) 18209 ShmRegisterFuncs(screen, &shm_funcs); 18210 else 18211 ShmRegisterFbFuncs(screen); 18212 18213 if (!sna_picture_init(screen)) 18214 return false; 18215 18216 backend = no_render_init(sna); 18217 if (sna_option_accel_none(sna)) { 18218 backend = "disabled"; 18219 sna->kgem.wedged = true; 18220 sna_render_mark_wedged(sna); 18221 } else if (sna_option_accel_blt(sna)) 18222 (void)backend; 18223 else if (sna->kgem.gen >= 0110) 18224 backend = gen9_render_init(sna, backend); 18225 else if (sna->kgem.gen >= 0100) 18226 backend = gen8_render_init(sna, backend); 18227 else if (sna->kgem.gen >= 070) 18228 backend = gen7_render_init(sna, backend); 18229 else if (sna->kgem.gen >= 060) 18230 backend = gen6_render_init(sna, backend); 18231 else if (sna->kgem.gen >= 050) 18232 backend = gen5_render_init(sna, backend); 18233 else if (sna->kgem.gen >= 040) 18234 backend = gen4_render_init(sna, backend); 18235 else if (sna->kgem.gen >= 030) 18236 backend = gen3_render_init(sna, backend); 18237 else if (sna->kgem.gen >= 020) 18238 backend = gen2_render_init(sna, backend); 18239 18240 DBG(("%s(backend=%s, prefer_gpu=%x)\n", 18241 __FUNCTION__, backend, sna->render.prefer_gpu)); 18242 18243 kgem_reset(&sna->kgem); 18244 sigtrap_init(); 18245 18246 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 18247 "SNA initialized with %s backend\n", 18248 backend); 18249 18250 return true; 18251} 18252 18253void sna_accel_create(struct sna *sna) 18254{ 18255 ExtensionEntry *damage; 18256 18257 DBG(("%s\n", __FUNCTION__)); 18258 18259 damage = CheckExtension("DAMAGE"); 18260 if (damage) 18261 sna->damage_event = damage->eventBase + XDamageNotify; 18262 18263 if (!sna_glyphs_create(sna)) 18264 goto fail; 18265 18266 if (!sna_gradients_create(sna)) 18267 goto fail; 18268 18269 if (!sna_composite_create(sna)) 18270 goto fail; 18271 18272 return; 18273 18274fail: 18275 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 18276 "Failed to allocate caches, disabling RENDER acceleration\n"); 18277 no_render_init(sna); 18278} 18279 18280static void sna_shm_watch_flush(struct sna *sna, int enable) 18281{ 18282 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 18283 assert(enable); 18284 18285 if (sna->watch_shm_flush == 0) { 18286 DBG(("%s: installing shm watchers\n", __FUNCTION__)); 18287 assert(enable > 0); 18288 18289 if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna)) 18290 return; 18291 18292 sna->watch_shm_flush++; 18293 } 18294 18295 sna->watch_shm_flush += enable; 18296} 18297 18298void sna_watch_flush(struct sna *sna, int enable) 18299{ 18300 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 18301 assert(enable); 18302 18303 if (sna->watch_dri_flush == 0) { 18304 int err = 0; 18305 18306 DBG(("%s: installing watchers\n", __FUNCTION__)); 18307 assert(enable > 0); 18308 18309 if (!sna->damage_event) 18310 return; 18311 18312 if (!AddCallback(&EventCallback, sna_event_callback, sna)) 18313 err = 1; 18314 18315 if (!AddCallback(&FlushCallback, sna_flush_callback, sna)) 18316 err = 1; 18317 18318 if (err) { 18319 xf86DrvMsg(sna->scrn->scrnIndex, X_Error, 18320 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n"); 18321 } 18322 18323 sna->watch_dri_flush++; 18324 } 18325 18326 sna->watch_dri_flush += enable; 18327} 18328 18329void sna_accel_leave(struct sna *sna) 18330{ 18331 DBG(("%s\n", __FUNCTION__)); 18332 sna_scanout_flush(sna); 18333 18334 /* as root we always have permission to render */ 18335 if (geteuid() == 0) 18336 return; 18337 18338 /* as a user, we can only render now if we have a rendernode */ 18339 if (intel_has_render_node(sna->dev)) 18340 return; 18341 18342 /* no longer authorized to use our fd */ 18343 DBG(("%s: dropping render privileges\n", __FUNCTION__)); 18344 18345 kgem_submit(&sna->kgem); 18346 sna->kgem.wedged |= 2; 18347} 18348 18349void sna_accel_enter(struct sna *sna) 18350{ 18351 DBG(("%s\n", __FUNCTION__)); 18352 sna->kgem.wedged &= kgem_is_wedged(&sna->kgem); 18353 kgem_throttle(&sna->kgem); 18354} 18355 18356void sna_accel_close(struct sna *sna) 18357{ 18358 DBG(("%s\n", __FUNCTION__)); 18359 18360 sna_composite_close(sna); 18361 sna_gradients_close(sna); 18362 sna_glyphs_close(sna); 18363 18364 sna_pixmap_expire(sna); 18365 18366 DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna); 18367 DeleteCallback(&FlushCallback, sna_flush_callback, sna); 18368 DeleteCallback(&EventCallback, sna_event_callback, sna); 18369 RemoveNotifyFd(sna->kgem.fd); 18370 18371 kgem_cleanup_cache(&sna->kgem); 18372} 18373 18374void sna_accel_block(struct sna *sna, struct timeval **tv) 18375{ 18376 sigtrap_assert_inactive(); 18377 18378 if (sna->kgem.need_retire) 18379 kgem_retire(&sna->kgem); 18380 kgem_retire__buffers(&sna->kgem); 18381 18382 if (sna->timer_active) 18383 UpdateCurrentTimeIf(); 18384 18385 if (sna->kgem.nbatch && 18386 (sna->kgem.scanout_busy || 18387 kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) { 18388 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 18389 _kgem_submit(&sna->kgem); 18390 } 18391 18392 if (sna->mode.dirty) 18393 sna_crtc_config_notify(xf86ScrnToScreen(sna->scrn)); 18394 18395restart: 18396 if (sna_scanout_do_flush(sna)) 18397 sna_scanout_flush(sna); 18398 assert(sna_accel_scanout(sna) == NULL || 18399 !sna_accel_scanout(sna)->gpu_bo->needs_flush || 18400 sna->timer_active & (1<<(FLUSH_TIMER))); 18401 18402 if (sna_accel_do_throttle(sna)) 18403 sna_accel_throttle(sna); 18404 assert(!sna->kgem.need_retire || 18405 sna->timer_active & (1<<(THROTTLE_TIMER))); 18406 18407 if (sna_accel_do_expire(sna)) 18408 sna_accel_expire(sna); 18409 assert(!sna->kgem.need_expire || 18410 sna->timer_active & (1<<(EXPIRE_TIMER))); 18411 18412 if (sna_accel_do_debug_memory(sna)) 18413 sna_accel_debug_memory(sna); 18414 18415 if (sna->watch_shm_flush == 1) { 18416 DBG(("%s: removing shm watchers\n", __FUNCTION__)); 18417 DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna); 18418 sna->watch_shm_flush = 0; 18419 } 18420 18421 if (sna->watch_dri_flush == 1) { 18422 DBG(("%s: removing dri watchers\n", __FUNCTION__)); 18423 DeleteCallback(&FlushCallback, sna_flush_callback, sna); 18424 DeleteCallback(&EventCallback, sna_event_callback, sna); 18425 sna->watch_dri_flush = 0; 18426 } 18427 18428 if (sna->timer_active & 1) { 18429 int32_t timeout; 18430 18431 DBG(("%s: evaluating timers, active=%x\n", 18432 __FUNCTION__, sna->timer_active)); 18433 18434 timeout = sna->timer_expire[FLUSH_TIMER] - TIME; 18435 DBG(("%s: flush timer expires in %d [%d]\n", 18436 __FUNCTION__, timeout, sna->timer_expire[FLUSH_TIMER])); 18437 if (timeout < 3) 18438 goto restart; 18439 18440 if (*tv == NULL) { 18441 *tv = &sna->timer_tv; 18442 goto set_tv; 18443 } 18444 if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) { 18445set_tv: 18446 (*tv)->tv_sec = timeout / 1000; 18447 (*tv)->tv_usec = timeout % 1000 * 1000; 18448 } 18449 } 18450 18451 sna->kgem.scanout_busy = false; 18452 18453 if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) { 18454 DBG(("%s hardware acceleration\n", 18455 sna->kgem.wedged ? "Re-enabling" : "Disabling")); 18456 kgem_submit(&sna->kgem); 18457 sna->kgem.wedged = !sna->kgem.wedged; 18458 } 18459} 18460 18461void sna_accel_free(struct sna *sna) 18462{ 18463 DBG(("%s\n", __FUNCTION__)); 18464 sigtrap_assert_inactive(); 18465} 18466