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, &reg, &box, 1);
10653bfa90b6Smrg    REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, &reg);
10663bfa90b6Smrg    REGION_UNINIT(pScreen, &reg);
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 = &empty;
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, &reg);
13533bfa90b6Smrg		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_update,
13543bfa90b6Smrg				 damage);
13553bfa90b6Smrg		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
13563bfa90b6Smrg		    vsaa->present_flush(vsaa->pScreen);
13573bfa90b6Smrg		REGION_UNINIT(pScreen, &reg);
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, &reg);
13703bfa90b6Smrg		REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_present,
13713bfa90b6Smrg				 damage);
13723bfa90b6Smrg		if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
13733bfa90b6Smrg		    vsaa->present_flush(vsaa->pScreen);
13743bfa90b6Smrg		REGION_UNINIT(pScreen, &reg);
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