vmwgfx_saa.c revision 591e32d7
1/* 2 * Copyright 2011 VMWare, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Author: Thomas Hellstrom <thellstrom@vmware.com> 26 */ 27 28#include <xorg-server.h> 29#include <xorgVersion.h> 30#include <mi.h> 31#include <fb.h> 32#include <xf86drmMode.h> 33#include <xa_context.h> 34#include "vmwgfx_saa.h" 35#include "vmwgfx_drmi.h" 36#include "vmwgfx_saa_priv.h" 37 38/* 39 * Damage to be added as soon as we attach storage to the pixmap. 40 */ 41static Bool 42vmwgfx_pixmap_add_damage(PixmapPtr pixmap) 43{ 44 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 45 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 46 DrawablePtr draw = &pixmap->drawable; 47 BoxRec box; 48 49 if (spix->damage) 50 return TRUE; 51 52 if (!saa_add_damage(pixmap)) 53 return FALSE; 54 55 box.x1 = 0; 56 box.x2 = draw->width; 57 box.y1 = 0; 58 box.y2 = draw->height; 59 60 if (vpix->hw) { 61 REGION_RESET(draw->pScreen, &spix->dirty_hw, &box); 62 REGION_EMPTY(draw->pScreen, &spix->dirty_shadow); 63 } else { 64 REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box); 65 REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 66 } 67 68 return TRUE; 69} 70 71static void 72vmwgfx_pixmap_remove_damage(PixmapPtr pixmap) 73{ 74 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 75 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 76 77 if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc) 78 return; 79 80#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 81 DamageUnregister(spix->damage); 82#else 83 DamageUnregister(&pixmap->drawable, spix->damage); 84#endif 85 86 DamageDestroy(spix->damage); 87 spix->damage = NULL; 88} 89 90static void 91vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix) 92{ 93 if (vpix->dirty_present) 94 REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present); 95 if (vpix->present_damage) 96 REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage); 97 if (vpix->pending_update) 98 REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update); 99 if (vpix->pending_present) 100 REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present); 101 vpix->dirty_present = NULL; 102 vpix->present_damage = NULL; 103 vpix->pending_update = NULL; 104 vpix->pending_present = NULL; 105} 106 107static Bool 108vmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt) 109{ 110 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 111 ScreenPtr pScreen = pixmap->drawable.pScreen; 112 (void) pScreen; 113 114 if (present_opt) { 115 vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0); 116 if (!vpix->dirty_present) 117 return FALSE; 118 vpix->present_damage = REGION_CREATE(pScreen, NULL, 0); 119 if (!vpix->present_damage) 120 goto out_no_present_damage; 121 } 122 vpix->pending_update = REGION_CREATE(pScreen, NULL, 0); 123 if (!vpix->pending_update) 124 goto out_no_pending_update; 125 vpix->pending_present = REGION_CREATE(pScreen, NULL, 0); 126 if (!vpix->pending_present) 127 goto out_no_pending_present; 128 129 return TRUE; 130 out_no_pending_present: 131 REGION_DESTROY(pScreen, vpix->pending_update); 132 out_no_pending_update: 133 if (vpix->present_damage) 134 REGION_DESTROY(pScreen, vpix->present_damage); 135 out_no_present_damage: 136 if (vpix->dirty_present) 137 REGION_DESTROY(pScreen, vpix->dirty_present); 138 return FALSE; 139} 140 141static void 142vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix) 143{ 144 if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) { 145 free(vpix->malloc); 146 vpix->malloc = NULL; 147 } 148 if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) { 149 xa_surface_destroy(vpix->hw); 150 vpix->hw = NULL; 151 } 152 if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) { 153 vmwgfx_dmabuf_destroy(vpix->gmr); 154 vpix->gmr = NULL; 155 } 156} 157 158static Bool 159vmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 160{ 161 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 162 size_t size; 163 struct vmwgfx_dmabuf *gmr; 164 void *addr; 165 166 if (vpix->gmr) 167 return TRUE; 168 169 size = pixmap->devKind * pixmap->drawable.height; 170 gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 171 if (!gmr) 172 return FALSE; 173 174 if (vpix->malloc) { 175 176 addr = vmwgfx_dmabuf_map(gmr); 177 if (!addr) 178 goto out_no_transfer; 179 memcpy(addr, vpix->malloc, size); 180 vmwgfx_dmabuf_unmap(gmr); 181 182 } else if (!vmwgfx_pixmap_add_damage(pixmap)) 183 goto out_no_transfer; 184 185 vpix->backing |= VMWGFX_PIX_GMR; 186 vpix->backing &= ~VMWGFX_PIX_MALLOC; 187 vpix->gmr = gmr; 188 189 vmwgfx_pixmap_free_storage(vpix); 190 191 return TRUE; 192 193 out_no_transfer: 194 vmwgfx_dmabuf_destroy(gmr); 195 return FALSE; 196} 197 198static Bool 199vmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 200{ 201 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 202 203 if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR))) 204 return FALSE; 205 206 if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) { 207 vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height); 208 if (!vpix->malloc) 209 goto out_no_malloc; 210 if (!vmwgfx_pixmap_add_damage(pixmap)) 211 goto out_no_damage; 212 } else if (vpix->backing & VMWGFX_PIX_GMR) 213 return vmwgfx_pixmap_create_gmr(vsaa, pixmap); 214 215 return TRUE; 216 217 out_no_damage: 218 free(vpix->malloc); 219 vpix->malloc = NULL; 220 out_no_malloc: 221 return FALSE; 222} 223 224 225/** 226 * 227 * Makes sure all presented contents covered by @region are read 228 * back and are present in a valid GMR. 229 */ 230 231static Bool 232vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa, 233 PixmapPtr pixmap, 234 RegionPtr region) 235{ 236 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 237 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 238 RegionRec intersection; 239 240 if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) || 241 !vpix->dirty_present) 242 return TRUE; 243 244 /* 245 * Intersect dirty region with region to be read back, if any. 246 */ 247 248 REGION_NULL(vsaa->pScreen, &intersection); 249 REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw); 250 REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, 251 vpix->dirty_present); 252 253 if (region) 254 REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region); 255 256 if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection)) 257 goto out; 258 259 /* 260 * Make really sure there is a GMR to read back to. 261 */ 262 263 if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 264 goto out_err; 265 266 if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id, 267 &intersection) != 0) 268 goto out_err; 269 270 REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, 271 &spix->dirty_hw, &intersection); 272 out: 273 REGION_UNINIT(vsaa->pScreen, &intersection); 274 return TRUE; 275 276 out_err: 277 REGION_UNINIT(vsaa->pScreen, &intersection); 278 return FALSE; 279} 280 281static Bool 282vmwgfx_saa_dma(struct vmwgfx_saa *vsaa, 283 PixmapPtr pixmap, 284 RegionPtr reg, 285 Bool to_hw, 286 int dx, 287 int dy, 288 struct xa_surface *srf) 289{ 290 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 291 292 if (!srf) 293 srf = vpix->hw; 294 295 if (!srf || (!vpix->gmr && !vpix->malloc)) 296 return TRUE; 297 298 if (vpix->gmr && vsaa->can_optimize_dma) { 299 uint32_t handle, dummy; 300 301 if (_xa_surface_handle(srf, &handle, &dummy) != 0) 302 goto out_err; 303 if (vmwgfx_dma(dx, dy, reg, vpix->gmr, pixmap->devKind, handle, 304 to_hw) != 0) 305 goto out_err; 306 } else { 307 uint8_t *data = (uint8_t *) vpix->malloc; 308 int ret; 309 310 if (vpix->gmr) { 311 data = (uint8_t *) vmwgfx_dmabuf_map(vpix->gmr); 312 if (!data) 313 goto out_err; 314 } 315 316 if (dx || dy) { 317 REGION_TRANSLATE(pScreen, reg, dx, dy); 318 data -= ((dx * pixmap->drawable.bitsPerPixel + 7)/8 + 319 dy * pixmap->devKind); 320 } 321 322 ret = xa_surface_dma(vsaa->xa_ctx, srf, data, pixmap->devKind, 323 (int) to_hw, 324 (struct xa_box *) REGION_RECTS(reg), 325 REGION_NUM_RECTS(reg)); 326 if (to_hw) 327 xa_context_flush(vsaa->xa_ctx); 328 if (vpix->gmr) 329 vmwgfx_dmabuf_unmap(vpix->gmr); 330 if (dx || dy) 331 REGION_TRANSLATE(pScreen, reg, -dx, -dy); 332 if (ret) 333 goto out_err; 334 } 335 return TRUE; 336 out_err: 337 LogMessage(X_ERROR, "DMA %s surface failed.\n", 338 to_hw ? "to" : "from"); 339 return FALSE; 340} 341 342 343static Bool 344vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap, 345 RegionPtr readback) 346{ 347 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 348 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 349 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 350 351 RegionRec intersection; 352 353 if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback)) 354 return FALSE; 355 356 if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw)) 357 return TRUE; 358 359 if (!vpix->hw) 360 return TRUE; 361 362 REGION_NULL(vsaa->pScreen, &intersection); 363 REGION_INTERSECT(vsaa->pScreen, &intersection, readback, 364 &spix->dirty_hw); 365 readback = &intersection; 366 367 if (!vmwgfx_pixmap_create_sw(vsaa, pixmap)) 368 goto out_err; 369 370 if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE, 0, 0, NULL)) 371 goto out_err; 372 REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback); 373 REGION_UNINIT(vsaa->pScreen, &intersection); 374 return TRUE; 375 out_err: 376 REGION_UNINIT(vsaa->pScreen, &intersection); 377 return FALSE; 378} 379 380 381static Bool 382vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap, 383 RegionPtr upload) 384{ 385 return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE, 386 0, 0, NULL); 387} 388 389static void 390vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 391{ 392 // LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n", 393 // (unsigned long) pixmap, (unsigned) access); 394} 395 396static void * 397vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 398{ 399 /* 400 * Errors in this functions will turn up in subsequent map 401 * calls. 402 */ 403 404 (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap); 405 406 return NULL; 407} 408 409static void * 410vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 411{ 412 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 413 414 if (vpix->malloc) 415 return vpix->malloc; 416 else if (vpix->gmr) 417 return vmwgfx_dmabuf_map(vpix->gmr); 418 else 419 return NULL; 420} 421 422static void 423vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 424{ 425 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 426 427 if (vpix->gmr) 428 return vmwgfx_dmabuf_unmap(vpix->gmr); 429 430// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n", 431 // (unsigned long) pixmap, (unsigned) access); 432 ; 433} 434 435static Bool 436vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix, 437 int w, int h, int depth, 438 unsigned int usage_hint, int bpp, int *new_pitch) 439{ 440 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 441 442 *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 443 444 WSBMINITLISTHEAD(&vpix->sync_x_head); 445 WSBMINITLISTHEAD(&vpix->scanout_list); 446 WSBMINITLISTHEAD(&vpix->pixmap_list); 447 448 return TRUE; 449} 450 451Bool 452vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, 453 struct saa_pixmap *spix) 454{ 455 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 456 457 if (!vpix->hw) 458 return TRUE; 459 460 /* 461 * Read back any dirty regions from hardware. 462 */ 463 464 if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 465 &spix->dirty_hw)) 466 return FALSE; 467 468 xa_surface_destroy(vpix->hw); 469 vpix->hw = NULL; 470 471 /* 472 * Remove damage tracking if this is not a scanout pixmap. 473 */ 474 475 if (WSBMLISTEMPTY(&vpix->scanout_list)) 476 vmwgfx_pixmap_remove_damage(spix->pixmap); 477 478 return TRUE; 479} 480 481void 482vmwgfx_flush_dri2(ScreenPtr pScreen) 483{ 484 struct vmwgfx_saa *vsaa = 485 to_vmwgfx_saa(saa_get_driver(pScreen)); 486 struct _WsbmListHead *list, *next; 487 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 488 489 if (!pScrn->vtSema) 490 return; 491 492 WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { 493 struct vmwgfx_saa_pixmap *vpix = 494 WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); 495 struct saa_pixmap *spix = &vpix->base; 496 PixmapPtr pixmap = spix->pixmap; 497 498 if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { 499 REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 500 WSBMLISTDELINIT(list); 501 } 502 } 503} 504 505 506static void 507vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap) 508{ 509 ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen; 510 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 511 (void) pScreen; 512 513 vpix->backing = 0; 514 vmwgfx_pixmap_free_storage(vpix); 515 516 /* 517 * Any damage we've registered has already been removed by the server 518 * at this point. Any attempt to unregister / destroy it will result 519 * in a double free. 520 */ 521 522 vmwgfx_pixmap_remove_present(vpix); 523 WSBMLISTDELINIT(&vpix->pixmap_list); 524 WSBMLISTDELINIT(&vpix->sync_x_head); 525 526 if (vpix->hw_is_dri2_fronts) 527 LogMessage(X_ERROR, "Incorrect dri2 front count.\n"); 528} 529 530 531 532/** 533 * 534 * Makes sure we have a surface with valid contents. 535 */ 536 537static void 538vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch, 539 unsigned int src_pitch, unsigned int dst_height, 540 unsigned int src_height) 541{ 542 unsigned int i; 543 unsigned int height = (dst_height < src_height) ? dst_height : src_height; 544 unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch; 545 546 for(i=0; i<height; ++i) { 547 memcpy(dst, src, pitch); 548 dst += dst_pitch; 549 src += src_pitch; 550 } 551} 552 553 554static Bool 555vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch, 556 unsigned int old_height, unsigned int old_width) 557{ 558 ScreenPtr pScreen = pixmap->drawable.pScreen; 559 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 560 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 561 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 562 DrawablePtr draw = &pixmap->drawable; 563 unsigned int size = pixmap->devKind * draw->height; 564 BoxRec b_box; 565 RegionRec b_reg; 566 567 /* 568 * Ignore copying errors. At worst they will show up as rendering 569 * artefacts. 570 */ 571 572 if (vpix->malloc) { 573 574 void *new_malloc = malloc(size); 575 if (!new_malloc) 576 return FALSE; 577 578 vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind, 579 old_pitch, draw->height, 580 old_height); 581 free(vpix->malloc); 582 vpix->malloc = new_malloc; 583 } 584 585 if (vpix->gmr) { 586 struct vmwgfx_dmabuf *gmr; 587 void *new_addr; 588 void *old_addr; 589 590 gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 591 if (!gmr) 592 return FALSE; 593 594 new_addr = vmwgfx_dmabuf_map(gmr); 595 old_addr = vmwgfx_dmabuf_map(vpix->gmr); 596 597 if (new_addr && old_addr) 598 vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind, 599 old_pitch, draw->height, 600 old_height); 601 else 602 LogMessage(X_ERROR, "Failed pixmap resize copy.\n"); 603 604 if (old_addr) 605 vmwgfx_dmabuf_unmap(vpix->gmr); 606 if (new_addr) 607 vmwgfx_dmabuf_unmap(gmr); 608 vmwgfx_dmabuf_destroy(vpix->gmr); 609 vpix->gmr = gmr; 610 } 611 612 if (vpix->hw) { 613 if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width, 614 draw->height, draw->depth, xa_type_argb, 615 xa_format_unknown, vpix->xa_flags, 1)) 616 return FALSE; 617 } 618 619 b_box.x1 = 0; 620 b_box.x2 = draw->width; 621 b_box.y1 = 0; 622 b_box.y2 = draw->height; 623 624 REGION_INIT(pScreen, &b_reg, &b_box, 1); 625 REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, 626 &b_reg); 627 REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); 628 if (vpix->dirty_present) 629 REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, 630 &b_reg); 631 if (vpix->pending_update) 632 REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, 633 &b_reg); 634 if (vpix->pending_present) 635 REGION_INTERSECT(pScreen, vpix->pending_present, 636 vpix->pending_present, &b_reg); 637 if (vpix->present_damage) 638 REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, 639 &b_reg); 640 641 REGION_UNINIT(pScreen, &b_reg); 642 643 return TRUE; 644} 645 646 647static Bool 648vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth, 649 int bpp, int devkind, void *pixdata) 650{ 651 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 652 ScreenPtr pScreen = pixmap->drawable.pScreen; 653 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 654 unsigned int old_height; 655 unsigned int old_width; 656 unsigned int old_pitch; 657 658 if (!vpix) { 659 LogMessage(X_ERROR, "Not an SAA pixmap.\n"); 660 return FALSE; 661 } 662 663 if (pixdata) { 664 vpix->backing = 0; 665 vmwgfx_pixmap_free_storage(vpix); 666 return FALSE; 667 } 668 669 if (depth <= 0) 670 depth = pixmap->drawable.depth; 671 672 if (bpp <= 0) 673 bpp = pixmap->drawable.bitsPerPixel; 674 675 if (w <= 0) 676 w = pixmap->drawable.width; 677 678 if (h <= 0) 679 h = pixmap->drawable.height; 680 681 if (w <= 0 || h <= 0 || depth <= 0) 682 return FALSE; 683 684 old_height = pixmap->drawable.height; 685 old_width = pixmap->drawable.width; 686 old_pitch = pixmap->devKind; 687 688 if (!miModifyPixmapHeader(pixmap, w, h, depth, 689 bpp, devkind, NULL)) 690 goto out_no_modify; 691 692 if (!vpix->backing) 693 vpix->backing = VMWGFX_PIX_MALLOC; 694 695 vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width); 696 vmwgfx_pixmap_free_storage(vpix); 697 if (WSBMLISTEMPTY(&vpix->pixmap_list)) 698 WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps); 699 700 return TRUE; 701 702 out_no_modify: 703 return FALSE; 704} 705 706static Bool 707vmwgfx_present_prepare(struct vmwgfx_saa *vsaa, 708 struct vmwgfx_saa_pixmap *src_vpix, 709 struct vmwgfx_saa_pixmap *dst_vpix) 710{ 711 ScreenPtr pScreen = vsaa->pScreen; 712 unsigned int dummy; 713 714 (void) pScreen; 715 if (src_vpix == dst_vpix || !src_vpix->hw || 716 _xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0) 717 return FALSE; 718 719 REGION_NULL(pScreen, &vsaa->present_region); 720 vsaa->diff_valid = FALSE; 721 vsaa->dst_vpix = dst_vpix; 722 vsaa->present_flush(pScreen); 723 724 return TRUE; 725} 726 727/** 728 * Determine whether we should try present copies on this pixmap. 729 */ 730 731static Bool 732vmwgfx_is_present_hw(PixmapPtr pixmap) 733{ 734 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 735 return (vpix->dirty_present != NULL); 736} 737 738static void 739vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa, 740 struct vmwgfx_saa_pixmap *vpix, 741 RegionPtr region, 742 Bool *has_dirty_hw, 743 Bool *has_valid_hw) 744{ 745 RegionRec intersection; 746 747 748 if (!vpix->hw) { 749 *has_dirty_hw = FALSE; 750 *has_valid_hw = FALSE; 751 return; 752 } 753 754 if (!region) { 755 *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, 756 &vpix->base.dirty_hw); 757 *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, 758 &vpix->base.dirty_shadow); 759 return; 760 } 761 762 REGION_NULL(vsaa->pScreen, &intersection); 763 REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw, 764 region); 765 *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection); 766 REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow, 767 region); 768 *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection); 769 REGION_UNINIT(vsaa->pScreen, &intersection); 770} 771 772/** 773 * vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software 774 * rendered storage 775 * 776 * @vsaa: Pointer to a struct vmwgfx_saa accelerator. 777 * @pixmap: Pointer to pixmap whose storage preference we want to alter. 778 * 779 * If possible, alter the storage or future storage of the software contents 780 * of this pixmap to be in a DMA buffer rather than in malloced memory. 781 * This function should be called when it's likely that frequent DMA operations 782 * will occur between a surface and the memory holding the software 783 * contents. 784 */ 785static void 786vmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 787{ 788 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 789 790 if (vsaa->can_optimize_dma) { 791 if (vpix->malloc) { 792 (void) vmwgfx_pixmap_create_gmr(vsaa, pixmap); 793 } else if (vpix->backing & VMWGFX_PIX_MALLOC) { 794 vpix->backing |= VMWGFX_PIX_GMR; 795 vpix->backing &= ~VMWGFX_PIX_MALLOC; 796 } 797 } 798} 799 800Bool 801vmwgfx_create_hw(struct vmwgfx_saa *vsaa, 802 PixmapPtr pixmap) 803{ 804 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 805 struct xa_surface *hw; 806 uint32_t new_flags; 807 808 if (!vsaa->xat) 809 return FALSE; 810 811 if (vpix->hw) 812 return TRUE; 813 814 new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | 815 vpix->staging_add_flags | XA_FLAG_SHARED; 816 817 hw = xa_surface_create(vsaa->xat, 818 pixmap->drawable.width, 819 pixmap->drawable.height, 820 0, 821 xa_type_other, 822 vpix->staging_format, 823 new_flags); 824 if (hw == NULL) 825 return FALSE; 826 827 vpix->xa_flags = new_flags; 828 vpix->hw = hw; 829 830 if (!vmwgfx_pixmap_add_damage(pixmap)) 831 goto out_no_damage; 832 833 vpix->backing |= VMWGFX_PIX_SURFACE; 834 vmwgfx_pixmap_free_storage(vpix); 835 836 /* 837 * If there is a HW surface, make sure that the shadow is 838 * (or will be) a GMR, provided we can do fast DMAs from / to it. 839 */ 840 vmwgfx_prefer_gmr(vsaa, pixmap); 841 842 return TRUE; 843 844out_no_damage: 845 vpix->hw = NULL; 846 xa_surface_destroy(hw); 847 return FALSE; 848} 849 850 851Bool 852vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) 853{ 854 struct vmwgfx_saa *vsaa = 855 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 856 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 857 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 858 RegionRec intersection; 859 860 if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region)) 861 return FALSE; 862 863 REGION_NULL(vsaa->pScreen, &intersection); 864 REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow); 865 866 if (vpix->dirty_present) 867 REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present, 868 &spix->dirty_shadow); 869 870 if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) { 871 RegionPtr upload = &intersection; 872 873 /* 874 * Check whether we need to upload from GMR. 875 */ 876 877 if (region) { 878 REGION_INTERSECT(vsaa->pScreen, &intersection, region, 879 &intersection); 880 upload = &intersection; 881 } 882 883 if (REGION_NOTEMPTY(vsaa->pScreen, upload)) { 884 Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload); 885 if (ret) { 886 REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow, 887 &spix->dirty_shadow, upload); 888 if (vpix->dirty_present) 889 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 890 vpix->dirty_present, upload); 891 } else { 892 REGION_UNINIT(vsaa->pScreen, &intersection); 893 return FALSE; 894 } 895 } 896 } 897 REGION_UNINIT(vsaa->pScreen, &intersection); 898 return TRUE; 899} 900 901static Bool 902vmwgfx_copy_prepare(struct saa_driver *driver, 903 PixmapPtr src_pixmap, 904 PixmapPtr dst_pixmap, 905 int dx, 906 int dy, 907 int alu, 908 RegionPtr src_reg, 909 uint32_t plane_mask) 910{ 911 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 912 struct vmwgfx_saa_pixmap *src_vpix; 913 struct vmwgfx_saa_pixmap *dst_vpix; 914 Bool has_dirty_hw; 915 Bool has_valid_hw; 916 917 if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) || 918 alu != GXcopy || !vsaa->is_master) 919 return FALSE; 920 921 src_vpix = vmwgfx_saa_pixmap(src_pixmap); 922 dst_vpix = vmwgfx_saa_pixmap(dst_pixmap); 923 924 vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg, 925 &has_dirty_hw, &has_valid_hw); 926 927 if (vmwgfx_is_present_hw(dst_pixmap) && 928 src_vpix->backing & VMWGFX_PIX_SURFACE) { 929 930 if (!has_dirty_hw && !has_valid_hw) 931 return FALSE; 932 933 if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) 934 return FALSE; 935 if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { 936 vsaa->present_copy = TRUE; 937 return TRUE; 938 } 939 return FALSE; 940 } 941 942 vsaa->present_copy = FALSE; 943 if (src_vpix != dst_vpix) { 944 945 /* 946 * Use hardware acceleration either if source is partially only 947 * in hardware, or if source is entirely in hardware and destination 948 * has a hardware surface. 949 */ 950 951 if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL))) 952 return FALSE; 953 954 /* 955 * Determine surface formats. 956 */ 957 958 if (src_vpix->base.src_format == 0) { 959 if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 960 return FALSE; 961 } else { 962 if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || 963 !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) 964 return FALSE; 965 } 966 967 if (dst_vpix->base.dst_format == 0) { 968 if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 969 return FALSE; 970 } else { 971 if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || 972 !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) 973 return FALSE; 974 } 975 976 /* 977 * Create hardware surfaces. 978 */ 979 980 if (!vmwgfx_hw_commit(src_pixmap)) 981 return FALSE; 982 if (!vmwgfx_hw_commit(dst_pixmap)) 983 return FALSE; 984 985 /* 986 * Migrate data. 987 */ 988 989 if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { 990 xa_copy_done(vsaa->xa_ctx); 991 xa_context_flush(vsaa->xa_ctx); 992 return FALSE; 993 } 994 995 /* 996 * Setup copy state. 997 */ 998 999 if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != 1000 XA_ERR_NONE) 1001 return FALSE; 1002 1003 return TRUE; 1004 } 1005 1006 return FALSE; 1007} 1008 1009 1010static void 1011vmwgfx_present_done(struct vmwgfx_saa *vsaa) 1012{ 1013 ScreenPtr pScreen = vsaa->pScreen; 1014 struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix; 1015 1016 (void) pScreen; 1017 if (!vsaa->diff_valid) 1018 return; 1019 1020 (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id, 1021 vsaa->xdiff, vsaa->ydiff, 1022 &vsaa->present_region, vsaa->src_handle); 1023 1024 REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff); 1025 REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage, 1026 &vsaa->present_region); 1027 vsaa->diff_valid = FALSE; 1028 REGION_UNINIT(pScreen, &vsaa->present_region); 1029} 1030 1031static void 1032vmwgfx_present_copy(struct vmwgfx_saa *vsaa, 1033 int src_x, 1034 int src_y, 1035 int dst_x, 1036 int dst_y, 1037 int w, 1038 int h) 1039{ 1040 int xdiff = dst_x - src_x; 1041 int ydiff = dst_y - src_y; 1042 BoxRec box; 1043 RegionRec reg; 1044 1045 if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff))) 1046 (void) vmwgfx_present_done(vsaa); 1047 1048 if (!vsaa->diff_valid) { 1049 vsaa->xdiff = xdiff; 1050 vsaa->ydiff = ydiff; 1051 vsaa->diff_valid = TRUE; 1052 } 1053 1054 box.x1 = src_x; 1055 box.x2 = src_x + w; 1056 box.y1 = src_y; 1057 box.y2 = src_y + h; 1058 1059 REGION_INIT(pScreen, ®, &box, 1); 1060 REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); 1061 REGION_UNINIT(pScreen, ®); 1062} 1063 1064static void 1065vmwgfx_copy(struct saa_driver *driver, 1066 int src_x, 1067 int src_y, 1068 int dst_x, 1069 int dst_y, 1070 int w, 1071 int h) 1072{ 1073 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1074 1075 if (vsaa->present_copy) { 1076 vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h); 1077 return; 1078 } 1079 xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h); 1080} 1081 1082static void 1083vmwgfx_copy_done(struct saa_driver *driver) 1084{ 1085 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1086 1087 if (vsaa->present_copy) { 1088 vmwgfx_present_done(vsaa); 1089 return; 1090 } 1091 xa_copy_done(vsaa->xa_ctx); 1092 xa_context_flush(vsaa->xa_ctx); 1093} 1094 1095static Bool 1096vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, 1097 PicturePtr src_pict, PicturePtr mask_pict, 1098 PicturePtr dst_pict, 1099 PixmapPtr src_pix, PixmapPtr mask_pix, 1100 PixmapPtr dst_pix, 1101 RegionPtr src_region, 1102 RegionPtr mask_region, 1103 RegionPtr dst_region) 1104{ 1105 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1106 struct vmwgfx_saa_pixmap *src_vpix; 1107 struct vmwgfx_saa_pixmap *dst_vpix; 1108 struct vmwgfx_saa_pixmap *mask_vpix; 1109 Bool tmp_valid_hw; 1110 Bool dirty_hw; 1111 Bool valid_hw; 1112 RegionRec empty; 1113 struct xa_composite *xa_comp; 1114 1115 if (!vsaa->is_master) 1116 return FALSE; 1117 1118 REGION_NULL(pScreen, &empty); 1119 1120 /* 1121 * First we define our migration policy. We accelerate only if there 1122 * are dirty hw regions to be read or if all source data is 1123 * available in hw, and the destination has a hardware surface. 1124 */ 1125 dst_vpix = vmwgfx_saa_pixmap(dst_pix); 1126 valid_hw = (dst_vpix->hw != NULL); 1127 if (saa_op_reads_destination(op)) { 1128 vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, 1129 &dirty_hw, &tmp_valid_hw); 1130 valid_hw = (valid_hw && tmp_valid_hw); 1131 } else { 1132 dirty_hw = FALSE; 1133 dst_region = ∅ 1134 } 1135 1136 if (src_pix && !dirty_hw) { 1137 src_vpix = vmwgfx_saa_pixmap(src_pix); 1138 vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, 1139 &dirty_hw, &tmp_valid_hw); 1140 valid_hw = (valid_hw && tmp_valid_hw); 1141 } 1142 1143 if (mask_pict && mask_pix && !dirty_hw) { 1144 mask_vpix = vmwgfx_saa_pixmap(mask_pix); 1145 vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, 1146 &dirty_hw, &tmp_valid_hw); 1147 valid_hw = (valid_hw && tmp_valid_hw); 1148 } 1149 1150 /* 1151 * In rendercheck mode we try to accelerate all supported 1152 * composite operations. 1153 */ 1154 1155 if (!valid_hw && !dirty_hw && !vsaa->rendercheck) 1156 goto out_err; 1157 1158 /* 1159 * Then, setup most of the XA composite state (except hardware surfaces) 1160 * and check whether XA can accelerate. 1161 */ 1162 1163 if (!mask_pix) 1164 mask_pict = NULL; 1165 xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, 1166 src_pict, mask_pict, dst_pict); 1167 if (!xa_comp) 1168 goto out_err; 1169 1170 if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) 1171 goto out_err; 1172 1173 /* 1174 * Check that we can create the needed hardware surfaces. 1175 */ 1176 if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) 1177 goto out_err; 1178 if (mask_pict && mask_pix && 1179 !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) 1180 goto out_err; 1181 if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) 1182 goto out_err; 1183 1184 /* 1185 * Seems OK. Commit the changes, creating hardware surfaces. 1186 */ 1187 if (src_pix && !vmwgfx_hw_commit(src_pix)) 1188 goto out_err; 1189 if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) 1190 goto out_err; 1191 if (!vmwgfx_hw_commit(dst_pix)) 1192 goto out_err; 1193 1194 /* 1195 * Update the XA state with our hardware surfaces and 1196 * surface formats 1197 */ 1198 if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) 1199 goto out_err; 1200 1201 /* 1202 * Migrate data to surfaces. 1203 */ 1204 if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) 1205 goto out_err; 1206 if (mask_pict && mask_pix && mask_region && 1207 !vmwgfx_hw_validate(mask_pix, NULL)) 1208 goto out_err; 1209 if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) 1210 goto out_err; 1211 1212 1213 /* 1214 * Bind the XA state. This must be done after data migration, since 1215 * migration may change the hardware surfaces. 1216 */ 1217 if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) 1218 goto out_err; 1219 1220 return TRUE; 1221 1222 out_err: 1223 return FALSE; 1224} 1225 1226static void 1227vmwgfx_composite(struct saa_driver *driver, 1228 int src_x, int src_y, int mask_x, int mask_y, 1229 int dst_x, int dst_y, 1230 int width, int height) 1231{ 1232 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1233 1234 xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, 1235 dst_x, dst_y, width, height); 1236} 1237 1238static void 1239vmwgfx_composite_done(struct saa_driver *driver) 1240{ 1241 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1242 1243 xa_composite_done(vsaa->xa_ctx); 1244 xa_context_flush(vsaa->xa_ctx); 1245} 1246 1247static void 1248vmwgfx_takedown(struct saa_driver *driver) 1249{ 1250 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1251 1252 if (vsaa->vcomp) 1253 vmwgfx_free_composite(vsaa->vcomp); 1254 free(vsaa); 1255} 1256 1257/* 1258 * This function call originates from the damage layer (outside SAA) 1259 * to indicate that an operation is complete, and that damage is being 1260 * processed. 1261 */ 1262static void 1263vmwgfx_operation_complete(struct saa_driver *driver, 1264 PixmapPtr pixmap) 1265{ 1266 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1267 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 1268 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 1269 ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen); 1270 1271 /* 1272 * Make dri2 drawables up to date, or add them to the flush list 1273 * executed at glxWaitX(). Currently glxWaitX() is broken, so 1274 * we flush immediately, unless we're VT-switched away, in which 1275 * case a flush would deadlock in the kernel. 1276 * 1277 * For pixmaps for which vpix->hw_is_hosted is true, we can explicitly 1278 * inform the compositor when contents has changed, so for those pixmaps 1279 * we defer the upload until the compositor is informed, by putting 1280 * them on the sync_x_list. Note that hw_is_dri2_fronts take precedence. 1281 */ 1282 if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) { 1283 if (pScrn->vtSema && vpix->hw_is_dri2_fronts && 1284 vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { 1285 1286 REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 1287 return; 1288 } 1289 1290 if (WSBMLISTEMPTY(&vpix->sync_x_head)) 1291 WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); 1292 } 1293} 1294 1295/* 1296 * This function is called by SAA to indicate that SAA has 1297 * dirtied a region of a pixmap, either as hw (accelerated) or as 1298 * !hw (not accelerated). 1299 */ 1300static Bool 1301vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, 1302 Bool hw, RegionPtr damage) 1303{ 1304 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1305 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 1306 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 1307 1308 /* 1309 * Return if this is not a scanout pixmap. 1310 */ 1311 if (WSBMLISTEMPTY(&vpix->scanout_list)) 1312 return TRUE; 1313 1314#if 0 1315 /* 1316 * This code can be enabled to immediately upload scanout sw 1317 * contents to the hw surface. Otherwise this is done 1318 * just before we call the kms update function for the hw 1319 * surface. 1320 */ 1321 if (vsaa->only_hw_presents) { 1322 if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) 1323 return FALSE; 1324 1325 REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, 1326 &spix->dirty_shadow, damage); 1327 hw = TRUE; 1328 } 1329#endif 1330 1331 /* 1332 * Is the new scanout damage hw or sw? 1333 */ 1334 if (hw) { 1335 /* 1336 * Dump pending present into present tracking region. 1337 */ 1338 if (vpix->dirty_present && 1339 REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) { 1340 REGION_UNION(vsaa->pScreen, vpix->dirty_present, 1341 vpix->dirty_present, damage); 1342 REGION_EMPTY(vsaa->pScreen, vpix->present_damage); 1343 } else { 1344 if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) { 1345 RegionRec reg; 1346 1347 REGION_NULL(vsaa->pScreen, ®); 1348 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, 1349 damage); 1350 if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 1351 vsaa->present_flush(vsaa->pScreen); 1352 REGION_UNINIT(pScreen, ®); 1353 } 1354 REGION_UNION(vsaa->pScreen, vpix->pending_present, 1355 vpix->pending_present, damage); 1356 if (vpix->dirty_present) 1357 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 1358 vpix->dirty_present, damage); 1359 } 1360 } else { 1361 if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { 1362 RegionRec reg; 1363 1364 REGION_NULL(vsaa->pScreen, ®); 1365 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, 1366 damage); 1367 if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 1368 vsaa->present_flush(vsaa->pScreen); 1369 REGION_UNINIT(pScreen, ®); 1370 } 1371 REGION_UNION(vsaa->pScreen, vpix->pending_update, 1372 vpix->pending_update, damage); 1373 if (vpix->dirty_present) 1374 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 1375 vpix->dirty_present, damage); 1376 } 1377 1378 return TRUE; 1379} 1380 1381 1382static const struct saa_driver vmwgfx_saa_driver = { 1383 .saa_major = SAA_VERSION_MAJOR, 1384 .saa_minor = SAA_VERSION_MINOR, 1385 .pixmap_size = sizeof(struct vmwgfx_saa_pixmap), 1386 .damage = vmwgfx_dirty, 1387 .operation_complete = vmwgfx_operation_complete, 1388 .download_from_hw = vmwgfx_download_from_hw, 1389 .release_from_cpu = vmwgfx_release_from_cpu, 1390 .sync_for_cpu = vmwgfx_sync_for_cpu, 1391 .map = vmwgfx_map, 1392 .unmap = vmwgfx_unmap, 1393 .create_pixmap = vmwgfx_create_pixmap, 1394 .destroy_pixmap = vmwgfx_destroy_pixmap, 1395 .modify_pixmap_header = vmwgfx_modify_pixmap_header, 1396 .copy_prepare = vmwgfx_copy_prepare, 1397 .copy = vmwgfx_copy, 1398 .copy_done = vmwgfx_copy_done, 1399 .composite_prepare = vmwgfx_composite_prepare, 1400 .composite = vmwgfx_composite, 1401 .composite_done = vmwgfx_composite_done, 1402 .takedown = vmwgfx_takedown, 1403}; 1404 1405 1406Bool 1407vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, 1408 void (*present_flush)(ScreenPtr pScreen), 1409 Bool direct_presents, 1410 Bool only_hw_presents, 1411 Bool rendercheck) 1412{ 1413 struct vmwgfx_saa *vsaa; 1414 1415 vsaa = calloc(1, sizeof(*vsaa)); 1416 if (!vsaa) 1417 return FALSE; 1418 1419 if (xat == NULL) { 1420 direct_presents = FALSE; 1421 only_hw_presents = FALSE; 1422 } 1423 1424 vsaa->pScreen = pScreen; 1425 vsaa->xat = xat; 1426 if (xat) 1427 vsaa->xa_ctx = xa_context_default(xat); 1428 vsaa->drm_fd = drm_fd; 1429 vsaa->present_flush = present_flush; 1430 vsaa->can_optimize_dma = TRUE; 1431 vsaa->use_present_opt = direct_presents; 1432 vsaa->only_hw_presents = only_hw_presents; 1433 vsaa->rendercheck = rendercheck; 1434 vsaa->is_master = TRUE; 1435 vsaa->known_prime_format = FALSE; 1436 WSBMINITLISTHEAD(&vsaa->sync_x_list); 1437 WSBMINITLISTHEAD(&vsaa->pixmaps); 1438 1439 vsaa->driver = vmwgfx_saa_driver; 1440 vsaa->vcomp = vmwgfx_alloc_composite(); 1441 1442 if (!vsaa->vcomp) 1443 vsaa->driver.composite_prepare = NULL; 1444 1445 if (!saa_driver_init(pScreen, &vsaa->driver)) 1446 goto out_no_saa; 1447 1448 return TRUE; 1449 out_no_saa: 1450 free(vsaa); 1451 return FALSE; 1452} 1453 1454/* 1455 * ************************************************************************* 1456 * Scanout functions. 1457 * These do not strictly belong here, but we choose to hide the scanout 1458 * pixmap private data in the saa pixmaps. Might want to revisit this. 1459 */ 1460 1461/* 1462 * Make sure we flush / update this scanout on next update run. 1463 */ 1464 1465void 1466vmwgfx_scanout_refresh(PixmapPtr pixmap) 1467{ 1468 ScreenPtr pScreen = pixmap->drawable.pScreen; 1469 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1470 BoxRec box; 1471 1472 (void) pScreen; 1473 box.x1 = 0; 1474 box.y1 = 0; 1475 box.x2 = pixmap->drawable.width; 1476 box.y2 = pixmap->drawable.height; 1477 1478 REGION_RESET(vsaa->pScreen, vpix->pending_present, &box); 1479 if (vpix->dirty_present) 1480 REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 1481 vpix->pending_present, vpix->dirty_present); 1482 REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 1483 vpix->pending_present, &vpix->base.dirty_shadow); 1484 REGION_COPY(vsaa->pScreen, vpix->pending_update, 1485 &vpix->base.dirty_shadow); 1486} 1487 1488/* 1489 * Take a "scanout reference" on a pixmap. If this is the first scanout 1490 * reference, allocate resources needed for scanout, like proper 1491 * damage tracking and kms fbs. 1492 */ 1493 1494uint32_t 1495vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry) 1496{ 1497 PixmapPtr pixmap = entry->pixmap; 1498 struct vmwgfx_saa *vsaa = 1499 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 1500 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1501 1502 if (WSBMLISTEMPTY(&vpix->scanout_list)) { 1503 uint32_t handle, dummy; 1504 unsigned int depth; 1505 1506 if (vsaa->only_hw_presents) { 1507 /* 1508 * The KMS fb will be a HW surface. Create it, add damage 1509 * and get the handle. 1510 */ 1511 if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT | 1512 XA_FLAG_RENDER_TARGET, 0, NULL)) 1513 goto out_err; 1514 if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0) 1515 goto out_err; 1516 depth = xa_format_depth(xa_surface_format(vpix->hw)); 1517 1518 } else { 1519 /* 1520 * The KMS fb will be a Guest Memory Region. Create it, 1521 * add damage and get the handle. 1522 */ 1523 if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 1524 goto out_err; 1525 1526 handle = vpix->gmr->handle; 1527 depth = pixmap->drawable.depth; 1528 1529 } 1530 1531 if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) 1532 goto out_no_present; 1533 1534 if (drmModeAddFB(vsaa->drm_fd, 1535 pixmap->drawable.width, 1536 pixmap->drawable.height, 1537 depth, 1538 pixmap->drawable.bitsPerPixel, 1539 pixmap->devKind, 1540 handle, 1541 &vpix->fb_id) != 0) 1542 goto out_no_fb;; 1543 } 1544 pixmap->refcnt += 1; 1545 WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); 1546 return vpix->fb_id; 1547 1548 out_no_fb: 1549 vmwgfx_pixmap_remove_present(vpix); 1550 out_no_present: 1551 vmwgfx_pixmap_remove_damage(pixmap); 1552 out_err: 1553 vpix->fb_id = -1; 1554 return -1; 1555} 1556 1557/* 1558 * Free a "scanout reference" on a pixmap. If this was the last scanout 1559 * reference, free pixmap resources needed for scanout, like 1560 * damage tracking and kms fbs. 1561 */ 1562void 1563vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry) 1564{ 1565 struct vmwgfx_saa *vsaa; 1566 struct vmwgfx_saa_pixmap *vpix; 1567 PixmapPtr pixmap = entry->pixmap; 1568 1569 if (!pixmap) 1570 return; 1571 1572 vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 1573 vpix = vmwgfx_saa_pixmap(pixmap); 1574 WSBMLISTDELINIT(&entry->scanout_head); 1575 1576 if (WSBMLISTEMPTY(&vpix->scanout_list)) { 1577 REGION_EMPTY(vsaa->pScreen, vpix->pending_update); 1578 drmModeRmFB(vsaa->drm_fd, vpix->fb_id); 1579 vpix->fb_id = -1; 1580 vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL); 1581 vmwgfx_pixmap_remove_present(vpix); 1582 vmwgfx_pixmap_remove_damage(pixmap); 1583 } 1584 1585 entry->pixmap = NULL; 1586 pixmap->drawable.pScreen->DestroyPixmap(pixmap); 1587} 1588 1589void 1590vmwgfx_saa_set_master(ScreenPtr pScreen) 1591{ 1592 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1593 1594 vsaa->is_master = TRUE; 1595 vmwgfx_flush_dri2(pScreen); 1596} 1597 1598void 1599vmwgfx_saa_drop_master(ScreenPtr pScreen) 1600{ 1601 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1602 struct _WsbmListHead *list; 1603 struct vmwgfx_saa_pixmap *vpix; 1604 struct saa_pixmap *spix; 1605 1606 WSBMLISTFOREACH(list, &vsaa->pixmaps) { 1607 vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list); 1608 spix = &vpix->base; 1609 1610 if (!vpix->hw) 1611 continue; 1612 1613 (void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 1614 &spix->dirty_hw); 1615 REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 1616 } 1617 1618 vsaa->is_master = FALSE; 1619} 1620 1621/* 1622 * ************************************************************************* 1623 * Helpers for hosted. 1624 */ 1625 1626#if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38) 1627 1628/** 1629 * vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface. 1630 * 1631 * @pDraw: Pointer to source drawable. 1632 * @surface_fd: Prime file descriptor of external surface to copy to. 1633 * @dst_box: BoxRec describing the destination bounding box. 1634 * @region: Region of drawable to copy. Note: The code assumes that the 1635 * region is relative to the drawable origin, not the underlying pixmap 1636 * origin. 1637 * 1638 * Copies the contents (both software- and accelerated contents) to an 1639 * external surface. 1640 */ 1641Bool 1642vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd, 1643 const BoxRec *dst_box, RegionPtr region) 1644{ 1645 ScreenPtr pScreen = pDraw->pScreen; 1646 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1647 PixmapPtr src; 1648 struct saa_pixmap *spix; 1649 struct vmwgfx_saa_pixmap *vpix; 1650 const BoxRec *box; 1651 int n; 1652 int sx, sy, dx, dy; 1653 struct xa_surface *dst; 1654 uint32_t handle; 1655 Bool ret = TRUE; 1656 RegionRec intersection; 1657 RegionPtr copy_region = region; 1658 1659 if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0) 1660 return FALSE; 1661 1662 dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height, 1663 pDraw->depth, xa_type_argb, 1664 xa_format_unknown, 1665 XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET, 1666 handle, 1667 (pDraw->width * pDraw->bitsPerPixel + 7) / 8); 1668 1669 if (!dst) { 1670 ret = FALSE; 1671 goto out_no_surface; 1672 } 1673 1674 /* 1675 * Assume damage region is relative to the source window. 1676 */ 1677 src = saa_get_pixmap(pDraw, &sx, &sy); 1678 sx += pDraw->x; 1679 sy += pDraw->y; 1680 if (sx || sy) 1681 REGION_TRANSLATE(pScreen, region, sx, sy); 1682 1683 dx = dst_box->x1 - sx; 1684 dy = dst_box->y1 - sy; 1685 1686 spix = saa_get_saa_pixmap(src); 1687 vpix = to_vmwgfx_saa_pixmap(spix); 1688 1689 /* 1690 * Make sure software contents of the source pixmap is henceforth put 1691 * in a GMR to avoid the extra copy in the xa DMA. 1692 */ 1693 vmwgfx_prefer_gmr(vsaa, src); 1694 1695 /* 1696 * Determine the intersection between software contents and region to copy. 1697 */ 1698 1699 if (vsaa->known_prime_format) { 1700 REGION_NULL(pScreen, &intersection); 1701 if (!vpix->hw) 1702 REGION_COPY(pScreen, &intersection, region); 1703 else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow)) 1704 REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow); 1705 1706 /* 1707 * DMA software contents directly into the destination. Then subtract 1708 * the region we've DMA'd from the region to copy. 1709 */ 1710 if (REGION_NOTEMPTY(pScreen, &intersection)) { 1711 if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) { 1712 REGION_SUBTRACT(pScreen, &intersection, region, &intersection); 1713 copy_region = &intersection; 1714 } 1715 } 1716 } 1717 1718 if (!REGION_NOTEMPTY(pScreen, copy_region)) 1719 goto out_no_copy; 1720 1721 /* 1722 * Copy Hardware contents to the destination 1723 */ 1724 box = REGION_RECTS(copy_region); 1725 n = REGION_NUM_RECTS(copy_region); 1726 1727 if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) { 1728 ret = FALSE; 1729 goto out_no_copy; 1730 } 1731 1732 if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) { 1733 ret = FALSE; 1734 goto out_no_copy; 1735 } 1736 1737 while(n--) { 1738 xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1, 1739 box->x2 - box->x1, box->y2 - box->y1); 1740 box++; 1741 } 1742 1743 xa_copy_done(vsaa->xa_ctx); 1744 xa_context_flush(vsaa->xa_ctx); 1745 1746 out_no_copy: 1747 if (vsaa->known_prime_format) 1748 REGION_UNINIT(pScreen, &intersection); 1749 if (sx || sy) 1750 REGION_TRANSLATE(pScreen, region, -sx, -sy); 1751 xa_surface_unref(dst); 1752 out_no_surface: 1753 vmwgfx_prime_release_handle(vsaa->drm_fd, handle); 1754 1755 return ret; 1756} 1757#endif 1758