vmwgfx_saa.c revision 3bfa90b6
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> 293bfa90b6Smrg#include <mi.h> 303bfa90b6Smrg#include <fb.h> 313bfa90b6Smrg#include <xf86drmMode.h> 323bfa90b6Smrg#include <xa_context.h> 333bfa90b6Smrg#include "vmwgfx_saa.h" 343bfa90b6Smrg#include "vmwgfx_drmi.h" 353bfa90b6Smrg#include "vmwgfx_saa_priv.h" 363bfa90b6Smrg 373bfa90b6Smrg/* 383bfa90b6Smrg * Damage to be added as soon as we attach storage to the pixmap. 393bfa90b6Smrg */ 403bfa90b6Smrgstatic Bool 413bfa90b6Smrgvmwgfx_pixmap_add_damage(PixmapPtr pixmap) 423bfa90b6Smrg{ 433bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 443bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 453bfa90b6Smrg DrawablePtr draw = &pixmap->drawable; 463bfa90b6Smrg BoxRec box; 473bfa90b6Smrg 483bfa90b6Smrg if (spix->damage) 493bfa90b6Smrg return TRUE; 503bfa90b6Smrg 513bfa90b6Smrg if (!saa_add_damage(pixmap)) 523bfa90b6Smrg return FALSE; 533bfa90b6Smrg 543bfa90b6Smrg box.x1 = 0; 553bfa90b6Smrg box.x2 = draw->width; 563bfa90b6Smrg box.y1 = 0; 573bfa90b6Smrg box.y2 = draw->height; 583bfa90b6Smrg 593bfa90b6Smrg if (vpix->hw) { 603bfa90b6Smrg REGION_RESET(draw->pScreen, &spix->dirty_hw, &box); 613bfa90b6Smrg REGION_EMPTY(draw->pScreen, &spix->dirty_shadow); 623bfa90b6Smrg } else { 633bfa90b6Smrg REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box); 643bfa90b6Smrg REGION_EMPTY(draw->pScreen, &spix->dirty_hw); 653bfa90b6Smrg } 663bfa90b6Smrg 673bfa90b6Smrg return TRUE; 683bfa90b6Smrg} 693bfa90b6Smrg 703bfa90b6Smrgstatic void 713bfa90b6Smrgvmwgfx_pixmap_remove_damage(PixmapPtr pixmap) 723bfa90b6Smrg{ 733bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 743bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 753bfa90b6Smrg 763bfa90b6Smrg if (!spix->damage || vpix->hw || vpix->gmr || vpix->malloc) 773bfa90b6Smrg return; 783bfa90b6Smrg 793bfa90b6Smrg DamageUnregister(&pixmap->drawable, spix->damage); 803bfa90b6Smrg DamageDestroy(spix->damage); 813bfa90b6Smrg spix->damage = NULL; 823bfa90b6Smrg} 833bfa90b6Smrg 843bfa90b6Smrgstatic void 853bfa90b6Smrgvmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix) 863bfa90b6Smrg{ 873bfa90b6Smrg if (vpix->dirty_present) 883bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present); 893bfa90b6Smrg if (vpix->present_damage) 903bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage); 913bfa90b6Smrg if (vpix->pending_update) 923bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update); 933bfa90b6Smrg if (vpix->pending_present) 943bfa90b6Smrg REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present); 953bfa90b6Smrg vpix->dirty_present = NULL; 963bfa90b6Smrg vpix->present_damage = NULL; 973bfa90b6Smrg vpix->pending_update = NULL; 983bfa90b6Smrg vpix->pending_present = NULL; 993bfa90b6Smrg} 1003bfa90b6Smrg 1013bfa90b6Smrgstatic Bool 1023bfa90b6Smrgvmwgfx_pixmap_add_present(PixmapPtr pixmap, Bool present_opt) 1033bfa90b6Smrg{ 1043bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1053bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 1063bfa90b6Smrg (void) pScreen; 1073bfa90b6Smrg 1083bfa90b6Smrg if (present_opt) { 1093bfa90b6Smrg vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0); 1103bfa90b6Smrg if (!vpix->dirty_present) 1113bfa90b6Smrg return FALSE; 1123bfa90b6Smrg vpix->present_damage = REGION_CREATE(pScreen, NULL, 0); 1133bfa90b6Smrg if (!vpix->present_damage) 1143bfa90b6Smrg goto out_no_present_damage; 1153bfa90b6Smrg } 1163bfa90b6Smrg vpix->pending_update = REGION_CREATE(pScreen, NULL, 0); 1173bfa90b6Smrg if (!vpix->pending_update) 1183bfa90b6Smrg goto out_no_pending_update; 1193bfa90b6Smrg vpix->pending_present = REGION_CREATE(pScreen, NULL, 0); 1203bfa90b6Smrg if (!vpix->pending_present) 1213bfa90b6Smrg goto out_no_pending_present; 1223bfa90b6Smrg 1233bfa90b6Smrg return TRUE; 1243bfa90b6Smrg out_no_pending_present: 1253bfa90b6Smrg REGION_DESTROY(pScreen, vpix->pending_update); 1263bfa90b6Smrg out_no_pending_update: 1273bfa90b6Smrg if (vpix->present_damage) 1283bfa90b6Smrg REGION_DESTROY(pScreen, vpix->present_damage); 1293bfa90b6Smrg out_no_present_damage: 1303bfa90b6Smrg if (vpix->dirty_present) 1313bfa90b6Smrg REGION_DESTROY(pScreen, vpix->dirty_present); 1323bfa90b6Smrg return FALSE; 1333bfa90b6Smrg} 1343bfa90b6Smrg 1353bfa90b6Smrgstatic void 1363bfa90b6Smrgvmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix) 1373bfa90b6Smrg{ 1383bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) { 1393bfa90b6Smrg free(vpix->malloc); 1403bfa90b6Smrg vpix->malloc = NULL; 1413bfa90b6Smrg } 1423bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) { 1433bfa90b6Smrg xa_surface_destroy(vpix->hw); 1443bfa90b6Smrg vpix->hw = NULL; 1453bfa90b6Smrg } 1463bfa90b6Smrg if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) { 1473bfa90b6Smrg vmwgfx_dmabuf_destroy(vpix->gmr); 1483bfa90b6Smrg vpix->gmr = NULL; 1493bfa90b6Smrg } 1503bfa90b6Smrg} 1513bfa90b6Smrg 1523bfa90b6Smrgstatic Bool 1533bfa90b6Smrgvmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 1543bfa90b6Smrg{ 1553bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1563bfa90b6Smrg size_t size; 1573bfa90b6Smrg struct vmwgfx_dmabuf *gmr; 1583bfa90b6Smrg void *addr; 1593bfa90b6Smrg 1603bfa90b6Smrg if (vpix->gmr) 1613bfa90b6Smrg return TRUE; 1623bfa90b6Smrg 1633bfa90b6Smrg size = pixmap->devKind * pixmap->drawable.height; 1643bfa90b6Smrg gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 1653bfa90b6Smrg if (!gmr) 1663bfa90b6Smrg return FALSE; 1673bfa90b6Smrg 1683bfa90b6Smrg if (vpix->malloc) { 1693bfa90b6Smrg 1703bfa90b6Smrg addr = vmwgfx_dmabuf_map(gmr); 1713bfa90b6Smrg if (!addr) 1723bfa90b6Smrg goto out_no_transfer; 1733bfa90b6Smrg memcpy(addr, vpix->malloc, size); 1743bfa90b6Smrg vmwgfx_dmabuf_unmap(gmr); 1753bfa90b6Smrg 1763bfa90b6Smrg } else if (!vmwgfx_pixmap_add_damage(pixmap)) 1773bfa90b6Smrg goto out_no_transfer; 1783bfa90b6Smrg 1793bfa90b6Smrg vpix->backing |= VMWGFX_PIX_GMR; 1803bfa90b6Smrg vpix->backing &= ~VMWGFX_PIX_MALLOC; 1813bfa90b6Smrg vpix->gmr = gmr; 1823bfa90b6Smrg 1833bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 1843bfa90b6Smrg 1853bfa90b6Smrg return TRUE; 1863bfa90b6Smrg 1873bfa90b6Smrg out_no_transfer: 1883bfa90b6Smrg vmwgfx_dmabuf_destroy(gmr); 1893bfa90b6Smrg return FALSE; 1903bfa90b6Smrg} 1913bfa90b6Smrg 1923bfa90b6Smrgstatic Bool 1933bfa90b6Smrgvmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap) 1943bfa90b6Smrg{ 1953bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 1963bfa90b6Smrg 1973bfa90b6Smrg if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR))) 1983bfa90b6Smrg return FALSE; 1993bfa90b6Smrg 2003bfa90b6Smrg if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) { 2013bfa90b6Smrg vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height); 2023bfa90b6Smrg if (!vpix->malloc) 2033bfa90b6Smrg goto out_no_malloc; 2043bfa90b6Smrg if (!vmwgfx_pixmap_add_damage(pixmap)) 2053bfa90b6Smrg goto out_no_damage; 2063bfa90b6Smrg } else if (vpix->backing & VMWGFX_PIX_GMR) 2073bfa90b6Smrg return vmwgfx_pixmap_create_gmr(vsaa, pixmap); 2083bfa90b6Smrg 2093bfa90b6Smrg return TRUE; 2103bfa90b6Smrg 2113bfa90b6Smrg out_no_damage: 2123bfa90b6Smrg free(vpix->malloc); 2133bfa90b6Smrg vpix->malloc = NULL; 2143bfa90b6Smrg out_no_malloc: 2153bfa90b6Smrg return FALSE; 2163bfa90b6Smrg} 2173bfa90b6Smrg 2183bfa90b6Smrg 2193bfa90b6Smrg/** 2203bfa90b6Smrg * 2213bfa90b6Smrg * Makes sure all presented contents covered by @region are read 2223bfa90b6Smrg * back and are present in a valid GMR. 2233bfa90b6Smrg */ 2243bfa90b6Smrg 2253bfa90b6Smrgstatic Bool 2263bfa90b6Smrgvmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa, 2273bfa90b6Smrg PixmapPtr pixmap, 2283bfa90b6Smrg RegionPtr region) 2293bfa90b6Smrg{ 2303bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 2313bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 2323bfa90b6Smrg RegionRec intersection; 2333bfa90b6Smrg 2343bfa90b6Smrg if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) || 2353bfa90b6Smrg !vpix->dirty_present) 2363bfa90b6Smrg return TRUE; 2373bfa90b6Smrg 2383bfa90b6Smrg /* 2393bfa90b6Smrg * Intersect dirty region with region to be read back, if any. 2403bfa90b6Smrg */ 2413bfa90b6Smrg 2423bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 2433bfa90b6Smrg REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw); 2443bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, 2453bfa90b6Smrg vpix->dirty_present); 2463bfa90b6Smrg 2473bfa90b6Smrg if (region) 2483bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region); 2493bfa90b6Smrg 2503bfa90b6Smrg if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection)) 2513bfa90b6Smrg goto out; 2523bfa90b6Smrg 2533bfa90b6Smrg /* 2543bfa90b6Smrg * Make really sure there is a GMR to read back to. 2553bfa90b6Smrg */ 2563bfa90b6Smrg 2573bfa90b6Smrg if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 2583bfa90b6Smrg goto out_err; 2593bfa90b6Smrg 2603bfa90b6Smrg if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id, 2613bfa90b6Smrg &intersection) != 0) 2623bfa90b6Smrg goto out_err; 2633bfa90b6Smrg 2643bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, 2653bfa90b6Smrg &spix->dirty_hw, &intersection); 2663bfa90b6Smrg out: 2673bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 2683bfa90b6Smrg return TRUE; 2693bfa90b6Smrg 2703bfa90b6Smrg out_err: 2713bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 2723bfa90b6Smrg return FALSE; 2733bfa90b6Smrg} 2743bfa90b6Smrg 2753bfa90b6Smrgstatic Bool 2763bfa90b6Smrgvmwgfx_saa_dma(struct vmwgfx_saa *vsaa, 2773bfa90b6Smrg PixmapPtr pixmap, 2783bfa90b6Smrg RegionPtr reg, 2793bfa90b6Smrg Bool to_hw) 2803bfa90b6Smrg{ 2813bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 2823bfa90b6Smrg 2833bfa90b6Smrg if (!vpix->hw || (!vpix->gmr && !vpix->malloc)) 2843bfa90b6Smrg return TRUE; 2853bfa90b6Smrg 2863bfa90b6Smrg if (vpix->gmr && vsaa->can_optimize_dma) { 2873bfa90b6Smrg uint32_t handle, dummy; 2883bfa90b6Smrg 2893bfa90b6Smrg if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) 2903bfa90b6Smrg goto out_err; 2913bfa90b6Smrg if (vmwgfx_dma(0, 0, reg, vpix->gmr, pixmap->devKind, handle, 2923bfa90b6Smrg to_hw) != 0) 2933bfa90b6Smrg goto out_err; 2943bfa90b6Smrg } else { 2953bfa90b6Smrg void *data = vpix->malloc; 2963bfa90b6Smrg int ret; 2973bfa90b6Smrg 2983bfa90b6Smrg if (vpix->gmr) { 2993bfa90b6Smrg data = vmwgfx_dmabuf_map(vpix->gmr); 3003bfa90b6Smrg if (!data) 3013bfa90b6Smrg goto out_err; 3023bfa90b6Smrg } 3033bfa90b6Smrg 3043bfa90b6Smrg ret = xa_surface_dma(vsaa->xa_ctx, vpix->hw, data, pixmap->devKind, 3053bfa90b6Smrg (int) to_hw, 3063bfa90b6Smrg (struct xa_box *) REGION_RECTS(reg), 3073bfa90b6Smrg REGION_NUM_RECTS(reg)); 3083bfa90b6Smrg if (vpix->gmr) 3093bfa90b6Smrg vmwgfx_dmabuf_unmap(vpix->gmr); 3103bfa90b6Smrg if (ret) 3113bfa90b6Smrg goto out_err; 3123bfa90b6Smrg } 3133bfa90b6Smrg return TRUE; 3143bfa90b6Smrg out_err: 3153bfa90b6Smrg LogMessage(X_ERROR, "DMA %s surface failed.\n", 3163bfa90b6Smrg to_hw ? "to" : "from"); 3173bfa90b6Smrg return FALSE; 3183bfa90b6Smrg} 3193bfa90b6Smrg 3203bfa90b6Smrg 3213bfa90b6Smrgstatic Bool 3223bfa90b6Smrgvmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap, 3233bfa90b6Smrg RegionPtr readback) 3243bfa90b6Smrg{ 3253bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 3263bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 3273bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 3283bfa90b6Smrg 3293bfa90b6Smrg RegionRec intersection; 3303bfa90b6Smrg 3313bfa90b6Smrg if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback)) 3323bfa90b6Smrg return FALSE; 3333bfa90b6Smrg 3343bfa90b6Smrg if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw)) 3353bfa90b6Smrg return TRUE; 3363bfa90b6Smrg 3373bfa90b6Smrg if (!vpix->hw) 3383bfa90b6Smrg return TRUE; 3393bfa90b6Smrg 3403bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 3413bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, readback, 3423bfa90b6Smrg &spix->dirty_hw); 3433bfa90b6Smrg readback = &intersection; 3443bfa90b6Smrg 3453bfa90b6Smrg if (!vmwgfx_pixmap_create_sw(vsaa, pixmap)) 3463bfa90b6Smrg goto out_err; 3473bfa90b6Smrg 3483bfa90b6Smrg if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE)) 3493bfa90b6Smrg goto out_err; 3503bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback); 3513bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 3523bfa90b6Smrg return TRUE; 3533bfa90b6Smrg out_err: 3543bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 3553bfa90b6Smrg return FALSE; 3563bfa90b6Smrg} 3573bfa90b6Smrg 3583bfa90b6Smrg 3593bfa90b6Smrgstatic Bool 3603bfa90b6Smrgvmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap, 3613bfa90b6Smrg RegionPtr upload) 3623bfa90b6Smrg{ 3633bfa90b6Smrg return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE); 3643bfa90b6Smrg} 3653bfa90b6Smrg 3663bfa90b6Smrgstatic void 3673bfa90b6Smrgvmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 3683bfa90b6Smrg{ 3693bfa90b6Smrg // LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n", 3703bfa90b6Smrg // (unsigned long) pixmap, (unsigned) access); 3713bfa90b6Smrg} 3723bfa90b6Smrg 3733bfa90b6Smrgstatic void * 3743bfa90b6Smrgvmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 3753bfa90b6Smrg{ 3763bfa90b6Smrg /* 3773bfa90b6Smrg * Errors in this functions will turn up in subsequent map 3783bfa90b6Smrg * calls. 3793bfa90b6Smrg */ 3803bfa90b6Smrg 3813bfa90b6Smrg (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap); 3823bfa90b6Smrg 3833bfa90b6Smrg return NULL; 3843bfa90b6Smrg} 3853bfa90b6Smrg 3863bfa90b6Smrgstatic void * 3873bfa90b6Smrgvmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 3883bfa90b6Smrg{ 3893bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 3903bfa90b6Smrg 3913bfa90b6Smrg if (vpix->malloc) 3923bfa90b6Smrg return vpix->malloc; 3933bfa90b6Smrg else if (vpix->gmr) 3943bfa90b6Smrg return vmwgfx_dmabuf_map(vpix->gmr); 3953bfa90b6Smrg else 3963bfa90b6Smrg return NULL; 3973bfa90b6Smrg} 3983bfa90b6Smrg 3993bfa90b6Smrgstatic void 4003bfa90b6Smrgvmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access) 4013bfa90b6Smrg{ 4023bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 4033bfa90b6Smrg 4043bfa90b6Smrg if (vpix->gmr) 4053bfa90b6Smrg return vmwgfx_dmabuf_unmap(vpix->gmr); 4063bfa90b6Smrg 4073bfa90b6Smrg// LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n", 4083bfa90b6Smrg // (unsigned long) pixmap, (unsigned) access); 4093bfa90b6Smrg ; 4103bfa90b6Smrg} 4113bfa90b6Smrg 4123bfa90b6Smrgstatic Bool 4133bfa90b6Smrgvmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix, 4143bfa90b6Smrg int w, int h, int depth, 4153bfa90b6Smrg unsigned int usage_hint, int bpp, int *new_pitch) 4163bfa90b6Smrg{ 4173bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 4183bfa90b6Smrg 4193bfa90b6Smrg *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); 4203bfa90b6Smrg 4213bfa90b6Smrg WSBMINITLISTHEAD(&vpix->sync_x_head); 4223bfa90b6Smrg WSBMINITLISTHEAD(&vpix->scanout_list); 4233bfa90b6Smrg 4243bfa90b6Smrg return TRUE; 4253bfa90b6Smrg} 4263bfa90b6Smrg 4273bfa90b6SmrgBool 4283bfa90b6Smrgvmwgfx_hw_kill(struct vmwgfx_saa *vsaa, 4293bfa90b6Smrg struct saa_pixmap *spix) 4303bfa90b6Smrg{ 4313bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 4323bfa90b6Smrg 4333bfa90b6Smrg if (!vpix->hw) 4343bfa90b6Smrg return TRUE; 4353bfa90b6Smrg 4363bfa90b6Smrg /* 4373bfa90b6Smrg * Read back any dirty regions from hardware. 4383bfa90b6Smrg */ 4393bfa90b6Smrg 4403bfa90b6Smrg if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, 4413bfa90b6Smrg &spix->dirty_hw)) 4423bfa90b6Smrg return FALSE; 4433bfa90b6Smrg 4443bfa90b6Smrg xa_surface_destroy(vpix->hw); 4453bfa90b6Smrg vpix->hw = NULL; 4463bfa90b6Smrg 4473bfa90b6Smrg /* 4483bfa90b6Smrg * Remove damage tracking if this is not a scanout pixmap. 4493bfa90b6Smrg */ 4503bfa90b6Smrg 4513bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) 4523bfa90b6Smrg vmwgfx_pixmap_remove_damage(spix->pixmap); 4533bfa90b6Smrg 4543bfa90b6Smrg return TRUE; 4553bfa90b6Smrg} 4563bfa90b6Smrg 4573bfa90b6Smrgvoid 4583bfa90b6Smrgvmwgfx_flush_dri2(ScreenPtr pScreen) 4593bfa90b6Smrg{ 4603bfa90b6Smrg struct vmwgfx_saa *vsaa = 4613bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pScreen)); 4623bfa90b6Smrg struct _WsbmListHead *list, *next; 4633bfa90b6Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 4643bfa90b6Smrg 4653bfa90b6Smrg if (!pScrn->vtSema) 4663bfa90b6Smrg return; 4673bfa90b6Smrg 4683bfa90b6Smrg WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { 4693bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = 4703bfa90b6Smrg WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); 4713bfa90b6Smrg struct saa_pixmap *spix = &vpix->base; 4723bfa90b6Smrg PixmapPtr pixmap = spix->pixmap; 4733bfa90b6Smrg 4743bfa90b6Smrg if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { 4753bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 4763bfa90b6Smrg WSBMLISTDELINIT(list); 4773bfa90b6Smrg } 4783bfa90b6Smrg } 4793bfa90b6Smrg} 4803bfa90b6Smrg 4813bfa90b6Smrg 4823bfa90b6Smrgstatic void 4833bfa90b6Smrgvmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap) 4843bfa90b6Smrg{ 4853bfa90b6Smrg ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen; 4863bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 4873bfa90b6Smrg (void) pScreen; 4883bfa90b6Smrg 4893bfa90b6Smrg vpix->backing = 0; 4903bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 4913bfa90b6Smrg 4923bfa90b6Smrg /* 4933bfa90b6Smrg * Any damage we've registered has already been removed by the server 4943bfa90b6Smrg * at this point. Any attempt to unregister / destroy it will result 4953bfa90b6Smrg * in a double free. 4963bfa90b6Smrg */ 4973bfa90b6Smrg 4983bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 4993bfa90b6Smrg WSBMLISTDELINIT(&vpix->sync_x_head); 5003bfa90b6Smrg 5013bfa90b6Smrg if (vpix->hw_is_dri2_fronts) 5023bfa90b6Smrg LogMessage(X_ERROR, "Incorrect dri2 front count.\n"); 5033bfa90b6Smrg} 5043bfa90b6Smrg 5053bfa90b6Smrg 5063bfa90b6Smrg 5073bfa90b6Smrg/** 5083bfa90b6Smrg * 5093bfa90b6Smrg * Makes sure we have a surface with valid contents. 5103bfa90b6Smrg */ 5113bfa90b6Smrg 5123bfa90b6Smrgstatic void 5133bfa90b6Smrgvmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch, 5143bfa90b6Smrg unsigned int src_pitch, unsigned int dst_height, 5153bfa90b6Smrg unsigned int src_height) 5163bfa90b6Smrg{ 5173bfa90b6Smrg unsigned int i; 5183bfa90b6Smrg unsigned int height = (dst_height < src_height) ? dst_height : src_height; 5193bfa90b6Smrg unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch; 5203bfa90b6Smrg 5213bfa90b6Smrg for(i=0; i<height; ++i) { 5223bfa90b6Smrg memcpy(dst, src, pitch); 5233bfa90b6Smrg dst += dst_pitch; 5243bfa90b6Smrg src += src_pitch; 5253bfa90b6Smrg } 5263bfa90b6Smrg} 5273bfa90b6Smrg 5283bfa90b6Smrg 5293bfa90b6Smrgstatic Bool 5303bfa90b6Smrgvmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch, 5313bfa90b6Smrg unsigned int old_height, unsigned int old_width) 5323bfa90b6Smrg{ 5333bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 5343bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen)); 5353bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 5363bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 5373bfa90b6Smrg DrawablePtr draw = &pixmap->drawable; 5383bfa90b6Smrg unsigned int size = pixmap->devKind * draw->height; 5393bfa90b6Smrg BoxRec b_box; 5403bfa90b6Smrg RegionRec b_reg; 5413bfa90b6Smrg 5423bfa90b6Smrg /* 5433bfa90b6Smrg * Ignore copying errors. At worst they will show up as rendering 5443bfa90b6Smrg * artefacts. 5453bfa90b6Smrg */ 5463bfa90b6Smrg 5473bfa90b6Smrg if (vpix->malloc) { 5483bfa90b6Smrg 5493bfa90b6Smrg void *new_malloc = malloc(size); 5503bfa90b6Smrg if (!new_malloc) 5513bfa90b6Smrg return FALSE; 5523bfa90b6Smrg 5533bfa90b6Smrg vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind, 5543bfa90b6Smrg old_pitch, draw->height, 5553bfa90b6Smrg old_height); 5563bfa90b6Smrg free(vpix->malloc); 5573bfa90b6Smrg vpix->malloc = new_malloc; 5583bfa90b6Smrg } 5593bfa90b6Smrg 5603bfa90b6Smrg if (vpix->gmr) { 5613bfa90b6Smrg struct vmwgfx_dmabuf *gmr; 5623bfa90b6Smrg void *new_addr; 5633bfa90b6Smrg void *old_addr; 5643bfa90b6Smrg 5653bfa90b6Smrg gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size); 5663bfa90b6Smrg if (!gmr) 5673bfa90b6Smrg return FALSE; 5683bfa90b6Smrg 5693bfa90b6Smrg new_addr = vmwgfx_dmabuf_map(gmr); 5703bfa90b6Smrg old_addr = vmwgfx_dmabuf_map(vpix->gmr); 5713bfa90b6Smrg 5723bfa90b6Smrg if (new_addr && old_addr) 5733bfa90b6Smrg vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind, 5743bfa90b6Smrg old_pitch, draw->height, 5753bfa90b6Smrg old_height); 5763bfa90b6Smrg else 5773bfa90b6Smrg LogMessage(X_ERROR, "Failed pixmap resize copy.\n"); 5783bfa90b6Smrg 5793bfa90b6Smrg if (old_addr) 5803bfa90b6Smrg vmwgfx_dmabuf_unmap(vpix->gmr); 5813bfa90b6Smrg if (new_addr) 5823bfa90b6Smrg vmwgfx_dmabuf_unmap(gmr); 5833bfa90b6Smrg vmwgfx_dmabuf_destroy(vpix->gmr); 5843bfa90b6Smrg vpix->gmr = gmr; 5853bfa90b6Smrg } 5863bfa90b6Smrg 5873bfa90b6Smrg if (vpix->hw) { 5883bfa90b6Smrg if (xa_surface_redefine(vpix->hw, draw->width, draw->height, 5893bfa90b6Smrg draw->depth, xa_type_argb, 5903bfa90b6Smrg xa_format_unknown, vpix->xa_flags, 1) != 0) 5913bfa90b6Smrg return FALSE; 5923bfa90b6Smrg } 5933bfa90b6Smrg 5943bfa90b6Smrg b_box.x1 = 0; 5953bfa90b6Smrg b_box.x2 = draw->width; 5963bfa90b6Smrg b_box.y1 = 0; 5973bfa90b6Smrg b_box.y2 = draw->height; 5983bfa90b6Smrg 5993bfa90b6Smrg REGION_INIT(pScreen, &b_reg, &b_box, 1); 6003bfa90b6Smrg REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, 6013bfa90b6Smrg &b_reg); 6023bfa90b6Smrg REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); 6033bfa90b6Smrg if (vpix->dirty_present) 6043bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, 6053bfa90b6Smrg &b_reg); 6063bfa90b6Smrg if (vpix->pending_update) 6073bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, 6083bfa90b6Smrg &b_reg); 6093bfa90b6Smrg if (vpix->pending_present) 6103bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->pending_present, 6113bfa90b6Smrg vpix->pending_present, &b_reg); 6123bfa90b6Smrg if (vpix->present_damage) 6133bfa90b6Smrg REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, 6143bfa90b6Smrg &b_reg); 6153bfa90b6Smrg 6163bfa90b6Smrg REGION_UNINIT(pScreen, &b_reg); 6173bfa90b6Smrg 6183bfa90b6Smrg return TRUE; 6193bfa90b6Smrg} 6203bfa90b6Smrg 6213bfa90b6Smrg 6223bfa90b6Smrgstatic Bool 6233bfa90b6Smrgvmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth, 6243bfa90b6Smrg int bpp, int devkind, void *pixdata) 6253bfa90b6Smrg{ 6263bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 6273bfa90b6Smrg unsigned int old_height; 6283bfa90b6Smrg unsigned int old_width; 6293bfa90b6Smrg unsigned int old_pitch; 6303bfa90b6Smrg 6313bfa90b6Smrg if (!vpix) { 6323bfa90b6Smrg LogMessage(X_ERROR, "Not an SAA pixmap.\n"); 6333bfa90b6Smrg return FALSE; 6343bfa90b6Smrg } 6353bfa90b6Smrg 6363bfa90b6Smrg if (pixdata) { 6373bfa90b6Smrg vpix->backing = 0; 6383bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 6393bfa90b6Smrg return FALSE; 6403bfa90b6Smrg } 6413bfa90b6Smrg 6423bfa90b6Smrg if (depth <= 0) 6433bfa90b6Smrg depth = pixmap->drawable.depth; 6443bfa90b6Smrg 6453bfa90b6Smrg if (bpp <= 0) 6463bfa90b6Smrg bpp = pixmap->drawable.bitsPerPixel; 6473bfa90b6Smrg 6483bfa90b6Smrg if (w <= 0) 6493bfa90b6Smrg w = pixmap->drawable.width; 6503bfa90b6Smrg 6513bfa90b6Smrg if (h <= 0) 6523bfa90b6Smrg h = pixmap->drawable.height; 6533bfa90b6Smrg 6543bfa90b6Smrg if (w <= 0 || h <= 0 || depth <= 0) 6553bfa90b6Smrg return FALSE; 6563bfa90b6Smrg 6573bfa90b6Smrg old_height = pixmap->drawable.height; 6583bfa90b6Smrg old_width = pixmap->drawable.width; 6593bfa90b6Smrg old_pitch = pixmap->devKind; 6603bfa90b6Smrg 6613bfa90b6Smrg if (!miModifyPixmapHeader(pixmap, w, h, depth, 6623bfa90b6Smrg bpp, devkind, NULL)) 6633bfa90b6Smrg goto out_no_modify; 6643bfa90b6Smrg 6653bfa90b6Smrg if (!vpix->backing) 6663bfa90b6Smrg vpix->backing = VMWGFX_PIX_MALLOC; 6673bfa90b6Smrg 6683bfa90b6Smrg vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width); 6693bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 6703bfa90b6Smrg return TRUE; 6713bfa90b6Smrg 6723bfa90b6Smrg out_no_modify: 6733bfa90b6Smrg return FALSE; 6743bfa90b6Smrg} 6753bfa90b6Smrg 6763bfa90b6Smrgstatic Bool 6773bfa90b6Smrgvmwgfx_present_prepare(struct vmwgfx_saa *vsaa, 6783bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix, 6793bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix) 6803bfa90b6Smrg{ 6813bfa90b6Smrg ScreenPtr pScreen = vsaa->pScreen; 6823bfa90b6Smrg unsigned int dummy; 6833bfa90b6Smrg 6843bfa90b6Smrg (void) pScreen; 6853bfa90b6Smrg if (src_vpix == dst_vpix || !src_vpix->hw || 6863bfa90b6Smrg xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0) 6873bfa90b6Smrg return FALSE; 6883bfa90b6Smrg 6893bfa90b6Smrg REGION_NULL(pScreen, &vsaa->present_region); 6903bfa90b6Smrg vsaa->diff_valid = FALSE; 6913bfa90b6Smrg vsaa->dst_vpix = dst_vpix; 6923bfa90b6Smrg vsaa->present_flush(pScreen); 6933bfa90b6Smrg 6943bfa90b6Smrg return TRUE; 6953bfa90b6Smrg} 6963bfa90b6Smrg 6973bfa90b6Smrg/** 6983bfa90b6Smrg * Determine whether we should try present copies on this pixmap. 6993bfa90b6Smrg */ 7003bfa90b6Smrg 7013bfa90b6Smrgstatic Bool 7023bfa90b6Smrgvmwgfx_is_present_hw(PixmapPtr pixmap) 7033bfa90b6Smrg{ 7043bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 7053bfa90b6Smrg return (vpix->dirty_present != NULL); 7063bfa90b6Smrg} 7073bfa90b6Smrg 7083bfa90b6Smrgstatic void 7093bfa90b6Smrgvmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa, 7103bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix, 7113bfa90b6Smrg RegionPtr region, 7123bfa90b6Smrg Bool *has_dirty_hw, 7133bfa90b6Smrg Bool *has_valid_hw) 7143bfa90b6Smrg{ 7153bfa90b6Smrg RegionRec intersection; 7163bfa90b6Smrg 7173bfa90b6Smrg 7183bfa90b6Smrg if (!vpix->hw) { 7193bfa90b6Smrg *has_dirty_hw = FALSE; 7203bfa90b6Smrg *has_valid_hw = FALSE; 7213bfa90b6Smrg return; 7223bfa90b6Smrg } 7233bfa90b6Smrg 7243bfa90b6Smrg if (!region) { 7253bfa90b6Smrg *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, 7263bfa90b6Smrg &vpix->base.dirty_hw); 7273bfa90b6Smrg *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, 7283bfa90b6Smrg &vpix->base.dirty_shadow); 7293bfa90b6Smrg return; 7303bfa90b6Smrg } 7313bfa90b6Smrg 7323bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 7333bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw, 7343bfa90b6Smrg region); 7353bfa90b6Smrg *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection); 7363bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow, 7373bfa90b6Smrg region); 7383bfa90b6Smrg *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection); 7393bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 7403bfa90b6Smrg} 7413bfa90b6Smrg 7423bfa90b6Smrg 7433bfa90b6SmrgBool 7443bfa90b6Smrgvmwgfx_create_hw(struct vmwgfx_saa *vsaa, 7453bfa90b6Smrg PixmapPtr pixmap) 7463bfa90b6Smrg{ 7473bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 7483bfa90b6Smrg struct xa_surface *hw; 7493bfa90b6Smrg uint32_t new_flags; 7503bfa90b6Smrg 7513bfa90b6Smrg if (!vsaa->xat) 7523bfa90b6Smrg return FALSE; 7533bfa90b6Smrg 7543bfa90b6Smrg if (vpix->hw) 7553bfa90b6Smrg return TRUE; 7563bfa90b6Smrg 7573bfa90b6Smrg new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | 7583bfa90b6Smrg vpix->staging_add_flags; 7593bfa90b6Smrg 7603bfa90b6Smrg hw = xa_surface_create(vsaa->xat, 7613bfa90b6Smrg pixmap->drawable.width, 7623bfa90b6Smrg pixmap->drawable.height, 7633bfa90b6Smrg 0, 7643bfa90b6Smrg xa_type_other, 7653bfa90b6Smrg vpix->staging_format, 7663bfa90b6Smrg new_flags); 7673bfa90b6Smrg if (hw == NULL) 7683bfa90b6Smrg return FALSE; 7693bfa90b6Smrg 7703bfa90b6Smrg vpix->xa_flags = new_flags; 7713bfa90b6Smrg 7723bfa90b6Smrg if (!vmwgfx_pixmap_add_damage(pixmap)) 7733bfa90b6Smrg goto out_no_damage; 7743bfa90b6Smrg 7753bfa90b6Smrg /* 7763bfa90b6Smrg * Even if we don't have a GMR yet, indicate that when needed it 7773bfa90b6Smrg * should be created. 7783bfa90b6Smrg */ 7793bfa90b6Smrg 7803bfa90b6Smrg vpix->hw = hw; 7813bfa90b6Smrg vpix->backing |= VMWGFX_PIX_SURFACE; 7823bfa90b6Smrg vmwgfx_pixmap_free_storage(vpix); 7833bfa90b6Smrg 7843bfa90b6Smrg return TRUE; 7853bfa90b6Smrg 7863bfa90b6Smrgout_no_damage: 7873bfa90b6Smrg xa_surface_destroy(hw); 7883bfa90b6Smrg return FALSE; 7893bfa90b6Smrg} 7903bfa90b6Smrg 7913bfa90b6Smrg 7923bfa90b6SmrgBool 7933bfa90b6Smrgvmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) 7943bfa90b6Smrg{ 7953bfa90b6Smrg struct vmwgfx_saa *vsaa = 7963bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 7973bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 7983bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 7993bfa90b6Smrg RegionRec intersection; 8003bfa90b6Smrg 8013bfa90b6Smrg if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region)) 8023bfa90b6Smrg return FALSE; 8033bfa90b6Smrg 8043bfa90b6Smrg REGION_NULL(vsaa->pScreen, &intersection); 8053bfa90b6Smrg REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow); 8063bfa90b6Smrg 8073bfa90b6Smrg if (vpix->dirty_present) 8083bfa90b6Smrg REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present, 8093bfa90b6Smrg &spix->dirty_shadow); 8103bfa90b6Smrg 8113bfa90b6Smrg if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) { 8123bfa90b6Smrg RegionPtr upload = &intersection; 8133bfa90b6Smrg 8143bfa90b6Smrg /* 8153bfa90b6Smrg * Check whether we need to upload from GMR. 8163bfa90b6Smrg */ 8173bfa90b6Smrg 8183bfa90b6Smrg if (region) { 8193bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, &intersection, region, 8203bfa90b6Smrg &intersection); 8213bfa90b6Smrg upload = &intersection; 8223bfa90b6Smrg } 8233bfa90b6Smrg 8243bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, upload)) { 8253bfa90b6Smrg Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload); 8263bfa90b6Smrg if (ret) { 8273bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow, 8283bfa90b6Smrg &spix->dirty_shadow, upload); 8293bfa90b6Smrg if (vpix->dirty_present) 8303bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 8313bfa90b6Smrg vpix->dirty_present, upload); 8323bfa90b6Smrg } else { 8333bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 8343bfa90b6Smrg return FALSE; 8353bfa90b6Smrg } 8363bfa90b6Smrg } 8373bfa90b6Smrg } 8383bfa90b6Smrg REGION_UNINIT(vsaa->pScreen, &intersection); 8393bfa90b6Smrg return TRUE; 8403bfa90b6Smrg} 8413bfa90b6Smrg 8423bfa90b6Smrgstatic Bool 8433bfa90b6Smrgvmwgfx_copy_prepare(struct saa_driver *driver, 8443bfa90b6Smrg PixmapPtr src_pixmap, 8453bfa90b6Smrg PixmapPtr dst_pixmap, 8463bfa90b6Smrg int dx, 8473bfa90b6Smrg int dy, 8483bfa90b6Smrg int alu, 8493bfa90b6Smrg RegionPtr src_reg, 8503bfa90b6Smrg uint32_t plane_mask) 8513bfa90b6Smrg{ 8523bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 8533bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix; 8543bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix; 8553bfa90b6Smrg Bool has_dirty_hw; 8563bfa90b6Smrg Bool has_valid_hw; 8573bfa90b6Smrg 8583bfa90b6Smrg if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) || 8593bfa90b6Smrg alu != GXcopy) 8603bfa90b6Smrg return FALSE; 8613bfa90b6Smrg 8623bfa90b6Smrg src_vpix = vmwgfx_saa_pixmap(src_pixmap); 8633bfa90b6Smrg dst_vpix = vmwgfx_saa_pixmap(dst_pixmap); 8643bfa90b6Smrg 8653bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg, 8663bfa90b6Smrg &has_dirty_hw, &has_valid_hw); 8673bfa90b6Smrg 8683bfa90b6Smrg if (vmwgfx_is_present_hw(dst_pixmap) && 8693bfa90b6Smrg src_vpix->backing & VMWGFX_PIX_SURFACE) { 8703bfa90b6Smrg 8713bfa90b6Smrg if (!has_dirty_hw && !has_valid_hw) 8723bfa90b6Smrg return FALSE; 8733bfa90b6Smrg 8743bfa90b6Smrg if (!vmwgfx_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) 8753bfa90b6Smrg return FALSE; 8763bfa90b6Smrg if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { 8773bfa90b6Smrg vsaa->present_copy = TRUE; 8783bfa90b6Smrg return TRUE; 8793bfa90b6Smrg } 8803bfa90b6Smrg return FALSE; 8813bfa90b6Smrg } 8823bfa90b6Smrg 8833bfa90b6Smrg vsaa->present_copy = FALSE; 8843bfa90b6Smrg if (src_vpix != dst_vpix) { 8853bfa90b6Smrg 8863bfa90b6Smrg /* 8873bfa90b6Smrg * Use hardware acceleration either if source is partially only 8883bfa90b6Smrg * in hardware, or if source is entirely in hardware and destination 8893bfa90b6Smrg * has a hardware surface. 8903bfa90b6Smrg */ 8913bfa90b6Smrg 8923bfa90b6Smrg if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL))) 8933bfa90b6Smrg return FALSE; 8943bfa90b6Smrg 8953bfa90b6Smrg /* 8963bfa90b6Smrg * Determine surface formats. 8973bfa90b6Smrg */ 8983bfa90b6Smrg 8993bfa90b6Smrg if (src_vpix->base.src_format == 0) { 9003bfa90b6Smrg if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 9013bfa90b6Smrg return FALSE; 9023bfa90b6Smrg } else { 9033bfa90b6Smrg if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || 9043bfa90b6Smrg !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) 9053bfa90b6Smrg return FALSE; 9063bfa90b6Smrg } 9073bfa90b6Smrg 9083bfa90b6Smrg if (dst_vpix->base.dst_format == 0) { 9093bfa90b6Smrg if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) 9103bfa90b6Smrg return FALSE; 9113bfa90b6Smrg } else { 9123bfa90b6Smrg if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || 9133bfa90b6Smrg !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) 9143bfa90b6Smrg return FALSE; 9153bfa90b6Smrg } 9163bfa90b6Smrg 9173bfa90b6Smrg /* 9183bfa90b6Smrg * Create hardware surfaces. 9193bfa90b6Smrg */ 9203bfa90b6Smrg 9213bfa90b6Smrg if (!vmwgfx_hw_commit(src_pixmap)) 9223bfa90b6Smrg return FALSE; 9233bfa90b6Smrg if (!vmwgfx_hw_commit(dst_pixmap)) 9243bfa90b6Smrg return FALSE; 9253bfa90b6Smrg 9263bfa90b6Smrg /* 9273bfa90b6Smrg * Migrate data. 9283bfa90b6Smrg */ 9293bfa90b6Smrg 9303bfa90b6Smrg if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { 9313bfa90b6Smrg xa_copy_done(vsaa->xa_ctx); 9323bfa90b6Smrg return FALSE; 9333bfa90b6Smrg } 9343bfa90b6Smrg 9353bfa90b6Smrg /* 9363bfa90b6Smrg * Setup copy state. 9373bfa90b6Smrg */ 9383bfa90b6Smrg 9393bfa90b6Smrg if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != 9403bfa90b6Smrg XA_ERR_NONE) 9413bfa90b6Smrg return FALSE; 9423bfa90b6Smrg 9433bfa90b6Smrg return TRUE; 9443bfa90b6Smrg } 9453bfa90b6Smrg 9463bfa90b6Smrg return FALSE; 9473bfa90b6Smrg} 9483bfa90b6Smrg 9493bfa90b6Smrg 9503bfa90b6Smrgstatic void 9513bfa90b6Smrgvmwgfx_present_done(struct vmwgfx_saa *vsaa) 9523bfa90b6Smrg{ 9533bfa90b6Smrg ScreenPtr pScreen = vsaa->pScreen; 9543bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix; 9553bfa90b6Smrg 9563bfa90b6Smrg (void) pScreen; 9573bfa90b6Smrg if (!vsaa->diff_valid) 9583bfa90b6Smrg return; 9593bfa90b6Smrg 9603bfa90b6Smrg (void) vmwgfx_present(vsaa->drm_fd, dst_vpix->fb_id, 9613bfa90b6Smrg vsaa->xdiff, vsaa->ydiff, 9623bfa90b6Smrg &vsaa->present_region, vsaa->src_handle); 9633bfa90b6Smrg 9643bfa90b6Smrg REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff); 9653bfa90b6Smrg REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage, 9663bfa90b6Smrg &vsaa->present_region); 9673bfa90b6Smrg vsaa->diff_valid = FALSE; 9683bfa90b6Smrg REGION_UNINIT(pScreen, &vsaa->present_region); 9693bfa90b6Smrg} 9703bfa90b6Smrg 9713bfa90b6Smrgstatic void 9723bfa90b6Smrgvmwgfx_present_copy(struct vmwgfx_saa *vsaa, 9733bfa90b6Smrg int src_x, 9743bfa90b6Smrg int src_y, 9753bfa90b6Smrg int dst_x, 9763bfa90b6Smrg int dst_y, 9773bfa90b6Smrg int w, 9783bfa90b6Smrg int h) 9793bfa90b6Smrg{ 9803bfa90b6Smrg int xdiff = dst_x - src_x; 9813bfa90b6Smrg int ydiff = dst_y - src_y; 9823bfa90b6Smrg BoxRec box; 9833bfa90b6Smrg RegionRec reg; 9843bfa90b6Smrg 9853bfa90b6Smrg if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff))) 9863bfa90b6Smrg (void) vmwgfx_present_done(vsaa); 9873bfa90b6Smrg 9883bfa90b6Smrg if (!vsaa->diff_valid) { 9893bfa90b6Smrg vsaa->xdiff = xdiff; 9903bfa90b6Smrg vsaa->ydiff = ydiff; 9913bfa90b6Smrg vsaa->diff_valid = TRUE; 9923bfa90b6Smrg } 9933bfa90b6Smrg 9943bfa90b6Smrg box.x1 = src_x; 9953bfa90b6Smrg box.x2 = src_x + w; 9963bfa90b6Smrg box.y1 = src_y; 9973bfa90b6Smrg box.y2 = src_y + h; 9983bfa90b6Smrg 9993bfa90b6Smrg REGION_INIT(pScreen, ®, &box, 1); 10003bfa90b6Smrg REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); 10013bfa90b6Smrg REGION_UNINIT(pScreen, ®); 10023bfa90b6Smrg} 10033bfa90b6Smrg 10043bfa90b6Smrgstatic void 10053bfa90b6Smrgvmwgfx_copy(struct saa_driver *driver, 10063bfa90b6Smrg int src_x, 10073bfa90b6Smrg int src_y, 10083bfa90b6Smrg int dst_x, 10093bfa90b6Smrg int dst_y, 10103bfa90b6Smrg int w, 10113bfa90b6Smrg int h) 10123bfa90b6Smrg{ 10133bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 10143bfa90b6Smrg 10153bfa90b6Smrg if (vsaa->present_copy) { 10163bfa90b6Smrg vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h); 10173bfa90b6Smrg return; 10183bfa90b6Smrg } 10193bfa90b6Smrg xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h); 10203bfa90b6Smrg} 10213bfa90b6Smrg 10223bfa90b6Smrgstatic void 10233bfa90b6Smrgvmwgfx_copy_done(struct saa_driver *driver) 10243bfa90b6Smrg{ 10253bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 10263bfa90b6Smrg 10273bfa90b6Smrg if (vsaa->present_copy) { 10283bfa90b6Smrg vmwgfx_present_done(vsaa); 10293bfa90b6Smrg return; 10303bfa90b6Smrg } 10313bfa90b6Smrg xa_copy_done(vsaa->xa_ctx); 10323bfa90b6Smrg} 10333bfa90b6Smrg 10343bfa90b6Smrgstatic Bool 10353bfa90b6Smrgvmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, 10363bfa90b6Smrg PicturePtr src_pict, PicturePtr mask_pict, 10373bfa90b6Smrg PicturePtr dst_pict, 10383bfa90b6Smrg PixmapPtr src_pix, PixmapPtr mask_pix, 10393bfa90b6Smrg PixmapPtr dst_pix, 10403bfa90b6Smrg RegionPtr src_region, 10413bfa90b6Smrg RegionPtr mask_region, 10423bfa90b6Smrg RegionPtr dst_region) 10433bfa90b6Smrg{ 10443bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 10453bfa90b6Smrg struct vmwgfx_saa_pixmap *src_vpix; 10463bfa90b6Smrg struct vmwgfx_saa_pixmap *dst_vpix; 10473bfa90b6Smrg struct vmwgfx_saa_pixmap *mask_vpix; 10483bfa90b6Smrg Bool tmp_valid_hw; 10493bfa90b6Smrg Bool dirty_hw; 10503bfa90b6Smrg Bool valid_hw; 10513bfa90b6Smrg RegionRec empty; 10523bfa90b6Smrg struct xa_composite *xa_comp; 10533bfa90b6Smrg 10543bfa90b6Smrg REGION_NULL(pScreen, &empty); 10553bfa90b6Smrg 10563bfa90b6Smrg /* 10573bfa90b6Smrg * First we define our migration policy. We accelerate only if there 10583bfa90b6Smrg * are dirty hw regions to be read or if all source data is 10593bfa90b6Smrg * available in hw, and the destination has a hardware surface. 10603bfa90b6Smrg */ 10613bfa90b6Smrg dst_vpix = vmwgfx_saa_pixmap(dst_pix); 10623bfa90b6Smrg valid_hw = (dst_vpix->hw != NULL); 10633bfa90b6Smrg if (saa_op_reads_destination(op)) { 10643bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, 10653bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 10663bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 10673bfa90b6Smrg } else { 10683bfa90b6Smrg dirty_hw = FALSE; 10693bfa90b6Smrg dst_region = ∅ 10703bfa90b6Smrg } 10713bfa90b6Smrg 10723bfa90b6Smrg if (src_pix && !dirty_hw) { 10733bfa90b6Smrg src_vpix = vmwgfx_saa_pixmap(src_pix); 10743bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, 10753bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 10763bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 10773bfa90b6Smrg } 10783bfa90b6Smrg 10793bfa90b6Smrg if (mask_pict && mask_pix && !dirty_hw) { 10803bfa90b6Smrg mask_vpix = vmwgfx_saa_pixmap(mask_pix); 10813bfa90b6Smrg vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, 10823bfa90b6Smrg &dirty_hw, &tmp_valid_hw); 10833bfa90b6Smrg valid_hw = (valid_hw && tmp_valid_hw); 10843bfa90b6Smrg } 10853bfa90b6Smrg 10863bfa90b6Smrg /* 10873bfa90b6Smrg * In rendercheck mode we try to accelerate all supported 10883bfa90b6Smrg * composite operations. 10893bfa90b6Smrg */ 10903bfa90b6Smrg 10913bfa90b6Smrg if (!valid_hw && !dirty_hw && !vsaa->rendercheck) 10923bfa90b6Smrg goto out_err; 10933bfa90b6Smrg 10943bfa90b6Smrg /* 10953bfa90b6Smrg * Then, setup most of the XA composite state (except hardware surfaces) 10963bfa90b6Smrg * and check whether XA can accelerate. 10973bfa90b6Smrg */ 10983bfa90b6Smrg 10993bfa90b6Smrg xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, 11003bfa90b6Smrg src_pict, mask_pict, dst_pict); 11013bfa90b6Smrg if (!xa_comp) 11023bfa90b6Smrg goto out_err; 11033bfa90b6Smrg 11043bfa90b6Smrg if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) 11053bfa90b6Smrg goto out_err; 11063bfa90b6Smrg 11073bfa90b6Smrg /* 11083bfa90b6Smrg * Check that we can create the needed hardware surfaces. 11093bfa90b6Smrg */ 11103bfa90b6Smrg if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) 11113bfa90b6Smrg goto out_err; 11123bfa90b6Smrg if (mask_pict && mask_pix && 11133bfa90b6Smrg !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) 11143bfa90b6Smrg goto out_err; 11153bfa90b6Smrg if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) 11163bfa90b6Smrg goto out_err; 11173bfa90b6Smrg 11183bfa90b6Smrg /* 11193bfa90b6Smrg * Seems OK. Commit the changes, creating hardware surfaces. 11203bfa90b6Smrg */ 11213bfa90b6Smrg if (src_pix && !vmwgfx_hw_commit(src_pix)) 11223bfa90b6Smrg goto out_err; 11233bfa90b6Smrg if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) 11243bfa90b6Smrg goto out_err; 11253bfa90b6Smrg if (!vmwgfx_hw_commit(dst_pix)) 11263bfa90b6Smrg goto out_err; 11273bfa90b6Smrg 11283bfa90b6Smrg /* 11293bfa90b6Smrg * Update the XA state with our hardware surfaces and 11303bfa90b6Smrg * surface formats 11313bfa90b6Smrg */ 11323bfa90b6Smrg if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) 11333bfa90b6Smrg goto out_err; 11343bfa90b6Smrg 11353bfa90b6Smrg /* 11363bfa90b6Smrg * Migrate data to surfaces. 11373bfa90b6Smrg */ 11383bfa90b6Smrg if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) 11393bfa90b6Smrg goto out_err; 11403bfa90b6Smrg if (mask_pict && mask_pix && mask_region && 11413bfa90b6Smrg !vmwgfx_hw_validate(mask_pix, NULL)) 11423bfa90b6Smrg goto out_err; 11433bfa90b6Smrg if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) 11443bfa90b6Smrg goto out_err; 11453bfa90b6Smrg 11463bfa90b6Smrg 11473bfa90b6Smrg /* 11483bfa90b6Smrg * Bind the XA state. This must be done after data migration, since 11493bfa90b6Smrg * migration may change the hardware surfaces. 11503bfa90b6Smrg */ 11513bfa90b6Smrg if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) 11523bfa90b6Smrg goto out_err; 11533bfa90b6Smrg 11543bfa90b6Smrg return TRUE; 11553bfa90b6Smrg 11563bfa90b6Smrg out_err: 11573bfa90b6Smrg return FALSE; 11583bfa90b6Smrg} 11593bfa90b6Smrg 11603bfa90b6Smrgstatic void 11613bfa90b6Smrgvmwgfx_composite(struct saa_driver *driver, 11623bfa90b6Smrg int src_x, int src_y, int mask_x, int mask_y, 11633bfa90b6Smrg int dst_x, int dst_y, 11643bfa90b6Smrg int width, int height) 11653bfa90b6Smrg{ 11663bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 11673bfa90b6Smrg 11683bfa90b6Smrg xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, 11693bfa90b6Smrg dst_x, dst_y, width, height); 11703bfa90b6Smrg} 11713bfa90b6Smrg 11723bfa90b6Smrgstatic void 11733bfa90b6Smrgvmwgfx_composite_done(struct saa_driver *driver) 11743bfa90b6Smrg{ 11753bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 11763bfa90b6Smrg 11773bfa90b6Smrg xa_composite_done(vsaa->xa_ctx); 11783bfa90b6Smrg} 11793bfa90b6Smrg 11803bfa90b6Smrgstatic void 11813bfa90b6Smrgvmwgfx_takedown(struct saa_driver *driver) 11823bfa90b6Smrg{ 11833bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 11843bfa90b6Smrg 11853bfa90b6Smrg if (vsaa->vcomp) 11863bfa90b6Smrg vmwgfx_free_composite(vsaa->vcomp); 11873bfa90b6Smrg free(vsaa); 11883bfa90b6Smrg} 11893bfa90b6Smrg 11903bfa90b6Smrg/* 11913bfa90b6Smrg * This function call originates from the damage layer (outside SAA) 11923bfa90b6Smrg * to indicate that an operation is complete, and that damage is being 11933bfa90b6Smrg * processed. 11943bfa90b6Smrg */ 11953bfa90b6Smrgstatic void 11963bfa90b6Smrgvmwgfx_operation_complete(struct saa_driver *driver, 11973bfa90b6Smrg PixmapPtr pixmap) 11983bfa90b6Smrg{ 11993bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12003bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 12013bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 12023bfa90b6Smrg ScrnInfoPtr pScrn = xf86ScreenToScrn(vsaa->pScreen); 12033bfa90b6Smrg 12043bfa90b6Smrg /* 12053bfa90b6Smrg * Make dri2 drawables up to date, or add them to the flush list 12063bfa90b6Smrg * executed at glxWaitX(). Currently glxWaitX() is broken, so 12073bfa90b6Smrg * we flush immediately, unless we're VT-switched away, in which 12083bfa90b6Smrg * case a flush would deadlock in the kernel. 12093bfa90b6Smrg */ 12103bfa90b6Smrg 12113bfa90b6Smrg if (vpix->hw && vpix->hw_is_dri2_fronts) { 12123bfa90b6Smrg if (1 && pScrn->vtSema && 12133bfa90b6Smrg vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { 12143bfa90b6Smrg 12153bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); 12163bfa90b6Smrg return; 12173bfa90b6Smrg } 12183bfa90b6Smrg 12193bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->sync_x_head)) 12203bfa90b6Smrg WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); 12213bfa90b6Smrg } 12223bfa90b6Smrg} 12233bfa90b6Smrg 12243bfa90b6Smrg/* 12253bfa90b6Smrg * This function is called by SAA to indicate that SAA has 12263bfa90b6Smrg * dirtied a region of a pixmap, either as hw (accelerated) or as 12273bfa90b6Smrg * !hw (not accelerated). 12283bfa90b6Smrg */ 12293bfa90b6Smrgstatic Bool 12303bfa90b6Smrgvmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, 12313bfa90b6Smrg Bool hw, RegionPtr damage) 12323bfa90b6Smrg{ 12333bfa90b6Smrg struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); 12343bfa90b6Smrg struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap); 12353bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); 12363bfa90b6Smrg 12373bfa90b6Smrg /* 12383bfa90b6Smrg * Return if this is not a scanout pixmap. 12393bfa90b6Smrg */ 12403bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) 12413bfa90b6Smrg return TRUE; 12423bfa90b6Smrg 12433bfa90b6Smrg#if 0 12443bfa90b6Smrg /* 12453bfa90b6Smrg * This code can be enabled to immediately upload scanout sw 12463bfa90b6Smrg * contents to the hw surface. Otherwise this is done 12473bfa90b6Smrg * just before we call the kms update function for the hw 12483bfa90b6Smrg * surface. 12493bfa90b6Smrg */ 12503bfa90b6Smrg if (vsaa->only_hw_presents) { 12513bfa90b6Smrg if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) 12523bfa90b6Smrg return FALSE; 12533bfa90b6Smrg 12543bfa90b6Smrg REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, 12553bfa90b6Smrg &spix->dirty_shadow, damage); 12563bfa90b6Smrg hw = TRUE; 12573bfa90b6Smrg } 12583bfa90b6Smrg#endif 12593bfa90b6Smrg 12603bfa90b6Smrg /* 12613bfa90b6Smrg * Is the new scanout damage hw or sw? 12623bfa90b6Smrg */ 12633bfa90b6Smrg if (hw) { 12643bfa90b6Smrg /* 12653bfa90b6Smrg * Dump pending present into present tracking region. 12663bfa90b6Smrg */ 12673bfa90b6Smrg if (vpix->dirty_present && 12683bfa90b6Smrg REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) { 12693bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->dirty_present, 12703bfa90b6Smrg vpix->dirty_present, damage); 12713bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, vpix->present_damage); 12723bfa90b6Smrg } else { 12733bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) { 12743bfa90b6Smrg RegionRec reg; 12753bfa90b6Smrg 12763bfa90b6Smrg REGION_NULL(vsaa->pScreen, ®); 12773bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, 12783bfa90b6Smrg damage); 12793bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 12803bfa90b6Smrg vsaa->present_flush(vsaa->pScreen); 12813bfa90b6Smrg REGION_UNINIT(pScreen, ®); 12823bfa90b6Smrg } 12833bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->pending_present, 12843bfa90b6Smrg vpix->pending_present, damage); 12853bfa90b6Smrg if (vpix->dirty_present) 12863bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 12873bfa90b6Smrg vpix->dirty_present, damage); 12883bfa90b6Smrg } 12893bfa90b6Smrg } else { 12903bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { 12913bfa90b6Smrg RegionRec reg; 12923bfa90b6Smrg 12933bfa90b6Smrg REGION_NULL(vsaa->pScreen, ®); 12943bfa90b6Smrg REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, 12953bfa90b6Smrg damage); 12963bfa90b6Smrg if (REGION_NOTEMPTY(vsaa->pScreen, ®)) 12973bfa90b6Smrg vsaa->present_flush(vsaa->pScreen); 12983bfa90b6Smrg REGION_UNINIT(pScreen, ®); 12993bfa90b6Smrg } 13003bfa90b6Smrg REGION_UNION(vsaa->pScreen, vpix->pending_update, 13013bfa90b6Smrg vpix->pending_update, damage); 13023bfa90b6Smrg if (vpix->dirty_present) 13033bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, 13043bfa90b6Smrg vpix->dirty_present, damage); 13053bfa90b6Smrg } 13063bfa90b6Smrg 13073bfa90b6Smrg return TRUE; 13083bfa90b6Smrg} 13093bfa90b6Smrg 13103bfa90b6Smrg 13113bfa90b6Smrgstatic const struct saa_driver vmwgfx_saa_driver = { 13123bfa90b6Smrg .saa_major = SAA_VERSION_MAJOR, 13133bfa90b6Smrg .saa_minor = SAA_VERSION_MINOR, 13143bfa90b6Smrg .pixmap_size = sizeof(struct vmwgfx_saa_pixmap), 13153bfa90b6Smrg .damage = vmwgfx_dirty, 13163bfa90b6Smrg .operation_complete = vmwgfx_operation_complete, 13173bfa90b6Smrg .download_from_hw = vmwgfx_download_from_hw, 13183bfa90b6Smrg .release_from_cpu = vmwgfx_release_from_cpu, 13193bfa90b6Smrg .sync_for_cpu = vmwgfx_sync_for_cpu, 13203bfa90b6Smrg .map = vmwgfx_map, 13213bfa90b6Smrg .unmap = vmwgfx_unmap, 13223bfa90b6Smrg .create_pixmap = vmwgfx_create_pixmap, 13233bfa90b6Smrg .destroy_pixmap = vmwgfx_destroy_pixmap, 13243bfa90b6Smrg .modify_pixmap_header = vmwgfx_modify_pixmap_header, 13253bfa90b6Smrg .copy_prepare = vmwgfx_copy_prepare, 13263bfa90b6Smrg .copy = vmwgfx_copy, 13273bfa90b6Smrg .copy_done = vmwgfx_copy_done, 13283bfa90b6Smrg .composite_prepare = vmwgfx_composite_prepare, 13293bfa90b6Smrg .composite = vmwgfx_composite, 13303bfa90b6Smrg .composite_done = vmwgfx_composite_done, 13313bfa90b6Smrg .takedown = vmwgfx_takedown, 13323bfa90b6Smrg}; 13333bfa90b6Smrg 13343bfa90b6Smrg 13353bfa90b6SmrgBool 13363bfa90b6Smrgvmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, 13373bfa90b6Smrg void (*present_flush)(ScreenPtr pScreen), 13383bfa90b6Smrg Bool direct_presents, 13393bfa90b6Smrg Bool only_hw_presents, 13403bfa90b6Smrg Bool rendercheck) 13413bfa90b6Smrg{ 13423bfa90b6Smrg struct vmwgfx_saa *vsaa; 13433bfa90b6Smrg 13443bfa90b6Smrg vsaa = calloc(1, sizeof(*vsaa)); 13453bfa90b6Smrg if (!vsaa) 13463bfa90b6Smrg return FALSE; 13473bfa90b6Smrg 13483bfa90b6Smrg if (xat == NULL) { 13493bfa90b6Smrg direct_presents = FALSE; 13503bfa90b6Smrg only_hw_presents = FALSE; 13513bfa90b6Smrg } 13523bfa90b6Smrg 13533bfa90b6Smrg vsaa->pScreen = pScreen; 13543bfa90b6Smrg vsaa->xat = xat; 13553bfa90b6Smrg if (xat) 13563bfa90b6Smrg vsaa->xa_ctx = xa_context_default(xat); 13573bfa90b6Smrg vsaa->drm_fd = drm_fd; 13583bfa90b6Smrg vsaa->present_flush = present_flush; 13593bfa90b6Smrg vsaa->can_optimize_dma = FALSE; 13603bfa90b6Smrg vsaa->use_present_opt = direct_presents; 13613bfa90b6Smrg vsaa->only_hw_presents = only_hw_presents; 13623bfa90b6Smrg vsaa->rendercheck = rendercheck; 13633bfa90b6Smrg WSBMINITLISTHEAD(&vsaa->sync_x_list); 13643bfa90b6Smrg 13653bfa90b6Smrg vsaa->driver = vmwgfx_saa_driver; 13663bfa90b6Smrg vsaa->vcomp = vmwgfx_alloc_composite(); 13673bfa90b6Smrg 13683bfa90b6Smrg if (!vsaa->vcomp) 13693bfa90b6Smrg vsaa->driver.composite_prepare = NULL; 13703bfa90b6Smrg 13713bfa90b6Smrg if (!saa_driver_init(pScreen, &vsaa->driver)) 13723bfa90b6Smrg goto out_no_saa; 13733bfa90b6Smrg 13743bfa90b6Smrg return TRUE; 13753bfa90b6Smrg out_no_saa: 13763bfa90b6Smrg free(vsaa); 13773bfa90b6Smrg return FALSE; 13783bfa90b6Smrg} 13793bfa90b6Smrg 13803bfa90b6Smrg/* 13813bfa90b6Smrg * ************************************************************************* 13823bfa90b6Smrg * Scanout functions. 13833bfa90b6Smrg * These do not strictly belong here, but we choose to hide the scanout 13843bfa90b6Smrg * pixmap private data in the saa pixmaps. Might want to revisit this. 13853bfa90b6Smrg */ 13863bfa90b6Smrg 13873bfa90b6Smrg/* 13883bfa90b6Smrg * Make sure we flush / update this scanout on next update run. 13893bfa90b6Smrg */ 13903bfa90b6Smrg 13913bfa90b6Smrgvoid 13923bfa90b6Smrgvmwgfx_scanout_refresh(PixmapPtr pixmap) 13933bfa90b6Smrg{ 13943bfa90b6Smrg ScreenPtr pScreen = pixmap->drawable.pScreen; 13953bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 13963bfa90b6Smrg BoxRec box; 13973bfa90b6Smrg 13983bfa90b6Smrg (void) pScreen; 13993bfa90b6Smrg box.x1 = 0; 14003bfa90b6Smrg box.y1 = 0; 14013bfa90b6Smrg box.x2 = pixmap->drawable.width; 14023bfa90b6Smrg box.y2 = pixmap->drawable.height; 14033bfa90b6Smrg 14043bfa90b6Smrg REGION_RESET(vsaa->pScreen, vpix->pending_present, &box); 14053bfa90b6Smrg if (vpix->dirty_present) 14063bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 14073bfa90b6Smrg vpix->pending_present, vpix->dirty_present); 14083bfa90b6Smrg REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, 14093bfa90b6Smrg vpix->pending_present, &vpix->base.dirty_shadow); 14103bfa90b6Smrg REGION_COPY(vsaa->pScreen, vpix->pending_update, 14113bfa90b6Smrg &vpix->base.dirty_shadow); 14123bfa90b6Smrg} 14133bfa90b6Smrg 14143bfa90b6Smrg/* 14153bfa90b6Smrg * Take a "scanout reference" on a pixmap. If this is the first scanout 14163bfa90b6Smrg * reference, allocate resources needed for scanout, like proper 14173bfa90b6Smrg * damage tracking and kms fbs. 14183bfa90b6Smrg */ 14193bfa90b6Smrg 14203bfa90b6Smrguint32_t 14213bfa90b6Smrgvmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry) 14223bfa90b6Smrg{ 14233bfa90b6Smrg PixmapPtr pixmap = entry->pixmap; 14243bfa90b6Smrg struct vmwgfx_saa *vsaa = 14253bfa90b6Smrg to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 14263bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 14273bfa90b6Smrg 14283bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) { 14293bfa90b6Smrg uint32_t handle, dummy; 14303bfa90b6Smrg unsigned int depth; 14313bfa90b6Smrg 14323bfa90b6Smrg if (vsaa->only_hw_presents) { 14333bfa90b6Smrg /* 14343bfa90b6Smrg * The KMS fb will be a HW surface. Create it, add damage 14353bfa90b6Smrg * and get the handle. 14363bfa90b6Smrg */ 14373bfa90b6Smrg if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 0, NULL)) 14383bfa90b6Smrg goto out_err; 14393bfa90b6Smrg if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) 14403bfa90b6Smrg goto out_err; 14413bfa90b6Smrg depth = xa_format_depth(xa_surface_format(vpix->hw)); 14423bfa90b6Smrg 14433bfa90b6Smrg } else { 14443bfa90b6Smrg /* 14453bfa90b6Smrg * The KMS fb will be a Guest Memory Region. Create it, 14463bfa90b6Smrg * add damage and get the handle. 14473bfa90b6Smrg */ 14483bfa90b6Smrg if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) 14493bfa90b6Smrg goto out_err; 14503bfa90b6Smrg 14513bfa90b6Smrg handle = vpix->gmr->handle; 14523bfa90b6Smrg depth = pixmap->drawable.depth; 14533bfa90b6Smrg 14543bfa90b6Smrg } 14553bfa90b6Smrg 14563bfa90b6Smrg if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) 14573bfa90b6Smrg goto out_no_present; 14583bfa90b6Smrg 14593bfa90b6Smrg if (drmModeAddFB(vsaa->drm_fd, 14603bfa90b6Smrg pixmap->drawable.width, 14613bfa90b6Smrg pixmap->drawable.height, 14623bfa90b6Smrg depth, 14633bfa90b6Smrg pixmap->drawable.bitsPerPixel, 14643bfa90b6Smrg pixmap->devKind, 14653bfa90b6Smrg handle, 14663bfa90b6Smrg &vpix->fb_id) != 0) 14673bfa90b6Smrg goto out_no_fb;; 14683bfa90b6Smrg } 14693bfa90b6Smrg pixmap->refcnt += 1; 14703bfa90b6Smrg WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); 14713bfa90b6Smrg return vpix->fb_id; 14723bfa90b6Smrg 14733bfa90b6Smrg out_no_fb: 14743bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 14753bfa90b6Smrg out_no_present: 14763bfa90b6Smrg vmwgfx_pixmap_remove_damage(pixmap); 14773bfa90b6Smrg out_err: 14783bfa90b6Smrg vpix->fb_id = -1; 14793bfa90b6Smrg return -1; 14803bfa90b6Smrg} 14813bfa90b6Smrg 14823bfa90b6Smrg/* 14833bfa90b6Smrg * Free a "scanout reference" on a pixmap. If this was the last scanout 14843bfa90b6Smrg * reference, free pixmap resources needed for scanout, like 14853bfa90b6Smrg * damage tracking and kms fbs. 14863bfa90b6Smrg */ 14873bfa90b6Smrgvoid 14883bfa90b6Smrgvmwgfx_scanout_unref(struct vmwgfx_screen_entry *entry) 14893bfa90b6Smrg{ 14903bfa90b6Smrg struct vmwgfx_saa *vsaa; 14913bfa90b6Smrg struct vmwgfx_saa_pixmap *vpix; 14923bfa90b6Smrg PixmapPtr pixmap = entry->pixmap; 14933bfa90b6Smrg 14943bfa90b6Smrg if (!pixmap) 14953bfa90b6Smrg return; 14963bfa90b6Smrg 14973bfa90b6Smrg vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); 14983bfa90b6Smrg vpix = vmwgfx_saa_pixmap(pixmap); 14993bfa90b6Smrg WSBMLISTDELINIT(&entry->scanout_head); 15003bfa90b6Smrg 15013bfa90b6Smrg if (WSBMLISTEMPTY(&vpix->scanout_list)) { 15023bfa90b6Smrg REGION_EMPTY(vsaa->pScreen, vpix->pending_update); 15033bfa90b6Smrg drmModeRmFB(vsaa->drm_fd, vpix->fb_id); 15043bfa90b6Smrg vpix->fb_id = -1; 15053bfa90b6Smrg vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL); 15063bfa90b6Smrg vmwgfx_pixmap_remove_present(vpix); 15073bfa90b6Smrg vmwgfx_pixmap_remove_damage(pixmap); 15083bfa90b6Smrg } 15093bfa90b6Smrg 15103bfa90b6Smrg entry->pixmap = NULL; 15113bfa90b6Smrg pixmap->drawable.pScreen->DestroyPixmap(pixmap); 15123bfa90b6Smrg} 1513