13bfa90b6Smrg/* 23bfa90b6Smrg * Copyright 2011 VMWare, Inc. 33bfa90b6Smrg * All Rights Reserved. 43bfa90b6Smrg * 53bfa90b6Smrg * Permission is hereby granted, free of charge, to any person obtaining a 63bfa90b6Smrg * copy of this software and associated documentation files (the 73bfa90b6Smrg * "Software"), to deal in the Software without restriction, including 83bfa90b6Smrg * without limitation the rights to use, copy, modify, merge, publish, 93bfa90b6Smrg * distribute, sub license, and/or sell copies of the Software, and to 103bfa90b6Smrg * permit persons to whom the Software is furnished to do so, subject to 113bfa90b6Smrg * the following conditions: 123bfa90b6Smrg * 133bfa90b6Smrg * The above copyright notice and this permission notice (including the 143bfa90b6Smrg * next paragraph) shall be included in all copies or substantial portions 153bfa90b6Smrg * of the Software. 163bfa90b6Smrg * 173bfa90b6Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 183bfa90b6Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 193bfa90b6Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 203bfa90b6Smrg * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 213bfa90b6Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 223bfa90b6Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 233bfa90b6Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 243bfa90b6Smrg * 253bfa90b6Smrg * Author: Thomas Hellstrom <thellstrom@vmware.com> 263bfa90b6Smrg */ 273bfa90b6Smrg 283bfa90b6Smrg#include <xorg-server.h> 2922f7e8e5Smrg#include <xorgVersion.h> 303bfa90b6Smrg#include <mi.h> 313bfa90b6Smrg#include <fb.h> 323bfa90b6Smrg#include <xa_context.h> 333bfa90b6Smrg#include "vmwgfx_saa.h" 343bfa90b6Smrg#include "vmwgfx_drmi.h" 353bfa90b6Smrg#include "vmwgfx_saa_priv.h" 3625dbecb6Smrg#include <xf86drmMode.h> 373bfa90b6Smrg 383bfa90b6Smrg/* 393bfa90b6Smrg * Damage to be added as soon as we attach storage to the pixmap. 403bfa90b6Smrg */ 413bfa90b6Smrgstatic Bool 423bfa90b6Smrgvmwgfx_pixmap_add_damage(PixmapPtr pixmap) 433bfa90b6Smrg{ 443bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 453bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 463bfa90b6Smrg DrawablePtr draw = &pixmap->drawable; 473bfa90b6Smrg BoxRec box; 483bfa90b6Smrg 493bfa90b6Smrg if (spix->damage) 503bfa90b6Smrg return TRUE; 513bfa90b6Smrg 523bfa90b6Smrg if (!saa_add_damage(pixmap)) 533bfa90b6Smrg return FALSE; 543bfa90b6Smrg 553bfa90b6Smrg box.x1 = 0; 563bfa90b6Smrg box.x2 = draw->width; 573bfa90b6Smrg box.y1 = 0; 583bfa90b6Smrg box.y2 = draw->height; 593bfa90b6Smrg 603bfa90b6Smrg if (vpix->hw) { 613bfa90b6Smrg REGION_RESET(draw->pScreen, &spix->dirty_hw, &box); 623bfa90b6Smrg REGION_EMPTY(draw->pScreen, &spix->dirty_shadow); 633bfa90b6Smrg } else { 643bfa90b6Smrg REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box); 653bfa90b6Smrg REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 663bfa90b6Smrg } 673bfa90b6Smrg 683bfa90b6Smrg return TRUE; 693bfa90b6Smrg} 703bfa90b6Smrg 713bfa90b6Smrgstatic void 723bfa90b6Smrgvmwgfx_pixmap_remove_damage(PixmapPtr pixmap) 733bfa90b6Smrg{ 743bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 753bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 763bfa90b6Smrg 773bfa90b6Smrg if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc) 783bfa90b6Smrg return; 793bfa90b6Smrg 8022f7e8e5Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 8122f7e8e5Smrg DamageUnregister(spix->damage); 8222f7e8e5Smrg#else 833bfa90b6Smrg DamageUnregister(&pixmap->drawable, spix->damage); 8422f7e8e5Smrg#endif 8522f7e8e5Smrg 863bfa90b6Smrg DamageDestroy(spix->damage); 873bfa90b6Smrg spix->damage = NULL; 883bfa90b6Smrg} 893bfa90b6Smrg 903bfa90b6Smrgstatic void 913bfa90b6Smrgvmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix) 923bfa90b6Smrg{ 933bfa90b6Smrg if (vpix->dirty_present) 943bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present); 953bfa90b6Smrg if (vpix->present_damage) 963bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage); 973bfa90b6Smrg if (vpix->pending_update) 983bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update); 993bfa90b6Smrg if (vpix->pending_present) 1003bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present); 1013bfa90b6Smrg vpix->dirty_present = NULL; 1023bfa90b6Smrg vpix->present_damage = NULL; 1033bfa90b6Smrg vpix->pending_update = NULL; 1043bfa90b6Smrg vpix->pending_present = NULL; 1053bfa90b6Smrg} 1063bfa90b6Smrg 1073bfa90b6Smrgstatic Bool 1083bfa90b6Smrgvmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt) 1093bfa90b6Smrg{ 1103bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1113bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 1123bfa90b6Smrg (void) pScreen; 1133bfa90b6Smrg 1143bfa90b6Smrg if (present_opt) { 1153bfa90b6Smrg vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0); 1163bfa90b6Smrg if (!vpix->dirty_present) 1173bfa90b6Smrg return FALSE; 1183bfa90b6Smrg vpix->present_damage = REGION_CREATE(pScreen, NULL, 0); 1193bfa90b6Smrg if (!vpix->present_damage) 1203bfa90b6Smrg goto out_no_present_damage; 1213bfa90b6Smrg } 1223bfa90b6Smrg vpix->pending_update = REGION_CREATE(pScreen, NULL, 0); 1233bfa90b6Smrg if (!vpix->pending_update) 1243bfa90b6Smrg goto out_no_pending_update; 1253bfa90b6Smrg vpix->pending_present = REGION_CREATE(pScreen, NULL, 0); 1263bfa90b6Smrg if (!vpix->pending_present) 1273bfa90b6Smrg goto out_no_pending_present; 1283bfa90b6Smrg 1293bfa90b6Smrg return TRUE; 1303bfa90b6Smrg out_no_pending_present: 1313bfa90b6Smrg REGION_DESTROY(pScreen, vpix->pending_update); 1323bfa90b6Smrg out_no_pending_update: 1333bfa90b6Smrg if (vpix->present_damage) 1343bfa90b6Smrg REGION_DESTROY(pScreen, vpix->present_damage); 1353bfa90b6Smrg out_no_present_damage: 1363bfa90b6Smrg if (vpix->dirty_present) 1373bfa90b6Smrg REGION_DESTROY(pScreen, vpix->dirty_present); 1383bfa90b6Smrg return FALSE; 1393bfa90b6Smrg} 1403bfa90b6Smrg 1413bfa90b6Smrgstatic void 1423bfa90b6Smrgvmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix) 1433bfa90b6Smrg{ 1443bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) { 1453bfa90b6Smrg free(vpix->malloc); 1463bfa90b6Smrg vpix->malloc = NULL; 1473bfa90b6Smrg } 1483bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) { 1493bfa90b6Smrg xa_surface_destroy(vpix->hw); 1503bfa90b6Smrg vpix->hw = NULL; 1513bfa90b6Smrg } 1523bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) { 1533bfa90b6Smrg vmwgfx_dmabuf_destroy(vpix->gmr); 1543bfa90b6Smrg vpix->gmr = NULL; 1553bfa90b6Smrg } 1563bfa90b6Smrg} 1573bfa90b6Smrg 1583bfa90b6Smrgstatic Bool 1593bfa90b6Smrgvmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 1603bfa90b6Smrg{ 1613bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1623bfa90b6Smrg size_t size; 1633bfa90b6Smrg struct vmwgfx_dmabuf *gmr; 1643bfa90b6Smrg void *addr; 1653bfa90b6Smrg 1663bfa90b6Smrg if (vpix->gmr) 1673bfa90b6Smrg return TRUE; 1683bfa90b6Smrg 1693bfa90b6Smrg size = pixmap->devKind * pixmap->drawable.height; 1703bfa90b6Smrg gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 1713bfa90b6Smrg if (!gmr) 1723bfa90b6Smrg return FALSE; 1733bfa90b6Smrg 1743bfa90b6Smrg if (vpix->malloc) { 1753bfa90b6Smrg 1763bfa90b6Smrg addr = vmwgfx_dmabuf_map(gmr); 1773bfa90b6Smrg if (!addr) 1783bfa90b6Smrg goto out_no_transfer; 1793bfa90b6Smrg memcpy(addr, vpix->malloc, size); 1803bfa90b6Smrg vmwgfx_dmabuf_unmap(gmr); 1813bfa90b6Smrg 1823bfa90b6Smrg } else if (!vmwgfx_pixmap_add_damage(pixmap)) 1833bfa90b6Smrg goto out_no_transfer; 1843bfa90b6Smrg 1853bfa90b6Smrg vpix->backing |= VMWGFX_PIX_GMR; 1863bfa90b6Smrg vpix->backing &= ~VMWGFX_PIX_MALLOC; 1873bfa90b6Smrg vpix->gmr = gmr; 1883bfa90b6Smrg 1893bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 1903bfa90b6Smrg 1913bfa90b6Smrg return TRUE; 1923bfa90b6Smrg 1933bfa90b6Smrg out_no_transfer: 1943bfa90b6Smrg vmwgfx_dmabuf_destroy(gmr); 1953bfa90b6Smrg return FALSE; 1963bfa90b6Smrg} 1973bfa90b6Smrg 1983bfa90b6Smrgstatic Bool 1993bfa90b6Smrgvmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 2003bfa90b6Smrg{ 2013bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 2023bfa90b6Smrg 2033bfa90b6Smrg if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR))) 2043bfa90b6Smrg return FALSE; 2053bfa90b6Smrg 2063bfa90b6Smrg if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) { 2073bfa90b6Smrg vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height); 2083bfa90b6Smrg if (!vpix->malloc) 2093bfa90b6Smrg goto out_no_malloc; 2103bfa90b6Smrg if (!vmwgfx_pixmap_add_damage(pixmap)) 2113bfa90b6Smrg goto out_no_damage; 2123bfa90b6Smrg } else if (vpix->backing & VMWGFX_PIX_GMR) 2133bfa90b6Smrg return vmwgfx_pixmap_create_gmr(vsaa, pixmap); 2143bfa90b6Smrg 2153bfa90b6Smrg return TRUE; 2163bfa90b6Smrg 2173bfa90b6Smrg out_no_damage: 2183bfa90b6Smrg free(vpix->malloc); 2193bfa90b6Smrg vpix->malloc = NULL; 2203bfa90b6Smrg out_no_malloc: 2213bfa90b6Smrg return FALSE; 2223bfa90b6Smrg} 2233bfa90b6Smrg 2243bfa90b6Smrg 2253bfa90b6Smrg/** 2263bfa90b6Smrg * 2273bfa90b6Smrg * Makes sure all presented contents covered by @region are read 2283bfa90b6Smrg * back and are present in a valid GMR. 2293bfa90b6Smrg */ 2303bfa90b6Smrg 2313bfa90b6Smrgstatic Bool 2323bfa90b6Smrgvmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa, 2333bfa90b6Smrg PixmapPtr pixmap, 2343bfa90b6Smrg RegionPtr region) 2353bfa90b6Smrg{ 2363bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 2373bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 2383bfa90b6Smrg RegionRec intersection; 2393bfa90b6Smrg 2403bfa90b6Smrg if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) || 2413bfa90b6Smrg !vpix->dirty_present) 2423bfa90b6Smrg return TRUE; 2433bfa90b6Smrg 2443bfa90b6Smrg /* 2453bfa90b6Smrg * Intersect dirty region with region to be read back, if any. 2463bfa90b6Smrg */ 2473bfa90b6Smrg 2483bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 2493bfa90b6Smrg REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw); 2503bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, 2513bfa90b6Smrg vpix->dirty_present); 2523bfa90b6Smrg 2533bfa90b6Smrg if (region) 2543bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region); 2553bfa90b6Smrg 2563bfa90b6Smrg if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection)) 2573bfa90b6Smrg goto out; 2583bfa90b6Smrg 2593bfa90b6Smrg /* 2603bfa90b6Smrg * Make really sure there is a GMR to read back to. 2613bfa90b6Smrg */ 2623bfa90b6Smrg 2633bfa90b6Smrg if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 2643bfa90b6Smrg goto out_err; 2653bfa90b6Smrg 2663bfa90b6Smrg if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id, 2673bfa90b6Smrg &intersection) != 0) 2683bfa90b6Smrg goto out_err; 2693bfa90b6Smrg 2703bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, 2713bfa90b6Smrg &spix->dirty_hw, &intersection); 2723bfa90b6Smrg out: 2733bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 2743bfa90b6Smrg return TRUE; 2753bfa90b6Smrg 2763bfa90b6Smrg out_err: 2773bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 2783bfa90b6Smrg return FALSE; 2793bfa90b6Smrg} 2803bfa90b6Smrg 2813bfa90b6Smrgstatic Bool 2823bfa90b6Smrgvmwgfx_saa_dma(struct vmwgfx_saa *vsaa, 2833bfa90b6Smrg PixmapPtr pixmap, 2843bfa90b6Smrg RegionPtr reg, 28522f7e8e5Smrg Bool to_hw, 28622f7e8e5Smrg int dx, 28722f7e8e5Smrg int dy, 28822f7e8e5Smrg struct xa_surface *srf) 2893bfa90b6Smrg{ 2903bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 2913bfa90b6Smrg 29222f7e8e5Smrg if (!srf) 29322f7e8e5Smrg srf = vpix->hw; 29422f7e8e5Smrg 29522f7e8e5Smrg if (!srf || (!vpix->gmr && !vpix->malloc)) 2963bfa90b6Smrg return TRUE; 2973bfa90b6Smrg 2983bfa90b6Smrg if (vpix->gmr && vsaa->can_optimize_dma) { 2993bfa90b6Smrg uint32_t handle, dummy; 3003bfa90b6Smrg 30122f7e8e5Smrg if (_xa_surface_handle(srf, &handle, &dummy) != 0) 3023bfa90b6Smrg goto out_err; 30322f7e8e5Smrg if (vmwgfx_dma(dx, dy, reg, vpix->gmr, pixmap->devKind, handle, 3043bfa90b6Smrg to_hw) != 0) 3053bfa90b6Smrg goto out_err; 3063bfa90b6Smrg } else { 30722f7e8e5Smrg uint8_t *data = (uint8_t *) vpix->malloc; 3083bfa90b6Smrg int ret; 3093bfa90b6Smrg 3103bfa90b6Smrg if (vpix->gmr) { 31122f7e8e5Smrg data = (uint8_t *) vmwgfx_dmabuf_map(vpix->gmr); 3123bfa90b6Smrg if (!data) 3133bfa90b6Smrg goto out_err; 3143bfa90b6Smrg } 3153bfa90b6Smrg 31622f7e8e5Smrg if (dx || dy) { 31722f7e8e5Smrg REGION_TRANSLATE(pScreen, reg, dx, dy); 31822f7e8e5Smrg data -= ((dx * pixmap->drawable.bitsPerPixel + 7)/8 + 31922f7e8e5Smrg dy * pixmap->devKind); 32022f7e8e5Smrg } 32122f7e8e5Smrg 32222f7e8e5Smrg ret = xa_surface_dma(vsaa->xa_ctx, srf, data, pixmap->devKind, 3233bfa90b6Smrg (int) to_hw, 3243bfa90b6Smrg (struct xa_box *) REGION_RECTS(reg), 3253bfa90b6Smrg REGION_NUM_RECTS(reg)); 32622f7e8e5Smrg if (to_hw) 32722f7e8e5Smrg xa_context_flush(vsaa->xa_ctx); 3283bfa90b6Smrg if (vpix->gmr) 3293bfa90b6Smrg vmwgfx_dmabuf_unmap(vpix->gmr); 33022f7e8e5Smrg if (dx || dy) 33122f7e8e5Smrg REGION_TRANSLATE(pScreen, reg, -dx, -dy); 3323bfa90b6Smrg if (ret) 3333bfa90b6Smrg goto out_err; 3343bfa90b6Smrg } 3353bfa90b6Smrg return TRUE; 3363bfa90b6Smrg out_err: 3373bfa90b6Smrg LogMessage(X_ERROR, "DMA %s surface failed.\n", 3383bfa90b6Smrg to_hw ? "to" : "from"); 3393bfa90b6Smrg return FALSE; 3403bfa90b6Smrg} 3413bfa90b6Smrg 3423bfa90b6Smrg 3433bfa90b6Smrgstatic Bool 3443bfa90b6Smrgvmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap, 3453bfa90b6Smrg RegionPtr readback) 3463bfa90b6Smrg{ 3473bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 3483bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 3493bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 3503bfa90b6Smrg 3513bfa90b6Smrg RegionRec intersection; 3523bfa90b6Smrg 3533bfa90b6Smrg if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback)) 3543bfa90b6Smrg return FALSE; 3553bfa90b6Smrg 3563bfa90b6Smrg if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw)) 3573bfa90b6Smrg return TRUE; 3583bfa90b6Smrg 3593bfa90b6Smrg if (!vpix->hw) 3603bfa90b6Smrg return TRUE; 3613bfa90b6Smrg 3623bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 3633bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, readback, 3643bfa90b6Smrg &spix->dirty_hw); 3653bfa90b6Smrg readback = &intersection; 3663bfa90b6Smrg 3673bfa90b6Smrg if (!vmwgfx_pixmap_create_sw(vsaa, pixmap)) 3683bfa90b6Smrg goto out_err; 3693bfa90b6Smrg 37022f7e8e5Smrg if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE, 0, 0, NULL)) 3713bfa90b6Smrg goto out_err; 3723bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback); 3733bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 37425dbecb6Smrg 3753bfa90b6Smrg return TRUE; 3763bfa90b6Smrg out_err: 3773bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 3783bfa90b6Smrg return FALSE; 3793bfa90b6Smrg} 3803bfa90b6Smrg 3813bfa90b6Smrg 3823bfa90b6Smrgstatic Bool 3833bfa90b6Smrgvmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap, 3843bfa90b6Smrg RegionPtr upload) 3853bfa90b6Smrg{ 38622f7e8e5Smrg return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE, 38722f7e8e5Smrg 0, 0, NULL); 3883bfa90b6Smrg} 3893bfa90b6Smrg 3903bfa90b6Smrgstatic void 3913bfa90b6Smrgvmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 3923bfa90b6Smrg{ 3933bfa90b6Smrg // LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n", 3943bfa90b6Smrg // (unsigned long) pixmap, (unsigned) access); 3953bfa90b6Smrg} 3963bfa90b6Smrg 3973bfa90b6Smrgstatic void * 3983bfa90b6Smrgvmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 3993bfa90b6Smrg{ 4003bfa90b6Smrg /* 4013bfa90b6Smrg * Errors in this functions will turn up in subsequent map 4023bfa90b6Smrg * calls. 4033bfa90b6Smrg */ 4043bfa90b6Smrg 4053bfa90b6Smrg (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap); 4063bfa90b6Smrg 4073bfa90b6Smrg return NULL; 4083bfa90b6Smrg} 4093bfa90b6Smrg 4103bfa90b6Smrgstatic void * 4113bfa90b6Smrgvmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 4123bfa90b6Smrg{ 4133bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 4143bfa90b6Smrg 4153bfa90b6Smrg if (vpix->malloc) 4163bfa90b6Smrg return vpix->malloc; 4173bfa90b6Smrg else if (vpix->gmr) 4183bfa90b6Smrg return vmwgfx_dmabuf_map(vpix->gmr); 4193bfa90b6Smrg else 4203bfa90b6Smrg return NULL; 4213bfa90b6Smrg} 4223bfa90b6Smrg 4233bfa90b6Smrgstatic void 4243bfa90b6Smrgvmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 4253bfa90b6Smrg{ 4263bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 4273bfa90b6Smrg 4283bfa90b6Smrg if (vpix->gmr) 4293bfa90b6Smrg return vmwgfx_dmabuf_unmap(vpix->gmr); 4303bfa90b6Smrg 4313bfa90b6Smrg// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n", 4323bfa90b6Smrg // (unsigned long) pixmap, (unsigned) access); 4333bfa90b6Smrg ; 4343bfa90b6Smrg} 4353bfa90b6Smrg 4363bfa90b6Smrgstatic Bool 4373bfa90b6Smrgvmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix, 4383bfa90b6Smrg int w, int h, int depth, 4393bfa90b6Smrg unsigned int usage_hint, int bpp, int *new_pitch) 4403bfa90b6Smrg{ 4413bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 4423bfa90b6Smrg 4433bfa90b6Smrg *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 4443bfa90b6Smrg 4453bfa90b6Smrg WSBMINITLISTHEAD(&vpix->sync_x_head); 4463bfa90b6Smrg WSBMINITLISTHEAD(&vpix->scanout_list); 44722f7e8e5Smrg WSBMINITLISTHEAD(&vpix->pixmap_list); 4483bfa90b6Smrg 4493bfa90b6Smrg return TRUE; 4503bfa90b6Smrg} 4513bfa90b6Smrg 4523bfa90b6SmrgBool 4533bfa90b6Smrgvmwgfx_hw_kill(struct vmwgfx_saa *vsaa, 4543bfa90b6Smrg struct saa_pixmap *spix) 4553bfa90b6Smrg{ 4563bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 4573bfa90b6Smrg 4583bfa90b6Smrg if (!vpix->hw) 4593bfa90b6Smrg return TRUE; 4603bfa90b6Smrg 4613bfa90b6Smrg /* 4623bfa90b6Smrg * Read back any dirty regions from hardware. 4633bfa90b6Smrg */ 4643bfa90b6Smrg 4653bfa90b6Smrg if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 4663bfa90b6Smrg &spix->dirty_hw)) 4673bfa90b6Smrg return FALSE; 4683bfa90b6Smrg 4693bfa90b6Smrg xa_surface_destroy(vpix->hw); 4703bfa90b6Smrg vpix->hw = NULL; 4713bfa90b6Smrg 4723bfa90b6Smrg /* 4733bfa90b6Smrg * Remove damage tracking if this is not a scanout pixmap. 4743bfa90b6Smrg */ 4753bfa90b6Smrg 4763bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) 4773bfa90b6Smrg vmwgfx_pixmap_remove_damage(spix->pixmap); 4783bfa90b6Smrg 4793bfa90b6Smrg return TRUE; 4803bfa90b6Smrg} 4813bfa90b6Smrg 4823bfa90b6Smrgvoid 4833bfa90b6Smrgvmwgfx_flush_dri2(ScreenPtr pScreen) 4843bfa90b6Smrg{ 4853bfa90b6Smrg struct vmwgfx_saa *vsaa = 4863bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pScreen)); 4873bfa90b6Smrg struct _WsbmListHead *list, *next; 4883bfa90b6Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 4893bfa90b6Smrg 4903bfa90b6Smrg if (!pScrn->vtSema) 4913bfa90b6Smrg return; 4923bfa90b6Smrg 4933bfa90b6Smrg WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { 4943bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = 4953bfa90b6Smrg WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); 4963bfa90b6Smrg struct saa_pixmap *spix = &vpix->base; 4973bfa90b6Smrg PixmapPtr pixmap = spix->pixmap; 4983bfa90b6Smrg 4993bfa90b6Smrg if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { 5003bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 5013bfa90b6Smrg WSBMLISTDELINIT(list); 5023bfa90b6Smrg } 5033bfa90b6Smrg } 5043bfa90b6Smrg} 5053bfa90b6Smrg 5063bfa90b6Smrg 5073bfa90b6Smrgstatic void 5083bfa90b6Smrgvmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap) 5093bfa90b6Smrg{ 5103bfa90b6Smrg ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen; 5113bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 5123bfa90b6Smrg (void) pScreen; 5133bfa90b6Smrg 5143bfa90b6Smrg vpix->backing = 0; 5153bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 5163bfa90b6Smrg 5173bfa90b6Smrg /* 5183bfa90b6Smrg * Any damage we've registered has already been removed by the server 5193bfa90b6Smrg * at this point. Any attempt to unregister / destroy it will result 5203bfa90b6Smrg * in a double free. 5213bfa90b6Smrg */ 5223bfa90b6Smrg 5233bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 52422f7e8e5Smrg WSBMLISTDELINIT(&vpix->pixmap_list); 5253bfa90b6Smrg WSBMLISTDELINIT(&vpix->sync_x_head); 5263bfa90b6Smrg} 5273bfa90b6Smrg 5283bfa90b6Smrg 5293bfa90b6Smrg 5303bfa90b6Smrg/** 5313bfa90b6Smrg * 5323bfa90b6Smrg * Makes sure we have a surface with valid contents. 5333bfa90b6Smrg */ 5343bfa90b6Smrg 5353bfa90b6Smrgstatic void 5363bfa90b6Smrgvmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch, 5373bfa90b6Smrg unsigned int src_pitch, unsigned int dst_height, 5383bfa90b6Smrg unsigned int src_height) 5393bfa90b6Smrg{ 5403bfa90b6Smrg unsigned int i; 5413bfa90b6Smrg unsigned int height = (dst_height < src_height) ? dst_height : src_height; 5423bfa90b6Smrg unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch; 5433bfa90b6Smrg 5443bfa90b6Smrg for(i=0; i<height; ++i) { 5453bfa90b6Smrg memcpy(dst, src, pitch); 5463bfa90b6Smrg dst += dst_pitch; 5473bfa90b6Smrg src += src_pitch; 5483bfa90b6Smrg } 5493bfa90b6Smrg} 5503bfa90b6Smrg 5513bfa90b6Smrg 5523bfa90b6Smrgstatic Bool 5533bfa90b6Smrgvmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch, 5543bfa90b6Smrg unsigned int old_height, unsigned int old_width) 5553bfa90b6Smrg{ 5563bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 5573bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 5583bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 5593bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 5603bfa90b6Smrg DrawablePtr draw = &pixmap->drawable; 5613bfa90b6Smrg unsigned int size = pixmap->devKind * draw->height; 5623bfa90b6Smrg BoxRec b_box; 5633bfa90b6Smrg RegionRec b_reg; 5643bfa90b6Smrg 5653bfa90b6Smrg /* 5663bfa90b6Smrg * Ignore copying errors. At worst they will show up as rendering 5673bfa90b6Smrg * artefacts. 5683bfa90b6Smrg */ 5693bfa90b6Smrg 5703bfa90b6Smrg if (vpix->malloc) { 5713bfa90b6Smrg 5723bfa90b6Smrg void *new_malloc = malloc(size); 5733bfa90b6Smrg if (!new_malloc) 5743bfa90b6Smrg return FALSE; 5753bfa90b6Smrg 5763bfa90b6Smrg vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind, 5773bfa90b6Smrg old_pitch, draw->height, 5783bfa90b6Smrg old_height); 5793bfa90b6Smrg free(vpix->malloc); 5803bfa90b6Smrg vpix->malloc = new_malloc; 5813bfa90b6Smrg } 5823bfa90b6Smrg 5833bfa90b6Smrg if (vpix->gmr) { 5843bfa90b6Smrg struct vmwgfx_dmabuf *gmr; 5853bfa90b6Smrg void *new_addr; 5863bfa90b6Smrg void *old_addr; 5873bfa90b6Smrg 5883bfa90b6Smrg gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 5893bfa90b6Smrg if (!gmr) 5903bfa90b6Smrg return FALSE; 5913bfa90b6Smrg 5923bfa90b6Smrg new_addr = vmwgfx_dmabuf_map(gmr); 5933bfa90b6Smrg old_addr = vmwgfx_dmabuf_map(vpix->gmr); 5943bfa90b6Smrg 5953bfa90b6Smrg if (new_addr && old_addr) 5963bfa90b6Smrg vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind, 5973bfa90b6Smrg old_pitch, draw->height, 5983bfa90b6Smrg old_height); 5993bfa90b6Smrg else 6003bfa90b6Smrg LogMessage(X_ERROR, "Failed pixmap resize copy.\n"); 6013bfa90b6Smrg 6023bfa90b6Smrg if (old_addr) 6033bfa90b6Smrg vmwgfx_dmabuf_unmap(vpix->gmr); 6043bfa90b6Smrg if (new_addr) 6053bfa90b6Smrg vmwgfx_dmabuf_unmap(gmr); 6063bfa90b6Smrg vmwgfx_dmabuf_destroy(vpix->gmr); 6073bfa90b6Smrg vpix->gmr = gmr; 6083bfa90b6Smrg } 6093bfa90b6Smrg 6103bfa90b6Smrg if (vpix->hw) { 611591e32d7Ssnj if (!vmwgfx_xa_surface_redefine(vpix, vpix->hw, draw->width, 612591e32d7Ssnj draw->height, draw->depth, xa_type_argb, 613591e32d7Ssnj xa_format_unknown, vpix->xa_flags, 1)) 6143bfa90b6Smrg return FALSE; 6153bfa90b6Smrg } 6163bfa90b6Smrg 6173bfa90b6Smrg b_box.x1 = 0; 6183bfa90b6Smrg b_box.x2 = draw->width; 6193bfa90b6Smrg b_box.y1 = 0; 6203bfa90b6Smrg b_box.y2 = draw->height; 6213bfa90b6Smrg 6223bfa90b6Smrg REGION_INIT(pScreen, &b_reg, &b_box, 1); 6233bfa90b6Smrg REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, 6243bfa90b6Smrg &b_reg); 6253bfa90b6Smrg REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); 6263bfa90b6Smrg if (vpix->dirty_present) 6273bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, 6283bfa90b6Smrg &b_reg); 6293bfa90b6Smrg if (vpix->pending_update) 6303bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, 6313bfa90b6Smrg &b_reg); 6323bfa90b6Smrg if (vpix->pending_present) 6333bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->pending_present, 6343bfa90b6Smrg vpix->pending_present, &b_reg); 6353bfa90b6Smrg if (vpix->present_damage) 6363bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, 6373bfa90b6Smrg &b_reg); 6383bfa90b6Smrg 6393bfa90b6Smrg REGION_UNINIT(pScreen, &b_reg); 6403bfa90b6Smrg 6413bfa90b6Smrg return TRUE; 6423bfa90b6Smrg} 6433bfa90b6Smrg 6443bfa90b6Smrg 6453bfa90b6Smrgstatic Bool 6463bfa90b6Smrgvmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth, 6473bfa90b6Smrg int bpp, int devkind, void *pixdata) 6483bfa90b6Smrg{ 6493bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 65022f7e8e5Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 65122f7e8e5Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 6523bfa90b6Smrg unsigned int old_height; 6533bfa90b6Smrg unsigned int old_width; 6543bfa90b6Smrg unsigned int old_pitch; 6553bfa90b6Smrg 6563bfa90b6Smrg if (!vpix) { 6573bfa90b6Smrg LogMessage(X_ERROR, "Not an SAA pixmap.\n"); 6583bfa90b6Smrg return FALSE; 6593bfa90b6Smrg } 6603bfa90b6Smrg 6613bfa90b6Smrg if (pixdata) { 6623bfa90b6Smrg vpix->backing = 0; 6633bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 6643bfa90b6Smrg return FALSE; 6653bfa90b6Smrg } 6663bfa90b6Smrg 6673bfa90b6Smrg if (depth <= 0) 6683bfa90b6Smrg depth = pixmap->drawable.depth; 6693bfa90b6Smrg 6703bfa90b6Smrg if (bpp <= 0) 6713bfa90b6Smrg bpp = pixmap->drawable.bitsPerPixel; 6723bfa90b6Smrg 6733bfa90b6Smrg if (w <= 0) 6743bfa90b6Smrg w = pixmap->drawable.width; 6753bfa90b6Smrg 6763bfa90b6Smrg if (h <= 0) 6773bfa90b6Smrg h = pixmap->drawable.height; 6783bfa90b6Smrg 6793bfa90b6Smrg if (w <= 0 || h <= 0 || depth <= 0) 6803bfa90b6Smrg return FALSE; 6813bfa90b6Smrg 6823bfa90b6Smrg old_height = pixmap->drawable.height; 6833bfa90b6Smrg old_width = pixmap->drawable.width; 6843bfa90b6Smrg old_pitch = pixmap->devKind; 6853bfa90b6Smrg 6863bfa90b6Smrg if (!miModifyPixmapHeader(pixmap, w, h, depth, 6873bfa90b6Smrg bpp, devkind, NULL)) 6883bfa90b6Smrg goto out_no_modify; 6893bfa90b6Smrg 6903bfa90b6Smrg if (!vpix->backing) 6913bfa90b6Smrg vpix->backing = VMWGFX_PIX_MALLOC; 6923bfa90b6Smrg 6933bfa90b6Smrg vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width); 6943bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 695591e32d7Ssnj if (WSBMLISTEMPTY(&vpix->pixmap_list)) 696591e32d7Ssnj WSBMLISTADDTAIL(&vpix->pixmap_list, &vsaa->pixmaps); 69722f7e8e5Smrg 6983bfa90b6Smrg return TRUE; 6993bfa90b6Smrg 7003bfa90b6Smrg out_no_modify: 7013bfa90b6Smrg return FALSE; 7023bfa90b6Smrg} 7033bfa90b6Smrg 7043bfa90b6Smrgstatic Bool 7053bfa90b6Smrgvmwgfx_present_prepare(struct vmwgfx_saa *vsaa, 7063bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix, 7073bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix) 7083bfa90b6Smrg{ 7093bfa90b6Smrg ScreenPtr pScreen = vsaa->pScreen; 7103bfa90b6Smrg unsigned int dummy; 7113bfa90b6Smrg 7123bfa90b6Smrg (void) pScreen; 7133bfa90b6Smrg if (src_vpix == dst_vpix || !src_vpix->hw || 71422f7e8e5Smrg _xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0) 7153bfa90b6Smrg return FALSE; 7163bfa90b6Smrg 7173bfa90b6Smrg REGION_NULL(pScreen, &vsaa->present_region); 7183bfa90b6Smrg vsaa->diff_valid = FALSE; 7193bfa90b6Smrg vsaa->dst_vpix = dst_vpix; 7203bfa90b6Smrg vsaa->present_flush(pScreen); 7213bfa90b6Smrg 7223bfa90b6Smrg return TRUE; 7233bfa90b6Smrg} 7243bfa90b6Smrg 7253bfa90b6Smrg/** 7263bfa90b6Smrg * Determine whether we should try present copies on this pixmap. 7273bfa90b6Smrg */ 7283bfa90b6Smrg 7293bfa90b6Smrgstatic Bool 7303bfa90b6Smrgvmwgfx_is_present_hw(PixmapPtr pixmap) 7313bfa90b6Smrg{ 7323bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 7333bfa90b6Smrg return (vpix->dirty_present != NULL); 7343bfa90b6Smrg} 7353bfa90b6Smrg 7363bfa90b6Smrgstatic void 7373bfa90b6Smrgvmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa, 7383bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix, 7393bfa90b6Smrg RegionPtr region, 7403bfa90b6Smrg Bool *has_dirty_hw, 7413bfa90b6Smrg Bool *has_valid_hw) 7423bfa90b6Smrg{ 7433bfa90b6Smrg RegionRec intersection; 7443bfa90b6Smrg 7453bfa90b6Smrg 7463bfa90b6Smrg if (!vpix->hw) { 7473bfa90b6Smrg *has_dirty_hw = FALSE; 7483bfa90b6Smrg *has_valid_hw = FALSE; 7493bfa90b6Smrg return; 7503bfa90b6Smrg } 7513bfa90b6Smrg 7523bfa90b6Smrg if (!region) { 7533bfa90b6Smrg *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, 7543bfa90b6Smrg &vpix->base.dirty_hw); 7553bfa90b6Smrg *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, 7563bfa90b6Smrg &vpix->base.dirty_shadow); 7573bfa90b6Smrg return; 7583bfa90b6Smrg } 7593bfa90b6Smrg 7603bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 7613bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw, 7623bfa90b6Smrg region); 7633bfa90b6Smrg *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection); 7643bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow, 7653bfa90b6Smrg region); 7663bfa90b6Smrg *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection); 7673bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 7683bfa90b6Smrg} 7693bfa90b6Smrg 77022f7e8e5Smrg/** 77122f7e8e5Smrg * vmwgfx_prefer_gmr: Prefer a dma buffer over malloced memory for software 77222f7e8e5Smrg * rendered storage 77322f7e8e5Smrg * 77422f7e8e5Smrg * @vsaa: Pointer to a struct vmwgfx_saa accelerator. 77522f7e8e5Smrg * @pixmap: Pointer to pixmap whose storage preference we want to alter. 77622f7e8e5Smrg * 77722f7e8e5Smrg * If possible, alter the storage or future storage of the software contents 77822f7e8e5Smrg * of this pixmap to be in a DMA buffer rather than in malloced memory. 77922f7e8e5Smrg * This function should be called when it's likely that frequent DMA operations 78022f7e8e5Smrg * will occur between a surface and the memory holding the software 78122f7e8e5Smrg * contents. 78222f7e8e5Smrg */ 78322f7e8e5Smrgstatic void 78422f7e8e5Smrgvmwgfx_prefer_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 78522f7e8e5Smrg{ 78622f7e8e5Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 78722f7e8e5Smrg 78822f7e8e5Smrg if (vsaa->can_optimize_dma) { 78922f7e8e5Smrg if (vpix->malloc) { 79022f7e8e5Smrg (void) vmwgfx_pixmap_create_gmr(vsaa, pixmap); 79122f7e8e5Smrg } else if (vpix->backing & VMWGFX_PIX_MALLOC) { 79222f7e8e5Smrg vpix->backing |= VMWGFX_PIX_GMR; 79322f7e8e5Smrg vpix->backing &= ~VMWGFX_PIX_MALLOC; 79422f7e8e5Smrg } 79522f7e8e5Smrg } 79622f7e8e5Smrg} 7973bfa90b6Smrg 7983bfa90b6SmrgBool 7993bfa90b6Smrgvmwgfx_create_hw(struct vmwgfx_saa *vsaa, 80025dbecb6Smrg PixmapPtr pixmap, 80125dbecb6Smrg Bool shared) 8023bfa90b6Smrg{ 8033bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 8043bfa90b6Smrg struct xa_surface *hw; 8053bfa90b6Smrg uint32_t new_flags; 8063bfa90b6Smrg 8073bfa90b6Smrg if (!vsaa->xat) 8083bfa90b6Smrg return FALSE; 8093bfa90b6Smrg 81025dbecb6Smrg if (!shared) { 81125dbecb6Smrg if (vpix->hw) 81225dbecb6Smrg return TRUE; 81325dbecb6Smrg 81425dbecb6Smrg new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | 81525dbecb6Smrg vpix->staging_add_flags | XA_FLAG_SHARED; 8163bfa90b6Smrg 81725dbecb6Smrg hw = xa_surface_create(vsaa->xat, 81825dbecb6Smrg pixmap->drawable.width, 81925dbecb6Smrg pixmap->drawable.height, 82025dbecb6Smrg 0, 82125dbecb6Smrg xa_type_other, 82225dbecb6Smrg vpix->staging_format, 82325dbecb6Smrg new_flags); 82425dbecb6Smrg } else { 82525dbecb6Smrg new_flags = vpix->xa_flags; 82625dbecb6Smrg hw = vpix->hw; 82725dbecb6Smrg } 8283bfa90b6Smrg 8293bfa90b6Smrg if (hw == NULL) 8303bfa90b6Smrg return FALSE; 8313bfa90b6Smrg 8323bfa90b6Smrg vpix->xa_flags = new_flags; 833591e32d7Ssnj vpix->hw = hw; 8343bfa90b6Smrg 8353bfa90b6Smrg if (!vmwgfx_pixmap_add_damage(pixmap)) 8363bfa90b6Smrg goto out_no_damage; 8373bfa90b6Smrg 8383bfa90b6Smrg vpix->backing |= VMWGFX_PIX_SURFACE; 8393bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 8403bfa90b6Smrg 84122f7e8e5Smrg /* 84222f7e8e5Smrg * If there is a HW surface, make sure that the shadow is 84322f7e8e5Smrg * (or will be) a GMR, provided we can do fast DMAs from / to it. 84422f7e8e5Smrg */ 84522f7e8e5Smrg vmwgfx_prefer_gmr(vsaa, pixmap); 84622f7e8e5Smrg 8473bfa90b6Smrg return TRUE; 8483bfa90b6Smrg 8493bfa90b6Smrgout_no_damage: 850591e32d7Ssnj vpix->hw = NULL; 8513bfa90b6Smrg xa_surface_destroy(hw); 8523bfa90b6Smrg return FALSE; 8533bfa90b6Smrg} 8543bfa90b6Smrg 8553bfa90b6Smrg 8563bfa90b6SmrgBool 8573bfa90b6Smrgvmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) 8583bfa90b6Smrg{ 8593bfa90b6Smrg struct vmwgfx_saa *vsaa = 8603bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 8613bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 8623bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 8633bfa90b6Smrg RegionRec intersection; 8643bfa90b6Smrg 8653bfa90b6Smrg if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region)) 8663bfa90b6Smrg return FALSE; 8673bfa90b6Smrg 8683bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 8693bfa90b6Smrg REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow); 8703bfa90b6Smrg 8713bfa90b6Smrg if (vpix->dirty_present) 8723bfa90b6Smrg REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present, 8733bfa90b6Smrg &spix->dirty_shadow); 8743bfa90b6Smrg 8753bfa90b6Smrg if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) { 8763bfa90b6Smrg RegionPtr upload = &intersection; 8773bfa90b6Smrg 8783bfa90b6Smrg /* 8793bfa90b6Smrg * Check whether we need to upload from GMR. 8803bfa90b6Smrg */ 8813bfa90b6Smrg 8823bfa90b6Smrg if (region) { 8833bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, region, 8843bfa90b6Smrg &intersection); 8853bfa90b6Smrg upload = &intersection; 8863bfa90b6Smrg } 8873bfa90b6Smrg 8883bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, upload)) { 8893bfa90b6Smrg Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload); 8903bfa90b6Smrg if (ret) { 8913bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow, 8923bfa90b6Smrg &spix->dirty_shadow, upload); 8933bfa90b6Smrg if (vpix->dirty_present) 8943bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 8953bfa90b6Smrg vpix->dirty_present, upload); 8963bfa90b6Smrg } else { 8973bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 8983bfa90b6Smrg return FALSE; 8993bfa90b6Smrg } 9003bfa90b6Smrg } 9013bfa90b6Smrg } 9023bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 9033bfa90b6Smrg return TRUE; 9043bfa90b6Smrg} 9053bfa90b6Smrg 9063bfa90b6Smrgstatic Bool 9073bfa90b6Smrgvmwgfx_copy_prepare(struct saa_driver *driver, 9083bfa90b6Smrg PixmapPtr src_pixmap, 9093bfa90b6Smrg PixmapPtr dst_pixmap, 9103bfa90b6Smrg int dx, 9113bfa90b6Smrg int dy, 9123bfa90b6Smrg int alu, 9133bfa90b6Smrg RegionPtr src_reg, 9143bfa90b6Smrg uint32_t plane_mask) 9153bfa90b6Smrg{ 9163bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 9173bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix; 9183bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix; 9193bfa90b6Smrg Bool has_dirty_hw; 9203bfa90b6Smrg Bool has_valid_hw; 9213bfa90b6Smrg 9223bfa90b6Smrg if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) || 92322f7e8e5Smrg alu != GXcopy || !vsaa->is_master) 9243bfa90b6Smrg return FALSE; 9253bfa90b6Smrg 9263bfa90b6Smrg src_vpix = vmwgfx_saa_pixmap(src_pixmap); 9273bfa90b6Smrg dst_vpix = vmwgfx_saa_pixmap(dst_pixmap); 9283bfa90b6Smrg 9293bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg, 9303bfa90b6Smrg &has_dirty_hw, &has_valid_hw); 9313bfa90b6Smrg 9323bfa90b6Smrg if (vmwgfx_is_present_hw(dst_pixmap) && 9333bfa90b6Smrg src_vpix->backing & VMWGFX_PIX_SURFACE) { 9343bfa90b6Smrg 9353bfa90b6Smrg if (!has_dirty_hw && !has_valid_hw) 9363bfa90b6Smrg return FALSE; 9373bfa90b6Smrg 9383bfa90b6Smrg if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) 9393bfa90b6Smrg return FALSE; 9403bfa90b6Smrg if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { 9413bfa90b6Smrg vsaa->present_copy = TRUE; 9423bfa90b6Smrg return TRUE; 9433bfa90b6Smrg } 9443bfa90b6Smrg return FALSE; 9453bfa90b6Smrg } 9463bfa90b6Smrg 9473bfa90b6Smrg vsaa->present_copy = FALSE; 9483bfa90b6Smrg if (src_vpix != dst_vpix) { 9493bfa90b6Smrg 9503bfa90b6Smrg /* 9513bfa90b6Smrg * Use hardware acceleration either if source is partially only 9523bfa90b6Smrg * in hardware, or if source is entirely in hardware and destination 9533bfa90b6Smrg * has a hardware surface. 9543bfa90b6Smrg */ 9553bfa90b6Smrg 9563bfa90b6Smrg if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL))) 9573bfa90b6Smrg return FALSE; 9583bfa90b6Smrg 9593bfa90b6Smrg /* 9603bfa90b6Smrg * Determine surface formats. 9613bfa90b6Smrg */ 9623bfa90b6Smrg 9633bfa90b6Smrg if (src_vpix->base.src_format == 0) { 9643bfa90b6Smrg if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 9653bfa90b6Smrg return FALSE; 9663bfa90b6Smrg } else { 9673bfa90b6Smrg if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || 9683bfa90b6Smrg !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) 9693bfa90b6Smrg return FALSE; 9703bfa90b6Smrg } 9713bfa90b6Smrg 9723bfa90b6Smrg if (dst_vpix->base.dst_format == 0) { 9733bfa90b6Smrg if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 9743bfa90b6Smrg return FALSE; 9753bfa90b6Smrg } else { 9763bfa90b6Smrg if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || 9773bfa90b6Smrg !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) 9783bfa90b6Smrg return FALSE; 9793bfa90b6Smrg } 9803bfa90b6Smrg 9813bfa90b6Smrg /* 9823bfa90b6Smrg * Create hardware surfaces. 9833bfa90b6Smrg */ 9843bfa90b6Smrg 9853bfa90b6Smrg if (!vmwgfx_hw_commit(src_pixmap)) 9863bfa90b6Smrg return FALSE; 9873bfa90b6Smrg if (!vmwgfx_hw_commit(dst_pixmap)) 9883bfa90b6Smrg return FALSE; 9893bfa90b6Smrg 9903bfa90b6Smrg /* 9913bfa90b6Smrg * Migrate data. 9923bfa90b6Smrg */ 9933bfa90b6Smrg 9943bfa90b6Smrg if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { 9953bfa90b6Smrg xa_copy_done(vsaa->xa_ctx); 99622f7e8e5Smrg xa_context_flush(vsaa->xa_ctx); 9973bfa90b6Smrg return FALSE; 9983bfa90b6Smrg } 9993bfa90b6Smrg 10003bfa90b6Smrg /* 10013bfa90b6Smrg * Setup copy state. 10023bfa90b6Smrg */ 10033bfa90b6Smrg 10043bfa90b6Smrg if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != 10053bfa90b6Smrg XA_ERR_NONE) 10063bfa90b6Smrg return FALSE; 10073bfa90b6Smrg 10083bfa90b6Smrg return TRUE; 10093bfa90b6Smrg } 10103bfa90b6Smrg 10113bfa90b6Smrg return FALSE; 10123bfa90b6Smrg} 10133bfa90b6Smrg 10143bfa90b6Smrg 10153bfa90b6Smrgstatic void 10163bfa90b6Smrgvmwgfx_present_done(struct vmwgfx_saa *vsaa) 10173bfa90b6Smrg{ 10183bfa90b6Smrg ScreenPtr pScreen = vsaa->pScreen; 10193bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix; 10203bfa90b6Smrg 10213bfa90b6Smrg (void) pScreen; 10223bfa90b6Smrg if (!vsaa->diff_valid) 10233bfa90b6Smrg return; 10243bfa90b6Smrg 10253bfa90b6Smrg (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id, 10263bfa90b6Smrg vsaa->xdiff, vsaa->ydiff, 10273bfa90b6Smrg &vsaa->present_region, vsaa->src_handle); 10283bfa90b6Smrg 10293bfa90b6Smrg REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff); 10303bfa90b6Smrg REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage, 10313bfa90b6Smrg &vsaa->present_region); 10323bfa90b6Smrg vsaa->diff_valid = FALSE; 10333bfa90b6Smrg REGION_UNINIT(pScreen, &vsaa->present_region); 10343bfa90b6Smrg} 10353bfa90b6Smrg 10363bfa90b6Smrgstatic void 10373bfa90b6Smrgvmwgfx_present_copy(struct vmwgfx_saa *vsaa, 10383bfa90b6Smrg int src_x, 10393bfa90b6Smrg int src_y, 10403bfa90b6Smrg int dst_x, 10413bfa90b6Smrg int dst_y, 10423bfa90b6Smrg int w, 10433bfa90b6Smrg int h) 10443bfa90b6Smrg{ 10453bfa90b6Smrg int xdiff = dst_x - src_x; 10463bfa90b6Smrg int ydiff = dst_y - src_y; 10473bfa90b6Smrg BoxRec box; 10483bfa90b6Smrg RegionRec reg; 10493bfa90b6Smrg 10503bfa90b6Smrg if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff))) 10513bfa90b6Smrg (void) vmwgfx_present_done(vsaa); 10523bfa90b6Smrg 10533bfa90b6Smrg if (!vsaa->diff_valid) { 10543bfa90b6Smrg vsaa->xdiff = xdiff; 10553bfa90b6Smrg vsaa->ydiff = ydiff; 10563bfa90b6Smrg vsaa->diff_valid = TRUE; 10573bfa90b6Smrg } 10583bfa90b6Smrg 10593bfa90b6Smrg box.x1 = src_x; 10603bfa90b6Smrg box.x2 = src_x + w; 10613bfa90b6Smrg box.y1 = src_y; 10623bfa90b6Smrg box.y2 = src_y + h; 10633bfa90b6Smrg 10643bfa90b6Smrg REGION_INIT(pScreen, ®, &box, 1); 10653bfa90b6Smrg REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); 10663bfa90b6Smrg REGION_UNINIT(pScreen, ®); 10673bfa90b6Smrg} 10683bfa90b6Smrg 10693bfa90b6Smrgstatic void 10703bfa90b6Smrgvmwgfx_copy(struct saa_driver *driver, 10713bfa90b6Smrg int src_x, 10723bfa90b6Smrg int src_y, 10733bfa90b6Smrg int dst_x, 10743bfa90b6Smrg int dst_y, 10753bfa90b6Smrg int w, 10763bfa90b6Smrg int h) 10773bfa90b6Smrg{ 10783bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 10793bfa90b6Smrg 10803bfa90b6Smrg if (vsaa->present_copy) { 10813bfa90b6Smrg vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h); 10823bfa90b6Smrg return; 10833bfa90b6Smrg } 10843bfa90b6Smrg xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h); 10853bfa90b6Smrg} 10863bfa90b6Smrg 10873bfa90b6Smrgstatic void 10883bfa90b6Smrgvmwgfx_copy_done(struct saa_driver *driver) 10893bfa90b6Smrg{ 10903bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 10913bfa90b6Smrg 10923bfa90b6Smrg if (vsaa->present_copy) { 10933bfa90b6Smrg vmwgfx_present_done(vsaa); 10943bfa90b6Smrg return; 10953bfa90b6Smrg } 10963bfa90b6Smrg xa_copy_done(vsaa->xa_ctx); 109722f7e8e5Smrg xa_context_flush(vsaa->xa_ctx); 10983bfa90b6Smrg} 10993bfa90b6Smrg 11003bfa90b6Smrgstatic Bool 11013bfa90b6Smrgvmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, 11023bfa90b6Smrg PicturePtr src_pict, PicturePtr mask_pict, 11033bfa90b6Smrg PicturePtr dst_pict, 11043bfa90b6Smrg PixmapPtr src_pix, PixmapPtr mask_pix, 11053bfa90b6Smrg PixmapPtr dst_pix, 11063bfa90b6Smrg RegionPtr src_region, 11073bfa90b6Smrg RegionPtr mask_region, 11083bfa90b6Smrg RegionPtr dst_region) 11093bfa90b6Smrg{ 11103bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 11113bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix; 11123bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix; 11133bfa90b6Smrg struct vmwgfx_saa_pixmap *mask_vpix; 11143bfa90b6Smrg Bool tmp_valid_hw; 11153bfa90b6Smrg Bool dirty_hw; 11163bfa90b6Smrg Bool valid_hw; 11173bfa90b6Smrg RegionRec empty; 11183bfa90b6Smrg struct xa_composite *xa_comp; 11193bfa90b6Smrg 112022f7e8e5Smrg if (!vsaa->is_master) 112122f7e8e5Smrg return FALSE; 112222f7e8e5Smrg 11233bfa90b6Smrg REGION_NULL(pScreen, &empty); 11243bfa90b6Smrg 11253bfa90b6Smrg /* 11263bfa90b6Smrg * First we define our migration policy. We accelerate only if there 11273bfa90b6Smrg * are dirty hw regions to be read or if all source data is 11283bfa90b6Smrg * available in hw, and the destination has a hardware surface. 11293bfa90b6Smrg */ 11303bfa90b6Smrg dst_vpix = vmwgfx_saa_pixmap(dst_pix); 11313bfa90b6Smrg valid_hw = (dst_vpix->hw != NULL); 11323bfa90b6Smrg if (saa_op_reads_destination(op)) { 11333bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, 11343bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 11353bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 11363bfa90b6Smrg } else { 11373bfa90b6Smrg dirty_hw = FALSE; 11383bfa90b6Smrg dst_region = ∅ 11393bfa90b6Smrg } 11403bfa90b6Smrg 11413bfa90b6Smrg if (src_pix && !dirty_hw) { 11423bfa90b6Smrg src_vpix = vmwgfx_saa_pixmap(src_pix); 11433bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, 11443bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 11453bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 11463bfa90b6Smrg } 11473bfa90b6Smrg 11483bfa90b6Smrg if (mask_pict && mask_pix && !dirty_hw) { 11493bfa90b6Smrg mask_vpix = vmwgfx_saa_pixmap(mask_pix); 11503bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, 11513bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 11523bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 11533bfa90b6Smrg } 11543bfa90b6Smrg 11553bfa90b6Smrg /* 11563bfa90b6Smrg * In rendercheck mode we try to accelerate all supported 11573bfa90b6Smrg * composite operations. 11583bfa90b6Smrg */ 11593bfa90b6Smrg 11603bfa90b6Smrg if (!valid_hw && !dirty_hw && !vsaa->rendercheck) 11613bfa90b6Smrg goto out_err; 11623bfa90b6Smrg 11633bfa90b6Smrg /* 11643bfa90b6Smrg * Then, setup most of the XA composite state (except hardware surfaces) 11653bfa90b6Smrg * and check whether XA can accelerate. 11663bfa90b6Smrg */ 11673bfa90b6Smrg 1168591e32d7Ssnj if (!mask_pix) 1169591e32d7Ssnj mask_pict = NULL; 11703bfa90b6Smrg xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, 11713bfa90b6Smrg src_pict, mask_pict, dst_pict); 11723bfa90b6Smrg if (!xa_comp) 11733bfa90b6Smrg goto out_err; 11743bfa90b6Smrg 11753bfa90b6Smrg if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) 11763bfa90b6Smrg goto out_err; 11773bfa90b6Smrg 11783bfa90b6Smrg /* 11793bfa90b6Smrg * Check that we can create the needed hardware surfaces. 11803bfa90b6Smrg */ 11813bfa90b6Smrg if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) 11823bfa90b6Smrg goto out_err; 11833bfa90b6Smrg if (mask_pict && mask_pix && 11843bfa90b6Smrg !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) 11853bfa90b6Smrg goto out_err; 11863bfa90b6Smrg if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) 11873bfa90b6Smrg goto out_err; 11883bfa90b6Smrg 11893bfa90b6Smrg /* 11903bfa90b6Smrg * Seems OK. Commit the changes, creating hardware surfaces. 11913bfa90b6Smrg */ 11923bfa90b6Smrg if (src_pix && !vmwgfx_hw_commit(src_pix)) 11933bfa90b6Smrg goto out_err; 11943bfa90b6Smrg if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) 11953bfa90b6Smrg goto out_err; 11963bfa90b6Smrg if (!vmwgfx_hw_commit(dst_pix)) 11973bfa90b6Smrg goto out_err; 11983bfa90b6Smrg 11993bfa90b6Smrg /* 12003bfa90b6Smrg * Update the XA state with our hardware surfaces and 12013bfa90b6Smrg * surface formats 12023bfa90b6Smrg */ 12033bfa90b6Smrg if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) 12043bfa90b6Smrg goto out_err; 12053bfa90b6Smrg 12063bfa90b6Smrg /* 12073bfa90b6Smrg * Migrate data to surfaces. 12083bfa90b6Smrg */ 12093bfa90b6Smrg if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) 12103bfa90b6Smrg goto out_err; 12113bfa90b6Smrg if (mask_pict && mask_pix && mask_region && 12123bfa90b6Smrg !vmwgfx_hw_validate(mask_pix, NULL)) 12133bfa90b6Smrg goto out_err; 12143bfa90b6Smrg if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) 12153bfa90b6Smrg goto out_err; 12163bfa90b6Smrg 12173bfa90b6Smrg 12183bfa90b6Smrg /* 12193bfa90b6Smrg * Bind the XA state. This must be done after data migration, since 12203bfa90b6Smrg * migration may change the hardware surfaces. 12213bfa90b6Smrg */ 12223bfa90b6Smrg if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) 12233bfa90b6Smrg goto out_err; 12243bfa90b6Smrg 12253bfa90b6Smrg return TRUE; 12263bfa90b6Smrg 12273bfa90b6Smrg out_err: 12283bfa90b6Smrg return FALSE; 12293bfa90b6Smrg} 12303bfa90b6Smrg 12313bfa90b6Smrgstatic void 12323bfa90b6Smrgvmwgfx_composite(struct saa_driver *driver, 12333bfa90b6Smrg int src_x, int src_y, int mask_x, int mask_y, 12343bfa90b6Smrg int dst_x, int dst_y, 12353bfa90b6Smrg int width, int height) 12363bfa90b6Smrg{ 12373bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12383bfa90b6Smrg 12393bfa90b6Smrg xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, 12403bfa90b6Smrg dst_x, dst_y, width, height); 12413bfa90b6Smrg} 12423bfa90b6Smrg 12433bfa90b6Smrgstatic void 12443bfa90b6Smrgvmwgfx_composite_done(struct saa_driver *driver) 12453bfa90b6Smrg{ 12463bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12473bfa90b6Smrg 12483bfa90b6Smrg xa_composite_done(vsaa->xa_ctx); 124922f7e8e5Smrg xa_context_flush(vsaa->xa_ctx); 12503bfa90b6Smrg} 12513bfa90b6Smrg 12523bfa90b6Smrgstatic void 12533bfa90b6Smrgvmwgfx_takedown(struct saa_driver *driver) 12543bfa90b6Smrg{ 12553bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12563bfa90b6Smrg 12573bfa90b6Smrg if (vsaa->vcomp) 12583bfa90b6Smrg vmwgfx_free_composite(vsaa->vcomp); 12593bfa90b6Smrg free(vsaa); 12603bfa90b6Smrg} 12613bfa90b6Smrg 12623bfa90b6Smrg/* 12633bfa90b6Smrg * This function call originates from the damage layer (outside SAA) 12643bfa90b6Smrg * to indicate that an operation is complete, and that damage is being 12653bfa90b6Smrg * processed. 12663bfa90b6Smrg */ 12673bfa90b6Smrgstatic void 12683bfa90b6Smrgvmwgfx_operation_complete(struct saa_driver *driver, 12693bfa90b6Smrg PixmapPtr pixmap) 12703bfa90b6Smrg{ 12713bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12723bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 12733bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 12743bfa90b6Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen); 12753bfa90b6Smrg 12763bfa90b6Smrg /* 12773bfa90b6Smrg * Make dri2 drawables up to date, or add them to the flush list 12783bfa90b6Smrg * executed at glxWaitX(). Currently glxWaitX() is broken, so 12793bfa90b6Smrg * we flush immediately, unless we're VT-switched away, in which 12803bfa90b6Smrg * case a flush would deadlock in the kernel. 128122f7e8e5Smrg * 128222f7e8e5Smrg * For pixmaps for which vpix->hw_is_hosted is true, we can explicitly 128322f7e8e5Smrg * inform the compositor when contents has changed, so for those pixmaps 128422f7e8e5Smrg * we defer the upload until the compositor is informed, by putting 128522f7e8e5Smrg * them on the sync_x_list. Note that hw_is_dri2_fronts take precedence. 12863bfa90b6Smrg */ 128722f7e8e5Smrg if (vpix->hw && (vpix->hw_is_dri2_fronts || vpix->hw_is_hosted)) { 128822f7e8e5Smrg if (pScrn->vtSema && vpix->hw_is_dri2_fronts && 12893bfa90b6Smrg vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { 12903bfa90b6Smrg 12913bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 12923bfa90b6Smrg return; 12933bfa90b6Smrg } 12943bfa90b6Smrg 12953bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->sync_x_head)) 12963bfa90b6Smrg WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); 12973bfa90b6Smrg } 12983bfa90b6Smrg} 12993bfa90b6Smrg 13003bfa90b6Smrg/* 13013bfa90b6Smrg * This function is called by SAA to indicate that SAA has 13023bfa90b6Smrg * dirtied a region of a pixmap, either as hw (accelerated) or as 13033bfa90b6Smrg * !hw (not accelerated). 13043bfa90b6Smrg */ 13053bfa90b6Smrgstatic Bool 13063bfa90b6Smrgvmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, 13073bfa90b6Smrg Bool hw, RegionPtr damage) 13083bfa90b6Smrg{ 13093bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 13103bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 13113bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 13123bfa90b6Smrg 13133bfa90b6Smrg /* 13143bfa90b6Smrg * Return if this is not a scanout pixmap. 13153bfa90b6Smrg */ 13163bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) 13173bfa90b6Smrg return TRUE; 13183bfa90b6Smrg 13193bfa90b6Smrg#if 0 13203bfa90b6Smrg /* 13213bfa90b6Smrg * This code can be enabled to immediately upload scanout sw 13223bfa90b6Smrg * contents to the hw surface. Otherwise this is done 13233bfa90b6Smrg * just before we call the kms update function for the hw 13243bfa90b6Smrg * surface. 13253bfa90b6Smrg */ 132634a0776dSmrg if (vpix->scanout_hw) { 13273bfa90b6Smrg if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) 13283bfa90b6Smrg return FALSE; 13293bfa90b6Smrg 13303bfa90b6Smrg REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, 13313bfa90b6Smrg &spix->dirty_shadow, damage); 13323bfa90b6Smrg hw = TRUE; 13333bfa90b6Smrg } 13343bfa90b6Smrg#endif 13353bfa90b6Smrg 13363bfa90b6Smrg /* 13373bfa90b6Smrg * Is the new scanout damage hw or sw? 13383bfa90b6Smrg */ 13393bfa90b6Smrg if (hw) { 13403bfa90b6Smrg /* 13413bfa90b6Smrg * Dump pending present into present tracking region. 13423bfa90b6Smrg */ 13433bfa90b6Smrg if (vpix->dirty_present && 13443bfa90b6Smrg REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) { 13453bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->dirty_present, 13463bfa90b6Smrg vpix->dirty_present, damage); 13473bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, vpix->present_damage); 13483bfa90b6Smrg } else { 13493bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) { 13503bfa90b6Smrg RegionRec reg; 13513bfa90b6Smrg 13523bfa90b6Smrg REGION_NULL(vsaa->pScreen, ®); 13533bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, 13543bfa90b6Smrg damage); 13553bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 13563bfa90b6Smrg vsaa->present_flush(vsaa->pScreen); 13573bfa90b6Smrg REGION_UNINIT(pScreen, ®); 13583bfa90b6Smrg } 13593bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->pending_present, 13603bfa90b6Smrg vpix->pending_present, damage); 13613bfa90b6Smrg if (vpix->dirty_present) 13623bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 13633bfa90b6Smrg vpix->dirty_present, damage); 13643bfa90b6Smrg } 13653bfa90b6Smrg } else { 13663bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { 13673bfa90b6Smrg RegionRec reg; 13683bfa90b6Smrg 13693bfa90b6Smrg REGION_NULL(vsaa->pScreen, ®); 13703bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, 13713bfa90b6Smrg damage); 13723bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 13733bfa90b6Smrg vsaa->present_flush(vsaa->pScreen); 13743bfa90b6Smrg REGION_UNINIT(pScreen, ®); 13753bfa90b6Smrg } 13763bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->pending_update, 13773bfa90b6Smrg vpix->pending_update, damage); 13783bfa90b6Smrg if (vpix->dirty_present) 13793bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 13803bfa90b6Smrg vpix->dirty_present, damage); 13813bfa90b6Smrg } 13823bfa90b6Smrg 13833bfa90b6Smrg return TRUE; 13843bfa90b6Smrg} 13853bfa90b6Smrg 13863bfa90b6Smrg 13873bfa90b6Smrgstatic const struct saa_driver vmwgfx_saa_driver = { 13883bfa90b6Smrg .saa_major = SAA_VERSION_MAJOR, 13893bfa90b6Smrg .saa_minor = SAA_VERSION_MINOR, 13903bfa90b6Smrg .pixmap_size = sizeof(struct vmwgfx_saa_pixmap), 13913bfa90b6Smrg .damage = vmwgfx_dirty, 13923bfa90b6Smrg .operation_complete = vmwgfx_operation_complete, 13933bfa90b6Smrg .download_from_hw = vmwgfx_download_from_hw, 13943bfa90b6Smrg .release_from_cpu = vmwgfx_release_from_cpu, 13953bfa90b6Smrg .sync_for_cpu = vmwgfx_sync_for_cpu, 13963bfa90b6Smrg .map = vmwgfx_map, 13973bfa90b6Smrg .unmap = vmwgfx_unmap, 13983bfa90b6Smrg .create_pixmap = vmwgfx_create_pixmap, 13993bfa90b6Smrg .destroy_pixmap = vmwgfx_destroy_pixmap, 14003bfa90b6Smrg .modify_pixmap_header = vmwgfx_modify_pixmap_header, 14013bfa90b6Smrg .copy_prepare = vmwgfx_copy_prepare, 14023bfa90b6Smrg .copy = vmwgfx_copy, 14033bfa90b6Smrg .copy_done = vmwgfx_copy_done, 14043bfa90b6Smrg .composite_prepare = vmwgfx_composite_prepare, 14053bfa90b6Smrg .composite = vmwgfx_composite, 14063bfa90b6Smrg .composite_done = vmwgfx_composite_done, 14073bfa90b6Smrg .takedown = vmwgfx_takedown, 14083bfa90b6Smrg}; 14093bfa90b6Smrg 14103bfa90b6Smrg 14113bfa90b6SmrgBool 14123bfa90b6Smrgvmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, 14133bfa90b6Smrg void (*present_flush)(ScreenPtr pScreen), 14143bfa90b6Smrg Bool direct_presents, 14153bfa90b6Smrg Bool only_hw_presents, 141634a0776dSmrg Bool rendercheck, 141734a0776dSmrg Bool has_screen_targets) 14183bfa90b6Smrg{ 14193bfa90b6Smrg struct vmwgfx_saa *vsaa; 14203bfa90b6Smrg 14213bfa90b6Smrg vsaa = calloc(1, sizeof(*vsaa)); 14223bfa90b6Smrg if (!vsaa) 14233bfa90b6Smrg return FALSE; 14243bfa90b6Smrg 14253bfa90b6Smrg if (xat == NULL) { 14263bfa90b6Smrg direct_presents = FALSE; 14273bfa90b6Smrg only_hw_presents = FALSE; 142834a0776dSmrg has_screen_targets = FALSE; 14293bfa90b6Smrg } 14303bfa90b6Smrg 14313bfa90b6Smrg vsaa->pScreen = pScreen; 14323bfa90b6Smrg vsaa->xat = xat; 14333bfa90b6Smrg if (xat) 14343bfa90b6Smrg vsaa->xa_ctx = xa_context_default(xat); 14353bfa90b6Smrg vsaa->drm_fd = drm_fd; 14363bfa90b6Smrg vsaa->present_flush = present_flush; 143722f7e8e5Smrg vsaa->can_optimize_dma = TRUE; 14383bfa90b6Smrg vsaa->use_present_opt = direct_presents; 14393bfa90b6Smrg vsaa->only_hw_presents = only_hw_presents; 14403bfa90b6Smrg vsaa->rendercheck = rendercheck; 144122f7e8e5Smrg vsaa->is_master = TRUE; 144222f7e8e5Smrg vsaa->known_prime_format = FALSE; 144334a0776dSmrg vsaa->has_screen_targets = has_screen_targets; 14443bfa90b6Smrg WSBMINITLISTHEAD(&vsaa->sync_x_list); 144522f7e8e5Smrg WSBMINITLISTHEAD(&vsaa->pixmaps); 14463bfa90b6Smrg 14473bfa90b6Smrg vsaa->driver = vmwgfx_saa_driver; 14483bfa90b6Smrg vsaa->vcomp = vmwgfx_alloc_composite(); 14493bfa90b6Smrg 14503bfa90b6Smrg if (!vsaa->vcomp) 14513bfa90b6Smrg vsaa->driver.composite_prepare = NULL; 14523bfa90b6Smrg 14533bfa90b6Smrg if (!saa_driver_init(pScreen, &vsaa->driver)) 14543bfa90b6Smrg goto out_no_saa; 14553bfa90b6Smrg 14563bfa90b6Smrg return TRUE; 14573bfa90b6Smrg out_no_saa: 14583bfa90b6Smrg free(vsaa); 14593bfa90b6Smrg return FALSE; 14603bfa90b6Smrg} 14613bfa90b6Smrg 14623bfa90b6Smrg/* 14633bfa90b6Smrg * ************************************************************************* 14643bfa90b6Smrg * Scanout functions. 14653bfa90b6Smrg * These do not strictly belong here, but we choose to hide the scanout 14663bfa90b6Smrg * pixmap private data in the saa pixmaps. Might want to revisit this. 14673bfa90b6Smrg */ 14683bfa90b6Smrg 14693bfa90b6Smrg/* 14703bfa90b6Smrg * Make sure we flush / update this scanout on next update run. 14713bfa90b6Smrg */ 14723bfa90b6Smrg 14733bfa90b6Smrgvoid 14743bfa90b6Smrgvmwgfx_scanout_refresh(PixmapPtr pixmap) 14753bfa90b6Smrg{ 14763bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 14773bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 14783bfa90b6Smrg BoxRec box; 14793bfa90b6Smrg 14803bfa90b6Smrg (void) pScreen; 14813bfa90b6Smrg box.x1 = 0; 14823bfa90b6Smrg box.y1 = 0; 14833bfa90b6Smrg box.x2 = pixmap->drawable.width; 14843bfa90b6Smrg box.y2 = pixmap->drawable.height; 14853bfa90b6Smrg 14863bfa90b6Smrg REGION_RESET(vsaa->pScreen, vpix->pending_present, &box); 14873bfa90b6Smrg if (vpix->dirty_present) 14883bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 14893bfa90b6Smrg vpix->pending_present, vpix->dirty_present); 14903bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 14913bfa90b6Smrg vpix->pending_present, &vpix->base.dirty_shadow); 14923bfa90b6Smrg REGION_COPY(vsaa->pScreen, vpix->pending_update, 14933bfa90b6Smrg &vpix->base.dirty_shadow); 14943bfa90b6Smrg} 14953bfa90b6Smrg 14963bfa90b6Smrg/* 14973bfa90b6Smrg * Take a "scanout reference" on a pixmap. If this is the first scanout 14983bfa90b6Smrg * reference, allocate resources needed for scanout, like proper 14993bfa90b6Smrg * damage tracking and kms fbs. 15003bfa90b6Smrg */ 15013bfa90b6Smrg 15023bfa90b6Smrguint32_t 150334a0776dSmrgvmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry, 150434a0776dSmrg Bool scanout_equals_pixmap) 15053bfa90b6Smrg{ 15063bfa90b6Smrg PixmapPtr pixmap = entry->pixmap; 15073bfa90b6Smrg struct vmwgfx_saa *vsaa = 15083bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 15093bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 15103bfa90b6Smrg 15113bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) { 15123bfa90b6Smrg uint32_t handle, dummy; 15133bfa90b6Smrg unsigned int depth; 15143bfa90b6Smrg 151534a0776dSmrg vpix->scanout_hw = vsaa->only_hw_presents || 151634a0776dSmrg (vsaa->has_screen_targets && scanout_equals_pixmap); 151734a0776dSmrg 151834a0776dSmrg if (vpix->scanout_hw) { 15193bfa90b6Smrg /* 15203bfa90b6Smrg * The KMS fb will be a HW surface. Create it, add damage 15213bfa90b6Smrg * and get the handle. 15223bfa90b6Smrg */ 1523591e32d7Ssnj if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT | 1524591e32d7Ssnj XA_FLAG_RENDER_TARGET, 0, NULL)) 15253bfa90b6Smrg goto out_err; 152622f7e8e5Smrg if (_xa_surface_handle(vpix->hw, &handle, &dummy) != 0) 15273bfa90b6Smrg goto out_err; 15283bfa90b6Smrg depth = xa_format_depth(xa_surface_format(vpix->hw)); 15293bfa90b6Smrg 15303bfa90b6Smrg } else { 15313bfa90b6Smrg /* 15323bfa90b6Smrg * The KMS fb will be a Guest Memory Region. Create it, 15333bfa90b6Smrg * add damage and get the handle. 15343bfa90b6Smrg */ 15353bfa90b6Smrg if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 15363bfa90b6Smrg goto out_err; 15373bfa90b6Smrg 15383bfa90b6Smrg handle = vpix->gmr->handle; 15393bfa90b6Smrg depth = pixmap->drawable.depth; 15403bfa90b6Smrg 15413bfa90b6Smrg } 15423bfa90b6Smrg 15433bfa90b6Smrg if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) 15443bfa90b6Smrg goto out_no_present; 15453bfa90b6Smrg 15463bfa90b6Smrg if (drmModeAddFB(vsaa->drm_fd, 15473bfa90b6Smrg pixmap->drawable.width, 15483bfa90b6Smrg pixmap->drawable.height, 15493bfa90b6Smrg depth, 15503bfa90b6Smrg pixmap->drawable.bitsPerPixel, 15513bfa90b6Smrg pixmap->devKind, 15523bfa90b6Smrg handle, 15533bfa90b6Smrg &vpix->fb_id) != 0) 15543bfa90b6Smrg goto out_no_fb;; 15553bfa90b6Smrg } 15563bfa90b6Smrg pixmap->refcnt += 1; 15573bfa90b6Smrg WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); 15583bfa90b6Smrg return vpix->fb_id; 15593bfa90b6Smrg 15603bfa90b6Smrg out_no_fb: 15613bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 15623bfa90b6Smrg out_no_present: 15633bfa90b6Smrg vmwgfx_pixmap_remove_damage(pixmap); 15643bfa90b6Smrg out_err: 15653bfa90b6Smrg vpix->fb_id = -1; 15663bfa90b6Smrg return -1; 15673bfa90b6Smrg} 15683bfa90b6Smrg 15693bfa90b6Smrg/* 15703bfa90b6Smrg * Free a "scanout reference" on a pixmap. If this was the last scanout 15713bfa90b6Smrg * reference, free pixmap resources needed for scanout, like 15723bfa90b6Smrg * damage tracking and kms fbs. 15733bfa90b6Smrg */ 15743bfa90b6Smrgvoid 15753bfa90b6Smrgvmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry) 15763bfa90b6Smrg{ 15773bfa90b6Smrg struct vmwgfx_saa *vsaa; 15783bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix; 15793bfa90b6Smrg PixmapPtr pixmap = entry->pixmap; 15803bfa90b6Smrg 15813bfa90b6Smrg if (!pixmap) 15823bfa90b6Smrg return; 15833bfa90b6Smrg 15843bfa90b6Smrg vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 15853bfa90b6Smrg vpix = vmwgfx_saa_pixmap(pixmap); 15863bfa90b6Smrg WSBMLISTDELINIT(&entry->scanout_head); 15873bfa90b6Smrg 15883bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) { 15893bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, vpix->pending_update); 15903bfa90b6Smrg drmModeRmFB(vsaa->drm_fd, vpix->fb_id); 15913bfa90b6Smrg vpix->fb_id = -1; 15923bfa90b6Smrg vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL); 15933bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 15943bfa90b6Smrg vmwgfx_pixmap_remove_damage(pixmap); 15953bfa90b6Smrg } 15963bfa90b6Smrg 15973bfa90b6Smrg entry->pixmap = NULL; 15983bfa90b6Smrg pixmap->drawable.pScreen->DestroyPixmap(pixmap); 15993bfa90b6Smrg} 160022f7e8e5Smrg 160122f7e8e5Smrgvoid 160222f7e8e5Smrgvmwgfx_saa_set_master(ScreenPtr pScreen) 160322f7e8e5Smrg{ 160422f7e8e5Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 160522f7e8e5Smrg 160622f7e8e5Smrg vsaa->is_master = TRUE; 160722f7e8e5Smrg vmwgfx_flush_dri2(pScreen); 160822f7e8e5Smrg} 160922f7e8e5Smrg 161022f7e8e5Smrgvoid 161122f7e8e5Smrgvmwgfx_saa_drop_master(ScreenPtr pScreen) 161222f7e8e5Smrg{ 161322f7e8e5Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 161422f7e8e5Smrg struct _WsbmListHead *list; 161522f7e8e5Smrg struct vmwgfx_saa_pixmap *vpix; 161622f7e8e5Smrg struct saa_pixmap *spix; 161722f7e8e5Smrg 161822f7e8e5Smrg WSBMLISTFOREACH(list, &vsaa->pixmaps) { 161922f7e8e5Smrg vpix = WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, pixmap_list); 162022f7e8e5Smrg spix = &vpix->base; 162122f7e8e5Smrg 162222f7e8e5Smrg if (!vpix->hw) 162322f7e8e5Smrg continue; 162422f7e8e5Smrg 162522f7e8e5Smrg (void) vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 162622f7e8e5Smrg &spix->dirty_hw); 162722f7e8e5Smrg REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 162822f7e8e5Smrg } 162922f7e8e5Smrg 163022f7e8e5Smrg vsaa->is_master = FALSE; 163122f7e8e5Smrg} 163222f7e8e5Smrg 163322f7e8e5Smrg/* 163422f7e8e5Smrg * ************************************************************************* 163522f7e8e5Smrg * Helpers for hosted. 163622f7e8e5Smrg */ 163722f7e8e5Smrg 163822f7e8e5Smrg#if (XA_TRACKER_VERSION_MAJOR >= 2) && defined(HAVE_LIBDRM_2_4_38) 163922f7e8e5Smrg 164022f7e8e5Smrg/** 164122f7e8e5Smrg * vmwgfx_saa_copy_to_surface - Copy Drawable contents to an external surface. 164222f7e8e5Smrg * 164322f7e8e5Smrg * @pDraw: Pointer to source drawable. 164422f7e8e5Smrg * @surface_fd: Prime file descriptor of external surface to copy to. 164522f7e8e5Smrg * @dst_box: BoxRec describing the destination bounding box. 164622f7e8e5Smrg * @region: Region of drawable to copy. Note: The code assumes that the 164722f7e8e5Smrg * region is relative to the drawable origin, not the underlying pixmap 164822f7e8e5Smrg * origin. 164922f7e8e5Smrg * 165022f7e8e5Smrg * Copies the contents (both software- and accelerated contents) to an 165122f7e8e5Smrg * external surface. 165222f7e8e5Smrg */ 165322f7e8e5SmrgBool 165422f7e8e5Smrgvmwgfx_saa_copy_to_surface(DrawablePtr pDraw, uint32_t surface_fd, 165522f7e8e5Smrg const BoxRec *dst_box, RegionPtr region) 165622f7e8e5Smrg{ 165722f7e8e5Smrg ScreenPtr pScreen = pDraw->pScreen; 165822f7e8e5Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 165922f7e8e5Smrg PixmapPtr src; 166022f7e8e5Smrg struct saa_pixmap *spix; 166122f7e8e5Smrg struct vmwgfx_saa_pixmap *vpix; 166222f7e8e5Smrg const BoxRec *box; 166322f7e8e5Smrg int n; 166422f7e8e5Smrg int sx, sy, dx, dy; 166522f7e8e5Smrg struct xa_surface *dst; 166622f7e8e5Smrg uint32_t handle; 166722f7e8e5Smrg Bool ret = TRUE; 166822f7e8e5Smrg RegionRec intersection; 166922f7e8e5Smrg RegionPtr copy_region = region; 167022f7e8e5Smrg 167122f7e8e5Smrg if (vmwgfx_prime_fd_to_handle(vsaa->drm_fd, surface_fd, &handle) < 0) 167222f7e8e5Smrg return FALSE; 167322f7e8e5Smrg 167422f7e8e5Smrg dst = xa_surface_from_handle(vsaa->xat, pDraw->width, pDraw->height, 167522f7e8e5Smrg pDraw->depth, xa_type_argb, 167622f7e8e5Smrg xa_format_unknown, 167722f7e8e5Smrg XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET, 167822f7e8e5Smrg handle, 167922f7e8e5Smrg (pDraw->width * pDraw->bitsPerPixel + 7) / 8); 168022f7e8e5Smrg 168122f7e8e5Smrg if (!dst) { 168222f7e8e5Smrg ret = FALSE; 168322f7e8e5Smrg goto out_no_surface; 168422f7e8e5Smrg } 168522f7e8e5Smrg 168622f7e8e5Smrg /* 168722f7e8e5Smrg * Assume damage region is relative to the source window. 168822f7e8e5Smrg */ 168922f7e8e5Smrg src = saa_get_pixmap(pDraw, &sx, &sy); 169022f7e8e5Smrg sx += pDraw->x; 169122f7e8e5Smrg sy += pDraw->y; 169222f7e8e5Smrg if (sx || sy) 169322f7e8e5Smrg REGION_TRANSLATE(pScreen, region, sx, sy); 169422f7e8e5Smrg 169522f7e8e5Smrg dx = dst_box->x1 - sx; 169622f7e8e5Smrg dy = dst_box->y1 - sy; 169722f7e8e5Smrg 169822f7e8e5Smrg spix = saa_get_saa_pixmap(src); 169922f7e8e5Smrg vpix = to_vmwgfx_saa_pixmap(spix); 170022f7e8e5Smrg 170122f7e8e5Smrg /* 170222f7e8e5Smrg * Make sure software contents of the source pixmap is henceforth put 170322f7e8e5Smrg * in a GMR to avoid the extra copy in the xa DMA. 170422f7e8e5Smrg */ 170522f7e8e5Smrg vmwgfx_prefer_gmr(vsaa, src); 170622f7e8e5Smrg 170722f7e8e5Smrg /* 170822f7e8e5Smrg * Determine the intersection between software contents and region to copy. 170922f7e8e5Smrg */ 171022f7e8e5Smrg 171122f7e8e5Smrg if (vsaa->known_prime_format) { 171222f7e8e5Smrg REGION_NULL(pScreen, &intersection); 171322f7e8e5Smrg if (!vpix->hw) 171422f7e8e5Smrg REGION_COPY(pScreen, &intersection, region); 171522f7e8e5Smrg else if (spix->damage && REGION_NOTEMPTY(pScreen, &spix->dirty_shadow)) 171622f7e8e5Smrg REGION_INTERSECT(pScreen, &intersection, region, &spix->dirty_shadow); 171722f7e8e5Smrg 171822f7e8e5Smrg /* 171922f7e8e5Smrg * DMA software contents directly into the destination. Then subtract 172022f7e8e5Smrg * the region we've DMA'd from the region to copy. 172122f7e8e5Smrg */ 172222f7e8e5Smrg if (REGION_NOTEMPTY(pScreen, &intersection)) { 172322f7e8e5Smrg if (vmwgfx_saa_dma(vsaa, src, &intersection, TRUE, dx, dy, dst)) { 172422f7e8e5Smrg REGION_SUBTRACT(pScreen, &intersection, region, &intersection); 172522f7e8e5Smrg copy_region = &intersection; 172622f7e8e5Smrg } 172722f7e8e5Smrg } 172822f7e8e5Smrg } 172922f7e8e5Smrg 173022f7e8e5Smrg if (!REGION_NOTEMPTY(pScreen, copy_region)) 173122f7e8e5Smrg goto out_no_copy; 173222f7e8e5Smrg 173322f7e8e5Smrg /* 173422f7e8e5Smrg * Copy Hardware contents to the destination 173522f7e8e5Smrg */ 173622f7e8e5Smrg box = REGION_RECTS(copy_region); 173722f7e8e5Smrg n = REGION_NUM_RECTS(copy_region); 173822f7e8e5Smrg 173922f7e8e5Smrg if (!vmwgfx_hw_accel_validate(src, 0, 0, 0, copy_region)) { 174022f7e8e5Smrg ret = FALSE; 174122f7e8e5Smrg goto out_no_copy; 174222f7e8e5Smrg } 174322f7e8e5Smrg 174422f7e8e5Smrg if (xa_copy_prepare(vsaa->xa_ctx, dst, vpix->hw) != XA_ERR_NONE) { 174522f7e8e5Smrg ret = FALSE; 174622f7e8e5Smrg goto out_no_copy; 174722f7e8e5Smrg } 174822f7e8e5Smrg 174922f7e8e5Smrg while(n--) { 175022f7e8e5Smrg xa_copy(vsaa->xa_ctx, box->x1 + dx, box->y1 + dy, box->x1, box->y1, 175122f7e8e5Smrg box->x2 - box->x1, box->y2 - box->y1); 175222f7e8e5Smrg box++; 175322f7e8e5Smrg } 175422f7e8e5Smrg 175522f7e8e5Smrg xa_copy_done(vsaa->xa_ctx); 175622f7e8e5Smrg xa_context_flush(vsaa->xa_ctx); 175722f7e8e5Smrg 175822f7e8e5Smrg out_no_copy: 175922f7e8e5Smrg if (vsaa->known_prime_format) 176022f7e8e5Smrg REGION_UNINIT(pScreen, &intersection); 176122f7e8e5Smrg if (sx || sy) 176222f7e8e5Smrg REGION_TRANSLATE(pScreen, region, -sx, -sy); 176322f7e8e5Smrg xa_surface_unref(dst); 176422f7e8e5Smrg out_no_surface: 176522f7e8e5Smrg vmwgfx_prime_release_handle(vsaa->drm_fd, handle); 176622f7e8e5Smrg 176722f7e8e5Smrg return ret; 176822f7e8e5Smrg} 176922f7e8e5Smrg#endif 1770