sna_accel.c revision 03b705cf
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 "intel_options.h" 33#include "sna.h" 34#include "sna_reg.h" 35#include "sna_video.h" 36#include "rop.h" 37 38#include <X11/fonts/font.h> 39#include <X11/fonts/fontstruct.h> 40 41#include <dixfontstr.h> 42 43#include <mi.h> 44#include <migc.h> 45#include <miline.h> 46#include <micmap.h> 47#ifdef RENDER 48#include <mipict.h> 49#endif 50#include <shmint.h> 51 52#include <sys/time.h> 53#include <sys/mman.h> 54#include <unistd.h> 55 56#define FAULT_INJECTION 0 57 58#define FORCE_INPLACE 0 59#define FORCE_FALLBACK 0 60#define FORCE_FLUSH 0 61#define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */ 62 63#define DEFAULT_TILING I915_TILING_X 64 65#define USE_INPLACE 1 66#define USE_WIDE_SPANS 0 /* -1 force CPU, 1 force GPU */ 67#define USE_ZERO_SPANS 1 /* -1 force CPU, 1 force GPU */ 68#define USE_CPU_BO 1 69#define USE_USERPTR_UPLOADS 1 70#define USE_USERPTR_DOWNLOADS 1 71#define USE_COW 1 72#define UNDO 1 73 74#define MIGRATE_ALL 0 75#define DBG_NO_CPU_UPLOAD 0 76#define DBG_NO_CPU_DOWNLOAD 0 77 78#define ACCEL_FILL_SPANS 1 79#define ACCEL_SET_SPANS 1 80#define ACCEL_PUT_IMAGE 1 81#define ACCEL_GET_IMAGE 1 82#define ACCEL_COPY_AREA 1 83#define ACCEL_COPY_PLANE 1 84#define ACCEL_COPY_WINDOW 1 85#define ACCEL_POLY_POINT 1 86#define ACCEL_POLY_LINE 1 87#define ACCEL_POLY_SEGMENT 1 88#define ACCEL_POLY_RECTANGLE 1 89#define ACCEL_POLY_ARC 1 90#define ACCEL_POLY_FILL_POLYGON 1 91#define ACCEL_POLY_FILL_RECT 1 92#define ACCEL_POLY_FILL_ARC 1 93#define ACCEL_POLY_TEXT8 1 94#define ACCEL_POLY_TEXT16 1 95#define ACCEL_POLY_GLYPH 1 96#define ACCEL_IMAGE_TEXT8 1 97#define ACCEL_IMAGE_TEXT16 1 98#define ACCEL_IMAGE_GLYPH 1 99#define ACCEL_PUSH_PIXELS 1 100 101#define NO_TILE_8x8 0 102#define NO_STIPPLE_8x8 0 103 104#define IS_STATIC_PTR(ptr) ((uintptr_t)(ptr) & 1) 105#define MAKE_STATIC_PTR(ptr) ((void*)((uintptr_t)(ptr) | 1)) 106 107#define IS_COW_OWNER(ptr) ((uintptr_t)(ptr) & 1) 108#define MAKE_COW_OWNER(ptr) ((void*)((uintptr_t)(ptr) | 1)) 109#define COW(ptr) (void *)((uintptr_t)(ptr) & ~1) 110 111#if 0 112static void __sna_fallback_flush(DrawablePtr d) 113{ 114 PixmapPtr pixmap = get_drawable_pixmap(d); 115 struct sna *sna = to_sna_from_pixmap(pixmap); 116 struct sna_pixmap *priv; 117 BoxRec box; 118 PixmapPtr tmp; 119 int i, j; 120 char *src, *dst; 121 122 DBG(("%s: uploading CPU damage...\n", __FUNCTION__)); 123 priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ); 124 if (priv == NULL) 125 return; 126 127 DBG(("%s: downloading GPU damage...\n", __FUNCTION__)); 128 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 129 return; 130 131 box.x1 = box.y1 = 0; 132 box.x2 = pixmap->drawable.width; 133 box.y2 = pixmap->drawable.height; 134 135 tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen, 136 pixmap->drawable.width, 137 pixmap->drawable.height, 138 pixmap->drawable.depth, 139 0); 140 141 DBG(("%s: comparing with direct read...\n", __FUNCTION__)); 142 sna_read_boxes(sna, tmp, priv->gpu_bo, &box, 1); 143 144 src = pixmap->devPrivate.ptr; 145 dst = tmp->devPrivate.ptr; 146 for (i = 0; i < tmp->drawable.height; i++) { 147 if (memcmp(src, dst, tmp->drawable.width * tmp->drawable.bitsPerPixel >> 3)) { 148 for (j = 0; src[j] == dst[j]; j++) 149 ; 150 ErrorF("mismatch at (%d, %d)\n", 151 8*j / tmp->drawable.bitsPerPixel, i); 152 abort(); 153 } 154 src += pixmap->devKind; 155 dst += tmp->devKind; 156 } 157 tmp->drawable.pScreen->DestroyPixmap(tmp); 158} 159#define FALLBACK_FLUSH(d) __sna_fallback_flush(d) 160#else 161#define FALLBACK_FLUSH(d) 162#endif 163 164static int sna_font_key; 165 166static const uint8_t copy_ROP[] = { 167 ROP_0, /* GXclear */ 168 ROP_DSa, /* GXand */ 169 ROP_SDna, /* GXandReverse */ 170 ROP_S, /* GXcopy */ 171 ROP_DSna, /* GXandInverted */ 172 ROP_D, /* GXnoop */ 173 ROP_DSx, /* GXxor */ 174 ROP_DSo, /* GXor */ 175 ROP_DSon, /* GXnor */ 176 ROP_DSxn, /* GXequiv */ 177 ROP_Dn, /* GXinvert */ 178 ROP_SDno, /* GXorReverse */ 179 ROP_Sn, /* GXcopyInverted */ 180 ROP_DSno, /* GXorInverted */ 181 ROP_DSan, /* GXnand */ 182 ROP_1 /* GXset */ 183}; 184static const uint8_t fill_ROP[] = { 185 ROP_0, 186 ROP_DPa, 187 ROP_PDna, 188 ROP_P, 189 ROP_DPna, 190 ROP_D, 191 ROP_DPx, 192 ROP_DPo, 193 ROP_DPon, 194 ROP_PDxn, 195 ROP_Dn, 196 ROP_PDno, 197 ROP_Pn, 198 ROP_DPno, 199 ROP_DPan, 200 ROP_1 201}; 202 203static const GCOps sna_gc_ops; 204static const GCOps sna_gc_ops__cpu; 205static GCOps sna_gc_ops__tmp; 206static const GCFuncs sna_gc_funcs; 207static const GCFuncs sna_gc_funcs__cpu; 208 209static void 210sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect); 211 212static inline void region_set(RegionRec *r, const BoxRec *b) 213{ 214 r->extents = *b; 215 r->data = NULL; 216} 217 218static inline void region_maybe_clip(RegionRec *r, RegionRec *clip) 219{ 220 if (clip->data) 221 RegionIntersect(r, r, clip); 222} 223 224static inline bool region_is_singular(const RegionRec *r) 225{ 226 return r->data == NULL; 227} 228 229typedef struct box32 { 230 int32_t x1, y1, x2, y2; 231} Box32Rec; 232 233#define PM_IS_SOLID(_draw, _pm) \ 234 (((_pm) & FbFullMask((_draw)->depth)) == FbFullMask((_draw)->depth)) 235 236#ifdef DEBUG_PIXMAP 237static void _assert_pixmap_contains_box(PixmapPtr pixmap, const BoxRec *box, const char *function) 238{ 239 if (box->x1 < 0 || box->y1 < 0 || 240 box->x2 > pixmap->drawable.width || 241 box->y2 > pixmap->drawable.height) 242 { 243 ErrorF("%s: damage box is beyond the pixmap: box=(%d, %d), (%d, %d), pixmap=(%d, %d)\n", 244 __FUNCTION__, 245 box->x1, box->y1, box->x2, box->y2, 246 pixmap->drawable.width, 247 pixmap->drawable.height); 248 assert(0); 249 } 250} 251 252static void _assert_pixmap_contains_box_with_offset(PixmapPtr pixmap, const BoxRec *box, int dx, int dy, const char *function) 253{ 254 BoxRec b = *box; 255 b.x1 += dx; b.x2 += dx; 256 b.y1 += dy; b.y2 += dy; 257 _assert_pixmap_contains_box(pixmap, &b, function); 258} 259 260static void _assert_pixmap_contains_boxes(PixmapPtr pixmap, const BoxRec *box, int n, int dx, int dy, const char *function) 261{ 262 BoxRec extents; 263 264 extents = *box; 265 while (--n) { 266 ++box; 267 268 if (box->x1 < extents.x1) 269 extents.x1 = box->x1; 270 if (box->x2 > extents.x2) 271 extents.x2 = box->x2; 272 273 if (box->y1 < extents.y1) 274 extents.y1 = box->y1; 275 if (box->y2 > extents.y2) 276 extents.y2 = box->y2; 277 } 278 extents.x1 += dx; 279 extents.x2 += dx; 280 extents.y1 += dy; 281 extents.y2 += dy; 282 _assert_pixmap_contains_box(pixmap, &extents, function); 283} 284 285 286static void _assert_pixmap_contains_points(PixmapPtr pixmap, const DDXPointRec *pt, int n, int dx, int dy, const char *function) 287{ 288 BoxRec extents; 289 290 extents.x2 = extents.x1 = pt->x; 291 extents.y2 = extents.y1 = pt->y; 292 while (--n) { 293 ++pt; 294 295 if (pt->x < extents.x1) 296 extents.x1 = pt->x; 297 else if (pt->x > extents.x2) 298 extents.x2 = pt->x; 299 300 if (pt->y < extents.y1) 301 extents.y1 = pt->y; 302 else if (pt->y > extents.y2) 303 extents.y2 = pt->y; 304 } 305 extents.x1 += dx; 306 extents.x2 += dx + 1; 307 extents.y1 += dy; 308 extents.y2 += dy + 1; 309 _assert_pixmap_contains_box(pixmap, &extents, function); 310} 311 312static void _assert_drawable_contains_box(DrawablePtr drawable, const BoxRec *box, const char *function) 313{ 314 if (box->x1 < drawable->x || 315 box->y1 < drawable->y || 316 box->x2 > drawable->x + drawable->width || 317 box->y2 > drawable->y + drawable->height) 318 { 319 ErrorF("%s: damage box is beyond the drawable: box=(%d, %d), (%d, %d), drawable=(%d, %d)x(%d, %d)\n", 320 __FUNCTION__, 321 box->x1, box->y1, box->x2, box->y2, 322 drawable->x, drawable->y, 323 drawable->width, drawable->height); 324 assert(0); 325 } 326} 327 328static void assert_pixmap_damage(PixmapPtr p) 329{ 330 struct sna_pixmap *priv; 331 RegionRec reg, cpu, gpu; 332 333 priv = sna_pixmap(p); 334 if (priv == NULL) 335 return; 336 337 assert(priv->gpu_damage == NULL || priv->gpu_bo); 338 339 if (priv->clear) { 340 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 341 assert(priv->cpu_damage == NULL); 342 } 343 344 if (DAMAGE_IS_ALL(priv->gpu_damage) && DAMAGE_IS_ALL(priv->cpu_damage)) { 345 /* special upload buffer */ 346 assert(priv->gpu_bo && priv->gpu_bo->proxy); 347 assert(priv->cpu_bo == NULL); 348 return; 349 } 350 351 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 352 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 353 } 354 355 assert(!DAMAGE_IS_ALL(priv->gpu_damage) || priv->cpu_damage == NULL); 356 assert(!DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL); 357 358 /* Avoid reducing damage to minimise interferrence */ 359 RegionNull(®); 360 RegionNull(&gpu); 361 RegionNull(&cpu); 362 363 if (priv->gpu_damage) 364 _sna_damage_debug_get_region(DAMAGE_PTR(priv->gpu_damage), &gpu); 365 366 if (priv->cpu_damage) 367 _sna_damage_debug_get_region(DAMAGE_PTR(priv->cpu_damage), &cpu); 368 369 RegionIntersect(®, &cpu, &gpu); 370 assert(RegionNil(®)); 371 372 RegionUninit(®); 373 RegionUninit(&gpu); 374 RegionUninit(&cpu); 375} 376 377#define assert_pixmap_contains_box(p, b) _assert_pixmap_contains_box(p, b, __FUNCTION__) 378#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) _assert_pixmap_contains_box_with_offset(p, b, dx, dy, __FUNCTION__) 379#define assert_drawable_contains_box(d, b) _assert_drawable_contains_box(d, b, __FUNCTION__) 380#define assert_pixmap_contains_boxes(p, b, n, x, y) _assert_pixmap_contains_boxes(p, b, n, x, y, __FUNCTION__) 381#define assert_pixmap_contains_points(p, pt, n, x, y) _assert_pixmap_contains_points(p, pt, n, x, y, __FUNCTION__) 382 383#else 384#define assert_pixmap_contains_box(p, b) 385#define assert_pixmap_contains_box_with_offset(p, b, dx, dy) 386#define assert_pixmap_contains_boxes(p, b, n, x, y) 387#define assert_pixmap_contains_points(p, pt, n, x, y) 388#define assert_drawable_contains_box(d, b) 389#ifndef NDEBUG 390#define assert_pixmap_damage(p) do { \ 391 struct sna_pixmap *priv__ = sna_pixmap(p); \ 392 assert(priv__ == NULL || priv__->gpu_damage == NULL || priv__->gpu_bo); \ 393} while (0) 394#else 395#define assert_pixmap_damage(p) 396#endif 397#endif 398 399inline static bool 400sna_fill_init_blt(struct sna_fill_op *fill, 401 struct sna *sna, 402 PixmapPtr pixmap, 403 struct kgem_bo *bo, 404 uint8_t alu, 405 uint32_t pixel) 406{ 407 return sna->render.fill(sna, alu, pixmap, bo, pixel, fill); 408} 409 410static bool 411sna_copy_init_blt(struct sna_copy_op *copy, 412 struct sna *sna, 413 PixmapPtr src, struct kgem_bo *src_bo, 414 PixmapPtr dst, struct kgem_bo *dst_bo, 415 uint8_t alu) 416{ 417 memset(copy, 0, sizeof(*copy)); 418 return sna->render.copy(sna, alu, src, src_bo, dst, dst_bo, copy); 419} 420 421static void sna_pixmap_free_gpu(struct sna *sna, struct sna_pixmap *priv) 422{ 423 assert(priv->gpu_damage == NULL || priv->gpu_bo); 424 425 if (priv->cow) 426 sna_pixmap_undo_cow(sna, priv, 0); 427 assert(priv->cow == NULL); 428 429 sna_damage_destroy(&priv->gpu_damage); 430 priv->clear = false; 431 432 if (priv->gpu_bo && !priv->pinned) { 433 assert(!priv->flush); 434 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 435 priv->gpu_bo = NULL; 436 } 437 438 if (priv->mapped) { 439 assert(!priv->shm); 440 priv->pixmap->devPrivate.ptr = NULL; 441 priv->mapped = false; 442 } 443 444 /* and reset the upload counter */ 445 priv->source_count = SOURCE_BIAS; 446} 447 448static bool must_check 449sna_pixmap_alloc_cpu(struct sna *sna, 450 PixmapPtr pixmap, 451 struct sna_pixmap *priv, 452 bool from_gpu) 453{ 454 /* Restore after a GTT mapping? */ 455 assert(priv->gpu_damage == NULL || priv->gpu_bo); 456 assert(!priv->shm); 457 if (priv->ptr) 458 goto done; 459 460 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 461 assert(priv->stride); 462 463 if (priv->create & KGEM_CAN_CREATE_CPU) { 464 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__, 465 pixmap->drawable.width, pixmap->drawable.height)); 466 467 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem, 468 pixmap->drawable.width, 469 pixmap->drawable.height, 470 pixmap->drawable.bitsPerPixel, 471 from_gpu ? 0 : CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE); 472 if (priv->cpu_bo) { 473 priv->ptr = kgem_bo_map__cpu(&sna->kgem, priv->cpu_bo); 474 if (priv->ptr) { 475 DBG(("%s: allocated CPU handle=%d (snooped? %d)\n", __FUNCTION__, 476 priv->cpu_bo->handle, priv->cpu_bo->snoop)); 477 priv->stride = priv->cpu_bo->pitch; 478#ifdef DEBUG_MEMORY 479 sna->debug_memory.cpu_bo_allocs++; 480 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 481#endif 482 } else { 483 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 484 priv->cpu_bo = NULL; 485 } 486 } 487 } 488 489 if (priv->ptr == NULL) { 490 DBG(("%s: allocating ordinary memory for shadow pixels [%d bytes]\n", 491 __FUNCTION__, priv->stride * pixmap->drawable.height)); 492 priv->ptr = malloc(priv->stride * pixmap->drawable.height); 493 } 494 495 assert(priv->ptr); 496done: 497 assert(priv->stride); 498 assert(!priv->mapped); 499 pixmap->devPrivate.ptr = PTR(priv->ptr); 500 pixmap->devKind = priv->stride; 501 return priv->ptr != NULL; 502} 503 504static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 505{ 506 if (priv->cpu_bo) { 507 DBG(("%s: discarding CPU buffer, handle=%d, size=%d\n", 508 __FUNCTION__, priv->cpu_bo->handle, kgem_bo_size(priv->cpu_bo))); 509#ifdef DEBUG_MEMORY 510 sna->debug_memory.cpu_bo_allocs--; 511 sna->debug_memory.cpu_bo_bytes -= kgem_bo_size(priv->cpu_bo); 512#endif 513 if (!priv->cpu_bo->reusable) { 514 assert(priv->cpu_bo->flush == true); 515 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 516 sna_accel_watch_flush(sna, -1); 517 } 518 kgem_bo_destroy(&sna->kgem, priv->cpu_bo); 519 } else if (!IS_STATIC_PTR(priv->ptr)) 520 free(priv->ptr); 521} 522 523static void sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv) 524{ 525 assert(priv->cpu_damage == NULL); 526 assert(list_is_empty(&priv->flush_list)); 527 528 if (IS_STATIC_PTR(priv->ptr)) 529 return; 530 531 __sna_pixmap_free_cpu(sna, priv); 532 533 priv->cpu_bo = NULL; 534 priv->ptr = NULL; 535 536 if (!priv->mapped) 537 priv->pixmap->devPrivate.ptr = NULL; 538} 539 540static inline uint32_t default_tiling(PixmapPtr pixmap, 541 uint32_t tiling) 542{ 543 struct sna_pixmap *priv = sna_pixmap(pixmap); 544 struct sna *sna = to_sna_from_pixmap(pixmap); 545 546 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */ 547 if (sna->kgem.gen == 021) 548 return I915_TILING_X; 549 550 /* Only on later generations was the render pipeline 551 * more flexible than the BLT. So on gen2/3, prefer to 552 * keep large objects accessible through the BLT. 553 */ 554 if (sna->kgem.gen < 040 && 555 (pixmap->drawable.width > sna->render.max_3d_size || 556 pixmap->drawable.height > sna->render.max_3d_size)) 557 return I915_TILING_X; 558 559 if (tiling == I915_TILING_Y && 560 sna_damage_is_all(&priv->cpu_damage, 561 pixmap->drawable.width, 562 pixmap->drawable.height)) { 563 DBG(("%s: entire source is damaged, using Y-tiling\n", 564 __FUNCTION__)); 565 sna_damage_destroy(&priv->gpu_damage); 566 567 return I915_TILING_Y; 568 } 569 570 return tiling; 571} 572 573pure static uint32_t sna_pixmap_choose_tiling(PixmapPtr pixmap, 574 uint32_t tiling) 575{ 576 struct sna *sna = to_sna_from_pixmap(pixmap); 577 uint32_t bit; 578 579 /* Use tiling by default, but disable per user request */ 580 if (pixmap->usage_hint == SNA_CREATE_FB) { 581 tiling = -I915_TILING_X; 582 bit = SNA_TILING_FB; 583 } else { 584 tiling = default_tiling(pixmap, tiling); 585 bit = SNA_TILING_2D; 586 } 587 if ((sna->tiling & bit) == 0) 588 tiling = I915_TILING_NONE; 589 590 /* Also adjust tiling if it is not supported or likely to 591 * slow us down, 592 */ 593 return kgem_choose_tiling(&sna->kgem, tiling, 594 pixmap->drawable.width, 595 pixmap->drawable.height, 596 pixmap->drawable.bitsPerPixel); 597} 598 599struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling) 600{ 601 struct sna_pixmap *priv = sna_pixmap(pixmap); 602 struct sna *sna = to_sna_from_pixmap(pixmap); 603 struct kgem_bo *bo; 604 BoxRec box; 605 606 DBG(("%s: changing tiling %d -> %d for %dx%d pixmap\n", 607 __FUNCTION__, priv->gpu_bo->tiling, tiling, 608 pixmap->drawable.width, pixmap->drawable.height)); 609 assert(priv->gpu_damage == NULL || priv->gpu_bo); 610 611 if (priv->pinned) { 612 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 613 return NULL; 614 } 615 616 if (wedged(sna)) { 617 DBG(("%s: can't convert bo, wedged\n", __FUNCTION__)); 618 return NULL; 619 } 620 621 assert_pixmap_damage(pixmap); 622 623 bo = kgem_create_2d(&sna->kgem, 624 pixmap->drawable.width, 625 pixmap->drawable.height, 626 pixmap->drawable.bitsPerPixel, 627 tiling, 0); 628 if (bo == NULL) { 629 DBG(("%s: allocation failed\n", __FUNCTION__)); 630 return NULL; 631 } 632 633 box.x1 = box.y1 = 0; 634 box.x2 = pixmap->drawable.width; 635 box.y2 = pixmap->drawable.height; 636 637 if (!sna->render.copy_boxes(sna, GXcopy, 638 pixmap, priv->gpu_bo, 0, 0, 639 pixmap, bo, 0, 0, 640 &box, 1, 0)) { 641 DBG(("%s: copy failed\n", __FUNCTION__)); 642 kgem_bo_destroy(&sna->kgem, bo); 643 return NULL; 644 } 645 646 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 647 648 if (priv->mapped) { 649 assert(!priv->shm); 650 pixmap->devPrivate.ptr = NULL; 651 priv->mapped = false; 652 } 653 654 return priv->gpu_bo = bo; 655} 656 657static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna) 658{ 659 ((void **)__get_private(pixmap, sna_pixmap_key))[1] = sna; 660 assert(sna_pixmap(pixmap) == sna); 661} 662 663static struct sna_pixmap * 664_sna_pixmap_init(struct sna_pixmap *priv, PixmapPtr pixmap) 665{ 666 list_init(&priv->flush_list); 667 priv->source_count = SOURCE_BIAS; 668 priv->pixmap = pixmap; 669 670 return priv; 671} 672 673static struct sna_pixmap * 674_sna_pixmap_reset(PixmapPtr pixmap) 675{ 676 struct sna_pixmap *priv; 677 678 assert(pixmap->drawable.type == DRAWABLE_PIXMAP); 679 assert(pixmap->drawable.class == 0); 680 assert(pixmap->drawable.x == 0); 681 assert(pixmap->drawable.y == 0); 682 683 priv = sna_pixmap(pixmap); 684 assert(priv != NULL); 685 686 memset(priv, 0, sizeof(*priv)); 687 return _sna_pixmap_init(priv, pixmap); 688} 689 690static struct sna_pixmap *sna_pixmap_attach(PixmapPtr pixmap) 691{ 692 struct sna_pixmap *priv; 693 694 priv = calloc(1, sizeof(*priv)); 695 if (!priv) 696 return NULL; 697 698 sna_set_pixmap(pixmap, priv); 699 return _sna_pixmap_init(priv, pixmap); 700} 701 702bool sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo) 703{ 704 struct sna_pixmap *priv; 705 706 assert(bo); 707 708 priv = sna_pixmap_attach(pixmap); 709 if (!priv) 710 return false; 711 712 priv->gpu_bo = kgem_bo_reference(bo); 713 assert(priv->gpu_bo->proxy == NULL); 714 sna_damage_all(&priv->gpu_damage, 715 pixmap->drawable.width, 716 pixmap->drawable.height); 717 718 return true; 719} 720 721static int bits_per_pixel(int depth) 722{ 723 switch (depth) { 724 case 1: return 1; 725 case 4: 726 case 8: return 8; 727 case 15: 728 case 16: return 16; 729 case 24: 730 case 30: 731 case 32: return 32; 732 default: return 0; 733 } 734} 735static PixmapPtr 736create_pixmap(struct sna *sna, ScreenPtr screen, 737 int width, int height, int depth, 738 unsigned usage_hint) 739{ 740 PixmapPtr pixmap; 741 size_t datasize; 742 size_t stride; 743 int base, bpp; 744 745 bpp = bits_per_pixel(depth); 746 if (bpp == 0) 747 return NullPixmap; 748 749 stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 750 if (stride / 4 > 32767 || height > 32767) 751 return NullPixmap; 752 753 datasize = height * stride; 754 base = screen->totalPixmapSize; 755 if (datasize && base & 15) { 756 int adjust = 16 - (base & 15); 757 base += adjust; 758 datasize += adjust; 759 } 760 761 DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n", 762 __FUNCTION__, width, height, depth, (long)datasize)); 763 pixmap = AllocatePixmap(screen, datasize); 764 if (!pixmap) 765 return NullPixmap; 766 767 ((void **)__get_private(pixmap, sna_pixmap_key))[0] = sna; 768 assert(to_sna_from_pixmap(pixmap) == sna); 769 770 pixmap->drawable.type = DRAWABLE_PIXMAP; 771 pixmap->drawable.class = 0; 772 pixmap->drawable.pScreen = screen; 773 pixmap->drawable.depth = depth; 774 pixmap->drawable.bitsPerPixel = bpp; 775 pixmap->drawable.id = 0; 776 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 777 pixmap->drawable.x = 0; 778 pixmap->drawable.y = 0; 779 pixmap->drawable.width = width; 780 pixmap->drawable.height = height; 781 pixmap->devKind = stride; 782 pixmap->refcnt = 1; 783 pixmap->devPrivate.ptr = datasize ? (char *)pixmap + base : NULL; 784 785#ifdef COMPOSITE 786 pixmap->screen_x = 0; 787 pixmap->screen_y = 0; 788#endif 789 790 pixmap->usage_hint = usage_hint; 791#if DEBUG_MEMORY 792 sna->debug_memory.pixmap_allocs++; 793#endif 794 795 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 796 __FUNCTION__, 797 pixmap->drawable.serialNumber, 798 pixmap->usage_hint, 799 pixmap->drawable.width, 800 pixmap->drawable.height)); 801 802 return pixmap; 803} 804 805static PixmapPtr 806sna_pixmap_create_shm(ScreenPtr screen, 807 int width, int height, int depth, 808 char *addr) 809{ 810 struct sna *sna = to_sna_from_screen(screen); 811 int bpp = bits_per_pixel(depth); 812 int pitch = PixmapBytePad(width, depth); 813 struct sna_pixmap *priv; 814 PixmapPtr pixmap; 815 816 DBG(("%s(%dx%d, depth=%d, bpp=%d, pitch=%d)\n", 817 __FUNCTION__, width, height, depth, bpp, pitch)); 818 819 if (wedged(sna) || bpp == 0 || pitch*height < 4096) { 820fallback: 821 pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 822 if (pixmap == NULL) 823 return NULL; 824 825 if (!screen->ModifyPixmapHeader(pixmap, width, height, depth, 826 bpp, pitch, addr)) { 827 screen->DestroyPixmap(pixmap); 828 return NULL; 829 } 830 831 return pixmap; 832 } 833 834 if (sna->freed_pixmap) { 835 pixmap = sna->freed_pixmap; 836 sna->freed_pixmap = pixmap->devPrivate.ptr; 837 838 pixmap->usage_hint = 0; 839 pixmap->refcnt = 1; 840 841 pixmap->drawable.width = width; 842 pixmap->drawable.height = height; 843 pixmap->drawable.depth = depth; 844 pixmap->drawable.bitsPerPixel = bpp; 845 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 846 847 DBG(("%s: serial=%ld, %dx%d\n", 848 __FUNCTION__, 849 pixmap->drawable.serialNumber, 850 pixmap->drawable.width, 851 pixmap->drawable.height)); 852 853 priv = _sna_pixmap_reset(pixmap); 854 } else { 855 pixmap = create_pixmap(sna, screen, 0, 0, depth, 0); 856 if (pixmap == NullPixmap) 857 return NullPixmap; 858 859 pixmap->drawable.width = width; 860 pixmap->drawable.height = height; 861 pixmap->drawable.depth = depth; 862 pixmap->drawable.bitsPerPixel = bpp; 863 864 priv = sna_pixmap_attach(pixmap); 865 if (!priv) { 866 FreePixmap(pixmap); 867 return NullPixmap; 868 } 869 } 870 871 priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false); 872 if (priv->cpu_bo == NULL) { 873 priv->header = true; 874 sna_pixmap_destroy(pixmap); 875 goto fallback; 876 } 877 priv->cpu_bo->pitch = pitch; 878 kgem_bo_mark_unreusable(priv->cpu_bo); 879 sna_accel_watch_flush(sna, 1); 880#ifdef DEBUG_MEMORY 881 sna->debug_memory.cpu_bo_allocs++; 882 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo); 883#endif 884 885 priv->cpu = true; 886 priv->shm = true; 887 priv->stride = pitch; 888 priv->ptr = MAKE_STATIC_PTR(addr); 889 sna_damage_all(&priv->cpu_damage, width, height); 890 891 pixmap->devKind = pitch; 892 pixmap->devPrivate.ptr = addr; 893 return pixmap; 894} 895 896PixmapPtr 897sna_pixmap_create_unattached(ScreenPtr screen, 898 int width, int height, int depth) 899{ 900 return create_pixmap(to_sna_from_screen(screen), 901 screen, width, height, depth, 902 CREATE_PIXMAP_USAGE_SCRATCH); 903} 904 905static PixmapPtr 906sna_pixmap_create_scratch(ScreenPtr screen, 907 int width, int height, int depth, 908 uint32_t tiling) 909{ 910 struct sna *sna = to_sna_from_screen(screen); 911 struct sna_pixmap *priv; 912 PixmapPtr pixmap; 913 int bpp; 914 915 DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__, 916 width, height, depth, tiling)); 917 918 bpp = bits_per_pixel(depth); 919 if (tiling == I915_TILING_Y && 920 (sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0) 921 tiling = I915_TILING_X; 922 923 if (tiling == I915_TILING_Y && 924 (width > sna->render.max_3d_size || 925 height > sna->render.max_3d_size)) 926 tiling = I915_TILING_X; 927 928 tiling = kgem_choose_tiling(&sna->kgem, tiling, width, height, bpp); 929 930 /* you promise never to access this via the cpu... */ 931 if (sna->freed_pixmap) { 932 pixmap = sna->freed_pixmap; 933 sna->freed_pixmap = pixmap->devPrivate.ptr; 934 935 pixmap->usage_hint = CREATE_PIXMAP_USAGE_SCRATCH; 936 pixmap->refcnt = 1; 937 938 pixmap->drawable.width = width; 939 pixmap->drawable.height = height; 940 pixmap->drawable.depth = depth; 941 pixmap->drawable.bitsPerPixel = bpp; 942 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 943 944 DBG(("%s: serial=%ld, usage=%d, %dx%d\n", 945 __FUNCTION__, 946 pixmap->drawable.serialNumber, 947 pixmap->usage_hint, 948 pixmap->drawable.width, 949 pixmap->drawable.height)); 950 951 priv = _sna_pixmap_reset(pixmap); 952 } else { 953 pixmap = create_pixmap(sna, screen, 0, 0, depth, 954 CREATE_PIXMAP_USAGE_SCRATCH); 955 if (pixmap == NullPixmap) 956 return NullPixmap; 957 958 pixmap->drawable.width = width; 959 pixmap->drawable.height = height; 960 pixmap->drawable.depth = depth; 961 pixmap->drawable.bitsPerPixel = bpp; 962 963 priv = sna_pixmap_attach(pixmap); 964 if (!priv) { 965 FreePixmap(pixmap); 966 return NullPixmap; 967 } 968 } 969 970 priv->stride = PixmapBytePad(width, depth); 971 pixmap->devPrivate.ptr = NULL; 972 973 priv->gpu_bo = kgem_create_2d(&sna->kgem, 974 width, height, bpp, tiling, 975 CREATE_TEMPORARY); 976 if (priv->gpu_bo == NULL) { 977 free(priv); 978 FreePixmap(pixmap); 979 return NullPixmap; 980 } 981 982 priv->header = true; 983 sna_damage_all(&priv->gpu_damage, width, height); 984 985 assert(to_sna_from_pixmap(pixmap) == sna); 986 assert(pixmap->drawable.pScreen == screen); 987 988 return pixmap; 989} 990 991#ifdef CREATE_PIXMAP_USAGE_SHARED 992static Bool 993sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle) 994{ 995 struct sna *sna = to_sna_from_pixmap(pixmap); 996 struct sna_pixmap *priv; 997 int fd; 998 999 DBG(("%s: pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber)); 1000 1001 priv = sna_pixmap_move_to_gpu(pixmap, 1002 MOVE_READ | MOVE_WRITE | __MOVE_DRI | __MOVE_FORCE); 1003 if (priv == NULL) 1004 return FALSE; 1005 1006 assert(!priv->shm); 1007 assert(priv->gpu_bo); 1008 assert(priv->stride); 1009 1010 /* XXX negotiate format and stride restrictions */ 1011 if (priv->gpu_bo->tiling != I915_TILING_NONE || 1012 priv->gpu_bo->pitch & 255) { 1013 struct kgem_bo *bo; 1014 BoxRec box; 1015 1016 DBG(("%s: removing tiling %d, and aligning pitch for %dx%d pixmap=%ld\n", 1017 __FUNCTION__, priv->gpu_bo->tiling, 1018 pixmap->drawable.width, pixmap->drawable.height, 1019 pixmap->drawable.serialNumber)); 1020 1021 if (priv->pinned & ~(PIN_DRI | PIN_PRIME)) { 1022 DBG(("%s: can't convert pinned bo\n", __FUNCTION__)); 1023 return FALSE; 1024 } 1025 1026 assert_pixmap_damage(pixmap); 1027 1028 bo = kgem_create_2d(&sna->kgem, 1029 pixmap->drawable.width, 1030 pixmap->drawable.height, 1031 pixmap->drawable.bitsPerPixel, 1032 I915_TILING_NONE, 1033 CREATE_GTT_MAP | CREATE_PRIME); 1034 if (bo == NULL) { 1035 DBG(("%s: allocation failed\n", __FUNCTION__)); 1036 return FALSE; 1037 } 1038 1039 box.x1 = box.y1 = 0; 1040 box.x2 = pixmap->drawable.width; 1041 box.y2 = pixmap->drawable.height; 1042 1043 assert(!wedged(sna)); /* XXX */ 1044 if (!sna->render.copy_boxes(sna, GXcopy, 1045 pixmap, priv->gpu_bo, 0, 0, 1046 pixmap, bo, 0, 0, 1047 &box, 1, 0)) { 1048 DBG(("%s: copy failed\n", __FUNCTION__)); 1049 kgem_bo_destroy(&sna->kgem, bo); 1050 return FALSE; 1051 } 1052 1053 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1054 priv->gpu_bo = bo; 1055 1056 if (priv->mapped) { 1057 pixmap->devPrivate.ptr = NULL; 1058 priv->mapped = false; 1059 } 1060 } 1061 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1062 assert((priv->gpu_bo->pitch & 255) == 0); 1063 1064 /* And export the bo->pitch via pixmap->devKind */ 1065 pixmap->devPrivate.ptr = kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1066 if (pixmap->devPrivate.ptr == NULL) 1067 return FALSE; 1068 1069 pixmap->devKind = priv->gpu_bo->pitch; 1070 priv->mapped = true; 1071 1072 fd = kgem_bo_export_to_prime(&sna->kgem, priv->gpu_bo); 1073 if (fd == -1) 1074 return FALSE; 1075 1076 priv->pinned |= PIN_PRIME; 1077 1078 *fd_handle = (void *)(intptr_t)fd; 1079 return TRUE; 1080} 1081 1082static Bool 1083sna_set_shared_pixmap_backing(PixmapPtr pixmap, void *fd_handle) 1084{ 1085 struct sna *sna = to_sna_from_pixmap(pixmap); 1086 struct sna_pixmap *priv; 1087 struct kgem_bo *bo; 1088 1089 DBG(("%s: pixmap=%ld, size=%dx%d, depth=%d/%d, stride=%d\n", 1090 __FUNCTION__, pixmap->drawable.serialNumber, 1091 pixmap->drawable.width, pixmap->drawable.height, 1092 pixmap->drawable.depth, pixmap->drawable.bitsPerPixel, 1093 pixmap->devKind)); 1094 1095 priv = sna_pixmap(pixmap); 1096 if (priv == NULL) 1097 return FALSE; 1098 1099 assert(!priv->pinned); 1100 assert(priv->gpu_bo == NULL); 1101 assert(priv->cpu_bo == NULL); 1102 assert(priv->cpu_damage == NULL); 1103 assert(priv->gpu_damage == NULL); 1104 1105 bo = kgem_create_for_prime(&sna->kgem, 1106 (intptr_t)fd_handle, 1107 pixmap->devKind * pixmap->drawable.height); 1108 if (bo == NULL) 1109 return FALSE; 1110 1111 sna_damage_all(&priv->gpu_damage, 1112 pixmap->drawable.width, 1113 pixmap->drawable.height); 1114 1115 bo->pitch = pixmap->devKind; 1116 priv->stride = pixmap->devKind; 1117 1118 priv->gpu_bo = bo; 1119 priv->pinned |= PIN_PRIME; 1120 1121 close((intptr_t)fd_handle); 1122 return TRUE; 1123} 1124 1125static PixmapPtr 1126sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen, 1127 int width, int height, int depth) 1128{ 1129 PixmapPtr pixmap; 1130 struct sna_pixmap *priv; 1131 1132 DBG(("%s: depth=%d\n", __FUNCTION__, depth)); 1133 1134 /* Create a stub to be attached later */ 1135 pixmap = create_pixmap(sna, screen, 0, 0, depth, 0); 1136 if (pixmap == NullPixmap) 1137 return NullPixmap; 1138 1139 pixmap->devKind = 0; 1140 pixmap->devPrivate.ptr = NULL; 1141 1142 priv = sna_pixmap_attach(pixmap); 1143 if (priv == NULL) { 1144 free(pixmap); 1145 return NullPixmap; 1146 } 1147 1148 priv->stride = 0; 1149 priv->create = 0; 1150 1151 if (width|height) { 1152 int bpp = bits_per_pixel(depth); 1153 1154 priv->gpu_bo = kgem_create_2d(&sna->kgem, 1155 width, height, bpp, 1156 I915_TILING_NONE, 1157 CREATE_GTT_MAP | CREATE_PRIME); 1158 if (priv->gpu_bo == NULL) { 1159 free(priv); 1160 FreePixmap(pixmap); 1161 return NullPixmap; 1162 } 1163 1164 /* minimal interface for sharing is linear, 256 byte pitch */ 1165 assert(priv->gpu_bo->tiling == I915_TILING_NONE); 1166 assert((priv->gpu_bo->pitch & 255) == 0); 1167 1168 assert(!priv->mapped); 1169 pixmap->devPrivate.ptr = 1170 kgem_bo_map__async(&sna->kgem, priv->gpu_bo); 1171 if (pixmap->devPrivate.ptr == NULL) { 1172 free(priv); 1173 FreePixmap(pixmap); 1174 return FALSE; 1175 } 1176 1177 pixmap->devKind = priv->gpu_bo->pitch; 1178 pixmap->drawable.width = width; 1179 pixmap->drawable.height = height; 1180 1181 priv->stride = priv->gpu_bo->pitch; 1182 priv->mapped = true; 1183 1184 sna_damage_all(&priv->gpu_damage, width, height); 1185 } 1186 1187 return pixmap; 1188} 1189#endif 1190 1191static PixmapPtr sna_create_pixmap(ScreenPtr screen, 1192 int width, int height, int depth, 1193 unsigned int usage) 1194{ 1195 struct sna *sna = to_sna_from_screen(screen); 1196 PixmapPtr pixmap; 1197 struct sna_pixmap *priv; 1198 unsigned flags; 1199 int pad; 1200 void *ptr; 1201 1202 DBG(("%s(%d, %d, %d, usage=%x)\n", __FUNCTION__, 1203 width, height, depth, usage)); 1204 1205#ifdef CREATE_PIXMAP_USAGE_SHARED 1206 if (usage == CREATE_PIXMAP_USAGE_SHARED) 1207 return sna_create_pixmap_shared(sna, screen, 1208 width, height, depth); 1209#endif 1210 1211 if ((width|height) == 0) { 1212 usage = -1; 1213 goto fallback; 1214 } 1215 assert(width && height); 1216 1217 flags = kgem_can_create_2d(&sna->kgem, width, height, depth); 1218 if (flags == 0) { 1219 DBG(("%s: can not use GPU, just creating shadow\n", 1220 __FUNCTION__)); 1221 goto fallback; 1222 } 1223 1224 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0)) 1225 flags &= ~KGEM_CAN_CREATE_GPU; 1226 if (wedged(sna)) 1227 flags &= ~KGEM_CAN_CREATE_GTT; 1228 1229 switch (usage) { 1230 case CREATE_PIXMAP_USAGE_SCRATCH: 1231 if (flags & KGEM_CAN_CREATE_GPU) 1232 return sna_pixmap_create_scratch(screen, 1233 width, height, depth, 1234 I915_TILING_X); 1235 else 1236 goto fallback; 1237 1238 case SNA_CREATE_GLYPHS: 1239 if (flags & KGEM_CAN_CREATE_GPU) 1240 return sna_pixmap_create_scratch(screen, 1241 width, height, depth, 1242 -I915_TILING_Y); 1243 else 1244 goto fallback; 1245 1246 case SNA_CREATE_SCRATCH: 1247 if (flags & KGEM_CAN_CREATE_GPU) 1248 return sna_pixmap_create_scratch(screen, 1249 width, height, depth, 1250 I915_TILING_Y); 1251 else 1252 goto fallback; 1253 } 1254 1255 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE) 1256 flags &= ~KGEM_CAN_CREATE_GPU; 1257 if (usage == CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 1258 usage = 0; 1259 1260 pad = PixmapBytePad(width, depth); 1261 if (pad * height < 4096) { 1262 DBG(("%s: small buffer [%d], attaching to shadow pixmap\n", 1263 __FUNCTION__, pad * height)); 1264 pixmap = create_pixmap(sna, screen, 1265 width, height, depth, usage); 1266 if (pixmap == NullPixmap) 1267 return NullPixmap; 1268 1269 ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr); 1270 pad = pixmap->devKind; 1271 flags &= ~(KGEM_CAN_CREATE_GPU | KGEM_CAN_CREATE_CPU); 1272 } else { 1273 DBG(("%s: creating GPU pixmap %dx%d, stride=%d, flags=%x\n", 1274 __FUNCTION__, width, height, pad, flags)); 1275 1276 pixmap = create_pixmap(sna, screen, 0, 0, depth, usage); 1277 if (pixmap == NullPixmap) 1278 return NullPixmap; 1279 1280 pixmap->drawable.width = width; 1281 pixmap->drawable.height = height; 1282 pixmap->devKind = pad; 1283 pixmap->devPrivate.ptr = NULL; 1284 1285 ptr = NULL; 1286 } 1287 1288 priv = sna_pixmap_attach(pixmap); 1289 if (priv == NULL) { 1290 free(pixmap); 1291 goto fallback; 1292 } 1293 1294 priv->stride = pad; 1295 priv->create = flags; 1296 priv->ptr = ptr; 1297 1298 assert(to_sna_from_pixmap(pixmap) == sna); 1299 assert(pixmap->drawable.pScreen == screen); 1300 1301 return pixmap; 1302 1303fallback: 1304 return create_pixmap(sna, screen, width, height, depth, usage); 1305} 1306 1307void sna_add_flush_pixmap(struct sna *sna, 1308 struct sna_pixmap *priv, 1309 struct kgem_bo *bo) 1310{ 1311 DBG(("%s: marking pixmap=%ld for flushing\n", 1312 __FUNCTION__, priv->pixmap->drawable.serialNumber)); 1313 assert(bo); 1314 assert(bo->flush); 1315 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1316 list_move(&priv->flush_list, &sna->flush_pixmaps); 1317 1318 if (bo->exec == NULL && kgem_is_idle(&sna->kgem)) { 1319 DBG(("%s: new flush bo, flushin before\n", __FUNCTION__)); 1320 kgem_submit(&sna->kgem); 1321 } 1322} 1323 1324static void __sna_free_pixmap(struct sna *sna, 1325 PixmapPtr pixmap, 1326 struct sna_pixmap *priv) 1327{ 1328 list_del(&priv->flush_list); 1329 1330 assert(priv->gpu_damage == NULL); 1331 assert(priv->cpu_damage == NULL); 1332 1333 __sna_pixmap_free_cpu(sna, priv); 1334 1335 if (priv->header) { 1336 assert(!priv->shm); 1337 assert(pixmap->drawable.pScreen == sna->scrn->pScreen); 1338 pixmap->devPrivate.ptr = sna->freed_pixmap; 1339 sna->freed_pixmap = pixmap; 1340 } else { 1341 free(priv); 1342 FreePixmap(pixmap); 1343 } 1344} 1345 1346static Bool sna_destroy_pixmap(PixmapPtr pixmap) 1347{ 1348 struct sna *sna; 1349 struct sna_pixmap *priv; 1350 1351 if (--pixmap->refcnt) 1352 return TRUE; 1353 1354#if DEBUG_MEMORY 1355 to_sna_from_pixmap(pixmap)->debug_memory.pixmap_allocs--; 1356#endif 1357 1358 priv = sna_pixmap(pixmap); 1359 DBG(("%s: pixmap=%ld, attached?=%d\n", 1360 __FUNCTION__, pixmap->drawable.serialNumber, priv != NULL)); 1361 if (priv == NULL) { 1362 FreePixmap(pixmap); 1363 return TRUE; 1364 } 1365 1366 assert_pixmap_damage(pixmap); 1367 sna = to_sna_from_pixmap(pixmap); 1368 1369 sna_damage_destroy(&priv->gpu_damage); 1370 sna_damage_destroy(&priv->cpu_damage); 1371 1372 if (priv->cow) { 1373 struct sna_cow *cow = COW(priv->cow); 1374 DBG(("%s: pixmap=%ld discarding cow, refcnt=%d\n", 1375 __FUNCTION__, pixmap->drawable.serialNumber, cow->refcnt)); 1376 assert(cow->refcnt); 1377 list_del(&priv->cow_list); 1378 if (!--cow->refcnt) 1379 free(cow); 1380 priv->cow = NULL; 1381 } 1382 1383 /* Always release the gpu bo back to the lower levels of caching */ 1384 if (priv->gpu_bo) { 1385 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1386 priv->gpu_bo = NULL; 1387 } 1388 1389 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) { 1390 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 1391 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */ 1392 } else 1393 __sna_free_pixmap(sna, pixmap, priv); 1394 return TRUE; 1395} 1396 1397void sna_pixmap_destroy(PixmapPtr pixmap) 1398{ 1399 assert(pixmap->refcnt == 1); 1400 assert(sna_pixmap(pixmap) == NULL || sna_pixmap(pixmap)->header == true); 1401 1402 sna_destroy_pixmap(pixmap); 1403} 1404 1405static inline bool has_coherent_map(struct sna *sna, 1406 struct kgem_bo *bo, 1407 unsigned flags) 1408{ 1409 assert(bo); 1410 assert(bo->map); 1411 1412 if (!IS_CPU_MAP(bo->map)) 1413 return true; 1414 1415 if (bo->tiling == I915_TILING_Y) 1416 return false; 1417 1418 return kgem_bo_can_map__cpu(&sna->kgem, bo, flags & MOVE_WRITE); 1419} 1420 1421static inline bool has_coherent_ptr(struct sna_pixmap *priv) 1422{ 1423 if (priv == NULL) 1424 return true; 1425 1426 if (!priv->mapped) { 1427 if (!priv->cpu_bo) 1428 return true; 1429 1430 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map); 1431 } 1432 1433 if (priv->cpu && !IS_CPU_MAP(priv->gpu_bo->map)) 1434 return false; 1435 1436 return priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map); 1437} 1438 1439static inline bool pixmap_inplace(struct sna *sna, 1440 PixmapPtr pixmap, 1441 struct sna_pixmap *priv, 1442 unsigned flags) 1443{ 1444 if (FORCE_INPLACE) 1445 return FORCE_INPLACE > 0; 1446 1447 if (wedged(sna) && !priv->pinned) 1448 return false; 1449 1450 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) { 1451 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) 1452 return false; 1453 1454 if ((flags & MOVE_READ) == 0) 1455 return !priv->pinned; 1456 } 1457 1458 if (priv->mapped) 1459 return has_coherent_map(sna, priv->gpu_bo, flags); 1460 1461 if (flags & MOVE_READ && 1462 (priv->cpu || priv->cpu_damage || priv->gpu_damage == NULL)) 1463 return false; 1464 1465 return (pixmap->devKind * pixmap->drawable.height >> 12) > 1466 sna->kgem.half_cpu_cache_pages; 1467} 1468 1469static bool 1470sna_pixmap_create_mappable_gpu(PixmapPtr pixmap, 1471 bool can_replace) 1472{ 1473 struct sna *sna = to_sna_from_pixmap(pixmap); 1474 struct sna_pixmap *priv = sna_pixmap(pixmap); 1475 unsigned create; 1476 1477 if (wedged(sna)) 1478 goto done; 1479 1480 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) 1481 goto done; 1482 1483 assert_pixmap_damage(pixmap); 1484 1485 if (can_replace && priv->gpu_bo && 1486 (!kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo) || 1487 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1488 if (priv->pinned) 1489 goto done; 1490 1491 DBG(("%s: discard busy GPU bo\n", __FUNCTION__)); 1492 sna_pixmap_free_gpu(sna, priv); 1493 } 1494 1495 if (priv->gpu_bo) 1496 return kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo); 1497 1498 assert_pixmap_damage(pixmap); 1499 1500 assert(priv->gpu_damage == NULL); 1501 assert(priv->gpu_bo == NULL); 1502 1503 create = CREATE_GTT_MAP | CREATE_INACTIVE; 1504 if (pixmap->usage_hint == SNA_CREATE_FB) 1505 create |= CREATE_SCANOUT; 1506 1507 priv->gpu_bo = 1508 kgem_create_2d(&sna->kgem, 1509 pixmap->drawable.width, 1510 pixmap->drawable.height, 1511 pixmap->drawable.bitsPerPixel, 1512 sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING), 1513 create); 1514 1515done: 1516 return priv->gpu_bo && kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo); 1517} 1518 1519static inline bool use_cpu_bo_for_download(struct sna *sna, 1520 struct sna_pixmap *priv, 1521 int nbox, const BoxRec *box) 1522{ 1523 if (DBG_NO_CPU_DOWNLOAD) 1524 return false; 1525 1526 if (wedged(sna)) 1527 return false; 1528 1529 if (priv->cpu_bo == NULL || !sna->kgem.can_blt_cpu) 1530 return false; 1531 1532 if (kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo)) { 1533 DBG(("%s: yes, either bo is busy, so use GPU for readback\n", 1534 __FUNCTION__)); 1535 return true; 1536 } 1537 1538 /* Is it worth detiling? */ 1539 assert(box[0].y1 < box[nbox-1].y2); 1540 if (kgem_bo_is_mappable(&sna->kgem, priv->gpu_bo) && 1541 (box[nbox-1].y2 - box[0].y1 - 1) * priv->gpu_bo->pitch < 4096) { 1542 DBG(("%s: no, tiny transfer (height=%d, pitch=%d) expect to read inplace\n", 1543 __FUNCTION__, box[nbox-1].y2-box[0].y1, priv->gpu_bo->pitch)); 1544 return false; 1545 } 1546 1547 DBG(("%s: yes, default action\n", __FUNCTION__)); 1548 return true; 1549} 1550 1551static inline bool use_cpu_bo_for_upload(struct sna *sna, 1552 struct sna_pixmap *priv, 1553 unsigned flags) 1554{ 1555 if (DBG_NO_CPU_UPLOAD) 1556 return false; 1557 1558 if (wedged(sna)) 1559 return false; 1560 1561 if (priv->cpu_bo == NULL) 1562 return false; 1563 1564 DBG(("%s? flags=%x, gpu busy?=%d, cpu busy?=%d\n", __FUNCTION__, 1565 flags, 1566 kgem_bo_is_busy(priv->gpu_bo), 1567 kgem_bo_is_busy(priv->cpu_bo))); 1568 1569 if (!priv->cpu) 1570 return true; 1571 1572 if (flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) 1573 return true; 1574 1575 if (priv->gpu_bo->tiling) 1576 return true; 1577 1578 return kgem_bo_is_busy(priv->gpu_bo) || kgem_bo_is_busy(priv->cpu_bo); 1579} 1580 1581bool 1582sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags) 1583{ 1584 struct sna_cow *cow = COW(priv->cow); 1585 1586 DBG(("%s: pixmap=%ld, handle=%d, flags=%x\n", 1587 __FUNCTION__, 1588 priv->pixmap->drawable.serialNumber, 1589 priv->gpu_bo->handle, 1590 flags)); 1591 1592 assert(priv->gpu_bo == cow->bo); 1593 assert(cow->refcnt); 1594 1595 list_del(&priv->cow_list); 1596 1597 if (!--cow->refcnt) { 1598 assert(list_is_empty(&cow->list)); 1599 free(cow); 1600 } else if (IS_COW_OWNER(priv->cow) && priv->pinned) { 1601 PixmapPtr pixmap = priv->pixmap; 1602 struct kgem_bo *bo; 1603 BoxRec box; 1604 1605 DBG(("%s: copying the Holy cow\n", __FUNCTION__)); 1606 1607 box.x1 = box.y1 = 0; 1608 box.x2 = pixmap->drawable.width; 1609 box.y2 = pixmap->drawable.height; 1610 1611 bo = kgem_create_2d(&sna->kgem, 1612 box.x2, box.y2, 1613 pixmap->drawable.bitsPerPixel, 1614 sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING), 1615 0); 1616 if (bo == NULL) { 1617 cow->refcnt++; 1618 DBG(("%s: allocation failed\n", __FUNCTION__)); 1619 return false; 1620 } 1621 1622 if (!sna->render.copy_boxes(sna, GXcopy, 1623 pixmap, priv->gpu_bo, 0, 0, 1624 pixmap, bo, 0, 0, 1625 &box, 1, 0)) { 1626 DBG(("%s: copy failed\n", __FUNCTION__)); 1627 kgem_bo_destroy(&sna->kgem, bo); 1628 cow->refcnt++; 1629 return false; 1630 } 1631 1632 assert(!list_is_empty(&cow->list)); 1633 while (!list_is_empty(&cow->list)) { 1634 struct sna_pixmap *clone; 1635 1636 clone = list_first_entry(&cow->list, 1637 struct sna_pixmap, cow_list); 1638 list_del(&clone->cow_list); 1639 1640 assert(clone->gpu_bo == cow->bo); 1641 kgem_bo_destroy(&sna->kgem, clone->gpu_bo); 1642 clone->gpu_bo = kgem_bo_reference(bo); 1643 } 1644 cow->bo = bo; 1645 kgem_bo_destroy(&sna->kgem, bo); 1646 } else { 1647 struct kgem_bo *bo = NULL; 1648 1649 if (flags & MOVE_READ) { 1650 PixmapPtr pixmap = priv->pixmap; 1651 BoxRec box; 1652 1653 DBG(("%s: copying cow\n", __FUNCTION__)); 1654 1655 box.x1 = box.y1 = 0; 1656 box.x2 = pixmap->drawable.width; 1657 box.y2 = pixmap->drawable.height; 1658 1659 bo = kgem_create_2d(&sna->kgem, 1660 box.x2, box.y2, 1661 pixmap->drawable.bitsPerPixel, 1662 sna_pixmap_choose_tiling(pixmap, DEFAULT_TILING), 1663 0); 1664 if (bo == NULL) { 1665 cow->refcnt++; 1666 DBG(("%s: allocation failed\n", __FUNCTION__)); 1667 return false; 1668 } 1669 1670 if (!sna->render.copy_boxes(sna, GXcopy, 1671 pixmap, priv->gpu_bo, 0, 0, 1672 pixmap, bo, 0, 0, 1673 &box, 1, 0)) { 1674 DBG(("%s: copy failed\n", __FUNCTION__)); 1675 kgem_bo_destroy(&sna->kgem, bo); 1676 cow->refcnt++; 1677 return false; 1678 } 1679 } 1680 1681 assert(priv->gpu_bo); 1682 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1683 priv->gpu_bo = bo; 1684 if (priv->gpu_bo == NULL && priv->mapped) { 1685 priv->pixmap->devPrivate.ptr = NULL; 1686 priv->mapped = false; 1687 } 1688 } 1689 1690 priv->cow = NULL; 1691 return true; 1692} 1693 1694static bool 1695sna_pixmap_make_cow(struct sna *sna, 1696 struct sna_pixmap *src_priv, 1697 struct sna_pixmap *dst_priv) 1698{ 1699 struct sna_cow *cow; 1700 1701 assert(src_priv->gpu_bo); 1702 1703 if (!USE_COW) 1704 return false; 1705 1706 if (src_priv->gpu_bo->proxy) 1707 return false; 1708 1709 DBG(("%s: make cow src=%ld, dst=%ld, handle=%d (already cow? src=%d, dst=%d)\n", 1710 __FUNCTION__, 1711 src_priv->pixmap->drawable.serialNumber, 1712 dst_priv->pixmap->drawable.serialNumber, 1713 src_priv->gpu_bo->handle, 1714 src_priv->cow ? IS_COW_OWNER(src_priv->cow) ? 1 : -1 : 0, 1715 dst_priv->cow ? IS_COW_OWNER(dst_priv->cow) ? 1 : -1 : 0)); 1716 1717 if (dst_priv->pinned) { 1718 DBG(("%s: can't cow, dst_pinned=%x\n", 1719 __FUNCTION__, dst_priv->pinned)); 1720 return false; 1721 } 1722 1723 assert(!dst_priv->flush); 1724 1725 cow = COW(src_priv->cow); 1726 if (cow == NULL) { 1727 cow = malloc(sizeof(*cow)); 1728 if (cow == NULL) 1729 return false; 1730 1731 list_init(&cow->list); 1732 1733 cow->bo = src_priv->gpu_bo; 1734 cow->refcnt = 1; 1735 1736 DBG(("%s: moo! attaching source cow to pixmap=%ld, handle=%d\n", 1737 __FUNCTION__, 1738 src_priv->pixmap->drawable.serialNumber, 1739 cow->bo->handle)); 1740 1741 src_priv->cow = MAKE_COW_OWNER(cow); 1742 list_init(&src_priv->cow_list); 1743 } 1744 1745 if (cow == COW(dst_priv->cow)) { 1746 assert(dst_priv->gpu_bo == cow->bo); 1747 return true; 1748 } 1749 1750 if (dst_priv->cow) 1751 sna_pixmap_undo_cow(sna, dst_priv, 0); 1752 1753 if (dst_priv->gpu_bo) 1754 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 1755 dst_priv->gpu_bo = kgem_bo_reference(cow->bo); 1756 dst_priv->cow = cow; 1757 list_add(&dst_priv->cow_list, &cow->list); 1758 cow->refcnt++; 1759 1760 DBG(("%s: moo! attaching clone to pixmap=%ld (source=%ld, handle=%d)\n", 1761 __FUNCTION__, 1762 dst_priv->pixmap->drawable.serialNumber, 1763 src_priv->pixmap->drawable.serialNumber, 1764 cow->bo->handle)); 1765 1766 if (dst_priv->mapped) { 1767 dst_priv->pixmap->devPrivate.ptr = NULL; 1768 dst_priv->mapped = false; 1769 } 1770 1771 return true; 1772} 1773 1774static inline bool operate_inplace(struct sna_pixmap *priv, unsigned flags) 1775{ 1776 if ((flags & MOVE_INPLACE_HINT) == 0) { 1777 DBG(("%s: no, inplace operation not suitable\n", __FUNCTION__)); 1778 return false; 1779 } 1780 1781 assert((flags & MOVE_ASYNC_HINT) == 0); 1782 1783 if (priv->cow && flags & MOVE_WRITE) { 1784 DBG(("%s: no, has COW\n", __FUNCTION__)); 1785 return false; 1786 } 1787 1788 if ((priv->create & KGEM_CAN_CREATE_GTT) == 0) { 1789 DBG(("%s: no, not accessible via GTT\n", __FUNCTION__)); 1790 return false; 1791 } 1792 1793 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 1794 DBG(("%s: yes, CPU is busy\n", __FUNCTION__)); 1795 return true; 1796 } 1797 1798 if (priv->create & KGEM_CAN_CREATE_LARGE) { 1799 DBG(("%s: large object, has GPU? %d\n", 1800 __FUNCTION__, priv->gpu_bo ? priv->gpu_bo->handle : 0)); 1801 return priv->gpu_bo != NULL; 1802 } 1803 1804 if (flags & MOVE_WRITE && priv->gpu_bo&&kgem_bo_is_busy(priv->gpu_bo)) { 1805 DBG(("%s: no, GPU is busy, so stage write\n", __FUNCTION__)); 1806 return false; 1807 } 1808 1809 return true; 1810} 1811 1812bool 1813_sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned int flags) 1814{ 1815 struct sna *sna = to_sna_from_pixmap(pixmap); 1816 struct sna_pixmap *priv; 1817 1818 DBG(("%s(pixmap=%ld, %dx%d, flags=%x)\n", __FUNCTION__, 1819 pixmap->drawable.serialNumber, 1820 pixmap->drawable.width, 1821 pixmap->drawable.height, 1822 flags)); 1823 1824 assert(flags & (MOVE_READ | MOVE_WRITE)); 1825 assert_pixmap_damage(pixmap); 1826 1827 priv = sna_pixmap(pixmap); 1828 if (priv == NULL) { 1829 DBG(("%s: not attached\n", __FUNCTION__)); 1830 return true; 1831 } 1832 1833 DBG(("%s: gpu_bo=%d, gpu_damage=%p, cpu_damage=%p, is-clear?=%d\n", 1834 __FUNCTION__, 1835 priv->gpu_bo ? priv->gpu_bo->handle : 0, 1836 priv->gpu_damage, priv->cpu_damage, priv->clear)); 1837 1838 assert(priv->gpu_damage == NULL || priv->gpu_bo); 1839 1840 if ((flags & MOVE_READ) == 0 && UNDO) { 1841 if (priv->gpu_bo) 1842 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 1843 if (priv->cpu_bo) 1844 kgem_bo_undo(&sna->kgem, priv->cpu_bo); 1845 } 1846 1847 if (USE_INPLACE && (flags & MOVE_READ) == 0 && !priv->cow) { 1848 assert(flags & MOVE_WRITE); 1849 DBG(("%s: no readbck, discarding gpu damage [%d], pending clear[%d]\n", 1850 __FUNCTION__, priv->gpu_damage != NULL, priv->clear)); 1851 1852 if ((priv->gpu_bo || priv->create & KGEM_CAN_CREATE_GPU) && 1853 pixmap_inplace(sna, pixmap, priv, flags) && 1854 sna_pixmap_create_mappable_gpu(pixmap, true)) { 1855 DBG(("%s: write inplace\n", __FUNCTION__)); 1856 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 1857 assert(!priv->shm); 1858 assert(priv->gpu_bo->exec == NULL); 1859 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 1860 1861 pixmap->devPrivate.ptr = 1862 kgem_bo_map(&sna->kgem, priv->gpu_bo); 1863 priv->mapped = pixmap->devPrivate.ptr != NULL; 1864 if (!priv->mapped) 1865 goto skip_inplace_map; 1866 1867 assert(has_coherent_map(sna, priv->gpu_bo, flags)); 1868 pixmap->devKind = priv->gpu_bo->pitch; 1869 1870 assert(priv->gpu_bo->proxy == NULL); 1871 sna_damage_all(&priv->gpu_damage, 1872 pixmap->drawable.width, 1873 pixmap->drawable.height); 1874 sna_damage_destroy(&priv->cpu_damage); 1875 priv->clear = false; 1876 priv->cpu = false; 1877 list_del(&priv->flush_list); 1878 1879 assert(!priv->shm); 1880 assert(priv->cpu_bo == NULL || !priv->cpu_bo->flush); 1881 sna_pixmap_free_cpu(sna, priv); 1882 1883 assert_pixmap_damage(pixmap); 1884 return true; 1885 } 1886 1887skip_inplace_map: 1888 sna_damage_destroy(&priv->gpu_damage); 1889 priv->clear = false; 1890 if (priv->cpu_bo && !priv->cpu_bo->flush && 1891 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 1892 DBG(("%s: discarding busy CPU bo\n", __FUNCTION__)); 1893 assert(!priv->shm); 1894 assert(priv->gpu_bo == NULL || priv->gpu_damage == NULL); 1895 1896 sna_damage_destroy(&priv->cpu_damage); 1897 sna_pixmap_free_cpu(sna, priv); 1898 1899 if (!sna_pixmap_alloc_cpu(sna, pixmap, priv, false)) 1900 return false; 1901 1902 goto mark_damage; 1903 } 1904 } 1905 1906 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 1907 DBG(("%s: CPU all-damaged\n", __FUNCTION__)); 1908 assert(priv->gpu_damage == NULL || DAMAGE_IS_ALL(priv->gpu_damage)); 1909 goto done; 1910 } 1911 1912 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 1913 1914 if (USE_INPLACE && 1915 operate_inplace(priv, flags) && 1916 pixmap_inplace(sna, pixmap, priv, flags) && 1917 sna_pixmap_create_mappable_gpu(pixmap, (flags & MOVE_READ) == 0)) { 1918 DBG(("%s: try to operate inplace (GTT)\n", __FUNCTION__)); 1919 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 1920 assert((flags & MOVE_READ) == 0 || priv->cpu_damage == NULL); 1921 /* XXX only sync for writes? */ 1922 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 1923 assert(priv->gpu_bo->exec == NULL); 1924 1925 pixmap->devPrivate.ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 1926 priv->mapped = pixmap->devPrivate.ptr != NULL; 1927 if (priv->mapped) { 1928 assert(has_coherent_map(sna, priv->gpu_bo, flags)); 1929 pixmap->devKind = priv->gpu_bo->pitch; 1930 1931 if (flags & MOVE_WRITE) { 1932 assert(priv->gpu_bo->proxy == NULL); 1933 sna_damage_all(&priv->gpu_damage, 1934 pixmap->drawable.width, 1935 pixmap->drawable.height); 1936 sna_damage_destroy(&priv->cpu_damage); 1937 sna_pixmap_free_cpu(sna, priv); 1938 list_del(&priv->flush_list); 1939 priv->clear = false; 1940 } 1941 priv->cpu = false; 1942 1943 assert_pixmap_damage(pixmap); 1944 DBG(("%s: operate inplace (GTT)\n", __FUNCTION__)); 1945 return true; 1946 } 1947 } 1948 1949 if (priv->mapped) { 1950 assert(!priv->shm && priv->stride); 1951 pixmap->devPrivate.ptr = PTR(priv->ptr); 1952 pixmap->devKind = priv->stride; 1953 priv->mapped = false; 1954 } 1955 1956 if (USE_INPLACE && 1957 priv->gpu_damage && priv->cpu_damage == NULL && !priv->cow && 1958 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) && 1959 priv->gpu_bo->tiling == I915_TILING_NONE && 1960 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 1961 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 1962 DBG(("%s: try to operate inplace (CPU)\n", __FUNCTION__)); 1963 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 1964 1965 assert(!priv->mapped); 1966 pixmap->devPrivate.ptr = 1967 kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 1968 if (pixmap->devPrivate.ptr != NULL) { 1969 priv->cpu = true; 1970 priv->mapped = true; 1971 pixmap->devKind = priv->gpu_bo->pitch; 1972 if (flags & MOVE_WRITE) { 1973 assert(priv->gpu_bo->proxy == NULL); 1974 sna_damage_all(&priv->gpu_damage, 1975 pixmap->drawable.width, 1976 pixmap->drawable.height); 1977 sna_damage_destroy(&priv->cpu_damage); 1978 sna_pixmap_free_cpu(sna, priv); 1979 list_del(&priv->flush_list); 1980 priv->clear = false; 1981 } 1982 1983 assert(IS_CPU_MAP(priv->gpu_bo->map)); 1984 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 1985 FORCE_FULL_SYNC || flags & MOVE_WRITE); 1986 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->gpu_bo->map & ~3)); 1987 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 1988 assert_pixmap_damage(pixmap); 1989 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 1990 return true; 1991 } 1992 } 1993 1994 if (((flags & MOVE_READ) == 0 || priv->clear) && 1995 priv->cpu_bo && !priv->cpu_bo->flush && 1996 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 1997 assert(!priv->shm); 1998 sna_pixmap_free_cpu(sna, priv); 1999 } 2000 2001 if (pixmap->devPrivate.ptr == NULL && 2002 !sna_pixmap_alloc_cpu(sna, pixmap, priv, 2003 flags & MOVE_READ ? priv->gpu_damage && !priv->clear : 0)) 2004 return false; 2005 assert(pixmap->devPrivate.ptr); 2006 assert(!priv->mapped); 2007 2008 if (priv->clear) { 2009 DBG(("%s: applying clear [%08x] size=%dx%d, stride=%d (total=%d)\n", 2010 __FUNCTION__, priv->clear_color, pixmap->drawable.width, pixmap->drawable.height, 2011 pixmap->devKind, pixmap->devKind * pixmap->drawable.height)); 2012 2013 if (priv->cpu_bo) { 2014 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2015 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2016 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3)); 2017 } 2018 2019 if (priv->clear_color == 0 || 2020 pixmap->drawable.bitsPerPixel == 8 || 2021 priv->clear_color == (1 << pixmap->drawable.depth) - 1) { 2022 memset(pixmap->devPrivate.ptr, priv->clear_color, 2023 pixmap->devKind * pixmap->drawable.height); 2024 } else { 2025 pixman_fill(pixmap->devPrivate.ptr, 2026 pixmap->devKind/sizeof(uint32_t), 2027 pixmap->drawable.bitsPerPixel, 2028 0, 0, 2029 pixmap->drawable.width, 2030 pixmap->drawable.height, 2031 priv->clear_color); 2032 } 2033 2034 sna_damage_all(&priv->cpu_damage, 2035 pixmap->drawable.width, 2036 pixmap->drawable.height); 2037 sna_pixmap_free_gpu(sna, priv); 2038 assert(priv->gpu_damage == NULL); 2039 assert(priv->clear == false); 2040 } 2041 2042 if (priv->gpu_damage) { 2043 BoxPtr box; 2044 int n; 2045 2046 DBG(("%s: flushing GPU damage\n", __FUNCTION__)); 2047 assert(priv->gpu_bo); 2048 2049 n = sna_damage_get_boxes(priv->gpu_damage, &box); 2050 if (n) { 2051 bool ok = false; 2052 2053 if (use_cpu_bo_for_download(sna, priv, n, box)) { 2054 DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__)); 2055 ok = sna->render.copy_boxes(sna, GXcopy, 2056 pixmap, priv->gpu_bo, 0, 0, 2057 pixmap, priv->cpu_bo, 0, 0, 2058 box, n, COPY_LAST); 2059 } 2060 if (!ok) { 2061 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2062 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2063 box, n); 2064 } 2065 } 2066 2067 __sna_damage_destroy(DAMAGE_PTR(priv->gpu_damage)); 2068 priv->gpu_damage = NULL; 2069 } 2070 2071 if (flags & MOVE_WRITE || priv->create & KGEM_CAN_CREATE_LARGE) { 2072mark_damage: 2073 DBG(("%s: marking as damaged\n", __FUNCTION__)); 2074 sna_damage_all(&priv->cpu_damage, 2075 pixmap->drawable.width, 2076 pixmap->drawable.height); 2077 assert(priv->gpu_damage == NULL); 2078 sna_pixmap_free_gpu(sna, priv); 2079 2080 if (priv->flush) { 2081 assert(!priv->shm); 2082 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2083 } 2084 } 2085 2086done: 2087 if (flags & MOVE_WRITE) { 2088 assert(DAMAGE_IS_ALL(priv->cpu_damage)); 2089 assert(priv->gpu_damage == NULL); 2090 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2091 if (priv->cow) 2092 sna_pixmap_undo_cow(sna, priv, 0); 2093 if (priv->gpu_bo && priv->gpu_bo->rq == NULL) { 2094 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__)); 2095 sna_pixmap_free_gpu(sna, priv); 2096 } 2097 priv->source_count = SOURCE_BIAS; 2098 } 2099 2100 if (priv->cpu_bo) { 2101 if ((flags & MOVE_ASYNC_HINT) == 0) { 2102 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2103 assert(IS_CPU_MAP(priv->cpu_bo->map)); 2104 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2105 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2106 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3)); 2107 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2108 } 2109 } 2110 priv->cpu = 2111 (flags & (MOVE_INPLACE_HINT | MOVE_ASYNC_HINT)) == 0 && 2112 !DAMAGE_IS_ALL(priv->gpu_damage); 2113 assert(pixmap->devPrivate.ptr); 2114 assert(pixmap->devKind); 2115 assert_pixmap_damage(pixmap); 2116 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2117 return true; 2118} 2119 2120static bool 2121region_overlaps_damage(const RegionRec *region, 2122 struct sna_damage *damage, 2123 int dx, int dy) 2124{ 2125 const BoxRec *re, *de; 2126 2127 DBG(("%s?\n", __FUNCTION__)); 2128 2129 if (damage == NULL) 2130 return false; 2131 2132 if (DAMAGE_IS_ALL(damage)) 2133 return true; 2134 2135 re = ®ion->extents; 2136 de = &DAMAGE_PTR(damage)->extents; 2137 DBG(("%s: region (%d, %d), (%d, %d), damage (%d, %d), (%d, %d)\n", 2138 __FUNCTION__, 2139 re->x1, re->y1, re->x2, re->y2, 2140 de->x1, de->y1, de->x2, de->y2)); 2141 2142 return (re->x1 + dx < de->x2 && re->x2 + dx > de->x1 && 2143 re->y1 + dy < de->y2 && re->y2 + dy > de->y1); 2144} 2145 2146#ifndef NDEBUG 2147static bool 2148pixmap_contains_damage(PixmapPtr pixmap, struct sna_damage *damage) 2149{ 2150 if (damage == NULL) 2151 return true; 2152 2153 damage = DAMAGE_PTR(damage); 2154 return (damage->extents.x2 <= pixmap->drawable.width && 2155 damage->extents.y2 <= pixmap->drawable.height && 2156 damage->extents.x1 >= 0 && 2157 damage->extents.y1 >= 0); 2158} 2159#endif 2160 2161static inline bool region_inplace(struct sna *sna, 2162 PixmapPtr pixmap, 2163 RegionPtr region, 2164 struct sna_pixmap *priv, 2165 unsigned flags) 2166{ 2167 assert_pixmap_damage(pixmap); 2168 2169 if (FORCE_INPLACE) 2170 return FORCE_INPLACE > 0; 2171 2172 if (wedged(sna) && !priv->pinned) 2173 return false; 2174 2175 if (priv->gpu_damage && 2176 (priv->clear || (flags & MOVE_READ) == 0) && 2177 kgem_bo_is_busy(priv->gpu_bo)) 2178 return false; 2179 2180 if (flags & MOVE_READ && 2181 (priv->cpu || 2182 priv->gpu_damage == NULL || 2183 region_overlaps_damage(region, priv->cpu_damage, 0, 0))) { 2184 DBG(("%s: no, uncovered CPU damage pending\n", __FUNCTION__)); 2185 return false; 2186 } 2187 2188 if (priv->mapped) { 2189 DBG(("%s: %s, already mapped, continuing\n", __FUNCTION__, 2190 has_coherent_map(sna, priv->gpu_bo, flags) ? "yes" : "no")); 2191 return has_coherent_map(sna, priv->gpu_bo, flags); 2192 } 2193 2194 if (priv->flush) { 2195 DBG(("%s: yes, exported via dri, will flush\n", __FUNCTION__)); 2196 return true; 2197 } 2198 2199 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 2200 DBG(("%s: yes, already wholly damaged on the GPU\n", __FUNCTION__)); 2201 assert(priv->gpu_bo); 2202 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 2203 return true; 2204 } 2205 2206 DBG(("%s: (%dx%d), inplace? %d\n", 2207 __FUNCTION__, 2208 region->extents.x2 - region->extents.x1, 2209 region->extents.y2 - region->extents.y1, 2210 ((int)(region->extents.x2 - region->extents.x1) * 2211 (int)(region->extents.y2 - region->extents.y1) * 2212 pixmap->drawable.bitsPerPixel >> 12) 2213 >= sna->kgem.half_cpu_cache_pages)); 2214 return ((int)(region->extents.x2 - region->extents.x1) * 2215 (int)(region->extents.y2 - region->extents.y1) * 2216 pixmap->drawable.bitsPerPixel >> 12) 2217 >= sna->kgem.half_cpu_cache_pages; 2218} 2219 2220bool 2221sna_drawable_move_region_to_cpu(DrawablePtr drawable, 2222 RegionPtr region, 2223 unsigned flags) 2224{ 2225 PixmapPtr pixmap = get_drawable_pixmap(drawable); 2226 struct sna *sna = to_sna_from_pixmap(pixmap); 2227 struct sna_pixmap *priv; 2228 int16_t dx, dy; 2229 2230 DBG(("%s(pixmap=%ld (%dx%d), [(%d, %d), (%d, %d)], flags=%d)\n", 2231 __FUNCTION__, pixmap->drawable.serialNumber, 2232 pixmap->drawable.width, pixmap->drawable.height, 2233 RegionExtents(region)->x1, RegionExtents(region)->y1, 2234 RegionExtents(region)->x2, RegionExtents(region)->y2, 2235 flags)); 2236 2237 assert_pixmap_damage(pixmap); 2238 if (flags & MOVE_WRITE) { 2239 assert_drawable_contains_box(drawable, ®ion->extents); 2240 } 2241 assert(flags & (MOVE_WRITE | MOVE_READ)); 2242 2243 if (box_empty(®ion->extents)) 2244 return true; 2245 2246 priv = sna_pixmap(pixmap); 2247 if (priv == NULL) { 2248 DBG(("%s: not attached to %p\n", __FUNCTION__, pixmap)); 2249 return true; 2250 } 2251 2252 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2253 2254 if (sna_damage_is_all(&priv->cpu_damage, 2255 pixmap->drawable.width, 2256 pixmap->drawable.height)) { 2257 DBG(("%s: pixmap=%ld all damaged on CPU\n", 2258 __FUNCTION__, pixmap->drawable.serialNumber)); 2259 assert(!priv->clear); 2260 2261 sna_damage_destroy(&priv->gpu_damage); 2262 2263 if (flags & MOVE_WRITE) 2264 sna_pixmap_free_gpu(sna, priv); 2265 2266 if (pixmap->devPrivate.ptr == NULL && 2267 !sna_pixmap_alloc_cpu(sna, pixmap, priv, false)) 2268 return false; 2269 2270 goto out; 2271 } 2272 2273 if (USE_INPLACE && 2274 (priv->create & KGEM_CAN_CREATE_LARGE || 2275 ((flags & (MOVE_READ | MOVE_ASYNC_HINT)) == 0 && 2276 (priv->flush || box_inplace(pixmap, ®ion->extents))))) { 2277 DBG(("%s: marking for inplace hint (%d, %d)\n", 2278 __FUNCTION__, priv->flush, box_inplace(pixmap, ®ion->extents))); 2279 flags |= MOVE_INPLACE_HINT; 2280 } 2281 2282 if (flags & MOVE_WHOLE_HINT) 2283 return _sna_pixmap_move_to_cpu(pixmap, flags); 2284 2285 if (priv->gpu_bo == NULL && 2286 (priv->create & KGEM_CAN_CREATE_GPU) == 0 && 2287 flags & MOVE_WRITE) 2288 return _sna_pixmap_move_to_cpu(pixmap, flags); 2289 2290 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 2291 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 2292 RegionTranslate(region, dx, dy); 2293 } 2294 2295 if (region_subsumes_drawable(region, &pixmap->drawable)) { 2296 DBG(("%s: region (%d, %d), (%d, %d) subsumes pixmap (%dx%d)\n", 2297 __FUNCTION__, 2298 region->extents.x1, 2299 region->extents.y1, 2300 region->extents.x2, 2301 region->extents.y2, 2302 pixmap->drawable.width, 2303 pixmap->drawable.height)); 2304 if (dx | dy) 2305 RegionTranslate(region, -dx, -dy); 2306 return _sna_pixmap_move_to_cpu(pixmap, flags); 2307 } 2308 2309 if (USE_INPLACE && 2310 operate_inplace(priv, flags) && 2311 region_inplace(sna, pixmap, region, priv, flags) && 2312 sna_pixmap_create_mappable_gpu(pixmap, false)) { 2313 DBG(("%s: try to operate inplace\n", __FUNCTION__)); 2314 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2315 /* XXX only sync for writes? */ 2316 kgem_bo_submit(&sna->kgem, priv->gpu_bo); 2317 assert(priv->gpu_bo->exec == NULL); 2318 2319 pixmap->devPrivate.ptr = kgem_bo_map(&sna->kgem, priv->gpu_bo); 2320 priv->mapped = pixmap->devPrivate.ptr != NULL; 2321 if (priv->mapped) { 2322 assert(has_coherent_map(sna, priv->gpu_bo, flags)); 2323 pixmap->devKind = priv->gpu_bo->pitch; 2324 if (flags & MOVE_WRITE) { 2325 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2326 assert(!priv->clear); 2327 sna_damage_add(&priv->gpu_damage, region); 2328 if (sna_damage_is_all(&priv->gpu_damage, 2329 pixmap->drawable.width, 2330 pixmap->drawable.height)) { 2331 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2332 __FUNCTION__)); 2333 sna_damage_destroy(&priv->cpu_damage); 2334 list_del(&priv->flush_list); 2335 } else 2336 sna_damage_subtract(&priv->cpu_damage, 2337 region); 2338 } 2339 priv->clear = false; 2340 } 2341 assert_pixmap_damage(pixmap); 2342 priv->cpu = false; 2343 if (dx | dy) 2344 RegionTranslate(region, -dx, -dy); 2345 DBG(("%s: operate inplace\n", __FUNCTION__)); 2346 return true; 2347 } 2348 } 2349 2350 if (priv->clear && flags & MOVE_WRITE) { 2351 DBG(("%s: pending clear, moving whole pixmap for partial write\n", __FUNCTION__)); 2352 if (dx | dy) 2353 RegionTranslate(region, -dx, -dy); 2354 return _sna_pixmap_move_to_cpu(pixmap, flags | MOVE_READ); 2355 } 2356 2357 if (priv->mapped) { 2358 assert(!priv->shm); 2359 pixmap->devPrivate.ptr = NULL; 2360 priv->mapped = false; 2361 } 2362 2363 if (USE_INPLACE && 2364 priv->gpu_damage && 2365 priv->gpu_bo->tiling == I915_TILING_NONE && 2366 (DAMAGE_IS_ALL(priv->gpu_damage) || 2367 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2368 ®ion->extents)) && 2369 kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE) && 2370 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 || 2371 !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))) { 2372 DBG(("%s: try to operate inplace (CPU), read? %d, write? %d\n", 2373 __FUNCTION__, !!(flags & MOVE_READ), !!(flags & MOVE_WRITE))); 2374 assert(priv->cow == NULL || (flags & MOVE_WRITE) == 0); 2375 assert(sna_damage_contains_box(priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2376 assert(sna_damage_contains_box(priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2377 2378 assert(!priv->mapped); 2379 pixmap->devPrivate.ptr = 2380 kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 2381 if (pixmap->devPrivate.ptr != NULL) { 2382 assert(has_coherent_map(sna, priv->gpu_bo, flags)); 2383 assert(IS_CPU_MAP(priv->gpu_bo->map)); 2384 pixmap->devKind = priv->gpu_bo->pitch; 2385 priv->cpu = true; 2386 priv->mapped = true; 2387 if (flags & MOVE_WRITE) { 2388 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 2389 assert(!priv->clear); 2390 sna_damage_add(&priv->gpu_damage, region); 2391 if (sna_damage_is_all(&priv->gpu_damage, 2392 pixmap->drawable.width, 2393 pixmap->drawable.height)) { 2394 DBG(("%s: replaced entire pixmap, destroying CPU shadow\n", 2395 __FUNCTION__)); 2396 sna_damage_destroy(&priv->cpu_damage); 2397 list_del(&priv->flush_list); 2398 } else 2399 sna_damage_subtract(&priv->cpu_damage, 2400 region); 2401 } 2402 priv->clear = false; 2403 } 2404 assert_pixmap_damage(pixmap); 2405 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, 2406 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2407 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->gpu_bo->map & ~3)); 2408 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->gpu_bo)); 2409 assert_pixmap_damage(pixmap); 2410 if (dx | dy) 2411 RegionTranslate(region, -dx, -dy); 2412 DBG(("%s: operate inplace (CPU)\n", __FUNCTION__)); 2413 return true; 2414 } 2415 } 2416 2417 if ((priv->clear || (flags & MOVE_READ) == 0) && 2418 priv->cpu_bo && !priv->cpu_bo->flush && 2419 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 2420 sna_damage_subtract(&priv->cpu_damage, region); 2421 if (sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 2422 assert(priv->gpu_bo); 2423 sna_damage_all(&priv->gpu_damage, 2424 pixmap->drawable.width, 2425 pixmap->drawable.height); 2426 sna_pixmap_free_cpu(sna, priv); 2427 } 2428 } 2429 2430 if (pixmap->devPrivate.ptr == NULL && 2431 !sna_pixmap_alloc_cpu(sna, pixmap, priv, 2432 flags & MOVE_READ ? priv->gpu_damage && !priv->clear : 0)) { 2433 if (dx | dy) 2434 RegionTranslate(region, -dx, -dy); 2435 return false; 2436 } 2437 assert(pixmap->devPrivate.ptr); 2438 2439 if (priv->gpu_bo == NULL) { 2440 assert(priv->gpu_damage == NULL); 2441 goto done; 2442 } 2443 2444 assert(priv->gpu_bo->proxy == NULL); 2445 if (priv->clear) { 2446 int n = RegionNumRects(region); 2447 BoxPtr box = RegionRects(region); 2448 2449 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 2450 2451 DBG(("%s: pending clear, doing partial fill\n", __FUNCTION__)); 2452 if (priv->cpu_bo) { 2453 DBG(("%s: syncing CPU bo\n", __FUNCTION__)); 2454 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo); 2455 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3)); 2456 } 2457 2458 do { 2459 pixman_fill(pixmap->devPrivate.ptr, 2460 pixmap->devKind/sizeof(uint32_t), 2461 pixmap->drawable.bitsPerPixel, 2462 box->x1, box->y1, 2463 box->x2 - box->x1, 2464 box->y2 - box->y1, 2465 priv->clear_color); 2466 box++; 2467 } while (--n); 2468 2469 if (region->extents.x2 - region->extents.x1 > 1 || 2470 region->extents.y2 - region->extents.y1 > 1) { 2471 sna_damage_subtract(&priv->gpu_damage, region); 2472 priv->clear = false; 2473 } 2474 goto done; 2475 } 2476 2477 if ((flags & MOVE_READ) == 0) { 2478 assert(flags & MOVE_WRITE); 2479 sna_damage_subtract(&priv->gpu_damage, region); 2480 goto done; 2481 } 2482 2483 if (MIGRATE_ALL && priv->gpu_damage) { 2484 BoxPtr box; 2485 int n = sna_damage_get_boxes(priv->gpu_damage, &box); 2486 if (n) { 2487 bool ok; 2488 2489 DBG(("%s: forced migration\n", __FUNCTION__)); 2490 2491 assert(pixmap_contains_damage(pixmap, priv->gpu_damage)); 2492 assert(priv->gpu_bo); 2493 2494 ok = false; 2495 if (use_cpu_bo_for_download(sna, priv, n, box)) { 2496 DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__)); 2497 ok = sna->render.copy_boxes(sna, GXcopy, 2498 pixmap, priv->gpu_bo, 0, 0, 2499 pixmap, priv->cpu_bo, 0, 0, 2500 box, n, COPY_LAST); 2501 } 2502 if (!ok) { 2503 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2504 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2505 box, n); 2506 } 2507 } 2508 sna_damage_destroy(&priv->gpu_damage); 2509 } 2510 2511 if (priv->gpu_damage && 2512 (DAMAGE_IS_ALL(priv->gpu_damage) || 2513 sna_damage_overlaps_box(priv->gpu_damage, ®ion->extents))) { 2514 DBG(("%s: region (%dx%d) overlaps gpu damage\n", 2515 __FUNCTION__, 2516 region->extents.x2 - region->extents.x1, 2517 region->extents.y2 - region->extents.y1)); 2518 assert(priv->gpu_bo); 2519 2520 if (priv->cpu_damage == NULL) { 2521 if ((flags & MOVE_WRITE) == 0 && 2522 region->extents.x2 - region->extents.x1 == 1 && 2523 region->extents.y2 - region->extents.y1 == 1) { 2524 /* Often associated with synchronisation, KISS */ 2525 DBG(("%s: single pixel read\n", __FUNCTION__)); 2526 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2527 ®ion->extents, 1); 2528 goto done; 2529 } 2530 } else { 2531 if (sna_damage_contains_box__no_reduce(priv->cpu_damage, 2532 ®ion->extents)) { 2533 assert(sna_damage_contains_box(priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 2534 assert(sna_damage_contains_box(priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 2535 2536 DBG(("%s: region already in CPU damage\n", 2537 __FUNCTION__)); 2538 goto done; 2539 } 2540 } 2541 2542 if (sna_damage_contains_box(priv->gpu_damage, 2543 ®ion->extents) != PIXMAN_REGION_OUT) { 2544 RegionRec want, *r = region; 2545 2546 DBG(("%s: region (%dx%d) intersects gpu damage\n", 2547 __FUNCTION__, 2548 region->extents.x2 - region->extents.x1, 2549 region->extents.y2 - region->extents.y1)); 2550 2551 if ((flags & MOVE_WRITE) == 0 && 2552 region->extents.x2 - region->extents.x1 == 1 && 2553 region->extents.y2 - region->extents.y1 == 1) { 2554 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2555 ®ion->extents, 1); 2556 goto done; 2557 } 2558 2559 /* Expand the region to move 32x32 pixel blocks at a 2560 * time, as we assume that we will continue writing 2561 * afterwards and so aim to coallesce subsequent 2562 * reads. 2563 */ 2564 if (flags & MOVE_WRITE) { 2565 int n = RegionNumRects(region), i; 2566 BoxPtr boxes = RegionRects(region); 2567 BoxPtr blocks; 2568 2569 blocks = NULL; 2570 if (priv->cpu_damage == NULL) 2571 blocks = malloc(sizeof(BoxRec) * RegionNumRects(region)); 2572 if (blocks) { 2573 for (i = 0; i < n; i++) { 2574 blocks[i].x1 = boxes[i].x1 & ~31; 2575 if (blocks[i].x1 < 0) 2576 blocks[i].x1 = 0; 2577 2578 blocks[i].x2 = (boxes[i].x2 + 31) & ~31; 2579 if (blocks[i].x2 > pixmap->drawable.width) 2580 blocks[i].x2 = pixmap->drawable.width; 2581 2582 blocks[i].y1 = boxes[i].y1 & ~31; 2583 if (blocks[i].y1 < 0) 2584 blocks[i].y1 = 0; 2585 2586 blocks[i].y2 = (boxes[i].y2 + 31) & ~31; 2587 if (blocks[i].y2 > pixmap->drawable.height) 2588 blocks[i].y2 = pixmap->drawable.height; 2589 } 2590 if (pixman_region_init_rects(&want, blocks, i)) 2591 r = &want; 2592 free(blocks); 2593 } 2594 } 2595 2596 if (region_subsumes_damage(r, priv->gpu_damage)) { 2597 BoxPtr box; 2598 int n; 2599 2600 DBG(("%s: region wholly contains damage\n", 2601 __FUNCTION__)); 2602 2603 n = sna_damage_get_boxes(priv->gpu_damage, 2604 &box); 2605 if (n) { 2606 bool ok = false; 2607 2608 if (use_cpu_bo_for_download(sna, priv, n, box)) { 2609 DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__)); 2610 ok = sna->render.copy_boxes(sna, GXcopy, 2611 pixmap, priv->gpu_bo, 0, 0, 2612 pixmap, priv->cpu_bo, 0, 0, 2613 box, n, COPY_LAST); 2614 } 2615 2616 if (!ok) { 2617 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2618 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2619 box, n); 2620 } 2621 } 2622 2623 sna_damage_destroy(&priv->gpu_damage); 2624 } else if (DAMAGE_IS_ALL(priv->gpu_damage) || 2625 sna_damage_contains_box__no_reduce(priv->gpu_damage, 2626 &r->extents)) { 2627 BoxPtr box = RegionRects(r); 2628 int n = RegionNumRects(r); 2629 bool ok = false; 2630 2631 DBG(("%s: region wholly inside damage\n", 2632 __FUNCTION__)); 2633 2634 assert(sna_damage_contains_box(priv->gpu_damage, &r->extents) == PIXMAN_REGION_IN); 2635 assert(sna_damage_contains_box(priv->cpu_damage, &r->extents) == PIXMAN_REGION_OUT); 2636 2637 if (use_cpu_bo_for_download(sna, priv, n, box)) { 2638 DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__)); 2639 ok = sna->render.copy_boxes(sna, GXcopy, 2640 pixmap, priv->gpu_bo, 0, 0, 2641 pixmap, priv->cpu_bo, 0, 0, 2642 box, n, COPY_LAST); 2643 } 2644 if (!ok) { 2645 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2646 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2647 box, n); 2648 } 2649 2650 sna_damage_subtract(&priv->gpu_damage, r); 2651 } else { 2652 RegionRec need; 2653 2654 pixman_region_init(&need); 2655 if (sna_damage_intersect(priv->gpu_damage, r, &need)) { 2656 BoxPtr box = RegionRects(&need); 2657 int n = RegionNumRects(&need); 2658 bool ok = false; 2659 2660 DBG(("%s: region intersects damage\n", 2661 __FUNCTION__)); 2662 2663 if (use_cpu_bo_for_download(sna, priv, n, box)) { 2664 DBG(("%s: using CPU bo for download from GPU\n", __FUNCTION__)); 2665 ok = sna->render.copy_boxes(sna, GXcopy, 2666 pixmap, priv->gpu_bo, 0, 0, 2667 pixmap, priv->cpu_bo, 0, 0, 2668 box, n, COPY_LAST); 2669 } 2670 if (!ok) { 2671 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2672 sna_read_boxes(sna, pixmap, priv->gpu_bo, 2673 box, n); 2674 } 2675 2676 sna_damage_subtract(&priv->gpu_damage, r); 2677 RegionUninit(&need); 2678 } 2679 } 2680 if (r == &want) 2681 pixman_region_fini(&want); 2682 } 2683 } 2684 2685done: 2686 if ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == MOVE_WRITE) { 2687 DBG(("%s: applying cpu damage\n", __FUNCTION__)); 2688 assert(!DAMAGE_IS_ALL(priv->cpu_damage)); 2689 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 2690 sna_damage_add(&priv->cpu_damage, region); 2691 sna_damage_reduce_all(&priv->cpu_damage, 2692 pixmap->drawable.width, 2693 pixmap->drawable.height); 2694 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 2695 DBG(("%s: replaced entire pixmap\n", __FUNCTION__)); 2696 sna_pixmap_free_gpu(sna, priv); 2697 } 2698 if (priv->flush) { 2699 assert(!priv->shm); 2700 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 2701 } 2702 } 2703 2704 if (dx | dy) 2705 RegionTranslate(region, -dx, -dy); 2706 2707out: 2708 if (flags & MOVE_WRITE) { 2709 assert(!DAMAGE_IS_ALL(priv->gpu_damage)); 2710 priv->source_count = SOURCE_BIAS; 2711 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 2712 assert(priv->gpu_bo || priv->gpu_damage == NULL); 2713 assert(!priv->flush || !list_is_empty(&priv->flush_list)); 2714 assert(!priv->clear); 2715 } 2716 if ((flags & MOVE_ASYNC_HINT) == 0 && priv->cpu_bo) { 2717 DBG(("%s: syncing cpu bo\n", __FUNCTION__)); 2718 assert(IS_CPU_MAP(priv->cpu_bo->map)); 2719 kgem_bo_sync__cpu_full(&sna->kgem, priv->cpu_bo, 2720 FORCE_FULL_SYNC || flags & MOVE_WRITE); 2721 assert(pixmap->devPrivate.ptr == (void *)((unsigned long)priv->cpu_bo->map & ~3)); 2722 assert((flags & MOVE_WRITE) == 0 || !kgem_bo_is_busy(priv->cpu_bo)); 2723 } 2724 priv->cpu = 2725 (flags & (MOVE_INPLACE_HINT | MOVE_ASYNC_HINT)) == 0 && 2726 !DAMAGE_IS_ALL(priv->gpu_damage); 2727 assert(pixmap->devPrivate.ptr); 2728 assert(pixmap->devKind); 2729 assert_pixmap_damage(pixmap); 2730 assert(has_coherent_ptr(sna_pixmap(pixmap))); 2731 return true; 2732} 2733 2734bool 2735sna_drawable_move_to_cpu(DrawablePtr drawable, unsigned flags) 2736{ 2737 RegionRec region; 2738 PixmapPtr pixmap; 2739 int16_t dx, dy; 2740 2741 if (drawable->type == DRAWABLE_PIXMAP) 2742 return sna_pixmap_move_to_cpu((PixmapPtr)drawable, flags); 2743 2744 pixmap = get_window_pixmap((WindowPtr)drawable); 2745 get_drawable_deltas(drawable, pixmap, &dx, &dy); 2746 2747 DBG(("%s: (%d, %d)x(%d, %d) + (%d, %d), flags=%x\n", 2748 __FUNCTION__, 2749 drawable->x, drawable->y, 2750 drawable->width, drawable->height, 2751 dx, dy, flags)); 2752 2753 region.extents.x1 = drawable->x + dx; 2754 region.extents.y1 = drawable->y + dy; 2755 region.extents.x2 = region.extents.x1 + drawable->width; 2756 region.extents.y2 = region.extents.y1 + drawable->height; 2757 region.data = NULL; 2758 2759 if (region.extents.x1 < 0) 2760 region.extents.x1 = 0; 2761 if (region.extents.y1 < 0) 2762 region.extents.y1 = 0; 2763 if (region.extents.x2 > pixmap->drawable.width) 2764 region.extents.x2 = pixmap->drawable.width; 2765 if (region.extents.y2 > pixmap->drawable.height) 2766 region.extents.y2 = pixmap->drawable.height; 2767 2768 if (box_empty(®ion.extents)) 2769 return true; 2770 2771 return sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, flags); 2772} 2773 2774pure static bool alu_overwrites(uint8_t alu) 2775{ 2776 switch (alu) { 2777 case GXclear: 2778 case GXcopy: 2779 case GXcopyInverted: 2780 case GXset: 2781 return true; 2782 default: 2783 return false; 2784 } 2785} 2786 2787inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc) 2788{ 2789 if (!alu_overwrites(gc->alu)) 2790 return false; 2791 2792 if (!PM_IS_SOLID(draw, gc->planemask)) 2793 return false; 2794 2795 if (gc->fillStyle == FillStippled) 2796 return false; 2797 2798 return true; 2799} 2800 2801inline static unsigned 2802drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial) 2803{ 2804 assert(sna_gc(gc)->changes == 0); 2805 2806 if (gc->fillStyle == FillStippled) { 2807 DBG(("%s: read due to fill %d\n", 2808 __FUNCTION__, gc->fillStyle)); 2809 return MOVE_READ | MOVE_WRITE; 2810 } 2811 2812 if (fb_gc(gc)->and | fb_gc(gc)->bgand) { 2813 DBG(("%s: read due to rrop %d:%x\n", 2814 __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and)); 2815 return MOVE_READ | MOVE_WRITE; 2816 } 2817 2818 DBG(("%s: try operating on drawable inplace [hint? %d]\n", 2819 __FUNCTION__, drawable_gc_inplace_hint(draw, gc))); 2820 2821 return (partial ? MOVE_READ : 0) | MOVE_WRITE | MOVE_INPLACE_HINT; 2822} 2823 2824static inline struct sna_pixmap * 2825sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv) 2826{ 2827 assert(priv->gpu_bo); 2828 DBG(("%s: pixmap=%ld, handle=%u\n", __FUNCTION__, 2829 priv->pixmap->drawable.serialNumber, 2830 priv->gpu_bo->handle)); 2831 return priv; 2832} 2833 2834bool 2835sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags) 2836{ 2837 struct sna *sna = to_sna_from_pixmap(pixmap); 2838 struct sna_pixmap *priv = sna_pixmap(pixmap); 2839 RegionRec i, r; 2840 2841 DBG(("%s: pixmap=%ld box=(%d, %d), (%d, %d), flags=%x\n", 2842 __FUNCTION__, pixmap->drawable.serialNumber, 2843 box->x1, box->y1, box->x2, box->y2, flags)); 2844 2845 assert(box->x2 > box->x1 && box->y2 > box->y1); 2846 assert_pixmap_damage(pixmap); 2847 assert_pixmap_contains_box(pixmap, box); 2848 assert(!wedged(sna)); 2849 assert(priv->gpu_damage == NULL || priv->gpu_bo); 2850 2851 if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) { 2852 unsigned cow = MOVE_READ; 2853 2854 if ((flags & MOVE_READ) == 0) { 2855 if (priv->gpu_damage) { 2856 r.extents = *box; 2857 r.data = NULL; 2858 if (region_subsumes_damage(&r, 2859 priv->gpu_damage)) 2860 cow = 0; 2861 } else 2862 cow = 0; 2863 } 2864 2865 if (!sna_pixmap_undo_cow(sna, priv, cow)) 2866 return false; 2867 2868 if (priv->gpu_bo == NULL) 2869 sna_damage_destroy(&priv->gpu_damage); 2870 } 2871 2872 if (sna_damage_is_all(&priv->gpu_damage, 2873 pixmap->drawable.width, 2874 pixmap->drawable.height)) { 2875 assert(priv->gpu_bo); 2876 assert(priv->gpu_bo->proxy == NULL); 2877 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 2878 sna_damage_destroy(&priv->cpu_damage); 2879 list_del(&priv->flush_list); 2880 goto done; 2881 } 2882 2883 if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) { 2884 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 2885 assert(priv->gpu_damage == NULL); 2886 assert(!priv->pinned); 2887 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 2888 priv->gpu_bo = NULL; 2889 } 2890 2891 if ((flags & MOVE_READ) == 0) 2892 sna_damage_subtract_box(&priv->cpu_damage, box); 2893 2894 sna_damage_reduce(&priv->cpu_damage); 2895 assert_pixmap_damage(pixmap); 2896 2897 if (priv->cpu_damage == NULL) { 2898 list_del(&priv->flush_list); 2899 return sna_pixmap_move_to_gpu(pixmap, flags); 2900 } 2901 2902 if (priv->gpu_bo == NULL) { 2903 assert(priv->gpu_damage == NULL); 2904 2905 if (flags & __MOVE_FORCE || 2906 priv->create & KGEM_CAN_CREATE_GPU) { 2907 unsigned create, tiling; 2908 2909 create = CREATE_INACTIVE; 2910 if (pixmap->usage_hint == SNA_CREATE_FB) 2911 create |= CREATE_SCANOUT; 2912 2913 tiling = (flags & MOVE_SOURCE_HINT) ? I915_TILING_Y : DEFAULT_TILING; 2914 tiling = sna_pixmap_choose_tiling(pixmap, tiling); 2915 2916 priv->gpu_bo = kgem_create_2d(&sna->kgem, 2917 pixmap->drawable.width, 2918 pixmap->drawable.height, 2919 pixmap->drawable.bitsPerPixel, 2920 tiling, create); 2921 } 2922 2923 if (priv->gpu_bo == NULL) 2924 return false; 2925 2926 DBG(("%s: created gpu bo\n", __FUNCTION__)); 2927 } 2928 2929 if (priv->gpu_bo->proxy) { 2930 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 2931 assert((flags & MOVE_WRITE) == 0); 2932 assert(priv->gpu_damage == NULL); 2933 return priv; 2934 } 2935 2936 if (priv->shm) { 2937 assert(!priv->flush); 2938 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 2939 } 2940 2941 assert(priv->cpu_damage); 2942 region_set(&r, box); 2943 if (MIGRATE_ALL || region_subsumes_damage(&r, priv->cpu_damage)) { 2944 int n; 2945 2946 n = sna_damage_get_boxes(priv->cpu_damage, (BoxPtr *)&box); 2947 if (n) { 2948 bool ok = false; 2949 2950 if (use_cpu_bo_for_upload(sna, priv, 0)) { 2951 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 2952 ok = sna->render.copy_boxes(sna, GXcopy, 2953 pixmap, priv->cpu_bo, 0, 0, 2954 pixmap, priv->gpu_bo, 0, 0, 2955 box, n, 0); 2956 } 2957 if (!ok) { 2958 if (priv->mapped || pixmap->devPrivate.ptr == NULL) { 2959 assert(priv->ptr && priv->stride); 2960 pixmap->devPrivate.ptr = PTR(priv->ptr); 2961 pixmap->devKind = priv->stride; 2962 priv->mapped = false; 2963 } 2964 if (n == 1 && !priv->pinned && 2965 box->x1 <= 0 && box->y1 <= 0 && 2966 box->x2 >= pixmap->drawable.width && 2967 box->y2 >= pixmap->drawable.height) { 2968 ok = sna_replace(sna, pixmap, 2969 &priv->gpu_bo, 2970 pixmap->devPrivate.ptr, 2971 pixmap->devKind); 2972 } else { 2973 ok = sna_write_boxes(sna, pixmap, 2974 priv->gpu_bo, 0, 0, 2975 pixmap->devPrivate.ptr, 2976 pixmap->devKind, 2977 0, 0, 2978 box, n); 2979 } 2980 if (!ok) 2981 return false; 2982 } 2983 } 2984 2985 sna_damage_destroy(&priv->cpu_damage); 2986 } else if (DAMAGE_IS_ALL(priv->cpu_damage) || 2987 sna_damage_contains_box__no_reduce(priv->cpu_damage, box)) { 2988 bool ok = false; 2989 2990 assert(sna_damage_contains_box(priv->gpu_damage, box) == PIXMAN_REGION_OUT); 2991 assert(sna_damage_contains_box(priv->cpu_damage, box) == PIXMAN_REGION_IN); 2992 2993 if (use_cpu_bo_for_upload(sna, priv, 0)) { 2994 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 2995 ok = sna->render.copy_boxes(sna, GXcopy, 2996 pixmap, priv->cpu_bo, 0, 0, 2997 pixmap, priv->gpu_bo, 0, 0, 2998 box, 1, 0); 2999 } 3000 if (!ok) { 3001 if (priv->mapped || pixmap->devPrivate.ptr == NULL) { 3002 assert(priv->ptr && priv->stride); 3003 pixmap->devPrivate.ptr = PTR(priv->ptr); 3004 pixmap->devKind = priv->stride; 3005 priv->mapped = false; 3006 } 3007 ok = sna_write_boxes(sna, pixmap, 3008 priv->gpu_bo, 0, 0, 3009 pixmap->devPrivate.ptr, 3010 pixmap->devKind, 3011 0, 0, 3012 box, 1); 3013 } 3014 if (!ok) 3015 return false; 3016 3017 sna_damage_subtract(&priv->cpu_damage, &r); 3018 } else if (sna_damage_intersect(priv->cpu_damage, &r, &i)) { 3019 int n = RegionNumRects(&i); 3020 bool ok; 3021 3022 box = RegionRects(&i); 3023 ok = false; 3024 if (use_cpu_bo_for_upload(sna, priv, 0)) { 3025 DBG(("%s: using CPU bo for upload to GPU, %d boxes\n", __FUNCTION__, n)); 3026 ok = sna->render.copy_boxes(sna, GXcopy, 3027 pixmap, priv->cpu_bo, 0, 0, 3028 pixmap, priv->gpu_bo, 0, 0, 3029 box, n, 0); 3030 } 3031 if (!ok) { 3032 if (priv->mapped || pixmap->devPrivate.ptr == NULL) { 3033 assert(priv->ptr && priv->stride); 3034 pixmap->devPrivate.ptr = PTR(priv->ptr); 3035 pixmap->devKind = priv->stride; 3036 priv->mapped = false; 3037 } 3038 ok = sna_write_boxes(sna, pixmap, 3039 priv->gpu_bo, 0, 0, 3040 pixmap->devPrivate.ptr, 3041 pixmap->devKind, 3042 0, 0, 3043 box, n); 3044 } 3045 if (!ok) 3046 return false; 3047 3048 sna_damage_subtract(&priv->cpu_damage, &r); 3049 RegionUninit(&i); 3050 } 3051 3052done: 3053 if (priv->cpu_damage == NULL && priv->flush) 3054 list_del(&priv->flush_list); 3055 if (flags & MOVE_WRITE) { 3056 priv->clear = false; 3057 priv->cpu = false; 3058 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 3059 priv->cpu_damage == NULL && 3060 box_inplace(pixmap, &r.extents)) { 3061 DBG(("%s: large operation on undamaged, promoting to full GPU\n", 3062 __FUNCTION__)); 3063 assert(priv->gpu_bo); 3064 assert(priv->gpu_bo->proxy == NULL); 3065 sna_damage_all(&priv->gpu_damage, 3066 pixmap->drawable.width, 3067 pixmap->drawable.height); 3068 } 3069 if (DAMAGE_IS_ALL(priv->gpu_damage)) 3070 sna_pixmap_free_cpu(sna, priv); 3071 } 3072 3073 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3074 return sna_pixmap_mark_active(sna, priv) != NULL; 3075} 3076 3077struct kgem_bo * 3078sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box, 3079 struct sna_damage ***damage) 3080{ 3081 PixmapPtr pixmap = get_drawable_pixmap(drawable); 3082 struct sna_pixmap *priv = sna_pixmap(pixmap); 3083 struct sna *sna; 3084 RegionRec region; 3085 int16_t dx, dy; 3086 int ret; 3087 3088 DBG(("%s pixmap=%ld, box=((%d, %d), (%d, %d)), flags=%x...\n", 3089 __FUNCTION__, 3090 pixmap->drawable.serialNumber, 3091 box->x1, box->y1, box->x2, box->y2, 3092 flags)); 3093 3094 assert(box->x2 > box->x1 && box->y2 > box->y1); 3095 assert(pixmap->refcnt); 3096 assert_pixmap_damage(pixmap); 3097 assert_drawable_contains_box(drawable, box); 3098 3099 if (priv == NULL) { 3100 DBG(("%s: not attached\n", __FUNCTION__)); 3101 return NULL; 3102 } 3103 3104 if (priv->cow) { 3105 unsigned cow = MOVE_READ; 3106 3107 if (flags & IGNORE_CPU) { 3108 if (priv->gpu_damage) { 3109 region.extents = *box; 3110 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3111 region.extents.x1 += dx; 3112 region.extents.x2 += dx; 3113 region.extents.y1 += dy; 3114 region.extents.y2 += dy; 3115 } 3116 region.data = NULL; 3117 if (region_subsumes_damage(®ion, 3118 priv->gpu_damage)) 3119 cow = 0; 3120 } else 3121 cow = 0; 3122 } 3123 3124 if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow)) 3125 return NULL; 3126 3127 if (priv->gpu_bo == NULL) 3128 sna_damage_destroy(&priv->gpu_damage); 3129 } 3130 3131 if (priv->gpu_bo && priv->gpu_bo->proxy) { 3132 DBG(("%s: cached upload proxy, discard and revert to GPU\n", 3133 __FUNCTION__)); 3134 assert(priv->gpu_damage == NULL); 3135 assert(!priv->pinned); 3136 kgem_bo_destroy(&to_sna_from_pixmap(pixmap)->kgem, 3137 priv->gpu_bo); 3138 priv->gpu_bo = NULL; 3139 goto use_cpu_bo; 3140 } 3141 3142 if (priv->flush) 3143 flags |= PREFER_GPU; 3144 if (priv->shm) 3145 flags &= ~PREFER_GPU; 3146 if (priv->cpu && (flags & (FORCE_GPU | IGNORE_CPU)) == 0) 3147 flags &= ~PREFER_GPU; 3148 3149 DBG(("%s: flush=%d, shm=%d, cpu=%d => flags=%x\n", 3150 __FUNCTION__, priv->flush, priv->shm, priv->cpu, flags)); 3151 3152 if ((flags & PREFER_GPU) == 0 && 3153 (flags & REPLACES || !priv->gpu_damage || !kgem_bo_is_busy(priv->gpu_bo))) { 3154 DBG(("%s: try cpu as GPU bo is idle\n", __FUNCTION__)); 3155 goto use_cpu_bo; 3156 } 3157 3158 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 3159 DBG(("%s: use GPU fast path (all-damaged)\n", __FUNCTION__)); 3160 assert(priv->cpu_damage == NULL); 3161 assert(priv->gpu_bo); 3162 assert(priv->gpu_bo->proxy == NULL); 3163 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 3164 goto use_gpu_bo; 3165 } 3166 3167 if (DAMAGE_IS_ALL(priv->cpu_damage)) { 3168 assert(priv->gpu_damage == NULL); 3169 if ((flags & FORCE_GPU) == 0 || priv->cpu_bo) { 3170 DBG(("%s: use CPU fast path (all-damaged), and not forced-gpu\n", 3171 __FUNCTION__)); 3172 goto use_cpu_bo; 3173 } 3174 } 3175 3176 DBG(("%s: gpu? %d, damaged? %d; cpu? %d, damaged? %d\n", __FUNCTION__, 3177 priv->gpu_bo ? priv->gpu_bo->handle : 0, priv->gpu_damage != NULL, 3178 priv->cpu_bo ? priv->cpu_bo->handle : 0, priv->cpu_damage != NULL)); 3179 if (priv->gpu_bo == NULL) { 3180 unsigned int move; 3181 3182 if ((flags & FORCE_GPU) == 0 && 3183 (priv->create & KGEM_CAN_CREATE_GPU) == 0) { 3184 DBG(("%s: untiled, will not force allocation\n", 3185 __FUNCTION__)); 3186 goto use_cpu_bo; 3187 } 3188 3189 if ((flags & IGNORE_CPU) == 0) { 3190 if (priv->cpu_bo) { 3191 if (to_sna_from_pixmap(pixmap)->kgem.can_blt_cpu) { 3192 if (kgem_bo_is_busy(priv->cpu_bo)) { 3193 DBG(("%s: already using CPU bo, will not force allocation\n", 3194 __FUNCTION__)); 3195 goto use_cpu_bo; 3196 } 3197 3198 if ((flags & RENDER_GPU) == 0) { 3199 DBG(("%s: prefer cpu", __FUNCTION__)); 3200 goto use_cpu_bo; 3201 } 3202 } else { 3203 if (kgem_bo_is_busy(priv->cpu_bo)) { 3204 DBG(("%s: CPU bo active, must force allocation\n", 3205 __FUNCTION__)); 3206 goto create_gpu_bo; 3207 } 3208 } 3209 } 3210 3211 if ((flags & FORCE_GPU) == 0 && priv->cpu_damage) { 3212 if ((flags & PREFER_GPU) == 0) { 3213 DBG(("%s: already damaged and prefer cpu", 3214 __FUNCTION__)); 3215 goto use_cpu_bo; 3216 } 3217 3218 if (!box_inplace(pixmap, box)) { 3219 DBG(("%s: damaged with a small operation, will not force allocation\n", 3220 __FUNCTION__)); 3221 goto use_cpu_bo; 3222 } 3223 } 3224 } else if (priv->cpu_damage) { 3225 region.extents = *box; 3226 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3227 region.extents.x1 += dx; 3228 region.extents.x2 += dx; 3229 region.extents.y1 += dy; 3230 region.extents.y2 += dy; 3231 } 3232 region.data = NULL; 3233 3234 sna_damage_subtract(&priv->cpu_damage, ®ion); 3235 if (priv->cpu_damage == NULL) { 3236 list_del(&priv->flush_list); 3237 priv->cpu = false; 3238 } 3239 } 3240 3241create_gpu_bo: 3242 move = MOVE_WRITE | MOVE_READ; 3243 if (flags & FORCE_GPU) 3244 move |= __MOVE_FORCE; 3245 if (!sna_pixmap_move_to_gpu(pixmap, move)) 3246 goto use_cpu_bo; 3247 3248 DBG(("%s: allocated GPU bo for operation\n", __FUNCTION__)); 3249 goto done; 3250 } 3251 3252 3253 region.extents = *box; 3254 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3255 region.extents.x1 += dx; 3256 region.extents.x2 += dx; 3257 region.extents.y1 += dy; 3258 region.extents.y2 += dy; 3259 } 3260 region.data = NULL; 3261 3262 DBG(("%s extents (%d, %d), (%d, %d)\n", __FUNCTION__, 3263 region.extents.x1, region.extents.y1, 3264 region.extents.x2, region.extents.y2)); 3265 3266 if (priv->gpu_damage) { 3267 assert(priv->gpu_bo); 3268 if (!priv->cpu_damage) { 3269 if (sna_damage_contains_box__no_reduce(priv->gpu_damage, 3270 ®ion.extents)) { 3271 DBG(("%s: region wholly contained within GPU damage\n", 3272 __FUNCTION__)); 3273 assert(sna_damage_contains_box(priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3274 assert(sna_damage_contains_box(priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3275 goto use_gpu_bo; 3276 } else { 3277 DBG(("%s: partial GPU damage with no CPU damage, continuing to use GPU\n", 3278 __FUNCTION__)); 3279 priv->cpu = false; 3280 goto done; 3281 } 3282 } 3283 3284 ret = sna_damage_contains_box(priv->gpu_damage, ®ion.extents); 3285 if (ret == PIXMAN_REGION_IN) { 3286 DBG(("%s: region wholly contained within GPU damage\n", 3287 __FUNCTION__)); 3288 goto use_gpu_bo; 3289 } 3290 3291 if (ret != PIXMAN_REGION_OUT) { 3292 DBG(("%s: region partially contained within GPU damage\n", 3293 __FUNCTION__)); 3294 goto move_to_gpu; 3295 } 3296 } 3297 3298 if ((flags & IGNORE_CPU) == 0 && priv->cpu_damage) { 3299 ret = sna_damage_contains_box(priv->cpu_damage, ®ion.extents); 3300 if (ret == PIXMAN_REGION_IN) { 3301 DBG(("%s: region wholly contained within CPU damage\n", 3302 __FUNCTION__)); 3303 goto use_cpu_bo; 3304 } 3305 3306 if (box_inplace(pixmap, box)) { 3307 DBG(("%s: forcing inplace\n", __FUNCTION__)); 3308 goto move_to_gpu; 3309 } 3310 3311 if (ret != PIXMAN_REGION_OUT) { 3312 DBG(("%s: region partially contained within CPU damage\n", 3313 __FUNCTION__)); 3314 goto use_cpu_bo; 3315 } 3316 } 3317 3318move_to_gpu: 3319 if (!sna_pixmap_move_area_to_gpu(pixmap, ®ion.extents, 3320 flags & IGNORE_CPU ? MOVE_WRITE : MOVE_READ | MOVE_WRITE)) { 3321 DBG(("%s: failed to move-to-gpu, fallback\n", __FUNCTION__)); 3322 assert(priv->gpu_bo == NULL); 3323 goto use_cpu_bo; 3324 } 3325 3326done: 3327 assert(priv->gpu_bo != NULL); 3328 assert(priv->gpu_bo->refcnt); 3329 if (sna_damage_is_all(&priv->gpu_damage, 3330 pixmap->drawable.width, 3331 pixmap->drawable.height)) { 3332 sna_damage_destroy(&priv->cpu_damage); 3333 list_del(&priv->flush_list); 3334 *damage = NULL; 3335 } else 3336 *damage = &priv->gpu_damage; 3337 3338 DBG(("%s: using GPU bo with damage? %d\n", 3339 __FUNCTION__, *damage != NULL)); 3340 assert(*damage == NULL || !DAMAGE_IS_ALL(*damage)); 3341 assert(priv->gpu_bo->proxy == NULL); 3342 assert(priv->clear == false); 3343 assert(priv->cpu == false); 3344 return priv->gpu_bo; 3345 3346use_gpu_bo: 3347 DBG(("%s: using whole GPU bo\n", __FUNCTION__)); 3348 assert(priv->gpu_bo != NULL); 3349 assert(priv->gpu_bo->refcnt); 3350 assert(priv->gpu_bo->proxy == NULL); 3351 assert(priv->gpu_damage); 3352 priv->clear = false; 3353 priv->cpu = false; 3354 *damage = NULL; 3355 return priv->gpu_bo; 3356 3357use_cpu_bo: 3358 if (!USE_CPU_BO || priv->cpu_bo == NULL) { 3359cpu_fail: 3360 if ((flags & FORCE_GPU) && priv->gpu_bo) { 3361 region.extents = *box; 3362 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3363 region.extents.x1 += dx; 3364 region.extents.x2 += dx; 3365 region.extents.y1 += dy; 3366 region.extents.y2 += dy; 3367 } 3368 region.data = NULL; 3369 3370 goto move_to_gpu; 3371 } 3372 3373 return NULL; 3374 } 3375 3376 assert(priv->cpu_bo->refcnt); 3377 3378 sna = to_sna_from_pixmap(pixmap); 3379 if ((flags & FORCE_GPU) == 0 && 3380 !__kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 3381 DBG(("%s: has CPU bo, but is idle and acceleration not forced\n", 3382 __FUNCTION__)); 3383 return NULL; 3384 } 3385 3386 3387 region.extents = *box; 3388 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 3389 region.extents.x1 += dx; 3390 region.extents.x2 += dx; 3391 region.extents.y1 += dy; 3392 region.extents.y2 += dy; 3393 } 3394 region.data = NULL; 3395 3396 /* Both CPU and GPU are busy, prefer to use the GPU */ 3397 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) 3398 goto move_to_gpu; 3399 3400 assert(priv->gpu_bo == NULL || priv->gpu_bo->proxy == NULL); 3401 3402 if (flags & RENDER_GPU) { 3403 if (priv->gpu_bo && priv->gpu_bo->tiling) 3404 goto move_to_gpu; 3405 3406 if (priv->cpu_bo->pitch >= 4096) 3407 goto move_to_gpu; 3408 3409 if (!sna->kgem.can_blt_cpu) 3410 goto move_to_gpu; 3411 } 3412 3413 if (!sna->kgem.can_blt_cpu) 3414 goto cpu_fail; 3415 3416 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, ®ion, 3417 (flags & IGNORE_CPU ? MOVE_READ : 0) | MOVE_WRITE | MOVE_ASYNC_HINT)) { 3418 DBG(("%s: failed to move-to-cpu, fallback\n", __FUNCTION__)); 3419 goto cpu_fail; 3420 } 3421 3422 if (priv->shm) { 3423 assert(!priv->flush); 3424 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3425 3426 /* As we may have flushed and retired,, recheck for busy bo */ 3427 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo)) 3428 return NULL; 3429 } 3430 if (priv->flush) { 3431 assert(!priv->shm); 3432 sna_add_flush_pixmap(sna, priv, priv->gpu_bo); 3433 } 3434 3435 if (sna_damage_is_all(&priv->cpu_damage, 3436 pixmap->drawable.width, 3437 pixmap->drawable.height)) { 3438 sna_damage_destroy(&priv->gpu_damage); 3439 *damage = NULL; 3440 } else { 3441 if (priv->cpu_damage && 3442 sna_damage_contains_box__no_reduce(priv->cpu_damage, 3443 ®ion.extents)) { 3444 assert(sna_damage_contains_box(priv->gpu_damage, ®ion.extents) == PIXMAN_REGION_OUT); 3445 assert(sna_damage_contains_box(priv->cpu_damage, ®ion.extents) == PIXMAN_REGION_IN); 3446 *damage = NULL; 3447 } else 3448 *damage = &priv->cpu_damage; 3449 } 3450 3451 DBG(("%s: using CPU bo with damage? %d\n", 3452 __FUNCTION__, *damage != NULL)); 3453 assert(damage == NULL || !DAMAGE_IS_ALL(*damage)); 3454 assert(priv->clear == false); 3455 return priv->cpu_bo; 3456} 3457 3458PixmapPtr 3459sna_pixmap_create_upload(ScreenPtr screen, 3460 int width, int height, int depth, 3461 unsigned flags) 3462{ 3463 struct sna *sna = to_sna_from_screen(screen); 3464 PixmapPtr pixmap; 3465 struct sna_pixmap *priv; 3466 void *ptr; 3467 3468 DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__, 3469 width, height, depth, flags)); 3470 assert(width); 3471 assert(height); 3472 3473 if (depth == 1) 3474 return create_pixmap(sna, screen, width, height, depth, 3475 CREATE_PIXMAP_USAGE_SCRATCH); 3476 3477 if (sna->freed_pixmap) { 3478 pixmap = sna->freed_pixmap; 3479 sna->freed_pixmap = pixmap->devPrivate.ptr; 3480 3481 pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 3482 pixmap->refcnt = 1; 3483 } else { 3484 pixmap = create_pixmap(sna, screen, 0, 0, depth, 0); 3485 if (!pixmap) 3486 return NullPixmap; 3487 3488 priv = malloc(sizeof(*priv)); 3489 if (!priv) { 3490 FreePixmap(pixmap); 3491 return NullPixmap; 3492 } 3493 3494 sna_set_pixmap(pixmap, priv); 3495 } 3496 3497 pixmap->drawable.width = width; 3498 pixmap->drawable.height = height; 3499 pixmap->drawable.depth = depth; 3500 pixmap->drawable.bitsPerPixel = bits_per_pixel(depth); 3501 3502 priv = _sna_pixmap_reset(pixmap); 3503 priv->header = true; 3504 3505 priv->gpu_bo = kgem_create_buffer_2d(&sna->kgem, 3506 width, height, 3507 pixmap->drawable.bitsPerPixel, 3508 flags, &ptr); 3509 if (!priv->gpu_bo) { 3510 free(priv); 3511 FreePixmap(pixmap); 3512 return NullPixmap; 3513 } 3514 priv->mapped = true; 3515 3516 /* Marking both the shadow and the GPU bo is a little dubious, 3517 * but will work so long as we always check before doing the 3518 * transfer. 3519 */ 3520 sna_damage_all(&priv->gpu_damage, width, height); 3521 sna_damage_all(&priv->cpu_damage, width, height); 3522 3523 pixmap->devKind = priv->gpu_bo->pitch; 3524 pixmap->devPrivate.ptr = ptr; 3525 3526 pixmap->usage_hint = 0; 3527 if (!kgem_buffer_is_inplace(priv->gpu_bo)) 3528 pixmap->usage_hint = 1; 3529 3530 DBG(("%s: serial=%ld, usage=%d\n", 3531 __FUNCTION__, 3532 pixmap->drawable.serialNumber, 3533 pixmap->usage_hint)); 3534 3535 return pixmap; 3536} 3537 3538struct sna_pixmap * 3539sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags) 3540{ 3541 struct sna *sna = to_sna_from_pixmap(pixmap); 3542 struct sna_pixmap *priv; 3543 BoxPtr box; 3544 int n; 3545 3546 DBG(("%s(pixmap=%ld, usage=%d), flags=%x\n", 3547 __FUNCTION__, 3548 pixmap->drawable.serialNumber, 3549 pixmap->usage_hint, 3550 flags)); 3551 3552 if ((flags & __MOVE_FORCE) == 0 && wedged(sna)) 3553 return NULL; 3554 3555 priv = sna_pixmap(pixmap); 3556 if (priv == NULL) { 3557 DBG(("%s: not attached\n", __FUNCTION__)); 3558 if ((flags & __MOVE_DRI) == 0) 3559 return NULL; 3560 3561 DBG(("%s: forcing the creation on the GPU\n", __FUNCTION__)); 3562 3563 priv = sna_pixmap_attach(pixmap); 3564 if (priv == NULL) 3565 return NULL; 3566 3567 sna_damage_all(&priv->cpu_damage, 3568 pixmap->drawable.width, 3569 pixmap->drawable.height); 3570 3571 assert(priv->gpu_bo == NULL); 3572 assert(priv->gpu_damage == NULL); 3573 } 3574 3575 assert(priv->gpu_damage == NULL || priv->gpu_bo); 3576 3577 if ((flags & MOVE_READ) == 0 && UNDO) { 3578 if (priv->gpu_bo) 3579 kgem_bo_undo(&sna->kgem, priv->gpu_bo); 3580 if (priv->cpu_bo) 3581 kgem_bo_undo(&sna->kgem, priv->cpu_bo); 3582 } 3583 3584 if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) { 3585 if (!sna_pixmap_undo_cow(sna, priv, flags & MOVE_READ)) 3586 return false; 3587 3588 if (priv->gpu_bo == NULL) 3589 sna_damage_destroy(&priv->gpu_damage); 3590 } 3591 3592 if (sna_damage_is_all(&priv->gpu_damage, 3593 pixmap->drawable.width, 3594 pixmap->drawable.height)) { 3595 DBG(("%s: already all-damaged\n", __FUNCTION__)); 3596 assert(priv->gpu_bo); 3597 assert(priv->gpu_bo->proxy == NULL); 3598 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 3599 sna_damage_destroy(&priv->cpu_damage); 3600 list_del(&priv->flush_list); 3601 goto active; 3602 } 3603 3604 if (flags & MOVE_WRITE && priv->gpu_bo && priv->gpu_bo->proxy) { 3605 DBG(("%s: discarding cached upload buffer\n", __FUNCTION__)); 3606 assert(priv->gpu_damage == NULL); 3607 assert(!priv->pinned); 3608 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 3609 priv->gpu_bo = NULL; 3610 } 3611 3612 if ((flags & MOVE_READ) == 0) 3613 sna_damage_destroy(&priv->cpu_damage); 3614 3615 sna_damage_reduce(&priv->cpu_damage); 3616 assert_pixmap_damage(pixmap); 3617 DBG(("%s: CPU damage? %d\n", __FUNCTION__, priv->cpu_damage != NULL)); 3618 if (priv->gpu_bo == NULL) { 3619 DBG(("%s: creating GPU bo (%dx%d@%d), create=%x\n", 3620 __FUNCTION__, 3621 pixmap->drawable.width, 3622 pixmap->drawable.height, 3623 pixmap->drawable.bitsPerPixel, 3624 priv->create)); 3625 assert(!priv->mapped); 3626 if (flags & __MOVE_FORCE || priv->create & KGEM_CAN_CREATE_GPU) { 3627 unsigned create, tiling; 3628 3629 assert(pixmap->drawable.width > 0); 3630 assert(pixmap->drawable.height > 0); 3631 assert(pixmap->drawable.bitsPerPixel >= 8); 3632 3633 tiling = (flags & MOVE_SOURCE_HINT) ? I915_TILING_Y : DEFAULT_TILING; 3634 tiling = sna_pixmap_choose_tiling(pixmap, tiling); 3635 3636 create = 0; 3637 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL)) 3638 create = CREATE_GTT_MAP | CREATE_INACTIVE; 3639 if (pixmap->usage_hint == SNA_CREATE_FB) 3640 create |= CREATE_SCANOUT; 3641 3642 priv->gpu_bo = 3643 kgem_create_2d(&sna->kgem, 3644 pixmap->drawable.width, 3645 pixmap->drawable.height, 3646 pixmap->drawable.bitsPerPixel, 3647 tiling, create); 3648 } 3649 if (priv->gpu_bo == NULL) { 3650 DBG(("%s: not creating GPU bo\n", __FUNCTION__)); 3651 assert(priv->gpu_damage == NULL); 3652 return NULL; 3653 } 3654 3655 if (flags & MOVE_WRITE && priv->cpu_damage == NULL) { 3656 /* Presume that we will only ever write to the GPU 3657 * bo. Readbacks are expensive but fairly constant 3658 * in cost for all sizes i.e. it is the act of 3659 * synchronisation that takes the most time. This is 3660 * mitigated by avoiding fallbacks in the first place. 3661 */ 3662 assert(priv->gpu_bo); 3663 assert(priv->gpu_bo->proxy == NULL); 3664 sna_damage_all(&priv->gpu_damage, 3665 pixmap->drawable.width, 3666 pixmap->drawable.height); 3667 DBG(("%s: marking as all-damaged for GPU\n", 3668 __FUNCTION__)); 3669 goto active; 3670 } 3671 } 3672 3673 if (priv->gpu_bo->proxy) { 3674 DBG(("%s: reusing cached upload\n", __FUNCTION__)); 3675 assert((flags & MOVE_WRITE) == 0); 3676 assert(priv->gpu_damage == NULL); 3677 return priv; 3678 } 3679 3680 if (priv->cpu_damage == NULL) 3681 goto done; 3682 3683 if (priv->shm) { 3684 assert(!priv->flush); 3685 sna_add_flush_pixmap(sna, priv, priv->cpu_bo); 3686 } 3687 3688 n = sna_damage_get_boxes(priv->cpu_damage, &box); 3689 if (n) { 3690 bool ok; 3691 3692 assert(pixmap_contains_damage(pixmap, priv->cpu_damage)); 3693 DBG(("%s: uploading %d damage boxes\n", __FUNCTION__, n)); 3694 3695 ok = false; 3696 if (use_cpu_bo_for_upload(sna, priv, flags)) { 3697 DBG(("%s: using CPU bo for upload to GPU\n", __FUNCTION__)); 3698 ok = sna->render.copy_boxes(sna, GXcopy, 3699 pixmap, priv->cpu_bo, 0, 0, 3700 pixmap, priv->gpu_bo, 0, 0, 3701 box, n, 0); 3702 } 3703 if (!ok) { 3704 if (priv->mapped) { 3705 assert(priv->stride && priv->stride); 3706 pixmap->devPrivate.ptr = PTR(priv->ptr); 3707 pixmap->devKind = priv->stride; 3708 priv->mapped = false; 3709 } 3710 if (pixmap->devPrivate.ptr == NULL) { 3711 assert(priv->ptr && priv->stride); 3712 pixmap->devPrivate.ptr = PTR(priv->ptr); 3713 pixmap->devKind = priv->stride; 3714 } 3715 if (n == 1 && !priv->pinned && 3716 (box->x2 - box->x1) >= pixmap->drawable.width && 3717 (box->y2 - box->y1) >= pixmap->drawable.height) { 3718 ok = sna_replace(sna, pixmap, 3719 &priv->gpu_bo, 3720 pixmap->devPrivate.ptr, 3721 pixmap->devKind); 3722 } else { 3723 ok = sna_write_boxes(sna, pixmap, 3724 priv->gpu_bo, 0, 0, 3725 pixmap->devPrivate.ptr, 3726 pixmap->devKind, 3727 0, 0, 3728 box, n); 3729 } 3730 if (!ok) 3731 return NULL; 3732 } 3733 } 3734 3735 __sna_damage_destroy(DAMAGE_PTR(priv->cpu_damage)); 3736 priv->cpu_damage = NULL; 3737 3738 /* For large bo, try to keep only a single copy around */ 3739 if (priv->create & KGEM_CAN_CREATE_LARGE || flags & MOVE_SOURCE_HINT) { 3740 DBG(("%s: disposing of system copy for large/source\n", 3741 __FUNCTION__)); 3742 assert(!priv->shm); 3743 assert(priv->gpu_bo); 3744 assert(priv->gpu_bo->proxy == NULL); 3745 sna_damage_all(&priv->gpu_damage, 3746 pixmap->drawable.width, 3747 pixmap->drawable.height); 3748 sna_pixmap_free_cpu(sna, priv); 3749 } 3750done: 3751 list_del(&priv->flush_list); 3752 3753 sna_damage_reduce_all(&priv->gpu_damage, 3754 pixmap->drawable.width, 3755 pixmap->drawable.height); 3756 if (DAMAGE_IS_ALL(priv->gpu_damage)) 3757 sna_pixmap_free_cpu(sna, priv); 3758 3759active: 3760 if (flags & MOVE_WRITE) 3761 priv->clear = false; 3762 priv->cpu = false; 3763 assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0); 3764 return sna_pixmap_mark_active(sna, priv); 3765} 3766 3767static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap) 3768{ 3769 if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel && 3770 FbEvenTile(pixmap->drawable.width * 3771 pixmap->drawable.bitsPerPixel)) { 3772 DBG(("%s: flushing pixmap\n", __FUNCTION__)); 3773 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 3774 return false; 3775 3776 fbPadPixmap(pixmap); 3777 } 3778 3779 return true; 3780} 3781 3782static bool must_check sna_gc_move_to_cpu(GCPtr gc, 3783 DrawablePtr drawable, 3784 RegionPtr region) 3785{ 3786 struct sna_gc *sgc = sna_gc(gc); 3787 long changes = sgc->changes; 3788 3789 DBG(("%s, changes=%lx\n", __FUNCTION__, changes)); 3790 3791 assert(gc->ops == (GCOps *)&sna_gc_ops); 3792 gc->ops = (GCOps *)&sna_gc_ops__cpu; 3793 3794 sgc->old_funcs = gc->funcs; 3795 gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu; 3796 3797 sgc->priv = gc->pCompositeClip; 3798 gc->pCompositeClip = region; 3799 3800 if (gc->clientClipType == CT_PIXMAP) { 3801 PixmapPtr clip = gc->clientClip; 3802 gc->clientClip = region_from_bitmap(gc->pScreen, clip); 3803 gc->pScreen->DestroyPixmap(clip); 3804 gc->clientClipType = gc->clientClip ? CT_REGION : CT_NONE; 3805 changes |= GCClipMask; 3806 } else 3807 changes &= ~GCClipMask; 3808 3809 if (changes || drawable->serialNumber != sgc->serial) { 3810 gc->serialNumber = sgc->serial; 3811 3812 if (fb_gc(gc)->bpp != drawable->bitsPerPixel) { 3813 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask; 3814 fb_gc(gc)->bpp = drawable->bitsPerPixel; 3815 } 3816 3817 if (changes & GCTile && !gc->tileIsPixel) { 3818 DBG(("%s: flushing tile pixmap\n", __FUNCTION__)); 3819 if (!sna_validate_pixmap(drawable, gc->tile.pixmap)) 3820 return false; 3821 } 3822 3823 if (changes & GCStipple && gc->stipple) { 3824 DBG(("%s: flushing stipple pixmap\n", __FUNCTION__)); 3825 if (!sna_validate_pixmap(drawable, gc->stipple)) 3826 return false; 3827 } 3828 3829 fbValidateGC(gc, changes, drawable); 3830 3831 gc->serialNumber = drawable->serialNumber; 3832 sgc->serial = drawable->serialNumber; 3833 } 3834 sgc->changes = 0; 3835 3836 switch (gc->fillStyle) { 3837 case FillTiled: 3838 return sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, MOVE_READ); 3839 case FillStippled: 3840 case FillOpaqueStippled: 3841 return sna_drawable_move_to_cpu(&gc->stipple->drawable, MOVE_READ); 3842 default: 3843 return true; 3844 } 3845} 3846 3847static void sna_gc_move_to_gpu(GCPtr gc) 3848{ 3849 assert(gc->ops == (GCOps *)&sna_gc_ops__cpu); 3850 assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu); 3851 3852 gc->ops = (GCOps *)&sna_gc_ops; 3853 gc->funcs = sna_gc(gc)->old_funcs; 3854 gc->pCompositeClip = sna_gc(gc)->priv; 3855} 3856 3857static inline bool clip_box(BoxPtr box, GCPtr gc) 3858{ 3859 const BoxRec *clip; 3860 bool clipped; 3861 3862 clip = &gc->pCompositeClip->extents; 3863 3864 clipped = !region_is_singular(gc->pCompositeClip); 3865 if (box->x1 < clip->x1) 3866 box->x1 = clip->x1, clipped = true; 3867 if (box->x2 > clip->x2) 3868 box->x2 = clip->x2, clipped = true; 3869 3870 if (box->y1 < clip->y1) 3871 box->y1 = clip->y1, clipped = true; 3872 if (box->y2 > clip->y2) 3873 box->y2 = clip->y2, clipped = true; 3874 3875 return clipped; 3876} 3877 3878static inline void translate_box(BoxPtr box, DrawablePtr d) 3879{ 3880 box->x1 += d->x; 3881 box->x2 += d->x; 3882 3883 box->y1 += d->y; 3884 box->y2 += d->y; 3885} 3886 3887static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc) 3888{ 3889 translate_box(box, d); 3890 return clip_box(box, gc); 3891} 3892 3893static inline bool box32_clip(Box32Rec *box, GCPtr gc) 3894{ 3895 bool clipped = !region_is_singular(gc->pCompositeClip); 3896 const BoxRec *clip = &gc->pCompositeClip->extents; 3897 3898 if (box->x1 < clip->x1) 3899 box->x1 = clip->x1, clipped = true; 3900 if (box->x2 > clip->x2) 3901 box->x2 = clip->x2, clipped = true; 3902 3903 if (box->y1 < clip->y1) 3904 box->y1 = clip->y1, clipped = true; 3905 if (box->y2 > clip->y2) 3906 box->y2 = clip->y2, clipped = true; 3907 3908 return clipped; 3909} 3910 3911static inline void box32_translate(Box32Rec *box, DrawablePtr d) 3912{ 3913 box->x1 += d->x; 3914 box->x2 += d->x; 3915 3916 box->y1 += d->y; 3917 box->y2 += d->y; 3918} 3919 3920static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr gc) 3921{ 3922 box32_translate(box, d); 3923 return box32_clip(box, gc); 3924} 3925 3926static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y) 3927{ 3928 if (box->x1 > x) 3929 box->x1 = x; 3930 else if (box->x2 < x) 3931 box->x2 = x; 3932 3933 if (box->y1 > y) 3934 box->y1 = y; 3935 else if (box->y2 < y) 3936 box->y2 = y; 3937} 3938 3939static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16) 3940{ 3941 b16->x1 = b32->x1; 3942 b16->y1 = b32->y1; 3943 b16->x2 = b32->x2; 3944 b16->y2 = b32->y2; 3945 3946 return b16->x2 > b16->x1 && b16->y2 > b16->y1; 3947} 3948 3949static inline void box32_add_rect(Box32Rec *box, const xRectangle *r) 3950{ 3951 int32_t v; 3952 3953 v = r->x; 3954 if (box->x1 > v) 3955 box->x1 = v; 3956 v += r->width; 3957 if (box->x2 < v) 3958 box->x2 = v; 3959 3960 v = r->y; 3961 if (box->y1 > v) 3962 box->y1 = v; 3963 v += r->height; 3964 if (box->y2 < v) 3965 box->y2 = v; 3966} 3967 3968static bool 3969create_upload_tiled_x(struct kgem *kgem, 3970 PixmapPtr pixmap, 3971 struct sna_pixmap *priv) 3972{ 3973 unsigned create, tiling; 3974 3975 if (priv->shm || priv->cpu) 3976 return false; 3977 3978 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 3979 return false; 3980 3981 tiling = sna_pixmap_choose_tiling(pixmap, I915_TILING_X); 3982 assert(tiling != I915_TILING_Y && tiling != -I915_TILING_Y); 3983 3984 assert(priv->gpu_bo == NULL); 3985 assert(priv->gpu_damage == NULL); 3986 3987 create = CREATE_CPU_MAP | CREATE_INACTIVE; 3988 if (pixmap->usage_hint == SNA_CREATE_FB) 3989 create |= CREATE_SCANOUT; 3990 if (!kgem->has_llc) 3991 create |= CREATE_CACHED; 3992 3993 priv->gpu_bo = 3994 kgem_create_2d(kgem, 3995 pixmap->drawable.width, 3996 pixmap->drawable.height, 3997 pixmap->drawable.bitsPerPixel, 3998 tiling, create); 3999 return priv->gpu_bo != NULL; 4000} 4001 4002static bool 4003try_upload_blt(PixmapPtr pixmap, RegionRec *region, 4004 int x, int y, int w, int h, char *bits, int stride) 4005{ 4006 struct sna *sna = to_sna_from_pixmap(pixmap); 4007 struct sna_pixmap *priv; 4008 struct kgem_bo *src_bo; 4009 bool ok; 4010 4011 if (!sna->kgem.has_userptr || !USE_USERPTR_UPLOADS) 4012 return false; 4013 4014 priv = sna_pixmap(pixmap); 4015 if (priv == NULL) 4016 return false; 4017 4018 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 4019 return false; 4020 4021 assert(priv->gpu_bo); 4022 assert(priv->gpu_bo->proxy == NULL); 4023 4024 if (priv->cow || !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4025 return false; 4026 4027 if (priv->cpu_damage && 4028 sna_damage_contains_box__no_reduce(priv->cpu_damage, 4029 ®ion->extents) && 4030 !box_inplace(pixmap, ®ion->extents)) 4031 return false; 4032 4033 src_bo = kgem_create_map(&sna->kgem, bits, stride * h, true); 4034 if (src_bo == NULL) 4035 return false; 4036 4037 src_bo->pitch = stride; 4038 kgem_bo_mark_unreusable(src_bo); 4039 4040 DBG(("%s: upload(%d, %d, %d, %d) x %d through a temporary map\n", 4041 __FUNCTION__, x, y, w, h, 4042 RegionNumRects(region))); 4043 4044 ok = sna->render.copy_boxes(sna, GXcopy, 4045 pixmap, src_bo, -x, -y, 4046 pixmap, priv->gpu_bo, 0, 0, 4047 RegionRects(region), 4048 RegionNumRects(region), 4049 COPY_LAST); 4050 4051 kgem_bo_sync__cpu(&sna->kgem, src_bo); 4052 assert(src_bo->rq == NULL); 4053 kgem_bo_destroy(&sna->kgem, src_bo); 4054 4055 if (!ok) 4056 return false; 4057 4058 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4059 assert(!priv->clear); 4060 if (region->data == NULL && 4061 w >= pixmap->drawable.width && 4062 h >= pixmap->drawable.height) { 4063 sna_damage_all(&priv->gpu_damage, 4064 pixmap->drawable.width, 4065 pixmap->drawable.height); 4066 } else { 4067 sna_damage_add(&priv->gpu_damage, region); 4068 sna_damage_reduce_all(&priv->gpu_damage, 4069 pixmap->drawable.width, 4070 pixmap->drawable.height); 4071 } 4072 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 4073 list_del(&priv->flush_list); 4074 sna_damage_destroy(&priv->cpu_damage); 4075 sna_pixmap_free_cpu(sna, priv); 4076 } 4077 } 4078 4079 return true; 4080} 4081 4082static bool 4083try_upload_tiled_x(PixmapPtr pixmap, RegionRec *region, 4084 int x, int y, int w, int h, char *bits, int stride) 4085{ 4086 struct sna *sna = to_sna_from_pixmap(pixmap); 4087 struct sna_pixmap *priv = sna_pixmap(pixmap); 4088 bool replaces; 4089 BoxRec *box; 4090 uint8_t *dst; 4091 int n; 4092 4093 if (wedged(sna)) 4094 return false; 4095 4096 DBG(("%s: bo? %d, can map? %d\n", __FUNCTION__, 4097 priv->gpu_bo != NULL, 4098 priv->gpu_bo ? kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, true) : 0)); 4099 4100 replaces = region->data == NULL && 4101 w >= pixmap->drawable.width && 4102 h >= pixmap->drawable.height; 4103 4104 if (priv->gpu_bo && (replaces || priv->gpu_bo->proxy)) { 4105 DBG(("%s: discarding cached upload proxy\n", __FUNCTION__)); 4106 sna_pixmap_free_gpu(sna, priv); 4107 } 4108 4109 if (priv->cow) { 4110 DBG(("%s: no, has COW\n", __FUNCTION__)); 4111 return false; 4112 } 4113 4114 if (priv->gpu_bo == NULL && 4115 !create_upload_tiled_x(&sna->kgem, pixmap, priv)) 4116 return false; 4117 4118 DBG(("%s: tiling=%d\n", __FUNCTION__, priv->gpu_bo->tiling)); 4119 switch (priv->gpu_bo->tiling) { 4120 case I915_TILING_Y: 4121 return false; 4122 case I915_TILING_X: 4123 if (!sna->kgem.memcpy_to_tiled_x) 4124 return false; 4125 default: 4126 break; 4127 } 4128 4129 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, 4130 (priv->create & KGEM_CAN_CREATE_LARGE) == 0)) { 4131 DBG(("%s: no, cannot map through the CPU\n", __FUNCTION__)); 4132 return false; 4133 } 4134 4135 if ((priv->create & KGEM_CAN_CREATE_LARGE) == 0 && 4136 __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 4137 return false; 4138 4139 dst = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 4140 if (dst == NULL) 4141 return false; 4142 4143 kgem_bo_sync__cpu(&sna->kgem, priv->gpu_bo); 4144 4145 box = RegionRects(region); 4146 n = RegionNumRects(region); 4147 4148 DBG(("%s: upload(%d, %d, %d, %d) x %d\n", __FUNCTION__, x, y, w, h, n)); 4149 4150 if (priv->gpu_bo->tiling) { 4151 do { 4152 memcpy_to_tiled_x(&sna->kgem, bits, dst, 4153 pixmap->drawable.bitsPerPixel, 4154 stride, priv->gpu_bo->pitch, 4155 box->x1 - x, box->y1 - y, 4156 box->x1, box->y1, 4157 box->x2 - box->x1, box->y2 - box->y1); 4158 box++; 4159 } while (--n); 4160 } else { 4161 do { 4162 memcpy_blt(bits, dst, 4163 pixmap->drawable.bitsPerPixel, 4164 stride, priv->gpu_bo->pitch, 4165 box->x1 - x, box->y1 - y, 4166 box->x1, box->y1, 4167 box->x2 - box->x1, box->y2 - box->y1); 4168 box++; 4169 } while (--n); 4170 } 4171 4172 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4173 assert(!priv->clear); 4174 if (replaces) { 4175 sna_damage_all(&priv->gpu_damage, 4176 pixmap->drawable.width, 4177 pixmap->drawable.height); 4178 } else { 4179 sna_damage_add(&priv->gpu_damage, region); 4180 sna_damage_reduce_all(&priv->gpu_damage, 4181 pixmap->drawable.width, 4182 pixmap->drawable.height); 4183 } 4184 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 4185 list_del(&priv->flush_list); 4186 sna_damage_destroy(&priv->cpu_damage); 4187 sna_pixmap_free_cpu(sna, priv); 4188 } 4189 } 4190 if (priv->cpu_damage) 4191 sna_damage_subtract(&priv->cpu_damage, region); 4192 4193 if (priv->mapped) { 4194 assert(!priv->shm); 4195 priv->pixmap->devPrivate.ptr = NULL; 4196 priv->mapped = false; 4197 } 4198 4199 priv->clear = false; 4200 priv->cpu = false; 4201 return true; 4202} 4203 4204static bool 4205sna_put_zpixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 4206 int x, int y, int w, int h, char *bits, int stride) 4207{ 4208 PixmapPtr pixmap = get_drawable_pixmap(drawable); 4209 BoxRec *box; 4210 int16_t dx, dy; 4211 int n; 4212 4213 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 4214 4215 if (gc->alu != GXcopy) 4216 return false; 4217 4218 if (drawable->depth < 8) 4219 return false; 4220 4221 get_drawable_deltas(drawable, pixmap, &dx, &dy); 4222 x += dx + drawable->x; 4223 y += dy + drawable->y; 4224 4225 if (try_upload_blt(pixmap, region, x, y, w, h, bits, stride)) 4226 return true; 4227 4228 if (try_upload_tiled_x(pixmap, region, x, y, w, h, bits, stride)) 4229 return true; 4230 4231 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 4232 region, MOVE_WRITE)) 4233 return false; 4234 4235 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 4236 4237 /* Region is pre-clipped and translated into pixmap space */ 4238 box = RegionRects(region); 4239 n = RegionNumRects(region); 4240 do { 4241 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 4242 __FUNCTION__, 4243 box->x1 - x, box->y1 - y, 4244 box->x1, box->y1, 4245 box->x2 - box->x1, box->y2 - box->y1)); 4246 4247 assert(box->x2 > box->x1); 4248 assert(box->y2 > box->y1); 4249 4250 assert(box->x1 >= 0); 4251 assert(box->y1 >= 0); 4252 assert(box->x2 <= pixmap->drawable.width); 4253 assert(box->y2 <= pixmap->drawable.height); 4254 4255 assert(box->x1 - x >= 0); 4256 assert(box->y1 - y >= 0); 4257 assert(box->x2 - x <= w); 4258 assert(box->y2 - y <= h); 4259 4260 assert(has_coherent_ptr(sna_pixmap(pixmap))); 4261 memcpy_blt(bits, pixmap->devPrivate.ptr, 4262 pixmap->drawable.bitsPerPixel, 4263 stride, pixmap->devKind, 4264 box->x1 - x, box->y1 - y, 4265 box->x1, box->y1, 4266 box->x2 - box->x1, box->y2 - box->y1); 4267 box++; 4268 } while (--n); 4269 4270 assert_pixmap_damage(pixmap); 4271 return true; 4272} 4273 4274static inline uint8_t byte_reverse(uint8_t b) 4275{ 4276 return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; 4277} 4278 4279static inline uint8_t blt_depth(int depth) 4280{ 4281 switch (depth) { 4282 case 8: return 0; 4283 case 15: return 0x2; 4284 case 16: return 0x1; 4285 default: return 0x3; 4286 } 4287} 4288 4289static bool 4290sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 4291 int x, int y, int w, int h, char *bits) 4292{ 4293 PixmapPtr pixmap = get_drawable_pixmap(drawable); 4294 struct sna *sna = to_sna_from_pixmap(pixmap); 4295 struct sna_damage **damage; 4296 struct kgem_bo *bo; 4297 BoxRec *box; 4298 int16_t dx, dy; 4299 int n; 4300 uint8_t rop = copy_ROP[gc->alu]; 4301 4302 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 4303 ®ion->extents, &damage); 4304 if (bo == NULL) 4305 return false; 4306 4307 if (bo->tiling == I915_TILING_Y) { 4308 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 4309 assert(bo == __sna_pixmap_get_bo(pixmap)); 4310 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 4311 if (bo == NULL) { 4312 DBG(("%s: fallback -- unable to change tiling\n", 4313 __FUNCTION__)); 4314 return false; 4315 } 4316 } 4317 4318 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 4319 if (damage) 4320 sna_damage_add(damage, region); 4321 assert_pixmap_damage(pixmap); 4322 4323 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 4324 4325 get_drawable_deltas(drawable, pixmap, &dx, &dy); 4326 x += dx + drawable->x; 4327 y += dy + drawable->y; 4328 4329 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 4330 4331 /* Region is pre-clipped and translated into pixmap space */ 4332 box = RegionRects(region); 4333 n = RegionNumRects(region); 4334 do { 4335 int bx1 = (box->x1 - x) & ~7; 4336 int bx2 = (box->x2 - x + 7) & ~7; 4337 int bw = (bx2 - bx1)/8; 4338 int bh = box->y2 - box->y1; 4339 int bstride = ALIGN(bw, 2); 4340 int src_stride; 4341 uint8_t *dst, *src; 4342 uint32_t *b; 4343 struct kgem_bo *upload; 4344 void *ptr; 4345 4346 if (!kgem_check_batch(&sna->kgem, 8) || 4347 !kgem_check_bo_fenced(&sna->kgem, bo) || 4348 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 4349 kgem_submit(&sna->kgem); 4350 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 4351 return false; 4352 _kgem_set_mode(&sna->kgem, KGEM_BLT); 4353 } 4354 4355 upload = kgem_create_buffer(&sna->kgem, 4356 bstride*bh, 4357 KGEM_BUFFER_WRITE_INPLACE, 4358 &ptr); 4359 if (!upload) 4360 break; 4361 4362 dst = ptr; 4363 bstride -= bw; 4364 4365 src_stride = BitmapBytePad(w); 4366 src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 4367 src_stride -= bw; 4368 do { 4369 int i = bw; 4370 do { 4371 *dst++ = byte_reverse(*src++); 4372 } while (--i); 4373 dst += bstride; 4374 src += src_stride; 4375 } while (--bh); 4376 4377 b = sna->kgem.batch + sna->kgem.nbatch; 4378 b[0] = XY_MONO_SRC_COPY | 3 << 20; 4379 b[0] |= ((box->x1 - x) & 7) << 17; 4380 b[1] = bo->pitch; 4381 if (sna->kgem.gen >= 040 && bo->tiling) { 4382 b[0] |= BLT_DST_TILED; 4383 b[1] >>= 2; 4384 } 4385 b[1] |= blt_depth(drawable->depth) << 24; 4386 b[1] |= rop << 16; 4387 b[2] = box->y1 << 16 | box->x1; 4388 b[3] = box->y2 << 16 | box->x2; 4389 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 4390 I915_GEM_DOMAIN_RENDER << 16 | 4391 I915_GEM_DOMAIN_RENDER | 4392 KGEM_RELOC_FENCED, 4393 0); 4394 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 4395 upload, 4396 I915_GEM_DOMAIN_RENDER << 16 | 4397 KGEM_RELOC_FENCED, 4398 0); 4399 b[6] = gc->bgPixel; 4400 b[7] = gc->fgPixel; 4401 4402 sna->kgem.nbatch += 8; 4403 kgem_bo_destroy(&sna->kgem, upload); 4404 4405 box++; 4406 } while (--n); 4407 4408 sna->blt_state.fill_bo = 0; 4409 return true; 4410} 4411 4412static bool 4413sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region, 4414 int x, int y, int w, int h, int left,char *bits) 4415{ 4416 PixmapPtr pixmap = get_drawable_pixmap(drawable); 4417 struct sna *sna = to_sna_from_pixmap(pixmap); 4418 struct sna_damage **damage; 4419 struct kgem_bo *bo; 4420 int16_t dx, dy; 4421 unsigned i, skip; 4422 4423 if (gc->alu != GXcopy) 4424 return false; 4425 4426 bo = sna_drawable_use_bo(&pixmap->drawable, PREFER_GPU, 4427 ®ion->extents, &damage); 4428 if (bo == NULL) 4429 return false; 4430 4431 if (bo->tiling == I915_TILING_Y) { 4432 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 4433 assert(bo == __sna_pixmap_get_bo(pixmap)); 4434 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 4435 if (bo == NULL) { 4436 DBG(("%s: fallback -- unable to change tiling\n", 4437 __FUNCTION__)); 4438 return false; 4439 } 4440 } 4441 4442 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 4443 if (damage) 4444 sna_damage_add(damage, region); 4445 assert_pixmap_damage(pixmap); 4446 4447 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, x, y, w, h)); 4448 4449 get_drawable_deltas(drawable, pixmap, &dx, &dy); 4450 x += dx + drawable->x; 4451 y += dy + drawable->y; 4452 4453 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 4454 4455 skip = h * BitmapBytePad(w + left); 4456 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) { 4457 const BoxRec *box = RegionRects(region); 4458 int n = RegionNumRects(region); 4459 4460 if ((gc->planemask & i) == 0) 4461 continue; 4462 4463 /* Region is pre-clipped and translated into pixmap space */ 4464 do { 4465 int bx1 = (box->x1 - x) & ~7; 4466 int bx2 = (box->x2 - x + 7) & ~7; 4467 int bw = (bx2 - bx1)/8; 4468 int bh = box->y2 - box->y1; 4469 int bstride = ALIGN(bw, 2); 4470 int src_stride; 4471 uint8_t *dst, *src; 4472 uint32_t *b; 4473 struct kgem_bo *upload; 4474 void *ptr; 4475 4476 if (!kgem_check_batch(&sna->kgem, 12) || 4477 !kgem_check_bo_fenced(&sna->kgem, bo) || 4478 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 4479 kgem_submit(&sna->kgem); 4480 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 4481 return false; 4482 _kgem_set_mode(&sna->kgem, KGEM_BLT); 4483 } 4484 4485 upload = kgem_create_buffer(&sna->kgem, 4486 bstride*bh, 4487 KGEM_BUFFER_WRITE_INPLACE, 4488 &ptr); 4489 if (!upload) 4490 break; 4491 4492 dst = ptr; 4493 bstride -= bw; 4494 4495 src_stride = BitmapBytePad(w); 4496 src = (uint8_t*)bits + (box->y1 - y) * src_stride + bx1/8; 4497 src_stride -= bw; 4498 do { 4499 int j = bw; 4500 do { 4501 *dst++ = byte_reverse(*src++); 4502 } while (--j); 4503 dst += bstride; 4504 src += src_stride; 4505 } while (--bh); 4506 4507 b = sna->kgem.batch + sna->kgem.nbatch; 4508 b[0] = XY_FULL_MONO_PATTERN_MONO_SRC_BLT | 3 << 20; 4509 b[0] |= ((box->x1 - x) & 7) << 17; 4510 b[1] = bo->pitch; 4511 if (sna->kgem.gen >= 040 && bo->tiling) { 4512 b[0] |= BLT_DST_TILED; 4513 b[1] >>= 2; 4514 } 4515 b[1] |= 1 << 31; /* solid pattern */ 4516 b[1] |= blt_depth(drawable->depth) << 24; 4517 b[1] |= 0xce << 16; /* S or (D and !P) */ 4518 b[2] = box->y1 << 16 | box->x1; 4519 b[3] = box->y2 << 16 | box->x2; 4520 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 4521 bo, 4522 I915_GEM_DOMAIN_RENDER << 16 | 4523 I915_GEM_DOMAIN_RENDER | 4524 KGEM_RELOC_FENCED, 4525 0); 4526 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 4527 upload, 4528 I915_GEM_DOMAIN_RENDER << 16 | 4529 KGEM_RELOC_FENCED, 4530 0); 4531 b[6] = 0; 4532 b[7] = i; 4533 b[8] = i; 4534 b[9] = i; 4535 b[10] = -1; 4536 b[11] = -1; 4537 4538 sna->kgem.nbatch += 12; 4539 kgem_bo_destroy(&sna->kgem, upload); 4540 4541 box++; 4542 } while (--n); 4543 } 4544 4545 sna->blt_state.fill_bo = 0; 4546 return true; 4547} 4548 4549static void 4550sna_put_image(DrawablePtr drawable, GCPtr gc, int depth, 4551 int x, int y, int w, int h, int left, int format, 4552 char *bits) 4553{ 4554 PixmapPtr pixmap = get_drawable_pixmap(drawable); 4555 struct sna *sna = to_sna_from_pixmap(pixmap); 4556 struct sna_pixmap *priv = sna_pixmap(pixmap); 4557 RegionRec region; 4558 int16_t dx, dy; 4559 4560 DBG(("%s((%d, %d)x(%d, %d), depth=%d, format=%d)\n", 4561 __FUNCTION__, x, y, w, h, depth, format)); 4562 4563 if (w == 0 || h == 0) 4564 return; 4565 4566 region.extents.x1 = x + drawable->x; 4567 region.extents.y1 = y + drawable->y; 4568 region.extents.x2 = region.extents.x1 + w; 4569 region.extents.y2 = region.extents.y1 + h; 4570 region.data = NULL; 4571 4572 if (!region_is_singular(gc->pCompositeClip) || 4573 gc->pCompositeClip->extents.x1 > region.extents.x1 || 4574 gc->pCompositeClip->extents.y1 > region.extents.y1 || 4575 gc->pCompositeClip->extents.x2 < region.extents.x2 || 4576 gc->pCompositeClip->extents.y2 < region.extents.y2) { 4577 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 4578 if (RegionNil(®ion)) 4579 return; 4580 } 4581 4582 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 4583 RegionTranslate(®ion, dx, dy); 4584 4585 if (priv == NULL) { 4586 DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n", 4587 __FUNCTION__, x, y, w, h)); 4588 goto fallback; 4589 } 4590 4591 if (FORCE_FALLBACK) 4592 goto fallback; 4593 4594 if (wedged(sna)) 4595 goto fallback; 4596 4597 if (!ACCEL_PUT_IMAGE) 4598 goto fallback; 4599 4600 switch (format) { 4601 case ZPixmap: 4602 if (!PM_IS_SOLID(drawable, gc->planemask)) 4603 goto fallback; 4604 4605 if (sna_put_zpixmap_blt(drawable, gc, ®ion, 4606 x, y, w, h, 4607 bits, PixmapBytePad(w, depth))) 4608 return; 4609 break; 4610 4611 case XYBitmap: 4612 if (!PM_IS_SOLID(drawable, gc->planemask)) 4613 goto fallback; 4614 4615 if (sna_put_xybitmap_blt(drawable, gc, ®ion, 4616 x, y, w, h, 4617 bits)) 4618 return; 4619 break; 4620 4621 case XYPixmap: 4622 if (sna_put_xypixmap_blt(drawable, gc, ®ion, 4623 x, y, w, h, left, 4624 bits)) 4625 return; 4626 break; 4627 4628 default: 4629 return; 4630 } 4631 4632fallback: 4633 DBG(("%s: fallback\n", __FUNCTION__)); 4634 RegionTranslate(®ion, -dx, -dy); 4635 4636 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 4637 goto out; 4638 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 4639 format == XYPixmap ? 4640 MOVE_READ | MOVE_WRITE : 4641 drawable_gc_flags(drawable, gc, false))) 4642 goto out_gc; 4643 4644 DBG(("%s: fbPutImage(%d, %d, %d, %d)\n", 4645 __FUNCTION__, x, y, w, h)); 4646 fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits); 4647 FALLBACK_FLUSH(drawable); 4648out_gc: 4649 sna_gc_move_to_gpu(gc); 4650out: 4651 RegionUninit(®ion); 4652} 4653 4654static bool 4655source_contains_region(struct sna_damage *damage, 4656 const RegionRec *region, int16_t dx, int16_t dy) 4657{ 4658 BoxRec box; 4659 4660 if (DAMAGE_IS_ALL(damage)) 4661 return true; 4662 4663 box = region->extents; 4664 box.x1 += dx; 4665 box.x2 += dx; 4666 box.y1 += dy; 4667 box.y2 += dy; 4668 return sna_damage_contains_box__no_reduce(damage, &box); 4669} 4670 4671static bool 4672move_to_gpu(PixmapPtr pixmap, struct sna_pixmap *priv, 4673 RegionRec *region, int16_t dx, int16_t dy, 4674 uint8_t alu, bool dst_is_gpu) 4675{ 4676 int w = region->extents.x2 - region->extents.x1; 4677 int h = region->extents.y2 - region->extents.y1; 4678 int count; 4679 4680 if (DAMAGE_IS_ALL(priv->gpu_damage)) { 4681 assert(priv->gpu_bo); 4682 assert(priv->cpu == false || (priv->mapped && IS_CPU_MAP(priv->gpu_bo->map))); 4683 return true; 4684 } 4685 4686 if (dst_is_gpu && priv->cpu_bo && priv->cpu_damage) { 4687 DBG(("%s: can use CPU bo? cpu_damage=%d, gpu_damage=%d, cpu hint=%d\n", 4688 __FUNCTION__, 4689 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 4690 priv->gpu_damage ? DAMAGE_IS_ALL(priv->gpu_damage) ? -1 : 1 : 0, 4691 priv->cpu)); 4692 if (DAMAGE_IS_ALL(priv->cpu_damage) || priv->gpu_damage == NULL) 4693 return false; 4694 4695 if (priv->cpu && 4696 source_contains_region(priv->cpu_damage, region, dx, dy)) 4697 return false; 4698 } 4699 4700 if (priv->gpu_bo) { 4701 DBG(("%s: has gpu bo (cpu damage?=%d, cpu=%d, gpu tiling=%d)\n", 4702 __FUNCTION__, 4703 priv->cpu_damage ? DAMAGE_IS_ALL(priv->cpu_damage) ? -1 : 1 : 0, 4704 priv->cpu, priv->gpu_bo->tiling)); 4705 4706 if (priv->cpu_damage == NULL) 4707 return true; 4708 4709 if (alu != GXcopy) 4710 return true; 4711 4712 if (!priv->cpu) 4713 return true; 4714 4715 if (priv->gpu_bo->tiling) 4716 return true; 4717 4718 RegionTranslate(region, dx, dy); 4719 count = region_subsumes_damage(region, priv->cpu_damage); 4720 RegionTranslate(region, -dx, -dy); 4721 if (count) 4722 return true; 4723 } else { 4724 if ((priv->create & KGEM_CAN_CREATE_GPU) == 0) 4725 return false; 4726 if (priv->shm) 4727 return false; 4728 } 4729 4730 count = priv->source_count++; 4731 if (priv->cpu_bo) { 4732 if (priv->cpu_bo->flush && count > SOURCE_BIAS) 4733 return true; 4734 4735 if (sna_pixmap_choose_tiling(pixmap, 4736 DEFAULT_TILING) == I915_TILING_NONE) 4737 return false; 4738 4739 if (priv->cpu) 4740 return false; 4741 4742 return count > SOURCE_BIAS; 4743 } else { 4744 if (w == pixmap->drawable.width && h == pixmap->drawable.height) 4745 return count > SOURCE_BIAS; 4746 4747 return count * w*h >= (SOURCE_BIAS+2) * (int)pixmap->drawable.width * pixmap->drawable.height; 4748 } 4749} 4750 4751static BoxPtr 4752reorder_boxes(BoxPtr box, int n, int dx, int dy) 4753{ 4754 BoxPtr new, base, next, tmp; 4755 4756 DBG(("%s x %d dx=%d, dy=%d\n", __FUNCTION__, n, dx, dy)); 4757 4758 if (dy <= 0 && dx <= 0) { 4759 new = malloc(sizeof(BoxRec) * n); 4760 if (new == NULL) 4761 return NULL; 4762 4763 tmp = new; 4764 next = box + n; 4765 do { 4766 *tmp++ = *--next; 4767 } while (next != box); 4768 } else if (dy < 0) { 4769 new = malloc(sizeof(BoxRec) * n); 4770 if (new == NULL) 4771 return NULL; 4772 4773 base = next = box + n - 1; 4774 while (base >= box) { 4775 while (next >= box && base->y1 == next->y1) 4776 next--; 4777 tmp = next + 1; 4778 while (tmp <= base) 4779 *new++ = *tmp++; 4780 base = next; 4781 } 4782 new -= n; 4783 } else { 4784 new = malloc(sizeof(BoxRec) * n); 4785 if (!new) 4786 return NULL; 4787 4788 base = next = box; 4789 while (base < box + n) { 4790 while (next < box + n && next->y1 == base->y1) 4791 next++; 4792 tmp = next; 4793 while (tmp != base) 4794 *new++ = *--tmp; 4795 base = next; 4796 } 4797 new -= n; 4798 } 4799 4800 return new; 4801} 4802 4803static void 4804sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 4805 RegionPtr region,int dx, int dy, 4806 Pixel bitplane, void *closure) 4807{ 4808 PixmapPtr pixmap = get_drawable_pixmap(src); 4809 struct sna *sna = to_sna_from_pixmap(pixmap); 4810 struct sna_pixmap *priv = sna_pixmap(pixmap); 4811 BoxPtr box = RegionRects(region); 4812 int n = RegionNumRects(region); 4813 int alu = gc ? gc->alu : GXcopy; 4814 int16_t tx, ty; 4815 4816 assert(RegionNumRects(region)); 4817 if (((dx | dy) == 0 && alu == GXcopy)) 4818 return; 4819 4820 if (n > 1 && (dx | dy) < 0) { 4821 box = reorder_boxes(box, n, dx, dy); 4822 if (box == NULL) 4823 return; 4824 } 4825 4826 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, pix.size=%dx%d)\n", 4827 __FUNCTION__, n, 4828 region->extents.x1, region->extents.y1, 4829 region->extents.x2, region->extents.y2, 4830 dx, dy, alu, 4831 pixmap->drawable.width, pixmap->drawable.height)); 4832 4833 if (get_drawable_deltas(src, pixmap, &tx, &ty)) 4834 dx += tx, dy += ty; 4835 if (dst != src) 4836 get_drawable_deltas(dst, pixmap, &tx, &ty); 4837 4838 if (priv == NULL || DAMAGE_IS_ALL(priv->cpu_damage) || priv->shm) 4839 goto fallback; 4840 4841 if (priv->gpu_damage || (priv->cpu_damage == NULL && priv->gpu_bo)) { 4842 assert(priv->gpu_bo); 4843 4844 if (alu == GXcopy && priv->clear) 4845 goto out; 4846 4847 assert(priv->gpu_bo->proxy == NULL); 4848 if (!sna_pixmap_move_to_gpu(pixmap, MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT)) { 4849 DBG(("%s: fallback - not a pure copy and failed to move dst to GPU\n", 4850 __FUNCTION__)); 4851 goto fallback; 4852 } 4853 4854 if (!sna->render.copy_boxes(sna, alu, 4855 pixmap, priv->gpu_bo, dx, dy, 4856 pixmap, priv->gpu_bo, tx, ty, 4857 box, n, 0)) { 4858 DBG(("%s: fallback - accelerated copy boxes failed\n", 4859 __FUNCTION__)); 4860 goto fallback; 4861 } 4862 4863 if (!DAMAGE_IS_ALL(priv->gpu_damage)) { 4864 assert(!priv->clear); 4865 RegionTranslate(region, tx, ty); 4866 sna_damage_add(&priv->gpu_damage, region); 4867 } 4868 assert_pixmap_damage(pixmap); 4869 } else { 4870fallback: 4871 DBG(("%s: fallback", __FUNCTION__)); 4872 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 4873 goto out; 4874 4875 if (alu == GXcopy && pixmap->drawable.bitsPerPixel >= 8) { 4876 FbBits *dst_bits, *src_bits; 4877 int stride = pixmap->devKind; 4878 int bpp = pixmap->drawable.bitsPerPixel; 4879 int i; 4880 4881 dst_bits = (FbBits *) 4882 ((char *)pixmap->devPrivate.ptr + 4883 ty * stride + tx * bpp / 8); 4884 src_bits = (FbBits *) 4885 ((char *)pixmap->devPrivate.ptr + 4886 dy * stride + dx * bpp / 8); 4887 4888 for (i = 0; i < n; i++) 4889 memmove_box(src_bits, dst_bits, 4890 bpp, stride, box+i, 4891 dx, dy); 4892 } else { 4893 if (gc && !sna_gc_move_to_cpu(gc, dst, region)) 4894 goto out; 4895 4896 get_drawable_deltas(src, pixmap, &tx, &ty); 4897 miCopyRegion(src, dst, gc, 4898 region, dx - tx, dy - ty, 4899 fbCopyNtoN, 0, NULL); 4900 4901 if (gc) 4902 sna_gc_move_to_gpu(gc); 4903 } 4904 } 4905 4906out: 4907 if (box != RegionRects(region)) 4908 free(box); 4909} 4910 4911static inline bool 4912sna_pixmap_is_gpu(PixmapPtr pixmap) 4913{ 4914 struct sna_pixmap *priv = sna_pixmap(pixmap); 4915 4916 if (priv == NULL || priv->clear) 4917 return false; 4918 4919 if (DAMAGE_IS_ALL(priv->gpu_damage) || 4920 (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo) && !priv->gpu_bo->proxy)) 4921 return true; 4922 4923 return priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo); 4924} 4925 4926static int 4927source_prefer_gpu(struct sna *sna, struct sna_pixmap *priv, 4928 RegionRec *region, int16_t dx, int16_t dy) 4929{ 4930 if (priv == NULL) { 4931 DBG(("%s: source unattached, use cpu\n", __FUNCTION__)); 4932 return 0; 4933 } 4934 4935 if (priv->clear) { 4936 DBG(("%s: source is clear, don't force use of GPU\n", __FUNCTION__)); 4937 return 0; 4938 } 4939 4940 if (priv->gpu_damage && 4941 (priv->cpu_damage == NULL || 4942 !source_contains_region(priv->cpu_damage, region, dx, dy))) { 4943 DBG(("%s: source has gpu damage, force gpu? %d\n", 4944 __FUNCTION__, priv->cpu_damage == NULL)); 4945 assert(priv->gpu_bo); 4946 return priv->cpu_damage ? PREFER_GPU : PREFER_GPU | FORCE_GPU; 4947 } 4948 4949 if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo)) { 4950 DBG(("%s: source has busy CPU bo, force gpu\n", __FUNCTION__)); 4951 return PREFER_GPU | FORCE_GPU; 4952 } 4953 4954 if (DAMAGE_IS_ALL(priv->cpu_damage)) 4955 return priv->cpu_bo && kgem_is_idle(&sna->kgem); 4956 4957 DBG(("%s: source has GPU bo? %d\n", 4958 __FUNCTION__, priv->gpu_bo != NULL)); 4959 return priv->gpu_bo != NULL; 4960} 4961 4962static bool use_shm_bo(struct sna *sna, 4963 struct kgem_bo *bo, 4964 struct sna_pixmap *priv, 4965 int alu, bool replaces) 4966{ 4967 if (priv == NULL || priv->cpu_bo == NULL) { 4968 DBG(("%s: no, not attached\n", __FUNCTION__)); 4969 return false; 4970 } 4971 4972 if (!priv->shm && !priv->cpu) { 4973 DBG(("%s: yes, ordinary CPU bo\n", __FUNCTION__)); 4974 return true; 4975 } 4976 4977 if (alu != GXcopy) { 4978 DBG(("%s: yes, complex alu=%d\n", __FUNCTION__, alu)); 4979 return true; 4980 } 4981 4982 if (!replaces && __kgem_bo_is_busy(&sna->kgem, bo)) { 4983 DBG(("%s: yes, dst is busy\n", __FUNCTION__)); 4984 return true; 4985 } 4986 4987 if (priv->cpu_bo->needs_flush && 4988 __kgem_bo_is_busy(&sna->kgem, priv->cpu_bo)) { 4989 DBG(("%s: yes, src is busy\n", __FUNCTION__)); 4990 return true; 4991 } 4992 4993 return false; 4994} 4995 4996static void 4997sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 4998 RegionPtr region, int dx, int dy, 4999 Pixel bitplane, void *closure) 5000{ 5001 PixmapPtr src_pixmap = get_drawable_pixmap(src); 5002 struct sna_pixmap *src_priv = sna_pixmap(src_pixmap); 5003 PixmapPtr dst_pixmap = get_drawable_pixmap(dst); 5004 struct sna_pixmap *dst_priv = sna_pixmap(dst_pixmap); 5005 struct sna *sna = to_sna_from_pixmap(src_pixmap); 5006 struct sna_damage **damage; 5007 struct kgem_bo *bo; 5008 unsigned hint; 5009 int16_t src_dx, src_dy; 5010 int16_t dst_dx, dst_dy; 5011 BoxPtr box = RegionRects(region); 5012 int n = RegionNumRects(region); 5013 int alu = gc->alu; 5014 int stride, bpp; 5015 char *bits; 5016 bool replaces; 5017 5018 assert(RegionNumRects(region)); 5019 5020 if (src_pixmap == dst_pixmap) 5021 return sna_self_copy_boxes(src, dst, gc, 5022 region, dx, dy, 5023 bitplane, closure); 5024 5025 DBG(("%s (boxes=%dx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d, src.size=%dx%d, dst.size=%dx%d)\n", 5026 __FUNCTION__, n, 5027 box[0].x1, box[0].y1, box[0].x2, box[0].y2, 5028 dx, dy, alu, 5029 src_pixmap->drawable.width, src_pixmap->drawable.height, 5030 dst_pixmap->drawable.width, dst_pixmap->drawable.height)); 5031 5032 assert_pixmap_damage(dst_pixmap); 5033 assert_pixmap_damage(src_pixmap); 5034 5035 bpp = dst_pixmap->drawable.bitsPerPixel; 5036 5037 if (get_drawable_deltas(dst, dst_pixmap, &dst_dx, &dst_dy)) 5038 RegionTranslate(region, dst_dx, dst_dy); 5039 get_drawable_deltas(src, src_pixmap, &src_dx, &src_dy); 5040 src_dx += dx - dst_dx; 5041 src_dy += dy - dst_dy; 5042 5043 assert_pixmap_contains_box(dst_pixmap, RegionExtents(region)); 5044 assert_pixmap_contains_box_with_offset(src_pixmap, 5045 RegionExtents(region), 5046 src_dx, src_dy); 5047 5048 replaces = n == 1 && 5049 alu_overwrites(alu) && 5050 box->x1 <= 0 && 5051 box->y1 <= 0 && 5052 box->x2 >= dst_pixmap->drawable.width && 5053 box->y2 >= dst_pixmap->drawable.height; 5054 5055 DBG(("%s: dst=(priv=%p, gpu_bo=%d, cpu_bo=%d), src=(priv=%p, gpu_bo=%d, cpu_bo=%d), replaces=%d\n", 5056 __FUNCTION__, 5057 dst_priv, 5058 dst_priv && dst_priv->gpu_bo ? dst_priv->gpu_bo->handle : 0, 5059 dst_priv && dst_priv->cpu_bo ? dst_priv->cpu_bo->handle : 0, 5060 src_priv, 5061 src_priv && src_priv->gpu_bo ? src_priv->gpu_bo->handle : 0, 5062 src_priv && src_priv->cpu_bo ? src_priv->cpu_bo->handle : 0, 5063 replaces)); 5064 5065 if (dst_priv == NULL) 5066 goto fallback; 5067 5068 hint = source_prefer_gpu(sna, src_priv, region, src_dx, src_dy) ?: 5069 region_inplace(sna, dst_pixmap, region, 5070 dst_priv, alu_overwrites(alu) ? MOVE_WRITE : MOVE_READ | MOVE_WRITE); 5071 if (dst_priv->cpu_damage && alu_overwrites(alu)) { 5072 DBG(("%s: overwritting CPU damage\n", __FUNCTION__)); 5073 if (region_subsumes_damage(region, dst_priv->cpu_damage)) { 5074 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 5075 if (dst_priv->gpu_bo && dst_priv->gpu_bo->proxy) { 5076 assert(!dst_priv->pinned); 5077 kgem_bo_destroy(&sna->kgem, dst_priv->gpu_bo); 5078 dst_priv->gpu_bo = NULL; 5079 } 5080 sna_damage_destroy(&dst_priv->cpu_damage); 5081 list_del(&dst_priv->flush_list); 5082 dst_priv->cpu = false; 5083 } 5084 } 5085 if (region->data == NULL && alu_overwrites(alu)) 5086 hint |= IGNORE_CPU; 5087 5088 /* XXX hack for firefox -- subsequent uses of src will be corrupt! */ 5089 if (src_priv && 5090 COW(src_priv->cow) == COW(dst_priv->cow) && 5091 IS_COW_OWNER(dst_priv->cow)) { 5092 DBG(("%s: ignoring cow reference for cousin copy\n", 5093 __FUNCTION__)); 5094 assert(src_priv->cpu_damage == NULL); 5095 bo = dst_priv->gpu_bo; 5096 damage = NULL; 5097 } else 5098 bo = sna_drawable_use_bo(&dst_pixmap->drawable, hint, 5099 ®ion->extents, &damage); 5100 if (bo) { 5101 if (src_priv && src_priv->clear) { 5102 DBG(("%s: applying src clear [%08x] to dst\n", 5103 __FUNCTION__, src_priv->clear_color)); 5104 if (n == 1) { 5105 if (replaces && UNDO) 5106 kgem_bo_undo(&sna->kgem, bo); 5107 5108 if (!sna->render.fill_one(sna, 5109 dst_pixmap, bo, 5110 src_priv->clear_color, 5111 box->x1, box->y1, 5112 box->x2, box->y2, 5113 alu)) { 5114 DBG(("%s: unsupported fill\n", 5115 __FUNCTION__)); 5116 goto fallback; 5117 } 5118 5119 if (replaces && bo == dst_priv->gpu_bo) { 5120 DBG(("%s: marking dst handle=%d as all clear [%08x]\n", 5121 __FUNCTION__, 5122 dst_priv->gpu_bo->handle, 5123 src_priv->clear_color)); 5124 dst_priv->clear = true; 5125 dst_priv->clear_color = src_priv->clear_color; 5126 sna_damage_all(&dst_priv->gpu_damage, 5127 dst_pixmap->drawable.width, 5128 dst_pixmap->drawable.height); 5129 sna_damage_destroy(&dst_priv->cpu_damage); 5130 list_del(&dst_priv->flush_list); 5131 return; 5132 } 5133 } else { 5134 struct sna_fill_op fill; 5135 5136 if (!sna_fill_init_blt(&fill, sna, 5137 dst_pixmap, bo, 5138 alu, src_priv->clear_color)) { 5139 DBG(("%s: unsupported fill\n", 5140 __FUNCTION__)); 5141 goto fallback; 5142 } 5143 5144 fill.boxes(sna, &fill, box, n); 5145 fill.done(sna, &fill); 5146 } 5147 5148 if (damage) 5149 sna_damage_add(damage, region); 5150 return; 5151 } 5152 5153 if (src_priv && 5154 move_to_gpu(src_pixmap, src_priv, region, src_dx, src_dy, alu, bo == dst_priv->gpu_bo) && 5155 sna_pixmap_move_to_gpu(src_pixmap, MOVE_READ | MOVE_ASYNC_HINT)) { 5156 DBG(("%s: move whole src_pixmap to GPU and copy\n", 5157 __FUNCTION__)); 5158 if (replaces && UNDO) 5159 kgem_bo_undo(&sna->kgem, bo); 5160 5161 if (replaces && 5162 src_pixmap->drawable.width == dst_pixmap->drawable.width && 5163 src_pixmap->drawable.height == dst_pixmap->drawable.height) { 5164 assert(src_pixmap->drawable.depth == dst_pixmap->drawable.depth); 5165 assert(src_pixmap->drawable.bitsPerPixel == dst_pixmap->drawable.bitsPerPixel); 5166 if (sna_pixmap_make_cow(sna, src_priv, dst_priv)) { 5167 assert(dst_priv->gpu_bo == src_priv->gpu_bo); 5168 sna_damage_all(&dst_priv->gpu_damage, 5169 dst_pixmap->drawable.width, 5170 dst_pixmap->drawable.height); 5171 sna_damage_destroy(&dst_priv->cpu_damage); 5172 list_del(&dst_priv->flush_list); 5173 if (dst_priv->shm) 5174 sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo); 5175 return; 5176 } 5177 } 5178 if (!sna->render.copy_boxes(sna, alu, 5179 src_pixmap, src_priv->gpu_bo, src_dx, src_dy, 5180 dst_pixmap, bo, 0, 0, 5181 box, n, 0)) { 5182 DBG(("%s: fallback - accelerated copy boxes failed\n", 5183 __FUNCTION__)); 5184 goto fallback; 5185 } 5186 5187 if (damage) 5188 sna_damage_add(damage, region); 5189 return; 5190 } 5191 5192 if (src_priv && 5193 region_overlaps_damage(region, src_priv->gpu_damage, 5194 src_dx, src_dy)) { 5195 BoxRec area; 5196 5197 DBG(("%s: region overlaps GPU damage, upload and copy\n", 5198 __FUNCTION__)); 5199 5200 area = region->extents; 5201 area.x1 += src_dx; 5202 area.x2 += src_dx; 5203 area.y1 += src_dy; 5204 area.y2 += src_dy; 5205 5206 if (!sna_pixmap_move_area_to_gpu(src_pixmap, &area, 5207 MOVE_READ | MOVE_ASYNC_HINT)) 5208 goto fallback; 5209 5210 if (replaces && UNDO) 5211 kgem_bo_undo(&sna->kgem, bo); 5212 5213 if (!sna->render.copy_boxes(sna, alu, 5214 src_pixmap, src_priv->gpu_bo, src_dx, src_dy, 5215 dst_pixmap, bo, 0, 0, 5216 box, n, 0)) { 5217 DBG(("%s: fallback - accelerated copy boxes failed\n", 5218 __FUNCTION__)); 5219 goto fallback; 5220 } 5221 5222 if (damage) 5223 sna_damage_add(damage, region); 5224 return; 5225 } 5226 5227 if (bo != dst_priv->gpu_bo) 5228 goto fallback; 5229 5230 if (use_shm_bo(sna, bo, src_priv, alu, replaces)) { 5231 bool ret; 5232 5233 DBG(("%s: region overlaps CPU damage, copy from CPU bo (shm? %d)\n", 5234 __FUNCTION__, src_priv->shm)); 5235 5236 assert(bo != dst_priv->cpu_bo); 5237 5238 RegionTranslate(region, src_dx, src_dy); 5239 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 5240 region, 5241 MOVE_READ | MOVE_ASYNC_HINT); 5242 RegionTranslate(region, -src_dx, -src_dy); 5243 if (!ret) 5244 goto fallback; 5245 5246 if (replaces && UNDO) 5247 kgem_bo_undo(&sna->kgem, bo); 5248 5249 if (src_priv->shm) { 5250 assert(!src_priv->flush); 5251 sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo); 5252 } 5253 5254 if (!sna->render.copy_boxes(sna, alu, 5255 src_pixmap, src_priv->cpu_bo, src_dx, src_dy, 5256 dst_pixmap, bo, 0, 0, 5257 box, n, src_priv->shm ? COPY_LAST : 0)) { 5258 DBG(("%s: fallback - accelerated copy boxes failed\n", 5259 __FUNCTION__)); 5260 goto fallback; 5261 } 5262 5263 if (damage) 5264 sna_damage_add(damage, region); 5265 return; 5266 } 5267 5268 if (src_priv) { 5269 bool ret; 5270 5271 RegionTranslate(region, src_dx, src_dy); 5272 ret = sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 5273 region, MOVE_READ); 5274 RegionTranslate(region, -src_dx, -src_dy); 5275 if (!ret) 5276 goto fallback; 5277 5278 assert(!src_priv->mapped); 5279 if (src_pixmap->devPrivate.ptr == NULL) 5280 /* uninitialised!*/ 5281 return; 5282 } 5283 5284 if (USE_USERPTR_UPLOADS && 5285 sna->kgem.has_userptr && 5286 (alu != GXcopy || 5287 (box_inplace(src_pixmap, ®ion->extents) && 5288 __kgem_bo_is_busy(&sna->kgem, bo)))) { 5289 struct kgem_bo *src_bo; 5290 bool ok = false; 5291 5292 DBG(("%s: upload through a temporary map\n", 5293 __FUNCTION__)); 5294 5295 src_bo = kgem_create_map(&sna->kgem, 5296 src_pixmap->devPrivate.ptr, 5297 src_pixmap->devKind * src_pixmap->drawable.height, 5298 true); 5299 if (src_bo) { 5300 src_bo->pitch = src_pixmap->devKind; 5301 kgem_bo_mark_unreusable(src_bo); 5302 5303 ok = sna->render.copy_boxes(sna, alu, 5304 src_pixmap, src_bo, src_dx, src_dy, 5305 dst_pixmap, bo, 0, 0, 5306 box, n, COPY_LAST); 5307 5308 kgem_bo_sync__cpu(&sna->kgem, src_bo); 5309 assert(src_bo->rq == NULL); 5310 kgem_bo_destroy(&sna->kgem, src_bo); 5311 } 5312 5313 if (ok) { 5314 if (damage) 5315 sna_damage_add(damage, region); 5316 return; 5317 } 5318 } 5319 5320 if (alu != GXcopy) { 5321 PixmapPtr tmp; 5322 struct kgem_bo *src_bo; 5323 int i; 5324 5325 assert(src_pixmap->drawable.depth != 1); 5326 5327 DBG(("%s: creating temporary source upload for non-copy alu [%d]\n", 5328 __FUNCTION__, alu)); 5329 5330 tmp = sna_pixmap_create_upload(src->pScreen, 5331 region->extents.x2 - region->extents.x1, 5332 region->extents.y2 - region->extents.y1, 5333 src->depth, 5334 KGEM_BUFFER_WRITE_INPLACE); 5335 if (tmp == NullPixmap) 5336 return; 5337 5338 src_bo = __sna_pixmap_get_bo(tmp); 5339 assert(src_bo != NULL); 5340 5341 dx = -region->extents.x1; 5342 dy = -region->extents.y1; 5343 for (i = 0; i < n; i++) { 5344 assert(box[i].x1 + src_dx >= 0); 5345 assert(box[i].y1 + src_dy >= 0); 5346 assert(box[i].x2 + src_dx <= src_pixmap->drawable.width); 5347 assert(box[i].y2 + src_dy <= src_pixmap->drawable.height); 5348 5349 assert(box[i].x1 + dx >= 0); 5350 assert(box[i].y1 + dy >= 0); 5351 assert(box[i].x2 + dx <= tmp->drawable.width); 5352 assert(box[i].y2 + dy <= tmp->drawable.height); 5353 5354 assert(has_coherent_ptr(sna_pixmap(src_pixmap))); 5355 assert(has_coherent_ptr(sna_pixmap(tmp))); 5356 memcpy_blt(src_pixmap->devPrivate.ptr, 5357 tmp->devPrivate.ptr, 5358 src_pixmap->drawable.bitsPerPixel, 5359 src_pixmap->devKind, 5360 tmp->devKind, 5361 box[i].x1 + src_dx, 5362 box[i].y1 + src_dy, 5363 box[i].x1 + dx, 5364 box[i].y1 + dy, 5365 box[i].x2 - box[i].x1, 5366 box[i].y2 - box[i].y1); 5367 } 5368 5369 if (n == 1 && 5370 tmp->drawable.width == src_pixmap->drawable.width && 5371 tmp->drawable.height == src_pixmap->drawable.height) { 5372 DBG(("%s: caching upload for src bo\n", 5373 __FUNCTION__)); 5374 assert(src_priv->gpu_damage == NULL); 5375 assert(src_priv->gpu_bo == NULL); 5376 kgem_proxy_bo_attach(src_bo, &src_priv->gpu_bo); 5377 } 5378 5379 if (!sna->render.copy_boxes(sna, alu, 5380 tmp, src_bo, dx, dy, 5381 dst_pixmap, bo, 0, 0, 5382 box, n, 0)) { 5383 DBG(("%s: fallback - accelerated copy boxes failed\n", 5384 __FUNCTION__)); 5385 tmp->drawable.pScreen->DestroyPixmap(tmp); 5386 goto fallback; 5387 } 5388 tmp->drawable.pScreen->DestroyPixmap(tmp); 5389 5390 if (damage) 5391 sna_damage_add(damage, region); 5392 return; 5393 } else { 5394 DBG(("%s: dst is on the GPU, src is on the CPU, uploading into dst\n", 5395 __FUNCTION__)); 5396 5397 if (!dst_priv->pinned && replaces) { 5398 stride = src_pixmap->devKind; 5399 bits = src_pixmap->devPrivate.ptr; 5400 bits += (src_dy + box->y1) * stride + (src_dx + box->x1) * bpp / 8; 5401 5402 if (!sna_replace(sna, dst_pixmap, 5403 &dst_priv->gpu_bo, 5404 bits, stride)) 5405 goto fallback; 5406 } else { 5407 assert(!DAMAGE_IS_ALL(dst_priv->cpu_damage)); 5408 if (!sna_write_boxes(sna, dst_pixmap, 5409 dst_priv->gpu_bo, 0, 0, 5410 src_pixmap->devPrivate.ptr, 5411 src_pixmap->devKind, 5412 src_dx, src_dy, 5413 box, n)) 5414 goto fallback; 5415 } 5416 5417 assert(dst_priv->clear == false); 5418 dst_priv->cpu = false; 5419 if (damage) { 5420 assert(!dst_priv->clear); 5421 assert(dst_priv->gpu_bo); 5422 assert(dst_priv->gpu_bo->proxy == NULL); 5423 assert(*damage == dst_priv->gpu_damage); 5424 if (replaces) { 5425 sna_damage_destroy(&dst_priv->cpu_damage); 5426 sna_damage_all(&dst_priv->gpu_damage, 5427 dst_pixmap->drawable.width, 5428 dst_pixmap->drawable.height); 5429 list_del(&dst_priv->flush_list); 5430 } else 5431 sna_damage_add(&dst_priv->gpu_damage, 5432 region); 5433 assert_pixmap_damage(dst_pixmap); 5434 } 5435 } 5436 5437 return; 5438 } 5439 5440fallback: 5441 if (alu == GXcopy && src_priv && src_priv->clear) { 5442 DBG(("%s: copying clear [%08x]\n", 5443 __FUNCTION__, src_priv->clear_color)); 5444 5445 if (dst_priv) { 5446 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 5447 region, 5448 MOVE_WRITE | MOVE_INPLACE_HINT)) 5449 return; 5450 } 5451 5452 assert(dst_pixmap->devPrivate.ptr); 5453 do { 5454 pixman_fill(dst_pixmap->devPrivate.ptr, 5455 dst_pixmap->devKind/sizeof(uint32_t), 5456 dst_pixmap->drawable.bitsPerPixel, 5457 box->x1, box->y1, 5458 box->x2 - box->x1, 5459 box->y2 - box->y1, 5460 src_priv->clear_color); 5461 box++; 5462 } while (--n); 5463 } else { 5464 FbBits *dst_bits, *src_bits; 5465 int dst_stride, src_stride; 5466 5467 DBG(("%s: fallback -- src=(%d, %d), dst=(%d, %d)\n", 5468 __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy)); 5469 if (src_priv) { 5470 unsigned mode; 5471 5472 RegionTranslate(region, src_dx, src_dy); 5473 5474 assert_pixmap_contains_box(src_pixmap, 5475 RegionExtents(region)); 5476 5477 mode = MOVE_READ; 5478 if (!sna->kgem.can_blt_cpu || 5479 (src_priv->cpu_bo == NULL && 5480 (src_priv->create & KGEM_CAN_CREATE_CPU) == 0)) 5481 mode |= MOVE_INPLACE_HINT; 5482 5483 if (!sna_drawable_move_region_to_cpu(&src_pixmap->drawable, 5484 region, mode)) 5485 return; 5486 5487 RegionTranslate(region, -src_dx, -src_dy); 5488 } 5489 5490 if (dst_priv) { 5491 unsigned mode; 5492 5493 if (alu_overwrites(alu)) 5494 mode = MOVE_WRITE | MOVE_INPLACE_HINT; 5495 else 5496 mode = MOVE_WRITE | MOVE_READ; 5497 if (!sna_drawable_move_region_to_cpu(&dst_pixmap->drawable, 5498 region, mode)) 5499 return; 5500 } 5501 5502 dst_stride = dst_pixmap->devKind; 5503 src_stride = src_pixmap->devKind; 5504 5505 if (alu == GXcopy && bpp >= 8) { 5506 dst_bits = (FbBits *)dst_pixmap->devPrivate.ptr; 5507 src_bits = (FbBits *) 5508 ((char *)src_pixmap->devPrivate.ptr + 5509 src_dy * src_stride + src_dx * bpp / 8); 5510 5511 do { 5512 DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n", 5513 __FUNCTION__, 5514 box->x1, box->y1, 5515 box->x2 - box->x1, 5516 box->y2 - box->y1, 5517 src_dx, src_dy, 5518 src_stride, dst_stride)); 5519 5520 assert(box->x1 >= 0); 5521 assert(box->y1 >= 0); 5522 assert(box->x2 <= dst_pixmap->drawable.width); 5523 assert(box->y2 <= dst_pixmap->drawable.height); 5524 5525 assert(box->x1 + src_dx >= 0); 5526 assert(box->y1 + src_dy >= 0); 5527 assert(box->x2 + src_dx <= src_pixmap->drawable.width); 5528 assert(box->y2 + src_dy <= src_pixmap->drawable.height); 5529 assert(has_coherent_ptr(sna_pixmap(src_pixmap))); 5530 assert(has_coherent_ptr(sna_pixmap(dst_pixmap))); 5531 memcpy_blt(src_bits, dst_bits, bpp, 5532 src_stride, dst_stride, 5533 box->x1, box->y1, 5534 box->x1, box->y1, 5535 box->x2 - box->x1, 5536 box->y2 - box->y1); 5537 box++; 5538 } while (--n); 5539 } else { 5540 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__)); 5541 5542 RegionTranslate(region, -dst_dx, -dst_dy); 5543 5544 if (!sna_gc_move_to_cpu(gc, dst, region)) 5545 return; 5546 5547 miCopyRegion(src, dst, gc, 5548 region, dx, dy, 5549 fbCopyNtoN, 0, NULL); 5550 5551 sna_gc_move_to_gpu(gc); 5552 } 5553 } 5554} 5555 5556typedef void (*sna_copy_func)(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5557 RegionPtr region, int dx, int dy, 5558 Pixel bitPlane, void *closure); 5559 5560static inline bool box_equal(const BoxRec *a, const BoxRec *b) 5561{ 5562 return *(const uint64_t *)a == *(const uint64_t *)b; 5563} 5564 5565static RegionPtr 5566sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5567 int sx, int sy, 5568 int width, int height, 5569 int dx, int dy, 5570 sna_copy_func copy, Pixel bitPlane, void *closure) 5571{ 5572 RegionPtr clip; 5573 RegionRec region; 5574 BoxRec src_extents; 5575 bool expose; 5576 5577 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 5578 __FUNCTION__, sx, sy, dx, dy, width, height)); 5579 5580 /* Short cut for unmapped windows */ 5581 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) { 5582 DBG(("%s: unmapped\n", __FUNCTION__)); 5583 return NULL; 5584 } 5585 5586 SourceValidate(src, sx, sy, width, height, gc->subWindowMode); 5587 5588 sx += src->x; 5589 sy += src->y; 5590 5591 dx += dst->x; 5592 dy += dst->y; 5593 5594 DBG(("%s: after drawable: src=(%d, %d), dst=(%d, %d), size=(%dx%d)\n", 5595 __FUNCTION__, sx, sy, dx, dy, width, height)); 5596 5597 region.extents.x1 = dx; 5598 region.extents.y1 = dy; 5599 region.extents.x2 = bound(dx, width); 5600 region.extents.y2 = bound(dy, height); 5601 region.data = NULL; 5602 5603 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", __FUNCTION__, 5604 region.extents.x1, region.extents.y1, 5605 region.extents.x2, region.extents.y2)); 5606 5607 if (!box_intersect(®ion.extents, &gc->pCompositeClip->extents)) { 5608 DBG(("%s: dst clipped out\n", __FUNCTION__)); 5609 return NULL; 5610 } 5611 5612 region.extents.x1 = clamp(region.extents.x1, sx - dx); 5613 region.extents.x2 = clamp(region.extents.x2, sx - dx); 5614 region.extents.y1 = clamp(region.extents.y1, sy - dy); 5615 region.extents.y2 = clamp(region.extents.y2, sy - dy); 5616 5617 src_extents = region.extents; 5618 expose = gc->fExpose; 5619 5620 if (region.extents.x1 < src->x) 5621 region.extents.x1 = src->x; 5622 if (region.extents.y1 < src->y) 5623 region.extents.y1 = src->y; 5624 if (region.extents.x2 > src->x + (int) src->width) 5625 region.extents.x2 = src->x + (int) src->width; 5626 if (region.extents.y2 > src->y + (int) src->height) 5627 region.extents.y2 = src->y + (int) src->height; 5628 5629 /* Compute source clip region */ 5630 if (src->type == DRAWABLE_PIXMAP) { 5631 if (src == dst && gc->clientClipType == CT_NONE) { 5632 DBG(("%s: pixmap -- using gc clip\n", __FUNCTION__)); 5633 clip = gc->pCompositeClip; 5634 } else { 5635 DBG(("%s: pixmap -- no source clipping\n", __FUNCTION__)); 5636 expose = false; 5637 clip = NULL; 5638 } 5639 } else { 5640 WindowPtr w = (WindowPtr)src; 5641 if (gc->subWindowMode == IncludeInferiors) { 5642 DBG(("%s: window -- include inferiors\n", __FUNCTION__)); 5643 5644 assert(!w->winSize.data); 5645 box_intersect(®ion.extents, &w->winSize.extents); 5646 clip = &w->borderClip; 5647 } else { 5648 DBG(("%s: window -- clip by children\n", __FUNCTION__)); 5649 clip = &w->clipList; 5650 } 5651 } 5652 if (clip != NULL) { 5653 if (clip->data == NULL) { 5654 box_intersect(®ion.extents, &clip->extents); 5655 if (box_equal(&src_extents, ®ion.extents)) 5656 expose = false; 5657 } else 5658 RegionIntersect(®ion, ®ion, clip); 5659 } 5660 DBG(("%s: src extents (%d, %d), (%d, %d) x %ld\n", __FUNCTION__, 5661 region.extents.x1, region.extents.y1, 5662 region.extents.x2, region.extents.y2, 5663 (long)RegionNumRects(®ion))); 5664 5665 RegionTranslate(®ion, dx-sx, dy-sy); 5666 if (gc->pCompositeClip->data) 5667 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 5668 DBG(("%s: copy region (%d, %d), (%d, %d) x %ld\n", __FUNCTION__, 5669 region.extents.x1, region.extents.y1, 5670 region.extents.x2, region.extents.y2, 5671 (long)RegionNumRects(®ion))); 5672 5673 if (!box_empty(®ion.extents)) 5674 copy(src, dst, gc, ®ion, sx-dx, sy-dy, bitPlane, closure); 5675 RegionUninit(®ion); 5676 5677 /* Pixmap sources generate a NoExposed (we return NULL to do this) */ 5678 clip = NULL; 5679 if (expose) 5680 clip = miHandleExposures(src, dst, gc, 5681 sx - src->x, sy - src->y, 5682 width, height, 5683 dx - dst->x, dy - dst->y, 5684 (unsigned long) bitPlane); 5685 return clip; 5686} 5687 5688static void 5689sna_fallback_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5690 RegionPtr region, int dx, int dy, 5691 Pixel bitplane, void *closure) 5692{ 5693 DBG(("%s (boxes=%ldx[(%d, %d), (%d, %d)...], src=+(%d, %d), alu=%d\n", 5694 __FUNCTION__, (long)RegionNumRects(region), 5695 region->extents.x1, region->extents.y1, 5696 region->extents.x2, region->extents.y2, 5697 dx, dy, gc->alu)); 5698 5699 if (!sna_gc_move_to_cpu(gc, dst, region)) 5700 return; 5701 5702 RegionTranslate(region, dx, dy); 5703 if (!sna_drawable_move_region_to_cpu(src, region, MOVE_READ)) 5704 goto out_gc; 5705 RegionTranslate(region, -dx, -dy); 5706 5707 if (src == dst || 5708 get_drawable_pixmap(src) == get_drawable_pixmap(dst)) { 5709 DBG(("%s: self-copy\n", __FUNCTION__)); 5710 if (!sna_drawable_move_to_cpu(dst, MOVE_WRITE | MOVE_READ)) 5711 goto out_gc; 5712 } else { 5713 if (!sna_drawable_move_region_to_cpu(dst, region, 5714 drawable_gc_flags(dst, gc, false))) 5715 goto out_gc; 5716 } 5717 5718 miCopyRegion(src, dst, gc, 5719 region, dx, dy, 5720 fbCopyNtoN, 0, NULL); 5721 FALLBACK_FLUSH(dst); 5722out_gc: 5723 sna_gc_move_to_gpu(gc); 5724} 5725 5726static RegionPtr 5727sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc, 5728 int src_x, int src_y, 5729 int width, int height, 5730 int dst_x, int dst_y) 5731{ 5732 struct sna *sna = to_sna_from_drawable(dst); 5733 sna_copy_func copy; 5734 5735 if (gc->planemask == 0) 5736 return NULL; 5737 5738 DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx\n", 5739 __FUNCTION__, 5740 src_x, src_y, width, height, src->x, src->y, 5741 dst_x, dst_y, dst->x, dst->y, 5742 gc->alu, gc->planemask)); 5743 5744 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) || 5745 !PM_IS_SOLID(dst, gc->planemask)) 5746 copy = sna_fallback_copy_boxes; 5747 else if (src == dst) 5748 copy = sna_self_copy_boxes; 5749 else 5750 copy = sna_copy_boxes; 5751 5752 return sna_do_copy(src, dst, gc, 5753 src_x, src_y, 5754 width, height, 5755 dst_x, dst_y, 5756 copy, 0, NULL); 5757} 5758 5759static const BoxRec * 5760find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y) 5761{ 5762 const BoxRec *mid; 5763 5764 if (end == begin) 5765 return end; 5766 5767 if (end - begin == 1) { 5768 if (begin->y2 > y) 5769 return begin; 5770 else 5771 return end; 5772 } 5773 5774 mid = begin + (end - begin) / 2; 5775 if (mid->y2 > y) 5776 /* If no box is found in [begin, mid], the function 5777 * will return @mid, which is then known to be the 5778 * correct answer. 5779 */ 5780 return find_clip_box_for_y(begin, mid, y); 5781 else 5782 return find_clip_box_for_y(mid, end, y); 5783} 5784 5785struct sna_fill_spans { 5786 struct sna *sna; 5787 PixmapPtr pixmap; 5788 RegionRec region; 5789 unsigned flags; 5790 struct kgem_bo *bo; 5791 struct sna_damage **damage; 5792 int16_t dx, dy; 5793 void *op; 5794}; 5795 5796static void 5797sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc, 5798 int mode, int n, DDXPointPtr pt) 5799{ 5800 fbPolyPoint(drawable, gc, mode, n, pt, -1); 5801} 5802 5803static void 5804sna_poly_point__fill(DrawablePtr drawable, GCPtr gc, 5805 int mode, int n, DDXPointPtr pt) 5806{ 5807 struct sna_fill_spans *data = sna_gc(gc)->priv; 5808 struct sna_fill_op *op = data->op; 5809 BoxRec box[512]; 5810 DDXPointRec last; 5811 5812 DBG(("%s: count=%d\n", __FUNCTION__, n)); 5813 5814 last.x = drawable->x + data->dx; 5815 last.y = drawable->y + data->dy; 5816 while (n) { 5817 BoxRec *b = box; 5818 unsigned nbox = n; 5819 if (nbox > ARRAY_SIZE(box)) 5820 nbox = ARRAY_SIZE(box); 5821 n -= nbox; 5822 do { 5823 *(DDXPointRec *)b = *pt++; 5824 5825 b->x1 += last.x; 5826 b->y1 += last.y; 5827 if (mode == CoordModePrevious) 5828 last = *(DDXPointRec *)b; 5829 5830 b->x2 = b->x1 + 1; 5831 b->y2 = b->y1 + 1; 5832 b++; 5833 } while (--nbox); 5834 op->boxes(data->sna, op, box, b - box); 5835 } 5836} 5837 5838static void 5839sna_poly_point__gpu(DrawablePtr drawable, GCPtr gc, 5840 int mode, int n, DDXPointPtr pt) 5841{ 5842 struct sna_fill_spans *data = sna_gc(gc)->priv; 5843 struct sna_fill_op fill; 5844 BoxRec box[512]; 5845 DDXPointRec last; 5846 5847 if (!sna_fill_init_blt(&fill, 5848 data->sna, data->pixmap, 5849 data->bo, gc->alu, gc->fgPixel)) 5850 return; 5851 5852 DBG(("%s: count=%d\n", __FUNCTION__, n)); 5853 5854 last.x = drawable->x; 5855 last.y = drawable->y; 5856 while (n) { 5857 BoxRec *b = box; 5858 unsigned nbox = n; 5859 if (nbox > ARRAY_SIZE(box)) 5860 nbox = ARRAY_SIZE(box); 5861 n -= nbox; 5862 do { 5863 *(DDXPointRec *)b = *pt++; 5864 5865 b->x1 += last.x; 5866 b->y1 += last.y; 5867 if (mode == CoordModePrevious) 5868 last = *(DDXPointRec *)b; 5869 5870 if (RegionContainsPoint(&data->region, 5871 b->x1, b->y1, NULL)) { 5872 b->x1 += data->dx; 5873 b->y1 += data->dy; 5874 b->x2 = b->x1 + 1; 5875 b->y2 = b->y1 + 1; 5876 b++; 5877 } 5878 } while (--nbox); 5879 fill.boxes(data->sna, &fill, box, b - box); 5880 } 5881 fill.done(data->sna, &fill); 5882} 5883 5884static void 5885sna_poly_point__fill_clip_extents(DrawablePtr drawable, GCPtr gc, 5886 int mode, int n, DDXPointPtr pt) 5887{ 5888 struct sna_fill_spans *data = sna_gc(gc)->priv; 5889 struct sna_fill_op *op = data->op; 5890 const BoxRec *extents = &data->region.extents; 5891 BoxRec box[512], *b = box; 5892 const BoxRec *const last_box = b + ARRAY_SIZE(box); 5893 DDXPointRec last; 5894 5895 DBG(("%s: count=%d\n", __FUNCTION__, n)); 5896 5897 last.x = drawable->x + data->dx; 5898 last.y = drawable->y + data->dy; 5899 while (n--) { 5900 *(DDXPointRec *)b = *pt++; 5901 5902 b->x1 += last.x; 5903 b->y1 += last.y; 5904 if (mode == CoordModePrevious) 5905 last = *(DDXPointRec *)b; 5906 5907 if (b->x1 >= extents->x1 && b->x1 < extents->x2 && 5908 b->y1 >= extents->y1 && b->y1 < extents->y2) { 5909 b->x2 = b->x1 + 1; 5910 b->y2 = b->y1 + 1; 5911 if (++b == last_box) { 5912 op->boxes(data->sna, op, box, last_box - box); 5913 b = box; 5914 } 5915 } 5916 } 5917 if (b != box) 5918 op->boxes(data->sna, op, box, b - box); 5919} 5920 5921static void 5922sna_poly_point__fill_clip_boxes(DrawablePtr drawable, GCPtr gc, 5923 int mode, int n, DDXPointPtr pt) 5924{ 5925 struct sna_fill_spans *data = sna_gc(gc)->priv; 5926 struct sna_fill_op *op = data->op; 5927 RegionRec *clip = &data->region; 5928 BoxRec box[512], *b = box; 5929 const BoxRec *const last_box = b + ARRAY_SIZE(box); 5930 DDXPointRec last; 5931 5932 DBG(("%s: count=%d\n", __FUNCTION__, n)); 5933 5934 last.x = drawable->x + data->dx; 5935 last.y = drawable->y + data->dy; 5936 while (n--) { 5937 *(DDXPointRec *)b = *pt++; 5938 5939 b->x1 += last.x; 5940 b->y1 += last.y; 5941 if (mode == CoordModePrevious) 5942 last = *(DDXPointRec *)b; 5943 5944 if (RegionContainsPoint(clip, b->x1, b->y1, NULL)) { 5945 b->x2 = b->x1 + 1; 5946 b->y2 = b->y1 + 1; 5947 if (++b == last_box) { 5948 op->boxes(data->sna, op, box, last_box - box); 5949 b = box; 5950 } 5951 } 5952 } 5953 if (b != box) 5954 op->boxes(data->sna, op, box, b - box); 5955} 5956 5957static void 5958sna_poly_point__dash(DrawablePtr drawable, GCPtr gc, 5959 int mode, int n, DDXPointPtr pt) 5960{ 5961 struct sna_fill_spans *data = sna_gc(gc)->priv; 5962 struct sna_fill_op *op = data->op; 5963 5964 if (op->base.u.blt.pixel == gc->fgPixel) 5965 sna_poly_point__fill(drawable, gc, mode, n, pt); 5966} 5967 5968static void 5969sna_poly_point__dash_clip_extents(DrawablePtr drawable, GCPtr gc, 5970 int mode, int n, DDXPointPtr pt) 5971{ 5972 struct sna_fill_spans *data = sna_gc(gc)->priv; 5973 struct sna_fill_op *op = data->op; 5974 5975 if (op->base.u.blt.pixel == gc->fgPixel) 5976 sna_poly_point__fill_clip_extents(drawable, gc, mode, n, pt); 5977} 5978 5979static void 5980sna_poly_point__dash_clip_boxes(DrawablePtr drawable, GCPtr gc, 5981 int mode, int n, DDXPointPtr pt) 5982{ 5983 struct sna_fill_spans *data = sna_gc(gc)->priv; 5984 struct sna_fill_op *op = data->op; 5985 5986 if (op->base.u.blt.pixel == gc->fgPixel) 5987 sna_poly_point__fill_clip_boxes(drawable, gc, mode, n, pt); 5988} 5989 5990static void 5991sna_fill_spans__fill(DrawablePtr drawable, 5992 GCPtr gc, int n, 5993 DDXPointPtr pt, int *width, int sorted) 5994{ 5995 struct sna_fill_spans *data = sna_gc(gc)->priv; 5996 struct sna_fill_op *op = data->op; 5997 BoxRec box[512]; 5998 5999 DBG(("%s: alu=%d, fg=%08lx, count=%d\n", 6000 __FUNCTION__, gc->alu, gc->fgPixel, n)); 6001 6002 while (n) { 6003 BoxRec *b = box; 6004 int nbox = n; 6005 if (nbox > ARRAY_SIZE(box)) 6006 nbox = ARRAY_SIZE(box); 6007 n -= nbox; 6008 do { 6009 *(DDXPointRec *)b = *pt++; 6010 b->x2 = b->x1 + (int)*width++; 6011 b->y2 = b->y1 + 1; 6012 DBG(("%s: (%d, %d), (%d, %d)\n", 6013 __FUNCTION__, b->x1, b->y1, b->x2, b->y2)); 6014 assert(b->x1 >= drawable->x); 6015 assert(b->x2 <= drawable->x + drawable->width); 6016 assert(b->y1 >= drawable->y); 6017 assert(b->y2 <= drawable->y + drawable->height); 6018 if (b->x2 > b->x1) { 6019 if (b != box && 6020 b->y1 == b[-1].y2 && 6021 b->x1 == b[-1].x1 && 6022 b->x2 == b[-1].x2) 6023 b[-1].y2 = b->y2; 6024 else 6025 b++; 6026 } 6027 } while (--nbox); 6028 if (b != box) 6029 op->boxes(data->sna, op, box, b - box); 6030 } 6031} 6032 6033static void 6034sna_fill_spans__dash(DrawablePtr drawable, 6035 GCPtr gc, int n, 6036 DDXPointPtr pt, int *width, int sorted) 6037{ 6038 struct sna_fill_spans *data = sna_gc(gc)->priv; 6039 struct sna_fill_op *op = data->op; 6040 6041 if (op->base.u.blt.pixel == gc->fgPixel) 6042 sna_fill_spans__fill(drawable, gc, n, pt, width, sorted); 6043} 6044 6045static void 6046sna_fill_spans__fill_offset(DrawablePtr drawable, 6047 GCPtr gc, int n, 6048 DDXPointPtr pt, int *width, int sorted) 6049{ 6050 struct sna_fill_spans *data = sna_gc(gc)->priv; 6051 struct sna_fill_op *op = data->op; 6052 BoxRec box[512]; 6053 6054 DBG(("%s: alu=%d, fg=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel)); 6055 6056 while (n) { 6057 BoxRec *b = box; 6058 int nbox = n; 6059 if (nbox > ARRAY_SIZE(box)) 6060 nbox = ARRAY_SIZE(box); 6061 n -= nbox; 6062 do { 6063 *(DDXPointRec *)b = *pt++; 6064 b->x1 += data->dx; 6065 b->y1 += data->dy; 6066 b->x2 = b->x1 + (int)*width++; 6067 b->y2 = b->y1 + 1; 6068 if (b->x2 > b->x1) 6069 b++; 6070 } while (--nbox); 6071 if (b != box) 6072 op->boxes(data->sna, op, box, b - box); 6073 } 6074} 6075 6076static void 6077sna_fill_spans__dash_offset(DrawablePtr drawable, 6078 GCPtr gc, int n, 6079 DDXPointPtr pt, int *width, int sorted) 6080{ 6081 struct sna_fill_spans *data = sna_gc(gc)->priv; 6082 struct sna_fill_op *op = data->op; 6083 6084 if (op->base.u.blt.pixel == gc->fgPixel) 6085 sna_fill_spans__fill_offset(drawable, gc, n, pt, width, sorted); 6086} 6087 6088static void 6089sna_fill_spans__fill_clip_extents(DrawablePtr drawable, 6090 GCPtr gc, int n, 6091 DDXPointPtr pt, int *width, int sorted) 6092{ 6093 struct sna_fill_spans *data = sna_gc(gc)->priv; 6094 struct sna_fill_op *op = data->op; 6095 const BoxRec *extents = &data->region.extents; 6096 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 6097 6098 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 6099 __FUNCTION__, gc->alu, gc->fgPixel, n, 6100 extents->x1, extents->y1, 6101 extents->x2, extents->y2)); 6102 6103 while (n--) { 6104 DBG(("%s: [%d] pt=(%d, %d), width=%d\n", 6105 __FUNCTION__, n, pt->x, pt->y, *width)); 6106 *(DDXPointRec *)b = *pt++; 6107 b->x2 = b->x1 + (int)*width++; 6108 b->y2 = b->y1 + 1; 6109 if (box_intersect(b, extents)) { 6110 DBG(("%s: [%d] clipped=(%d, %d), (%d, %d)\n", 6111 __FUNCTION__, n, b->x1, b->y1, b->x2, b->y2)); 6112 if (data->dx|data->dy) { 6113 b->x1 += data->dx; b->x2 += data->dx; 6114 b->y1 += data->dy; b->y2 += data->dy; 6115 } 6116 if (b != box && 6117 b->y1 == b[-1].y2 && 6118 b->x1 == b[-1].x1 && 6119 b->x2 == b[-1].x2) { 6120 b[-1].y2 = b->y2; 6121 } else if (++b == last_box) { 6122 op->boxes(data->sna, op, box, last_box - box); 6123 b = box; 6124 } 6125 } 6126 } 6127 if (b != box) 6128 op->boxes(data->sna, op, box, b - box); 6129} 6130 6131static void 6132sna_fill_spans__dash_clip_extents(DrawablePtr drawable, 6133 GCPtr gc, int n, 6134 DDXPointPtr pt, int *width, int sorted) 6135{ 6136 struct sna_fill_spans *data = sna_gc(gc)->priv; 6137 struct sna_fill_op *op = data->op; 6138 6139 if (op->base.u.blt.pixel == gc->fgPixel) 6140 sna_fill_spans__fill_clip_extents(drawable, gc, n, pt, width, sorted); 6141} 6142 6143static void 6144sna_fill_spans__fill_clip_boxes(DrawablePtr drawable, 6145 GCPtr gc, int n, 6146 DDXPointPtr pt, int *width, int sorted) 6147{ 6148 struct sna_fill_spans *data = sna_gc(gc)->priv; 6149 struct sna_fill_op *op = data->op; 6150 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 6151 const BoxRec * const clip_start = RegionBoxptr(&data->region); 6152 const BoxRec * const clip_end = clip_start + data->region.data->numRects; 6153 6154 DBG(("%s: alu=%d, fg=%08lx, count=%d, extents=(%d, %d), (%d, %d)\n", 6155 __FUNCTION__, gc->alu, gc->fgPixel, n, 6156 data->region.extents.x1, data->region.extents.y1, 6157 data->region.extents.x2, data->region.extents.y2)); 6158 6159 while (n--) { 6160 int16_t X1 = pt->x; 6161 int16_t y = pt->y; 6162 int16_t X2 = X1 + (int)*width; 6163 const BoxRec *c; 6164 6165 pt++; 6166 width++; 6167 6168 if (y < data->region.extents.y1 || data->region.extents.y2 <= y) 6169 continue; 6170 6171 if (X1 < data->region.extents.x1) 6172 X1 = data->region.extents.x1; 6173 6174 if (X2 > data->region.extents.x2) 6175 X2 = data->region.extents.x2; 6176 6177 if (X1 >= X2) 6178 continue; 6179 6180 c = find_clip_box_for_y(clip_start, clip_end, y); 6181 while (c != clip_end) { 6182 if (y + 1 <= c->y1 || X2 <= c->x1) 6183 break; 6184 6185 if (X1 >= c->x2) { 6186 c++; 6187 continue; 6188 } 6189 6190 b->x1 = c->x1; 6191 b->x2 = c->x2; 6192 c++; 6193 6194 if (b->x1 < X1) 6195 b->x1 = X1; 6196 if (b->x2 > X2) 6197 b->x2 = X2; 6198 if (b->x2 <= b->x1) 6199 continue; 6200 6201 b->x1 += data->dx; 6202 b->x2 += data->dx; 6203 b->y1 = y + data->dy; 6204 b->y2 = b->y1 + 1; 6205 if (++b == last_box) { 6206 op->boxes(data->sna, op, box, last_box - box); 6207 b = box; 6208 } 6209 } 6210 } 6211 if (b != box) 6212 op->boxes(data->sna, op, box, b - box); 6213} 6214 6215static void 6216sna_fill_spans__dash_clip_boxes(DrawablePtr drawable, 6217 GCPtr gc, int n, 6218 DDXPointPtr pt, int *width, int sorted) 6219{ 6220 struct sna_fill_spans *data = sna_gc(gc)->priv; 6221 struct sna_fill_op *op = data->op; 6222 6223 if (op->base.u.blt.pixel == gc->fgPixel) 6224 sna_fill_spans__fill_clip_boxes(drawable, gc, n, pt, width, sorted); 6225} 6226 6227static bool 6228sna_fill_spans_blt(DrawablePtr drawable, 6229 struct kgem_bo *bo, struct sna_damage **damage, 6230 GCPtr gc, uint32_t pixel, 6231 int n, DDXPointPtr pt, int *width, int sorted, 6232 const BoxRec *extents, unsigned clipped) 6233{ 6234 PixmapPtr pixmap = get_drawable_pixmap(drawable); 6235 struct sna *sna = to_sna_from_pixmap(pixmap); 6236 int16_t dx, dy; 6237 struct sna_fill_op fill; 6238 BoxRec box[512], *b = box, *const last_box = box + ARRAY_SIZE(box); 6239 static void * const jump[] = { 6240 &&no_damage, 6241 &&damage, 6242 &&no_damage_clipped, 6243 &&damage_clipped, 6244 }; 6245 unsigned v; 6246 6247 DBG(("%s: alu=%d, fg=%08lx, damge=%p, clipped?=%d\n", 6248 __FUNCTION__, gc->alu, gc->fgPixel, damage, clipped)); 6249 6250 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel)) 6251 return false; 6252 6253 get_drawable_deltas(drawable, pixmap, &dx, &dy); 6254 6255 v = (damage != NULL) | clipped; 6256 goto *jump[v]; 6257 6258no_damage: 6259 if (dx|dy) { 6260 do { 6261 int nbox = n; 6262 if (nbox > last_box - box) 6263 nbox = last_box - box; 6264 n -= nbox; 6265 do { 6266 *(DDXPointRec *)b = *pt++; 6267 b->x1 += dx; 6268 b->y1 += dy; 6269 b->x2 = b->x1 + (int)*width++; 6270 b->y2 = b->y1 + 1; 6271 b++; 6272 } while (--nbox); 6273 fill.boxes(sna, &fill, box, b - box); 6274 b = box; 6275 } while (n); 6276 } else { 6277 do { 6278 int nbox = n; 6279 if (nbox > last_box - box) 6280 nbox = last_box - box; 6281 n -= nbox; 6282 do { 6283 *(DDXPointRec *)b = *pt++; 6284 b->x2 = b->x1 + (int)*width++; 6285 b->y2 = b->y1 + 1; 6286 b++; 6287 } while (--nbox); 6288 fill.boxes(sna, &fill, box, b - box); 6289 b = box; 6290 } while (n); 6291 } 6292 goto done; 6293 6294damage: 6295 do { 6296 *(DDXPointRec *)b = *pt++; 6297 b->x1 += dx; 6298 b->y1 += dy; 6299 b->x2 = b->x1 + (int)*width++; 6300 b->y2 = b->y1 + 1; 6301 6302 if (++b == last_box) { 6303 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 6304 fill.boxes(sna, &fill, box, last_box - box); 6305 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 6306 b = box; 6307 } 6308 } while (--n); 6309 if (b != box) { 6310 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 6311 fill.boxes(sna, &fill, box, b - box); 6312 sna_damage_add_boxes(damage, box, b - box, 0, 0); 6313 } 6314 goto done; 6315 6316no_damage_clipped: 6317 { 6318 RegionRec clip; 6319 6320 region_set(&clip, extents); 6321 region_maybe_clip(&clip, gc->pCompositeClip); 6322 if (RegionNil(&clip)) 6323 return true; 6324 6325 assert(dx + clip.extents.x1 >= 0); 6326 assert(dy + clip.extents.y1 >= 0); 6327 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 6328 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 6329 6330 DBG(("%s: clip %ld x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 6331 __FUNCTION__, 6332 (long)RegionNumRects(&clip), 6333 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 6334 n, pt->x, pt->y)); 6335 6336 if (clip.data == NULL) { 6337 do { 6338 *(DDXPointRec *)b = *pt++; 6339 b->x2 = b->x1 + (int)*width++; 6340 b->y2 = b->y1 + 1; 6341 6342 if (box_intersect(b, &clip.extents)) { 6343 if (dx|dy) { 6344 b->x1 += dx; b->x2 += dx; 6345 b->y1 += dy; b->y2 += dy; 6346 } 6347 if (++b == last_box) { 6348 fill.boxes(sna, &fill, box, last_box - box); 6349 b = box; 6350 } 6351 } 6352 } while (--n); 6353 } else { 6354 const BoxRec * const clip_start = RegionBoxptr(&clip); 6355 const BoxRec * const clip_end = clip_start + clip.data->numRects; 6356 do { 6357 int16_t X1 = pt->x; 6358 int16_t y = pt->y; 6359 int16_t X2 = X1 + (int)*width; 6360 const BoxRec *c; 6361 6362 pt++; 6363 width++; 6364 6365 if (y < extents->y1 || extents->y2 <= y) 6366 continue; 6367 6368 if (X1 < extents->x1) 6369 X1 = extents->x1; 6370 6371 if (X2 > extents->x2) 6372 X2 = extents->x2; 6373 6374 if (X1 >= X2) 6375 continue; 6376 6377 c = find_clip_box_for_y(clip_start, 6378 clip_end, 6379 y); 6380 while (c != clip_end) { 6381 if (y + 1 <= c->y1 || X2 <= c->x1) 6382 break; 6383 6384 if (X1 >= c->x2) { 6385 c++; 6386 continue; 6387 } 6388 6389 b->x1 = c->x1; 6390 b->x2 = c->x2; 6391 c++; 6392 6393 if (b->x1 < X1) 6394 b->x1 = X1; 6395 if (b->x2 > X2) 6396 b->x2 = X2; 6397 if (b->x2 <= b->x1) 6398 continue; 6399 6400 b->x1 += dx; 6401 b->x2 += dx; 6402 b->y1 = y + dy; 6403 b->y2 = b->y1 + 1; 6404 if (++b == last_box) { 6405 fill.boxes(sna, &fill, box, last_box - box); 6406 b = box; 6407 } 6408 } 6409 } while (--n); 6410 RegionUninit(&clip); 6411 } 6412 if (b != box) 6413 fill.boxes(sna, &fill, box, b - box); 6414 goto done; 6415 } 6416 6417damage_clipped: 6418 { 6419 RegionRec clip; 6420 6421 region_set(&clip, extents); 6422 region_maybe_clip(&clip, gc->pCompositeClip); 6423 if (RegionNil(&clip)) 6424 return true; 6425 6426 assert(dx + clip.extents.x1 >= 0); 6427 assert(dy + clip.extents.y1 >= 0); 6428 assert(dx + clip.extents.x2 <= pixmap->drawable.width); 6429 assert(dy + clip.extents.y2 <= pixmap->drawable.height); 6430 6431 DBG(("%s: clip %ld x [(%d, %d), (%d, %d)] x %d [(%d, %d)...]\n", 6432 __FUNCTION__, 6433 (long)RegionNumRects(&clip), 6434 clip.extents.x1, clip.extents.y1, clip.extents.x2, clip.extents.y2, 6435 n, pt->x, pt->y)); 6436 6437 if (clip.data == NULL) { 6438 do { 6439 *(DDXPointRec *)b = *pt++; 6440 b->x2 = b->x1 + (int)*width++; 6441 b->y2 = b->y1 + 1; 6442 6443 if (box_intersect(b, &clip.extents)) { 6444 b->x1 += dx; 6445 b->x2 += dx; 6446 b->y1 += dy; 6447 b->y2 += dy; 6448 if (++b == last_box) { 6449 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 6450 fill.boxes(sna, &fill, box, last_box - box); 6451 sna_damage_add_boxes(damage, box, b - box, 0, 0); 6452 b = box; 6453 } 6454 } 6455 } while (--n); 6456 } else { 6457 const BoxRec * const clip_start = RegionBoxptr(&clip); 6458 const BoxRec * const clip_end = clip_start + clip.data->numRects; 6459 do { 6460 int16_t X1 = pt->x; 6461 int16_t y = pt->y; 6462 int16_t X2 = X1 + (int)*width; 6463 const BoxRec *c; 6464 6465 pt++; 6466 width++; 6467 6468 if (y < extents->y1 || extents->y2 <= y) 6469 continue; 6470 6471 if (X1 < extents->x1) 6472 X1 = extents->x1; 6473 6474 if (X2 > extents->x2) 6475 X2 = extents->x2; 6476 6477 if (X1 >= X2) 6478 continue; 6479 6480 c = find_clip_box_for_y(clip_start, 6481 clip_end, 6482 y); 6483 while (c != clip_end) { 6484 if (y + 1 <= c->y1 || X2 <= c->x1) 6485 break; 6486 6487 if (X1 >= c->x2) { 6488 c++; 6489 continue; 6490 } 6491 6492 b->x1 = c->x1; 6493 b->x2 = c->x2; 6494 c++; 6495 6496 if (b->x1 < X1) 6497 b->x1 = X1; 6498 if (b->x2 > X2) 6499 b->x2 = X2; 6500 if (b->x2 <= b->x1) 6501 continue; 6502 6503 b->x1 += dx; 6504 b->x2 += dx; 6505 b->y1 = y + dy; 6506 b->y2 = b->y1 + 1; 6507 if (++b == last_box) { 6508 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 6509 fill.boxes(sna, &fill, box, last_box - box); 6510 sna_damage_add_boxes(damage, box, last_box - box, 0, 0); 6511 b = box; 6512 } 6513 } 6514 } while (--n); 6515 RegionUninit(&clip); 6516 } 6517 if (b != box) { 6518 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 6519 fill.boxes(sna, &fill, box, b - box); 6520 sna_damage_add_boxes(damage, box, b - box, 0, 0); 6521 } 6522 goto done; 6523 } 6524 6525done: 6526 fill.done(sna, &fill); 6527 assert_pixmap_damage(pixmap); 6528 return true; 6529} 6530 6531static bool 6532sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 6533 struct kgem_bo *bo, 6534 struct sna_damage **damage, 6535 GCPtr gc, int n, xRectangle *rect, 6536 const BoxRec *extents, unsigned clipped); 6537 6538static bool 6539sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 6540 struct kgem_bo *bo, 6541 struct sna_damage **damage, 6542 GCPtr gc, int n, xRectangle *rect, 6543 const BoxRec *extents, unsigned clipped); 6544 6545static inline bool 6546gc_is_solid(GCPtr gc, uint32_t *color) 6547{ 6548 if (gc->fillStyle == FillSolid || 6549 (gc->fillStyle == FillTiled && gc->tileIsPixel) || 6550 (gc->fillStyle == FillOpaqueStippled && gc->bgPixel == gc->fgPixel)) { 6551 *color = gc->fillStyle == FillTiled ? gc->tile.pixel : gc->fgPixel; 6552 return true; 6553 } 6554 6555 return false; 6556} 6557 6558static void 6559sna_fill_spans__gpu(DrawablePtr drawable, GCPtr gc, int n, 6560 DDXPointPtr pt, int *width, int sorted) 6561{ 6562 struct sna_fill_spans *data = sna_gc(gc)->priv; 6563 uint32_t color; 6564 6565 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 6566 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 6567 6568 assert(PM_IS_SOLID(drawable, gc->planemask)); 6569 if (n == 0) 6570 return; 6571 6572 /* The mi routines do not attempt to keep the spans it generates 6573 * within the clip, so we must run them through the clipper. 6574 */ 6575 6576 if (gc_is_solid(gc, &color)) { 6577 sna_fill_spans_blt(drawable, 6578 data->bo, NULL, 6579 gc, color, n, pt, width, sorted, 6580 &data->region.extents, 2); 6581 } else { 6582 /* Try converting these to a set of rectangles instead */ 6583 xRectangle *rect; 6584 int i; 6585 6586 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 6587 6588 rect = malloc (n * sizeof (xRectangle)); 6589 if (rect == NULL) 6590 return; 6591 6592 for (i = 0; i < n; i++) { 6593 rect[i].x = pt[i].x - drawable->x; 6594 rect[i].width = width[i]; 6595 rect[i].y = pt[i].y - drawable->y; 6596 rect[i].height = 1; 6597 } 6598 6599 if (gc->fillStyle == FillTiled) { 6600 (void)sna_poly_fill_rect_tiled_blt(drawable, 6601 data->bo, NULL, 6602 gc, n, rect, 6603 &data->region.extents, 2); 6604 } else { 6605 (void)sna_poly_fill_rect_stippled_blt(drawable, 6606 data->bo, NULL, 6607 gc, n, rect, 6608 &data->region.extents, 2); 6609 } 6610 free (rect); 6611 } 6612} 6613 6614static unsigned 6615sna_spans_extents(DrawablePtr drawable, GCPtr gc, 6616 int n, DDXPointPtr pt, int *width, 6617 BoxPtr out) 6618{ 6619 BoxRec box; 6620 bool clipped = false; 6621 6622 if (n == 0) 6623 return 0; 6624 6625 box.x1 = pt->x; 6626 box.x2 = box.x1 + *width; 6627 box.y2 = box.y1 = pt->y; 6628 6629 while (--n) { 6630 pt++; 6631 width++; 6632 if (box.x1 > pt->x) 6633 box.x1 = pt->x; 6634 if (box.x2 < pt->x + *width) 6635 box.x2 = pt->x + *width; 6636 6637 if (box.y1 > pt->y) 6638 box.y1 = pt->y; 6639 else if (box.y2 < pt->y) 6640 box.y2 = pt->y; 6641 } 6642 box.y2++; 6643 6644 if (gc) 6645 clipped = clip_box(&box, gc); 6646 if (box_empty(&box)) 6647 return 0; 6648 6649 *out = box; 6650 return 1 | clipped << 1; 6651} 6652 6653static void 6654sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n, 6655 DDXPointPtr pt, int *width, int sorted) 6656{ 6657 PixmapPtr pixmap = get_drawable_pixmap(drawable); 6658 struct sna *sna = to_sna_from_pixmap(pixmap); 6659 struct sna_damage **damage; 6660 struct kgem_bo *bo; 6661 RegionRec region; 6662 unsigned flags; 6663 uint32_t color; 6664 6665 DBG(("%s(n=%d, pt[0]=(%d, %d)+%d, sorted=%d\n", 6666 __FUNCTION__, n, pt[0].x, pt[0].y, width[0], sorted)); 6667 6668 flags = sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents); 6669 if (flags == 0) 6670 return; 6671 6672 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 6673 region.extents.x1, region.extents.y1, 6674 region.extents.x2, region.extents.y2)); 6675 6676 if (FORCE_FALLBACK) 6677 goto fallback; 6678 6679 if (!ACCEL_FILL_SPANS) 6680 goto fallback; 6681 6682 if (wedged(sna)) { 6683 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 6684 goto fallback; 6685 } 6686 6687 DBG(("%s: fillStyle=%x [%d], mask=%lx [%d]\n", __FUNCTION__, 6688 gc->fillStyle, gc->fillStyle == FillSolid, 6689 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 6690 if (!PM_IS_SOLID(drawable, gc->planemask)) 6691 goto fallback; 6692 6693 bo = sna_drawable_use_bo(drawable, PREFER_GPU, 6694 ®ion.extents, &damage); 6695 if (bo) { 6696 if (gc_is_solid(gc, &color)) { 6697 DBG(("%s: trying solid fill [alu=%d, pixel=%08lx] blt paths\n", 6698 __FUNCTION__, gc->alu, gc->fgPixel)); 6699 6700 sna_fill_spans_blt(drawable, 6701 bo, damage, 6702 gc, color, n, pt, width, sorted, 6703 ®ion.extents, flags & 2); 6704 } else { 6705 /* Try converting these to a set of rectangles instead */ 6706 xRectangle *rect; 6707 int i; 6708 6709 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 6710 6711 rect = malloc (n * sizeof (xRectangle)); 6712 if (rect == NULL) 6713 return; 6714 6715 for (i = 0; i < n; i++) { 6716 rect[i].x = pt[i].x - drawable->x; 6717 rect[i].width = width[i]; 6718 rect[i].y = pt[i].y - drawable->y; 6719 rect[i].height = 1; 6720 } 6721 6722 if (gc->fillStyle == FillTiled) { 6723 i = sna_poly_fill_rect_tiled_blt(drawable, 6724 bo, damage, 6725 gc, n, rect, 6726 ®ion.extents, flags & 2); 6727 } else { 6728 i = sna_poly_fill_rect_stippled_blt(drawable, 6729 bo, damage, 6730 gc, n, rect, 6731 ®ion.extents, flags & 2); 6732 } 6733 free (rect); 6734 6735 if (i) 6736 return; 6737 } 6738 } 6739 6740fallback: 6741 DBG(("%s: fallback\n", __FUNCTION__)); 6742 region.data = NULL; 6743 region_maybe_clip(®ion, gc->pCompositeClip); 6744 if (RegionNil(®ion)) 6745 return; 6746 6747 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 6748 goto out; 6749 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 6750 drawable_gc_flags(drawable, gc, n > 1))) 6751 goto out_gc; 6752 6753 DBG(("%s: fbFillSpans\n", __FUNCTION__)); 6754 fbFillSpans(drawable, gc, n, pt, width, sorted); 6755 FALLBACK_FLUSH(drawable); 6756out_gc: 6757 sna_gc_move_to_gpu(gc); 6758out: 6759 RegionUninit(®ion); 6760} 6761 6762static void 6763sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src, 6764 DDXPointPtr pt, int *width, int n, int sorted) 6765{ 6766 RegionRec region; 6767 6768 if (sna_spans_extents(drawable, gc, n, pt, width, ®ion.extents) == 0) 6769 return; 6770 6771 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 6772 region.extents.x1, region.extents.y1, 6773 region.extents.x2, region.extents.y2)); 6774 6775 if (FORCE_FALLBACK) 6776 goto fallback; 6777 6778 if (!ACCEL_SET_SPANS) 6779 goto fallback; 6780 6781fallback: 6782 region.data = NULL; 6783 region_maybe_clip(®ion, gc->pCompositeClip); 6784 if (RegionNil(®ion)) 6785 return; 6786 6787 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 6788 goto out; 6789 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 6790 drawable_gc_flags(drawable, gc, n > 1))) 6791 goto out_gc; 6792 6793 DBG(("%s: fbSetSpans\n", __FUNCTION__)); 6794 fbSetSpans(drawable, gc, src, pt, width, n, sorted); 6795 FALLBACK_FLUSH(drawable); 6796out_gc: 6797 sna_gc_move_to_gpu(gc); 6798out: 6799 RegionUninit(®ion); 6800} 6801 6802struct sna_copy_plane { 6803 struct sna_damage **damage; 6804 struct kgem_bo *bo; 6805}; 6806 6807static void 6808sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc, 6809 RegionRec *region, int sx, int sy, 6810 Pixel bitplane, void *closure) 6811{ 6812 PixmapPtr pixmap = get_drawable_pixmap(drawable); 6813 struct sna *sna = to_sna_from_pixmap(pixmap); 6814 struct sna_copy_plane *arg = closure; 6815 PixmapPtr bitmap = (PixmapPtr)_bitmap; 6816 uint32_t br00, br13; 6817 int16_t dx, dy; 6818 BoxPtr box; 6819 int n; 6820 6821 DBG(("%s: plane=%x (%d,%d),(%d,%d)x%ld\n", 6822 __FUNCTION__, (unsigned)bitplane, 6823 region->extents.x1, region->extents.y1, 6824 region->extents.x2, region->extents.y2, 6825 (long)RegionNumRects(region))); 6826 6827 box = RegionRects(region); 6828 n = RegionNumRects(region); 6829 assert(n); 6830 6831 get_drawable_deltas(drawable, pixmap, &dx, &dy); 6832 assert_pixmap_contains_boxes(pixmap, box, n, dx, dy); 6833 6834 br00 = 3 << 20; 6835 br13 = arg->bo->pitch; 6836 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 6837 br00 |= BLT_DST_TILED; 6838 br13 >>= 2; 6839 } 6840 br13 |= blt_depth(drawable->depth) << 24; 6841 br13 |= copy_ROP[gc->alu] << 16; 6842 6843 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 6844 do { 6845 int bx1 = (box->x1 + sx) & ~7; 6846 int bx2 = (box->x2 + sx + 7) & ~7; 6847 int bw = (bx2 - bx1)/8; 6848 int bh = box->y2 - box->y1; 6849 int bstride = ALIGN(bw, 2); 6850 int src_stride; 6851 uint8_t *dst, *src; 6852 uint32_t *b; 6853 6854 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 6855 __FUNCTION__, 6856 box->x1, box->y1, 6857 box->x2, box->y2, 6858 sx, sy, bx1, bx2)); 6859 6860 src_stride = bstride*bh; 6861 if (src_stride <= 128) { 6862 src_stride = ALIGN(src_stride, 8) / 4; 6863 assert(src_stride <= 32); 6864 if (!kgem_check_batch(&sna->kgem, 7+src_stride) || 6865 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 6866 !kgem_check_reloc(&sna->kgem, 1)) { 6867 kgem_submit(&sna->kgem); 6868 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 6869 return; /* XXX fallback? */ 6870 _kgem_set_mode(&sna->kgem, KGEM_BLT); 6871 } 6872 6873 b = sna->kgem.batch + sna->kgem.nbatch; 6874 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 6875 b[0] |= ((box->x1 + sx) & 7) << 17; 6876 b[1] = br13; 6877 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 6878 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 6879 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 6880 arg->bo, 6881 I915_GEM_DOMAIN_RENDER << 16 | 6882 I915_GEM_DOMAIN_RENDER | 6883 KGEM_RELOC_FENCED, 6884 0); 6885 b[5] = gc->bgPixel; 6886 b[6] = gc->fgPixel; 6887 6888 sna->kgem.nbatch += 7 + src_stride; 6889 6890 dst = (uint8_t *)&b[7]; 6891 src_stride = bitmap->devKind; 6892 src = bitmap->devPrivate.ptr; 6893 src += (box->y1 + sy) * src_stride + bx1/8; 6894 src_stride -= bstride; 6895 do { 6896 int i = bstride; 6897 do { 6898 *dst++ = byte_reverse(*src++); 6899 *dst++ = byte_reverse(*src++); 6900 i -= 2; 6901 } while (i); 6902 src += src_stride; 6903 } while (--bh); 6904 } else { 6905 struct kgem_bo *upload; 6906 void *ptr; 6907 6908 if (!kgem_check_batch(&sna->kgem, 8) || 6909 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 6910 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 6911 kgem_submit(&sna->kgem); 6912 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 6913 return; /* XXX fallback? */ 6914 _kgem_set_mode(&sna->kgem, KGEM_BLT); 6915 } 6916 6917 upload = kgem_create_buffer(&sna->kgem, 6918 bstride*bh, 6919 KGEM_BUFFER_WRITE_INPLACE, 6920 &ptr); 6921 if (!upload) 6922 break; 6923 6924 b = sna->kgem.batch + sna->kgem.nbatch; 6925 b[0] = XY_MONO_SRC_COPY | br00; 6926 b[0] |= ((box->x1 + sx) & 7) << 17; 6927 b[1] = br13; 6928 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 6929 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 6930 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 6931 arg->bo, 6932 I915_GEM_DOMAIN_RENDER << 16 | 6933 I915_GEM_DOMAIN_RENDER | 6934 KGEM_RELOC_FENCED, 6935 0); 6936 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 6937 upload, 6938 I915_GEM_DOMAIN_RENDER << 16 | 6939 KGEM_RELOC_FENCED, 6940 0); 6941 b[6] = gc->bgPixel; 6942 b[7] = gc->fgPixel; 6943 6944 sna->kgem.nbatch += 8; 6945 6946 dst = ptr; 6947 src_stride = bitmap->devKind; 6948 src = bitmap->devPrivate.ptr; 6949 src += (box->y1 + sy) * src_stride + bx1/8; 6950 src_stride -= bstride; 6951 do { 6952 int i = bstride; 6953 do { 6954 *dst++ = byte_reverse(*src++); 6955 *dst++ = byte_reverse(*src++); 6956 i -= 2; 6957 } while (i); 6958 src += src_stride; 6959 } while (--bh); 6960 6961 kgem_bo_destroy(&sna->kgem, upload); 6962 } 6963 6964 box++; 6965 } while (--n); 6966 6967 if (arg->damage) { 6968 RegionTranslate(region, dx, dy); 6969 sna_damage_add(arg->damage, region); 6970 } 6971 assert_pixmap_damage(pixmap); 6972 sna->blt_state.fill_bo = 0; 6973} 6974 6975static void 6976sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc, 6977 RegionPtr region, int sx, int sy, 6978 Pixel bitplane, void *closure) 6979{ 6980 PixmapPtr dst_pixmap = get_drawable_pixmap(drawable); 6981 PixmapPtr src_pixmap = get_drawable_pixmap(source); 6982 struct sna *sna = to_sna_from_pixmap(dst_pixmap); 6983 struct sna_copy_plane *arg = closure; 6984 int16_t dx, dy; 6985 int bit = ffs(bitplane) - 1; 6986 uint32_t br00, br13; 6987 BoxPtr box = RegionRects(region); 6988 int n = RegionNumRects(region); 6989 6990 DBG(("%s: plane=%x [%d] x%d\n", __FUNCTION__, 6991 (unsigned)bitplane, bit, n)); 6992 6993 if (n == 0) 6994 return; 6995 6996 if (get_drawable_deltas(source, src_pixmap, &dx, &dy)) 6997 sx += dx, sy += dy; 6998 6999 get_drawable_deltas(drawable, dst_pixmap, &dx, &dy); 7000 assert_pixmap_contains_boxes(dst_pixmap, box, n, dx, dy); 7001 7002 br00 = XY_MONO_SRC_COPY | 3 << 20; 7003 br13 = arg->bo->pitch; 7004 if (sna->kgem.gen >= 040 && arg->bo->tiling) { 7005 br00 |= BLT_DST_TILED; 7006 br13 >>= 2; 7007 } 7008 br13 |= blt_depth(drawable->depth) << 24; 7009 br13 |= copy_ROP[gc->alu] << 16; 7010 7011 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo); 7012 do { 7013 int bx1 = (box->x1 + sx) & ~7; 7014 int bx2 = (box->x2 + sx + 7) & ~7; 7015 int bw = (bx2 - bx1)/8; 7016 int bh = box->y2 - box->y1; 7017 int bstride = ALIGN(bw, 2); 7018 uint32_t *b; 7019 struct kgem_bo *upload; 7020 void *ptr; 7021 7022 DBG(("%s: box(%d, %d), (%d, %d), sx=(%d,%d) bx=[%d, %d]\n", 7023 __FUNCTION__, 7024 box->x1, box->y1, 7025 box->x2, box->y2, 7026 sx, sy, bx1, bx2)); 7027 7028 if (!kgem_check_batch(&sna->kgem, 8) || 7029 !kgem_check_bo_fenced(&sna->kgem, arg->bo) || 7030 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 7031 kgem_submit(&sna->kgem); 7032 if (!kgem_check_bo_fenced(&sna->kgem, arg->bo)) 7033 return; /* XXX fallback? */ 7034 _kgem_set_mode(&sna->kgem, KGEM_BLT); 7035 } 7036 7037 upload = kgem_create_buffer(&sna->kgem, 7038 bstride*bh, 7039 KGEM_BUFFER_WRITE_INPLACE, 7040 &ptr); 7041 if (!upload) 7042 break; 7043 7044 switch (source->bitsPerPixel) { 7045 case 32: 7046 { 7047 uint32_t *src = src_pixmap->devPrivate.ptr; 7048 int src_stride = src_pixmap->devKind/sizeof(uint32_t); 7049 uint8_t *dst = ptr; 7050 7051 src += (box->y1 + sy) * src_stride; 7052 src += bx1; 7053 7054 src_stride -= bw * 8; 7055 bstride -= bw; 7056 7057 do { 7058 int i = bw; 7059 do { 7060 uint8_t v = 0; 7061 7062 v |= ((*src++ >> bit) & 1) << 7; 7063 v |= ((*src++ >> bit) & 1) << 6; 7064 v |= ((*src++ >> bit) & 1) << 5; 7065 v |= ((*src++ >> bit) & 1) << 4; 7066 v |= ((*src++ >> bit) & 1) << 3; 7067 v |= ((*src++ >> bit) & 1) << 2; 7068 v |= ((*src++ >> bit) & 1) << 1; 7069 v |= ((*src++ >> bit) & 1) << 0; 7070 7071 *dst++ = v; 7072 } while (--i); 7073 dst += bstride; 7074 src += src_stride; 7075 } while (--bh); 7076 break; 7077 } 7078 case 16: 7079 { 7080 uint16_t *src = src_pixmap->devPrivate.ptr; 7081 int src_stride = src_pixmap->devKind/sizeof(uint16_t); 7082 uint8_t *dst = ptr; 7083 7084 src += (box->y1 + sy) * src_stride; 7085 src += bx1; 7086 7087 src_stride -= bw * 8; 7088 bstride -= bw; 7089 7090 do { 7091 int i = bw; 7092 do { 7093 uint8_t v = 0; 7094 7095 v |= ((*src++ >> bit) & 1) << 7; 7096 v |= ((*src++ >> bit) & 1) << 6; 7097 v |= ((*src++ >> bit) & 1) << 5; 7098 v |= ((*src++ >> bit) & 1) << 4; 7099 v |= ((*src++ >> bit) & 1) << 3; 7100 v |= ((*src++ >> bit) & 1) << 2; 7101 v |= ((*src++ >> bit) & 1) << 1; 7102 v |= ((*src++ >> bit) & 1) << 0; 7103 7104 *dst++ = v; 7105 } while (--i); 7106 dst += bstride; 7107 src += src_stride; 7108 } while (--bh); 7109 break; 7110 } 7111 default: 7112 assert(0); 7113 case 8: 7114 { 7115 uint8_t *src = src_pixmap->devPrivate.ptr; 7116 int src_stride = src_pixmap->devKind/sizeof(uint8_t); 7117 uint8_t *dst = ptr; 7118 7119 src += (box->y1 + sy) * src_stride; 7120 src += bx1; 7121 7122 src_stride -= bw * 8; 7123 bstride -= bw; 7124 7125 do { 7126 int i = bw; 7127 do { 7128 uint8_t v = 0; 7129 7130 v |= ((*src++ >> bit) & 1) << 7; 7131 v |= ((*src++ >> bit) & 1) << 6; 7132 v |= ((*src++ >> bit) & 1) << 5; 7133 v |= ((*src++ >> bit) & 1) << 4; 7134 v |= ((*src++ >> bit) & 1) << 3; 7135 v |= ((*src++ >> bit) & 1) << 2; 7136 v |= ((*src++ >> bit) & 1) << 1; 7137 v |= ((*src++ >> bit) & 1) << 0; 7138 7139 *dst++ = v; 7140 } while (--i); 7141 dst += bstride; 7142 src += src_stride; 7143 } while (--bh); 7144 break; 7145 } 7146 } 7147 7148 b = sna->kgem.batch + sna->kgem.nbatch; 7149 b[0] = br00 | ((box->x1 + sx) & 7) << 17; 7150 b[1] = br13; 7151 b[2] = (box->y1 + dy) << 16 | (box->x1 + dx); 7152 b[3] = (box->y2 + dy) << 16 | (box->x2 + dx); 7153 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 7154 arg->bo, 7155 I915_GEM_DOMAIN_RENDER << 16 | 7156 I915_GEM_DOMAIN_RENDER | 7157 KGEM_RELOC_FENCED, 7158 0); 7159 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 7160 upload, 7161 I915_GEM_DOMAIN_RENDER << 16 | 7162 KGEM_RELOC_FENCED, 7163 0); 7164 b[6] = gc->bgPixel; 7165 b[7] = gc->fgPixel; 7166 7167 sna->kgem.nbatch += 8; 7168 kgem_bo_destroy(&sna->kgem, upload); 7169 7170 box++; 7171 } while (--n); 7172 7173 if (arg->damage) { 7174 RegionTranslate(region, dx, dy); 7175 sna_damage_add(arg->damage, region); 7176 } 7177 assert_pixmap_damage(dst_pixmap); 7178 sna->blt_state.fill_bo = 0; 7179} 7180 7181static RegionPtr 7182sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc, 7183 int src_x, int src_y, 7184 int w, int h, 7185 int dst_x, int dst_y, 7186 unsigned long bit) 7187{ 7188 PixmapPtr pixmap = get_drawable_pixmap(dst); 7189 struct sna *sna = to_sna_from_pixmap(pixmap); 7190 RegionRec region, *ret = NULL; 7191 struct sna_copy_plane arg; 7192 7193 DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n", __FUNCTION__, 7194 src_x, src_y, dst_x, dst_y, w, h)); 7195 7196 if (gc->planemask == 0) 7197 goto empty; 7198 7199 if (src->bitsPerPixel == 1 && (bit&1) == 0) 7200 goto empty; 7201 7202 region.extents.x1 = dst_x + dst->x; 7203 region.extents.y1 = dst_y + dst->y; 7204 region.extents.x2 = region.extents.x1 + w; 7205 region.extents.y2 = region.extents.y1 + h; 7206 region.data = NULL; 7207 RegionIntersect(®ion, ®ion, gc->pCompositeClip); 7208 7209 DBG(("%s: dst extents (%d, %d), (%d, %d)\n", 7210 __FUNCTION__, 7211 region.extents.x1, region.extents.y1, 7212 region.extents.x2, region.extents.y2)); 7213 7214 { 7215 RegionRec clip; 7216 7217 clip.extents.x1 = src->x - (src->x + src_x) + (dst->x + dst_x); 7218 clip.extents.y1 = src->y - (src->y + src_y) + (dst->y + dst_y); 7219 clip.extents.x2 = clip.extents.x1 + src->width; 7220 clip.extents.y2 = clip.extents.y1 + src->height; 7221 clip.data = NULL; 7222 7223 DBG(("%s: src extents (%d, %d), (%d, %d)\n", 7224 __FUNCTION__, 7225 clip.extents.x1, clip.extents.y1, 7226 clip.extents.x2, clip.extents.y2)); 7227 7228 RegionIntersect(®ion, ®ion, &clip); 7229 } 7230 DBG(("%s: dst^src extents (%d, %d), (%d, %d)\n", 7231 __FUNCTION__, 7232 region.extents.x1, region.extents.y1, 7233 region.extents.x2, region.extents.y2)); 7234 if (RegionNil(®ion)) 7235 goto empty; 7236 7237 RegionTranslate(®ion, 7238 src_x - dst_x - dst->x + src->x, 7239 src_y - dst_y - dst->y + src->y); 7240 7241 if (!sna_drawable_move_region_to_cpu(src, ®ion, MOVE_READ)) 7242 goto out; 7243 7244 RegionTranslate(®ion, 7245 -(src_x - dst_x - dst->x + src->x), 7246 -(src_y - dst_y - dst->y + src->y)); 7247 7248 if (FORCE_FALLBACK) 7249 goto fallback; 7250 7251 if (!ACCEL_COPY_PLANE) 7252 goto fallback; 7253 7254 if (wedged(sna)) 7255 goto fallback; 7256 7257 if (!PM_IS_SOLID(dst, gc->planemask)) 7258 goto fallback; 7259 7260 arg.bo = sna_drawable_use_bo(dst, PREFER_GPU, 7261 ®ion.extents, &arg.damage); 7262 if (arg.bo) { 7263 if (arg.bo->tiling == I915_TILING_Y) { 7264 assert(arg.bo == __sna_pixmap_get_bo(pixmap)); 7265 arg.bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 7266 if (arg.bo == NULL) { 7267 DBG(("%s: fallback -- unable to change tiling\n", 7268 __FUNCTION__)); 7269 goto fallback; 7270 } 7271 } 7272 RegionUninit(®ion); 7273 return sna_do_copy(src, dst, gc, 7274 src_x, src_y, 7275 w, h, 7276 dst_x, dst_y, 7277 src->depth == 1 ? sna_copy_bitmap_blt : sna_copy_plane_blt, 7278 (Pixel)bit, &arg); 7279 } 7280 7281fallback: 7282 DBG(("%s: fallback\n", __FUNCTION__)); 7283 if (!sna_gc_move_to_cpu(gc, dst, ®ion)) 7284 goto out; 7285 if (!sna_drawable_move_region_to_cpu(dst, ®ion, 7286 drawable_gc_flags(dst, gc, false))) 7287 goto out_gc; 7288 7289 DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n", 7290 __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit)); 7291 ret = miDoCopy(src, dst, gc, 7292 src_x, src_y, w, h, dst_x, dst_y, 7293 src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN, 7294 bit, 0); 7295 FALLBACK_FLUSH(dst); 7296out_gc: 7297 sna_gc_move_to_gpu(gc); 7298out: 7299 RegionUninit(®ion); 7300 return ret; 7301empty: 7302 return miHandleExposures(src, dst, gc, 7303 src_x, src_y, 7304 w, h, 7305 dst_x, dst_y, bit); 7306} 7307 7308static bool 7309sna_poly_point_blt(DrawablePtr drawable, 7310 struct kgem_bo *bo, 7311 struct sna_damage **damage, 7312 GCPtr gc, int mode, int n, DDXPointPtr pt, 7313 bool clipped) 7314{ 7315 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7316 struct sna *sna = to_sna_from_pixmap(pixmap); 7317 BoxRec box[512], *b = box, * const last_box = box + ARRAY_SIZE(box); 7318 struct sna_fill_op fill; 7319 DDXPointRec last; 7320 int16_t dx, dy; 7321 7322 DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n", 7323 __FUNCTION__, gc->alu, gc->fgPixel, clipped)); 7324 7325 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel)) 7326 return false; 7327 7328 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7329 7330 last.x = drawable->x; 7331 last.y = drawable->y; 7332 7333 if (!clipped) { 7334 last.x += dx; 7335 last.y += dy; 7336 7337 assert_pixmap_contains_points(pixmap, pt, n, last.x, last.y); 7338 sna_damage_add_points(damage, pt, n, last.x, last.y); 7339 do { 7340 unsigned nbox = n; 7341 if (nbox > ARRAY_SIZE(box)) 7342 nbox = ARRAY_SIZE(box); 7343 n -= nbox; 7344 do { 7345 *(DDXPointRec *)b = *pt++; 7346 7347 b->x1 += last.x; 7348 b->y1 += last.y; 7349 if (mode == CoordModePrevious) 7350 last = *(DDXPointRec *)b; 7351 7352 b->x2 = b->x1 + 1; 7353 b->y2 = b->y1 + 1; 7354 b++; 7355 } while (--nbox); 7356 fill.boxes(sna, &fill, box, b - box); 7357 b = box; 7358 } while (n); 7359 } else { 7360 RegionPtr clip = gc->pCompositeClip; 7361 7362 while (n--) { 7363 int x, y; 7364 7365 x = pt->x; 7366 y = pt->y; 7367 pt++; 7368 if (mode == CoordModePrevious) { 7369 x += last.x; 7370 y += last.y; 7371 last.x = x; 7372 last.y = y; 7373 } else { 7374 x += drawable->x; 7375 y += drawable->y; 7376 } 7377 7378 if (RegionContainsPoint(clip, x, y, NULL)) { 7379 b->x1 = x + dx; 7380 b->y1 = y + dy; 7381 b->x2 = b->x1 + 1; 7382 b->y2 = b->y1 + 1; 7383 if (++b == last_box){ 7384 assert_pixmap_contains_boxes(pixmap, box, last_box-box, 0, 0); 7385 fill.boxes(sna, &fill, box, last_box - box); 7386 if (damage) 7387 sna_damage_add_boxes(damage, box, last_box-box, 0, 0); 7388 b = box; 7389 } 7390 } 7391 } 7392 if (b != box){ 7393 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7394 fill.boxes(sna, &fill, box, b - box); 7395 if (damage) 7396 sna_damage_add_boxes(damage, box, b-box, 0, 0); 7397 } 7398 } 7399 fill.done(sna, &fill); 7400 assert_pixmap_damage(pixmap); 7401 return true; 7402} 7403 7404static unsigned 7405sna_poly_point_extents(DrawablePtr drawable, GCPtr gc, 7406 int mode, int n, DDXPointPtr pt, BoxPtr out) 7407{ 7408 BoxRec box; 7409 bool clipped; 7410 7411 if (n == 0) 7412 return 0; 7413 7414 box.x2 = box.x1 = pt->x; 7415 box.y2 = box.y1 = pt->y; 7416 if (mode == CoordModePrevious) { 7417 DDXPointRec last = *pt++; 7418 while (--n) { 7419 last.x += pt->x; 7420 last.y += pt->y; 7421 pt++; 7422 box_add_pt(&box, last.x, last.y); 7423 } 7424 } else { 7425 while (--n) { 7426 ++pt; 7427 box_add_pt(&box, pt->x, pt->y); 7428 } 7429 } 7430 box.x2++; 7431 box.y2++; 7432 7433 clipped = trim_and_translate_box(&box, drawable, gc); 7434 if (box_empty(&box)) 7435 return 0; 7436 7437 *out = box; 7438 return 1 | clipped << 1; 7439} 7440 7441static void 7442sna_poly_point(DrawablePtr drawable, GCPtr gc, 7443 int mode, int n, DDXPointPtr pt) 7444{ 7445 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7446 struct sna *sna = to_sna_from_pixmap(pixmap); 7447 RegionRec region; 7448 unsigned flags; 7449 7450 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n", 7451 __FUNCTION__, mode, n, pt[0].x, pt[0].y)); 7452 7453 flags = sna_poly_point_extents(drawable, gc, mode, n, pt, ®ion.extents); 7454 if (flags == 0) 7455 return; 7456 7457 DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 7458 region.extents.x1, region.extents.y1, 7459 region.extents.x2, region.extents.y2, 7460 flags)); 7461 7462 if (FORCE_FALLBACK) 7463 goto fallback; 7464 7465 if (!ACCEL_POLY_POINT) 7466 goto fallback; 7467 7468 if (wedged(sna)) { 7469 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 7470 goto fallback; 7471 } 7472 7473 if (PM_IS_SOLID(drawable, gc->planemask)) { 7474 struct sna_damage **damage; 7475 struct kgem_bo *bo; 7476 7477 DBG(("%s: trying solid fill [%08lx] blt paths\n", 7478 __FUNCTION__, gc->fgPixel)); 7479 7480 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 7481 ®ion.extents, &damage)) && 7482 sna_poly_point_blt(drawable, bo, damage, 7483 gc, mode, n, pt, flags & 2)) 7484 return; 7485 } 7486 7487fallback: 7488 DBG(("%s: fallback\n", __FUNCTION__)); 7489 region.data = NULL; 7490 region_maybe_clip(®ion, gc->pCompositeClip); 7491 if (RegionNil(®ion)) 7492 return; 7493 7494 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 7495 goto out; 7496 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 7497 MOVE_READ | MOVE_WRITE)) 7498 goto out_gc; 7499 7500 DBG(("%s: fbPolyPoint\n", __FUNCTION__)); 7501 fbPolyPoint(drawable, gc, mode, n, pt, flags); 7502 FALLBACK_FLUSH(drawable); 7503out_gc: 7504 sna_gc_move_to_gpu(gc); 7505out: 7506 RegionUninit(®ion); 7507} 7508 7509static bool 7510sna_poly_zero_line_blt(DrawablePtr drawable, 7511 struct kgem_bo *bo, 7512 struct sna_damage **damage, 7513 GCPtr gc, int mode, const int _n, const DDXPointRec * const _pt, 7514 const BoxRec *extents, unsigned clipped) 7515{ 7516 static void * const _jump[] = { 7517 &&no_damage, 7518 &&damage, 7519 7520 &&no_damage_offset, 7521 &&damage_offset, 7522 }; 7523 7524 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7525 struct sna *sna = to_sna_from_pixmap(pixmap); 7526 int x2, y2, xstart, ystart, oc2; 7527 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 7528 bool degenerate = true; 7529 struct sna_fill_op fill; 7530 RegionRec clip; 7531 BoxRec box[512], *b, * const last_box = box + ARRAY_SIZE(box); 7532 const BoxRec *last_extents; 7533 int16_t dx, dy; 7534 void *jump, *ret; 7535 7536 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 7537 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 7538 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel)) 7539 return false; 7540 7541 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7542 7543 region_set(&clip, extents); 7544 if (clipped) { 7545 region_maybe_clip(&clip, gc->pCompositeClip); 7546 if (RegionNil(&clip)) 7547 return true; 7548 } 7549 7550 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 7551 DBG(("%s: [clipped=%x] extents=(%d, %d), (%d, %d), delta=(%d, %d), damage=%p\n", 7552 __FUNCTION__, clipped, 7553 clip.extents.x1, clip.extents.y1, 7554 clip.extents.x2, clip.extents.y2, 7555 dx, dy, damage)); 7556 7557 extents = RegionRects(&clip); 7558 last_extents = extents + RegionNumRects(&clip); 7559 7560 b = box; 7561 do { 7562 int n = _n; 7563 const DDXPointRec *pt = _pt; 7564 7565 xstart = pt->x + drawable->x; 7566 ystart = pt->y + drawable->y; 7567 7568 x2 = xstart; 7569 y2 = ystart; 7570 oc2 = 0; 7571 OUTCODES(oc2, x2, y2, extents); 7572 7573 while (--n) { 7574 int16_t sdx, sdy; 7575 int adx, ady, length; 7576 int e, e1, e2, e3; 7577 int x1 = x2, x; 7578 int y1 = y2, y; 7579 int oc1 = oc2; 7580 int octant; 7581 7582 ++pt; 7583 7584 x2 = pt->x; 7585 y2 = pt->y; 7586 if (mode == CoordModePrevious) { 7587 x2 += x1; 7588 y2 += y1; 7589 } else { 7590 x2 += drawable->x; 7591 y2 += drawable->y; 7592 } 7593 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 7594 __FUNCTION__, x1, y1, x2, y2)); 7595 if (x2 == x1 && y2 == y1) 7596 continue; 7597 7598 degenerate = false; 7599 7600 oc2 = 0; 7601 OUTCODES(oc2, x2, y2, extents); 7602 if (oc1 & oc2) 7603 continue; 7604 7605 CalcLineDeltas(x1, y1, x2, y2, 7606 adx, ady, sdx, sdy, 7607 1, 1, octant); 7608 7609 DBG(("%s: adx=(%d, %d), sdx=(%d, %d), oc1=%x, oc2=%x\n", 7610 __FUNCTION__, adx, ady, sdx, sdy, oc1, oc2)); 7611 if (adx == 0 || ady == 0) { 7612 if (x1 <= x2) { 7613 b->x1 = x1; 7614 b->x2 = x2; 7615 } else { 7616 b->x1 = x2; 7617 b->x2 = x1; 7618 } 7619 if (y1 <= y2) { 7620 b->y1 = y1; 7621 b->y2 = y2; 7622 } else { 7623 b->y1 = y2; 7624 b->y2 = y1; 7625 } 7626 b->x2++; 7627 b->y2++; 7628 if (oc1 | oc2) { 7629 bool intersects; 7630 7631 intersects = box_intersect(b, extents); 7632 assert(intersects); 7633 } 7634 if (++b == last_box) { 7635 ret = &&rectangle_continue; 7636 goto *jump; 7637rectangle_continue: 7638 b = box; 7639 } 7640 } else if (adx >= ady) { 7641 int x2_clipped = x2, y2_clipped = y2; 7642 bool dirty; 7643 7644 /* X-major segment */ 7645 e1 = ady << 1; 7646 e2 = e1 - (adx << 1); 7647 e = e1 - adx; 7648 length = adx; 7649 7650 FIXUP_ERROR(e, octant, bias); 7651 7652 x = x1; 7653 y = y1; 7654 7655 if (oc1 | oc2) { 7656 int pt1_clipped, pt2_clipped; 7657 7658 if (miZeroClipLine(extents->x1, extents->y1, 7659 extents->x2-1, extents->y2-1, 7660 &x, &y, &x2_clipped, &y2_clipped, 7661 adx, ady, 7662 &pt1_clipped, &pt2_clipped, 7663 octant, bias, oc1, oc2) == -1) 7664 continue; 7665 7666 length = abs(x2_clipped - x); 7667 if (length == 0) 7668 continue; 7669 7670 if (pt1_clipped) { 7671 int clipdx = abs(x - x1); 7672 int clipdy = abs(y - y1); 7673 e += clipdy * e2 + (clipdx - clipdy) * e1; 7674 } 7675 } 7676 7677 e3 = e2 - e1; 7678 e = e - e1; 7679 7680 b->x1 = x; 7681 b->y1 = y; 7682 dirty = false; 7683 while (length--) { 7684 e += e1; 7685 dirty = true; 7686 if (e >= 0) { 7687 e += e3; 7688 7689 if (sdx < 0) { 7690 b->x2 = b->x1 + 1; 7691 b->x1 = x; 7692 } else 7693 b->x2 = x + 1; 7694 b->y2 = b->y1 + 1; 7695 7696 if (++b == last_box) { 7697 ret = &&X_continue; 7698 goto *jump; 7699X_continue: 7700 b = box; 7701 } 7702 7703 b->x1 = x + sdx; 7704 b->y1 = y += sdy; 7705 dirty = false; 7706 } 7707 x += sdx; 7708 } 7709 if (dirty) { 7710 x -= sdx; 7711 if (sdx < 0) { 7712 b->x2 = b->x1 + 1; 7713 b->x1 = x; 7714 } else 7715 b->x2 = x + 1; 7716 b->y2 = b->y1 + 1; 7717 7718 if (++b == last_box) { 7719 ret = &&X2_continue; 7720 goto *jump; 7721X2_continue: 7722 b = box; 7723 } 7724 } 7725 } else { 7726 int x2_clipped = x2, y2_clipped = y2; 7727 bool dirty; 7728 7729 /* Y-major segment */ 7730 e1 = adx << 1; 7731 e2 = e1 - (ady << 1); 7732 e = e1 - ady; 7733 length = ady; 7734 7735 SetYMajorOctant(octant); 7736 FIXUP_ERROR(e, octant, bias); 7737 7738 x = x1; 7739 y = y1; 7740 7741 if (oc1 | oc2) { 7742 int pt1_clipped, pt2_clipped; 7743 7744 if (miZeroClipLine(extents->x1, extents->y1, 7745 extents->x2-1, extents->y2-1, 7746 &x, &y, &x2_clipped, &y2_clipped, 7747 adx, ady, 7748 &pt1_clipped, &pt2_clipped, 7749 octant, bias, oc1, oc2) == -1) 7750 continue; 7751 7752 length = abs(y2_clipped - y); 7753 if (length == 0) 7754 continue; 7755 7756 if (pt1_clipped) { 7757 int clipdx = abs(x - x1); 7758 int clipdy = abs(y - y1); 7759 e += clipdx * e2 + (clipdy - clipdx) * e1; 7760 } 7761 } 7762 7763 e3 = e2 - e1; 7764 e = e - e1; 7765 7766 b->x1 = x; 7767 b->y1 = y; 7768 dirty = false; 7769 while (length--) { 7770 e += e1; 7771 dirty = true; 7772 if (e >= 0) { 7773 e += e3; 7774 7775 if (sdy < 0) { 7776 b->y2 = b->y1 + 1; 7777 b->y1 = y; 7778 } else 7779 b->y2 = y + 1; 7780 b->x2 = x + 1; 7781 7782 if (++b == last_box) { 7783 ret = &&Y_continue; 7784 goto *jump; 7785Y_continue: 7786 b = box; 7787 } 7788 7789 b->x1 = x += sdx; 7790 b->y1 = y + sdy; 7791 dirty = false; 7792 } 7793 y += sdy; 7794 } 7795 7796 if (dirty) { 7797 y -= sdy; 7798 if (sdy < 0) { 7799 b->y2 = b->y1 + 1; 7800 b->y1 = y; 7801 } else 7802 b->y2 = y + 1; 7803 b->x2 = x + 1; 7804 7805 if (++b == last_box) { 7806 ret = &&Y2_continue; 7807 goto *jump; 7808Y2_continue: 7809 b = box; 7810 } 7811 } 7812 } 7813 } 7814 7815#if 0 7816 /* Only do the CapNotLast check on the last segment 7817 * and only if the endpoint wasn't clipped. And then, if the last 7818 * point is the same as the first point, do not draw it, unless the 7819 * line is degenerate 7820 */ 7821 if (!pt2_clipped && 7822 gc->capStyle != CapNotLast && 7823 !(xstart == x2 && ystart == y2 && !degenerate)) 7824 { 7825 b->x2 = x2; 7826 b->y2 = y2; 7827 if (b->x2 < b->x1) { 7828 int16_t t = b->x1; 7829 b->x1 = b->x2; 7830 b->x2 = t; 7831 } 7832 if (b->y2 < b->y1) { 7833 int16_t t = b->y1; 7834 b->y1 = b->y2; 7835 b->y2 = t; 7836 } 7837 b->x2++; 7838 b->y2++; 7839 b++; 7840 } 7841#endif 7842 } while (++extents != last_extents); 7843 7844 if (b != box) { 7845 ret = &&done; 7846 goto *jump; 7847 } 7848 7849done: 7850 fill.done(sna, &fill); 7851 assert_pixmap_damage(pixmap); 7852 RegionUninit(&clip); 7853 return true; 7854 7855damage: 7856 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7857 sna_damage_add_boxes(damage, box, b-box, 0, 0); 7858no_damage: 7859 fill.boxes(sna, &fill, box, b-box); 7860 goto *ret; 7861 7862no_damage_offset: 7863 { 7864 BoxRec *bb = box; 7865 do { 7866 bb->x1 += dx; 7867 bb->x2 += dx; 7868 bb->y1 += dy; 7869 bb->y2 += dy; 7870 } while (++bb != b); 7871 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7872 fill.boxes(sna, &fill, box, b - box); 7873 } 7874 goto *ret; 7875 7876damage_offset: 7877 { 7878 BoxRec *bb = box; 7879 do { 7880 bb->x1 += dx; 7881 bb->x2 += dx; 7882 bb->y1 += dy; 7883 bb->y2 += dy; 7884 } while (++bb != b); 7885 assert_pixmap_contains_boxes(pixmap, box, b-box, 0, 0); 7886 fill.boxes(sna, &fill, box, b - box); 7887 sna_damage_add_boxes(damage, box, b - box, 0, 0); 7888 } 7889 goto *ret; 7890} 7891 7892static bool 7893sna_poly_line_blt(DrawablePtr drawable, 7894 struct kgem_bo *bo, 7895 struct sna_damage **damage, 7896 GCPtr gc, uint32_t pixel, 7897 int mode, int n, DDXPointPtr pt, 7898 const BoxRec *extents, bool clipped) 7899{ 7900 PixmapPtr pixmap = get_drawable_pixmap(drawable); 7901 struct sna *sna = to_sna_from_pixmap(pixmap); 7902 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 7903 struct sna_fill_op fill; 7904 DDXPointRec last; 7905 int16_t dx, dy; 7906 7907 DBG(("%s: alu=%d, fg=%08x\n", __FUNCTION__, gc->alu, (unsigned)pixel)); 7908 7909 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel)) 7910 return false; 7911 7912 get_drawable_deltas(drawable, pixmap, &dx, &dy); 7913 7914 if (!clipped) { 7915 dx += drawable->x; 7916 dy += drawable->y; 7917 7918 last.x = pt->x + dx; 7919 last.y = pt->y + dy; 7920 pt++; 7921 7922 while (--n) { 7923 DDXPointRec p; 7924 7925 p = *pt++; 7926 if (mode == CoordModePrevious) { 7927 p.x += last.x; 7928 p.y += last.y; 7929 } else { 7930 p.x += dx; 7931 p.y += dy; 7932 } 7933 if (last.x == p.x) { 7934 b->x1 = last.x; 7935 b->x2 = last.x + 1; 7936 } else if (last.x < p.x) { 7937 b->x1 = last.x; 7938 b->x2 = p.x; 7939 } else { 7940 b->x1 = p.x; 7941 b->x2 = last.x; 7942 } 7943 if (last.y == p.y) { 7944 b->y1 = last.y; 7945 b->y2 = last.y + 1; 7946 } else if (last.y < p.y) { 7947 b->y1 = last.y; 7948 b->y2 = p.y; 7949 } else { 7950 b->y1 = p.y; 7951 b->y2 = last.y; 7952 } 7953 b->y2 += last.x == p.x; 7954 b->x2 += last.y == p.y; 7955 DBG(("%s: blt (%d, %d), (%d, %d)\n", 7956 __FUNCTION__, 7957 b->x1, b->y1, b->x2, b->y2)); 7958 if (++b == last_box) { 7959 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 7960 fill.boxes(sna, &fill, boxes, last_box - boxes); 7961 if (damage) 7962 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 7963 b = boxes; 7964 } 7965 7966 last = p; 7967 } 7968 } else { 7969 RegionRec clip; 7970 7971 region_set(&clip, extents); 7972 region_maybe_clip(&clip, gc->pCompositeClip); 7973 if (RegionNil(&clip)) 7974 return true; 7975 7976 last.x = pt->x + drawable->x; 7977 last.y = pt->y + drawable->y; 7978 pt++; 7979 7980 if (clip.data == NULL) { 7981 while (--n) { 7982 DDXPointRec p; 7983 7984 p = *pt++; 7985 if (mode == CoordModePrevious) { 7986 p.x += last.x; 7987 p.y += last.y; 7988 } else { 7989 p.x += drawable->x; 7990 p.y += drawable->y; 7991 } 7992 if (last.x == p.x) { 7993 b->x1 = last.x; 7994 b->x2 = last.x + 1; 7995 } else if (last.x < p.x) { 7996 b->x1 = last.x; 7997 b->x2 = p.x; 7998 } else { 7999 b->x1 = p.x; 8000 b->x2 = last.x; 8001 } 8002 if (last.y == p.y) { 8003 b->y1 = last.y; 8004 b->y2 = last.y + 1; 8005 } else if (last.y < p.y) { 8006 b->y1 = last.y; 8007 b->y2 = p.y; 8008 } else { 8009 b->y1 = p.y; 8010 b->y2 = last.y; 8011 } 8012 b->y2 += last.x == p.x; 8013 b->x2 += last.y == p.y; 8014 DBG(("%s: blt (%d, %d), (%d, %d)\n", 8015 __FUNCTION__, 8016 b->x1, b->y1, b->x2, b->y2)); 8017 if (box_intersect(b, &clip.extents)) { 8018 b->x1 += dx; 8019 b->x2 += dx; 8020 b->y1 += dy; 8021 b->y2 += dy; 8022 if (++b == last_box) { 8023 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 8024 fill.boxes(sna, &fill, boxes, last_box - boxes); 8025 if (damage) 8026 sna_damage_add_boxes(damage, boxes, last_box - boxes, 0, 0); 8027 b = boxes; 8028 } 8029 } 8030 8031 last = p; 8032 } 8033 } else { 8034 const BoxRec * const clip_start = RegionBoxptr(&clip); 8035 const BoxRec * const clip_end = clip_start + clip.data->numRects; 8036 const BoxRec *c; 8037 8038 while (--n) { 8039 DDXPointRec p; 8040 BoxRec box; 8041 8042 p = *pt++; 8043 if (mode == CoordModePrevious) { 8044 p.x += last.x; 8045 p.y += last.y; 8046 } else { 8047 p.x += drawable->x; 8048 p.y += drawable->y; 8049 } 8050 if (last.x == p.x) { 8051 box.x1 = last.x; 8052 box.x2 = last.x + 1; 8053 } else if (last.x < p.x) { 8054 box.x1 = last.x; 8055 box.x2 = p.x; 8056 } else { 8057 box.x1 = p.x; 8058 box.x2 = last.x; 8059 } 8060 if (last.y == p.y) { 8061 box.y1 = last.y; 8062 box.y2 = last.y + 1; 8063 } else if (last.y < p.y) { 8064 box.y1 = last.y; 8065 box.y2 = p.y; 8066 } else { 8067 box.y1 = p.y; 8068 box.y2 = last.y; 8069 } 8070 b->y2 += last.x == p.x; 8071 b->x2 += last.y == p.y; 8072 DBG(("%s: blt (%d, %d), (%d, %d)\n", 8073 __FUNCTION__, 8074 box.x1, box.y1, box.x2, box.y2)); 8075 8076 c = find_clip_box_for_y(clip_start, 8077 clip_end, 8078 box.y1); 8079 while (c != clip_end) { 8080 if (box.y2 <= c->y1) 8081 break; 8082 8083 *b = box; 8084 if (box_intersect(b, c++)) { 8085 b->x1 += dx; 8086 b->x2 += dx; 8087 b->y1 += dy; 8088 b->y2 += dy; 8089 if (++b == last_box) { 8090 assert_pixmap_contains_boxes(pixmap, boxes, last_box-boxes, 0, 0); 8091 fill.boxes(sna, &fill, boxes, last_box-boxes); 8092 if (damage) 8093 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 8094 b = boxes; 8095 } 8096 } 8097 } 8098 8099 last = p; 8100 } 8101 } 8102 RegionUninit(&clip); 8103 } 8104 if (b != boxes) { 8105 assert_pixmap_contains_boxes(pixmap, boxes, b-boxes, 0, 0); 8106 fill.boxes(sna, &fill, boxes, b - boxes); 8107 if (damage) 8108 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 8109 } 8110 fill.done(sna, &fill); 8111 assert_pixmap_damage(pixmap); 8112 return true; 8113} 8114 8115static unsigned 8116sna_poly_line_extents(DrawablePtr drawable, GCPtr gc, 8117 int mode, int n, DDXPointPtr pt, 8118 BoxPtr out) 8119{ 8120 BoxRec box; 8121 bool clip, blt = true; 8122 8123 if (n == 0) 8124 return 0; 8125 8126 box.x2 = box.x1 = pt->x; 8127 box.y2 = box.y1 = pt->y; 8128 if (mode == CoordModePrevious) { 8129 int x = box.x1; 8130 int y = box.y1; 8131 while (--n) { 8132 pt++; 8133 x += pt->x; 8134 y += pt->y; 8135 if (blt) 8136 blt &= pt->x == 0 || pt->y == 0; 8137 box_add_pt(&box, x, y); 8138 } 8139 } else { 8140 int x = box.x1; 8141 int y = box.y1; 8142 while (--n) { 8143 pt++; 8144 if (blt) { 8145 blt &= pt->x == x || pt->y == y; 8146 x = pt->x; 8147 y = pt->y; 8148 } 8149 box_add_pt(&box, pt->x, pt->y); 8150 } 8151 } 8152 box.x2++; 8153 box.y2++; 8154 8155 if (gc->lineWidth) { 8156 int extra = gc->lineWidth >> 1; 8157 if (n > 1) { 8158 if (gc->joinStyle == JoinMiter) 8159 extra = 6 * gc->lineWidth; 8160 else if (gc->capStyle == CapProjecting) 8161 extra = gc->lineWidth; 8162 } 8163 if (extra) { 8164 box.x1 -= extra; 8165 box.x2 += extra; 8166 box.y1 -= extra; 8167 box.y2 += extra; 8168 } 8169 } 8170 8171 clip = trim_and_translate_box(&box, drawable, gc); 8172 if (box_empty(&box)) 8173 return 0; 8174 8175 *out = box; 8176 return 1 | blt << 2 | clip << 1; 8177} 8178 8179/* Only use our spans code if the destination is busy and we can't perform 8180 * the operation in place. 8181 * 8182 * Currently it looks to be faster to use the GPU for zero spans on all 8183 * platforms. 8184 */ 8185inline static int 8186_use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 8187{ 8188 if (USE_ZERO_SPANS) 8189 return USE_ZERO_SPANS > 0; 8190 8191 return !drawable_gc_inplace_hint(drawable, gc); 8192} 8193 8194static int 8195use_zero_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 8196{ 8197 bool ret = _use_zero_spans(drawable, gc, extents); 8198 DBG(("%s? %d\n", __FUNCTION__, ret)); 8199 return ret; 8200} 8201 8202/* Only use our spans code if the destination is busy and we can't perform 8203 * the operation in place. 8204 * 8205 * Currently it looks to be faster to use the CPU for wide spans on all 8206 * platforms, slow MI code. But that does not take into account the true 8207 * cost of readback? 8208 */ 8209inline static int 8210_use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 8211{ 8212 if (USE_WIDE_SPANS) 8213 return USE_WIDE_SPANS > 0; 8214 8215 return !drawable_gc_inplace_hint(drawable, gc); 8216} 8217 8218static int 8219use_wide_spans(DrawablePtr drawable, GCPtr gc, const BoxRec *extents) 8220{ 8221 int ret = _use_wide_spans(drawable, gc, extents); 8222 DBG(("%s? %d\n", __FUNCTION__, ret)); 8223 return ret; 8224} 8225 8226static void 8227sna_poly_line(DrawablePtr drawable, GCPtr gc, 8228 int mode, int n, DDXPointPtr pt) 8229{ 8230 struct sna_pixmap *priv; 8231 struct sna_fill_spans data; 8232 uint32_t color; 8233 8234 DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n", 8235 __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth)); 8236 8237 data.flags = sna_poly_line_extents(drawable, gc, mode, n, pt, 8238 &data.region.extents); 8239 if (data.flags == 0) 8240 return; 8241 8242 DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__, 8243 data.region.extents.x1, data.region.extents.y1, 8244 data.region.extents.x2, data.region.extents.y2)); 8245 8246 data.region.data = NULL; 8247 8248 if (FORCE_FALLBACK) 8249 goto fallback; 8250 8251 if (!ACCEL_POLY_LINE) 8252 goto fallback; 8253 8254 data.pixmap = get_drawable_pixmap(drawable); 8255 data.sna = to_sna_from_pixmap(data.pixmap); 8256 if (wedged(data.sna)) { 8257 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 8258 goto fallback; 8259 } 8260 8261 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 8262 __FUNCTION__, 8263 gc->fillStyle, gc->fillStyle == FillSolid, 8264 gc->lineStyle, gc->lineStyle == LineSolid, 8265 gc->lineWidth, 8266 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 8267 data.flags & 4)); 8268 8269 if (!PM_IS_SOLID(drawable, gc->planemask)) 8270 goto fallback; 8271 8272 priv = sna_pixmap(data.pixmap); 8273 if (!priv) { 8274 DBG(("%s: not attached to pixmap %ld\n", 8275 __FUNCTION__, data.pixmap->drawable.serialNumber)); 8276 goto fallback; 8277 } 8278 8279 if (gc->lineStyle != LineSolid) { 8280 DBG(("%s: lineStyle, %d, is not solid\n", 8281 __FUNCTION__, gc->lineStyle)); 8282 goto spans_fallback; 8283 } 8284 if (!(gc->lineWidth == 0 || 8285 (gc->lineWidth == 1 && (n == 1 || gc->alu == GXcopy)))) { 8286 DBG(("%s: non-zero lineWidth %d\n", 8287 __FUNCTION__, gc->lineWidth)); 8288 goto spans_fallback; 8289 } 8290 8291 if (gc_is_solid(gc, &color)) { 8292 DBG(("%s: trying solid fill [%08x]\n", 8293 __FUNCTION__, (unsigned)color)); 8294 8295 if (data.flags & 4) { 8296 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8297 &data.region.extents, 8298 &data.damage); 8299 if (data.bo && 8300 sna_poly_line_blt(drawable, 8301 data.bo, data.damage, 8302 gc, color, mode, n, pt, 8303 &data.region.extents, 8304 data.flags & 2)) 8305 return; 8306 } else { /* !rectilinear */ 8307 if ((data.bo = sna_drawable_use_bo(drawable, 8308 use_zero_spans(drawable, gc, &data.region.extents), 8309 &data.region.extents, 8310 &data.damage)) && 8311 sna_poly_zero_line_blt(drawable, 8312 data.bo, data.damage, 8313 gc, mode, n, pt, 8314 &data.region.extents, 8315 data.flags & 2)) 8316 return; 8317 8318 } 8319 } else if (data.flags & 4) { 8320 /* Try converting these to a set of rectangles instead */ 8321 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 8322 &data.region.extents, &data.damage); 8323 if (data.bo) { 8324 DDXPointRec p1, p2; 8325 xRectangle *rect; 8326 int i; 8327 8328 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 8329 8330 rect = malloc (n * sizeof (xRectangle)); 8331 if (rect == NULL) 8332 return; 8333 8334 p1 = pt[0]; 8335 for (i = 1; i < n; i++) { 8336 if (mode == CoordModePrevious) { 8337 p2.x = p1.x + pt[i].x; 8338 p2.y = p1.y + pt[i].y; 8339 } else 8340 p2 = pt[i]; 8341 if (p1.x < p2.x) { 8342 rect[i].x = p1.x; 8343 rect[i].width = p2.x - p1.x + 1; 8344 } else if (p1.x > p2.x) { 8345 rect[i].x = p2.x; 8346 rect[i].width = p1.x - p2.x + 1; 8347 } else { 8348 rect[i].x = p1.x; 8349 rect[i].width = 1; 8350 } 8351 if (p1.y < p2.y) { 8352 rect[i].y = p1.y; 8353 rect[i].height = p2.y - p1.y + 1; 8354 } else if (p1.y > p2.y) { 8355 rect[i].y = p2.y; 8356 rect[i].height = p1.y - p2.y + 1; 8357 } else { 8358 rect[i].y = p1.y; 8359 rect[i].height = 1; 8360 } 8361 8362 /* don't paint last pixel */ 8363 if (gc->capStyle == CapNotLast) { 8364 if (p1.x == p2.x) 8365 rect[i].height--; 8366 else 8367 rect[i].width--; 8368 } 8369 p1 = p2; 8370 } 8371 8372 if (gc->fillStyle == FillTiled) { 8373 i = sna_poly_fill_rect_tiled_blt(drawable, 8374 data.bo, data.damage, 8375 gc, n - 1, rect + 1, 8376 &data.region.extents, 8377 data.flags & 2); 8378 } else { 8379 i = sna_poly_fill_rect_stippled_blt(drawable, 8380 data.bo, data.damage, 8381 gc, n - 1, rect + 1, 8382 &data.region.extents, 8383 data.flags & 2); 8384 } 8385 free (rect); 8386 8387 if (i) 8388 return; 8389 } 8390 } 8391 8392spans_fallback: 8393 if ((data.bo = sna_drawable_use_bo(drawable, 8394 use_wide_spans(drawable, gc, &data.region.extents), 8395 &data.region.extents, &data.damage))) { 8396 DBG(("%s: converting line into spans\n", __FUNCTION__)); 8397 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 8398 sna_gc(gc)->priv = &data; 8399 8400 if (gc->lineWidth == 0 && gc_is_solid(gc, &color)) { 8401 struct sna_fill_op fill; 8402 8403 if (gc->lineStyle == LineSolid) { 8404 if (!sna_fill_init_blt(&fill, 8405 data.sna, data.pixmap, 8406 data.bo, gc->alu, color)) 8407 goto fallback; 8408 8409 data.op = &fill; 8410 8411 if ((data.flags & 2) == 0) { 8412 if (data.dx | data.dy) 8413 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 8414 else 8415 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 8416 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 8417 } else { 8418 region_maybe_clip(&data.region, 8419 gc->pCompositeClip); 8420 if (RegionNil(&data.region)) 8421 return; 8422 8423 if (region_is_singular(&data.region)) { 8424 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 8425 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 8426 } else { 8427 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 8428 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 8429 } 8430 } 8431 assert(gc->miTranslate); 8432 8433 gc->ops = &sna_gc_ops__tmp; 8434 DBG(("%s: miZeroLine (solid fill)\n", __FUNCTION__)); 8435 miZeroLine(drawable, gc, mode, n, pt); 8436 fill.done(data.sna, &fill); 8437 } else { 8438 data.op = &fill; 8439 8440 if ((data.flags & 2) == 0) { 8441 if (data.dx | data.dy) 8442 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_offset; 8443 else 8444 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash; 8445 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash; 8446 } else { 8447 region_maybe_clip(&data.region, 8448 gc->pCompositeClip); 8449 if (RegionNil(&data.region)) 8450 return; 8451 8452 if (region_is_singular(&data.region)) { 8453 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_extents; 8454 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_extents; 8455 } else { 8456 sna_gc_ops__tmp.FillSpans = sna_fill_spans__dash_clip_boxes; 8457 sna_gc_ops__tmp.PolyPoint = sna_poly_point__dash_clip_boxes; 8458 } 8459 } 8460 assert(gc->miTranslate); 8461 8462 DBG(("%s: miZeroLine (solid dash)\n", __FUNCTION__)); 8463 if (!sna_fill_init_blt(&fill, 8464 data.sna, data.pixmap, 8465 data.bo, gc->alu, color)) 8466 goto fallback; 8467 8468 gc->ops = &sna_gc_ops__tmp; 8469 miZeroDashLine(drawable, gc, mode, n, pt); 8470 fill.done(data.sna, &fill); 8471 8472 if (sna_fill_init_blt(&fill, 8473 data.sna, data.pixmap, 8474 data.bo, gc->alu, 8475 gc->bgPixel)) { 8476 miZeroDashLine(drawable, gc, mode, n, pt); 8477 fill.done(data.sna, &fill); 8478 } 8479 } 8480 } else { 8481 /* Note that the WideDash functions alternate 8482 * between filling using fgPixel and bgPixel 8483 * so we need to reset state between FillSpans and 8484 * cannot use the fill fast paths. 8485 */ 8486 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 8487 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 8488 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 8489 gc->ops = &sna_gc_ops__tmp; 8490 8491 switch (gc->lineStyle) { 8492 default: 8493 assert(0); 8494 case LineSolid: 8495 if (gc->lineWidth == 0) { 8496 DBG(("%s: miZeroLine\n", __FUNCTION__)); 8497 miZeroLine(drawable, gc, mode, n, pt); 8498 } else { 8499 DBG(("%s: miWideLine\n", __FUNCTION__)); 8500 miWideLine(drawable, gc, mode, n, pt); 8501 } 8502 break; 8503 case LineOnOffDash: 8504 case LineDoubleDash: 8505 if (gc->lineWidth == 0) { 8506 DBG(("%s: miZeroDashLine\n", __FUNCTION__)); 8507 miZeroDashLine(drawable, gc, mode, n, pt); 8508 } else { 8509 DBG(("%s: miWideDash\n", __FUNCTION__)); 8510 miWideDash(drawable, gc, mode, n, pt); 8511 } 8512 break; 8513 } 8514 } 8515 8516 gc->ops = (GCOps *)&sna_gc_ops; 8517 if (data.damage) { 8518 if (data.dx | data.dy) 8519 pixman_region_translate(&data.region, data.dx, data.dy); 8520 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 8521 sna_damage_add(data.damage, &data.region); 8522 assert_pixmap_damage(data.pixmap); 8523 } 8524 RegionUninit(&data.region); 8525 return; 8526 } 8527 8528fallback: 8529 DBG(("%s: fallback\n", __FUNCTION__)); 8530 region_maybe_clip(&data.region, gc->pCompositeClip); 8531 if (RegionNil(&data.region)) 8532 return; 8533 8534 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 8535 goto out; 8536 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 8537 drawable_gc_flags(drawable, gc, 8538 !(data.flags & 4 && n == 2)))) 8539 goto out_gc; 8540 8541 DBG(("%s: fbPolyLine\n", __FUNCTION__)); 8542 fbPolyLine(drawable, gc, mode, n, pt); 8543 FALLBACK_FLUSH(drawable); 8544 8545out_gc: 8546 sna_gc_move_to_gpu(gc); 8547out: 8548 RegionUninit(&data.region); 8549} 8550 8551static inline void box_from_seg(BoxPtr b, xSegment *seg, GCPtr gc) 8552{ 8553 if (seg->x1 == seg->x2) { 8554 if (seg->y1 > seg->y2) { 8555 b->y2 = seg->y1 + 1; 8556 b->y1 = seg->y2 + 1; 8557 if (gc->capStyle != CapNotLast) 8558 b->y1--; 8559 } else { 8560 b->y1 = seg->y1; 8561 b->y2 = seg->y2; 8562 if (gc->capStyle != CapNotLast) 8563 b->y2++; 8564 } 8565 b->x1 = seg->x1; 8566 b->x2 = seg->x1 + 1; 8567 } else { 8568 if (seg->x1 > seg->x2) { 8569 b->x2 = seg->x1 + 1; 8570 b->x1 = seg->x2 + 1; 8571 if (gc->capStyle != CapNotLast) 8572 b->x1--; 8573 } else { 8574 b->x1 = seg->x1; 8575 b->x2 = seg->x2; 8576 if (gc->capStyle != CapNotLast) 8577 b->x2++; 8578 } 8579 b->y1 = seg->y1; 8580 b->y2 = seg->y1 + 1; 8581 } 8582 8583 DBG(("%s: seg=(%d,%d),(%d,%d); box=(%d,%d),(%d,%d)\n", 8584 __FUNCTION__, 8585 seg->x1, seg->y1, seg->x2, seg->y2, 8586 b->x1, b->y1, b->x2, b->y2)); 8587} 8588 8589static bool 8590sna_poly_segment_blt(DrawablePtr drawable, 8591 struct kgem_bo *bo, 8592 struct sna_damage **damage, 8593 GCPtr gc, uint32_t pixel, 8594 int n, xSegment *seg, 8595 const BoxRec *extents, unsigned clipped) 8596{ 8597 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8598 struct sna *sna = to_sna_from_pixmap(pixmap); 8599 BoxRec boxes[512], *b = boxes, * const last_box = boxes + ARRAY_SIZE(boxes); 8600 struct sna_fill_op fill; 8601 int16_t dx, dy; 8602 8603 DBG(("%s: n=%d, alu=%d, fg=%08lx, clipped=%d\n", 8604 __FUNCTION__, n, gc->alu, gc->fgPixel, clipped)); 8605 8606 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel)) 8607 return false; 8608 8609 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8610 8611 if (!clipped) { 8612 dx += drawable->x; 8613 dy += drawable->y; 8614 if (dx|dy) { 8615 do { 8616 unsigned nbox = n; 8617 if (nbox > ARRAY_SIZE(boxes)) 8618 nbox = ARRAY_SIZE(boxes); 8619 n -= nbox; 8620 do { 8621 box_from_seg(b, seg++, gc); 8622 if (b->y2 > b->y1 && b->x2 > b->x1) { 8623 b->x1 += dx; 8624 b->x2 += dx; 8625 b->y1 += dy; 8626 b->y2 += dy; 8627 b++; 8628 } 8629 } while (--nbox); 8630 8631 if (b != boxes) { 8632 fill.boxes(sna, &fill, boxes, b-boxes); 8633 if (damage) 8634 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 8635 b = boxes; 8636 } 8637 } while (n); 8638 } else { 8639 do { 8640 unsigned nbox = n; 8641 if (nbox > ARRAY_SIZE(boxes)) 8642 nbox = ARRAY_SIZE(boxes); 8643 n -= nbox; 8644 do { 8645 box_from_seg(b++, seg++, gc); 8646 } while (--nbox); 8647 8648 if (b != boxes) { 8649 fill.boxes(sna, &fill, boxes, b-boxes); 8650 if (damage) 8651 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 8652 b = boxes; 8653 } 8654 } while (n); 8655 } 8656 } else { 8657 RegionRec clip; 8658 8659 region_set(&clip, extents); 8660 region_maybe_clip(&clip, gc->pCompositeClip); 8661 if (RegionNil(&clip)) 8662 goto done; 8663 8664 if (clip.data) { 8665 const BoxRec * const clip_start = RegionBoxptr(&clip); 8666 const BoxRec * const clip_end = clip_start + clip.data->numRects; 8667 const BoxRec *c; 8668 do { 8669 BoxRec box; 8670 8671 box_from_seg(&box, seg++, gc); 8672 box.x1 += drawable->x; 8673 box.x2 += drawable->x; 8674 box.y1 += drawable->y; 8675 box.y2 += drawable->y; 8676 c = find_clip_box_for_y(clip_start, 8677 clip_end, 8678 box.y1); 8679 while (c != clip_end) { 8680 if (box.y2 <= c->y1) 8681 break; 8682 8683 *b = box; 8684 if (box_intersect(b, c++)) { 8685 b->x1 += dx; 8686 b->x2 += dx; 8687 b->y1 += dy; 8688 b->y2 += dy; 8689 if (++b == last_box) { 8690 fill.boxes(sna, &fill, boxes, last_box-boxes); 8691 if (damage) 8692 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 8693 b = boxes; 8694 } 8695 } 8696 } 8697 } while (--n); 8698 } else { 8699 do { 8700 box_from_seg(b, seg++, gc); 8701 b->x1 += drawable->x; 8702 b->x2 += drawable->x; 8703 b->y1 += drawable->y; 8704 b->y2 += drawable->y; 8705 if (box_intersect(b, &clip.extents)) { 8706 b->x1 += dx; 8707 b->x2 += dx; 8708 b->y1 += dy; 8709 b->y2 += dy; 8710 if (++b == last_box) { 8711 fill.boxes(sna, &fill, boxes, last_box-boxes); 8712 if (damage) 8713 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 8714 b = boxes; 8715 } 8716 } 8717 } while (--n); 8718 } 8719 RegionUninit(&clip); 8720 } 8721 if (b != boxes) { 8722 fill.boxes(sna, &fill, boxes, b - boxes); 8723 if (damage) 8724 sna_damage_add_boxes(damage, boxes, b - boxes, 0, 0); 8725 } 8726done: 8727 fill.done(sna, &fill); 8728 assert_pixmap_damage(pixmap); 8729 return true; 8730} 8731 8732static bool 8733sna_poly_zero_segment_blt(DrawablePtr drawable, 8734 struct kgem_bo *bo, 8735 struct sna_damage **damage, 8736 GCPtr gc, const int _n, const xSegment *_s, 8737 const BoxRec *extents, unsigned clipped) 8738{ 8739 static void * const _jump[] = { 8740 &&no_damage, 8741 &&damage, 8742 8743 &&no_damage_offset, 8744 &&damage_offset, 8745 }; 8746 8747 PixmapPtr pixmap = get_drawable_pixmap(drawable); 8748 struct sna *sna = to_sna_from_pixmap(pixmap); 8749 unsigned int bias = miGetZeroLineBias(drawable->pScreen); 8750 struct sna_fill_op fill; 8751 RegionRec clip; 8752 const BoxRec *last_extents; 8753 BoxRec box[512], *b; 8754 BoxRec *const last_box = box + ARRAY_SIZE(box); 8755 int16_t dx, dy; 8756 void *jump, *ret; 8757 8758 DBG(("%s: alu=%d, pixel=%lx, n=%d, clipped=%d, damage=%p\n", 8759 __FUNCTION__, gc->alu, gc->fgPixel, _n, clipped, damage)); 8760 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel)) 8761 return false; 8762 8763 get_drawable_deltas(drawable, pixmap, &dx, &dy); 8764 8765 region_set(&clip, extents); 8766 if (clipped) { 8767 region_maybe_clip(&clip, gc->pCompositeClip); 8768 if (RegionNil(&clip)) 8769 return true; 8770 } 8771 DBG(("%s: [clipped] extents=(%d, %d), (%d, %d), delta=(%d, %d)\n", 8772 __FUNCTION__, 8773 clip.extents.x1, clip.extents.y1, 8774 clip.extents.x2, clip.extents.y2, 8775 dx, dy)); 8776 8777 jump = _jump[(damage != NULL) | !!(dx|dy) << 1]; 8778 8779 b = box; 8780 extents = RegionRects(&clip); 8781 last_extents = extents + RegionNumRects(&clip); 8782 do { 8783 int n = _n; 8784 const xSegment *s = _s; 8785 do { 8786 int16_t sdx, sdy; 8787 int adx, ady, length; 8788 int e, e1, e2, e3; 8789 int x1, x2; 8790 int y1, y2; 8791 int oc1, oc2; 8792 int octant; 8793 8794 x1 = s->x1 + drawable->x; 8795 y1 = s->y1 + drawable->y; 8796 x2 = s->x2 + drawable->x; 8797 y2 = s->y2 + drawable->y; 8798 s++; 8799 8800 DBG(("%s: segment (%d, %d) to (%d, %d)\n", 8801 __FUNCTION__, x1, y1, x2, y2)); 8802 if (x2 == x1 && y2 == y1) 8803 continue; 8804 8805 oc1 = 0; 8806 OUTCODES(oc1, x1, y1, extents); 8807 oc2 = 0; 8808 OUTCODES(oc2, x2, y2, extents); 8809 if (oc1 & oc2) 8810 continue; 8811 8812 CalcLineDeltas(x1, y1, x2, y2, 8813 adx, ady, sdx, sdy, 8814 1, 1, octant); 8815 8816 DBG(("%s: adx=(%d, %d), sdx=(%d, %d)\n", 8817 __FUNCTION__, adx, ady, sdx, sdy)); 8818 if (adx == 0 || ady == 0) { 8819 if (x1 <= x2) { 8820 b->x1 = x1; 8821 b->x2 = x2; 8822 } else { 8823 b->x1 = x2; 8824 b->x2 = x1; 8825 } 8826 if (y1 <= y2) { 8827 b->y1 = y1; 8828 b->y2 = y2; 8829 } else { 8830 b->y1 = y2; 8831 b->y2 = y1; 8832 } 8833 b->x2++; 8834 b->y2++; 8835 if (oc1 | oc2) 8836 box_intersect(b, extents); 8837 if (++b == last_box) { 8838 ret = &&rectangle_continue; 8839 goto *jump; 8840rectangle_continue: 8841 b = box; 8842 } 8843 } else if (adx >= ady) { 8844 bool dirty; 8845 8846 /* X-major segment */ 8847 e1 = ady << 1; 8848 e2 = e1 - (adx << 1); 8849 e = e1 - adx; 8850 length = adx; /* don't draw endpoint in main loop */ 8851 8852 FIXUP_ERROR(e, octant, bias); 8853 8854 if (oc1 | oc2) { 8855 int pt1_clipped, pt2_clipped; 8856 int x = x1, y = y1; 8857 8858 if (miZeroClipLine(extents->x1, extents->y1, 8859 extents->x2-1, extents->y2-1, 8860 &x1, &y1, &x2, &y2, 8861 adx, ady, 8862 &pt1_clipped, &pt2_clipped, 8863 octant, bias, oc1, oc2) == -1) 8864 continue; 8865 8866 length = abs(x2 - x1); 8867 if (length == 0) 8868 continue; 8869 8870 if (pt1_clipped) { 8871 int clipdx = abs(x1 - x); 8872 int clipdy = abs(y1 - y); 8873 e += clipdy * e2 + (clipdx - clipdy) * e1; 8874 } 8875 } 8876 e3 = e2 - e1; 8877 e = e - e1; 8878 8879 b->x1 = x1; 8880 b->y1 = y1; 8881 dirty = false; 8882 while (length--) { 8883 dirty = true; 8884 e += e1; 8885 if (e >= 0) { 8886 e += e3; 8887 8888 if (sdx < 0) { 8889 b->x2 = b->x1 + 1; 8890 b->x1 = x1; 8891 } else 8892 b->x2 = x1 + 1; 8893 b->y2 = b->y1 + 1; 8894 8895 DBG(("%s: horizontal step: (%d, %d), box: (%d, %d), (%d, %d)\n", 8896 __FUNCTION__, x1, y1, 8897 b->x1, b->y1, b->x2, b->y2)); 8898 8899 if (++b == last_box) { 8900 ret = &&X_continue; 8901 goto *jump; 8902X_continue: 8903 b = box; 8904 } 8905 8906 b->x1 = x1 + sdx; 8907 b->y1 = y1 += sdy; 8908 dirty = false; 8909 } 8910 x1 += sdx; 8911 } 8912 if (dirty) { 8913 x1 -= sdx; 8914 DBG(("%s: horizontal tail: (%d, %d)\n", 8915 __FUNCTION__, x1, y1)); 8916 if (sdx < 0) { 8917 b->x2 = b->x1 + 1; 8918 b->x1 = x1; 8919 } else 8920 b->x2 = x1 + 1; 8921 b->y2 = b->y1 + 1; 8922 8923 if (++b == last_box) { 8924 ret = &&X2_continue; 8925 goto *jump; 8926X2_continue: 8927 b = box; 8928 } 8929 } 8930 } else { 8931 bool dirty; 8932 8933 /* Y-major segment */ 8934 e1 = adx << 1; 8935 e2 = e1 - (ady << 1); 8936 e = e1 - ady; 8937 length = ady; /* don't draw endpoint in main loop */ 8938 8939 SetYMajorOctant(octant); 8940 FIXUP_ERROR(e, octant, bias); 8941 8942 if (oc1 | oc2) { 8943 int pt1_clipped, pt2_clipped; 8944 int x = x1, y = y1; 8945 8946 if (miZeroClipLine(extents->x1, extents->y1, 8947 extents->x2-1, extents->y2-1, 8948 &x1, &y1, &x2, &y2, 8949 adx, ady, 8950 &pt1_clipped, &pt2_clipped, 8951 octant, bias, oc1, oc2) == -1) 8952 continue; 8953 8954 length = abs(y2 - y1); 8955 if (length == 0) 8956 continue; 8957 8958 if (pt1_clipped) { 8959 int clipdx = abs(x1 - x); 8960 int clipdy = abs(y1 - y); 8961 e += clipdx * e2 + (clipdy - clipdx) * e1; 8962 } 8963 } 8964 8965 e3 = e2 - e1; 8966 e = e - e1; 8967 8968 b->x1 = x1; 8969 b->y1 = y1; 8970 dirty = false; 8971 while (length--) { 8972 e += e1; 8973 dirty = true; 8974 if (e >= 0) { 8975 e += e3; 8976 8977 if (sdy < 0) { 8978 b->y2 = b->y1 + 1; 8979 b->y1 = y1; 8980 } else 8981 b->y2 = y1 + 1; 8982 b->x2 = x1 + 1; 8983 8984 if (++b == last_box) { 8985 ret = &&Y_continue; 8986 goto *jump; 8987Y_continue: 8988 b = box; 8989 } 8990 8991 b->x1 = x1 += sdx; 8992 b->y1 = y1 + sdy; 8993 dirty = false; 8994 } 8995 y1 += sdy; 8996 } 8997 8998 if (dirty) { 8999 y1 -= sdy; 9000 if (sdy < 0) { 9001 b->y2 = b->y1 + 1; 9002 b->y1 = y1; 9003 } else 9004 b->y2 = y1 + 1; 9005 b->x2 = x1 + 1; 9006 9007 if (++b == last_box) { 9008 ret = &&Y2_continue; 9009 goto *jump; 9010Y2_continue: 9011 b = box; 9012 } 9013 } 9014 } 9015 } while (--n); 9016 } while (++extents != last_extents); 9017 9018 if (b != box) { 9019 ret = &&done; 9020 goto *jump; 9021 } 9022 9023done: 9024 fill.done(sna, &fill); 9025 assert_pixmap_damage(pixmap); 9026 RegionUninit(&clip); 9027 return true; 9028 9029damage: 9030 sna_damage_add_boxes(damage, box, b-box, 0, 0); 9031no_damage: 9032 fill.boxes(sna, &fill, box, b-box); 9033 goto *ret; 9034 9035no_damage_offset: 9036 { 9037 BoxRec *bb = box; 9038 do { 9039 bb->x1 += dx; 9040 bb->x2 += dx; 9041 bb->y1 += dy; 9042 bb->y2 += dy; 9043 } while (++bb != b); 9044 fill.boxes(sna, &fill, box, b - box); 9045 } 9046 goto *ret; 9047 9048damage_offset: 9049 { 9050 BoxRec *bb = box; 9051 do { 9052 bb->x1 += dx; 9053 bb->x2 += dx; 9054 bb->y1 += dy; 9055 bb->y2 += dy; 9056 } while (++bb != b); 9057 fill.boxes(sna, &fill, box, b - box); 9058 sna_damage_add_boxes(damage, box, b - box, 0, 0); 9059 } 9060 goto *ret; 9061} 9062 9063static unsigned 9064sna_poly_segment_extents(DrawablePtr drawable, GCPtr gc, 9065 int n, xSegment *seg, 9066 BoxPtr out) 9067{ 9068 BoxRec box; 9069 bool clipped, can_blit; 9070 9071 if (n == 0) 9072 return 0; 9073 9074 if (seg->x2 >= seg->x1) { 9075 box.x1 = seg->x1; 9076 box.x2 = seg->x2; 9077 } else { 9078 box.x2 = seg->x1; 9079 box.x1 = seg->x2; 9080 } 9081 9082 if (seg->y2 >= seg->y1) { 9083 box.y1 = seg->y1; 9084 box.y2 = seg->y2; 9085 } else { 9086 box.y2 = seg->y1; 9087 box.y1 = seg->y2; 9088 } 9089 9090 can_blit = seg->x1 == seg->x2 || seg->y1 == seg->y2; 9091 while (--n) { 9092 seg++; 9093 if (seg->x2 > seg->x1) { 9094 if (seg->x1 < box.x1) box.x1 = seg->x1; 9095 if (seg->x2 > box.x2) box.x2 = seg->x2; 9096 } else { 9097 if (seg->x2 < box.x1) box.x1 = seg->x2; 9098 if (seg->x1 > box.x2) box.x2 = seg->x1; 9099 } 9100 9101 if (seg->y2 > seg->y1) { 9102 if (seg->y1 < box.y1) box.y1 = seg->y1; 9103 if (seg->y2 > box.y2) box.y2 = seg->y2; 9104 } else { 9105 if (seg->y2 < box.y1) box.y1 = seg->y2; 9106 if (seg->y1 > box.y2) box.y2 = seg->y1; 9107 } 9108 9109 if (can_blit && !(seg->x1 == seg->x2 || seg->y1 == seg->y2)) 9110 can_blit = false; 9111 } 9112 9113 box.x2++; 9114 box.y2++; 9115 9116 if (gc->lineWidth) { 9117 int extra = gc->lineWidth; 9118 if (gc->capStyle != CapProjecting) 9119 extra >>= 1; 9120 if (extra) { 9121 box.x1 -= extra; 9122 box.x2 += extra; 9123 box.y1 -= extra; 9124 box.y2 += extra; 9125 } 9126 } 9127 9128 DBG(("%s: unclipped, untranslated extents (%d, %d), (%d, %d)\n", 9129 __FUNCTION__, box.x1, box.y1, box.x2, box.y2)); 9130 9131 clipped = trim_and_translate_box(&box, drawable, gc); 9132 if (box_empty(&box)) 9133 return 0; 9134 9135 *out = box; 9136 return 1 | clipped << 1 | can_blit << 2; 9137} 9138 9139static void 9140sna_poly_segment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg) 9141{ 9142 struct sna_pixmap *priv; 9143 struct sna_fill_spans data; 9144 uint32_t color; 9145 9146 DBG(("%s(n=%d, first=((%d, %d), (%d, %d)), lineWidth=%d\n", 9147 __FUNCTION__, 9148 n, seg->x1, seg->y1, seg->x2, seg->y2, 9149 gc->lineWidth)); 9150 9151 data.flags = sna_poly_segment_extents(drawable, gc, n, seg, 9152 &data.region.extents); 9153 if (data.flags == 0) 9154 return; 9155 9156 DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__, 9157 data.region.extents.x1, data.region.extents.y1, 9158 data.region.extents.x2, data.region.extents.y2)); 9159 9160 data.region.data = NULL; 9161 9162 if (FORCE_FALLBACK) 9163 goto fallback; 9164 9165 if (!ACCEL_POLY_SEGMENT) 9166 goto fallback; 9167 9168 data.pixmap = get_drawable_pixmap(drawable); 9169 data.sna = to_sna_from_pixmap(data.pixmap); 9170 priv = sna_pixmap(data.pixmap); 9171 if (priv == NULL) { 9172 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 9173 goto fallback; 9174 } 9175 9176 if (wedged(data.sna)) { 9177 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9178 goto fallback; 9179 } 9180 9181 DBG(("%s: fill=%d [%d], line=%d [%d], width=%d, mask=%lu [%d], rectlinear=%d\n", 9182 __FUNCTION__, 9183 gc->fillStyle, gc->fillStyle == FillSolid, 9184 gc->lineStyle, gc->lineStyle == LineSolid, 9185 gc->lineWidth, 9186 gc->planemask, PM_IS_SOLID(drawable, gc->planemask), 9187 data.flags & 4)); 9188 if (!PM_IS_SOLID(drawable, gc->planemask)) 9189 goto fallback; 9190 9191 if (gc->lineStyle != LineSolid || gc->lineWidth > 1) 9192 goto spans_fallback; 9193 if (gc_is_solid(gc, &color)) { 9194 DBG(("%s: trying blt solid fill [%08x, flags=%x] paths\n", 9195 __FUNCTION__, (unsigned)color, data.flags)); 9196 9197 if (data.flags & 4) { 9198 if ((data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9199 &data.region.extents, 9200 &data.damage)) && 9201 sna_poly_segment_blt(drawable, 9202 data.bo, data.damage, 9203 gc, color, n, seg, 9204 &data.region.extents, 9205 data.flags & 2)) 9206 return; 9207 } else { 9208 if ((data.bo = sna_drawable_use_bo(drawable, 9209 use_zero_spans(drawable, gc, &data.region.extents), 9210 &data.region.extents, 9211 &data.damage)) && 9212 sna_poly_zero_segment_blt(drawable, 9213 data.bo, data.damage, 9214 gc, n, seg, 9215 &data.region.extents, 9216 data.flags & 2)) 9217 return; 9218 } 9219 } else if (data.flags & 4) { 9220 /* Try converting these to a set of rectangles instead */ 9221 xRectangle *rect; 9222 int i; 9223 9224 data.bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9225 &data.region.extents, 9226 &data.damage); 9227 if (data.bo == NULL) 9228 goto fallback; 9229 9230 DBG(("%s: converting to rectagnles\n", __FUNCTION__)); 9231 9232 rect = malloc (n * sizeof (xRectangle)); 9233 if (rect == NULL) 9234 return; 9235 9236 for (i = 0; i < n; i++) { 9237 if (seg[i].x1 < seg[i].x2) { 9238 rect[i].x = seg[i].x1; 9239 rect[i].width = seg[i].x2 - seg[i].x1 + 1; 9240 } else if (seg[i].x1 > seg[i].x2) { 9241 rect[i].x = seg[i].x2; 9242 rect[i].width = seg[i].x1 - seg[i].x2 + 1; 9243 } else { 9244 rect[i].x = seg[i].x1; 9245 rect[i].width = 1; 9246 } 9247 if (seg[i].y1 < seg[i].y2) { 9248 rect[i].y = seg[i].y1; 9249 rect[i].height = seg[i].y2 - seg[i].y1 + 1; 9250 } else if (seg[i].y1 > seg[i].y2) { 9251 rect[i].y = seg[i].y2; 9252 rect[i].height = seg[i].y1 - seg[i].y2 + 1; 9253 } else { 9254 rect[i].y = seg[i].y1; 9255 rect[i].height = 1; 9256 } 9257 9258 /* don't paint last pixel */ 9259 if (gc->capStyle == CapNotLast) { 9260 if (seg[i].x1 == seg[i].x2) 9261 rect[i].height--; 9262 else 9263 rect[i].width--; 9264 } 9265 } 9266 9267 if (gc->fillStyle == FillTiled) { 9268 i = sna_poly_fill_rect_tiled_blt(drawable, 9269 data.bo, data.damage, 9270 gc, n, rect, 9271 &data.region.extents, 9272 data.flags & 2); 9273 } else { 9274 i = sna_poly_fill_rect_stippled_blt(drawable, 9275 data.bo, data.damage, 9276 gc, n, rect, 9277 &data.region.extents, 9278 data.flags & 2); 9279 } 9280 free (rect); 9281 9282 if (i) 9283 return; 9284 } 9285 9286spans_fallback: 9287 if ((data.bo = sna_drawable_use_bo(drawable, 9288 use_wide_spans(drawable, gc, &data.region.extents), 9289 &data.region.extents, 9290 &data.damage))) { 9291 void (*line)(DrawablePtr, GCPtr, int, int, DDXPointPtr); 9292 int i; 9293 9294 DBG(("%s: converting segments into spans\n", __FUNCTION__)); 9295 9296 switch (gc->lineStyle) { 9297 default: 9298 case LineSolid: 9299 if (gc->lineWidth == 0) 9300 line = miZeroLine; 9301 else 9302 line = miWideLine; 9303 break; 9304 case LineOnOffDash: 9305 case LineDoubleDash: 9306 if (gc->lineWidth == 0) 9307 line = miZeroDashLine; 9308 else 9309 line = miWideDash; 9310 break; 9311 } 9312 9313 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 9314 sna_gc(gc)->priv = &data; 9315 9316 if (gc->lineWidth == 0 && 9317 gc->lineStyle == LineSolid && 9318 gc_is_solid(gc, &color)) { 9319 struct sna_fill_op fill; 9320 9321 if (!sna_fill_init_blt(&fill, 9322 data.sna, data.pixmap, 9323 data.bo, gc->alu, color)) 9324 goto fallback; 9325 9326 data.op = &fill; 9327 9328 if ((data.flags & 2) == 0) { 9329 if (data.dx | data.dy) 9330 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 9331 else 9332 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 9333 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 9334 } else { 9335 region_maybe_clip(&data.region, 9336 gc->pCompositeClip); 9337 if (RegionNil(&data.region)) 9338 return; 9339 9340 if (region_is_singular(&data.region)) { 9341 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 9342 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 9343 } else { 9344 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 9345 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 9346 } 9347 } 9348 assert(gc->miTranslate); 9349 gc->ops = &sna_gc_ops__tmp; 9350 for (i = 0; i < n; i++) 9351 line(drawable, gc, CoordModeOrigin, 2, 9352 (DDXPointPtr)&seg[i]); 9353 9354 fill.done(data.sna, &fill); 9355 } else { 9356 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 9357 sna_gc_ops__tmp.PolyFillRect = sna_poly_fill_rect__gpu; 9358 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 9359 gc->ops = &sna_gc_ops__tmp; 9360 9361 for (i = 0; i < n; i++) 9362 line(drawable, gc, CoordModeOrigin, 2, 9363 (DDXPointPtr)&seg[i]); 9364 } 9365 9366 gc->ops = (GCOps *)&sna_gc_ops; 9367 if (data.damage) { 9368 if (data.dx | data.dy) 9369 pixman_region_translate(&data.region, data.dx, data.dy); 9370 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 9371 sna_damage_add(data.damage, &data.region); 9372 } 9373 assert_pixmap_damage(data.pixmap); 9374 RegionUninit(&data.region); 9375 return; 9376 } 9377 9378fallback: 9379 DBG(("%s: fallback\n", __FUNCTION__)); 9380 region_maybe_clip(&data.region, gc->pCompositeClip); 9381 if (RegionNil(&data.region)) 9382 return; 9383 9384 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 9385 goto out; 9386 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 9387 drawable_gc_flags(drawable, gc, 9388 !(data.flags & 4 && n == 1)))) 9389 goto out_gc; 9390 9391 DBG(("%s: fbPolySegment\n", __FUNCTION__)); 9392 fbPolySegment(drawable, gc, n, seg); 9393 FALLBACK_FLUSH(drawable); 9394 9395out_gc: 9396 sna_gc_move_to_gpu(gc); 9397out: 9398 RegionUninit(&data.region); 9399} 9400 9401static unsigned 9402sna_poly_rectangle_extents(DrawablePtr drawable, GCPtr gc, 9403 int n, xRectangle *r, 9404 BoxPtr out) 9405{ 9406 Box32Rec box; 9407 int extra = gc->lineWidth >> 1; 9408 bool clipped; 9409 bool zero = false; 9410 9411 if (n == 0) 9412 return 0; 9413 9414 box.x1 = r->x; 9415 box.y1 = r->y; 9416 box.x2 = box.x1 + r->width; 9417 box.y2 = box.y1 + r->height; 9418 zero |= (r->width | r->height) == 0; 9419 9420 while (--n) { 9421 r++; 9422 zero |= (r->width | r->height) == 0; 9423 box32_add_rect(&box, r); 9424 } 9425 9426 box.x2++; 9427 box.y2++; 9428 9429 if (extra) { 9430 box.x1 -= extra; 9431 box.x2 += extra; 9432 box.y1 -= extra; 9433 box.y2 += extra; 9434 zero = !zero; 9435 } else 9436 zero = true; 9437 9438 clipped = box32_trim_and_translate(&box, drawable, gc); 9439 if (!box32_to_box16(&box, out)) 9440 return 0; 9441 9442 return 1 | clipped << 1 | zero << 2; 9443} 9444 9445static bool 9446sna_poly_rectangle_blt(DrawablePtr drawable, 9447 struct kgem_bo *bo, 9448 struct sna_damage **damage, 9449 GCPtr gc, int n, xRectangle *r, 9450 const BoxRec *extents, unsigned clipped) 9451{ 9452 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9453 struct sna *sna = to_sna_from_pixmap(pixmap); 9454 struct sna_fill_op fill; 9455 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 9456 int16_t dx, dy; 9457 static void * const jump[] = { 9458 &&wide, 9459 &&zero, 9460 &&wide_clipped, 9461 &&zero_clipped, 9462 }; 9463 9464 DBG(("%s: n=%d, alu=%d, width=%d, fg=%08lx, damge=%p, clipped?=%d\n", 9465 __FUNCTION__, n, gc->alu, gc->lineWidth, gc->fgPixel, damage, clipped)); 9466 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel)) 9467 return false; 9468 9469 get_drawable_deltas(drawable, pixmap, &dx, &dy); 9470 9471 goto *jump[(gc->lineWidth <= 1) | clipped]; 9472 9473zero: 9474 dx += drawable->x; 9475 dy += drawable->y; 9476 9477 do { 9478 xRectangle rr = *r++; 9479 9480 if ((rr.width | rr.height) == 0) 9481 continue; /* XXX -> PolyLine */ 9482 9483 DBG(("%s - zero : r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 9484 n, rr.x, rr.y, rr.width, rr.height)); 9485 rr.x += dx; 9486 rr.y += dy; 9487 9488 if (b+4 > last_box) { 9489 fill.boxes(sna, &fill, boxes, b-boxes); 9490 if (damage) 9491 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 9492 b = boxes; 9493 } 9494 9495 if (rr.width <= 1 || rr.height <= 1) { 9496 b->x1 = rr.x; 9497 b->y1 = rr.y; 9498 b->x2 = rr.x + rr.width + (rr.height != 0); 9499 b->y2 = rr.y + rr.height + (rr.width != 0); 9500 DBG(("%s: blt (%d, %d), (%d, %d)\n", 9501 __FUNCTION__, 9502 b->x1, b->y1, b->x2,b->y2)); 9503 b++; 9504 } else { 9505 b[0].x1 = rr.x; 9506 b[0].y1 = rr.y; 9507 b[0].x2 = rr.x + rr.width + 1; 9508 b[0].y2 = rr.y + 1; 9509 9510 b[1] = b[0]; 9511 b[1].y1 += rr.height; 9512 b[1].y2 += rr.height; 9513 9514 b[2].y1 = rr.y + 1; 9515 b[2].y2 = rr.y + rr.height; 9516 b[2].x1 = rr.x; 9517 b[2].x2 = rr.x + 1; 9518 9519 b[3] = b[2]; 9520 b[3].x1 += rr.width; 9521 b[3].x2 += rr.width; 9522 9523 b += 4; 9524 } 9525 } while (--n); 9526 goto done; 9527 9528zero_clipped: 9529 { 9530 RegionRec clip; 9531 BoxRec box[4]; 9532 int count; 9533 9534 region_set(&clip, extents); 9535 region_maybe_clip(&clip, gc->pCompositeClip); 9536 if (RegionNil(&clip)) 9537 goto done; 9538 9539 if (clip.data) { 9540 const BoxRec * const clip_start = RegionBoxptr(&clip); 9541 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9542 const BoxRec *c; 9543 do { 9544 xRectangle rr = *r++; 9545 9546 DBG(("%s - zero, clipped complex: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 9547 n, rr.x, rr.y, rr.width, rr.height)); 9548 9549 if ((rr.width | rr.height) == 0) 9550 continue; /* XXX -> PolyLine */ 9551 9552 rr.x += drawable->x; 9553 rr.y += drawable->y; 9554 9555 if (rr.width <= 1 || rr.height <= 1) { 9556 box[0].x1 = rr.x; 9557 box[0].y1 = rr.y; 9558 box[0].x2 = rr.x + rr.width + (rr.height != 0); 9559 box[0].y2 = rr.y + rr.height + (rr.width != 0); 9560 count = 1; 9561 } else { 9562 box[0].x1 = rr.x; 9563 box[0].y1 = rr.y; 9564 box[0].x2 = rr.x + rr.width + 1; 9565 box[0].y2 = rr.y + 1; 9566 9567 box[1] = box[0]; 9568 box[1].y1 += rr.height; 9569 box[1].y2 += rr.height; 9570 9571 box[2].y1 = rr.y + 1; 9572 box[2].y2 = rr.y + rr.height; 9573 box[2].x1 = rr.x; 9574 box[2].x2 = rr.x + 1; 9575 9576 box[3] = box[2]; 9577 box[3].x1 += rr.width; 9578 box[3].x2 += rr.width; 9579 count = 4; 9580 } 9581 9582 while (count--) { 9583 c = find_clip_box_for_y(clip_start, 9584 clip_end, 9585 box[count].y1); 9586 while (c != clip_end) { 9587 if (box[count].y2 <= c->y1) 9588 break; 9589 9590 *b = box[count]; 9591 if (box_intersect(b, c++)) { 9592 b->x1 += dx; 9593 b->x2 += dx; 9594 b->y1 += dy; 9595 b->y2 += dy; 9596 if (++b == last_box) { 9597 fill.boxes(sna, &fill, boxes, last_box-boxes); 9598 if (damage) 9599 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9600 b = boxes; 9601 } 9602 } 9603 9604 } 9605 } 9606 } while (--n); 9607 } else { 9608 do { 9609 xRectangle rr = *r++; 9610 DBG(("%s - zero, clip: r[%d] = (%d, %d) x (%d, %d)\n", __FUNCTION__, 9611 n, rr.x, rr.y, rr.width, rr.height)); 9612 9613 if ((rr.width | rr.height) == 0) 9614 continue; /* XXX -> PolyLine */ 9615 9616 rr.x += drawable->x; 9617 rr.y += drawable->y; 9618 9619 if (rr.width <= 1 || rr.height <= 1) { 9620 box[0].x1 = rr.x; 9621 box[0].y1 = rr.y; 9622 box[0].x2 = rr.x + rr.width + (rr.height != 0); 9623 box[0].y2 = rr.y + rr.height + (rr.width != 0); 9624 count = 1; 9625 } else { 9626 box[0].x1 = rr.x; 9627 box[0].y1 = rr.y; 9628 box[0].x2 = rr.x + rr.width + 1; 9629 box[0].y2 = rr.y + 1; 9630 9631 box[1] = box[0]; 9632 box[1].y1 += rr.height; 9633 box[1].y2 += rr.height; 9634 9635 box[2].y1 = rr.y + 1; 9636 box[2].y2 = rr.y + rr.height; 9637 box[2].x1 = rr.x; 9638 box[2].x2 = rr.x + 1; 9639 9640 box[3] = box[2]; 9641 box[3].x1 += rr.width; 9642 box[3].x2 += rr.width; 9643 count = 4; 9644 } 9645 9646 while (count--) { 9647 *b = box[count]; 9648 if (box_intersect(b, &clip.extents)) { 9649 b->x1 += dx; 9650 b->x2 += dx; 9651 b->y1 += dy; 9652 b->y2 += dy; 9653 if (++b == last_box) { 9654 fill.boxes(sna, &fill, boxes, last_box-boxes); 9655 if (damage) 9656 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9657 b = boxes; 9658 } 9659 } 9660 9661 } 9662 } while (--n); 9663 } 9664 RegionUninit(&clip); 9665 } 9666 goto done; 9667 9668wide_clipped: 9669 { 9670 RegionRec clip; 9671 BoxRec box[4]; 9672 int16_t offset2 = gc->lineWidth; 9673 int16_t offset1 = offset2 >> 1; 9674 int16_t offset3 = offset2 - offset1; 9675 9676 region_set(&clip, extents); 9677 region_maybe_clip(&clip, gc->pCompositeClip); 9678 DBG(("%s: wide clipped: extents=((%d, %d), (%d, %d))\n", 9679 __FUNCTION__, 9680 clip.extents.x1, clip.extents.y1, 9681 clip.extents.x2, clip.extents.y2)); 9682 if (RegionNil(&clip)) 9683 goto done; 9684 9685 if (clip.data) { 9686 const BoxRec * const clip_start = RegionBoxptr(&clip); 9687 const BoxRec * const clip_end = clip_start + clip.data->numRects; 9688 const BoxRec *c; 9689 do { 9690 xRectangle rr = *r++; 9691 int count; 9692 9693 if ((rr.width | rr.height) == 0) 9694 continue; /* XXX -> PolyLine */ 9695 9696 rr.x += drawable->x; 9697 rr.y += drawable->y; 9698 9699 if (rr.height <= offset2 || rr.width <= offset2) { 9700 if (rr.height == 0) { 9701 box[0].x1 = rr.x; 9702 box[0].x2 = rr.x + rr.width; 9703 } else { 9704 box[0].x1 = rr.x - offset1; 9705 box[0].x2 = rr.x + rr.width + offset3; 9706 } 9707 if (rr.width == 0) { 9708 box[0].y1 = rr.y; 9709 box[0].y2 = rr.y + rr.height; 9710 } else { 9711 box[0].y1 = rr.y - offset1; 9712 box[0].y2 = rr.y + rr.height + offset3; 9713 } 9714 count = 1; 9715 } else { 9716 box[0].x1 = rr.x - offset1; 9717 box[0].x2 = box[0].x1 + rr.width + offset2; 9718 box[0].y1 = rr.y - offset1; 9719 box[0].y2 = box[0].y1 + offset2; 9720 9721 box[1].x1 = rr.x - offset1; 9722 box[1].x2 = box[1].x1 + offset2; 9723 box[1].y1 = rr.y + offset3; 9724 box[1].y2 = rr.y + rr.height - offset1; 9725 9726 box[2] = box[1]; 9727 box[2].x1 += rr.width; 9728 box[2].x2 += rr.width; 9729 9730 box[3] = box[0]; 9731 box[3].y1 += rr.height; 9732 box[3].y2 += rr.height; 9733 count = 4; 9734 } 9735 9736 while (count--) { 9737 c = find_clip_box_for_y(clip_start, 9738 clip_end, 9739 box[count].y1); 9740 while (c != clip_end) { 9741 if (box[count].y2 <= c->y1) 9742 break; 9743 9744 *b = box[count]; 9745 if (box_intersect(b, c++)) { 9746 b->x1 += dx; 9747 b->x2 += dx; 9748 b->y1 += dy; 9749 b->y2 += dy; 9750 if (++b == last_box) { 9751 fill.boxes(sna, &fill, boxes, last_box-boxes); 9752 if (damage) 9753 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9754 b = boxes; 9755 } 9756 } 9757 } 9758 } 9759 } while (--n); 9760 } else { 9761 DBG(("%s: singular clip offset1=%d, offset2=%d, offset3=%d\n", 9762 __FUNCTION__, offset1, offset2, offset3)); 9763 do { 9764 xRectangle rr = *r++; 9765 int count; 9766 rr.x += drawable->x; 9767 rr.y += drawable->y; 9768 9769 DBG(("%s: r=(%d, %d)x(%d, %d)\n", 9770 __FUNCTION__, rr.x, rr.y, rr.width, rr.height)); 9771 if (rr.height <= offset2 || rr.width <= offset2) { 9772 if (rr.height == 0) { 9773 box[0].x1 = rr.x; 9774 box[0].x2 = rr.x + rr.width; 9775 } else { 9776 box[0].x1 = rr.x - offset1; 9777 box[0].x2 = box[0].x1 + rr.width + offset2; 9778 } 9779 if (rr.width == 0) { 9780 box[0].y1 = rr.y; 9781 box[0].y2 = rr.y + rr.height; 9782 } else { 9783 box[0].y1 = rr.y - offset1; 9784 box[0].y2 = box[0].y1 + rr.height + offset2; 9785 } 9786 count = 1; 9787 } else { 9788 box[0].x1 = rr.x - offset1; 9789 box[0].x2 = box[0].x1 + rr.width + offset2; 9790 box[0].y1 = rr.y - offset1; 9791 box[0].y2 = box[0].y1 + offset2; 9792 DBG(("%s: box[0]=(%d, %d), (%d, %d)\n", 9793 __FUNCTION__, 9794 box[0].x1, box[0].y1, 9795 box[0].x2, box[0].y2)); 9796 9797 box[1].x1 = rr.x - offset1; 9798 box[1].x2 = box[1].x1 + offset2; 9799 box[1].y1 = rr.y + offset3; 9800 box[1].y2 = rr.y + rr.height - offset1; 9801 DBG(("%s: box[1]=(%d, %d), (%d, %d)\n", 9802 __FUNCTION__, 9803 box[1].x1, box[1].y1, 9804 box[1].x2, box[1].y2)); 9805 9806 box[2] = box[1]; 9807 box[2].x1 += rr.width; 9808 box[2].x2 += rr.width; 9809 DBG(("%s: box[2]=(%d, %d), (%d, %d)\n", 9810 __FUNCTION__, 9811 box[2].x1, box[2].y1, 9812 box[2].x2, box[2].y2)); 9813 9814 box[3] = box[0]; 9815 box[3].y1 += rr.height; 9816 box[3].y2 += rr.height; 9817 DBG(("%s: box[3]=(%d, %d), (%d, %d)\n", 9818 __FUNCTION__, 9819 box[3].x1, box[3].y1, 9820 box[3].x2, box[3].y2)); 9821 9822 count = 4; 9823 } 9824 9825 while (count--) { 9826 *b = box[count]; 9827 if (box_intersect(b, &clip.extents)) { 9828 b->x1 += dx; 9829 b->x2 += dx; 9830 b->y1 += dy; 9831 b->y2 += dy; 9832 if (++b == last_box) { 9833 fill.boxes(sna, &fill, boxes, last_box-boxes); 9834 if (damage) 9835 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9836 b = boxes; 9837 } 9838 } 9839 } 9840 } while (--n); 9841 } 9842 RegionUninit(&clip); 9843 } 9844 goto done; 9845 9846wide: 9847 { 9848 int offset2 = gc->lineWidth; 9849 int offset1 = offset2 >> 1; 9850 int offset3 = offset2 - offset1; 9851 9852 dx += drawable->x; 9853 dy += drawable->y; 9854 9855 do { 9856 xRectangle rr = *r++; 9857 9858 if ((rr.width | rr.height) == 0) 9859 continue; /* XXX -> PolyLine */ 9860 9861 rr.x += dx; 9862 rr.y += dy; 9863 9864 if (b+4 > last_box) { 9865 fill.boxes(sna, &fill, boxes, last_box-boxes); 9866 if (damage) 9867 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 9868 b = boxes; 9869 } 9870 9871 if (rr.height <= offset2 || rr.width <= offset2) { 9872 if (rr.height == 0) { 9873 b->x1 = rr.x; 9874 b->x2 = rr.x + rr.width; 9875 } else { 9876 b->x1 = rr.x - offset1; 9877 b->x2 = rr.x + rr.width + offset3; 9878 } 9879 if (rr.width == 0) { 9880 b->y1 = rr.y; 9881 b->y2 = rr.y + rr.height; 9882 } else { 9883 b->y1 = rr.y - offset1; 9884 b->y2 = rr.y + rr.height + offset3; 9885 } 9886 b++; 9887 } else { 9888 b[0].x1 = rr.x - offset1; 9889 b[0].x2 = b[0].x1 + rr.width + offset2; 9890 b[0].y1 = rr.y - offset1; 9891 b[0].y2 = b[0].y1 + offset2; 9892 9893 b[1].x1 = rr.x - offset1; 9894 b[1].x2 = b[1].x1 + offset2; 9895 b[1].y1 = rr.y + offset3; 9896 b[1].y2 = rr.y + rr.height - offset1; 9897 9898 b[2] = b[1]; 9899 b[2].x1 += rr.width; 9900 b[2].x2 += rr.width; 9901 9902 b[3] = b[0]; 9903 b[3].y1 += rr.height; 9904 b[3].y2 += rr.height; 9905 b += 4; 9906 } 9907 } while (--n); 9908 } 9909 goto done; 9910 9911done: 9912 if (b != boxes) { 9913 fill.boxes(sna, &fill, boxes, b-boxes); 9914 if (damage) 9915 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 9916 } 9917 fill.done(sna, &fill); 9918 assert_pixmap_damage(pixmap); 9919 return true; 9920} 9921 9922static void 9923sna_poly_rectangle(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r) 9924{ 9925 PixmapPtr pixmap = get_drawable_pixmap(drawable); 9926 struct sna *sna = to_sna_from_pixmap(pixmap); 9927 struct sna_damage **damage; 9928 struct kgem_bo *bo; 9929 RegionRec region; 9930 unsigned flags; 9931 9932 DBG(("%s(n=%d, first=((%d, %d)x(%d, %d)), lineWidth=%d\n", 9933 __FUNCTION__, 9934 n, r->x, r->y, r->width, r->height, 9935 gc->lineWidth)); 9936 9937 flags = sna_poly_rectangle_extents(drawable, gc, n, r, ®ion.extents); 9938 if (flags == 0) 9939 return; 9940 9941 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 9942 region.extents.x1, region.extents.y1, 9943 region.extents.x2, region.extents.y2, 9944 flags)); 9945 9946 if (FORCE_FALLBACK) 9947 goto fallback; 9948 9949 if (!ACCEL_POLY_RECTANGLE) 9950 goto fallback; 9951 9952 if (wedged(sna)) { 9953 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 9954 goto fallback; 9955 } 9956 9957 DBG(("%s: fill=_%d [%d], line=%d [%d], join=%d [%d], mask=%lu [%d]\n", 9958 __FUNCTION__, 9959 gc->fillStyle, gc->fillStyle == FillSolid, 9960 gc->lineStyle, gc->lineStyle == LineSolid, 9961 gc->joinStyle, gc->joinStyle == JoinMiter, 9962 gc->planemask, PM_IS_SOLID(drawable, gc->planemask))); 9963 9964 if (!PM_IS_SOLID(drawable, gc->planemask)) 9965 goto fallback; 9966 9967 if (flags & 4 && gc->fillStyle == FillSolid && gc->lineStyle == LineSolid && gc->joinStyle == JoinMiter) { 9968 DBG(("%s: trying blt solid fill [%08lx] paths\n", 9969 __FUNCTION__, gc->fgPixel)); 9970 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 9971 ®ion.extents, &damage)) && 9972 sna_poly_rectangle_blt(drawable, bo, damage, 9973 gc, n, r, ®ion.extents, flags&2)) 9974 return; 9975 } else { 9976 /* Not a trivial outline, but we still maybe able to break it 9977 * down into simpler operations that we can accelerate. 9978 */ 9979 if (sna_drawable_use_bo(drawable, PREFER_GPU, 9980 ®ion.extents, &damage)) { 9981 miPolyRectangle(drawable, gc, n, r); 9982 return; 9983 } 9984 } 9985 9986fallback: 9987 DBG(("%s: fallback\n", __FUNCTION__)); 9988 9989 region.data = NULL; 9990 region_maybe_clip(®ion, gc->pCompositeClip); 9991 if (RegionNil(®ion)) 9992 return; 9993 9994 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 9995 goto out; 9996 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 9997 drawable_gc_flags(drawable, gc, true))) 9998 goto out_gc; 9999 10000 DBG(("%s: miPolyRectangle\n", __FUNCTION__)); 10001 miPolyRectangle(drawable, gc, n, r); 10002 FALLBACK_FLUSH(drawable); 10003out_gc: 10004 sna_gc_move_to_gpu(gc); 10005out: 10006 RegionUninit(®ion); 10007} 10008 10009static unsigned 10010sna_poly_arc_extents(DrawablePtr drawable, GCPtr gc, 10011 int n, xArc *arc, 10012 BoxPtr out) 10013{ 10014 BoxRec box; 10015 bool clipped; 10016 int v; 10017 10018 if (n == 0) 10019 return 0; 10020 10021 box.x1 = arc->x; 10022 box.x2 = bound(box.x1, arc->width); 10023 box.y1 = arc->y; 10024 box.y2 = bound(box.y1, arc->height); 10025 10026 while (--n) { 10027 arc++; 10028 if (box.x1 > arc->x) 10029 box.x1 = arc->x; 10030 v = bound(arc->x, arc->width); 10031 if (box.x2 < v) 10032 box.x2 = v; 10033 if (box.y1 > arc->y) 10034 box.y1 = arc->y; 10035 v = bound(arc->y, arc->height); 10036 if (box.y2 < v) 10037 box.y2 = v; 10038 } 10039 10040 v = gc->lineWidth >> 1; 10041 if (v) { 10042 box.x1 -= v; 10043 box.x2 += v; 10044 box.y1 -= v; 10045 box.y2 += v; 10046 } 10047 10048 box.x2++; 10049 box.y2++; 10050 10051 clipped = trim_and_translate_box(&box, drawable, gc); 10052 if (box_empty(&box)) 10053 return 0; 10054 10055 *out = box; 10056 return 1 | clipped << 1; 10057} 10058 10059static void 10060sna_poly_arc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc) 10061{ 10062 struct sna_fill_spans data; 10063 struct sna_pixmap *priv; 10064 10065 DBG(("%s(n=%d, lineWidth=%d\n", __FUNCTION__, n, gc->lineWidth)); 10066 10067 data.flags = sna_poly_arc_extents(drawable, gc, n, arc, 10068 &data.region.extents); 10069 if (data.flags == 0) 10070 return; 10071 10072 DBG(("%s: extents=(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 10073 data.region.extents.x1, data.region.extents.y1, 10074 data.region.extents.x2, data.region.extents.y2, 10075 data.flags)); 10076 10077 data.region.data = NULL; 10078 10079 if (FORCE_FALLBACK) 10080 goto fallback; 10081 10082 if (!ACCEL_POLY_ARC) 10083 goto fallback; 10084 10085 data.pixmap = get_drawable_pixmap(drawable); 10086 data.sna = to_sna_from_pixmap(data.pixmap); 10087 priv = sna_pixmap(data.pixmap); 10088 if (priv == NULL) { 10089 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10090 goto fallback; 10091 } 10092 10093 if (wedged(data.sna)) { 10094 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10095 goto fallback; 10096 } 10097 10098 if (!PM_IS_SOLID(drawable, gc->planemask)) 10099 goto fallback; 10100 10101 if ((data.bo = sna_drawable_use_bo(drawable, 10102 use_wide_spans(drawable, gc, &data.region.extents), 10103 &data.region.extents, &data.damage))) { 10104 uint32_t color; 10105 10106 DBG(("%s: converting arcs into spans\n", __FUNCTION__)); 10107 get_drawable_deltas(drawable, data.pixmap, &data.dx, &data.dy); 10108 10109 if (gc_is_solid(gc, &color)) { 10110 sna_gc(gc)->priv = &data; 10111 10112 assert(gc->miTranslate); 10113 if (gc->lineStyle == LineSolid) { 10114 struct sna_fill_op fill; 10115 10116 if (!sna_fill_init_blt(&fill, 10117 data.sna, data.pixmap, 10118 data.bo, gc->alu, color)) 10119 goto fallback; 10120 10121 if ((data.flags & 2) == 0) { 10122 if (data.dx | data.dy) 10123 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10124 else 10125 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10126 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill; 10127 } else { 10128 region_maybe_clip(&data.region, 10129 gc->pCompositeClip); 10130 if (RegionNil(&data.region)) 10131 return; 10132 10133 if (region_is_singular(&data.region)) { 10134 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10135 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_extents; 10136 } else { 10137 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10138 sna_gc_ops__tmp.PolyPoint = sna_poly_point__fill_clip_boxes; 10139 } 10140 } 10141 10142 data.op = &fill; 10143 gc->ops = &sna_gc_ops__tmp; 10144 if (gc->lineWidth == 0) 10145 miZeroPolyArc(drawable, gc, n, arc); 10146 else 10147 miPolyArc(drawable, gc, n, arc); 10148 gc->ops = (GCOps *)&sna_gc_ops; 10149 10150 fill.done(data.sna, &fill); 10151 } else { 10152 region_maybe_clip(&data.region, 10153 gc->pCompositeClip); 10154 if (RegionNil(&data.region)) 10155 return; 10156 10157 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10158 sna_gc_ops__tmp.PolyPoint = sna_poly_point__gpu; 10159 10160 gc->ops = &sna_gc_ops__tmp; 10161 if (gc->lineWidth == 0) 10162 miZeroPolyArc(drawable, gc, n, arc); 10163 else 10164 miPolyArc(drawable, gc, n, arc); 10165 gc->ops = (GCOps *)&sna_gc_ops; 10166 } 10167 10168 if (data.damage) { 10169 if (data.dx | data.dy) 10170 pixman_region_translate(&data.region, data.dx, data.dy); 10171 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10172 sna_damage_add(data.damage, &data.region); 10173 } 10174 assert_pixmap_damage(data.pixmap); 10175 RegionUninit(&data.region); 10176 return; 10177 } 10178 10179 /* XXX still around 10x slower for x11perf -ellipse */ 10180 if (gc->lineWidth == 0) 10181 miZeroPolyArc(drawable, gc, n, arc); 10182 else 10183 miPolyArc(drawable, gc, n, arc); 10184 return; 10185 } 10186 10187fallback: 10188 DBG(("%s -- fallback\n", __FUNCTION__)); 10189 region_maybe_clip(&data.region, gc->pCompositeClip); 10190 if (RegionNil(&data.region)) 10191 return; 10192 10193 if (!sna_gc_move_to_cpu(gc, drawable, &data.region)) 10194 goto out; 10195 if (!sna_drawable_move_region_to_cpu(drawable, &data.region, 10196 drawable_gc_flags(drawable, gc, true))) 10197 goto out_gc; 10198 10199 DBG(("%s -- fbPolyArc\n", __FUNCTION__)); 10200 fbPolyArc(drawable, gc, n, arc); 10201 FALLBACK_FLUSH(drawable); 10202 10203out_gc: 10204 sna_gc_move_to_gpu(gc); 10205out: 10206 RegionUninit(&data.region); 10207} 10208 10209static bool 10210sna_poly_fill_rect_blt(DrawablePtr drawable, 10211 struct kgem_bo *bo, 10212 struct sna_damage **damage, 10213 GCPtr gc, uint32_t pixel, 10214 int n, xRectangle *rect, 10215 const BoxRec *extents, 10216 bool clipped) 10217{ 10218 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10219 struct sna *sna = to_sna_from_pixmap(pixmap); 10220 struct sna_fill_op fill; 10221 BoxRec boxes[512], *b = boxes, *const last_box = boxes+ARRAY_SIZE(boxes); 10222 int16_t dx, dy; 10223 10224 DBG(("%s x %d [(%d, %d)x(%d, %d)...]+(%d,%d), clipped?=%d\n", 10225 __FUNCTION__, n, 10226 rect->x, rect->y, rect->width, rect->height, 10227 drawable->x, drawable->y, 10228 clipped)); 10229 10230 if (n == 1 && region_is_singular(gc->pCompositeClip)) { 10231 BoxRec r; 10232 bool success = true; 10233 10234 r.x1 = rect->x + drawable->x; 10235 r.y1 = rect->y + drawable->y; 10236 r.x2 = bound(r.x1, rect->width); 10237 r.y2 = bound(r.y1, rect->height); 10238 if (box_intersect(&r, &gc->pCompositeClip->extents)) { 10239 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) { 10240 r.x1 += dx; r.y1 += dy; 10241 r.x2 += dx; r.y2 += dy; 10242 } 10243 if (sna->render.fill_one(sna, pixmap, bo, pixel, 10244 r.x1, r.y1, r.x2, r.y2, 10245 gc->alu)) { 10246 if (damage) { 10247 assert_pixmap_contains_box(pixmap, &r); 10248 if (r.x2 - r.x1 == pixmap->drawable.width && 10249 r.y2 - r.y1 == pixmap->drawable.height) { 10250 sna_damage_all(damage, 10251 pixmap->drawable.width, 10252 pixmap->drawable.height); 10253 } else 10254 sna_damage_add_box(damage, &r); 10255 } 10256 assert_pixmap_damage(pixmap); 10257 10258 if ((gc->alu == GXcopy || gc->alu == GXclear) && 10259 r.x2 - r.x1 == pixmap->drawable.width && 10260 r.y2 - r.y1 == pixmap->drawable.height) { 10261 struct sna_pixmap *priv = sna_pixmap(pixmap); 10262 if (bo == priv->gpu_bo) { 10263 assert(priv->gpu_bo->proxy == NULL); 10264 sna_damage_all(&priv->gpu_damage, 10265 pixmap->drawable.width, 10266 pixmap->drawable.height); 10267 sna_damage_destroy(&priv->cpu_damage); 10268 list_del(&priv->flush_list); 10269 priv->clear = true; 10270 priv->clear_color = gc->alu == GXcopy ? pixel : 0; 10271 10272 DBG(("%s: pixmap=%ld, marking clear [%08x]\n", 10273 __FUNCTION__, pixmap->drawable.serialNumber, priv->clear_color)); 10274 } 10275 } 10276 } else 10277 success = false; 10278 } 10279 10280 return success; 10281 } 10282 10283 if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, pixel)) { 10284 DBG(("%s: unsupported blt\n", __FUNCTION__)); 10285 return false; 10286 } 10287 10288 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10289 if (!clipped) { 10290 dx += drawable->x; 10291 dy += drawable->y; 10292 10293 sna_damage_add_rectangles(damage, rect, n, dx, dy); 10294 if (dx|dy) { 10295 do { 10296 unsigned nbox = n; 10297 if (nbox > ARRAY_SIZE(boxes)) 10298 nbox = ARRAY_SIZE(boxes); 10299 n -= nbox; 10300 do { 10301 b->x1 = rect->x + dx; 10302 b->y1 = rect->y + dy; 10303 b->x2 = b->x1 + rect->width; 10304 b->y2 = b->y1 + rect->height; 10305 b++; 10306 rect++; 10307 } while (--nbox); 10308 fill.boxes(sna, &fill, boxes, b-boxes); 10309 b = boxes; 10310 } while (n); 10311 } else { 10312 do { 10313 unsigned nbox = n; 10314 if (nbox > ARRAY_SIZE(boxes)) 10315 nbox = ARRAY_SIZE(boxes); 10316 n -= nbox; 10317 do { 10318 b->x1 = rect->x; 10319 b->y1 = rect->y; 10320 b->x2 = b->x1 + rect->width; 10321 b->y2 = b->y1 + rect->height; 10322 b++; 10323 rect++; 10324 } while (--nbox); 10325 fill.boxes(sna, &fill, boxes, b-boxes); 10326 b = boxes; 10327 } while (n); 10328 } 10329 } else { 10330 RegionRec clip; 10331 10332 region_set(&clip, extents); 10333 region_maybe_clip(&clip, gc->pCompositeClip); 10334 if (RegionNil(&clip)) 10335 goto done; 10336 10337 if (clip.data == NULL) { 10338 do { 10339 b->x1 = rect->x + drawable->x; 10340 b->y1 = rect->y + drawable->y; 10341 b->x2 = bound(b->x1, rect->width); 10342 b->y2 = bound(b->y1, rect->height); 10343 rect++; 10344 10345 if (box_intersect(b, &clip.extents)) { 10346 b->x1 += dx; 10347 b->x2 += dx; 10348 b->y1 += dy; 10349 b->y2 += dy; 10350 if (++b == last_box) { 10351 fill.boxes(sna, &fill, boxes, last_box-boxes); 10352 if (damage) 10353 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10354 b = boxes; 10355 } 10356 } 10357 } while (--n); 10358 } else { 10359 const BoxRec * const clip_start = RegionBoxptr(&clip); 10360 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10361 const BoxRec *c; 10362 10363 do { 10364 BoxRec box; 10365 10366 box.x1 = rect->x + drawable->x; 10367 box.y1 = rect->y + drawable->y; 10368 box.x2 = bound(box.x1, rect->width); 10369 box.y2 = bound(box.y1, rect->height); 10370 rect++; 10371 10372 c = find_clip_box_for_y(clip_start, 10373 clip_end, 10374 box.y1); 10375 while (c != clip_end) { 10376 if (box.y2 <= c->y1) 10377 break; 10378 10379 *b = box; 10380 if (box_intersect(b, c++)) { 10381 b->x1 += dx; 10382 b->x2 += dx; 10383 b->y1 += dy; 10384 b->y2 += dy; 10385 if (++b == last_box) { 10386 fill.boxes(sna, &fill, boxes, last_box-boxes); 10387 if (damage) 10388 sna_damage_add_boxes(damage, boxes, last_box-boxes, 0, 0); 10389 b = boxes; 10390 } 10391 } 10392 10393 } 10394 } while (--n); 10395 } 10396 10397 RegionUninit(&clip); 10398 if (b != boxes) { 10399 fill.boxes(sna, &fill, boxes, b-boxes); 10400 if (damage) 10401 sna_damage_add_boxes(damage, boxes, b-boxes, 0, 0); 10402 } 10403 } 10404done: 10405 fill.done(sna, &fill); 10406 assert_pixmap_damage(pixmap); 10407 return true; 10408} 10409 10410static uint32_t 10411get_pixel(PixmapPtr pixmap) 10412{ 10413 DBG(("%s\n", __FUNCTION__)); 10414 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ)) 10415 return 0; 10416 10417 switch (pixmap->drawable.bitsPerPixel) { 10418 case 32: return *(uint32_t *)pixmap->devPrivate.ptr; 10419 case 16: return *(uint16_t *)pixmap->devPrivate.ptr; 10420 default: return *(uint8_t *)pixmap->devPrivate.ptr; 10421 } 10422} 10423 10424static void 10425sna_poly_fill_polygon(DrawablePtr draw, GCPtr gc, 10426 int shape, int mode, 10427 int n, DDXPointPtr pt) 10428{ 10429 struct sna_fill_spans data; 10430 struct sna_pixmap *priv; 10431 10432 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 10433 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 10434 (gc->fillStyle == FillSolid || 10435 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 10436 gc->fillStyle, gc->tileIsPixel, 10437 gc->alu)); 10438 DBG(("%s: draw=%ld, offset=(%d, %d), size=%dx%d\n", 10439 __FUNCTION__, draw->serialNumber, 10440 draw->x, draw->y, draw->width, draw->height)); 10441 10442 data.flags = sna_poly_point_extents(draw, gc, mode, n, pt, 10443 &data.region.extents); 10444 if (data.flags == 0) { 10445 DBG(("%s, nothing to do\n", __FUNCTION__)); 10446 return; 10447 } 10448 10449 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 10450 data.region.extents.x1, data.region.extents.y1, 10451 data.region.extents.x2, data.region.extents.y2, 10452 data.flags)); 10453 10454 data.region.data = NULL; 10455 10456 if (FORCE_FALLBACK) 10457 goto fallback; 10458 10459 if (!ACCEL_POLY_FILL_POLYGON) 10460 goto fallback; 10461 10462 data.pixmap = get_drawable_pixmap(draw); 10463 data.sna = to_sna_from_pixmap(data.pixmap); 10464 priv = sna_pixmap(data.pixmap); 10465 if (priv == NULL) { 10466 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 10467 goto fallback; 10468 } 10469 10470 if (wedged(data.sna)) { 10471 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 10472 goto fallback; 10473 } 10474 10475 if (!PM_IS_SOLID(draw, gc->planemask)) 10476 goto fallback; 10477 10478 if ((data.bo = sna_drawable_use_bo(draw, 10479 (shape == Convex ? use_zero_spans : use_wide_spans)(draw, gc, &data.region.extents), 10480 &data.region.extents, 10481 &data.damage))) { 10482 uint32_t color; 10483 10484 sna_gc(gc)->priv = &data; 10485 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 10486 10487 if (gc_is_solid(gc, &color)) { 10488 struct sna_fill_op fill; 10489 10490 if (!sna_fill_init_blt(&fill, 10491 data.sna, data.pixmap, 10492 data.bo, gc->alu, color)) 10493 goto fallback; 10494 10495 data.op = &fill; 10496 10497 if ((data.flags & 2) == 0) { 10498 if (data.dx | data.dy) 10499 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 10500 else 10501 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 10502 } else { 10503 region_maybe_clip(&data.region, 10504 gc->pCompositeClip); 10505 if (RegionNil(&data.region)) 10506 return; 10507 10508 if (region_is_singular(&data.region)) 10509 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 10510 else 10511 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 10512 } 10513 assert(gc->miTranslate); 10514 gc->ops = &sna_gc_ops__tmp; 10515 10516 miFillPolygon(draw, gc, shape, mode, n, pt); 10517 fill.done(data.sna, &fill); 10518 } else { 10519 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 10520 gc->ops = &sna_gc_ops__tmp; 10521 10522 miFillPolygon(draw, gc, shape, mode, n, pt); 10523 } 10524 10525 gc->ops = (GCOps *)&sna_gc_ops; 10526 if (data.damage) { 10527 if (data.dx | data.dy) 10528 pixman_region_translate(&data.region, data.dx, data.dy); 10529 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 10530 sna_damage_add(data.damage, &data.region); 10531 } 10532 assert_pixmap_damage(data.pixmap); 10533 RegionUninit(&data.region); 10534 return; 10535 } 10536 10537fallback: 10538 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 10539 data.region.extents.x1, data.region.extents.y1, 10540 data.region.extents.x2, data.region.extents.y2)); 10541 region_maybe_clip(&data.region, gc->pCompositeClip); 10542 if (RegionNil(&data.region)) { 10543 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 10544 return; 10545 } 10546 10547 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 10548 goto out; 10549 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 10550 drawable_gc_flags(draw, gc, true))) 10551 goto out_gc; 10552 10553 DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n", 10554 __FUNCTION__)); 10555 miFillPolygon(draw, gc, shape, mode, n, pt); 10556out_gc: 10557 sna_gc_move_to_gpu(gc); 10558out: 10559 RegionUninit(&data.region); 10560} 10561 10562static struct kgem_bo * 10563sna_pixmap_get_source_bo(PixmapPtr pixmap) 10564{ 10565 struct sna_pixmap *priv = sna_pixmap(pixmap); 10566 10567 if (priv == NULL) { 10568 struct kgem_bo *upload; 10569 struct sna *sna = to_sna_from_pixmap(pixmap); 10570 void *ptr; 10571 10572 upload = kgem_create_buffer_2d(&sna->kgem, 10573 pixmap->drawable.width, 10574 pixmap->drawable.height, 10575 pixmap->drawable.bitsPerPixel, 10576 KGEM_BUFFER_WRITE_INPLACE, 10577 &ptr); 10578 if (upload == NULL) 10579 return NULL; 10580 10581 assert(has_coherent_ptr(sna_pixmap(pixmap))); 10582 memcpy_blt(pixmap->devPrivate.ptr, ptr, 10583 pixmap->drawable.bitsPerPixel, 10584 pixmap->devKind, upload->pitch, 10585 0, 0, 10586 0, 0, 10587 pixmap->drawable.width, 10588 pixmap->drawable.height); 10589 10590 return upload; 10591 } 10592 10593 if (priv->gpu_damage && 10594 !sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT)) 10595 return NULL; 10596 10597 if (priv->cpu_damage && priv->cpu_bo) 10598 return kgem_bo_reference(priv->cpu_bo); 10599 10600 if (!sna_pixmap_force_to_gpu(pixmap, MOVE_READ)) 10601 return NULL; 10602 10603 return kgem_bo_reference(priv->gpu_bo); 10604} 10605 10606/* 10607static bool 10608tile(DrawablePtr drawable, 10609 struct kgem_bo *bo, struct sna_damage **damage, 10610 PixmapPtr tile, const DDXPointRec * const origin, int alu, 10611 int n, xRectangle *rect, 10612 const BoxRec *extents, unsigned clipped) 10613 */ 10614 10615static bool 10616sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable, 10617 struct kgem_bo *bo, struct sna_damage **damage, 10618 struct kgem_bo *tile_bo, GCPtr gc, 10619 int n, const xRectangle *r, 10620 const BoxRec *extents, unsigned clipped) 10621{ 10622 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10623 struct sna *sna = to_sna_from_pixmap(pixmap); 10624 const DDXPointRec * const origin = &gc->patOrg; 10625 uint32_t br00, br13; 10626 int tx, ty; 10627 int16_t dx, dy; 10628 uint32_t *b; 10629 10630 if (NO_TILE_8x8) 10631 return false; 10632 10633 DBG(("%s x %d [(%d, %d)x(%d, %d)...], clipped=%x\n", 10634 __FUNCTION__, n, r->x, r->y, r->width, r->height, clipped)); 10635 10636 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 10637 if (!kgem_check_batch(&sna->kgem, 8+2*3) || 10638 !kgem_check_reloc(&sna->kgem, 2) || 10639 !kgem_check_bo_fenced(&sna->kgem, bo)) { 10640 kgem_submit(&sna->kgem); 10641 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 10642 return false; 10643 _kgem_set_mode(&sna->kgem, KGEM_BLT); 10644 } 10645 10646 br00 = XY_SCANLINE_BLT; 10647 br13 = bo->pitch; 10648 if (sna->kgem.gen >= 040 && bo->tiling) { 10649 br00 |= BLT_DST_TILED; 10650 br13 >>= 2; 10651 } 10652 br13 |= blt_depth(drawable->depth) << 24; 10653 br13 |= fill_ROP[gc->alu] << 16; 10654 10655 get_drawable_deltas(drawable, pixmap, &dx, &dy); 10656 assert(extents->x1 + dx >= 0); 10657 assert(extents->y1 + dy >= 0); 10658 assert(extents->x2 + dx <= pixmap->drawable.width); 10659 assert(extents->y2 + dy <= pixmap->drawable.height); 10660 10661 if (!clipped) { 10662 dx += drawable->x; 10663 dy += drawable->y; 10664 10665 sna_damage_add_rectangles(damage, r, n, dx, dy); 10666 if (n == 1) { 10667 tx = (r->x - origin->x) % 8; 10668 if (tx < 0) 10669 tx = 8 - tx; 10670 ty = (r->y - origin->y) % 8; 10671 if (ty < 0) 10672 ty = 8 - ty; 10673 10674 assert(r->x + dx >= 0); 10675 assert(r->y + dy >= 0); 10676 assert(r->x + dx + r->width <= pixmap->drawable.width); 10677 assert(r->y + dy + r->height <= pixmap->drawable.height); 10678 10679 b = sna->kgem.batch + sna->kgem.nbatch; 10680 b[0] = XY_PAT_BLT | tx << 12 | ty << 8 | 3 << 20 | (br00 & BLT_DST_TILED); 10681 b[1] = br13; 10682 b[2] = (r->y + dy) << 16 | (r->x + dx); 10683 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 10684 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 10685 I915_GEM_DOMAIN_RENDER << 16 | 10686 I915_GEM_DOMAIN_RENDER | 10687 KGEM_RELOC_FENCED, 10688 0); 10689 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, tile_bo, 10690 I915_GEM_DOMAIN_RENDER << 16 | 10691 KGEM_RELOC_FENCED, 10692 0); 10693 sna->kgem.nbatch += 6; 10694 } else do { 10695 int n_this_time; 10696 10697 b = sna->kgem.batch + sna->kgem.nbatch; 10698 b[0] = XY_SETUP_BLT | 3 << 20; 10699 b[1] = br13; 10700 b[2] = 0; 10701 b[3] = 0; 10702 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 10703 I915_GEM_DOMAIN_RENDER << 16 | 10704 I915_GEM_DOMAIN_RENDER | 10705 KGEM_RELOC_FENCED, 10706 0); 10707 b[5] = gc->bgPixel; 10708 b[6] = gc->fgPixel; 10709 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 10710 I915_GEM_DOMAIN_RENDER << 16 | 10711 KGEM_RELOC_FENCED, 10712 0); 10713 sna->kgem.nbatch += 8; 10714 10715 n_this_time = n; 10716 if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) 10717 n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3; 10718 assert(n_this_time); 10719 n -= n_this_time; 10720 10721 b = sna->kgem.batch + sna->kgem.nbatch; 10722 sna->kgem.nbatch += 3*n_this_time; 10723 do { 10724 assert(r->x + dx >= 0); 10725 assert(r->y + dy >= 0); 10726 assert(r->x + dx + r->width <= pixmap->drawable.width); 10727 assert(r->y + dy + r->height <= pixmap->drawable.height); 10728 10729 tx = (r->x - origin->x) % 8; 10730 if (tx < 0) 10731 tx = 8 - tx; 10732 ty = (r->y - origin->y) % 8; 10733 if (ty < 0) 10734 ty = 8 - ty; 10735 10736 b[0] = br00 | tx << 12 | ty << 8; 10737 b[1] = (r->y + dy) << 16 | (r->x + dx); 10738 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 10739 b += 3; r++; 10740 } while (--n_this_time); 10741 10742 if (!n) 10743 break; 10744 10745 _kgem_submit(&sna->kgem); 10746 _kgem_set_mode(&sna->kgem, KGEM_BLT); 10747 } while (1); 10748 } else { 10749 RegionRec clip; 10750 uint16_t unwind_batch, unwind_reloc; 10751 10752 region_set(&clip, extents); 10753 region_maybe_clip(&clip, gc->pCompositeClip); 10754 if (RegionNil(&clip)) 10755 goto done; 10756 10757 unwind_batch = sna->kgem.nbatch; 10758 unwind_reloc = sna->kgem.nreloc; 10759 10760 b = sna->kgem.batch + sna->kgem.nbatch; 10761 b[0] = XY_SETUP_BLT | 3 << 20; 10762 b[1] = br13; 10763 b[2] = 0; 10764 b[3] = 0; 10765 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 10766 I915_GEM_DOMAIN_RENDER << 16 | 10767 I915_GEM_DOMAIN_RENDER | 10768 KGEM_RELOC_FENCED, 10769 0); 10770 b[5] = gc->bgPixel; 10771 b[6] = gc->fgPixel; 10772 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 10773 I915_GEM_DOMAIN_RENDER << 16 | 10774 KGEM_RELOC_FENCED, 10775 0); 10776 sna->kgem.nbatch += 8; 10777 10778 if (clip.data == NULL) { 10779 const BoxRec *c = &clip.extents; 10780 while (n--) { 10781 BoxRec box; 10782 10783 box.x1 = r->x + drawable->x; 10784 box.y1 = r->y + drawable->y; 10785 box.x2 = bound(box.x1, r->width); 10786 box.y2 = bound(box.y1, r->height); 10787 r++; 10788 10789 if (box_intersect(&box, c)) { 10790 if (!kgem_check_batch(&sna->kgem, 3)) { 10791 _kgem_submit(&sna->kgem); 10792 _kgem_set_mode(&sna->kgem, KGEM_BLT); 10793 10794 unwind_batch = sna->kgem.nbatch; 10795 unwind_reloc = sna->kgem.nreloc; 10796 10797 b = sna->kgem.batch + sna->kgem.nbatch; 10798 b[0] = XY_SETUP_BLT | 3 << 20; 10799 b[1] = br13; 10800 b[2] = 0; 10801 b[3] = 0; 10802 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 10803 I915_GEM_DOMAIN_RENDER << 16 | 10804 I915_GEM_DOMAIN_RENDER | 10805 KGEM_RELOC_FENCED, 10806 0); 10807 b[5] = gc->bgPixel; 10808 b[6] = gc->fgPixel; 10809 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 10810 I915_GEM_DOMAIN_RENDER << 16 | 10811 KGEM_RELOC_FENCED, 10812 0); 10813 sna->kgem.nbatch += 8; 10814 } 10815 10816 assert(box.x1 + dx >= 0); 10817 assert(box.y1 + dy >= 0); 10818 assert(box.x2 + dx <= pixmap->drawable.width); 10819 assert(box.y2 + dy <= pixmap->drawable.height); 10820 10821 ty = (box.y1 - drawable->y - origin->y) % 8; 10822 if (ty < 0) 10823 ty = 8 - ty; 10824 10825 tx = (box.x1 - drawable->x - origin->x) % 8; 10826 if (tx < 0) 10827 tx = 8 - tx; 10828 10829 b = sna->kgem.batch + sna->kgem.nbatch; 10830 b[0] = br00 | tx << 12 | ty << 8; 10831 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 10832 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 10833 sna->kgem.nbatch += 3; 10834 } 10835 } 10836 } else { 10837 const BoxRec * const clip_start = RegionBoxptr(&clip); 10838 const BoxRec * const clip_end = clip_start + clip.data->numRects; 10839 const BoxRec *c; 10840 10841 do { 10842 BoxRec box; 10843 10844 box.x1 = r->x + drawable->x; 10845 box.y1 = r->y + drawable->y; 10846 box.x2 = bound(box.x1, r->width); 10847 box.y2 = bound(box.y1, r->height); 10848 r++; 10849 10850 c = find_clip_box_for_y(clip_start, 10851 clip_end, 10852 box.y1); 10853 while (c != clip_end) { 10854 BoxRec bb; 10855 10856 if (box.y2 <= c->y1) 10857 break; 10858 10859 bb = box; 10860 if (box_intersect(&bb, c++)) { 10861 if (!kgem_check_batch(&sna->kgem, 3)) { 10862 _kgem_submit(&sna->kgem); 10863 _kgem_set_mode(&sna->kgem, KGEM_BLT); 10864 10865 unwind_batch = sna->kgem.nbatch; 10866 unwind_reloc = sna->kgem.nreloc; 10867 10868 b = sna->kgem.batch + sna->kgem.nbatch; 10869 b[0] = XY_SETUP_BLT | 3 << 20; 10870 b[1] = br13; 10871 b[2] = 0; 10872 b[3] = 0; 10873 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 10874 I915_GEM_DOMAIN_RENDER << 16 | 10875 I915_GEM_DOMAIN_RENDER | 10876 KGEM_RELOC_FENCED, 10877 0); 10878 b[5] = gc->bgPixel; 10879 b[6] = gc->fgPixel; 10880 b[7] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 7, tile_bo, 10881 I915_GEM_DOMAIN_RENDER << 16 | 10882 KGEM_RELOC_FENCED, 10883 0); 10884 sna->kgem.nbatch += 8; 10885 } 10886 10887 assert(bb.x1 + dx >= 0); 10888 assert(bb.y1 + dy >= 0); 10889 assert(bb.x2 + dx <= pixmap->drawable.width); 10890 assert(bb.y2 + dy <= pixmap->drawable.height); 10891 10892 ty = (bb.y1 - drawable->y - origin->y) % 8; 10893 if (ty < 0) 10894 ty = 8 - ty; 10895 10896 tx = (bb.x1 - drawable->x - origin->x) % 8; 10897 if (tx < 0) 10898 tx = 8 - tx; 10899 10900 b = sna->kgem.batch + sna->kgem.nbatch; 10901 b[0] = br00 | tx << 12 | ty << 8; 10902 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 10903 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 10904 sna->kgem.nbatch += 3; 10905 } 10906 } 10907 } while (--n); 10908 } 10909 10910 if (sna->kgem.nbatch == unwind_batch + 8) { 10911 sna->kgem.nbatch = unwind_batch; 10912 sna->kgem.nreloc = unwind_reloc; 10913 } 10914 } 10915done: 10916 assert_pixmap_damage(pixmap); 10917 sna->blt_state.fill_bo = 0; 10918 return true; 10919} 10920 10921static bool 10922sna_poly_fill_rect_tiled_nxm_blt(DrawablePtr drawable, 10923 struct kgem_bo *bo, 10924 struct sna_damage **damage, 10925 GCPtr gc, int n, const xRectangle *rect, 10926 const BoxRec *extents, unsigned clipped) 10927{ 10928 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10929 struct sna *sna = to_sna_from_pixmap(pixmap); 10930 PixmapPtr tile = gc->tile.pixmap; 10931 struct kgem_bo *upload; 10932 int w, h, cpp; 10933 void *ptr; 10934 bool ret; 10935 10936 DBG(("%s: %dx%d\n", __FUNCTION__, 10937 tile->drawable.width, tile->drawable.height)); 10938 10939 if (!sna_pixmap_move_to_cpu(tile, MOVE_READ)) 10940 return false; 10941 10942 upload = kgem_create_buffer(&sna->kgem, 8*tile->drawable.bitsPerPixel, 10943 KGEM_BUFFER_WRITE_INPLACE, 10944 &ptr); 10945 if (upload == NULL) 10946 return false; 10947 10948 assert(tile->drawable.height && tile->drawable.height <= 8); 10949 assert(tile->drawable.width && tile->drawable.width <= 8); 10950 assert(has_coherent_ptr(sna_pixmap(tile))); 10951 10952 cpp = tile->drawable.bitsPerPixel/8; 10953 for (h = 0; h < tile->drawable.height; h++) { 10954 uint8_t *src = (uint8_t *)tile->devPrivate.ptr + tile->devKind*h; 10955 uint8_t *dst = (uint8_t *)ptr + 8*cpp*h; 10956 10957 w = tile->drawable.width*cpp; 10958 memcpy(dst, src, w); 10959 while (w < 8*cpp) { 10960 memcpy(dst+w, dst, w); 10961 w *= 2; 10962 } 10963 } 10964 while (h < 8) { 10965 memcpy((uint8_t*)ptr + h*w, ptr, h*w); 10966 h *= 2; 10967 } 10968 10969 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 10970 upload, gc, n, rect, 10971 extents, clipped); 10972 10973 kgem_bo_destroy(&sna->kgem, upload); 10974 return ret; 10975} 10976 10977static bool 10978sna_poly_fill_rect_tiled_blt(DrawablePtr drawable, 10979 struct kgem_bo *bo, 10980 struct sna_damage **damage, 10981 GCPtr gc, int n, xRectangle *rect, 10982 const BoxRec *extents, unsigned clipped) 10983{ 10984 PixmapPtr pixmap = get_drawable_pixmap(drawable); 10985 struct sna *sna = to_sna_from_pixmap(pixmap); 10986 PixmapPtr tile = gc->tile.pixmap; 10987 struct kgem_bo *tile_bo; 10988 const DDXPointRec * const origin = &gc->patOrg; 10989 struct sna_copy_op copy; 10990 CARD32 alu = gc->alu; 10991 int tile_width, tile_height; 10992 int16_t dx, dy; 10993 10994 DBG(("%s x %d [(%d, %d)x(%d, %d)...]\n", 10995 __FUNCTION__, n, rect->x, rect->y, rect->width, rect->height)); 10996 10997 tile_width = tile->drawable.width; 10998 tile_height = tile->drawable.height; 10999 if ((tile_width | tile_height) == 1) { 11000 DBG(("%s: single pixel tile pixmap ,converting to solid fill\n", 11001 __FUNCTION__)); 11002 return sna_poly_fill_rect_blt(drawable, bo, damage, 11003 gc, get_pixel(tile), 11004 n, rect, 11005 extents, clipped); 11006 } 11007 11008 /* XXX [248]x[238] tiling can be reduced to a pattern fill. 11009 * Also we can do the lg2 reduction for BLT and use repeat modes for 11010 * RENDER. 11011 */ 11012 11013 if ((tile->drawable.width | tile->drawable.height) == 8) { 11014 bool ret; 11015 11016 tile_bo = sna_pixmap_get_source_bo(tile); 11017 ret = sna_poly_fill_rect_tiled_8x8_blt(drawable, bo, damage, 11018 tile_bo, gc, n, rect, 11019 extents, clipped); 11020 kgem_bo_destroy(&sna->kgem, tile_bo); 11021 11022 return ret; 11023 } 11024 11025 if ((tile->drawable.width | tile->drawable.height) <= 0xc && 11026 is_power_of_two(tile->drawable.width) && 11027 is_power_of_two(tile->drawable.height)) 11028 return sna_poly_fill_rect_tiled_nxm_blt(drawable, bo, damage, 11029 gc, n, rect, 11030 extents, clipped); 11031 11032 tile_bo = sna_pixmap_get_source_bo(tile); 11033 if (tile_bo == NULL) { 11034 DBG(("%s: unable to move tile go GPU, fallback\n", 11035 __FUNCTION__)); 11036 return false; 11037 } 11038 11039 if (!sna_copy_init_blt(©, sna, tile, tile_bo, pixmap, bo, alu)) { 11040 DBG(("%s: unsupported blt\n", __FUNCTION__)); 11041 kgem_bo_destroy(&sna->kgem, tile_bo); 11042 return false; 11043 } 11044 11045 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11046 if (!clipped) { 11047 dx += drawable->x; 11048 dy += drawable->y; 11049 11050 sna_damage_add_rectangles(damage, rect, n, dx, dy); 11051 do { 11052 xRectangle r = *rect++; 11053 int16_t tile_y = (r.y - origin->y) % tile_height; 11054 if (tile_y < 0) 11055 tile_y += tile_height; 11056 11057 assert(r.x + dx >= 0); 11058 assert(r.y + dy >= 0); 11059 assert(r.x + dx + r.width <= pixmap->drawable.width); 11060 assert(r.y + dy + r.height <= pixmap->drawable.height); 11061 11062 r.y += dy; 11063 do { 11064 int16_t width = r.width; 11065 int16_t x = r.x + dx, tile_x; 11066 int16_t h = tile_height - tile_y; 11067 if (h > r.height) 11068 h = r.height; 11069 r.height -= h; 11070 11071 tile_x = (r.x - origin->x) % tile_width; 11072 if (tile_x < 0) 11073 tile_x += tile_width; 11074 11075 do { 11076 int16_t w = tile_width - tile_x; 11077 if (w > width) 11078 w = width; 11079 width -= w; 11080 11081 copy.blt(sna, ©, 11082 tile_x, tile_y, 11083 w, h, 11084 x, r.y); 11085 11086 x += w; 11087 tile_x = 0; 11088 } while (width); 11089 r.y += h; 11090 tile_y = 0; 11091 } while (r.height); 11092 } while (--n); 11093 } else { 11094 RegionRec clip; 11095 11096 region_set(&clip, extents); 11097 region_maybe_clip(&clip, gc->pCompositeClip); 11098 if (RegionNil(&clip)) 11099 goto done; 11100 11101 if (clip.data == NULL) { 11102 const BoxRec *box = &clip.extents; 11103 while (n--) { 11104 BoxRec r; 11105 11106 r.x1 = rect->x + drawable->x; 11107 r.y1 = rect->y + drawable->y; 11108 r.x2 = bound(r.x1, rect->width); 11109 r.y2 = bound(r.y1, rect->height); 11110 rect++; 11111 11112 if (box_intersect(&r, box)) { 11113 int height = r.y2 - r.y1; 11114 int dst_y = r.y1; 11115 int tile_y = (r.y1 - drawable->y - origin->y) % tile_height; 11116 if (tile_y < 0) 11117 tile_y += tile_height; 11118 11119 while (height) { 11120 int width = r.x2 - r.x1; 11121 int dst_x = r.x1, tile_x; 11122 int h = tile_height - tile_y; 11123 if (h > height) 11124 h = height; 11125 height -= h; 11126 11127 tile_x = (r.x1 - drawable->x - origin->x) % tile_width; 11128 if (tile_x < 0) 11129 tile_x += tile_width; 11130 11131 while (width > 0) { 11132 int w = tile_width - tile_x; 11133 if (w > width) 11134 w = width; 11135 width -= w; 11136 11137 copy.blt(sna, ©, 11138 tile_x, tile_y, 11139 w, h, 11140 dst_x + dx, dst_y + dy); 11141 if (damage) { 11142 BoxRec b; 11143 11144 b.x1 = dst_x + dx; 11145 b.y1 = dst_y + dy; 11146 b.x2 = b.x1 + w; 11147 b.y2 = b.y1 + h; 11148 11149 assert_pixmap_contains_box(pixmap, &b); 11150 sna_damage_add_box(damage, &b); 11151 } 11152 11153 dst_x += w; 11154 tile_x = 0; 11155 } 11156 dst_y += h; 11157 tile_y = 0; 11158 } 11159 } 11160 } 11161 } else { 11162 while (n--) { 11163 RegionRec region; 11164 BoxRec *box; 11165 int nbox; 11166 11167 region.extents.x1 = rect->x + drawable->x; 11168 region.extents.y1 = rect->y + drawable->y; 11169 region.extents.x2 = bound(region.extents.x1, rect->width); 11170 region.extents.y2 = bound(region.extents.y1, rect->height); 11171 rect++; 11172 11173 region.data = NULL; 11174 RegionIntersect(®ion, ®ion, &clip); 11175 11176 nbox = RegionNumRects(®ion); 11177 box = RegionRects(®ion); 11178 while (nbox--) { 11179 int height = box->y2 - box->y1; 11180 int dst_y = box->y1; 11181 int tile_y = (box->y1 - drawable->y - origin->y) % tile_height; 11182 if (tile_y < 0) 11183 tile_y += tile_height; 11184 11185 while (height) { 11186 int width = box->x2 - box->x1; 11187 int dst_x = box->x1, tile_x; 11188 int h = tile_height - tile_y; 11189 if (h > height) 11190 h = height; 11191 height -= h; 11192 11193 tile_x = (box->x1 - drawable->x - origin->x) % tile_width; 11194 if (tile_x < 0) 11195 tile_x += tile_width; 11196 11197 while (width > 0) { 11198 int w = tile_width - tile_x; 11199 if (w > width) 11200 w = width; 11201 width -= w; 11202 11203 copy.blt(sna, ©, 11204 tile_x, tile_y, 11205 w, h, 11206 dst_x + dx, dst_y + dy); 11207 if (damage) { 11208 BoxRec b; 11209 11210 b.x1 = dst_x + dx; 11211 b.y1 = dst_y + dy; 11212 b.x2 = b.x1 + w; 11213 b.y2 = b.y1 + h; 11214 11215 assert_pixmap_contains_box(pixmap, &b); 11216 sna_damage_add_box(damage, &b); 11217 } 11218 11219 dst_x += w; 11220 tile_x = 0; 11221 } 11222 dst_y += h; 11223 tile_y = 0; 11224 } 11225 box++; 11226 } 11227 11228 RegionUninit(®ion); 11229 } 11230 } 11231 11232 RegionUninit(&clip); 11233 } 11234done: 11235 copy.done(sna, ©); 11236 assert_pixmap_damage(pixmap); 11237 kgem_bo_destroy(&sna->kgem, tile_bo); 11238 return true; 11239} 11240 11241static bool 11242sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable, 11243 struct kgem_bo *bo, 11244 struct sna_damage **damage, 11245 GCPtr gc, int n, xRectangle *r, 11246 const BoxRec *extents, unsigned clipped) 11247{ 11248 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11249 struct sna *sna = to_sna_from_pixmap(pixmap); 11250 uint32_t pat[2] = {0, 0}, br00, br13; 11251 int16_t dx, dy; 11252 uint32_t *b; 11253 11254 if (NO_STIPPLE_8x8) 11255 return false; 11256 11257 DBG(("%s: alu=%d, upload (%d, %d), (%d, %d), origin (%d, %d)\n", 11258 __FUNCTION__, gc->alu, 11259 extents->x1, extents->y1, 11260 extents->x2, extents->y2, 11261 gc->patOrg.x, gc->patOrg.y)); 11262 11263 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11264 { 11265 unsigned px = (0 - gc->patOrg.x - dx) & 7; 11266 unsigned py = (0 - gc->patOrg.y - dy) & 7; 11267 DBG(("%s: pat offset (%d, %d)\n", __FUNCTION__ ,px, py)); 11268 br00 = XY_SCANLINE_BLT | px << 12 | py << 8 | 3 << 20; 11269 br13 = bo->pitch; 11270 if (sna->kgem.gen >= 040 && bo->tiling) { 11271 br00 |= BLT_DST_TILED; 11272 br13 >>= 2; 11273 } 11274 br13 |= (gc->fillStyle == FillStippled) << 28; 11275 br13 |= blt_depth(drawable->depth) << 24; 11276 br13 |= fill_ROP[gc->alu] << 16; 11277 } 11278 11279 { 11280 uint8_t *dst = (uint8_t *)pat; 11281 const uint8_t *src = gc->stipple->devPrivate.ptr; 11282 int stride = gc->stipple->devKind; 11283 int j = gc->stipple->drawable.height; 11284 do { 11285 *dst++ = byte_reverse(*src); 11286 src += stride; 11287 } while (--j); 11288 } 11289 11290 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 11291 if (!kgem_check_batch(&sna->kgem, 9 + 2*3) || 11292 !kgem_check_bo_fenced(&sna->kgem, bo) || 11293 !kgem_check_reloc(&sna->kgem, 1)) { 11294 kgem_submit(&sna->kgem); 11295 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11296 return false; 11297 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11298 } 11299 11300 if (!clipped) { 11301 dx += drawable->x; 11302 dy += drawable->y; 11303 11304 sna_damage_add_rectangles(damage, r, n, dx, dy); 11305 if (n == 1) { 11306 DBG(("%s: single unclipped rect (%d, %d)x(%d, %d)\n", 11307 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 11308 11309 b = sna->kgem.batch + sna->kgem.nbatch; 11310 b[0] = XY_MONO_PAT | (br00 & (BLT_DST_TILED | 0x7<<12 | 0x7<<8)) | 3<<20; 11311 b[1] = br13; 11312 b[2] = (r->y + dy) << 16 | (r->x + dx); 11313 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 11314 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 11315 I915_GEM_DOMAIN_RENDER << 16 | 11316 I915_GEM_DOMAIN_RENDER | 11317 KGEM_RELOC_FENCED, 11318 0); 11319 b[5] = gc->bgPixel; 11320 b[6] = gc->fgPixel; 11321 b[7] = pat[0]; 11322 b[8] = pat[1]; 11323 sna->kgem.nbatch += 9; 11324 } else do { 11325 int n_this_time; 11326 11327 b = sna->kgem.batch + sna->kgem.nbatch; 11328 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20; 11329 b[1] = br13; 11330 b[2] = 0; 11331 b[3] = 0; 11332 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 11333 I915_GEM_DOMAIN_RENDER << 16 | 11334 I915_GEM_DOMAIN_RENDER | 11335 KGEM_RELOC_FENCED, 11336 0); 11337 b[5] = gc->bgPixel; 11338 b[6] = gc->fgPixel; 11339 b[7] = pat[0]; 11340 b[8] = pat[1]; 11341 sna->kgem.nbatch += 9; 11342 11343 n_this_time = n; 11344 if (3*n_this_time > sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) 11345 n_this_time = (sna->kgem.surface - sna->kgem.nbatch - KGEM_BATCH_RESERVED) / 3; 11346 assert(n_this_time); 11347 n -= n_this_time; 11348 11349 b = sna->kgem.batch + sna->kgem.nbatch; 11350 sna->kgem.nbatch += 3 * n_this_time; 11351 do { 11352 DBG(("%s: rect (%d, %d)x(%d, %d)\n", 11353 __FUNCTION__, r->x + dx, r->y + dy, r->width, r->height)); 11354 assert(r->x + dx >= 0); 11355 assert(r->y + dy >= 0); 11356 assert(r->x + dx + r->width <= pixmap->drawable.width); 11357 assert(r->y + dy + r->height <= pixmap->drawable.height); 11358 11359 b[0] = br00; 11360 b[1] = (r->y + dy) << 16 | (r->x + dx); 11361 b[2] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 11362 11363 b += 3; r++; 11364 } while(--n_this_time); 11365 11366 if (!n) 11367 break; 11368 11369 _kgem_submit(&sna->kgem); 11370 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11371 } while (1); 11372 } else { 11373 RegionRec clip; 11374 11375 region_set(&clip, extents); 11376 region_maybe_clip(&clip, gc->pCompositeClip); 11377 if (RegionNil(&clip)) 11378 return true; 11379 11380 b = sna->kgem.batch + sna->kgem.nbatch; 11381 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20; 11382 b[1] = br13; 11383 b[2] = 0; 11384 b[3] = 0; 11385 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 11386 I915_GEM_DOMAIN_RENDER << 16 | 11387 I915_GEM_DOMAIN_RENDER | 11388 KGEM_RELOC_FENCED, 11389 0); 11390 b[5] = gc->bgPixel; 11391 b[6] = gc->fgPixel; 11392 b[7] = pat[0]; 11393 b[8] = pat[1]; 11394 sna->kgem.nbatch += 9; 11395 11396 if (clip.data == NULL) { 11397 do { 11398 BoxRec box; 11399 11400 box.x1 = r->x + drawable->x; 11401 box.y1 = r->y + drawable->y; 11402 box.x2 = bound(box.x1, r->width); 11403 box.y2 = bound(box.y1, r->height); 11404 r++; 11405 11406 if (box_intersect(&box, &clip.extents)) { 11407 if (!kgem_check_batch(&sna->kgem, 3)) { 11408 _kgem_submit(&sna->kgem); 11409 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11410 11411 b = sna->kgem.batch + sna->kgem.nbatch; 11412 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20; 11413 b[1] = br13; 11414 b[2] = 0; 11415 b[3] = 0; 11416 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 11417 I915_GEM_DOMAIN_RENDER << 16 | 11418 I915_GEM_DOMAIN_RENDER | 11419 KGEM_RELOC_FENCED, 11420 0); 11421 b[5] = gc->bgPixel; 11422 b[6] = gc->fgPixel; 11423 b[7] = pat[0]; 11424 b[8] = pat[1]; 11425 sna->kgem.nbatch += 9; 11426 } 11427 11428 b = sna->kgem.batch + sna->kgem.nbatch; 11429 sna->kgem.nbatch += 3; 11430 b[0] = br00; 11431 b[1] = (box.y1 + dy) << 16 | (box.x1 + dx); 11432 b[2] = (box.y2 + dy) << 16 | (box.x2 + dx); 11433 } 11434 } while (--n); 11435 } else { 11436 const BoxRec * const clip_start = RegionBoxptr(&clip); 11437 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11438 const BoxRec *c; 11439 11440 do { 11441 BoxRec box; 11442 11443 box.x1 = r->x + drawable->x; 11444 box.y1 = r->y + drawable->y; 11445 box.x2 = bound(box.x1, r->width); 11446 box.y2 = bound(box.y1, r->height); 11447 r++; 11448 11449 c = find_clip_box_for_y(clip_start, 11450 clip_end, 11451 box.y1); 11452 while (c != clip_end) { 11453 BoxRec bb; 11454 if (box.y2 <= c->y1) 11455 break; 11456 11457 bb = box; 11458 if (box_intersect(&bb, c++)) { 11459 if (!kgem_check_batch(&sna->kgem, 3)) { 11460 _kgem_submit(&sna->kgem); 11461 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11462 11463 b = sna->kgem.batch + sna->kgem.nbatch; 11464 b[0] = XY_SETUP_MONO_PATTERN_SL_BLT | 3 << 20; 11465 b[1] = br13; 11466 b[2] = 0; 11467 b[3] = 0; 11468 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 11469 I915_GEM_DOMAIN_RENDER << 16 | 11470 I915_GEM_DOMAIN_RENDER | 11471 KGEM_RELOC_FENCED, 11472 0); 11473 b[5] = gc->bgPixel; 11474 b[6] = gc->fgPixel; 11475 b[7] = pat[0]; 11476 b[8] = pat[1]; 11477 sna->kgem.nbatch += 9; 11478 } 11479 11480 b = sna->kgem.batch + sna->kgem.nbatch; 11481 sna->kgem.nbatch += 3; 11482 b[0] = br00; 11483 b[1] = (bb.y1 + dy) << 16 | (bb.x1 + dx); 11484 b[2] = (bb.y2 + dy) << 16 | (bb.x2 + dx); 11485 } 11486 } 11487 } while (--n); 11488 } 11489 } 11490 11491 assert_pixmap_damage(pixmap); 11492 sna->blt_state.fill_bo = 0; 11493 return true; 11494} 11495 11496static bool 11497sna_poly_fill_rect_stippled_nxm_blt(DrawablePtr drawable, 11498 struct kgem_bo *bo, 11499 struct sna_damage **damage, 11500 GCPtr gc, int n, xRectangle *r, 11501 const BoxRec *extents, unsigned clipped) 11502{ 11503 PixmapPtr scratch, stipple; 11504 uint8_t bytes[8], *dst = bytes; 11505 const uint8_t *src, *end; 11506 int j, stride; 11507 bool ret; 11508 11509 DBG(("%s: expanding %dx%d stipple to 8x8\n", 11510 __FUNCTION__, 11511 gc->stipple->drawable.width, 11512 gc->stipple->drawable.height)); 11513 11514 scratch = GetScratchPixmapHeader(drawable->pScreen, 11515 8, 8, 1, 1, 1, bytes); 11516 if (scratch == NullPixmap) 11517 return false; 11518 11519 stipple = gc->stipple; 11520 gc->stipple = scratch; 11521 11522 stride = stipple->devKind; 11523 src = stipple->devPrivate.ptr; 11524 end = src + stride * stipple->drawable.height; 11525 for(j = 0; j < 8; j++) { 11526 switch (stipple->drawable.width) { 11527 case 1: *dst = (*src & 1) * 0xff; break; 11528 case 2: *dst = (*src & 3) * 0x55; break; 11529 case 4: *dst = (*src & 15) * 0x11; break; 11530 case 8: *dst = *src; break; 11531 default: assert(0); break; 11532 } 11533 dst++; 11534 src += stride; 11535 if (src == end) 11536 src = stipple->devPrivate.ptr; 11537 } 11538 11539 ret = sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 11540 gc, n, r, extents, clipped); 11541 11542 gc->stipple = stipple; 11543 FreeScratchPixmapHeader(scratch); 11544 11545 return ret; 11546} 11547 11548static bool 11549sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable, 11550 struct kgem_bo *bo, 11551 struct sna_damage **damage, 11552 GCPtr gc, int n, xRectangle *r, 11553 const BoxRec *extents, unsigned clipped) 11554{ 11555 PixmapPtr pixmap = get_drawable_pixmap(drawable); 11556 struct sna *sna = to_sna_from_pixmap(pixmap); 11557 PixmapPtr stipple = gc->stipple; 11558 const DDXPointRec *origin = &gc->patOrg; 11559 int16_t dx, dy; 11560 uint32_t br00, br13; 11561 11562 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%x\n", __FUNCTION__, 11563 extents->x1, extents->y1, 11564 extents->x2, extents->y2, 11565 origin->x, origin->y, 11566 clipped)); 11567 11568 get_drawable_deltas(drawable, pixmap, &dx, &dy); 11569 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 11570 11571 br00 = 3 << 20; 11572 br13 = bo->pitch; 11573 if (sna->kgem.gen >= 040 && bo->tiling) { 11574 br00 |= BLT_DST_TILED; 11575 br13 >>= 2; 11576 } 11577 br13 |= (gc->fillStyle == FillStippled) << 29; 11578 br13 |= blt_depth(drawable->depth) << 24; 11579 br13 |= copy_ROP[gc->alu] << 16; 11580 11581 if (!clipped) { 11582 dx += drawable->x; 11583 dy += drawable->y; 11584 11585 sna_damage_add_rectangles(damage, r, n, dx, dy); 11586 do { 11587 int bx1 = (r->x - origin->x) & ~7; 11588 int bx2 = (r->x + r->width - origin->x + 7) & ~7; 11589 int bw = (bx2 - bx1)/8; 11590 int bh = r->height; 11591 int bstride = ALIGN(bw, 2); 11592 int src_stride; 11593 uint8_t *dst, *src; 11594 uint32_t *b; 11595 11596 DBG(("%s: rect (%d, %d)x(%d, %d) stipple [%d,%d]\n", 11597 __FUNCTION__, 11598 r->x, r->y, r->width, r->height, 11599 bx1, bx2)); 11600 11601 src_stride = bstride*bh; 11602 if (src_stride <= 128) { 11603 src_stride = ALIGN(src_stride, 8) / 4; 11604 assert(src_stride <= 32); 11605 if (!kgem_check_batch(&sna->kgem, 7+src_stride) || 11606 !kgem_check_bo_fenced(&sna->kgem, bo) || 11607 !kgem_check_reloc(&sna->kgem, 1)) { 11608 kgem_submit(&sna->kgem); 11609 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11610 return false; 11611 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11612 } 11613 11614 b = sna->kgem.batch + sna->kgem.nbatch; 11615 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 11616 b[0] |= ((r->x - origin->x) & 7) << 17; 11617 b[1] = br13; 11618 b[2] = (r->y + dy) << 16 | (r->x + dx); 11619 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 11620 b[4] = kgem_add_reloc(&sna->kgem, 11621 sna->kgem.nbatch + 4, bo, 11622 I915_GEM_DOMAIN_RENDER << 16 | 11623 I915_GEM_DOMAIN_RENDER | 11624 KGEM_RELOC_FENCED, 11625 0); 11626 b[5] = gc->bgPixel; 11627 b[6] = gc->fgPixel; 11628 11629 sna->kgem.nbatch += 7 + src_stride; 11630 11631 dst = (uint8_t *)&b[7]; 11632 src_stride = stipple->devKind; 11633 src = stipple->devPrivate.ptr; 11634 src += (r->y - origin->y) * src_stride + bx1/8; 11635 src_stride -= bstride; 11636 do { 11637 int i = bstride; 11638 do { 11639 *dst++ = byte_reverse(*src++); 11640 *dst++ = byte_reverse(*src++); 11641 i -= 2; 11642 } while (i); 11643 src += src_stride; 11644 } while (--bh); 11645 } else { 11646 struct kgem_bo *upload; 11647 void *ptr; 11648 11649 if (!kgem_check_batch(&sna->kgem, 8) || 11650 !kgem_check_bo_fenced(&sna->kgem, bo) || 11651 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 11652 kgem_submit(&sna->kgem); 11653 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11654 return false; 11655 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11656 } 11657 11658 upload = kgem_create_buffer(&sna->kgem, 11659 bstride*bh, 11660 KGEM_BUFFER_WRITE_INPLACE, 11661 &ptr); 11662 if (!upload) 11663 break; 11664 11665 dst = ptr; 11666 src_stride = stipple->devKind; 11667 src = stipple->devPrivate.ptr; 11668 src += (r->y - origin->y) * src_stride + bx1/8; 11669 src_stride -= bstride; 11670 do { 11671 int i = bstride; 11672 do { 11673 *dst++ = byte_reverse(*src++); 11674 *dst++ = byte_reverse(*src++); 11675 i -= 2; 11676 } while (i); 11677 src += src_stride; 11678 } while (--bh); 11679 b = sna->kgem.batch + sna->kgem.nbatch; 11680 b[0] = XY_MONO_SRC_COPY | br00; 11681 b[0] |= ((r->x - origin->x) & 7) << 17; 11682 b[1] = br13; 11683 b[2] = (r->y + dy) << 16 | (r->x + dx); 11684 b[3] = (r->y + r->height + dy) << 16 | (r->x + r->width + dx); 11685 b[4] = kgem_add_reloc(&sna->kgem, 11686 sna->kgem.nbatch + 4, bo, 11687 I915_GEM_DOMAIN_RENDER << 16 | 11688 I915_GEM_DOMAIN_RENDER | 11689 KGEM_RELOC_FENCED, 11690 0); 11691 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 11692 upload, 11693 I915_GEM_DOMAIN_RENDER << 16 | 11694 KGEM_RELOC_FENCED, 11695 0); 11696 b[6] = gc->bgPixel; 11697 b[7] = gc->fgPixel; 11698 11699 sna->kgem.nbatch += 8; 11700 kgem_bo_destroy(&sna->kgem, upload); 11701 } 11702 11703 r++; 11704 } while (--n); 11705 } else { 11706 RegionRec clip; 11707 DDXPointRec pat; 11708 11709 region_set(&clip, extents); 11710 region_maybe_clip(&clip, gc->pCompositeClip); 11711 if (RegionNil(&clip)) 11712 return true; 11713 11714 pat.x = origin->x + drawable->x; 11715 pat.y = origin->y + drawable->y; 11716 11717 if (clip.data == NULL) { 11718 do { 11719 BoxRec box; 11720 int bx1, bx2, bw, bh, bstride; 11721 int src_stride; 11722 uint8_t *dst, *src; 11723 uint32_t *b; 11724 struct kgem_bo *upload; 11725 void *ptr; 11726 11727 box.x1 = r->x + drawable->x; 11728 box.x2 = bound(box.x1, r->width); 11729 box.y1 = r->y + drawable->y; 11730 box.y2 = bound(box.y1, r->height); 11731 r++; 11732 11733 if (!box_intersect(&box, &clip.extents)) 11734 continue; 11735 11736 bx1 = (box.x1 - pat.x) & ~7; 11737 bx2 = (box.x2 - pat.x + 7) & ~7; 11738 bw = (bx2 - bx1)/8; 11739 bh = box.y2 - box.y1; 11740 bstride = ALIGN(bw, 2); 11741 11742 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d], pitch=%d, stride=%d\n", 11743 __FUNCTION__, 11744 r->x, r->y, r->width, r->height, 11745 box.x1, box.y1, box.x2, box.y2, 11746 bx1, bx2, bw, bstride)); 11747 11748 src_stride = bstride*bh; 11749 if (src_stride <= 128) { 11750 src_stride = ALIGN(src_stride, 8) / 4; 11751 assert(src_stride <= 32); 11752 if (!kgem_check_batch(&sna->kgem, 7+src_stride) || 11753 !kgem_check_bo_fenced(&sna->kgem, bo) || 11754 !kgem_check_reloc(&sna->kgem, 1)) { 11755 kgem_submit(&sna->kgem); 11756 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11757 return false; 11758 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11759 } 11760 11761 b = sna->kgem.batch + sna->kgem.nbatch; 11762 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 11763 b[0] |= ((box.x1 - pat.x) & 7) << 17; 11764 b[1] = br13; 11765 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 11766 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 11767 b[4] = kgem_add_reloc(&sna->kgem, 11768 sna->kgem.nbatch + 4, bo, 11769 I915_GEM_DOMAIN_RENDER << 16 | 11770 I915_GEM_DOMAIN_RENDER | 11771 KGEM_RELOC_FENCED, 11772 0); 11773 b[5] = gc->bgPixel; 11774 b[6] = gc->fgPixel; 11775 11776 sna->kgem.nbatch += 7 + src_stride; 11777 11778 dst = (uint8_t *)&b[7]; 11779 src_stride = stipple->devKind; 11780 src = stipple->devPrivate.ptr; 11781 src += (box.y1 - pat.y) * src_stride + bx1/8; 11782 src_stride -= bstride; 11783 do { 11784 int i = bstride; 11785 do { 11786 *dst++ = byte_reverse(*src++); 11787 *dst++ = byte_reverse(*src++); 11788 i -= 2; 11789 } while (i); 11790 src += src_stride; 11791 } while (--bh); 11792 } else { 11793 if (!kgem_check_batch(&sna->kgem, 8) || 11794 !kgem_check_bo_fenced(&sna->kgem, bo) || 11795 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 11796 kgem_submit(&sna->kgem); 11797 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11798 return false; 11799 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11800 } 11801 11802 upload = kgem_create_buffer(&sna->kgem, 11803 bstride*bh, 11804 KGEM_BUFFER_WRITE_INPLACE, 11805 &ptr); 11806 if (!upload) 11807 break; 11808 11809 dst = ptr; 11810 src_stride = stipple->devKind; 11811 src = stipple->devPrivate.ptr; 11812 src += (box.y1 - pat.y) * src_stride + bx1/8; 11813 src_stride -= bstride; 11814 do { 11815 int i = bstride; 11816 do { 11817 *dst++ = byte_reverse(*src++); 11818 *dst++ = byte_reverse(*src++); 11819 i -= 2; 11820 } while (i); 11821 src += src_stride; 11822 } while (--bh); 11823 11824 b = sna->kgem.batch + sna->kgem.nbatch; 11825 b[0] = XY_MONO_SRC_COPY | br00; 11826 b[0] |= ((box.x1 - pat.x) & 7) << 17; 11827 b[1] = br13; 11828 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 11829 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 11830 b[4] = kgem_add_reloc(&sna->kgem, 11831 sna->kgem.nbatch + 4, bo, 11832 I915_GEM_DOMAIN_RENDER << 16 | 11833 I915_GEM_DOMAIN_RENDER | 11834 KGEM_RELOC_FENCED, 11835 0); 11836 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 11837 upload, 11838 I915_GEM_DOMAIN_RENDER << 16 | 11839 KGEM_RELOC_FENCED, 11840 0); 11841 b[6] = gc->bgPixel; 11842 b[7] = gc->fgPixel; 11843 11844 sna->kgem.nbatch += 8; 11845 kgem_bo_destroy(&sna->kgem, upload); 11846 } 11847 } while (--n); 11848 } else { 11849 const BoxRec * const clip_start = RegionBoxptr(&clip); 11850 const BoxRec * const clip_end = clip_start + clip.data->numRects; 11851 const BoxRec *c; 11852 11853 do { 11854 BoxRec unclipped; 11855 int bx1, bx2, bw, bh, bstride; 11856 int src_stride; 11857 uint8_t *dst, *src; 11858 uint32_t *b; 11859 struct kgem_bo *upload; 11860 void *ptr; 11861 11862 unclipped.x1 = r->x + drawable->x; 11863 unclipped.x2 = bound(unclipped.x2, r->width); 11864 unclipped.y1 = r->y + drawable->y; 11865 unclipped.y2 = bound(unclipped.y2, r->height); 11866 r++; 11867 11868 c = find_clip_box_for_y(clip_start, 11869 clip_end, 11870 unclipped.y1); 11871 while (c != clip_end) { 11872 BoxRec box; 11873 11874 if (unclipped.y2 <= c->y1) 11875 break; 11876 11877 box = unclipped; 11878 if (!box_intersect(&box, c++)) 11879 continue; 11880 11881 bx1 = (box.x1 - pat.x) & ~7; 11882 bx2 = (box.x2 - pat.x + 7) & ~7; 11883 bw = (bx2 - bx1)/8; 11884 bh = box.y2 - box.y1; 11885 bstride = ALIGN(bw, 2); 11886 11887 DBG(("%s: rect (%d, %d)x(%d, %d), box (%d,%d),(%d,%d) stipple [%d,%d]\n", 11888 __FUNCTION__, 11889 r->x, r->y, r->width, r->height, 11890 box.x1, box.y1, box.x2, box.y2, 11891 bx1, bx2)); 11892 11893 src_stride = bstride*bh; 11894 if (src_stride <= 128) { 11895 src_stride = ALIGN(src_stride, 8) / 4; 11896 assert(src_stride <= 32); 11897 if (!kgem_check_batch(&sna->kgem, 7+src_stride) || 11898 !kgem_check_bo_fenced(&sna->kgem, bo) || 11899 !kgem_check_reloc(&sna->kgem, 1)) { 11900 kgem_submit(&sna->kgem); 11901 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11902 return false; 11903 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11904 } 11905 11906 b = sna->kgem.batch + sna->kgem.nbatch; 11907 b[0] = XY_MONO_SRC_COPY_IMM | (5 + src_stride) | br00; 11908 b[0] |= ((box.x1 - pat.x) & 7) << 17; 11909 b[1] = br13; 11910 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 11911 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 11912 b[4] = kgem_add_reloc(&sna->kgem, 11913 sna->kgem.nbatch + 4, bo, 11914 I915_GEM_DOMAIN_RENDER << 16 | 11915 I915_GEM_DOMAIN_RENDER | 11916 KGEM_RELOC_FENCED, 11917 0); 11918 b[5] = gc->bgPixel; 11919 b[6] = gc->fgPixel; 11920 11921 sna->kgem.nbatch += 7 + src_stride; 11922 11923 dst = (uint8_t *)&b[7]; 11924 src_stride = stipple->devKind; 11925 src = stipple->devPrivate.ptr; 11926 src += (box.y1 - pat.y) * src_stride + bx1/8; 11927 src_stride -= bstride; 11928 do { 11929 int i = bstride; 11930 do { 11931 *dst++ = byte_reverse(*src++); 11932 *dst++ = byte_reverse(*src++); 11933 i -= 2; 11934 } while (i); 11935 src += src_stride; 11936 } while (--bh); 11937 } else { 11938 if (!kgem_check_batch(&sna->kgem, 8) || 11939 !kgem_check_bo_fenced(&sna->kgem, bo) || 11940 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 11941 kgem_submit(&sna->kgem); 11942 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 11943 return false; 11944 _kgem_set_mode(&sna->kgem, KGEM_BLT); 11945 } 11946 11947 upload = kgem_create_buffer(&sna->kgem, 11948 bstride*bh, 11949 KGEM_BUFFER_WRITE_INPLACE, 11950 &ptr); 11951 if (!upload) 11952 break; 11953 11954 dst = ptr; 11955 src_stride = stipple->devKind; 11956 src = stipple->devPrivate.ptr; 11957 src += (box.y1 - pat.y) * src_stride + bx1/8; 11958 src_stride -= bstride; 11959 do { 11960 int i = bstride; 11961 do { 11962 *dst++ = byte_reverse(*src++); 11963 *dst++ = byte_reverse(*src++); 11964 i -= 2; 11965 } while (i); 11966 src += src_stride; 11967 } while (--bh); 11968 11969 b = sna->kgem.batch + sna->kgem.nbatch; 11970 b[0] = XY_MONO_SRC_COPY | br00; 11971 b[0] |= ((box.x1 - pat.x) & 7) << 17; 11972 b[1] = br13; 11973 b[2] = (box.y1 + dy) << 16 | (box.x1 + dx); 11974 b[3] = (box.y2 + dy) << 16 | (box.x2 + dx); 11975 b[4] = kgem_add_reloc(&sna->kgem, 11976 sna->kgem.nbatch + 4, bo, 11977 I915_GEM_DOMAIN_RENDER << 16 | 11978 I915_GEM_DOMAIN_RENDER | 11979 KGEM_RELOC_FENCED, 11980 0); 11981 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 11982 upload, 11983 I915_GEM_DOMAIN_RENDER << 16 | 11984 KGEM_RELOC_FENCED, 11985 0); 11986 b[6] = gc->bgPixel; 11987 b[7] = gc->fgPixel; 11988 11989 sna->kgem.nbatch += 8; 11990 kgem_bo_destroy(&sna->kgem, upload); 11991 } 11992 } 11993 } while (--n); 11994 11995 } 11996 } 11997 11998 sna->blt_state.fill_bo = 0; 11999 return true; 12000} 12001 12002static void 12003sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna, 12004 struct kgem_bo *bo, 12005 uint32_t br00, uint32_t br13, 12006 const GC *gc, 12007 const BoxRec *box, 12008 const DDXPointRec *origin) 12009{ 12010 int x1, x2, y1, y2; 12011 uint32_t *b; 12012 12013 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 12014 int oy = (y1 - origin->y) % gc->stipple->drawable.height; 12015 if (oy < 0) 12016 oy += gc->stipple->drawable.height; 12017 12018 y2 = box->y2; 12019 if (y2 - y1 > gc->stipple->drawable.height - oy) 12020 y2 = y1 + gc->stipple->drawable.height - oy; 12021 12022 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 12023 int bx1, bx2, bw, bh, len, ox; 12024 uint8_t *dst, *src; 12025 12026 x2 = box->x2; 12027 ox = (x1 - origin->x) % gc->stipple->drawable.width; 12028 if (ox < 0) 12029 ox += gc->stipple->drawable.width; 12030 bx1 = ox & ~7; 12031 bx2 = ox + (x2 - x1); 12032 if (bx2 > gc->stipple->drawable.width) { 12033 bx2 = gc->stipple->drawable.width; 12034 x2 = x1 + bx2-ox; 12035 } 12036 bw = (bx2 - bx1 + 7)/8; 12037 bw = ALIGN(bw, 2); 12038 bh = y2 - y1; 12039 12040 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d\n", 12041 __FUNCTION__, 12042 x1, y1, x2-x1, y2-y1, 12043 origin->x, origin->y, 12044 ox, oy, bx1, bx2, 12045 gc->stipple->drawable.width, 12046 gc->stipple->drawable.height)); 12047 12048 len = bw*bh; 12049 len = ALIGN(len, 8) / 4; 12050 assert(len <= 32); 12051 if (!kgem_check_batch(&sna->kgem, 7+len) || 12052 !kgem_check_bo_fenced(&sna->kgem, bo) || 12053 !kgem_check_reloc(&sna->kgem, 1)) { 12054 kgem_submit(&sna->kgem); 12055 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 12056 return; /* XXX fallback? */ 12057 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12058 } 12059 12060 b = sna->kgem.batch + sna->kgem.nbatch; 12061 b[0] = br00 | (5 + len) | (ox & 7) << 17; 12062 b[1] = br13; 12063 b[2] = y1 << 16 | x1; 12064 b[3] = y2 << 16 | x2; 12065 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 12066 bo, 12067 I915_GEM_DOMAIN_RENDER << 16 | 12068 I915_GEM_DOMAIN_RENDER | 12069 KGEM_RELOC_FENCED, 12070 0); 12071 b[5] = gc->bgPixel; 12072 b[6] = gc->fgPixel; 12073 12074 sna->kgem.nbatch += 7 + len; 12075 12076 dst = (uint8_t *)&b[7]; 12077 len = gc->stipple->devKind; 12078 src = gc->stipple->devPrivate.ptr; 12079 src += oy*len + ox/8; 12080 len -= bw; 12081 do { 12082 int i = bw; 12083 do { 12084 *dst++ = byte_reverse(*src++); 12085 *dst++ = byte_reverse(*src++); 12086 i -= 2; 12087 } while (i); 12088 src += len; 12089 } while (--bh); 12090 } 12091 } 12092} 12093 12094static void 12095sna_poly_fill_rect_stippled_n_box(struct sna *sna, 12096 struct kgem_bo *bo, 12097 struct kgem_bo **tile, 12098 uint32_t br00, uint32_t br13, 12099 const GC *gc, 12100 const BoxRec *box, 12101 const DDXPointRec *origin) 12102{ 12103 int x1, x2, y1, y2; 12104 int w = gc->stipple->drawable.width; 12105 int h = gc->stipple->drawable.height; 12106 int stride = gc->stipple->devKind; 12107 uint32_t *b; 12108 12109 if ((((box->y2-box->y1) | (box->x2-box->x1)) & ~31) == 0) { 12110 br00 = XY_MONO_SRC_COPY_IMM |(br00 & (BLT_DST_TILED | 3 << 20)); 12111 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 12112 br00, br13, gc, 12113 box, origin); 12114 return; 12115 } 12116 12117 for (y1 = box->y1; y1 < box->y2; y1 = y2) { 12118 int row, oy = (y1 - origin->y) % gc->stipple->drawable.height; 12119 if (oy < 0) 12120 oy += h; 12121 12122 y2 = box->y2; 12123 if (y2 - y1 > h - oy) 12124 y2 = y1 + h - oy; 12125 12126 row = oy * stride; 12127 for (x1 = box->x1; x1 < box->x2; x1 = x2) { 12128 int bx1, bx2, bw, bh, len, ox; 12129 bool use_tile; 12130 12131 x2 = box->x2; 12132 ox = (x1 - origin->x) % w; 12133 if (ox < 0) 12134 ox += w; 12135 bx1 = ox & ~7; 12136 bx2 = ox + (x2 - x1); 12137 if (bx2 > w) { 12138 bx2 = w; 12139 x2 = x1 + bx2-ox; 12140 } 12141 12142 use_tile = y2-y1 == h && x2-x1 == w; 12143 12144 DBG(("%s: box((%d, %d)x(%d, %d)) origin=(%d, %d), pat=(%d, %d), up=(%d, %d), stipple=%dx%d, full tile?=%d\n", 12145 __FUNCTION__, 12146 x1, y1, x2-x1, y2-y1, 12147 origin->x, origin->y, 12148 ox, oy, bx1, bx2, w, h, 12149 use_tile)); 12150 12151 bw = (bx2 - bx1 + 7)/8; 12152 bw = ALIGN(bw, 2); 12153 bh = y2 - y1; 12154 12155 len = bw*bh; 12156 len = ALIGN(len, 8) / 4; 12157 if (!kgem_check_batch(&sna->kgem, 7+len) || 12158 !kgem_check_bo_fenced(&sna->kgem, bo) || 12159 !kgem_check_reloc(&sna->kgem, 2)) { 12160 kgem_submit(&sna->kgem); 12161 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 12162 return; /* XXX fallback? */ 12163 _kgem_set_mode(&sna->kgem, KGEM_BLT); 12164 } 12165 12166 b = sna->kgem.batch + sna->kgem.nbatch; 12167 12168 if (!use_tile && len <= 32) { 12169 uint8_t *dst, *src; 12170 12171 b[0] = XY_MONO_SRC_COPY_IMM; 12172 b[0] |= (br00 & (BLT_DST_TILED | 3 << 20)); 12173 b[0] |= (ox & 7) << 17; 12174 b[0] |= (5 + len); 12175 b[1] = br13; 12176 b[2] = y1 << 16 | x1; 12177 b[3] = y2 << 16 | x2; 12178 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 12179 bo, 12180 I915_GEM_DOMAIN_RENDER << 16 | 12181 I915_GEM_DOMAIN_RENDER | 12182 KGEM_RELOC_FENCED, 12183 0); 12184 b[5] = gc->bgPixel; 12185 b[6] = gc->fgPixel; 12186 12187 sna->kgem.nbatch += 7 + len; 12188 12189 dst = (uint8_t *)&b[7]; 12190 len = gc->stipple->devKind; 12191 src = gc->stipple->devPrivate.ptr; 12192 src += oy*len + ox/8; 12193 len -= bw; 12194 do { 12195 int i = bw; 12196 do { 12197 *dst++ = byte_reverse(*src++); 12198 *dst++ = byte_reverse(*src++); 12199 i -= 2; 12200 } while (i); 12201 src += len; 12202 } while (--bh); 12203 } else { 12204 bool has_tile = use_tile && *tile; 12205 struct kgem_bo *upload; 12206 uint8_t *dst, *src; 12207 void *ptr; 12208 12209 if (has_tile) { 12210 upload = kgem_bo_reference(*tile); 12211 } else { 12212 upload = kgem_create_buffer(&sna->kgem, bw*bh, 12213 KGEM_BUFFER_WRITE_INPLACE, 12214 &ptr); 12215 if (!upload) 12216 return; 12217 } 12218 12219 b = sna->kgem.batch + sna->kgem.nbatch; 12220 b[0] = br00 | (ox & 7) << 17; 12221 b[1] = br13; 12222 b[2] = y1 << 16 | x1; 12223 b[3] = y2 << 16 | x2; 12224 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 12225 bo, 12226 I915_GEM_DOMAIN_RENDER << 16 | 12227 I915_GEM_DOMAIN_RENDER | 12228 KGEM_RELOC_FENCED, 12229 0); 12230 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 12231 upload, 12232 I915_GEM_DOMAIN_RENDER << 16 | 12233 KGEM_RELOC_FENCED, 12234 0); 12235 b[6] = gc->bgPixel; 12236 b[7] = gc->fgPixel; 12237 12238 sna->kgem.nbatch += 8; 12239 12240 if (!has_tile) { 12241 dst = ptr; 12242 len = stride; 12243 src = gc->stipple->devPrivate.ptr; 12244 src += row + (ox >> 3); 12245 len -= bw; 12246 do { 12247 int i = bw; 12248 do { 12249 *dst++ = byte_reverse(*src++); 12250 *dst++ = byte_reverse(*src++); 12251 i -= 2; 12252 } while (i); 12253 src += len; 12254 } while (--bh); 12255 if (use_tile) 12256 *tile = kgem_bo_reference(upload); 12257 } 12258 12259 kgem_bo_destroy(&sna->kgem, upload); 12260 } 12261 } 12262 } 12263} 12264 12265static bool 12266sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable, 12267 struct kgem_bo *bo, 12268 struct sna_damage **damage, 12269 GCPtr gc, int n, xRectangle *r, 12270 const BoxRec *extents, unsigned clipped) 12271{ 12272 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12273 struct sna *sna = to_sna_from_pixmap(pixmap); 12274 DDXPointRec origin = gc->patOrg; 12275 int16_t dx, dy; 12276 uint32_t br00, br13; 12277 12278 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 12279 extents->x1, extents->y1, 12280 extents->x2, extents->y2, 12281 origin.x, origin.y, 12282 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 12283 12284 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12285 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12286 12287 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20; 12288 br13 = bo->pitch; 12289 if (sna->kgem.gen >= 040 && bo->tiling) { 12290 br00 |= BLT_DST_TILED; 12291 br13 >>= 2; 12292 } 12293 br13 |= (gc->fillStyle == FillStippled) << 29; 12294 br13 |= blt_depth(drawable->depth) << 24; 12295 br13 |= copy_ROP[gc->alu] << 16; 12296 12297 origin.x += dx + drawable->x; 12298 origin.y += dy + drawable->y; 12299 12300 if (!clipped) { 12301 dx += drawable->x; 12302 dy += drawable->y; 12303 12304 sna_damage_add_rectangles(damage, r, n, dx, dy); 12305 do { 12306 BoxRec box; 12307 12308 box.x1 = r->x + dx; 12309 box.y1 = r->y + dy; 12310 box.x2 = box.x1 + r->width; 12311 box.y2 = box.y1 + r->height; 12312 12313 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 12314 br00, br13, gc, 12315 &box, &origin); 12316 r++; 12317 } while (--n); 12318 } else { 12319 RegionRec clip; 12320 12321 region_set(&clip, extents); 12322 region_maybe_clip(&clip, gc->pCompositeClip); 12323 if (RegionNil(&clip)) { 12324 DBG(("%s: all clipped\n", __FUNCTION__)); 12325 return true; 12326 } 12327 12328 if (clip.data == NULL) { 12329 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 12330 __FUNCTION__, 12331 clip.extents.x1, clip.extents.y1, 12332 clip.extents.x2, clip.extents.y2)); 12333 do { 12334 BoxRec box; 12335 12336 box.x1 = r->x + drawable->x; 12337 box.x2 = bound(box.x1, r->width); 12338 box.y1 = r->y + drawable->y; 12339 box.y2 = bound(box.y1, r->height); 12340 r++; 12341 12342 DBG(("%s: box (%d, %d), (%d, %d)\n", 12343 __FUNCTION__, 12344 box.x1, box.y1, box.x2, box.y2)); 12345 if (!box_intersect(&box, &clip.extents)) 12346 continue; 12347 12348 box.x1 += dx; box.x2 += dx; 12349 box.y1 += dy; box.y2 += dy; 12350 12351 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 12352 br00, br13, gc, 12353 &box, &origin); 12354 } while (--n); 12355 } else { 12356 const BoxRec * const clip_start = RegionBoxptr(&clip); 12357 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12358 const BoxRec *c; 12359 12360 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 12361 clip_start->x1, clip_start->y1, 12362 clip_start->x2, clip_start->y2, 12363 clip_end->x1, clip_end->y1, 12364 clip_end->x2, clip_end->y2)); 12365 do { 12366 BoxRec unclipped; 12367 12368 unclipped.x1 = r->x + drawable->x; 12369 unclipped.x2 = bound(unclipped.x1, r->width); 12370 unclipped.y1 = r->y + drawable->y; 12371 unclipped.y2 = bound(unclipped.y1, r->height); 12372 r++; 12373 12374 c = find_clip_box_for_y(clip_start, 12375 clip_end, 12376 unclipped.y1); 12377 while (c != clip_end) { 12378 BoxRec box; 12379 12380 if (unclipped.y2 <= c->y1) 12381 break; 12382 12383 box = unclipped; 12384 if (!box_intersect(&box, c++)) 12385 continue; 12386 12387 box.x1 += dx; box.x2 += dx; 12388 box.y1 += dy; box.y2 += dy; 12389 12390 sna_poly_fill_rect_stippled_n_box__imm(sna, bo, 12391 br00, br13, gc, 12392 &box, &origin); 12393 } 12394 } while (--n); 12395 } 12396 } 12397 12398 assert_pixmap_damage(pixmap); 12399 sna->blt_state.fill_bo = 0; 12400 return true; 12401} 12402 12403static bool 12404sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable, 12405 struct kgem_bo *bo, 12406 struct sna_damage **damage, 12407 GCPtr gc, int n, xRectangle *r, 12408 const BoxRec *extents, unsigned clipped) 12409{ 12410 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12411 struct sna *sna = to_sna_from_pixmap(pixmap); 12412 DDXPointRec origin = gc->patOrg; 12413 struct kgem_bo *tile = NULL; 12414 int16_t dx, dy; 12415 uint32_t br00, br13; 12416 12417 DBG(("%s: upload (%d, %d), (%d, %d), origin (%d, %d), clipped=%d, alu=%d, opaque=%d\n", __FUNCTION__, 12418 extents->x1, extents->y1, 12419 extents->x2, extents->y2, 12420 origin.x, origin.y, 12421 clipped, gc->alu, gc->fillStyle == FillOpaqueStippled)); 12422 12423 if (((gc->stipple->drawable.width | gc->stipple->drawable.height) & ~31) == 0) 12424 return sna_poly_fill_rect_stippled_n_blt__imm(drawable, 12425 bo, damage, 12426 gc, n, r, 12427 extents, clipped); 12428 12429 get_drawable_deltas(drawable, pixmap, &dx, &dy); 12430 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 12431 12432 br00 = XY_MONO_SRC_COPY | 3 << 20; 12433 br13 = bo->pitch; 12434 if (sna->kgem.gen >= 040 && bo->tiling) { 12435 br00 |= BLT_DST_TILED; 12436 br13 >>= 2; 12437 } 12438 br13 |= (gc->fillStyle == FillStippled) << 29; 12439 br13 |= blt_depth(drawable->depth) << 24; 12440 br13 |= copy_ROP[gc->alu] << 16; 12441 12442 origin.x += dx + drawable->x; 12443 origin.y += dy + drawable->y; 12444 12445 if (!clipped) { 12446 dx += drawable->x; 12447 dy += drawable->y; 12448 12449 sna_damage_add_rectangles(damage, r, n, dx, dy); 12450 do { 12451 BoxRec box; 12452 12453 box.x1 = r->x + dx; 12454 box.y1 = r->y + dy; 12455 box.x2 = box.x1 + r->width; 12456 box.y2 = box.y1 + r->height; 12457 12458 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 12459 br00, br13, gc, 12460 &box, &origin); 12461 r++; 12462 } while (--n); 12463 } else { 12464 RegionRec clip; 12465 12466 region_set(&clip, extents); 12467 region_maybe_clip(&clip, gc->pCompositeClip); 12468 if (RegionNil(&clip)) { 12469 DBG(("%s: all clipped\n", __FUNCTION__)); 12470 return true; 12471 } 12472 12473 if (clip.data == NULL) { 12474 DBG(("%s: clipped to extents ((%d, %d), (%d, %d))\n", 12475 __FUNCTION__, 12476 clip.extents.x1, clip.extents.y1, 12477 clip.extents.x2, clip.extents.y2)); 12478 do { 12479 BoxRec box; 12480 12481 box.x1 = r->x + drawable->x; 12482 box.x2 = bound(box.x1, r->width); 12483 box.y1 = r->y + drawable->y; 12484 box.y2 = bound(box.y1, r->height); 12485 r++; 12486 12487 DBG(("%s: box (%d, %d), (%d, %d)\n", 12488 __FUNCTION__, 12489 box.x1, box.y1, box.x2, box.y2)); 12490 if (!box_intersect(&box, &clip.extents)) 12491 continue; 12492 12493 box.x1 += dx; box.x2 += dx; 12494 box.y1 += dy; box.y2 += dy; 12495 12496 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 12497 br00, br13, gc, 12498 &box, &origin); 12499 } while (--n); 12500 } else { 12501 const BoxRec * const clip_start = RegionBoxptr(&clip); 12502 const BoxRec * const clip_end = clip_start + clip.data->numRects; 12503 const BoxRec *c; 12504 12505 DBG(("%s: clipped to boxes: start((%d, %d), (%d, %d)); end=((%d, %d), (%d, %d))\n", __FUNCTION__, 12506 clip_start->x1, clip_start->y1, 12507 clip_start->x2, clip_start->y2, 12508 clip_end->x1, clip_end->y1, 12509 clip_end->x2, clip_end->y2)); 12510 do { 12511 BoxRec unclipped; 12512 12513 unclipped.x1 = r->x + drawable->x; 12514 unclipped.x2 = bound(unclipped.x1, r->width); 12515 unclipped.y1 = r->y + drawable->y; 12516 unclipped.y2 = bound(unclipped.y1, r->height); 12517 r++; 12518 12519 c = find_clip_box_for_y(clip_start, 12520 clip_end, 12521 unclipped.y1); 12522 while (c != clip_end) { 12523 BoxRec box; 12524 12525 if (unclipped.y2 <= c->y1) 12526 break; 12527 12528 box = unclipped; 12529 if (!box_intersect(&box, c++)) 12530 continue; 12531 12532 box.x1 += dx; box.x2 += dx; 12533 box.y1 += dy; box.y2 += dy; 12534 12535 sna_poly_fill_rect_stippled_n_box(sna, bo, &tile, 12536 br00, br13, gc, 12537 &box, &origin); 12538 } 12539 } while (--n); 12540 } 12541 } 12542 12543 assert_pixmap_damage(pixmap); 12544 if (tile) 12545 kgem_bo_destroy(&sna->kgem, tile); 12546 sna->blt_state.fill_bo = 0; 12547 return true; 12548} 12549 12550static bool 12551sna_poly_fill_rect_stippled_blt(DrawablePtr drawable, 12552 struct kgem_bo *bo, 12553 struct sna_damage **damage, 12554 GCPtr gc, int n, xRectangle *rect, 12555 const BoxRec *extents, unsigned clipped) 12556{ 12557 12558 PixmapPtr stipple = gc->stipple; 12559 12560 if (bo->tiling == I915_TILING_Y) { 12561 PixmapPtr pixmap = get_drawable_pixmap(drawable); 12562 12563 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 12564 /* This is cheating, but only the gpu_bo can be tiled */ 12565 assert(bo == __sna_pixmap_get_bo(pixmap)); 12566 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 12567 if (bo == NULL) { 12568 DBG(("%s: fallback -- unable to change tiling\n", 12569 __FUNCTION__)); 12570 return false; 12571 } 12572 } 12573 12574 if (!sna_drawable_move_to_cpu(&stipple->drawable, MOVE_READ)) 12575 return false; 12576 12577 DBG(("%s: origin (%d, %d), extents (stipple): (%d, %d), stipple size %dx%d\n", 12578 __FUNCTION__, gc->patOrg.x, gc->patOrg.y, 12579 extents->x2 - gc->patOrg.x - drawable->x, 12580 extents->y2 - gc->patOrg.y - drawable->y, 12581 stipple->drawable.width, stipple->drawable.height)); 12582 12583 if ((stipple->drawable.width | stipple->drawable.height) == 8) 12584 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 12585 gc, n, rect, 12586 extents, clipped); 12587 12588 if ((stipple->drawable.width | stipple->drawable.height) <= 0xc && 12589 is_power_of_two(stipple->drawable.width) && 12590 is_power_of_two(stipple->drawable.height)) 12591 return sna_poly_fill_rect_stippled_nxm_blt(drawable, bo, damage, 12592 gc, n, rect, 12593 extents, clipped); 12594 12595 if (extents->x2 - gc->patOrg.x - drawable->x <= stipple->drawable.width && 12596 extents->y2 - gc->patOrg.y - drawable->y <= stipple->drawable.height) { 12597 if (stipple->drawable.width <= 8 && stipple->drawable.height <= 8) 12598 return sna_poly_fill_rect_stippled_8x8_blt(drawable, bo, damage, 12599 gc, n, rect, 12600 extents, clipped); 12601 else 12602 return sna_poly_fill_rect_stippled_1_blt(drawable, bo, damage, 12603 gc, n, rect, 12604 extents, clipped); 12605 } else { 12606 return sna_poly_fill_rect_stippled_n_blt(drawable, bo, damage, 12607 gc, n, rect, 12608 extents, clipped); 12609 } 12610} 12611 12612static unsigned 12613sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc, 12614 int *_n, xRectangle **_r, 12615 BoxPtr out) 12616{ 12617 int n; 12618 xRectangle *r; 12619 Box32Rec box; 12620 bool clipped; 12621 12622 if (*_n == 0) 12623 return 0; 12624 12625 DBG(("%s: [0] = (%d, %d)x(%d, %d)\n", 12626 __FUNCTION__, (*_r)->x, (*_r)->y, (*_r)->width, (*_r)->height)); 12627 12628 /* Remove any zero-size rectangles from the array */ 12629 while (*_n && ((*_r)->width == 0 || (*_r)->height == 0)) 12630 --*_n, ++*_r; 12631 12632 if (*_n == 0) 12633 return 0; 12634 12635 n = *_n; 12636 r = *_r; 12637 12638 box.x1 = r->x; 12639 box.x2 = box.x1 + r->width; 12640 box.y1 = r->y; 12641 box.y2 = box.y1 + r->height; 12642 r++; 12643 12644 while (--n) { 12645 if (r->width == 0 || r->height == 0) 12646 goto slow; 12647 12648 box32_add_rect(&box, r++); 12649 } 12650 goto done; 12651slow: 12652 { 12653 xRectangle *rr = r; 12654 do { 12655 do { 12656 --*_n, r++; 12657 } while (--n && (r->width == 0 || r->height == 0)); 12658 while (n && r->width && r->height) { 12659 box32_add_rect(&box, r); 12660 *rr++ = *r++; 12661 n--; 12662 } 12663 } while (n); 12664 } 12665done: 12666 12667 clipped = box32_trim_and_translate(&box, drawable, gc); 12668 if (!box32_to_box16(&box, out)) 12669 return 0; 12670 12671 return 1 | clipped << 1; 12672} 12673 12674static void 12675sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect) 12676{ 12677 PixmapPtr pixmap = get_drawable_pixmap(draw); 12678 struct sna *sna = to_sna_from_pixmap(pixmap); 12679 struct sna_pixmap *priv = sna_pixmap(pixmap); 12680 struct sna_damage **damage; 12681 struct kgem_bo *bo; 12682 RegionRec region; 12683 unsigned flags, hint; 12684 uint32_t color; 12685 12686 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 12687 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 12688 (gc->fillStyle == FillSolid || 12689 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 12690 gc->fillStyle, gc->tileIsPixel, 12691 gc->alu)); 12692 12693 flags = sna_poly_fill_rect_extents(draw, gc, &n, &rect, ®ion.extents); 12694 if (flags == 0) { 12695 DBG(("%s, nothing to do\n", __FUNCTION__)); 12696 return; 12697 } 12698 12699 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 12700 region.extents.x1, region.extents.y1, 12701 region.extents.x2, region.extents.y2, 12702 flags)); 12703 12704 if (FORCE_FALLBACK || !ACCEL_POLY_FILL_RECT) { 12705 DBG(("%s: fallback forced\n", __FUNCTION__)); 12706 goto fallback; 12707 } 12708 12709 if (priv == NULL) { 12710 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 12711 goto fallback; 12712 } 12713 12714 if (wedged(sna)) { 12715 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 12716 goto fallback; 12717 } 12718 12719 if (!PM_IS_SOLID(draw, gc->planemask)) { 12720 DBG(("%s: fallback -- planemask=%#lx (not-solid)\n", 12721 __FUNCTION__, gc->planemask)); 12722 goto fallback; 12723 } 12724 12725 /* Clear the cpu damage so that we refresh the GPU status of the 12726 * pixmap upon a redraw after a period of inactivity. 12727 */ 12728 hint = PREFER_GPU; 12729 if (n == 1 && gc->fillStyle != FillStippled && alu_overwrites(gc->alu)) { 12730 int16_t dx, dy; 12731 12732 region.data = NULL; 12733 12734 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) { 12735 DBG(("%s: delta=(%d, %d)\n", __FUNCTION__, dx, dy)); 12736 RegionTranslate(®ion, dx, dy); 12737 } 12738 12739 if (priv->cpu_damage && (flags & 2) == 0) { 12740 if (region_subsumes_damage(®ion, priv->cpu_damage)) { 12741 DBG(("%s: discarding existing CPU damage\n", __FUNCTION__)); 12742 if (priv->gpu_bo && priv->gpu_bo->proxy) { 12743 assert(priv->gpu_damage == NULL); 12744 assert(!priv->pinned); 12745 kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 12746 priv->gpu_bo = NULL; 12747 } 12748 sna_damage_destroy(&priv->cpu_damage); 12749 list_del(&priv->flush_list); 12750 } 12751 hint |= IGNORE_CPU; 12752 } 12753 if (region_subsumes_drawable(®ion, &pixmap->drawable)) 12754 hint |= REPLACES; 12755 if (priv->cpu_damage == NULL) { 12756 if (priv->gpu_bo && 12757 (hint & REPLACES || box_inplace(pixmap, ®ion.extents))) { 12758 DBG(("%s: promoting to full GPU\n", 12759 __FUNCTION__)); 12760 assert(priv->gpu_bo->proxy == NULL); 12761 sna_damage_all(&priv->gpu_damage, 12762 pixmap->drawable.width, 12763 pixmap->drawable.height); 12764 } 12765 DBG(("%s: dropping last-cpu hint\n", __FUNCTION__)); 12766 priv->cpu = false; 12767 } 12768 12769 if (dx | dy) 12770 RegionTranslate(®ion, -dx, -dy); 12771 } 12772 12773 /* If the source is already on the GPU, keep the operation on the GPU */ 12774 if (gc->fillStyle == FillTiled && !gc->tileIsPixel && 12775 sna_pixmap_is_gpu(gc->tile.pixmap)) { 12776 DBG(("%s: source is already on the gpu\n", __FUNCTION__)); 12777 hint |= FORCE_GPU; 12778 } 12779 12780 bo = sna_drawable_use_bo(draw, hint, ®ion.extents, &damage); 12781 if (bo == NULL) { 12782 DBG(("%s: not using GPU, hint=%x\n", __FUNCTION__, hint)); 12783 goto fallback; 12784 } 12785 if (hint & REPLACES && (flags & 2) == 0 && UNDO) 12786 kgem_bo_undo(&sna->kgem, bo); 12787 12788 if (gc_is_solid(gc, &color)) { 12789 DBG(("%s: solid fill [%08x], testing for blt\n", 12790 __FUNCTION__, color)); 12791 12792 if (sna_poly_fill_rect_blt(draw, 12793 bo, damage, 12794 gc, color, n, rect, 12795 ®ion.extents, flags & 2)) 12796 return; 12797 } else if (gc->fillStyle == FillTiled) { 12798 DBG(("%s: tiled fill, testing for blt\n", __FUNCTION__)); 12799 12800 if (sna_poly_fill_rect_tiled_blt(draw, bo, damage, 12801 gc, n, rect, 12802 ®ion.extents, flags & 2)) 12803 return; 12804 } else { 12805 DBG(("%s: stippled fill, testing for blt\n", __FUNCTION__)); 12806 12807 if (sna_poly_fill_rect_stippled_blt(draw, bo, damage, 12808 gc, n, rect, 12809 ®ion.extents, flags & 2)) 12810 return; 12811 } 12812 12813fallback: 12814 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 12815 region.extents.x1, region.extents.y1, 12816 region.extents.x2, region.extents.y2)); 12817 region.data = NULL; 12818 region_maybe_clip(®ion, gc->pCompositeClip); 12819 if (RegionNil(®ion)) { 12820 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 12821 return; 12822 } 12823 12824 if (!sna_gc_move_to_cpu(gc, draw, ®ion)) 12825 goto out; 12826 if (!sna_drawable_move_region_to_cpu(draw, ®ion, 12827 drawable_gc_flags(draw, gc, n > 1))) 12828 goto out_gc; 12829 12830 DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__)); 12831 fbPolyFillRect(draw, gc, n, rect); 12832 FALLBACK_FLUSH(draw); 12833out_gc: 12834 sna_gc_move_to_gpu(gc); 12835out: 12836 RegionUninit(®ion); 12837} 12838 12839static void 12840sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *r) 12841{ 12842 struct sna_fill_spans *data = sna_gc(gc)->priv; 12843 uint32_t color; 12844 12845 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 12846 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 12847 (gc->fillStyle == FillSolid || 12848 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 12849 gc->fillStyle, gc->tileIsPixel, 12850 gc->alu)); 12851 12852 assert(PM_IS_SOLID(draw, gc->planemask)); 12853 if (n == 0) 12854 return; 12855 12856 /* The mi routines do not attempt to keep the spans it generates 12857 * within the clip, so we must run them through the clipper. 12858 */ 12859 12860 if (gc_is_solid(gc, &color)) { 12861 (void)sna_poly_fill_rect_blt(draw, 12862 data->bo, data->damage, 12863 gc, color, n, r, 12864 &data->region.extents, true); 12865 } else if (gc->fillStyle == FillTiled) { 12866 (void)sna_poly_fill_rect_tiled_blt(draw, 12867 data->bo, data->damage, 12868 gc, n, r, 12869 &data->region.extents, true); 12870 } else { 12871 (void)sna_poly_fill_rect_stippled_blt(draw, 12872 data->bo, data->damage, 12873 gc, n, r, 12874 &data->region.extents, true); 12875 } 12876} 12877 12878static void 12879sna_poly_fill_arc(DrawablePtr draw, GCPtr gc, int n, xArc *arc) 12880{ 12881 struct sna_fill_spans data; 12882 struct sna_pixmap *priv; 12883 12884 DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__, 12885 n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask), 12886 (gc->fillStyle == FillSolid || 12887 (gc->fillStyle == FillTiled && gc->tileIsPixel)), 12888 gc->fillStyle, gc->tileIsPixel, 12889 gc->alu)); 12890 12891 data.flags = sna_poly_arc_extents(draw, gc, n, arc, 12892 &data.region.extents); 12893 if (data.flags == 0) 12894 return; 12895 12896 DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__, 12897 data.region.extents.x1, data.region.extents.y1, 12898 data.region.extents.x2, data.region.extents.y2, 12899 data.flags)); 12900 12901 data.region.data = NULL; 12902 12903 if (FORCE_FALLBACK) 12904 goto fallback; 12905 12906 if (!ACCEL_POLY_FILL_ARC) 12907 goto fallback; 12908 12909 data.pixmap = get_drawable_pixmap(draw); 12910 data.sna = to_sna_from_pixmap(data.pixmap); 12911 priv = sna_pixmap(data.pixmap); 12912 if (priv == NULL) { 12913 DBG(("%s: fallback -- unattached\n", __FUNCTION__)); 12914 goto fallback; 12915 } 12916 12917 if (wedged(data.sna)) { 12918 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 12919 goto fallback; 12920 } 12921 12922 if (!PM_IS_SOLID(draw, gc->planemask)) 12923 goto fallback; 12924 12925 if ((data.bo = sna_drawable_use_bo(draw, PREFER_GPU, 12926 &data.region.extents, 12927 &data.damage))) { 12928 uint32_t color; 12929 12930 get_drawable_deltas(draw, data.pixmap, &data.dx, &data.dy); 12931 sna_gc(gc)->priv = &data; 12932 12933 if (gc_is_solid(gc, &color)) { 12934 struct sna_fill_op fill; 12935 12936 if (!sna_fill_init_blt(&fill, 12937 data.sna, data.pixmap, 12938 data.bo, gc->alu, color)) 12939 goto fallback; 12940 12941 data.op = &fill; 12942 12943 if ((data.flags & 2) == 0) { 12944 if (data.dx | data.dy) 12945 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_offset; 12946 else 12947 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill; 12948 } else { 12949 region_maybe_clip(&data.region, 12950 gc->pCompositeClip); 12951 if (RegionNil(&data.region)) 12952 return; 12953 12954 if (region_is_singular(&data.region)) 12955 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_extents; 12956 else 12957 sna_gc_ops__tmp.FillSpans = sna_fill_spans__fill_clip_boxes; 12958 } 12959 assert(gc->miTranslate); 12960 gc->ops = &sna_gc_ops__tmp; 12961 12962 miPolyFillArc(draw, gc, n, arc); 12963 fill.done(data.sna, &fill); 12964 } else { 12965 sna_gc_ops__tmp.FillSpans = sna_fill_spans__gpu; 12966 gc->ops = &sna_gc_ops__tmp; 12967 12968 miPolyFillArc(draw, gc, n, arc); 12969 } 12970 12971 gc->ops = (GCOps *)&sna_gc_ops; 12972 if (data.damage) { 12973 if (data.dx | data.dy) 12974 pixman_region_translate(&data.region, data.dx, data.dy); 12975 assert_pixmap_contains_box(data.pixmap, &data.region.extents); 12976 sna_damage_add(data.damage, &data.region); 12977 } 12978 assert_pixmap_damage(data.pixmap); 12979 RegionUninit(&data.region); 12980 return; 12981 } 12982 12983fallback: 12984 DBG(("%s: fallback (%d, %d), (%d, %d)\n", __FUNCTION__, 12985 data.region.extents.x1, data.region.extents.y1, 12986 data.region.extents.x2, data.region.extents.y2)); 12987 region_maybe_clip(&data.region, gc->pCompositeClip); 12988 if (RegionNil(&data.region)) { 12989 DBG(("%s: nothing to do, all clipped\n", __FUNCTION__)); 12990 return; 12991 } 12992 12993 if (!sna_gc_move_to_cpu(gc, draw, &data.region)) 12994 goto out; 12995 if (!sna_drawable_move_region_to_cpu(draw, &data.region, 12996 drawable_gc_flags(draw, gc, true))) 12997 goto out_gc; 12998 12999 DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n", 13000 __FUNCTION__)); 13001 13002 miPolyFillArc(draw, gc, n, arc); 13003out_gc: 13004 sna_gc_move_to_gpu(gc); 13005out: 13006 RegionUninit(&data.region); 13007} 13008 13009struct sna_font { 13010 CharInfoRec glyphs8[256]; 13011 CharInfoRec *glyphs16[256]; 13012}; 13013#define GLYPH_INVALID (void *)1 13014#define GLYPH_EMPTY (void *)2 13015#define GLYPH_CLEAR (void *)3 13016 13017static Bool 13018sna_realize_font(ScreenPtr screen, FontPtr font) 13019{ 13020 struct sna_font *priv; 13021 13022 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 13023 13024 priv = calloc(1, sizeof(struct sna_font)); 13025 if (priv == NULL) 13026 return FALSE; 13027 13028 if (!FontSetPrivate(font, sna_font_key, priv)) { 13029 free(priv); 13030 return FALSE; 13031 } 13032 13033 return TRUE; 13034} 13035 13036static Bool 13037sna_unrealize_font(ScreenPtr screen, FontPtr font) 13038{ 13039 struct sna_font *priv = FontGetPrivate(font, sna_font_key); 13040 int i, j; 13041 13042 DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key)); 13043 13044 if (priv == NULL) 13045 return TRUE; 13046 13047 for (i = 0; i < 256; i++) { 13048 if ((uintptr_t)priv->glyphs8[i].bits & ~3) 13049 free(priv->glyphs8[i].bits); 13050 } 13051 for (j = 0; j < 256; j++) { 13052 if (priv->glyphs16[j] == NULL) 13053 continue; 13054 13055 for (i = 0; i < 256; i++) { 13056 if ((uintptr_t)priv->glyphs16[j][i].bits & ~3) 13057 free(priv->glyphs16[j][i].bits); 13058 } 13059 free(priv->glyphs16[j]); 13060 } 13061 free(priv); 13062 13063 FontSetPrivate(font, sna_font_key, NULL); 13064 return TRUE; 13065} 13066 13067static bool 13068sna_glyph_blt(DrawablePtr drawable, GCPtr gc, 13069 int _x, int _y, unsigned int _n, 13070 CharInfoPtr *_info, 13071 RegionRec *clip, 13072 uint32_t fg, uint32_t bg, 13073 bool transparent) 13074{ 13075 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13076 struct sna *sna = to_sna_from_pixmap(pixmap); 13077 struct kgem_bo *bo; 13078 struct sna_damage **damage; 13079 const BoxRec *extents, *last_extents; 13080 uint32_t *b; 13081 int16_t dx, dy; 13082 uint32_t br00; 13083 uint16_t unwind_batch, unwind_reloc; 13084 13085 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 13086 13087 DBG(("%s (%d, %d) x %d, fg=%08x, bg=%08x alu=%02x\n", 13088 __FUNCTION__, _x, _y, _n, fg, bg, rop)); 13089 13090 if (wedged(sna)) { 13091 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 13092 return false; 13093 } 13094 13095 bo = sna_drawable_use_bo(drawable, PREFER_GPU, &clip->extents, &damage); 13096 if (bo == NULL) 13097 return false; 13098 13099 if (bo->tiling == I915_TILING_Y) { 13100 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 13101 assert(bo == __sna_pixmap_get_bo(pixmap)); 13102 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 13103 if (bo == NULL) { 13104 DBG(("%s: fallback -- unable to change tiling\n", 13105 __FUNCTION__)); 13106 return false; 13107 } 13108 } 13109 13110 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13111 _x += drawable->x + dx; 13112 _y += drawable->y + dy; 13113 13114 RegionTranslate(clip, dx, dy); 13115 extents = RegionRects(clip); 13116 last_extents = extents + RegionNumRects(clip); 13117 13118 if (!transparent) /* emulate miImageGlyphBlt */ 13119 sna_blt_fill_boxes(sna, GXcopy, 13120 bo, drawable->bitsPerPixel, 13121 bg, extents, RegionNumRects(clip)); 13122 13123 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13124 if (!kgem_check_batch(&sna->kgem, 16) || 13125 !kgem_check_bo_fenced(&sna->kgem, bo) || 13126 !kgem_check_reloc(&sna->kgem, 1)) { 13127 kgem_submit(&sna->kgem); 13128 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13129 return false; 13130 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13131 } 13132 13133 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 13134 __FUNCTION__, 13135 extents->x1, extents->y1, 13136 extents->x2, extents->y2)); 13137 13138 unwind_batch = sna->kgem.nbatch; 13139 unwind_reloc = sna->kgem.nreloc; 13140 13141 b = sna->kgem.batch + sna->kgem.nbatch; 13142 b[0] = XY_SETUP_BLT | 3 << 20; 13143 b[1] = bo->pitch; 13144 if (sna->kgem.gen >= 040 && bo->tiling) { 13145 b[0] |= BLT_DST_TILED; 13146 b[1] >>= 2; 13147 } 13148 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 13149 b[2] = extents->y1 << 16 | extents->x1; 13150 b[3] = extents->y2 << 16 | extents->x2; 13151 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13152 I915_GEM_DOMAIN_RENDER << 16 | 13153 I915_GEM_DOMAIN_RENDER | 13154 KGEM_RELOC_FENCED, 13155 0); 13156 b[5] = bg; 13157 b[6] = fg; 13158 b[7] = 0; 13159 sna->kgem.nbatch += 8; 13160 13161 br00 = XY_TEXT_IMMEDIATE_BLT; 13162 if (bo->tiling && sna->kgem.gen >= 040) 13163 br00 |= BLT_DST_TILED; 13164 13165 do { 13166 CharInfoPtr *info = _info; 13167 int x = _x, y = _y, n = _n; 13168 13169 do { 13170 CharInfoPtr c = *info++; 13171 int w = GLYPHWIDTHPIXELS(c); 13172 int h = GLYPHHEIGHTPIXELS(c); 13173 int w8 = (w + 7) >> 3; 13174 int x1, y1, len; 13175 13176 if (c->bits == GLYPH_EMPTY) 13177 goto skip; 13178 13179 if (!transparent && c->bits == GLYPH_CLEAR) 13180 goto skip; 13181 13182 len = (w8 * h + 7) >> 3 << 1; 13183 x1 = x + c->metrics.leftSideBearing; 13184 y1 = y - c->metrics.ascent; 13185 13186 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 13187 x,y, x1, y1, w, w8, h, len)); 13188 13189 if (x1 >= extents->x2 || y1 >= extents->y2) 13190 goto skip; 13191 if (x1 + w <= extents->x1 || y1 + h <= extents->y1) 13192 goto skip; 13193 13194 13195 if (!kgem_check_batch(&sna->kgem, 3+len)) { 13196 _kgem_submit(&sna->kgem); 13197 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13198 13199 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 13200 __FUNCTION__, 13201 extents->x1, extents->y1, 13202 extents->x2, extents->y2)); 13203 13204 unwind_batch = sna->kgem.nbatch; 13205 unwind_reloc = sna->kgem.nreloc; 13206 13207 b = sna->kgem.batch + sna->kgem.nbatch; 13208 b[0] = XY_SETUP_BLT | 3 << 20; 13209 b[1] = bo->pitch; 13210 if (sna->kgem.gen >= 040 && bo->tiling) { 13211 b[0] |= BLT_DST_TILED; 13212 b[1] >>= 2; 13213 } 13214 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 13215 b[2] = extents->y1 << 16 | extents->x1; 13216 b[3] = extents->y2 << 16 | extents->x2; 13217 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13218 I915_GEM_DOMAIN_RENDER << 16 | 13219 I915_GEM_DOMAIN_RENDER | 13220 KGEM_RELOC_FENCED, 13221 0); 13222 b[5] = bg; 13223 b[6] = fg; 13224 b[7] = 0; 13225 sna->kgem.nbatch += 8; 13226 } 13227 13228 b = sna->kgem.batch + sna->kgem.nbatch; 13229 sna->kgem.nbatch += 3 + len; 13230 13231 b[0] = br00 | (1 + len); 13232 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 13233 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 13234 if (c->bits == GLYPH_CLEAR) { 13235 memset(b+3, 0, len*4); 13236 } else { 13237 uint64_t *src = (uint64_t *)c->bits; 13238 uint64_t *dst = (uint64_t *)(b + 3); 13239 do { 13240 *dst++ = *src++; 13241 len -= 2; 13242 } while (len); 13243 } 13244 13245 if (damage) { 13246 BoxRec r; 13247 13248 r.x1 = x1; 13249 r.y1 = y1; 13250 r.x2 = x1 + w; 13251 r.y2 = y1 + h; 13252 if (box_intersect(&r, extents)) 13253 sna_damage_add_box(damage, &r); 13254 } 13255skip: 13256 x += c->metrics.characterWidth; 13257 } while (--n); 13258 13259 if (++extents == last_extents) 13260 break; 13261 13262 if (kgem_check_batch(&sna->kgem, 3)) { 13263 b = sna->kgem.batch + sna->kgem.nbatch; 13264 sna->kgem.nbatch += 3; 13265 13266 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 13267 __FUNCTION__, 13268 extents->x1, extents->y1, 13269 extents->x2, extents->y2)); 13270 13271 b[0] = XY_SETUP_CLIP; 13272 b[1] = extents->y1 << 16 | extents->x1; 13273 b[2] = extents->y2 << 16 | extents->x2; 13274 } 13275 } while (1); 13276 13277 if (sna->kgem.nbatch == unwind_batch + 8) { 13278 sna->kgem.nbatch = unwind_batch; 13279 sna->kgem.nreloc = unwind_reloc; 13280 } 13281 13282 assert_pixmap_damage(pixmap); 13283 sna->blt_state.fill_bo = 0; 13284 return true; 13285} 13286 13287static void 13288sna_glyph_extents(FontPtr font, 13289 CharInfoPtr *info, 13290 unsigned long count, 13291 ExtentInfoRec *extents) 13292{ 13293 extents->drawDirection = font->info.drawDirection; 13294 extents->fontAscent = font->info.fontAscent; 13295 extents->fontDescent = font->info.fontDescent; 13296 13297 extents->overallAscent = info[0]->metrics.ascent; 13298 extents->overallDescent = info[0]->metrics.descent; 13299 extents->overallLeft = info[0]->metrics.leftSideBearing; 13300 extents->overallRight = info[0]->metrics.rightSideBearing; 13301 extents->overallWidth = info[0]->metrics.characterWidth; 13302 13303 while (--count) { 13304 CharInfoPtr p =*++info; 13305 int v; 13306 13307 if (p->metrics.ascent > extents->overallAscent) 13308 extents->overallAscent = p->metrics.ascent; 13309 if (p->metrics.descent > extents->overallDescent) 13310 extents->overallDescent = p->metrics.descent; 13311 13312 v = extents->overallWidth + p->metrics.leftSideBearing; 13313 if (v < extents->overallLeft) 13314 extents->overallLeft = v; 13315 13316 v = extents->overallWidth + p->metrics.rightSideBearing; 13317 if (v > extents->overallRight) 13318 extents->overallRight = v; 13319 13320 extents->overallWidth += p->metrics.characterWidth; 13321 } 13322} 13323 13324static bool sna_set_glyph(CharInfoPtr in, CharInfoPtr out) 13325{ 13326 int w = GLYPHWIDTHPIXELS(in); 13327 int h = GLYPHHEIGHTPIXELS(in); 13328 int stride = GLYPHWIDTHBYTESPADDED(in); 13329 uint8_t *dst, *src; 13330 int clear = 1; 13331 13332 out->metrics = in->metrics; 13333 13334 /* Skip empty glyphs */ 13335 if (w == 0 || h == 0 || ((w|h) == 1 && (in->bits[0] & 1) == 0)) { 13336 out->bits = GLYPH_EMPTY; 13337 return true; 13338 } 13339 13340 w = (w + 7) >> 3; 13341 13342 out->bits = malloc((w*h + 7) & ~7); 13343 if (out->bits == NULL) 13344 return false; 13345 13346 VG(memset(out->bits, 0, (w*h + 7) & ~7)); 13347 src = (uint8_t *)in->bits; 13348 dst = (uint8_t *)out->bits; 13349 stride -= w; 13350 do { 13351 int i = w; 13352 do { 13353 clear &= *src == 0; 13354 *dst++ = byte_reverse(*src++); 13355 } while (--i); 13356 src += stride; 13357 } while (--h); 13358 13359 if (clear) { 13360 free(out->bits); 13361 out->bits = GLYPH_CLEAR; 13362 } 13363 13364 return true; 13365} 13366 13367inline static bool sna_get_glyph8(FontPtr font, struct sna_font *priv, 13368 uint8_t g, CharInfoPtr *out) 13369{ 13370 unsigned long n; 13371 CharInfoPtr p, ret; 13372 13373 p = &priv->glyphs8[g]; 13374 if (p->bits) { 13375 *out = p; 13376 return p->bits != GLYPH_INVALID; 13377 } 13378 13379 font->get_glyphs(font, 1, &g, Linear8Bit, &n, &ret); 13380 if (n == 0) { 13381 p->bits = GLYPH_INVALID; 13382 return false; 13383 } 13384 13385 return sna_set_glyph(ret, *out = p); 13386} 13387 13388inline static bool sna_get_glyph16(FontPtr font, struct sna_font *priv, 13389 uint16_t g, CharInfoPtr *out) 13390{ 13391 unsigned long n; 13392 CharInfoPtr page, p, ret; 13393 13394 page = priv->glyphs16[g>>8]; 13395 if (page == NULL) 13396 page = priv->glyphs16[g>>8] = calloc(256, sizeof(CharInfoRec)); 13397 13398 p = &page[g&0xff]; 13399 if (p->bits) { 13400 *out = p; 13401 return p->bits != GLYPH_INVALID; 13402 } 13403 13404 font->get_glyphs(font, 1, (unsigned char *)&g, 13405 FONTLASTROW(font) ? TwoD16Bit : Linear16Bit, 13406 &n, &ret); 13407 if (n == 0) { 13408 p->bits = GLYPH_INVALID; 13409 return false; 13410 } 13411 13412 return sna_set_glyph(ret, *out = p); 13413} 13414 13415static inline bool sna_font_too_large(FontPtr font) 13416{ 13417 int top = max(FONTMAXBOUNDS(font, ascent), FONTASCENT(font)); 13418 int bot = max(FONTMAXBOUNDS(font, descent), FONTDESCENT(font)); 13419 int width = max(FONTMAXBOUNDS(font, characterWidth), -FONTMINBOUNDS(font, characterWidth)); 13420 DBG(("%s? (%d + %d) x %d: %d > 124\n", __FUNCTION__, 13421 top, bot, width, (top + bot) * (width + 7)/8)); 13422 return (top + bot) * (width + 7)/8 > 124; 13423} 13424 13425static int 13426sna_poly_text8(DrawablePtr drawable, GCPtr gc, 13427 int x, int y, 13428 int count, char *chars) 13429{ 13430 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 13431 CharInfoPtr info[255]; 13432 ExtentInfoRec extents; 13433 RegionRec region; 13434 long unsigned i, n; 13435 uint32_t fg; 13436 13437 for (i = n = 0; i < count; i++) { 13438 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 13439 n++; 13440 } 13441 if (n == 0) 13442 return x; 13443 13444 sna_glyph_extents(gc->font, info, n, &extents); 13445 region.extents.x1 = x + extents.overallLeft; 13446 region.extents.y1 = y - extents.overallAscent; 13447 region.extents.x2 = x + extents.overallRight; 13448 region.extents.y2 = y + extents.overallDescent; 13449 13450 translate_box(®ion.extents, drawable); 13451 clip_box(®ion.extents, gc); 13452 if (box_empty(®ion.extents)) 13453 return x + extents.overallRight; 13454 13455 region.data = NULL; 13456 region_maybe_clip(®ion, gc->pCompositeClip); 13457 if (RegionNil(®ion)) 13458 return x + extents.overallRight; 13459 13460 if (FORCE_FALLBACK) 13461 goto fallback; 13462 13463 if (!ACCEL_POLY_TEXT8) 13464 goto fallback; 13465 13466 if (sna_font_too_large(gc->font)) 13467 goto fallback; 13468 13469 if (!PM_IS_SOLID(drawable, gc->planemask)) 13470 goto fallback; 13471 13472 if (!gc_is_solid(gc, &fg)) 13473 goto fallback; 13474 13475 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 13476fallback: 13477 DBG(("%s: fallback\n", __FUNCTION__)); 13478 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 13479 Linear8Bit, &n, info); 13480 13481 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 13482 goto out; 13483 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 13484 MOVE_READ | MOVE_WRITE)) 13485 goto out_gc; 13486 13487 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 13488 fbPolyGlyphBlt(drawable, gc, x, y, n, 13489 info, FONTGLYPHS(gc->font)); 13490 FALLBACK_FLUSH(drawable); 13491out_gc: 13492 sna_gc_move_to_gpu(gc); 13493 } 13494out: 13495 RegionUninit(®ion); 13496 return x + extents.overallRight; 13497} 13498 13499static int 13500sna_poly_text16(DrawablePtr drawable, GCPtr gc, 13501 int x, int y, 13502 int count, unsigned short *chars) 13503{ 13504 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 13505 CharInfoPtr info[255]; 13506 ExtentInfoRec extents; 13507 RegionRec region; 13508 long unsigned i, n; 13509 uint32_t fg; 13510 13511 for (i = n = 0; i < count; i++) { 13512 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 13513 n++; 13514 } 13515 if (n == 0) 13516 return x; 13517 13518 sna_glyph_extents(gc->font, info, n, &extents); 13519 region.extents.x1 = x + extents.overallLeft; 13520 region.extents.y1 = y - extents.overallAscent; 13521 region.extents.x2 = x + extents.overallRight; 13522 region.extents.y2 = y + extents.overallDescent; 13523 13524 translate_box(®ion.extents, drawable); 13525 clip_box(®ion.extents, gc); 13526 if (box_empty(®ion.extents)) 13527 return x + extents.overallRight; 13528 13529 region.data = NULL; 13530 region_maybe_clip(®ion, gc->pCompositeClip); 13531 if (RegionNil(®ion)) 13532 return x + extents.overallRight; 13533 13534 if (FORCE_FALLBACK) 13535 goto fallback; 13536 13537 if (!ACCEL_POLY_TEXT16) 13538 goto fallback; 13539 13540 if (sna_font_too_large(gc->font)) 13541 goto fallback; 13542 13543 if (!PM_IS_SOLID(drawable, gc->planemask)) 13544 goto fallback; 13545 13546 if (!gc_is_solid(gc, &fg)) 13547 goto fallback; 13548 13549 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, fg, -1, true)) { 13550fallback: 13551 DBG(("%s: fallback\n", __FUNCTION__)); 13552 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 13553 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 13554 &n, info); 13555 13556 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 13557 goto out; 13558 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 13559 MOVE_READ | MOVE_WRITE)) 13560 goto out_gc; 13561 13562 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 13563 fbPolyGlyphBlt(drawable, gc, x, y, n, 13564 info, FONTGLYPHS(gc->font)); 13565 FALLBACK_FLUSH(drawable); 13566out_gc: 13567 sna_gc_move_to_gpu(gc); 13568 } 13569out: 13570 RegionUninit(®ion); 13571 return x + extents.overallRight; 13572} 13573 13574static void 13575sna_image_text8(DrawablePtr drawable, GCPtr gc, 13576 int x, int y, 13577 int count, char *chars) 13578{ 13579 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 13580 CharInfoPtr info[255]; 13581 ExtentInfoRec extents; 13582 RegionRec region; 13583 long unsigned i, n; 13584 13585 for (i = n = 0; i < count; i++) { 13586 if (sna_get_glyph8(gc->font, priv, chars[i], &info[n])) 13587 n++; 13588 } 13589 if (n == 0) 13590 return; 13591 13592 sna_glyph_extents(gc->font, info, n, &extents); 13593 region.extents.x1 = x + MIN(0, extents.overallLeft); 13594 region.extents.y1 = y - extents.fontAscent; 13595 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 13596 region.extents.y2 = y + extents.fontDescent; 13597 13598 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 13599 __FUNCTION__, n, count, 13600 extents.overallLeft, extents.overallRight, extents.overallWidth, 13601 extents.fontAscent, extents.fontDescent, 13602 region.extents.x1, region.extents.y1, 13603 region.extents.x2, region.extents.y2)); 13604 13605 translate_box(®ion.extents, drawable); 13606 clip_box(®ion.extents, gc); 13607 if (box_empty(®ion.extents)) 13608 return; 13609 13610 region.data = NULL; 13611 region_maybe_clip(®ion, gc->pCompositeClip); 13612 if (RegionNil(®ion)) 13613 return; 13614 13615 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 13616 __FUNCTION__, 13617 region.extents.x1, region.extents.y1, 13618 region.extents.x2, region.extents.y2)); 13619 13620 if (FORCE_FALLBACK) 13621 goto fallback; 13622 13623 if (!ACCEL_IMAGE_TEXT8) 13624 goto fallback; 13625 13626 if (sna_font_too_large(gc->font)) 13627 goto fallback; 13628 13629 if (!PM_IS_SOLID(drawable, gc->planemask)) 13630 goto fallback; 13631 13632 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 13633 gc->fgPixel, gc->bgPixel, false)) { 13634fallback: 13635 DBG(("%s: fallback\n", __FUNCTION__)); 13636 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 13637 Linear8Bit, &n, info); 13638 13639 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 13640 goto out; 13641 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 13642 MOVE_READ | MOVE_WRITE)) 13643 goto out_gc; 13644 13645 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 13646 fbImageGlyphBlt(drawable, gc, x, y, n, 13647 info, FONTGLYPHS(gc->font)); 13648 FALLBACK_FLUSH(drawable); 13649out_gc: 13650 sna_gc_move_to_gpu(gc); 13651 } 13652out: 13653 RegionUninit(®ion); 13654} 13655 13656static void 13657sna_image_text16(DrawablePtr drawable, GCPtr gc, 13658 int x, int y, 13659 int count, unsigned short *chars) 13660{ 13661 struct sna_font *priv = gc->font->devPrivates[sna_font_key]; 13662 CharInfoPtr info[255]; 13663 ExtentInfoRec extents; 13664 RegionRec region; 13665 long unsigned i, n; 13666 13667 for (i = n = 0; i < count; i++) { 13668 if (sna_get_glyph16(gc->font, priv, chars[i], &info[n])) 13669 n++; 13670 } 13671 if (n == 0) 13672 return; 13673 13674 sna_glyph_extents(gc->font, info, n, &extents); 13675 region.extents.x1 = x + MIN(0, extents.overallLeft); 13676 region.extents.y1 = y - extents.fontAscent; 13677 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 13678 region.extents.y2 = y + extents.fontDescent; 13679 13680 DBG(("%s: count=%ld/%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 13681 __FUNCTION__, n, count, 13682 extents.overallLeft, extents.overallRight, extents.overallWidth, 13683 extents.fontAscent, extents.fontDescent, 13684 region.extents.x1, region.extents.y1, 13685 region.extents.x2, region.extents.y2)); 13686 13687 translate_box(®ion.extents, drawable); 13688 clip_box(®ion.extents, gc); 13689 if (box_empty(®ion.extents)) 13690 return; 13691 13692 region.data = NULL; 13693 region_maybe_clip(®ion, gc->pCompositeClip); 13694 if (RegionNil(®ion)) 13695 return; 13696 13697 DBG(("%s: clipped extents (%d, %d), (%d, %d)\n", 13698 __FUNCTION__, 13699 region.extents.x1, region.extents.y1, 13700 region.extents.x2, region.extents.y2)); 13701 13702 if (FORCE_FALLBACK) 13703 goto fallback; 13704 13705 if (!ACCEL_IMAGE_TEXT16) 13706 goto fallback; 13707 13708 if (sna_font_too_large(gc->font)) 13709 goto fallback; 13710 13711 if (!PM_IS_SOLID(drawable, gc->planemask)) 13712 goto fallback; 13713 13714 if (!sna_glyph_blt(drawable, gc, x, y, n, info, ®ion, 13715 gc->fgPixel, gc->bgPixel, false)) { 13716fallback: 13717 DBG(("%s: fallback\n", __FUNCTION__)); 13718 gc->font->get_glyphs(gc->font, count, (unsigned char *)chars, 13719 FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit, 13720 &n, info); 13721 13722 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 13723 goto out; 13724 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 13725 MOVE_READ | MOVE_WRITE)) 13726 goto out_gc; 13727 13728 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 13729 fbImageGlyphBlt(drawable, gc, x, y, n, 13730 info, FONTGLYPHS(gc->font)); 13731 FALLBACK_FLUSH(drawable); 13732out_gc: 13733 sna_gc_move_to_gpu(gc); 13734 } 13735out: 13736 RegionUninit(®ion); 13737} 13738 13739/* XXX Damage bypasses the Text interface and so we lose our custom gluphs */ 13740static bool 13741sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc, 13742 int _x, int _y, unsigned int _n, 13743 CharInfoPtr *_info, pointer _base, 13744 struct kgem_bo *bo, 13745 struct sna_damage **damage, 13746 RegionPtr clip, 13747 uint32_t fg, uint32_t bg, 13748 bool transparent) 13749{ 13750 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13751 struct sna *sna = to_sna_from_pixmap(pixmap); 13752 const BoxRec *extents, *last_extents; 13753 uint32_t *b; 13754 int16_t dx, dy; 13755 uint8_t rop = transparent ? copy_ROP[gc->alu] : ROP_S; 13756 uint16_t unwind_batch, unwind_reloc; 13757 13758 if (bo->tiling == I915_TILING_Y) { 13759 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 13760 assert(bo == __sna_pixmap_get_bo(pixmap)); 13761 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 13762 if (bo == NULL) { 13763 DBG(("%s: fallback -- unable to change tiling\n", 13764 __FUNCTION__)); 13765 return false; 13766 } 13767 } 13768 13769 get_drawable_deltas(drawable, pixmap, &dx, &dy); 13770 _x += drawable->x + dx; 13771 _y += drawable->y + dy; 13772 13773 RegionTranslate(clip, dx, dy); 13774 extents = RegionRects(clip); 13775 last_extents = extents + RegionNumRects(clip); 13776 13777 if (!transparent) /* emulate miImageGlyphBlt */ 13778 sna_blt_fill_boxes(sna, GXcopy, 13779 bo, drawable->bitsPerPixel, 13780 bg, extents, RegionNumRects(clip)); 13781 13782 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 13783 if (!kgem_check_batch(&sna->kgem, 16) || 13784 !kgem_check_bo_fenced(&sna->kgem, bo) || 13785 !kgem_check_reloc(&sna->kgem, 1)) { 13786 kgem_submit(&sna->kgem); 13787 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 13788 return false; 13789 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13790 } 13791 13792 unwind_batch = sna->kgem.nbatch; 13793 unwind_reloc = sna->kgem.nreloc; 13794 13795 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 13796 __FUNCTION__, 13797 extents->x1, extents->y1, 13798 extents->x2, extents->y2)); 13799 b = sna->kgem.batch + sna->kgem.nbatch; 13800 b[0] = XY_SETUP_BLT | 1 << 20; 13801 b[1] = bo->pitch; 13802 if (sna->kgem.gen >= 040 && bo->tiling) { 13803 b[0] |= BLT_DST_TILED; 13804 b[1] >>= 2; 13805 } 13806 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 13807 b[2] = extents->y1 << 16 | extents->x1; 13808 b[3] = extents->y2 << 16 | extents->x2; 13809 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 13810 I915_GEM_DOMAIN_RENDER << 16 | 13811 I915_GEM_DOMAIN_RENDER | 13812 KGEM_RELOC_FENCED, 13813 0); 13814 b[5] = bg; 13815 b[6] = fg; 13816 b[7] = 0; 13817 sna->kgem.nbatch += 8; 13818 13819 do { 13820 CharInfoPtr *info = _info; 13821 int x = _x, y = _y, n = _n; 13822 13823 do { 13824 CharInfoPtr c = *info++; 13825 uint8_t *glyph = FONTGLYPHBITS(base, c); 13826 int w = GLYPHWIDTHPIXELS(c); 13827 int h = GLYPHHEIGHTPIXELS(c); 13828 int stride = GLYPHWIDTHBYTESPADDED(c); 13829 int w8 = (w + 7) >> 3; 13830 int x1, y1, len, i; 13831 uint8_t *byte; 13832 13833 if (w == 0 || h == 0) 13834 goto skip; 13835 13836 len = (w8 * h + 7) >> 3 << 1; 13837 x1 = x + c->metrics.leftSideBearing; 13838 y1 = y - c->metrics.ascent; 13839 13840 DBG(("%s glyph: (%d, %d) -> (%d, %d) x (%d[%d], %d), len=%d\n" ,__FUNCTION__, 13841 x,y, x1, y1, w, w8, h, len)); 13842 13843 if (x1 >= extents->x2 || y1 >= extents->y2 || 13844 x1 + w <= extents->x1 || y1 + h <= extents->y1) { 13845 DBG(("%s: glyph is clipped (%d, %d)x(%d,%d) against extents (%d, %d), (%d, %d)\n", 13846 __FUNCTION__, 13847 x1, y1, w, h, 13848 extents->x1, extents->y1, 13849 extents->x2, extents->y2)); 13850 goto skip; 13851 } 13852 13853 if (!transparent) { 13854 int clear = 1, j = h; 13855 uint8_t *g = glyph; 13856 13857 do { 13858 i = w8; 13859 do { 13860 clear = *g++ == 0; 13861 } while (clear && --i); 13862 g += stride - w8; 13863 } while (clear && --j); 13864 if (clear) { 13865 DBG(("%s: skipping clear glyph for ImageGlyph\n", 13866 __FUNCTION__)); 13867 goto skip; 13868 } 13869 } 13870 13871 if (!kgem_check_batch(&sna->kgem, 3+len)) { 13872 _kgem_submit(&sna->kgem); 13873 _kgem_set_mode(&sna->kgem, KGEM_BLT); 13874 13875 unwind_batch = sna->kgem.nbatch; 13876 unwind_reloc = sna->kgem.nreloc; 13877 13878 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n", 13879 __FUNCTION__, 13880 extents->x1, extents->y1, 13881 extents->x2, extents->y2)); 13882 13883 b = sna->kgem.batch + sna->kgem.nbatch; 13884 b[0] = XY_SETUP_BLT | 1 << 20; 13885 b[1] = bo->pitch; 13886 if (sna->kgem.gen >= 040 && bo->tiling) { 13887 b[0] |= BLT_DST_TILED; 13888 b[1] >>= 2; 13889 } 13890 b[1] |= 1 << 30 | transparent << 29 | blt_depth(drawable->depth) << 24 | rop << 16; 13891 b[2] = extents->y1 << 16 | extents->x1; 13892 b[3] = extents->y2 << 16 | extents->x2; 13893 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, 13894 bo, 13895 I915_GEM_DOMAIN_RENDER << 16 | 13896 I915_GEM_DOMAIN_RENDER | 13897 KGEM_RELOC_FENCED, 13898 0); 13899 b[5] = bg; 13900 b[6] = fg; 13901 b[7] = 0; 13902 sna->kgem.nbatch += 8; 13903 } 13904 13905 b = sna->kgem.batch + sna->kgem.nbatch; 13906 sna->kgem.nbatch += 3 + len; 13907 13908 b[0] = XY_TEXT_IMMEDIATE_BLT | (1 + len); 13909 if (bo->tiling && sna->kgem.gen >= 040) 13910 b[0] |= BLT_DST_TILED; 13911 b[1] = (uint16_t)y1 << 16 | (uint16_t)x1; 13912 b[2] = (uint16_t)(y1+h) << 16 | (uint16_t)(x1+w); 13913 13914 byte = (uint8_t *)&b[3]; 13915 stride -= w8; 13916 do { 13917 i = w8; 13918 do { 13919 *byte++ = byte_reverse(*glyph++); 13920 } while (--i); 13921 glyph += stride; 13922 } while (--h); 13923 while ((byte - (uint8_t *)&b[3]) & 7) 13924 *byte++ = 0; 13925 assert((uint32_t *)byte == sna->kgem.batch + sna->kgem.nbatch); 13926 13927 if (damage) { 13928 BoxRec r; 13929 13930 r.x1 = x1; 13931 r.y1 = y1; 13932 r.x2 = x1 + w; 13933 r.y2 = y1 + h; 13934 if (box_intersect(&r, extents)) 13935 sna_damage_add_box(damage, &r); 13936 } 13937skip: 13938 x += c->metrics.characterWidth; 13939 } while (--n); 13940 13941 if (++extents == last_extents) 13942 break; 13943 13944 if (kgem_check_batch(&sna->kgem, 3 + 5)) { 13945 b = sna->kgem.batch + sna->kgem.nbatch; 13946 sna->kgem.nbatch += 3; 13947 13948 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n", 13949 __FUNCTION__, 13950 extents->x1, extents->y1, 13951 extents->x2, extents->y2)); 13952 13953 b[0] = XY_SETUP_CLIP; 13954 b[1] = extents->y1 << 16 | extents->x1; 13955 b[2] = extents->y2 << 16 | extents->x2; 13956 } 13957 } while (1); 13958 13959 if (sna->kgem.nbatch == unwind_batch + 8) { 13960 sna->kgem.nbatch = unwind_batch; 13961 sna->kgem.nreloc = unwind_reloc; 13962 } 13963 13964 assert_pixmap_damage(pixmap); 13965 sna->blt_state.fill_bo = 0; 13966 return true; 13967} 13968 13969static void 13970sna_image_glyph(DrawablePtr drawable, GCPtr gc, 13971 int x, int y, unsigned int n, 13972 CharInfoPtr *info, pointer base) 13973{ 13974 PixmapPtr pixmap = get_drawable_pixmap(drawable); 13975 struct sna *sna = to_sna_from_pixmap(pixmap); 13976 ExtentInfoRec extents; 13977 RegionRec region; 13978 struct sna_damage **damage; 13979 struct kgem_bo *bo; 13980 13981 if (n == 0) 13982 return; 13983 13984 sna_glyph_extents(gc->font, info, n, &extents); 13985 region.extents.x1 = x + MIN(0, extents.overallLeft); 13986 region.extents.y1 = y - extents.fontAscent; 13987 region.extents.x2 = x + MAX(extents.overallWidth, extents.overallRight); 13988 region.extents.y2 = y + extents.fontDescent; 13989 13990 DBG(("%s: count=%d, extents=(left=%d, right=%d, width=%d, ascent=%d, descent=%d), box=(%d, %d), (%d, %d)\n", 13991 __FUNCTION__, n, 13992 extents.overallLeft, extents.overallRight, extents.overallWidth, 13993 extents.fontAscent, extents.fontDescent, 13994 region.extents.x1, region.extents.y1, 13995 region.extents.x2, region.extents.y2)); 13996 13997 translate_box(®ion.extents, drawable); 13998 clip_box(®ion.extents, gc); 13999 if (box_empty(®ion.extents)) 14000 return; 14001 14002 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 14003 region.extents.x1, region.extents.y1, 14004 region.extents.x2, region.extents.y2)); 14005 14006 region.data = NULL; 14007 region_maybe_clip(®ion, gc->pCompositeClip); 14008 if (RegionNil(®ion)) 14009 return; 14010 14011 if (FORCE_FALLBACK) 14012 goto fallback; 14013 14014 if (!ACCEL_IMAGE_GLYPH) 14015 goto fallback; 14016 14017 if (wedged(sna)) { 14018 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14019 goto fallback; 14020 } 14021 14022 if (!PM_IS_SOLID(drawable, gc->planemask)) 14023 goto fallback; 14024 14025 if (sna_font_too_large(gc->font)) 14026 goto fallback; 14027 14028 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 14029 ®ion.extents, &damage)) && 14030 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 14031 bo, damage, ®ion, 14032 gc->fgPixel, gc->bgPixel, false)) 14033 goto out; 14034 14035fallback: 14036 DBG(("%s: fallback\n", __FUNCTION__)); 14037 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 14038 goto out; 14039 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 14040 MOVE_READ | MOVE_WRITE)) 14041 goto out_gc; 14042 14043 DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__)); 14044 fbImageGlyphBlt(drawable, gc, x, y, n, info, base); 14045 FALLBACK_FLUSH(drawable); 14046 14047out_gc: 14048 sna_gc_move_to_gpu(gc); 14049out: 14050 RegionUninit(®ion); 14051} 14052 14053static void 14054sna_poly_glyph(DrawablePtr drawable, GCPtr gc, 14055 int x, int y, unsigned int n, 14056 CharInfoPtr *info, pointer base) 14057{ 14058 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14059 struct sna *sna = to_sna_from_pixmap(pixmap); 14060 ExtentInfoRec extents; 14061 RegionRec region; 14062 struct sna_damage **damage; 14063 struct kgem_bo *bo; 14064 uint32_t fg; 14065 14066 if (n == 0) 14067 return; 14068 14069 sna_glyph_extents(gc->font, info, n, &extents); 14070 region.extents.x1 = x + extents.overallLeft; 14071 region.extents.y1 = y - extents.overallAscent; 14072 region.extents.x2 = x + extents.overallRight; 14073 region.extents.y2 = y + extents.overallDescent; 14074 14075 translate_box(®ion.extents, drawable); 14076 clip_box(®ion.extents, gc); 14077 if (box_empty(®ion.extents)) 14078 return; 14079 14080 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 14081 region.extents.x1, region.extents.y1, 14082 region.extents.x2, region.extents.y2)); 14083 14084 region.data = NULL; 14085 region_maybe_clip(®ion, gc->pCompositeClip); 14086 if (RegionNil(®ion)) 14087 return; 14088 14089 if (FORCE_FALLBACK) 14090 goto fallback; 14091 14092 if (!ACCEL_POLY_GLYPH) 14093 goto fallback; 14094 14095 if (wedged(sna)) { 14096 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14097 goto fallback; 14098 } 14099 14100 if (!PM_IS_SOLID(drawable, gc->planemask)) 14101 goto fallback; 14102 14103 if (!gc_is_solid(gc, &fg)) 14104 goto fallback; 14105 14106 if (sna_font_too_large(gc->font)) 14107 goto fallback; 14108 14109 if ((bo = sna_drawable_use_bo(drawable, PREFER_GPU, 14110 ®ion.extents, &damage)) && 14111 sna_reversed_glyph_blt(drawable, gc, x, y, n, info, base, 14112 bo, damage, ®ion, fg, -1, true)) 14113 goto out; 14114 14115fallback: 14116 DBG(("%s: fallback\n", __FUNCTION__)); 14117 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 14118 goto out; 14119 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 14120 MOVE_READ | MOVE_WRITE)) 14121 goto out_gc; 14122 14123 DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__)); 14124 fbPolyGlyphBlt(drawable, gc, x, y, n, info, base); 14125 FALLBACK_FLUSH(drawable); 14126 14127out_gc: 14128 sna_gc_move_to_gpu(gc); 14129out: 14130 RegionUninit(®ion); 14131} 14132 14133static bool 14134sna_push_pixels_solid_blt(GCPtr gc, 14135 PixmapPtr bitmap, 14136 DrawablePtr drawable, 14137 RegionPtr region) 14138{ 14139 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14140 struct sna *sna = to_sna_from_pixmap(pixmap); 14141 struct sna_damage **damage; 14142 struct kgem_bo *bo; 14143 BoxRec *box; 14144 int16_t dx, dy; 14145 int n; 14146 uint8_t rop = copy_ROP[gc->alu]; 14147 14148 bo = sna_drawable_use_bo(drawable, PREFER_GPU, ®ion->extents, &damage); 14149 if (bo == NULL) 14150 return false; 14151 14152 if (bo->tiling == I915_TILING_Y) { 14153 DBG(("%s: converting bo from Y-tiling\n", __FUNCTION__)); 14154 assert(bo == __sna_pixmap_get_bo(pixmap)); 14155 bo = sna_pixmap_change_tiling(pixmap, I915_TILING_X); 14156 if (bo == NULL) { 14157 DBG(("%s: fallback -- unable to change tiling\n", 14158 __FUNCTION__)); 14159 return false; 14160 } 14161 } 14162 14163 if (get_drawable_deltas(drawable, pixmap, &dx, &dy)) 14164 RegionTranslate(region, dx, dy); 14165 14166 assert_pixmap_contains_box(pixmap, RegionExtents(region)); 14167 if (damage) 14168 sna_damage_add(damage, region); 14169 assert_pixmap_damage(pixmap); 14170 14171 DBG(("%s: upload(%d, %d, %d, %d)\n", __FUNCTION__, 14172 region->extents.x1, region->extents.y1, 14173 region->extents.x2, region->extents.y2)); 14174 14175 kgem_set_mode(&sna->kgem, KGEM_BLT, bo); 14176 14177 /* Region is pre-clipped and translated into pixmap space */ 14178 box = RegionRects(region); 14179 n = RegionNumRects(region); 14180 do { 14181 int bx1 = (box->x1 - region->extents.x1) & ~7; 14182 int bx2 = (box->x2 - region->extents.x1 + 7) & ~7; 14183 int bw = (bx2 - bx1)/8; 14184 int bh = box->y2 - box->y1; 14185 int bstride = ALIGN(bw, 2); 14186 int src_stride; 14187 uint8_t *dst, *src; 14188 uint32_t *b; 14189 struct kgem_bo *upload; 14190 void *ptr; 14191 14192 if (!kgem_check_batch(&sna->kgem, 8) || 14193 !kgem_check_bo_fenced(&sna->kgem, bo) || 14194 !kgem_check_reloc_and_exec(&sna->kgem, 2)) { 14195 kgem_submit(&sna->kgem); 14196 if (!kgem_check_bo_fenced(&sna->kgem, bo)) 14197 return false; 14198 _kgem_set_mode(&sna->kgem, KGEM_BLT); 14199 } 14200 14201 upload = kgem_create_buffer(&sna->kgem, 14202 bstride*bh, 14203 KGEM_BUFFER_WRITE_INPLACE, 14204 &ptr); 14205 if (!upload) 14206 break; 14207 14208 dst = ptr; 14209 14210 src_stride = bitmap->devKind; 14211 src = (uint8_t*)bitmap->devPrivate.ptr; 14212 src += (box->y1 - region->extents.y1) * src_stride + bx1/8; 14213 src_stride -= bstride; 14214 do { 14215 int i = bstride; 14216 do { 14217 *dst++ = byte_reverse(*src++); 14218 *dst++ = byte_reverse(*src++); 14219 i -= 2; 14220 } while (i); 14221 src += src_stride; 14222 } while (--bh); 14223 14224 b = sna->kgem.batch + sna->kgem.nbatch; 14225 b[0] = XY_MONO_SRC_COPY | 3 << 20; 14226 b[0] |= ((box->x1 - region->extents.x1) & 7) << 17; 14227 b[1] = bo->pitch; 14228 if (sna->kgem.gen >= 040 && bo->tiling) { 14229 b[0] |= BLT_DST_TILED; 14230 b[1] >>= 2; 14231 } 14232 b[1] |= 1 << 29; 14233 b[1] |= blt_depth(drawable->depth) << 24; 14234 b[1] |= rop << 16; 14235 b[2] = box->y1 << 16 | box->x1; 14236 b[3] = box->y2 << 16 | box->x2; 14237 b[4] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 4, bo, 14238 I915_GEM_DOMAIN_RENDER << 16 | 14239 I915_GEM_DOMAIN_RENDER | 14240 KGEM_RELOC_FENCED, 14241 0); 14242 b[5] = kgem_add_reloc(&sna->kgem, sna->kgem.nbatch + 5, 14243 upload, 14244 I915_GEM_DOMAIN_RENDER << 16 | 14245 KGEM_RELOC_FENCED, 14246 0); 14247 b[6] = gc->bgPixel; 14248 b[7] = gc->fgPixel; 14249 14250 sna->kgem.nbatch += 8; 14251 kgem_bo_destroy(&sna->kgem, upload); 14252 14253 box++; 14254 } while (--n); 14255 14256 sna->blt_state.fill_bo = 0; 14257 return true; 14258} 14259 14260static void 14261sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable, 14262 int w, int h, 14263 int x, int y) 14264{ 14265 RegionRec region; 14266 14267 if (w == 0 || h == 0) 14268 return; 14269 14270 DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h)); 14271 14272 region.extents.x1 = x; 14273 region.extents.y1 = y; 14274 region.extents.x2 = region.extents.x1 + w; 14275 region.extents.y2 = region.extents.y1 + h; 14276 14277 clip_box(®ion.extents, gc); 14278 if (box_empty(®ion.extents)) 14279 return; 14280 14281 DBG(("%s: extents(%d, %d), (%d, %d)\n", __FUNCTION__, 14282 region.extents.x1, region.extents.y1, 14283 region.extents.x2, region.extents.y2)); 14284 14285 region.data = NULL; 14286 region_maybe_clip(®ion, gc->pCompositeClip); 14287 if (RegionNil(®ion)) 14288 return; 14289 14290 switch (gc->fillStyle) { 14291 case FillSolid: 14292 if (sna_push_pixels_solid_blt(gc, bitmap, drawable, ®ion)) 14293 return; 14294 break; 14295 default: 14296 break; 14297 } 14298 14299 DBG(("%s: fallback\n", __FUNCTION__)); 14300 if (!sna_gc_move_to_cpu(gc, drawable, ®ion)) 14301 goto out; 14302 if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ)) 14303 goto out_gc; 14304 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, 14305 drawable_gc_flags(drawable, gc, false))) 14306 goto out_gc; 14307 14308 DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n", 14309 __FUNCTION__, w, h, x, y)); 14310 fbPushPixels(gc, bitmap, drawable, w, h, x, y); 14311 FALLBACK_FLUSH(drawable); 14312out_gc: 14313 sna_gc_move_to_gpu(gc); 14314out: 14315 RegionUninit(®ion); 14316} 14317 14318static const GCOps sna_gc_ops = { 14319 sna_fill_spans, 14320 sna_set_spans, 14321 sna_put_image, 14322 sna_copy_area, 14323 sna_copy_plane, 14324 sna_poly_point, 14325 sna_poly_line, 14326 sna_poly_segment, 14327 sna_poly_rectangle, 14328 sna_poly_arc, 14329 sna_poly_fill_polygon, 14330 sna_poly_fill_rect, 14331 sna_poly_fill_arc, 14332 sna_poly_text8, 14333 sna_poly_text16, 14334 sna_image_text8, 14335 sna_image_text16, 14336 sna_image_glyph, 14337 sna_poly_glyph, 14338 sna_push_pixels, 14339}; 14340 14341static const GCOps sna_gc_ops__cpu = { 14342 fbFillSpans, 14343 fbSetSpans, 14344 fbPutImage, 14345 fbCopyArea, 14346 fbCopyPlane, 14347 sna_poly_point__cpu, 14348 fbPolyLine, 14349 fbPolySegment, 14350 miPolyRectangle, 14351 fbPolyArc, 14352 miFillPolygon, 14353 fbPolyFillRect, 14354 miPolyFillArc, 14355 miPolyText8, 14356 miPolyText16, 14357 miImageText8, 14358 miImageText16, 14359 fbImageGlyphBlt, 14360 fbPolyGlyphBlt, 14361 fbPushPixels 14362}; 14363 14364static GCOps sna_gc_ops__tmp = { 14365 sna_fill_spans, 14366 sna_set_spans, 14367 sna_put_image, 14368 sna_copy_area, 14369 sna_copy_plane, 14370 sna_poly_point, 14371 sna_poly_line, 14372 sna_poly_segment, 14373 sna_poly_rectangle, 14374 sna_poly_arc, 14375 sna_poly_fill_polygon, 14376 sna_poly_fill_rect, 14377 sna_poly_fill_arc, 14378 sna_poly_text8, 14379 sna_poly_text16, 14380 sna_image_text8, 14381 sna_image_text16, 14382 sna_image_glyph, 14383 sna_poly_glyph, 14384 sna_push_pixels, 14385}; 14386 14387static void 14388sna_validate_gc(GCPtr gc, unsigned long changes, DrawablePtr drawable) 14389{ 14390 DBG(("%s changes=%lx\n", __FUNCTION__, changes)); 14391 14392 if (changes & (GCClipMask|GCSubwindowMode) || 14393 drawable->serialNumber != (gc->serialNumber & DRAWABLE_SERIAL_BITS) || 14394 (gc->clientClipType != CT_NONE && (changes & (GCClipXOrigin | GCClipYOrigin)))) 14395 miComputeCompositeClip(gc, drawable); 14396 14397 sna_gc(gc)->changes |= changes; 14398} 14399 14400static const GCFuncs sna_gc_funcs = { 14401 sna_validate_gc, 14402 miChangeGC, 14403 miCopyGC, 14404 miDestroyGC, 14405 miChangeClip, 14406 miDestroyClip, 14407 miCopyClip 14408}; 14409 14410static const GCFuncs sna_gc_funcs__cpu = { 14411 fbValidateGC, 14412 miChangeGC, 14413 miCopyGC, 14414 miDestroyGC, 14415 miChangeClip, 14416 miDestroyClip, 14417 miCopyClip 14418}; 14419 14420static int sna_create_gc(GCPtr gc) 14421{ 14422 gc->miTranslate = 1; 14423 gc->fExpose = 1; 14424 14425 gc->freeCompClip = 0; 14426 gc->pCompositeClip = 0; 14427 gc->pRotatedPixmap = 0; 14428 14429 fb_gc(gc)->bpp = bits_per_pixel(gc->depth); 14430 14431 gc->funcs = (GCFuncs *)&sna_gc_funcs; 14432 gc->ops = (GCOps *)&sna_gc_ops; 14433 return true; 14434} 14435 14436static bool 14437sna_get_image_blt(PixmapPtr pixmap, 14438 RegionPtr region, 14439 char *dst, 14440 unsigned flags) 14441{ 14442 struct sna_pixmap *priv = sna_pixmap(pixmap); 14443 struct sna *sna = to_sna_from_pixmap(pixmap); 14444 struct kgem_bo *dst_bo; 14445 bool ok = false; 14446 int pitch; 14447 14448 if (priv == NULL) 14449 return false; 14450 14451 if (priv->clear) { 14452 int w = region->extents.x2 - region->extents.x1; 14453 int h = region->extents.y2 - region->extents.y1; 14454 14455 DBG(("%s: applying clear [%08x]\n", 14456 __FUNCTION__, priv->clear_color)); 14457 assert(DAMAGE_IS_ALL(priv->gpu_damage)); 14458 assert(priv->cpu_damage == NULL); 14459 14460 pitch = PixmapBytePad(w, pixmap->drawable.depth); 14461 if (priv->clear_color == 0 || 14462 pixmap->drawable.bitsPerPixel == 8 || 14463 priv->clear_color == (1U << pixmap->drawable.depth) - 1) { 14464 DBG(("%s: memset clear [%02x]\n", 14465 __FUNCTION__, priv->clear_color & 0xff)); 14466 memset(dst, priv->clear_color, pitch * h); 14467 } else { 14468 pixman_fill((uint32_t *)dst, 14469 pitch/sizeof(uint32_t), 14470 pixmap->drawable.bitsPerPixel, 14471 0, 0, 14472 w, h, 14473 priv->clear_color); 14474 } 14475 14476 return true; 14477 } 14478 14479 if (!sna->kgem.has_userptr || !USE_USERPTR_DOWNLOADS) 14480 return false; 14481 14482 if (!sna->kgem.can_blt_cpu) 14483 return false; 14484 14485 if (flags & (MOVE_WHOLE_HINT | MOVE_INPLACE_HINT)) 14486 return false; 14487 14488 if (priv->gpu_damage == NULL) 14489 return false; 14490 14491 assert(priv->gpu_bo); 14492 if (!__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)) 14493 return false; 14494 14495 if (!DAMAGE_IS_ALL(priv->gpu_damage) && 14496 !sna_damage_contains_box__no_reduce(priv->gpu_damage, 14497 ®ion->extents)) 14498 return false; 14499 14500 DBG(("%s: download through a temporary map\n", __FUNCTION__)); 14501 14502 assert(sna_damage_contains_box(priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 14503 assert(sna_damage_contains_box(priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 14504 14505 pitch = PixmapBytePad(region->extents.x2 - region->extents.x1, 14506 pixmap->drawable.depth); 14507 dst_bo = kgem_create_map(&sna->kgem, dst, 14508 pitch * (region->extents.y2 - region->extents.y1), 14509 false); 14510 if (dst_bo) { 14511 dst_bo->pitch = pitch; 14512 kgem_bo_mark_unreusable(dst_bo); 14513 14514 ok = sna->render.copy_boxes(sna, GXcopy, 14515 pixmap, priv->gpu_bo, 0, 0, 14516 pixmap, dst_bo, 14517 -region->extents.x1, 14518 -region->extents.y1, 14519 ®ion->extents, 1, 14520 COPY_LAST); 14521 14522 kgem_bo_sync__cpu(&sna->kgem, dst_bo); 14523 assert(dst_bo->rq == NULL); 14524 kgem_bo_destroy(&sna->kgem, dst_bo); 14525 } 14526 14527 return ok; 14528} 14529 14530static bool 14531sna_get_image_inplace(PixmapPtr pixmap, 14532 RegionPtr region, 14533 char *dst, 14534 unsigned flags) 14535{ 14536 struct sna_pixmap *priv = sna_pixmap(pixmap); 14537 struct sna *sna = to_sna_from_pixmap(pixmap); 14538 char *src; 14539 14540 if (!USE_INPLACE) 14541 return false; 14542 14543 if (priv == NULL || priv->gpu_bo == NULL) 14544 return false; 14545 14546 switch (priv->gpu_bo->tiling) { 14547 case I915_TILING_Y: 14548 return false; 14549 case I915_TILING_X: 14550 if (!sna->kgem.memcpy_from_tiled_x) 14551 return false; 14552 default: 14553 break; 14554 } 14555 14556 if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, false)) 14557 return false; 14558 14559 if (priv->gpu_damage == NULL || 14560 !(DAMAGE_IS_ALL(priv->gpu_damage) || 14561 sna_damage_contains_box__no_reduce(priv->gpu_damage, 14562 ®ion->extents))) 14563 return false; 14564 14565 assert(sna_damage_contains_box(priv->gpu_damage, ®ion->extents) == PIXMAN_REGION_IN); 14566 assert(sna_damage_contains_box(priv->cpu_damage, ®ion->extents) == PIXMAN_REGION_OUT); 14567 14568 src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo); 14569 if (src == NULL) 14570 return false; 14571 14572 kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC); 14573 14574 if (priv->gpu_bo->tiling) { 14575 DBG(("%s: download through a tiled CPU map\n", __FUNCTION__)); 14576 memcpy_from_tiled_x(&sna->kgem, src, dst, 14577 pixmap->drawable.bitsPerPixel, 14578 priv->gpu_bo->pitch, 14579 PixmapBytePad(region->extents.x2 - region->extents.x1, 14580 pixmap->drawable.depth), 14581 region->extents.x1, region->extents.y1, 14582 0, 0, 14583 region->extents.x2 - region->extents.x1, 14584 region->extents.y2 - region->extents.y1); 14585 } else { 14586 DBG(("%s: download through a linear CPU map\n", __FUNCTION__)); 14587 memcpy_blt(src, dst, 14588 pixmap->drawable.bitsPerPixel, 14589 priv->gpu_bo->pitch, 14590 PixmapBytePad(region->extents.x2 - region->extents.x1, 14591 pixmap->drawable.depth), 14592 region->extents.x1, region->extents.y1, 14593 0, 0, 14594 region->extents.x2 - region->extents.x1, 14595 region->extents.y2 - region->extents.y1); 14596 } 14597 14598 if (!priv->shm) { 14599 pixmap->devPrivate.ptr = src; 14600 pixmap->devKind = priv->gpu_bo->pitch; 14601 priv->mapped = true; 14602 priv->cpu = true; 14603 } 14604 14605 return true; 14606} 14607 14608static void 14609sna_get_image(DrawablePtr drawable, 14610 int x, int y, int w, int h, 14611 unsigned int format, unsigned long mask, 14612 char *dst) 14613{ 14614 RegionRec region; 14615 unsigned int flags; 14616 14617 if (!fbDrawableEnabled(drawable)) 14618 return; 14619 14620 DBG(("%s: pixmap=%ld (%d, %d)x(%d, %d), format=%d, mask=%lx, depth=%d\n", 14621 __FUNCTION__, 14622 (long)get_drawable_pixmap(drawable)->drawable.serialNumber, 14623 x, y, w, h, format, mask, drawable->depth)); 14624 14625 flags = MOVE_READ; 14626 if ((w | h) == 1) 14627 flags |= MOVE_INPLACE_HINT; 14628 if (w == drawable->width) 14629 flags |= MOVE_WHOLE_HINT; 14630 14631 if (ACCEL_GET_IMAGE && 14632 !FORCE_FALLBACK && 14633 format == ZPixmap && 14634 drawable->bitsPerPixel >= 8 && 14635 PM_IS_SOLID(drawable, mask)) { 14636 PixmapPtr pixmap = get_drawable_pixmap(drawable); 14637 int16_t dx, dy; 14638 14639 get_drawable_deltas(drawable, pixmap, &dx, &dy); 14640 region.extents.x1 = x + drawable->x + dx; 14641 region.extents.y1 = y + drawable->y + dy; 14642 region.extents.x2 = region.extents.x1 + w; 14643 region.extents.y2 = region.extents.y1 + h; 14644 region.data = NULL; 14645 14646 if (sna_get_image_blt(pixmap, ®ion, dst, flags)) 14647 return; 14648 14649 if (sna_get_image_inplace(pixmap, ®ion, dst, flags)) 14650 return; 14651 14652 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable, 14653 ®ion, flags)) 14654 return; 14655 14656 DBG(("%s: copy box (%d, %d), (%d, %d)\n", 14657 __FUNCTION__, 14658 region.extents.x1, region.extents.y1, 14659 region.extents.x2, region.extents.y2)); 14660 assert(has_coherent_ptr(sna_pixmap(pixmap))); 14661 memcpy_blt(pixmap->devPrivate.ptr, dst, drawable->bitsPerPixel, 14662 pixmap->devKind, PixmapBytePad(w, drawable->depth), 14663 region.extents.x1, region.extents.y1, 0, 0, w, h); 14664 } else { 14665 region.extents.x1 = x + drawable->x; 14666 region.extents.y1 = y + drawable->y; 14667 region.extents.x2 = region.extents.x1 + w; 14668 region.extents.y2 = region.extents.y1 + h; 14669 region.data = NULL; 14670 14671 if (sna_drawable_move_region_to_cpu(drawable, ®ion, flags)) 14672 fbGetImage(drawable, x, y, w, h, format, mask, dst); 14673 } 14674} 14675 14676static void 14677sna_get_spans(DrawablePtr drawable, int wMax, 14678 DDXPointPtr pt, int *width, int n, char *start) 14679{ 14680 RegionRec region; 14681 14682 if (!fbDrawableEnabled(drawable)) 14683 return; 14684 14685 if (sna_spans_extents(drawable, NULL, n, pt, width, ®ion.extents) == 0) 14686 return; 14687 14688 region.data = NULL; 14689 if (!sna_drawable_move_region_to_cpu(drawable, ®ion, MOVE_READ)) 14690 return; 14691 14692 fbGetSpans(drawable, wMax, pt, width, n, start); 14693} 14694 14695static void 14696sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src) 14697{ 14698 PixmapPtr pixmap = get_window_pixmap(win); 14699 struct sna *sna = to_sna_from_pixmap(pixmap); 14700 RegionRec dst; 14701 int dx, dy; 14702 14703 DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y)); 14704 if (!fbWindowEnabled(win)) 14705 return; 14706 14707 dx = origin.x - win->drawable.x; 14708 dy = origin.y - win->drawable.y; 14709 RegionTranslate(src, -dx, -dy); 14710 14711 RegionNull(&dst); 14712 RegionIntersect(&dst, &win->borderClip, src); 14713 if (RegionNil(&dst)) 14714 return; 14715 14716#ifdef COMPOSITE 14717 if (pixmap->screen_x | pixmap->screen_y) 14718 RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y); 14719#endif 14720 14721 if (wedged(sna) || FORCE_FALLBACK || !ACCEL_COPY_WINDOW) { 14722 DBG(("%s: fallback -- wedged\n", __FUNCTION__)); 14723 if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE)) 14724 return; 14725 14726 miCopyRegion(&pixmap->drawable, &pixmap->drawable, 14727 0, &dst, dx, dy, fbCopyNtoN, 0, NULL); 14728 } else { 14729 sna_self_copy_boxes(&pixmap->drawable, &pixmap->drawable, NULL, 14730 &dst, dx, dy, 0, NULL); 14731 } 14732 14733 RegionUninit(&dst); 14734} 14735 14736static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask) 14737{ 14738 bool ret = true; 14739 14740 DBG(("%s\n", __FUNCTION__)); 14741 14742 /* Check if the fb layer wishes to modify the attached pixmaps, 14743 * to fix up mismatches between the window and pixmap depths. 14744 */ 14745 if (mask & CWBackPixmap && win->backgroundState == BackgroundPixmap) { 14746 DBG(("%s: flushing background pixmap\n", __FUNCTION__)); 14747 ret &= sna_validate_pixmap(&win->drawable, win->background.pixmap); 14748 } 14749 14750 if (mask & CWBorderPixmap && win->borderIsPixel == false) { 14751 DBG(("%s: flushing border pixmap\n", __FUNCTION__)); 14752 ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap); 14753 } 14754 14755 return ret; 14756} 14757 14758static void 14759sna_accel_flush_callback(CallbackListPtr *list, 14760 pointer user_data, pointer call_data) 14761{ 14762 struct sna *sna = user_data; 14763 struct sna_pixmap *priv; 14764 14765 /* XXX we should be able to reduce the frequency of flushes further 14766 * by checking for outgoing damage events or sync replies. Tricky, 14767 * and doesn't appear to mitigate the performance loss. 14768 */ 14769 DBG(("%s: flush?=%d, dirty?=%d\n", __FUNCTION__, 14770 sna->kgem.flush, !list_is_empty(&sna->flush_pixmaps))); 14771 14772 /* flush any pending damage from shadow copies to tfp clients */ 14773 while (!list_is_empty(&sna->flush_pixmaps)) { 14774 bool ret; 14775 14776 priv = list_first_entry(&sna->flush_pixmaps, 14777 struct sna_pixmap, flush_list); 14778 14779 list_del(&priv->flush_list); 14780 if (priv->shm) { 14781 DBG(("%s: syncing SHM pixmap=%ld (refcnt=%d)\n", 14782 __FUNCTION__, 14783 priv->pixmap->drawable.serialNumber, 14784 priv->pixmap->refcnt)); 14785 assert(!priv->flush); 14786 ret = sna_pixmap_move_to_cpu(priv->pixmap, 14787 MOVE_READ | MOVE_WRITE); 14788 assert(!ret || priv->gpu_bo == NULL); 14789 if (priv->pixmap->refcnt == 0) { 14790 sna_damage_destroy(&priv->cpu_damage); 14791 __sna_free_pixmap(sna, priv->pixmap, priv); 14792 } 14793 } else { 14794 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__, 14795 priv->pixmap->drawable.serialNumber)); 14796 assert(priv->flush); 14797 if (sna_pixmap_move_to_gpu(priv->pixmap, 14798 MOVE_READ | __MOVE_FORCE)) 14799 kgem_bo_unclean(&sna->kgem, priv->gpu_bo); 14800 } 14801 (void)ret; 14802 } 14803 14804 if (sna->kgem.flush) 14805 kgem_submit(&sna->kgem); 14806} 14807 14808static struct sna_pixmap *sna_accel_scanout(struct sna *sna) 14809{ 14810 struct sna_pixmap *priv; 14811 14812 if (sna->vblank_interval == 0) 14813 return NULL; 14814 14815 if (sna->front == NULL) 14816 return NULL; 14817 14818 priv = sna_pixmap(sna->front); 14819 return priv && priv->gpu_bo ? priv : NULL; 14820} 14821 14822#define TIME currentTime.milliseconds 14823static void sna_accel_disarm_timer(struct sna *sna, int id) 14824{ 14825 DBG(("%s[%d] (time=%ld)\n", __FUNCTION__, id, (long)TIME)); 14826 sna->timer_active &= ~(1<<id); 14827} 14828 14829static bool has_offload_slaves(struct sna *sna) 14830{ 14831#if HAS_PIXMAP_SHARING 14832 ScreenPtr screen = sna->scrn->pScreen; 14833 PixmapDirtyUpdatePtr dirty; 14834 14835 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 14836 assert(dirty->src == sna->front); 14837 if (RegionNotEmpty(DamageRegion(dirty->damage))) 14838 return true; 14839 } 14840#endif 14841 return false; 14842} 14843 14844static bool has_shadow(struct sna *sna) 14845{ 14846 DamagePtr damage = sna->mode.shadow_damage; 14847 14848 if (!(damage && RegionNotEmpty(DamageRegion(damage)))) 14849 return false; 14850 14851 DBG(("%s: has pending damage\n", __FUNCTION__)); 14852 if ((sna->flags & SNA_TEAR_FREE) == 0) 14853 return true; 14854 14855 DBG(("%s: outstanding flips: %d\n", 14856 __FUNCTION__, sna->mode.shadow_flip)); 14857 return !sna->mode.shadow_flip; 14858} 14859 14860static bool start_flush(struct sna *sna, struct sna_pixmap *scanout) 14861{ 14862 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 14863 __FUNCTION__, 14864 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 14865 has_shadow(sna), has_offload_slaves(sna), 14866 scanout && scanout->cpu_damage != NULL, 14867 scanout && scanout->gpu_bo && scanout->gpu_bo->exec != NULL)); 14868 14869 if (has_offload_slaves(sna)) 14870 return true; 14871 14872 if (has_shadow(sna)) 14873 return true; 14874 14875 if (!scanout) 14876 return false; 14877 14878 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 14879 scanout->gpu_bo->needs_flush = true; 14880 return true; 14881 } 14882 14883 return scanout->cpu_damage || scanout->gpu_bo->exec; 14884} 14885 14886static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout) 14887{ 14888 DBG(("%s: scanout=%d shadow?=%d, slaves?=%d, (cpu?=%d || gpu?=%d))\n", 14889 __FUNCTION__, 14890 scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0, 14891 has_shadow(sna), has_offload_slaves(sna), 14892 scanout && scanout->cpu_damage != NULL, 14893 scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL)); 14894 14895 if (has_offload_slaves(sna)) 14896 return true; 14897 14898 if (has_shadow(sna)) 14899 return true; 14900 14901 if (!scanout) 14902 return false; 14903 14904 if (sna->flags & SNA_FLUSH_GTT && scanout->gpu_bo->gtt_dirty) { 14905 scanout->gpu_bo->needs_flush = true; 14906 return true; 14907 } 14908 14909 return scanout->cpu_damage || scanout->gpu_bo->needs_flush; 14910} 14911 14912static void timer_enable(struct sna *sna, int whom, int interval) 14913{ 14914 if (!sna->timer_active) 14915 UpdateCurrentTimeIf(); 14916 sna->timer_active |= 1 << whom; 14917 sna->timer_expire[whom] = TIME + interval; 14918 DBG(("%s (time=%ld), starting timer %d\n", __FUNCTION__, (long)TIME, whom)); 14919} 14920 14921static bool sna_accel_do_flush(struct sna *sna) 14922{ 14923 struct sna_pixmap *priv; 14924 int interval; 14925 14926 priv = sna_accel_scanout(sna); 14927 if (priv == NULL && !sna->mode.shadow_active && !has_offload_slaves(sna)) { 14928 DBG(("%s -- no scanout attached\n", __FUNCTION__)); 14929 sna_accel_disarm_timer(sna, FLUSH_TIMER); 14930 return false; 14931 } 14932 14933 interval = sna->vblank_interval ?: 20; 14934 if (sna->timer_active & (1<<(FLUSH_TIMER))) { 14935 int32_t delta = sna->timer_expire[FLUSH_TIMER] - TIME; 14936 DBG(("%s: flush timer active: delta=%d\n", 14937 __FUNCTION__, delta)); 14938 if (delta <= 3) { 14939 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 14940 sna->timer_expire[FLUSH_TIMER] = TIME + interval; 14941 return true; 14942 } 14943 } else if (!start_flush(sna, priv)) { 14944 DBG(("%s -- no pending write to scanout\n", __FUNCTION__)); 14945 if (priv) 14946 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 14947 } else 14948 timer_enable(sna, FLUSH_TIMER, interval/2); 14949 14950 return false; 14951} 14952 14953static bool sna_accel_do_throttle(struct sna *sna) 14954{ 14955 if (sna->timer_active & (1<<(THROTTLE_TIMER))) { 14956 int32_t delta = sna->timer_expire[THROTTLE_TIMER] - TIME; 14957 if (delta <= 3) { 14958 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 14959 sna->timer_expire[THROTTLE_TIMER] = TIME + 20; 14960 return true; 14961 } 14962 } else if (!sna->kgem.need_retire) { 14963 DBG(("%s -- no pending activity\n", __FUNCTION__)); 14964 } else 14965 timer_enable(sna, THROTTLE_TIMER, 20); 14966 14967 return false; 14968} 14969 14970static bool sna_accel_do_expire(struct sna *sna) 14971{ 14972 if (sna->timer_active & (1<<(EXPIRE_TIMER))) { 14973 int32_t delta = sna->timer_expire[EXPIRE_TIMER] - TIME; 14974 if (delta <= 3) { 14975 DBG(("%s (time=%ld), triggered\n", __FUNCTION__, (long)TIME)); 14976 sna->timer_expire[EXPIRE_TIMER] = 14977 TIME + MAX_INACTIVE_TIME * 1000; 14978 return true; 14979 } 14980 } else if (sna->kgem.need_expire) 14981 timer_enable(sna, EXPIRE_TIMER, MAX_INACTIVE_TIME * 1000); 14982 14983 return false; 14984} 14985 14986static void sna_accel_post_damage(struct sna *sna) 14987{ 14988#if HAS_PIXMAP_SHARING 14989 ScreenPtr screen = sna->scrn->pScreen; 14990 PixmapDirtyUpdatePtr dirty; 14991 bool flush = false; 14992 14993 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 14994 RegionRec region, *damage; 14995 PixmapPtr src, dst; 14996 BoxPtr box; 14997 int n; 14998 14999 assert(dirty->src == sna->front); 15000 15001 damage = DamageRegion(dirty->damage); 15002 if (RegionNil(damage)) 15003 continue; 15004 15005 src = dirty->src; 15006 dst = dirty->slave_dst->master_pixmap; 15007 15008 region.extents.x1 = dirty->x; 15009 region.extents.x2 = dirty->x + dst->drawable.width; 15010 region.extents.y1 = dirty->y; 15011 region.extents.y2 = dirty->y + dst->drawable.height; 15012 region.data = NULL; 15013 15014 DBG(("%s: pushing damage ((%d, %d), (%d, %d))x%d to slave pixmap=%ld, ((%d, %d), (%d, %d))\n", __FUNCTION__, 15015 damage->extents.x1, damage->extents.y1, 15016 damage->extents.x2, damage->extents.y2, 15017 RegionNumRects(damage), 15018 dst->drawable.serialNumber, 15019 region.extents.x1, region.extents.y1, 15020 region.extents.x2, region.extents.y2)); 15021 15022 RegionIntersect(®ion, ®ion, damage); 15023 if (RegionNil(®ion)) 15024 goto skip; 15025 15026 RegionTranslate(®ion, -dirty->x, -dirty->y); 15027 DamageRegionAppend(&dirty->slave_dst->drawable, ®ion); 15028 15029 DBG(("%s: slave: ((%d, %d), (%d, %d))x%d\n", __FUNCTION__, 15030 region.extents.x1, region.extents.y1, 15031 region.extents.x2, region.extents.y2, 15032 RegionNumRects(®ion))); 15033 15034 box = RegionRects(®ion); 15035 n = RegionNumRects(®ion); 15036 if (wedged(sna)) { 15037fallback: 15038 if (!sna_pixmap_move_to_cpu(src, MOVE_READ)) 15039 goto skip; 15040 15041 if (!sna_pixmap_move_to_cpu(dst, MOVE_READ | MOVE_WRITE | MOVE_INPLACE_HINT)) 15042 goto skip; 15043 15044 assert(src->drawable.bitsPerPixel == dst->drawable.bitsPerPixel); 15045 do { 15046 DBG(("%s: copy box (%d, %d)->(%d, %d)x(%d, %d)\n", 15047 __FUNCTION__, 15048 box->x1 + dirty->x, box->y1 + dirty->y, 15049 box->x1, box->y1, 15050 box->x2 - box->x1, box->y2 - box->y1)); 15051 15052 assert(box->x2 > box->x1); 15053 assert(box->y2 > box->y1); 15054 15055 assert(box->x1 + dirty->x >= 0); 15056 assert(box->y1 + dirty->y >= 0); 15057 assert(box->x2 + dirty->x <= src->drawable.width); 15058 assert(box->y2 + dirty->y <= src->drawable.height); 15059 15060 assert(box->x1 >= 0); 15061 assert(box->y1 >= 0); 15062 assert(box->x2 <= src->drawable.width); 15063 assert(box->y2 <= src->drawable.height); 15064 15065 assert(has_coherent_ptr(sna_pixmap(src))); 15066 assert(has_coherent_ptr(sna_pixmap(dst))); 15067 memcpy_blt(src->devPrivate.ptr, 15068 dst->devPrivate.ptr, 15069 src->drawable.bitsPerPixel, 15070 src->devKind, dst->devKind, 15071 box->x1 + dirty->x, 15072 box->y1 + dirty->y, 15073 box->x1, 15074 box->y1, 15075 box->x2 - box->x1, 15076 box->y2 - box->y1); 15077 box++; 15078 } while (--n); 15079 } else { 15080 if (!sna_pixmap_move_to_gpu(src, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE)) 15081 goto fallback; 15082 15083 if (!sna_pixmap_move_to_gpu(dst, MOVE_READ | MOVE_WRITE | MOVE_ASYNC_HINT | __MOVE_FORCE)) 15084 goto fallback; 15085 15086 if (!sna->render.copy_boxes(sna, GXcopy, 15087 src, __sna_pixmap_get_bo(src), dirty->x, dirty->y, 15088 dst, __sna_pixmap_get_bo(dst),0, 0, 15089 box, n, COPY_LAST)) 15090 goto fallback; 15091 15092 flush = true; 15093 } 15094 15095 DamageRegionProcessPending(&dirty->slave_dst->drawable); 15096skip: 15097 RegionUninit(®ion); 15098 DamageEmpty(dirty->damage); 15099 } 15100 if (flush) 15101 kgem_submit(&sna->kgem); 15102#endif 15103} 15104 15105static void sna_accel_flush(struct sna *sna) 15106{ 15107 struct sna_pixmap *priv = sna_accel_scanout(sna); 15108 bool busy; 15109 15110 DBG(("%s (time=%ld), cpu damage? %d, exec? %d nbatch=%d, busy? %d\n", 15111 __FUNCTION__, (long)TIME, 15112 priv && priv->cpu_damage, 15113 priv && priv->gpu_bo->exec != NULL, 15114 sna->kgem.nbatch, 15115 sna->kgem.busy)); 15116 15117 busy = stop_flush(sna, priv); 15118 if (!sna->kgem.busy && !busy) 15119 sna_accel_disarm_timer(sna, FLUSH_TIMER); 15120 sna->kgem.busy = busy; 15121 15122 if (priv) { 15123 sna_pixmap_force_to_gpu(priv->pixmap, 15124 MOVE_READ | MOVE_ASYNC_HINT); 15125 kgem_scanout_flush(&sna->kgem, priv->gpu_bo); 15126 assert(!priv->cpu); 15127 } 15128 15129 sna_mode_redisplay(sna); 15130 sna_accel_post_damage(sna); 15131} 15132 15133static void sna_accel_throttle(struct sna *sna) 15134{ 15135 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 15136 15137 if (sna->kgem.need_throttle) { 15138 kgem_submit(&sna->kgem); 15139 kgem_throttle(&sna->kgem); 15140 } 15141 15142 if (!sna->kgem.need_retire) 15143 sna_accel_disarm_timer(sna, THROTTLE_TIMER); 15144} 15145 15146static void sna_accel_expire(struct sna *sna) 15147{ 15148 DBG(("%s (time=%ld)\n", __FUNCTION__, (long)TIME)); 15149 15150 if (!kgem_expire_cache(&sna->kgem)) 15151 sna_accel_disarm_timer(sna, EXPIRE_TIMER); 15152} 15153 15154#ifdef DEBUG_MEMORY 15155static bool sna_accel_do_debug_memory(struct sna *sna) 15156{ 15157 int32_t delta = sna->timer_expire[DEBUG_MEMORY_TIMER] - TIME; 15158 15159 if (delta <= 3) { 15160 sna->timer_expire[DEBUG_MEMORY_TIMER] = TIME + 10 * 1000; 15161 return true; 15162 } else 15163 return false; 15164} 15165 15166static void sna_accel_debug_memory(struct sna *sna) 15167{ 15168 ErrorF("Allocated pixmaps: %d\n", 15169 sna->debug_memory.pixmap_allocs); 15170 ErrorF("Allocated bo: %d, %ld bytes\n", 15171 sna->kgem.debug_memory.bo_allocs, 15172 (long)sna->kgem.debug_memory.bo_bytes); 15173 ErrorF("Allocated CPU bo: %d, %ld bytes\n", 15174 sna->debug_memory.cpu_bo_allocs, 15175 (long)sna->debug_memory.cpu_bo_bytes); 15176} 15177 15178#else 15179#define sna_accel_do_debug_memory(x) 0 15180static void sna_accel_debug_memory(struct sna *sna) { } 15181#endif 15182 15183static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL }; 15184 15185static PixmapPtr 15186sna_get_window_pixmap(WindowPtr window) 15187{ 15188 return get_window_pixmap(window); 15189} 15190 15191static void 15192sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) 15193{ 15194 *(PixmapPtr *)__get_private(window, sna_window_key) = pixmap; 15195} 15196 15197struct sna_visit_set_pixmap_window { 15198 PixmapPtr old, new; 15199}; 15200 15201static int 15202sna_visit_set_window_pixmap(WindowPtr window, pointer data) 15203{ 15204 struct sna_visit_set_pixmap_window *visit = data; 15205 15206 if (fbGetWindowPixmap(window) == visit->old) { 15207 window->drawable.pScreen->SetWindowPixmap(window, visit->new); 15208 return WT_WALKCHILDREN; 15209 } 15210 15211 return WT_DONTWALKCHILDREN; 15212} 15213 15214static void 15215migrate_dirty_tracking(PixmapPtr old_front, PixmapPtr new_front) 15216{ 15217#if HAS_PIXMAP_SHARING 15218 ScreenPtr screen = old_front->drawable.pScreen; 15219 PixmapDirtyUpdatePtr dirty, safe; 15220 15221 xorg_list_for_each_entry_safe(dirty, safe, &screen->pixmap_dirty_list, ent) { 15222 assert(dirty->src == old_front); 15223 if (dirty->src != old_front) 15224 continue; 15225 15226 DamageUnregister(&dirty->src->drawable, dirty->damage); 15227 DamageDestroy(dirty->damage); 15228 15229 dirty->damage = DamageCreate(NULL, NULL, 15230 DamageReportNone, 15231 TRUE, screen, screen); 15232 if (!dirty->damage) { 15233 xorg_list_del(&dirty->ent); 15234 free(dirty); 15235 continue; 15236 } 15237 15238 DamageRegister(&new_front->drawable, dirty->damage); 15239 dirty->src = new_front; 15240 } 15241#endif 15242} 15243 15244static void 15245sna_set_screen_pixmap(PixmapPtr pixmap) 15246{ 15247 PixmapPtr old_front = pixmap->drawable.pScreen->devPrivate; 15248 WindowPtr root; 15249 15250 assert(pixmap == to_sna_from_pixmap(pixmap)->front); 15251 15252 if (old_front) 15253 migrate_dirty_tracking(old_front, pixmap); 15254 15255 root = get_root_window(pixmap->drawable.pScreen); 15256 if (root) { 15257 struct sna_visit_set_pixmap_window visit; 15258 15259 visit.old = old_front; 15260 visit.new = pixmap; 15261 TraverseTree(root, sna_visit_set_window_pixmap, &visit); 15262 assert(fbGetWindowPixmap(root) == pixmap); 15263 } 15264 15265 pixmap->drawable.pScreen->devPrivate = pixmap; 15266} 15267 15268static Bool 15269sna_create_window(WindowPtr win) 15270{ 15271 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate); 15272 return TRUE; 15273} 15274 15275static Bool 15276sna_map_window(WindowPtr win) 15277{ 15278 return TRUE; 15279} 15280 15281static Bool 15282sna_position_window(WindowPtr win, int x, int y) 15283{ 15284 return TRUE; 15285} 15286 15287static Bool 15288sna_unmap_window(WindowPtr win) 15289{ 15290 return TRUE; 15291} 15292 15293static Bool 15294sna_destroy_window(WindowPtr win) 15295{ 15296 sna_video_destroy_window(win); 15297 sna_dri_destroy_window(win); 15298 return TRUE; 15299} 15300 15301static void 15302sna_query_best_size(int class, 15303 unsigned short *width, unsigned short *height, 15304 ScreenPtr screen) 15305{ 15306 unsigned short w; 15307 15308 switch (class) { 15309 case CursorShape: 15310 if (*width > screen->width) 15311 *width = screen->width; 15312 if (*height > screen->height) 15313 *height = screen->height; 15314 break; 15315 15316 case TileShape: 15317 case StippleShape: 15318 w = *width; 15319 if ((w & (w - 1)) && w < FB_UNIT) { 15320 for (w = 1; w < *width; w <<= 1) 15321 ; 15322 *width = w; 15323 } 15324 break; 15325 } 15326} 15327 15328static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def) 15329{ 15330} 15331 15332static bool sna_picture_init(ScreenPtr screen) 15333{ 15334 PictureScreenPtr ps; 15335 15336 DBG(("%s\n", __FUNCTION__)); 15337 15338 if (!miPictureInit(screen, NULL, 0)) 15339 return false; 15340 15341 ps = GetPictureScreen(screen); 15342 assert(ps != NULL); 15343 assert(ps->CreatePicture != NULL); 15344 assert(ps->DestroyPicture != NULL); 15345 15346 ps->Composite = sna_composite; 15347 ps->CompositeRects = sna_composite_rectangles; 15348 ps->Glyphs = sna_glyphs; 15349 if (xf86IsEntityShared(xf86ScreenToScrn(screen)->entityList[0])) 15350 ps->Glyphs = sna_glyphs__shared; 15351 ps->UnrealizeGlyph = sna_glyph_unrealize; 15352 ps->AddTraps = sna_add_traps; 15353 ps->Trapezoids = sna_composite_trapezoids; 15354#if HAS_PIXMAN_TRIANGLES 15355 ps->Triangles = sna_composite_triangles; 15356#if PICTURE_SCREEN_VERSION >= 2 15357 ps->TriStrip = sna_composite_tristrip; 15358 ps->TriFan = sna_composite_trifan; 15359#endif 15360#endif 15361 15362 return true; 15363} 15364 15365static bool sna_option_accel_blt(struct sna *sna) 15366{ 15367 const char *s; 15368 15369 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD); 15370 if (s == NULL) 15371 return false; 15372 15373 return strcasecmp(s, "blt") == 0; 15374} 15375 15376bool sna_accel_init(ScreenPtr screen, struct sna *sna) 15377{ 15378 const char *backend; 15379 15380 DBG(("%s\n", __FUNCTION__)); 15381 15382 sna_font_key = AllocateFontPrivateIndex(); 15383 15384 list_init(&sna->flush_pixmaps); 15385 list_init(&sna->active_pixmaps); 15386 15387 AddGeneralSocket(sna->kgem.fd); 15388 15389#ifdef DEBUG_MEMORY 15390 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000; 15391#endif 15392 15393 screen->defColormap = FakeClientID(0); 15394 /* let CreateDefColormap do whatever it wants for pixels */ 15395 screen->blackPixel = screen->whitePixel = (Pixel) 0; 15396 screen->QueryBestSize = sna_query_best_size; 15397 assert(screen->GetImage == NULL); 15398 screen->GetImage = sna_get_image; 15399 assert(screen->GetSpans == NULL); 15400 screen->GetSpans = sna_get_spans; 15401 assert(screen->CreateWindow == NULL); 15402 screen->CreateWindow = sna_create_window; 15403 assert(screen->DestroyWindow == NULL); 15404 screen->DestroyWindow = sna_destroy_window; 15405 screen->PositionWindow = sna_position_window; 15406 screen->ChangeWindowAttributes = sna_change_window_attributes; 15407 screen->RealizeWindow = sna_map_window; 15408 screen->UnrealizeWindow = sna_unmap_window; 15409 screen->CopyWindow = sna_copy_window; 15410 assert(screen->CreatePixmap == NULL); 15411 screen->CreatePixmap = sna_create_pixmap; 15412 assert(screen->DestroyPixmap == NULL); 15413 screen->DestroyPixmap = sna_destroy_pixmap; 15414#ifdef CREATE_PIXMAP_USAGE_SHARED 15415 screen->SharePixmapBacking = sna_share_pixmap_backing; 15416 screen->SetSharedPixmapBacking = sna_set_shared_pixmap_backing; 15417#endif 15418 screen->RealizeFont = sna_realize_font; 15419 screen->UnrealizeFont = sna_unrealize_font; 15420 assert(screen->CreateGC == NULL); 15421 screen->CreateGC = sna_create_gc; 15422 screen->CreateColormap = miInitializeColormap; 15423 screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA; 15424 screen->InstallColormap = miInstallColormap; 15425 screen->UninstallColormap = miUninstallColormap; 15426 screen->ListInstalledColormaps = miListInstalledColormaps; 15427 screen->ResolveColor = miResolveColor; 15428 assert(screen->StoreColors == NULL); 15429 screen->StoreColors = sna_store_colors; 15430 screen->BitmapToRegion = fbBitmapToRegion; 15431 15432#if HAS_PIXMAP_SHARING 15433 screen->StartPixmapTracking = PixmapStartDirtyTracking; 15434 screen->StopPixmapTracking = PixmapStopDirtyTracking; 15435#endif 15436 15437 assert(screen->GetWindowPixmap == NULL); 15438 screen->GetWindowPixmap = sna_get_window_pixmap; 15439 assert(screen->SetWindowPixmap == NULL); 15440 screen->SetWindowPixmap = sna_set_window_pixmap; 15441 15442 screen->SetScreenPixmap = sna_set_screen_pixmap; 15443 15444 if (sna->kgem.has_userptr) 15445 ShmRegisterFuncs(screen, &shm_funcs); 15446 else 15447 ShmRegisterFbFuncs(screen); 15448 15449 if (!sna_picture_init(screen)) 15450 return false; 15451 15452 backend = no_render_init(sna); 15453 if (sna_option_accel_blt(sna) || sna->info->gen >= 0100) 15454 (void)backend; 15455 else if (sna->info->gen >= 070) 15456 backend = gen7_render_init(sna, backend); 15457 else if (sna->info->gen >= 060) 15458 backend = gen6_render_init(sna, backend); 15459 else if (sna->info->gen >= 050) 15460 backend = gen5_render_init(sna, backend); 15461 else if (sna->info->gen >= 040) 15462 backend = gen4_render_init(sna, backend); 15463 else if (sna->info->gen >= 030) 15464 backend = gen3_render_init(sna, backend); 15465 else if (sna->info->gen >= 020) 15466 backend = gen2_render_init(sna, backend); 15467 15468 DBG(("%s(backend=%s, prefer_gpu=%x)\n", 15469 __FUNCTION__, backend, sna->render.prefer_gpu)); 15470 15471 kgem_reset(&sna->kgem); 15472 15473 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 15474 "SNA initialized with %s backend\n", 15475 backend); 15476 15477 return true; 15478} 15479 15480void sna_accel_create(struct sna *sna) 15481{ 15482 DBG(("%s\n", __FUNCTION__)); 15483 15484 if (!sna_glyphs_create(sna)) 15485 goto fail; 15486 15487 if (!sna_gradients_create(sna)) 15488 goto fail; 15489 15490 if (!sna_composite_create(sna)) 15491 goto fail; 15492 15493 return; 15494 15495fail: 15496 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 15497 "Failed to allocate caches, disabling RENDER acceleration\n"); 15498 no_render_init(sna); 15499} 15500 15501void sna_accel_watch_flush(struct sna *sna, int enable) 15502{ 15503 DBG(("%s: enable=%d\n", __FUNCTION__, enable)); 15504 assert(enable); 15505 15506 if (sna->watch_flush == 0) { 15507 DBG(("%s: installing watchers\n", __FUNCTION__)); 15508 assert(enable > 0); 15509 if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) { 15510 xf86DrvMsg(sna->scrn->scrnIndex, X_Error, 15511 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n"); 15512 } 15513 sna->watch_flush++; 15514 } 15515 15516 sna->watch_flush += enable; 15517} 15518 15519void sna_accel_close(struct sna *sna) 15520{ 15521 DBG(("%s\n", __FUNCTION__)); 15522 15523 sna_composite_close(sna); 15524 sna_gradients_close(sna); 15525 sna_glyphs_close(sna); 15526 15527 while (sna->freed_pixmap) { 15528 PixmapPtr pixmap = sna->freed_pixmap; 15529 sna->freed_pixmap = pixmap->devPrivate.ptr; 15530 assert(pixmap->refcnt == 0); 15531 free(sna_pixmap(pixmap)); 15532 FreePixmap(pixmap); 15533 } 15534 15535 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 15536 RemoveGeneralSocket(sna->kgem.fd); 15537 15538 kgem_cleanup_cache(&sna->kgem); 15539} 15540 15541void sna_accel_block_handler(struct sna *sna, struct timeval **tv) 15542{ 15543 if (sna->kgem.need_retire) 15544 kgem_retire(&sna->kgem); 15545 15546 if (sna->timer_active) 15547 UpdateCurrentTimeIf(); 15548 15549 if (sna->kgem.nbatch && 15550 (sna->kgem.scanout_busy || 15551 kgem_ring_is_idle(&sna->kgem, sna->kgem.ring))) { 15552 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 15553 _kgem_submit(&sna->kgem); 15554 } 15555 15556 if (sna_accel_do_flush(sna)) 15557 sna_accel_flush(sna); 15558 assert(sna_accel_scanout(sna) == NULL || 15559 sna_accel_scanout(sna)->gpu_bo->exec == NULL || 15560 sna->timer_active & (1<<(FLUSH_TIMER))); 15561 15562 if (sna_accel_do_throttle(sna)) 15563 sna_accel_throttle(sna); 15564 assert(!sna->kgem.need_retire || 15565 sna->timer_active & (1<<(THROTTLE_TIMER))); 15566 15567 if (sna_accel_do_expire(sna)) 15568 sna_accel_expire(sna); 15569 assert(!sna->kgem.need_expire || 15570 sna->timer_active & (1<<(EXPIRE_TIMER))); 15571 15572 if (sna_accel_do_debug_memory(sna)) 15573 sna_accel_debug_memory(sna); 15574 15575 if (sna->watch_flush == 1) { 15576 DBG(("%s: removing watchers\n", __FUNCTION__)); 15577 DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna); 15578 sna->watch_flush = 0; 15579 } 15580 15581 if (sna->timer_active & 1) { 15582 int32_t timeout; 15583 15584 DBG(("%s: evaluating timers, active=%x\n", 15585 __FUNCTION__, sna->timer_active)); 15586 15587 timeout = sna->timer_expire[0] - TIME; 15588 DBG(("%s: flush timer expires in %d [%d]\n", 15589 __FUNCTION__, timeout, sna->timer_expire[0])); 15590 15591 if (*tv == NULL) { 15592 *tv = &sna->timer_tv; 15593 goto set_tv; 15594 } 15595 if ((*tv)->tv_sec * 1000 + (*tv)->tv_usec / 1000 > timeout) { 15596set_tv: 15597 (*tv)->tv_sec = timeout / 1000; 15598 (*tv)->tv_usec = timeout % 1000 * 1000; 15599 } 15600 } 15601 15602 sna->kgem.scanout_busy = false; 15603 15604 if (FAULT_INJECTION && (rand() % FAULT_INJECTION) == 0) { 15605 ErrorF("%s hardware acceleration\n", 15606 sna->kgem.wedged ? "Re-enabling" : "Disabling"); 15607 kgem_submit(&sna->kgem); 15608 sna->kgem.wedged = !sna->kgem.wedged; 15609 } 15610} 15611 15612void sna_accel_wakeup_handler(struct sna *sna) 15613{ 15614 DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__, 15615 sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge)); 15616 15617 if (!sna->kgem.nbatch) 15618 return; 15619 15620 if (kgem_is_idle(&sna->kgem)) { 15621 DBG(("%s: GPU idle, flushing\n", __FUNCTION__)); 15622 _kgem_submit(&sna->kgem); 15623 } 15624} 15625 15626void sna_accel_free(struct sna *sna) 15627{ 15628 DBG(("%s\n", __FUNCTION__)); 15629} 15630