vmwgfx_saa.c revision 25dbecb6
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 <xa_context.h> 33#include "vmwgfx_saa.h" 34#include "vmwgfx_drmi.h" 35#include "vmwgfx_saa_priv.h" 36#include <xf86drmMode.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 375 return TRUE; 376 out_err: 377 REGION_UNINIT(vsaa->pScreen, &intersection); 378 return FALSE; 379} 380 381 382static Bool 383vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap, 384 RegionPtr upload) 385{ 386 return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE, 387 0, 0, NULL); 388} 389 390static void 391vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 392{ 393 // LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n", 394 // (unsigned long) pixmap, (unsigned) access); 395} 396 397static void * 398vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 399{ 400 /* 401 * Errors in this functions will turn up in subsequent map 402 * calls. 403 */ 404 405 (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap); 406 407 return NULL; 408} 409 410static void * 411vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 412{ 413 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 414 415 if (vpix->malloc) 416 return vpix->malloc; 417 else if (vpix->gmr) 418 return vmwgfx_dmabuf_map(vpix->gmr); 419 else 420 return NULL; 421} 422 423static void 424vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 425{ 426 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 427 428 if (vpix->gmr) 429 return vmwgfx_dmabuf_unmap(vpix->gmr); 430 431// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n", 432 // (unsigned long) pixmap, (unsigned) access); 433 ; 434} 435 436static Bool 437vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix, 438 int w, int h, int depth, 439 unsigned int usage_hint, int bpp, int *new_pitch) 440{ 441 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 442 443 *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 444 445 WSBMINITLISTHEAD(&vpix->sync_x_head); 446 WSBMINITLISTHEAD(&vpix->scanout_list); 447 WSBMINITLISTHEAD(&vpix->pixmap_list); 448 449 return TRUE; 450} 451 452Bool 453vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, 454 struct saa_pixmap *spix) 455{ 456 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 457 458 if (!vpix->hw) 459 return TRUE; 460 461 /* 462 * Read back any dirty regions from hardware. 463 */ 464 465 if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 466 &spix->dirty_hw)) 467 return FALSE; 468 469 xa_surface_destroy(vpix->hw); 470 vpix->hw = NULL; 471 472 /* 473 * Remove damage tracking if this is not a scanout pixmap. 474 */ 475 476 if (WSBMLISTEMPTY(&vpix->scanout_list)) 477 vmwgfx_pixmap_remove_damage(spix->pixmap); 478 479 return TRUE; 480} 481 482void 483vmwgfx_flush_dri2(ScreenPtr pScreen) 484{ 485 struct vmwgfx_saa *vsaa = 486 to_vmwgfx_saa(saa_get_driver(pScreen)); 487 struct _WsbmListHead *list, *next; 488 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 489 490 if (!pScrn->vtSema) 491 return; 492 493 WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { 494 struct vmwgfx_saa_pixmap *vpix = 495 WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); 496 struct saa_pixmap *spix = &vpix->base; 497 PixmapPtr pixmap = spix->pixmap; 498 499 if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { 500 REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 501 WSBMLISTDELINIT(list); 502 } 503 } 504} 505 506 507static void 508vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap) 509{ 510 ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen; 511 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 512 (void) pScreen; 513 514 vpix->backing = 0; 515 vmwgfx_pixmap_free_storage(vpix); 516 517 /* 518 * Any damage we've registered has already been removed by the server 519 * at this point. Any attempt to unregister / destroy it will result 520 * in a double free. 521 */ 522 523 vmwgfx_pixmap_remove_present(vpix); 524 WSBMLISTDELINIT(&vpix->pixmap_list); 525 WSBMLISTDELINIT(&vpix->sync_x_head); 526} 527 528 529 530/** 531 * 532 * Makes sure we have a surface with valid contents. 533 */ 534 535static void 536vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch, 537 unsigned int src_pitch, unsigned int dst_height, 538 unsigned int src_height) 539{ 540 unsigned int i; 541 unsigned int height = (dst_height < src_height) ? dst_height : src_height; 542 unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch; 543 544 for(i=0; i<height; ++i) { 545 memcpy(dst, src, pitch); 546 dst += dst_pitch; 547 src += src_pitch; 548 } 549} 550 551 552static Bool 553vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch, 554 unsigned int old_height, unsigned int old_width) 555{ 556 ScreenPtr pScreen = pixmap->drawable.pScreen; 557 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 558 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 559 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 560 DrawablePtr draw = &pixmap->drawable; 561 unsigned int size = pixmap->devKind * draw->height; 562 BoxRec b_box; 563 RegionRec b_reg; 564 565 /* 566 * Ignore copying errors. At worst they will show up as rendering 567 * artefacts. 568 */ 569 570 if (vpix->malloc) { 571 572 void *new_malloc = malloc(size); 573 if (!new_malloc) 574 return FALSE; 575 576 vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind, 577 old_pitch, draw->height, 578 old_height); 579 free(vpix->malloc); 580 vpix->malloc = new_malloc; 581 } 582 583 if (vpix->gmr) { 584 struct vmwgfx_dmabuf *gmr; 585 void *new_addr; 586 void *old_addr; 587 588 gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 589 if (!gmr) 590 return FALSE; 591 592 new_addr = vmwgfx_dmabuf_map(gmr); 593 old_addr = vmwgfx_dmabuf_map(vpix->gmr); 594 595 if (new_addr && old_addr) 596 vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind, 597 old_pitch, draw->height, 598 old_height); 599 else 600 LogMessage(X_ERROR, "Failed pixmap resize copy.\n"); 601 602 if (old_addr) 603 vmwgfx_dmabuf_unmap(vpix->gmr); 604 if (new_addr) 605 vmwgfx_dmabuf_unmap(gmr); 606 vmwgfx_dmabuf_destroy(vpix->gmr); 607 vpix->gmr = gmr; 608 } 609 610 if (vpix->hw) { 611 if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width, 612 draw->height, draw->depth, xa_type_argb, 613 xa_format_unknown, vpix->xa_flags, 1)) 614 return FALSE; 615 } 616 617 b_box.x1 = 0; 618 b_box.x2 = draw->width; 619 b_box.y1 = 0; 620 b_box.y2 = draw->height; 621 622 REGION_INIT(pScreen, &b_reg, &b_box, 1); 623 REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, 624 &b_reg); 625 REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); 626 if (vpix->dirty_present) 627 REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, 628 &b_reg); 629 if (vpix->pending_update) 630 REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, 631 &b_reg); 632 if (vpix->pending_present) 633 REGION_INTERSECT(pScreen, vpix->pending_present, 634 vpix->pending_present, &b_reg); 635 if (vpix->present_damage) 636 REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, 637 &b_reg); 638 639 REGION_UNINIT(pScreen, &b_reg); 640 641 return TRUE; 642} 643 644 645static Bool 646vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth, 647 int bpp, int devkind, void *pixdata) 648{ 649 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 650 ScreenPtr pScreen = pixmap->drawable.pScreen; 651 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 652 unsigned int old_height; 653 unsigned int old_width; 654 unsigned int old_pitch; 655 656 if (!vpix) { 657 LogMessage(X_ERROR, "Not an SAA pixmap.\n"); 658 return FALSE; 659 } 660 661 if (pixdata) { 662 vpix->backing = 0; 663 vmwgfx_pixmap_free_storage(vpix); 664 return FALSE; 665 } 666 667 if (depth <= 0) 668 depth = pixmap->drawable.depth; 669 670 if (bpp <= 0) 671 bpp = pixmap->drawable.bitsPerPixel; 672 673 if (w <= 0) 674 w = pixmap->drawable.width; 675 676 if (h <= 0) 677 h = pixmap->drawable.height; 678 679 if (w <= 0 || h <= 0 || depth <= 0) 680 return FALSE; 681 682 old_height = pixmap->drawable.height; 683 old_width = pixmap->drawable.width; 684 old_pitch = pixmap->devKind; 685 686 if (!miModifyPixmapHeader(pixmap, w, h, depth, 687 bpp, devkind, NULL)) 688 goto out_no_modify; 689 690 if (!vpix->backing) 691 vpix->backing = VMWGFX_PIX_MALLOC; 692 693 vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width); 694 vmwgfx_pixmap_free_storage(vpix); 695 if (WSBMLISTEMPTY(&vpix->pixmap_list)) 696 WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps); 697 698 return TRUE; 699 700 out_no_modify: 701 return FALSE; 702} 703 704static Bool 705vmwgfx_present_prepare(struct vmwgfx_saa *vsaa, 706 struct vmwgfx_saa_pixmap *src_vpix, 707 struct vmwgfx_saa_pixmap *dst_vpix) 708{ 709 ScreenPtr pScreen = vsaa->pScreen; 710 unsigned int dummy; 711 712 (void) pScreen; 713 if (src_vpix == dst_vpix || !src_vpix->hw || 714 _xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0) 715 return FALSE; 716 717 REGION_NULL(pScreen, &vsaa->present_region); 718 vsaa->diff_valid = FALSE; 719 vsaa->dst_vpix = dst_vpix; 720 vsaa->present_flush(pScreen); 721 722 return TRUE; 723} 724 725/** 726 * Determine whether we should try present copies on this pixmap. 727 */ 728 729static Bool 730vmwgfx_is_present_hw(PixmapPtr pixmap) 731{ 732 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 733 return (vpix->dirty_present != NULL); 734} 735 736static void 737vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa, 738 struct vmwgfx_saa_pixmap *vpix, 739 RegionPtr region, 740 Bool *has_dirty_hw, 741 Bool *has_valid_hw) 742{ 743 RegionRec intersection; 744 745 746 if (!vpix->hw) { 747 *has_dirty_hw = FALSE; 748 *has_valid_hw = FALSE; 749 return; 750 } 751 752 if (!region) { 753 *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, 754 &vpix->base.dirty_hw); 755 *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, 756 &vpix->base.dirty_shadow); 757 return; 758 } 759 760 REGION_NULL(vsaa->pScreen, &intersection); 761 REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw, 762 region); 763 *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection); 764 REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow, 765 region); 766 *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection); 767 REGION_UNINIT(vsaa->pScreen, &intersection); 768} 769 770/** 771 * vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software 772 * rendered storage 773 * 774 * @vsaa: Pointer to a struct vmwgfx_saa accelerator. 775 * @pixmap: Pointer to pixmap whose storage preference we want to alter. 776 * 777 * If possible, alter the storage or future storage of the software contents 778 * of this pixmap to be in a DMA buffer rather than in malloced memory. 779 * This function should be called when it's likely that frequent DMA operations 780 * will occur between a surface and the memory holding the software 781 * contents. 782 */ 783static void 784vmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 785{ 786 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 787 788 if (vsaa->can_optimize_dma) { 789 if (vpix->malloc) { 790 (void) vmwgfx_pixmap_create_gmr(vsaa, pixmap); 791 } else if (vpix->backing & VMWGFX_PIX_MALLOC) { 792 vpix->backing |= VMWGFX_PIX_GMR; 793 vpix->backing &= ~VMWGFX_PIX_MALLOC; 794 } 795 } 796} 797 798Bool 799vmwgfx_create_hw(struct vmwgfx_saa *vsaa, 800 PixmapPtr pixmap, 801 Bool shared) 802{ 803 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 804 struct xa_surface *hw; 805 uint32_t new_flags; 806 807 if (!vsaa->xat) 808 return FALSE; 809 810 if (!shared) { 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 } else { 825 new_flags = vpix->xa_flags; 826 hw = vpix->hw; 827 } 828 829 if (hw == NULL) 830 return FALSE; 831 832 vpix->xa_flags = new_flags; 833 vpix->hw = hw; 834 835 if (!vmwgfx_pixmap_add_damage(pixmap)) 836 goto out_no_damage; 837 838 vpix->backing |= VMWGFX_PIX_SURFACE; 839 vmwgfx_pixmap_free_storage(vpix); 840 841 /* 842 * If there is a HW surface, make sure that the shadow is 843 * (or will be) a GMR, provided we can do fast DMAs from / to it. 844 */ 845 vmwgfx_prefer_gmr(vsaa, pixmap); 846 847 return TRUE; 848 849out_no_damage: 850 vpix->hw = NULL; 851 xa_surface_destroy(hw); 852 return FALSE; 853} 854 855 856Bool 857vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) 858{ 859 struct vmwgfx_saa *vsaa = 860 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 861 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 862 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 863 RegionRec intersection; 864 865 if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region)) 866 return FALSE; 867 868 REGION_NULL(vsaa->pScreen, &intersection); 869 REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow); 870 871 if (vpix->dirty_present) 872 REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present, 873 &spix->dirty_shadow); 874 875 if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) { 876 RegionPtr upload = &intersection; 877 878 /* 879 * Check whether we need to upload from GMR. 880 */ 881 882 if (region) { 883 REGION_INTERSECT(vsaa->pScreen, &intersection, region, 884 &intersection); 885 upload = &intersection; 886 } 887 888 if (REGION_NOTEMPTY(vsaa->pScreen, upload)) { 889 Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload); 890 if (ret) { 891 REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow, 892 &spix->dirty_shadow, upload); 893 if (vpix->dirty_present) 894 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 895 vpix->dirty_present, upload); 896 } else { 897 REGION_UNINIT(vsaa->pScreen, &intersection); 898 return FALSE; 899 } 900 } 901 } 902 REGION_UNINIT(vsaa->pScreen, &intersection); 903 return TRUE; 904} 905 906static Bool 907vmwgfx_copy_prepare(struct saa_driver *driver, 908 PixmapPtr src_pixmap, 909 PixmapPtr dst_pixmap, 910 int dx, 911 int dy, 912 int alu, 913 RegionPtr src_reg, 914 uint32_t plane_mask) 915{ 916 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 917 struct vmwgfx_saa_pixmap *src_vpix; 918 struct vmwgfx_saa_pixmap *dst_vpix; 919 Bool has_dirty_hw; 920 Bool has_valid_hw; 921 922 if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) || 923 alu != GXcopy || !vsaa->is_master) 924 return FALSE; 925 926 src_vpix = vmwgfx_saa_pixmap(src_pixmap); 927 dst_vpix = vmwgfx_saa_pixmap(dst_pixmap); 928 929 vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg, 930 &has_dirty_hw, &has_valid_hw); 931 932 if (vmwgfx_is_present_hw(dst_pixmap) && 933 src_vpix->backing & VMWGFX_PIX_SURFACE) { 934 935 if (!has_dirty_hw && !has_valid_hw) 936 return FALSE; 937 938 if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) 939 return FALSE; 940 if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { 941 vsaa->present_copy = TRUE; 942 return TRUE; 943 } 944 return FALSE; 945 } 946 947 vsaa->present_copy = FALSE; 948 if (src_vpix != dst_vpix) { 949 950 /* 951 * Use hardware acceleration either if source is partially only 952 * in hardware, or if source is entirely in hardware and destination 953 * has a hardware surface. 954 */ 955 956 if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL))) 957 return FALSE; 958 959 /* 960 * Determine surface formats. 961 */ 962 963 if (src_vpix->base.src_format == 0) { 964 if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 965 return FALSE; 966 } else { 967 if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || 968 !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) 969 return FALSE; 970 } 971 972 if (dst_vpix->base.dst_format == 0) { 973 if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 974 return FALSE; 975 } else { 976 if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || 977 !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) 978 return FALSE; 979 } 980 981 /* 982 * Create hardware surfaces. 983 */ 984 985 if (!vmwgfx_hw_commit(src_pixmap)) 986 return FALSE; 987 if (!vmwgfx_hw_commit(dst_pixmap)) 988 return FALSE; 989 990 /* 991 * Migrate data. 992 */ 993 994 if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { 995 xa_copy_done(vsaa->xa_ctx); 996 xa_context_flush(vsaa->xa_ctx); 997 return FALSE; 998 } 999 1000 /* 1001 * Setup copy state. 1002 */ 1003 1004 if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != 1005 XA_ERR_NONE) 1006 return FALSE; 1007 1008 return TRUE; 1009 } 1010 1011 return FALSE; 1012} 1013 1014 1015static void 1016vmwgfx_present_done(struct vmwgfx_saa *vsaa) 1017{ 1018 ScreenPtr pScreen = vsaa->pScreen; 1019 struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix; 1020 1021 (void) pScreen; 1022 if (!vsaa->diff_valid) 1023 return; 1024 1025 (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id, 1026 vsaa->xdiff, vsaa->ydiff, 1027 &vsaa->present_region, vsaa->src_handle); 1028 1029 REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff); 1030 REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage, 1031 &vsaa->present_region); 1032 vsaa->diff_valid = FALSE; 1033 REGION_UNINIT(pScreen, &vsaa->present_region); 1034} 1035 1036static void 1037vmwgfx_present_copy(struct vmwgfx_saa *vsaa, 1038 int src_x, 1039 int src_y, 1040 int dst_x, 1041 int dst_y, 1042 int w, 1043 int h) 1044{ 1045 int xdiff = dst_x - src_x; 1046 int ydiff = dst_y - src_y; 1047 BoxRec box; 1048 RegionRec reg; 1049 1050 if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff))) 1051 (void) vmwgfx_present_done(vsaa); 1052 1053 if (!vsaa->diff_valid) { 1054 vsaa->xdiff = xdiff; 1055 vsaa->ydiff = ydiff; 1056 vsaa->diff_valid = TRUE; 1057 } 1058 1059 box.x1 = src_x; 1060 box.x2 = src_x + w; 1061 box.y1 = src_y; 1062 box.y2 = src_y + h; 1063 1064 REGION_INIT(pScreen, ®, &box, 1); 1065 REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); 1066 REGION_UNINIT(pScreen, ®); 1067} 1068 1069static void 1070vmwgfx_copy(struct saa_driver *driver, 1071 int src_x, 1072 int src_y, 1073 int dst_x, 1074 int dst_y, 1075 int w, 1076 int h) 1077{ 1078 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1079 1080 if (vsaa->present_copy) { 1081 vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h); 1082 return; 1083 } 1084 xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h); 1085} 1086 1087static void 1088vmwgfx_copy_done(struct saa_driver *driver) 1089{ 1090 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1091 1092 if (vsaa->present_copy) { 1093 vmwgfx_present_done(vsaa); 1094 return; 1095 } 1096 xa_copy_done(vsaa->xa_ctx); 1097 xa_context_flush(vsaa->xa_ctx); 1098} 1099 1100static Bool 1101vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, 1102 PicturePtr src_pict, PicturePtr mask_pict, 1103 PicturePtr dst_pict, 1104 PixmapPtr src_pix, PixmapPtr mask_pix, 1105 PixmapPtr dst_pix, 1106 RegionPtr src_region, 1107 RegionPtr mask_region, 1108 RegionPtr dst_region) 1109{ 1110 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1111 struct vmwgfx_saa_pixmap *src_vpix; 1112 struct vmwgfx_saa_pixmap *dst_vpix; 1113 struct vmwgfx_saa_pixmap *mask_vpix; 1114 Bool tmp_valid_hw; 1115 Bool dirty_hw; 1116 Bool valid_hw; 1117 RegionRec empty; 1118 struct xa_composite *xa_comp; 1119 1120 if (!vsaa->is_master) 1121 return FALSE; 1122 1123 REGION_NULL(pScreen, &empty); 1124 1125 /* 1126 * First we define our migration policy. We accelerate only if there 1127 * are dirty hw regions to be read or if all source data is 1128 * available in hw, and the destination has a hardware surface. 1129 */ 1130 dst_vpix = vmwgfx_saa_pixmap(dst_pix); 1131 valid_hw = (dst_vpix->hw != NULL); 1132 if (saa_op_reads_destination(op)) { 1133 vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, 1134 &dirty_hw, &tmp_valid_hw); 1135 valid_hw = (valid_hw && tmp_valid_hw); 1136 } else { 1137 dirty_hw = FALSE; 1138 dst_region = ∅ 1139 } 1140 1141 if (src_pix && !dirty_hw) { 1142 src_vpix = vmwgfx_saa_pixmap(src_pix); 1143 vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, 1144 &dirty_hw, &tmp_valid_hw); 1145 valid_hw = (valid_hw && tmp_valid_hw); 1146 } 1147 1148 if (mask_pict && mask_pix && !dirty_hw) { 1149 mask_vpix = vmwgfx_saa_pixmap(mask_pix); 1150 vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, 1151 &dirty_hw, &tmp_valid_hw); 1152 valid_hw = (valid_hw && tmp_valid_hw); 1153 } 1154 1155 /* 1156 * In rendercheck mode we try to accelerate all supported 1157 * composite operations. 1158 */ 1159 1160 if (!valid_hw && !dirty_hw && !vsaa->rendercheck) 1161 goto out_err; 1162 1163 /* 1164 * Then, setup most of the XA composite state (except hardware surfaces) 1165 * and check whether XA can accelerate. 1166 */ 1167 1168 if (!mask_pix) 1169 mask_pict = NULL; 1170 xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, 1171 src_pict, mask_pict, dst_pict); 1172 if (!xa_comp) 1173 goto out_err; 1174 1175 if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) 1176 goto out_err; 1177 1178 /* 1179 * Check that we can create the needed hardware surfaces. 1180 */ 1181 if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) 1182 goto out_err; 1183 if (mask_pict && mask_pix && 1184 !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) 1185 goto out_err; 1186 if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) 1187 goto out_err; 1188 1189 /* 1190 * Seems OK. Commit the changes, creating hardware surfaces. 1191 */ 1192 if (src_pix && !vmwgfx_hw_commit(src_pix)) 1193 goto out_err; 1194 if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) 1195 goto out_err; 1196 if (!vmwgfx_hw_commit(dst_pix)) 1197 goto out_err; 1198 1199 /* 1200 * Update the XA state with our hardware surfaces and 1201 * surface formats 1202 */ 1203 if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) 1204 goto out_err; 1205 1206 /* 1207 * Migrate data to surfaces. 1208 */ 1209 if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) 1210 goto out_err; 1211 if (mask_pict && mask_pix && mask_region && 1212 !vmwgfx_hw_validate(mask_pix, NULL)) 1213 goto out_err; 1214 if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) 1215 goto out_err; 1216 1217 1218 /* 1219 * Bind the XA state. This must be done after data migration, since 1220 * migration may change the hardware surfaces. 1221 */ 1222 if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) 1223 goto out_err; 1224 1225 return TRUE; 1226 1227 out_err: 1228 return FALSE; 1229} 1230 1231static void 1232vmwgfx_composite(struct saa_driver *driver, 1233 int src_x, int src_y, int mask_x, int mask_y, 1234 int dst_x, int dst_y, 1235 int width, int height) 1236{ 1237 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1238 1239 xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, 1240 dst_x, dst_y, width, height); 1241} 1242 1243static void 1244vmwgfx_composite_done(struct saa_driver *driver) 1245{ 1246 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1247 1248 xa_composite_done(vsaa->xa_ctx); 1249 xa_context_flush(vsaa->xa_ctx); 1250} 1251 1252static void 1253vmwgfx_takedown(struct saa_driver *driver) 1254{ 1255 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1256 1257 if (vsaa->vcomp) 1258 vmwgfx_free_composite(vsaa->vcomp); 1259 free(vsaa); 1260} 1261 1262/* 1263 * This function call originates from the damage layer (outside SAA) 1264 * to indicate that an operation is complete, and that damage is being 1265 * processed. 1266 */ 1267static void 1268vmwgfx_operation_complete(struct saa_driver *driver, 1269 PixmapPtr pixmap) 1270{ 1271 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1272 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 1273 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 1274 ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen); 1275 1276 /* 1277 * Make dri2 drawables up to date, or add them to the flush list 1278 * executed at glxWaitX(). Currently glxWaitX() is broken, so 1279 * we flush immediately, unless we're VT-switched away, in which 1280 * case a flush would deadlock in the kernel. 1281 * 1282 * For pixmaps for which vpix->hw_is_hosted is true, we can explicitly 1283 * inform the compositor when contents has changed, so for those pixmaps 1284 * we defer the upload until the compositor is informed, by putting 1285 * them on the sync_x_list. Note that hw_is_dri2_fronts take precedence. 1286 */ 1287 if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) { 1288 if (pScrn->vtSema && vpix->hw_is_dri2_fronts && 1289 vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { 1290 1291 REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 1292 return; 1293 } 1294 1295 if (WSBMLISTEMPTY(&vpix->sync_x_head)) 1296 WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); 1297 } 1298} 1299 1300/* 1301 * This function is called by SAA to indicate that SAA has 1302 * dirtied a region of a pixmap, either as hw (accelerated) or as 1303 * !hw (not accelerated). 1304 */ 1305static Bool 1306vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, 1307 Bool hw, RegionPtr damage) 1308{ 1309 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 1310 struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 1311 struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 1312 1313 /* 1314 * Return if this is not a scanout pixmap. 1315 */ 1316 if (WSBMLISTEMPTY(&vpix->scanout_list)) 1317 return TRUE; 1318 1319#if 0 1320 /* 1321 * This code can be enabled to immediately upload scanout sw 1322 * contents to the hw surface. Otherwise this is done 1323 * just before we call the kms update function for the hw 1324 * surface. 1325 */ 1326 if (vpix->scanout_hw) { 1327 if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) 1328 return FALSE; 1329 1330 REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, 1331 &spix->dirty_shadow, damage); 1332 hw = TRUE; 1333 } 1334#endif 1335 1336 /* 1337 * Is the new scanout damage hw or sw? 1338 */ 1339 if (hw) { 1340 /* 1341 * Dump pending present into present tracking region. 1342 */ 1343 if (vpix->dirty_present && 1344 REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) { 1345 REGION_UNION(vsaa->pScreen, vpix->dirty_present, 1346 vpix->dirty_present, damage); 1347 REGION_EMPTY(vsaa->pScreen, vpix->present_damage); 1348 } else { 1349 if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) { 1350 RegionRec reg; 1351 1352 REGION_NULL(vsaa->pScreen, ®); 1353 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, 1354 damage); 1355 if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 1356 vsaa->present_flush(vsaa->pScreen); 1357 REGION_UNINIT(pScreen, ®); 1358 } 1359 REGION_UNION(vsaa->pScreen, vpix->pending_present, 1360 vpix->pending_present, damage); 1361 if (vpix->dirty_present) 1362 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 1363 vpix->dirty_present, damage); 1364 } 1365 } else { 1366 if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { 1367 RegionRec reg; 1368 1369 REGION_NULL(vsaa->pScreen, ®); 1370 REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, 1371 damage); 1372 if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 1373 vsaa->present_flush(vsaa->pScreen); 1374 REGION_UNINIT(pScreen, ®); 1375 } 1376 REGION_UNION(vsaa->pScreen, vpix->pending_update, 1377 vpix->pending_update, damage); 1378 if (vpix->dirty_present) 1379 REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 1380 vpix->dirty_present, damage); 1381 } 1382 1383 return TRUE; 1384} 1385 1386 1387static const struct saa_driver vmwgfx_saa_driver = { 1388 .saa_major = SAA_VERSION_MAJOR, 1389 .saa_minor = SAA_VERSION_MINOR, 1390 .pixmap_size = sizeof(struct vmwgfx_saa_pixmap), 1391 .damage = vmwgfx_dirty, 1392 .operation_complete = vmwgfx_operation_complete, 1393 .download_from_hw = vmwgfx_download_from_hw, 1394 .release_from_cpu = vmwgfx_release_from_cpu, 1395 .sync_for_cpu = vmwgfx_sync_for_cpu, 1396 .map = vmwgfx_map, 1397 .unmap = vmwgfx_unmap, 1398 .create_pixmap = vmwgfx_create_pixmap, 1399 .destroy_pixmap = vmwgfx_destroy_pixmap, 1400 .modify_pixmap_header = vmwgfx_modify_pixmap_header, 1401 .copy_prepare = vmwgfx_copy_prepare, 1402 .copy = vmwgfx_copy, 1403 .copy_done = vmwgfx_copy_done, 1404 .composite_prepare = vmwgfx_composite_prepare, 1405 .composite = vmwgfx_composite, 1406 .composite_done = vmwgfx_composite_done, 1407 .takedown = vmwgfx_takedown, 1408}; 1409 1410 1411Bool 1412vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, 1413 void (*present_flush)(ScreenPtr pScreen), 1414 Bool direct_presents, 1415 Bool only_hw_presents, 1416 Bool rendercheck, 1417 Bool has_screen_targets) 1418{ 1419 struct vmwgfx_saa *vsaa; 1420 1421 vsaa = calloc(1, sizeof(*vsaa)); 1422 if (!vsaa) 1423 return FALSE; 1424 1425 if (xat == NULL) { 1426 direct_presents = FALSE; 1427 only_hw_presents = FALSE; 1428 has_screen_targets = FALSE; 1429 } 1430 1431 vsaa->pScreen = pScreen; 1432 vsaa->xat = xat; 1433 if (xat) 1434 vsaa->xa_ctx = xa_context_default(xat); 1435 vsaa->drm_fd = drm_fd; 1436 vsaa->present_flush = present_flush; 1437 vsaa->can_optimize_dma = TRUE; 1438 vsaa->use_present_opt = direct_presents; 1439 vsaa->only_hw_presents = only_hw_presents; 1440 vsaa->rendercheck = rendercheck; 1441 vsaa->is_master = TRUE; 1442 vsaa->known_prime_format = FALSE; 1443 vsaa->has_screen_targets = has_screen_targets; 1444 WSBMINITLISTHEAD(&vsaa->sync_x_list); 1445 WSBMINITLISTHEAD(&vsaa->pixmaps); 1446 1447 vsaa->driver = vmwgfx_saa_driver; 1448 vsaa->vcomp = vmwgfx_alloc_composite(); 1449 1450 if (!vsaa->vcomp) 1451 vsaa->driver.composite_prepare = NULL; 1452 1453 if (!saa_driver_init(pScreen, &vsaa->driver)) 1454 goto out_no_saa; 1455 1456 return TRUE; 1457 out_no_saa: 1458 free(vsaa); 1459 return FALSE; 1460} 1461 1462/* 1463 * ************************************************************************* 1464 * Scanout functions. 1465 * These do not strictly belong here, but we choose to hide the scanout 1466 * pixmap private data in the saa pixmaps. Might want to revisit this. 1467 */ 1468 1469/* 1470 * Make sure we flush / update this scanout on next update run. 1471 */ 1472 1473void 1474vmwgfx_scanout_refresh(PixmapPtr pixmap) 1475{ 1476 ScreenPtr pScreen = pixmap->drawable.pScreen; 1477 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1478 BoxRec box; 1479 1480 (void) pScreen; 1481 box.x1 = 0; 1482 box.y1 = 0; 1483 box.x2 = pixmap->drawable.width; 1484 box.y2 = pixmap->drawable.height; 1485 1486 REGION_RESET(vsaa->pScreen, vpix->pending_present, &box); 1487 if (vpix->dirty_present) 1488 REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 1489 vpix->pending_present, vpix->dirty_present); 1490 REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 1491 vpix->pending_present, &vpix->base.dirty_shadow); 1492 REGION_COPY(vsaa->pScreen, vpix->pending_update, 1493 &vpix->base.dirty_shadow); 1494} 1495 1496/* 1497 * Take a "scanout reference" on a pixmap. If this is the first scanout 1498 * reference, allocate resources needed for scanout, like proper 1499 * damage tracking and kms fbs. 1500 */ 1501 1502uint32_t 1503vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry, 1504 Bool scanout_equals_pixmap) 1505{ 1506 PixmapPtr pixmap = entry->pixmap; 1507 struct vmwgfx_saa *vsaa = 1508 to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 1509 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1510 1511 if (WSBMLISTEMPTY(&vpix->scanout_list)) { 1512 uint32_t handle, dummy; 1513 unsigned int depth; 1514 1515 vpix->scanout_hw = vsaa->only_hw_presents || 1516 (vsaa->has_screen_targets && scanout_equals_pixmap); 1517 1518 if (vpix->scanout_hw) { 1519 /* 1520 * The KMS fb will be a HW surface. Create it, add damage 1521 * and get the handle. 1522 */ 1523 if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT | 1524 XA_FLAG_RENDER_TARGET, 0, NULL)) 1525 goto out_err; 1526 if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0) 1527 goto out_err; 1528 depth = xa_format_depth(xa_surface_format(vpix->hw)); 1529 1530 } else { 1531 /* 1532 * The KMS fb will be a Guest Memory Region. Create it, 1533 * add damage and get the handle. 1534 */ 1535 if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 1536 goto out_err; 1537 1538 handle = vpix->gmr->handle; 1539 depth = pixmap->drawable.depth; 1540 1541 } 1542 1543 if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) 1544 goto out_no_present; 1545 1546 if (drmModeAddFB(vsaa->drm_fd, 1547 pixmap->drawable.width, 1548 pixmap->drawable.height, 1549 depth, 1550 pixmap->drawable.bitsPerPixel, 1551 pixmap->devKind, 1552 handle, 1553 &vpix->fb_id) != 0) 1554 goto out_no_fb;; 1555 } 1556 pixmap->refcnt += 1; 1557 WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); 1558 return vpix->fb_id; 1559 1560 out_no_fb: 1561 vmwgfx_pixmap_remove_present(vpix); 1562 out_no_present: 1563 vmwgfx_pixmap_remove_damage(pixmap); 1564 out_err: 1565 vpix->fb_id = -1; 1566 return -1; 1567} 1568 1569/* 1570 * Free a "scanout reference" on a pixmap. If this was the last scanout 1571 * reference, free pixmap resources needed for scanout, like 1572 * damage tracking and kms fbs. 1573 */ 1574void 1575vmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry) 1576{ 1577 struct vmwgfx_saa *vsaa; 1578 struct vmwgfx_saa_pixmap *vpix; 1579 PixmapPtr pixmap = entry->pixmap; 1580 1581 if (!pixmap) 1582 return; 1583 1584 vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 1585 vpix = vmwgfx_saa_pixmap(pixmap); 1586 WSBMLISTDELINIT(&entry->scanout_head); 1587 1588 if (WSBMLISTEMPTY(&vpix->scanout_list)) { 1589 REGION_EMPTY(vsaa->pScreen, vpix->pending_update); 1590 drmModeRmFB(vsaa->drm_fd, vpix->fb_id); 1591 vpix->fb_id = -1; 1592 vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL); 1593 vmwgfx_pixmap_remove_present(vpix); 1594 vmwgfx_pixmap_remove_damage(pixmap); 1595 } 1596 1597 entry->pixmap = NULL; 1598 pixmap->drawable.pScreen->DestroyPixmap(pixmap); 1599} 1600 1601void 1602vmwgfx_saa_set_master(ScreenPtr pScreen) 1603{ 1604 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1605 1606 vsaa->is_master = TRUE; 1607 vmwgfx_flush_dri2(pScreen); 1608} 1609 1610void 1611vmwgfx_saa_drop_master(ScreenPtr pScreen) 1612{ 1613 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1614 struct _WsbmListHead *list; 1615 struct vmwgfx_saa_pixmap *vpix; 1616 struct saa_pixmap *spix; 1617 1618 WSBMLISTFOREACH(list, &vsaa->pixmaps) { 1619 vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list); 1620 spix = &vpix->base; 1621 1622 if (!vpix->hw) 1623 continue; 1624 1625 (void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 1626 &spix->dirty_hw); 1627 REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 1628 } 1629 1630 vsaa->is_master = FALSE; 1631} 1632 1633/* 1634 * ************************************************************************* 1635 * Helpers for hosted. 1636 */ 1637 1638#if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38) 1639 1640/** 1641 * vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface. 1642 * 1643 * @pDraw: Pointer to source drawable. 1644 * @surface_fd: Prime file descriptor of external surface to copy to. 1645 * @dst_box: BoxRec describing the destination bounding box. 1646 * @region: Region of drawable to copy. Note: The code assumes that the 1647 * region is relative to the drawable origin, not the underlying pixmap 1648 * origin. 1649 * 1650 * Copies the contents (both software- and accelerated contents) to an 1651 * external surface. 1652 */ 1653Bool 1654vmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd, 1655 const BoxRec *dst_box, RegionPtr region) 1656{ 1657 ScreenPtr pScreen = pDraw->pScreen; 1658 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 1659 PixmapPtr src; 1660 struct saa_pixmap *spix; 1661 struct vmwgfx_saa_pixmap *vpix; 1662 const BoxRec *box; 1663 int n; 1664 int sx, sy, dx, dy; 1665 struct xa_surface *dst; 1666 uint32_t handle; 1667 Bool ret = TRUE; 1668 RegionRec intersection; 1669 RegionPtr copy_region = region; 1670 1671 if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0) 1672 return FALSE; 1673 1674 dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height, 1675 pDraw->depth, xa_type_argb, 1676 xa_format_unknown, 1677 XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET, 1678 handle, 1679 (pDraw->width * pDraw->bitsPerPixel + 7) / 8); 1680 1681 if (!dst) { 1682 ret = FALSE; 1683 goto out_no_surface; 1684 } 1685 1686 /* 1687 * Assume damage region is relative to the source window. 1688 */ 1689 src = saa_get_pixmap(pDraw, &sx, &sy); 1690 sx += pDraw->x; 1691 sy += pDraw->y; 1692 if (sx || sy) 1693 REGION_TRANSLATE(pScreen, region, sx, sy); 1694 1695 dx = dst_box->x1 - sx; 1696 dy = dst_box->y1 - sy; 1697 1698 spix = saa_get_saa_pixmap(src); 1699 vpix = to_vmwgfx_saa_pixmap(spix); 1700 1701 /* 1702 * Make sure software contents of the source pixmap is henceforth put 1703 * in a GMR to avoid the extra copy in the xa DMA. 1704 */ 1705 vmwgfx_prefer_gmr(vsaa, src); 1706 1707 /* 1708 * Determine the intersection between software contents and region to copy. 1709 */ 1710 1711 if (vsaa->known_prime_format) { 1712 REGION_NULL(pScreen, &intersection); 1713 if (!vpix->hw) 1714 REGION_COPY(pScreen, &intersection, region); 1715 else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow)) 1716 REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow); 1717 1718 /* 1719 * DMA software contents directly into the destination. Then subtract 1720 * the region we've DMA'd from the region to copy. 1721 */ 1722 if (REGION_NOTEMPTY(pScreen, &intersection)) { 1723 if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) { 1724 REGION_SUBTRACT(pScreen, &intersection, region, &intersection); 1725 copy_region = &intersection; 1726 } 1727 } 1728 } 1729 1730 if (!REGION_NOTEMPTY(pScreen, copy_region)) 1731 goto out_no_copy; 1732 1733 /* 1734 * Copy Hardware contents to the destination 1735 */ 1736 box = REGION_RECTS(copy_region); 1737 n = REGION_NUM_RECTS(copy_region); 1738 1739 if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) { 1740 ret = FALSE; 1741 goto out_no_copy; 1742 } 1743 1744 if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) { 1745 ret = FALSE; 1746 goto out_no_copy; 1747 } 1748 1749 while(n--) { 1750 xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1, 1751 box->x2 - box->x1, box->y2 - box->y1); 1752 box++; 1753 } 1754 1755 xa_copy_done(vsaa->xa_ctx); 1756 xa_context_flush(vsaa->xa_ctx); 1757 1758 out_no_copy: 1759 if (vsaa->known_prime_format) 1760 REGION_UNINIT(pScreen, &intersection); 1761 if (sx || sy) 1762 REGION_TRANSLATE(pScreen, region, -sx, -sy); 1763 xa_surface_unref(dst); 1764 out_no_surface: 1765 vmwgfx_prime_release_handle(vsaa->drm_fd, handle); 1766 1767 return ret; 1768} 1769#endif 1770