vmwgfx, saa: Initial import
authorThomas Hellstrom <thellstrom@vmware.com>
Thu, 16 Jun 2011 13:55:07 +0000 (15:55 +0200)
committerThomas Hellstrom <thellstrom@vmware.com>
Thu, 16 Jun 2011 14:04:47 +0000 (16:04 +0200)
This imports the vmwgfx driver, based on the Gallium3D Xorg state tracker,
as well as the saa library. A "Shadow Acceleration Architecture", which is
optimized for the case where transfers between system (shadow) and hw memory
is very costly.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
27 files changed:
Makefile.am
configure.ac
saa/Makefile.am [new file with mode: 0644]
saa/saa.c [new file with mode: 0644]
saa/saa.h [new file with mode: 0644]
saa/saa_accel.c [new file with mode: 0644]
saa/saa_pixmap.c [new file with mode: 0644]
saa/saa_priv.h [new file with mode: 0644]
saa/saa_render.c [new file with mode: 0644]
saa/saa_unaccel.c [new file with mode: 0644]
src/svga_reg.h
vmwgfx/Makefile.am [new file with mode: 0644]
vmwgfx/svga3d_reg.h [new file with mode: 0644]
vmwgfx/vmwgfx_bootstrap.c [new file with mode: 0644]
vmwgfx/vmwgfx_crtc.c [new file with mode: 0644]
vmwgfx/vmwgfx_ctrl.c [new file with mode: 0644]
vmwgfx/vmwgfx_ctrl.h [new file with mode: 0644]
vmwgfx/vmwgfx_dri2.c [new file with mode: 0644]
vmwgfx/vmwgfx_driver.c [new file with mode: 0644]
vmwgfx/vmwgfx_driver.h [new file with mode: 0644]
vmwgfx/vmwgfx_drmi.c [new file with mode: 0644]
vmwgfx/vmwgfx_drmi.h [new file with mode: 0644]
vmwgfx/vmwgfx_output.c [new file with mode: 0644]
vmwgfx/vmwgfx_overlay.c [new file with mode: 0644]
vmwgfx/vmwgfx_saa.c [new file with mode: 0644]
vmwgfx/vmwgfx_saa.h [new file with mode: 0644]
vmwgfx/vmwgfx_tex_video.c [new file with mode: 0644]

index 093e9f5..fff57f6 100644 (file)
@@ -18,7 +18,7 @@
 #  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 #  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-SUBDIRS = src man vmwarectrl
+SUBDIRS = src man vmwarectrl saa vmwgfx
 MAINTAINERCLEANFILES = ChangeLog INSTALL
 .PHONY: ChangeLog INSTALL
 
index cd2854e..bbb530a 100644 (file)
@@ -121,5 +121,7 @@ AC_CONFIG_FILES([
                 src/Makefile
                 vmwarectrl/Makefile
                 man/Makefile
+               saa/Makefile
+               vmwgfx/Makefile
 ])
 AC_OUTPUT
diff --git a/saa/Makefile.am b/saa/Makefile.am
new file mode 100644 (file)
index 0000000..4f56d3f
--- /dev/null
@@ -0,0 +1,13 @@
+libsaa_la_LTLIBRARIES = libsaa.la
+libsaa_ladir = @libdir@
+
+libsaa_la_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS)
+libsaa_la_SOURCES = \
+       saa.c \
+       saa_pixmap.c \
+       saa_unaccel.c \
+       saa_priv.h \
+       saa_render.c \
+       saa_accel.c \
+       saa.h
+
diff --git a/saa/saa.c b/saa/saa.c
new file mode 100644 (file)
index 0000000..e9567e3
--- /dev/null
+++ b/saa/saa.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright © 2001 Keith Packard
+ *
+ * Partly based on code that is Copyright © The XFree86 Project Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/** @file
+ * This file covers the initialization and teardown of SAA, and has various
+ * functions not responsible for performing rendering, pixmap migration, or
+ * memory management.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "saa_priv.h"
+#include <X11/fonts/fontstruct.h>
+#include "dixfontstr.h"
+#include "regionstr.h"
+#include "saa.h"
+
+#ifdef SAA_DEVPRIVATEKEYREC
+DevPrivateKeyRec saa_screen_index;
+DevPrivateKeyRec saa_pixmap_index;
+DevPrivateKeyRec saa_gc_index;
+#else
+int saa_screen_index = -1;
+int saa_pixmap_index = -1;
+int saa_gc_index = -1;
+#endif
+
+/**
+ * saa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
+ *
+ * @param pDrawable the drawable being requested.
+ *
+ * This function returns the backing pixmap for a drawable, whether it is a
+ * redirected window, unredirected window, or already a pixmap.  Note that
+ * coordinate translation is needed when drawing to the backing pixmap of a
+ * redirected window, and the translation coordinates are provided by calling
+ * saa_get_drawable_pixmap() on the drawable.
+ */
+PixmapPtr
+saa_get_drawable_pixmap(DrawablePtr pDrawable)
+{
+    if (pDrawable->type == DRAWABLE_WINDOW)
+       return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
+    else
+       return (PixmapPtr) pDrawable;
+}
+
+/**
+ * Sets the offsets to add to coordinates to make them address the same bits in
+ * the backing drawable. These coordinates are nonzero only for redirected
+ * windows.
+ */
+void
+saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
+                       int *xp, int *yp)
+{
+#ifdef COMPOSITE
+    if (pDrawable->type == DRAWABLE_WINDOW) {
+       *xp = -pPixmap->screen_x;
+       *yp = -pPixmap->screen_y;
+       return;
+    }
+#endif
+
+    *xp = 0;
+    *yp = 0;
+}
+
+/**
+ * Returns the pixmap which backs a drawable, and the offsets to add to
+ * coordinates to make them address the same bits in the backing drawable.
+ */
+PixmapPtr
+saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp)
+{
+    PixmapPtr pixmap = saa_get_drawable_pixmap(drawable);
+
+    saa_get_drawable_deltas(drawable, pixmap, xp, yp);
+
+    return pixmap;
+}
+
+static Bool
+saa_download_from_hw(PixmapPtr pix, RegionPtr readback)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
+    struct saa_driver *driver = sscreen->driver;
+    struct saa_pixmap *spix = saa_pixmap(pix);
+    void *addr;
+    Bool ret;
+
+    if (spix->mapped_access)
+       driver->release_from_cpu(driver, pix, spix->mapped_access);
+
+    ret = driver->download_from_hw(driver, pix, readback);
+
+    if (spix->mapped_access) {
+       addr = driver->sync_for_cpu(driver, pix, spix->mapped_access);
+       if (addr != NULL)
+           spix->addr = addr;
+    }
+
+    return ret;
+}
+
+Bool
+saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
+                         RegionPtr read_reg)
+{
+    ScreenPtr pScreen = pix->drawable.pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    struct saa_driver *driver = sscreen->driver;
+    struct saa_pixmap *spix = saa_pixmap(pix);
+    saa_access_t map_access = 0;
+    Bool ret = TRUE;
+
+    if (read_reg && REGION_NOTEMPTY(pScreen, read_reg))
+       ret = saa_download_from_hw(pix, read_reg);
+
+    if (!ret) {
+       LogMessage(X_ERROR, "Prepare access pixmap failed.\n");
+       return ret;
+    }
+
+    if ((access & SAA_ACCESS_R) != 0 && spix->read_access++ == 0)
+       map_access = SAA_ACCESS_R;
+    if ((access & SAA_ACCESS_W) != 0 && spix->write_access++ == 0)
+       map_access |= SAA_ACCESS_W;
+
+    if (map_access) {
+       if (spix->auth_loc != saa_loc_override) {
+           (void)driver->sync_for_cpu(driver, pix, map_access);
+           spix->addr = driver->map(driver, pix, map_access);
+       } else
+           spix->addr = spix->override;
+       spix->mapped_access |= map_access;
+    }
+
+    pix->devPrivate.ptr = spix->addr;
+    return TRUE;
+}
+
+void
+saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
+    struct saa_driver *driver = sscreen->driver;
+    struct saa_pixmap *spix = saa_pixmap(pix);
+    saa_access_t unmap_access = 0;
+
+    if ((access & SAA_ACCESS_R) != 0 && --spix->read_access == 0)
+       unmap_access = SAA_ACCESS_R;
+    if ((access & SAA_ACCESS_W) != 0 && --spix->write_access == 0)
+       unmap_access |= SAA_ACCESS_W;
+
+    if (spix->read_access < 0)
+       LogMessage(X_ERROR, "Incorrect read access.\n");
+    if (spix->write_access < 0)
+       LogMessage(X_ERROR, "Incorrect write access.\n");
+
+    if (unmap_access) {
+       if (spix->auth_loc != saa_loc_override) {
+           driver->unmap(driver, pix, unmap_access);
+           driver->release_from_cpu(driver, pix, unmap_access);
+       }
+       spix->mapped_access &= ~unmap_access;
+    }
+    if (!spix->mapped_access) {
+       spix->addr = NULL;
+       pix->devPrivate.ptr = SAA_INVALID_ADDRESS;
+    }
+}
+
+/*
+ * Callback that is called after a rendering operation. We try to
+ * determine whether it's a shadow damage or a hw damage and call the
+ * driver callback.
+ */
+
+static void
+saa_report_damage(DamagePtr damage, RegionPtr reg, void *closure)
+{
+    PixmapPtr pixmap = (PixmapPtr) closure;
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct saa_driver *driver = saa_screen(pixmap->drawable.pScreen)->driver;
+
+    if (spix->read_access || spix->write_access)
+       LogMessage(X_ERROR, "Damage report inside prepare access.\n");
+
+    driver->operation_complete(driver, pixmap);
+    DamageEmpty(damage);
+}
+
+Bool
+saa_add_damage(PixmapPtr pixmap)
+{
+    ScreenPtr pScreen = pixmap->drawable.pScreen;
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+
+    if (spix->damage)
+       return TRUE;
+
+    spix->damage = DamageCreate(saa_report_damage, NULL,
+                               DamageReportRawRegion, TRUE, pScreen, pixmap);
+    if (!spix->damage)
+       return FALSE;
+
+    DamageRegister(&pixmap->drawable, spix->damage);
+    DamageSetReportAfterOp(spix->damage, TRUE);
+
+    return TRUE;
+}
+
+static inline RegionPtr
+saa_pix_damage_region(struct saa_pixmap *spix)
+{
+    return (spix->damage ? DamageRegion(spix->damage) : NULL);
+}
+
+Bool
+saa_pad_read(DrawablePtr draw)
+{
+    ScreenPtr pScreen = draw->pScreen;
+    PixmapPtr pix;
+    int xp;
+    int yp;
+    BoxRec box;
+    RegionRec entire;
+    Bool ret;
+
+    (void)pScreen;
+    pix = saa_get_pixmap(draw, &xp, &yp);
+
+    box.x1 = draw->x + xp;
+    box.y1 = draw->y + yp;
+    box.x2 = box.x1 + draw->width;
+    box.y2 = box.y1 + draw->height;
+
+    REGION_INIT(pScreen, &entire, &box, 1);
+    ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
+    REGION_UNINIT(pScreen, &entire);
+    return ret;
+}
+
+Bool
+saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h)
+{
+    ScreenPtr pScreen = draw->pScreen;
+    PixmapPtr pix;
+    int xp;
+    int yp;
+    BoxRec box;
+    RegionRec entire;
+    Bool ret;
+
+    (void)pScreen;
+    pix = saa_get_pixmap(draw, &xp, &yp);
+
+    box.x1 = x + xp;
+    box.y1 = y + yp;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    REGION_INIT(pScreen, &entire, &box, 1);
+    ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
+    REGION_UNINIT(pScreen, &entire);
+    return ret;
+}
+
+/**
+ * Prepares a drawable destination for access, and maps it read-write.
+ * If check_read is TRUE, pGC should point to a valid GC. The drawable
+ * may then be mapped write-only if the pending operation admits.
+ */
+
+Bool
+saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
+             saa_access_t * access)
+{
+    int xp;
+    int yp;
+    PixmapPtr pixmap = saa_get_pixmap(draw, &xp, &yp);
+    struct saa_pixmap *spix = saa_pixmap(pixmap);
+
+    *access = SAA_ACCESS_W;
+
+    /*
+     * If the to-be-damaged area doesn't depend at all on previous
+     * rendered contents, we don't need to do any readback.
+     */
+
+    if (check_read && !saa_gc_reads_destination(draw, pGC))
+       return saa_prepare_access_pixmap(pixmap, *access, NULL);
+
+    *access |= SAA_ACCESS_R;
+
+    /*
+     * Read back the area to be damaged.
+     */
+
+    return saa_prepare_access_pixmap(pixmap, *access,
+                                    saa_pix_damage_pending(spix));
+}
+
+void
+saa_fad_read(DrawablePtr draw)
+{
+    saa_finish_access_pixmap(saa_get_drawable_pixmap(draw), SAA_ACCESS_R);
+}
+
+void
+saa_fad_write(DrawablePtr draw, saa_access_t access)
+{
+    PixmapPtr pix = saa_get_drawable_pixmap(draw);
+    struct saa_pixmap *spix = saa_pixmap(pix);
+
+    saa_finish_access_pixmap(pix, access);
+    if (spix->damage)
+       saa_pixmap_dirty(pix, FALSE, saa_pix_damage_pending(spix));
+}
+
+Bool
+saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC)
+{
+    return ((pGC->alu != GXcopy && pGC->alu != GXclear && pGC->alu != GXset &&
+            pGC->alu != GXcopyInverted) || pGC->fillStyle == FillStippled ||
+           pGC->clientClipType != CT_NONE ||
+           !SAA_PM_IS_SOLID(pDrawable, pGC->planemask));
+}
+
+Bool
+saa_op_reads_destination(CARD8 op)
+{
+    /* FALSE (does not read destination) is the list of ops in the protocol
+     * document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
+     * That's just Clear and Src.  ReduceCompositeOp() will already have
+     * converted con/disjoint clear/src to Clear or Src.
+     */
+    switch (op) {
+    case PictOpClear:
+    case PictOpSrc:
+       return FALSE;
+    default:
+       return TRUE;
+    }
+}
+
+static void
+saa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
+{
+    /* fbValidateGC will do direct access to pixmaps if the tiling has changed.
+     * Do a few smart things so fbValidateGC can do it's work.
+     */
+
+    ScreenPtr pScreen = pDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    PixmapPtr pTile = NULL;
+    Bool finish_current_tile = FALSE;
+
+    /* Either of these conditions is enough to trigger access to a tile pixmap. */
+    /* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
+    if (pGC->fillStyle == FillTiled
+       || ((changes & GCTile) && !pGC->tileIsPixel)) {
+       pTile = pGC->tile.pixmap;
+
+       /* Sometimes tile pixmaps are swapped, you need access to:
+        * - The current tile if it depth matches.
+        * - Or the rotated tile if that one matches depth and !(changes & GCTile).
+        * - Or the current tile pixmap and a newly created one.
+        */
+       if (pTile && pTile->drawable.depth != pDrawable->depth
+           && !(changes & GCTile)) {
+           PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
+
+           if (pRotatedTile
+               && pRotatedTile->drawable.depth == pDrawable->depth)
+               pTile = pRotatedTile;
+           else
+               finish_current_tile = TRUE;     /* CreatePixmap will be called. */
+       }
+    }
+
+    if (pGC->stipple && !saa_pad_read(&pGC->stipple->drawable)) {
+       LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
+       return;
+    }
+
+    if (pTile && !saa_pad_read(&pTile->drawable)) {
+       LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
+       goto out_no_tile;
+    }
+
+    /* Calls to Create/DestroyPixmap have to be identified as special, so
+     * up sscreen->fallback_count.
+     */
+
+    sscreen->fallback_count++;
+    saa_swap(sgc, pGC, funcs);
+    (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+    saa_swap(sgc, pGC, funcs);
+
+    if (finish_current_tile && pGC->tile.pixmap)
+       saa_fad_write(&pGC->tile.pixmap->drawable, SAA_ACCESS_W);
+    sscreen->fallback_count--;
+
+    if (pTile)
+       saa_fad_read(&pTile->drawable);
+ out_no_tile:
+    if (pGC->stipple)
+       saa_fad_read(&pGC->stipple->drawable);
+}
+
+static void
+saa_destroy_gc(GCPtr pGC)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+
+    saa_swap(sgc, pGC, funcs);
+    (*pGC->funcs->DestroyGC) (pGC);
+    saa_swap(sgc, pGC, funcs);
+}
+
+static void
+saa_change_gc(GCPtr pGC, unsigned long mask)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+
+    saa_swap(sgc, pGC, funcs);
+    (*pGC->funcs->ChangeGC) (pGC, mask);
+    saa_swap(sgc, pGC, funcs);
+}
+
+static void
+saa_copy_gc(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGCDst);
+
+    saa_swap(sgc, pGCDst, funcs);
+    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
+    saa_swap(sgc, pGCDst, funcs);
+}
+
+static void
+saa_change_clip(GCPtr pGC, int type, pointer pvalue, int nrects)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+
+    saa_swap(sgc, pGC, funcs);
+    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
+    saa_swap(sgc, pGC, funcs);
+}
+
+static void
+saa_copy_clip(GCPtr pGCDst, GCPtr pGCSrc)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGCDst);
+
+    saa_swap(sgc, pGCDst, funcs);
+    (*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
+    saa_swap(sgc, pGCDst, funcs);
+}
+
+static void
+saa_destroy_clip(GCPtr pGC)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+
+    saa_swap(sgc, pGC, funcs);
+    (*pGC->funcs->DestroyClip) (pGC);
+    saa_swap(sgc, pGC, funcs);
+}
+
+static GCFuncs saa_gc_funcs = {
+    saa_validate_gc,
+    saa_change_gc,
+    saa_copy_gc,
+    saa_destroy_gc,
+    saa_change_clip,
+    saa_destroy_clip,
+    saa_copy_clip
+};
+
+/**
+ * saa_create_gc makes a new GC and hooks up its funcs handler, so that
+ * saa_validate_gc() will get called.
+ */
+int
+saa_create_gc(GCPtr pGC)
+{
+    ScreenPtr pScreen = pGC->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    Bool ret;
+
+    saa_swap(sscreen, pScreen, CreateGC);
+    ret = pScreen->CreateGC(pGC);
+    if (ret) {
+       saa_wrap(sgc, pGC, funcs, &saa_gc_funcs);
+       saa_wrap(sgc, pGC, ops, &saa_gc_ops);
+    }
+    saa_swap(sscreen, pScreen, CreateGC);
+
+    return ret;
+}
+
+static Bool
+saa_prepare_access_window(WindowPtr pWin)
+{
+    if (pWin->backgroundState == BackgroundPixmap) {
+       if (!saa_pad_read(&pWin->background.pixmap->drawable))
+           return FALSE;
+    }
+
+    if (pWin->borderIsPixel == FALSE) {
+       if (!saa_pad_read(&pWin->border.pixmap->drawable)) {
+           if (pWin->backgroundState == BackgroundPixmap)
+               saa_fad_read(&pWin->background.pixmap->drawable);
+           return FALSE;
+       }
+    }
+    return TRUE;
+}
+
+static void
+saa_finish_access_window(WindowPtr pWin)
+{
+    if (pWin->backgroundState == BackgroundPixmap)
+       saa_fad_read(&pWin->background.pixmap->drawable);
+
+    if (pWin->borderIsPixel == FALSE)
+       saa_fad_read(&pWin->border.pixmap->drawable);
+}
+
+static Bool
+saa_change_window_attributes(WindowPtr pWin, unsigned long mask)
+{
+    Bool ret;
+
+    if (!saa_prepare_access_window(pWin))
+       return FALSE;
+    ret = fbChangeWindowAttributes(pWin, mask);
+    saa_finish_access_window(pWin);
+    return ret;
+}
+
+RegionPtr
+saa_bitmap_to_region(PixmapPtr pPix)
+{
+    RegionPtr ret;
+
+    if (!saa_pad_read(&pPix->drawable))
+       return NULL;
+    ret = fbPixmapToRegion(pPix);
+    saa_fad_read(&pPix->drawable);
+    return ret;
+}
+
+void
+saa_set_fallback_debug(ScreenPtr screen, Bool enable)
+{
+    struct saa_screen_priv *sscreen = saa_screen(screen);
+
+    sscreen->fallback_debug = enable;
+}
+
+/**
+ * saa_close_screen() unwraps its wrapped screen functions and tears down SAA's
+ * screen private, before calling down to the next CloseScreen.
+ */
+Bool
+saa_close_screen(int i, ScreenPtr pScreen)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    struct saa_driver *driver = sscreen->driver;
+
+    if (pScreen->devPrivate) {
+       /* Destroy the pixmap created by miScreenInit() *before*
+        * chaining up as we finalize ourselves here and so this
+        * is the last chance we have of releasing our resources
+        * associated with the Pixmap. So do it first.
+        */
+       (void)(*pScreen->DestroyPixmap) (pScreen->devPrivate);
+       pScreen->devPrivate = NULL;
+    }
+
+    saa_unwrap(sscreen, pScreen, CloseScreen);
+    saa_unwrap(sscreen, pScreen, CreateGC);
+    saa_unwrap(sscreen, pScreen, ChangeWindowAttributes);
+    saa_unwrap(sscreen, pScreen, CreatePixmap);
+    saa_unwrap(sscreen, pScreen, DestroyPixmap);
+    saa_unwrap(sscreen, pScreen, ModifyPixmapHeader);
+    saa_unwrap(sscreen, pScreen, BitmapToRegion);
+#ifdef RENDER
+    saa_render_takedown(pScreen);
+#endif
+    saa_unaccel_takedown(pScreen);
+    driver->takedown(driver);
+
+    free(sscreen);
+
+    return (*pScreen->CloseScreen) (i, pScreen);
+}
+
+struct saa_driver *
+saa_get_driver(ScreenPtr pScreen)
+{
+    return saa_screen(pScreen)->driver;
+}
+
+/**
+ * @param pScreen screen being initialized
+ * @param pScreenInfo SAA driver record
+ *
+ * saa_driver_init sets up SAA given a driver record filled in by the driver.
+ * pScreenInfo should have been allocated by saa_driver_alloc().  See the
+ * comments in _SaaDriver for what must be filled in and what is optional.
+ *
+ * @return TRUE if SAA was successfully initialized.
+ */
+Bool
+saa_driver_init(ScreenPtr screen, struct saa_driver * saa_driver)
+{
+    struct saa_screen_priv *sscreen;
+
+    if (!saa_driver)
+       return FALSE;
+
+    if (saa_driver->saa_major != SAA_VERSION_MAJOR ||
+       saa_driver->saa_minor > SAA_VERSION_MINOR) {
+       LogMessage(X_ERROR,
+                  "SAA(%d): driver's SAA version requirements "
+                  "(%d.%d) are incompatible with SAA version (%d.%d)\n",
+                  screen->myNum, saa_driver->saa_major,
+                  saa_driver->saa_minor, SAA_VERSION_MAJOR, SAA_VERSION_MINOR);
+       return FALSE;
+    }
+#if 0
+    if (!saa_driver->prepare_solid) {
+       LogMessage(X_ERROR,
+                  "SAA(%d): saa_driver_t::prepare_solid must be "
+                  "non-NULL\n", screen->myNum);
+       return FALSE;
+    }
+
+    if (!saa_driver->prepare_copy) {
+       LogMessage(X_ERROR,
+                  "SAA(%d): saa_driver_t::prepare_copy must be "
+                  "non-NULL\n", screen->myNum);
+       return FALSE;
+    }
+#endif
+#ifdef SAA_DEVPRIVATEKEYREC
+    if (!dixRegisterPrivateKey(&saa_screen_index, PRIVATE_SCREEN, 0)) {
+       LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
+       return FALSE;
+    }
+    if (!dixRegisterPrivateKey(&saa_pixmap_index, PRIVATE_PIXMAP,
+                              saa_driver->pixmap_size)) {
+       LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
+       return FALSE;
+    }
+    if (!dixRegisterPrivateKey(&saa_gc_index, PRIVATE_GC,
+                              sizeof(struct saa_gc_priv))) {
+       LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
+       return FALSE;
+    }
+#else
+    if (!dixRequestPrivate(&saa_screen_index, 0)) {
+       LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
+       return FALSE;
+    }
+    if (!dixRequestPrivate(&saa_pixmap_index, saa_driver->pixmap_size)) {
+       LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
+       return FALSE;
+    }
+    if (!dixRequestPrivate(&saa_gc_index, sizeof(struct saa_gc_priv))) {
+       LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
+       return FALSE;
+    }
+#endif
+
+    sscreen = calloc(1, sizeof(*sscreen));
+
+    if (!sscreen) {
+       LogMessage(X_WARNING,
+                  "SAA(%d): Failed to allocate screen private\n",
+                  screen->myNum);
+       return FALSE;
+    }
+
+    sscreen->driver = saa_driver;
+    dixSetPrivate(&screen->devPrivates, &saa_screen_index, sscreen);
+
+    /*
+     * Replace various fb screen functions
+     */
+
+    saa_wrap(sscreen, screen, CloseScreen, saa_close_screen);
+    saa_wrap(sscreen, screen, CreateGC, saa_create_gc);
+    saa_wrap(sscreen, screen, ChangeWindowAttributes,
+            saa_change_window_attributes);
+    saa_wrap(sscreen, screen, CreatePixmap, saa_create_pixmap);
+    saa_wrap(sscreen, screen, DestroyPixmap, saa_destroy_pixmap);
+    saa_wrap(sscreen, screen, ModifyPixmapHeader, saa_modify_pixmap_header);
+
+    saa_wrap(sscreen, screen, BitmapToRegion, saa_bitmap_to_region);
+    saa_unaccel_setup(screen);
+#ifdef RENDER
+    saa_render_setup(screen);
+#endif
+
+    return TRUE;
+}
+
+Bool
+saa_resources_init(ScreenPtr screen)
+{
+/*    if (!saa_glyphs_init(screen))
+       return FALSE;
+*/
+    return TRUE;
+}
diff --git a/saa/saa.h b/saa/saa.h
new file mode 100644 (file)
index 0000000..fe9617f
--- /dev/null
+++ b/saa/saa.h
@@ -0,0 +1,192 @@
+/*
+ *
+ * Copyright (C) 2000 Keith Packard
+ *               2004 Eric Anholt
+ *               2005 Zack Rusin
+ *
+ * Copyright 2011 VMWare, Inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Copyright holders make no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Author: Based on "exa.h"
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifndef _SAA_H_
+#define _SAA_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+#include <xf86.h>
+#include <damage.h>
+
+#define SAA_VERSION_MAJOR 0
+#define SAA_VERSION_MINOR 1
+
+#define SAA_ACCESS_R (1 << 0)
+#define SAA_ACCESS_W (1 << 1)
+#define SAA_ACCESS_RW (SAA_ACCESS_R | SAA_ACCESS_W)
+
+#define SAA_PIXMAP_HINT_CREATE_HW (1 << 25)
+#define SAA_PIXMAP_PREFER_SHADOW  (1 << 0)
+
+typedef unsigned int saa_access_t;
+
+enum saa_pixmap_loc {
+    saa_loc_driver,
+    saa_loc_override,
+};
+
+struct saa_pixmap {
+    PixmapPtr pixmap;
+    int read_access;
+    int write_access;
+    unsigned int mapped_access;
+    Bool fallback_created;
+    RegionRec dirty_shadow;
+    RegionRec dirty_hw;
+    RegionRec shadow_damage;
+    DamagePtr damage;
+    void *addr;
+    void *override;
+    enum saa_pixmap_loc auth_loc;
+    uint32_t pad[16];
+};
+
+struct saa_driver {
+    unsigned int saa_major;
+    unsigned int saa_minor;
+    size_t pixmap_size;
+     Bool(*damage) (struct saa_driver * driver, PixmapPtr pixmap,
+                   Bool hw, RegionPtr damage);
+    void (*operation_complete) (struct saa_driver * driver, PixmapPtr pixmap);
+     Bool(*download_from_hw) (struct saa_driver * driver, PixmapPtr pixmap,
+                             RegionPtr readback);
+    void (*release_from_cpu) (struct saa_driver * driver, PixmapPtr pixmap,
+                             saa_access_t access);
+    void *(*sync_for_cpu) (struct saa_driver * driver, PixmapPtr pixmap,
+                          saa_access_t access);
+    void *(*map) (struct saa_driver * driver, PixmapPtr pixmap,
+                 saa_access_t access);
+    void (*unmap) (struct saa_driver * driver, PixmapPtr pixmap,
+                  saa_access_t access);
+     Bool(*create_pixmap) (struct saa_driver * driver, struct saa_pixmap * spix,
+                          int w, int h, int depth, unsigned int usage_hint,
+                          int bpp, int *new_pitch);
+    void (*destroy_pixmap) (struct saa_driver * driver, PixmapPtr pixmap);
+     Bool(*modify_pixmap_header) (PixmapPtr pixmap, int w, int h, int depth,
+                                 int bpp, int devkind, void *pPixData);
+
+     Bool(*copy_prepare) (struct saa_driver * driver, PixmapPtr src_pixmap,
+                         PixmapPtr dst_pixmap, int dx, int dy, int alu,
+                         RegionPtr scr_reg, uint32_t plane_mask);
+    void (*copy) (struct saa_driver * driver, int src_x, int src_y, int dst_x,
+                 int dst_y, int w, int h);
+    void (*copy_done) (struct saa_driver * driver);
+    void (*takedown) (struct saa_driver * driver);
+    uint32_t pad[16];
+};
+
+extern _X_EXPORT PixmapPtr
+saa_get_drawable_pixmap(DrawablePtr pDrawable);
+
+extern _X_EXPORT void
+saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
+                       int *xp, int *yp);
+
+extern _X_EXPORT PixmapPtr
+saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp);
+
+extern _X_EXPORT Bool
+saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
+                         RegionPtr read_reg);
+
+extern _X_EXPORT Bool
+saa_pad_read(DrawablePtr draw);
+
+Bool
+saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h);
+
+extern _X_EXPORT Bool
+saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
+             saa_access_t * access);
+
+extern _X_EXPORT void
+saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access);
+
+extern _X_EXPORT void
+saa_fad_read(DrawablePtr draw);
+
+extern _X_EXPORT void
+saa_fad_write(DrawablePtr draw, saa_access_t access);
+
+extern _X_EXPORT Bool
+saa_resources_init(ScreenPtr screen);
+
+extern _X_EXPORT void
+saa_driver_fini(ScreenPtr pScreen);
+
+extern _X_EXPORT int
+saa_create_gc(GCPtr pGC);
+
+extern _X_EXPORT RegionPtr
+saa_bitmap_to_region(PixmapPtr pPix);
+
+extern _X_EXPORT Bool
+saa_close_screen(int i, ScreenPtr pScreen);
+
+extern _X_EXPORT Bool
+saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC);
+
+extern _X_EXPORT Bool
+saa_op_reads_destination(CARD8 op);
+
+extern _X_EXPORT void
+saa_set_fallback_debug(ScreenPtr screen, Bool enable);
+
+extern _X_EXPORT
+struct saa_pixmap *saa_get_saa_pixmap(PixmapPtr pPixmap);
+
+extern _X_EXPORT Bool
+saa_add_damage(PixmapPtr pixmap);
+
+extern _X_EXPORT struct saa_driver *
+saa_get_driver(ScreenPtr pScreen);
+
+extern _X_EXPORT Bool
+saa_driver_init(ScreenPtr screen, struct saa_driver *saa_driver);
+
+extern _X_EXPORT void
+saa_pixmap_dirty(PixmapPtr pixmap, Bool hw, RegionPtr reg);
+
+extern _X_EXPORT void
+saa_drawable_dirty(DrawablePtr draw, Bool hw, RegionPtr reg);
+
+#define SAA_PM_IS_SOLID(_pDrawable, _pm) \
+  (((_pm) & FbFullMask((_pDrawable)->depth)) == \
+   FbFullMask((_pDrawable)->depth))
+
+#endif
diff --git a/saa/saa_accel.c b/saa/saa_accel.c
new file mode 100644 (file)
index 0000000..be33170
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2001 Keith Packard
+ * Copyright 2011 VMWare, Inc. All Rights Reserved.
+ * May partly be based on code that is Copyright Â© The XFree86 Project Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Eric Anholt <eric@anholt.net>
+ * Author: Michel Dänzer <michel@tungstengraphics.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include "saa.h"
+#include "saa_priv.h"
+
+Bool
+saa_hw_copy_nton(DrawablePtr pSrcDrawable,
+                DrawablePtr pDstDrawable,
+                GCPtr pGC,
+                BoxPtr pbox,
+                int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
+{
+    ScreenPtr pScreen = pDstDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pDstDrawable->pScreen);
+    struct saa_driver *driver = sscreen->driver;
+    PixmapPtr pSrcPixmap, pDstPixmap;
+    struct saa_pixmap *src_spix, *dst_spix;
+    int src_off_x, src_off_y;
+    int dst_off_x, dst_off_y;
+    RegionRec dst_reg, *src_reg;
+    int ordering;
+    Bool ret = TRUE;
+
+    (void)pScreen;
+
+    /* avoid doing copy operations if no boxes */
+    if (nbox == 0)
+       return TRUE;
+
+    pSrcPixmap = saa_get_pixmap(pSrcDrawable, &src_off_x, &src_off_y);
+    pDstPixmap = saa_get_pixmap(pDstDrawable, &dst_off_x, &dst_off_y);
+    src_spix = saa_pixmap(pSrcPixmap);
+    dst_spix = saa_pixmap(pDstPixmap);
+
+    ordering = (nbox == 1 || (dx > 0 && dy > 0) ||
+               (pDstDrawable != pSrcDrawable &&
+                (pDstDrawable->type != DRAWABLE_WINDOW ||
+                 pSrcDrawable->type != DRAWABLE_WINDOW))) ?
+       CT_YXBANDED : CT_UNSORTED;
+
+    src_reg = saa_boxes_to_region(pScreen, nbox, pbox, ordering);
+    if (!src_reg)
+       return FALSE;
+
+    REGION_NULL(pScreen, &dst_reg);
+    REGION_COPY(pScreen, &dst_reg, src_reg);
+    REGION_TRANSLATE(pScreen, src_reg, dx + src_off_x, dy + src_off_y);
+    REGION_TRANSLATE(pScreen, &dst_reg, dst_off_x, dst_off_y);
+
+    if (!(driver->copy_prepare) (driver, pSrcPixmap, pDstPixmap,
+                                reverse ? -1 : 1,
+                                upsidedown ? -1 : 1,
+                                pGC ? pGC->alu : GXcopy,
+                                src_reg, pGC ? pGC->planemask : FB_ALLONES)) {
+       goto fallback;
+    }
+
+    while (nbox--) {
+       (driver->copy) (driver,
+                       pbox->x1 + dx + src_off_x,
+                       pbox->y1 + dy + src_off_y,
+                       pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
+                       pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
+       pbox++;
+    }
+
+    (driver->copy_done) (driver);
+    saa_pixmap_dirty(pDstPixmap, TRUE, &dst_reg);
+    goto out;
+
+ fallback:
+    ret = FALSE;
+
+ out:
+    REGION_UNINIT(pScreen, &dst_reg);
+    REGION_DESTROY(pScreen, src_reg);
+
+    return ret;
+}
+
+static void
+saa_copy_nton(DrawablePtr pSrcDrawable,
+             DrawablePtr pDstDrawable,
+             GCPtr pGC,
+             BoxPtr pbox,
+             int nbox,
+             int dx,
+             int dy,
+             Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
+{
+    if (saa_hw_copy_nton(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
+                        reverse, upsidedown))
+       return;
+
+    saa_check_copy_nton(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
+                       reverse, upsidedown, bitplane, closure);
+}
+
+RegionPtr
+saa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+             int srcx, int srcy, int width, int height, int dstx, int dsty)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pDstDrawable->pScreen);
+
+    if (sscreen->fallback_count) {
+       return saa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
+                                  srcx, srcy, width, height, dstx, dsty);
+    }
+
+    return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
+                   srcx, srcy, width, height,
+                   dstx, dsty, saa_copy_nton, 0, NULL);
+}
diff --git a/saa/saa_pixmap.c b/saa/saa_pixmap.c
new file mode 100644 (file)
index 0000000..0d63091
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2009 Maarten Maathuis
+ * Copyright 2011 VMWare, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Based on "exa_driver.c"
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include "saa_priv.h"
+#include "saa.h"
+
+PixmapPtr
+saa_create_pixmap(ScreenPtr pScreen, int w, int h, int depth,
+                 unsigned usage_hint)
+{
+    PixmapPtr pPixmap;
+    struct saa_pixmap *spix;
+    int bpp;
+    size_t paddedWidth;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    int new_pitch = 0;
+    struct saa_driver *driver = sscreen->driver;
+
+    if (w > 32767 || h > 32767)
+       return NullPixmap;
+
+    /*
+     * Create a scratch pixmap without backing storage (w and h are zero)
+     */
+
+    saa_swap(sscreen, pScreen, CreatePixmap);
+    pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
+    saa_swap(sscreen, pScreen, CreatePixmap);
+
+    if (!pPixmap)
+       goto out_no_pix;
+
+    spix = saa_pixmap(pPixmap);
+    memset(spix, 0, driver->pixmap_size);
+    REGION_NULL(pScreen, &spix->dirty_shadow);
+    REGION_NULL(pScreen, &spix->dirty_hw);
+    REGION_NULL(pScreen, &spix->shadow_damage);
+    spix->read_access = 0;
+    spix->write_access = 0;
+    spix->mapped_access = 0;
+    spix->addr = NULL;
+    spix->auth_loc = saa_loc_override;
+    spix->override = SAA_INVALID_ADDRESS;
+    spix->pixmap = pPixmap;
+    bpp = pPixmap->drawable.bitsPerPixel;
+
+    if (!driver->create_pixmap(driver, spix, w, h, depth,
+                              usage_hint, bpp, &new_pitch))
+       goto out_no_driver_priv;
+
+    paddedWidth = new_pitch;
+    spix->damage = NULL;
+
+    /*
+     * Now set w and h to the correct value. This might allocate
+     * backing store if w and h are NON-NULL.
+     */
+
+    if (!(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0,
+                                        paddedWidth, NULL))
+       goto out_no_pixmap_header;
+
+    /*
+     * During a fallback we must prepare access. This hack is initially used
+     * for pixmaps created during ValidateGC.
+     */
+
+    spix->fallback_created = FALSE;
+    if (sscreen->fallback_count) {
+       if (!saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL))
+           goto out_no_access;
+
+       spix->fallback_created = TRUE;
+    }
+
+    return pPixmap;
+ out_no_access:
+ out_no_pixmap_header:
+    driver->destroy_pixmap(driver, pPixmap);
+ out_no_driver_priv:
+    saa_swap(sscreen, pScreen, DestroyPixmap);
+    pScreen->DestroyPixmap(pPixmap);
+    saa_swap(sscreen, pScreen, DestroyPixmap);
+ out_no_pix:
+    LogMessage(X_ERROR, "Failing pixmap creation.\n");
+    return NullPixmap;
+}
+
+Bool
+saa_destroy_pixmap(PixmapPtr pPixmap)
+{
+    ScreenPtr pScreen = pPixmap->drawable.pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    Bool ret;
+    struct saa_driver *driver = sscreen->driver;
+
+    if (pPixmap->refcnt == 1) {
+       struct saa_pixmap *spix = saa_pixmap(pPixmap);
+
+       if (spix->fallback_created) {
+           if (!sscreen->fallback_count)
+               LogMessage(X_ERROR, "Fallback pixmap destroyed outside "
+                          "fallback.\n");
+
+           saa_finish_access_pixmap(pPixmap, SAA_ACCESS_W);
+       }
+
+       driver->destroy_pixmap(driver, pPixmap);
+
+       REGION_UNINIT(pScreen, &spix->dirty_hw);
+       REGION_UNINIT(pScreen, &spix->dirty_shadow);
+       spix->damage = NULL;
+    }
+
+    saa_swap(sscreen, pScreen, DestroyPixmap);
+    ret = pScreen->DestroyPixmap(pPixmap);
+    saa_swap(sscreen, pScreen, DestroyPixmap);
+
+    return ret;
+}
+
+Bool
+saa_modify_pixmap_header(PixmapPtr pPixmap, int width, int height, int depth,
+                        int bitsPerPixel, int devKind, pointer pPixData)
+{
+    ScreenPtr pScreen;
+    struct saa_screen_priv *sscreen;
+    struct saa_pixmap *spix;
+    struct saa_driver *driver;
+    Bool ret = TRUE;
+
+    if (!pPixmap)
+       return FALSE;
+
+    pScreen = pPixmap->drawable.pScreen;
+    sscreen = saa_screen(pScreen);
+    spix = saa_pixmap(pPixmap);
+    driver = sscreen->driver;
+
+    if (spix && driver->modify_pixmap_header &&
+       driver->modify_pixmap_header(pPixmap, width, height, depth,
+                                    bitsPerPixel, devKind, pPixData)) {
+       spix->auth_loc = saa_loc_driver;
+       spix->override = SAA_INVALID_ADDRESS;
+       goto out;
+    }
+
+    saa_swap(sscreen, pScreen, ModifyPixmapHeader);
+    ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
+                                     bitsPerPixel, devKind, pPixData);
+    saa_swap(sscreen, pScreen, ModifyPixmapHeader);
+    spix->override = pPixmap->devPrivate.ptr;
+    spix->auth_loc = saa_loc_override;
+
+ out:
+    pPixmap->devPrivate.ptr = NULL;
+    return ret;
+}
+
+struct saa_pixmap *
+saa_get_saa_pixmap(PixmapPtr pPixmap)
+{
+    return saa_pixmap(pPixmap);
+}
+
+void
+saa_pixmap_dirty(PixmapPtr pixmap, Bool hw, RegionPtr reg)
+{
+    struct saa_pixmap *spix = saa_pixmap(pixmap);
+    struct saa_screen_priv *sscreen = saa_screen(pixmap->drawable.pScreen);
+
+    if (hw) {
+       REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_hw,
+                    &spix->dirty_hw, reg);
+       REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_shadow,
+                       &spix->dirty_shadow, reg);
+    } else {
+       REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_shadow,
+                    &spix->dirty_shadow, reg);
+       REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_hw,
+                       &spix->dirty_hw, reg);
+    }
+
+    sscreen->driver->damage(sscreen->driver, pixmap, hw, reg);
+}
+
+void
+saa_drawable_dirty(DrawablePtr draw, Bool hw, RegionPtr reg)
+{
+    PixmapPtr pixmap;
+    int x_offset, y_offset;
+
+    pixmap = saa_get_pixmap(draw, &x_offset, &y_offset);
+    REGION_TRANSLATE(draw->pScreen, reg, x_offset, y_offset);
+    saa_pixmap_dirty(pixmap, hw, reg);
+    REGION_TRANSLATE(draw->pScreen, reg, -x_offset, -y_offset);
+}
diff --git a/saa/saa_priv.h b/saa/saa_priv.h
new file mode 100644 (file)
index 0000000..f86f196
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *
+ * Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *               2005 Zack Rusin, Trolltech
+ * Copyright 2011 VMWare, inc. All rights reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Authors: Based on exa_priv.h
+ * Authors: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifndef _SAA_PRIV_H
+#define _SAA_PRIV_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+#include "xf86.h"
+
+#include "saa.h"
+
+#include <X11/X.h>
+#include <X11/Xproto.h>
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "servermd.h"
+#include "mibstore.h"
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "mi.h"
+#include "dix.h"
+#include "fb.h"
+#include "fboverlay.h"
+#ifdef RENDER
+#include "glyphstr.h"
+#endif
+#include "damage.h"
+
+#define SAA_INVALID_ADDRESS \
+  ((void *) ((unsigned long) 0xFFFFFFFF - 1024*1024))
+
+struct saa_gc_priv {
+    /* GC values from the layer below. */
+    GCOps *saved_ops;
+    GCFuncs *saved_funcs;
+};
+
+struct saa_screen_priv {
+    struct saa_driver *driver;
+    CreateGCProcPtr saved_CreateGC;
+    CloseScreenProcPtr saved_CloseScreen;
+    GetImageProcPtr saved_GetImage;
+    GetSpansProcPtr saved_GetSpans;
+    CreatePixmapProcPtr saved_CreatePixmap;
+    DestroyPixmapProcPtr saved_DestroyPixmap;
+    CopyWindowProcPtr saved_CopyWindow;
+    ChangeWindowAttributesProcPtr saved_ChangeWindowAttributes;
+    BitmapToRegionProcPtr saved_BitmapToRegion;
+    ModifyPixmapHeaderProcPtr saved_ModifyPixmapHeader;
+#ifdef RENDER
+    CompositeProcPtr saved_Composite;
+    CompositeRectsProcPtr saved_CompositeRects;
+    TrianglesProcPtr saved_Triangles;
+    GlyphsProcPtr saved_Glyphs;
+    TrapezoidsProcPtr saved_Trapezoids;
+    AddTrapsProcPtr saved_AddTraps;
+    UnrealizeGlyphProcPtr saved_UnrealizeGlyph;
+    SourceValidateProcPtr saved_SourceValidate;
+#endif
+    Bool fallback_debug;
+
+    unsigned int fallback_count;
+
+    RegionRec srcReg;
+    RegionRec maskReg;
+    PixmapPtr srcPix;
+};
+
+extern GCOps saa_gc_ops;
+
+#if DEBUG_TRACE_FALL
+#define SAA_FALLBACK(x)                                                \
+do {                                                           \
+       ErrorF("SAA fallback at %s: ", __FUNCTION__);           \
+       ErrorF x;                                               \
+} while (0)
+
+#define saa_drawable_location() ("u")
+#else
+#define SAA_FALLBACK(x)
+#endif
+
+/*
+ * Some macros to deal with function wrapping.
+ */
+#define saa_wrap(priv, real, mem, func) {\
+       (priv)->saved_##mem = (real)->mem;      \
+       (real)->mem = func;                     \
+}
+
+#define saa_unwrap(priv, real, mem) {\
+       (real)->mem = (priv)->saved_##mem;      \
+}
+
+#define saa_swap(priv, real, mem) {\
+       void *tmp = (priv)->saved_##mem;                \
+       (priv)->saved_##mem = (real)->mem;      \
+       (real)->mem = tmp;                      \
+}
+
+#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 8)
+#define SAA_DEVPRIVATEKEYREC 1
+
+extern DevPrivateKeyRec saa_screen_index;
+extern DevPrivateKeyRec saa_pixmap_index;
+extern DevPrivateKeyRec saa_gc_index;
+
+static inline struct saa_screen_priv *
+saa_screen(ScreenPtr screen)
+{
+    return (struct saa_screen_priv *)dixGetPrivate(&screen->devPrivates,
+                                                  &saa_screen_index);
+}
+
+static inline struct saa_gc_priv *
+saa_gc(GCPtr gc)
+{
+    return (struct saa_gc_priv *)dixGetPrivateAddr(&gc->devPrivates,
+                                                  &saa_gc_index);
+}
+
+static inline struct saa_pixmap *
+saa_pixmap(PixmapPtr pix)
+{
+    return (struct saa_pixmap *)dixGetPrivateAddr(&pix->devPrivates,
+                                                 &saa_pixmap_index);
+}
+#else
+#undef SAA_DEVPRIVATEKEYREC
+extern int saa_screen_index;
+extern int saa_pixmap_index;
+extern int saa_gc_index;
+
+static inline struct saa_screen_priv *
+saa_screen(ScreenPtr screen)
+{
+    return (struct saa_screen_priv *)dixLookupPrivate(&screen->devPrivates,
+                                                     &saa_screen_index);
+}
+
+static inline struct saa_gc_priv *
+saa_gc(GCPtr gc)
+{
+    return (struct saa_gc_priv *)dixLookupPrivateAddr(&gc->devPrivates,
+                                                     &saa_gc_index);
+}
+
+static inline struct saa_pixmap_priv *
+saa_pixmap(PixmapPtr pix)
+{
+    return (struct saa_pixmap_priv *)dixLookupPrivateAddr(&pix->devPrivates,
+                                                         &saa_pixmap_index);
+}
+
+#endif
+
+extern void
+saa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
+                    DDXPointPtr ppt, int *pwidth, int fSorted);
+extern void
+saa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+                        int nrect, xRectangle * prect);
+extern RegionPtr
+saa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+                   int srcx, int srcy, int w, int h, int dstx, int dsty);
+extern void
+saa_check_copy_nton(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+                   BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
+                   Bool upsidedown, Pixel bitplane, void *closure);
+
+extern void
+saa_unaccel_setup(ScreenPtr pScreen);
+
+extern void
+saa_unaccel_takedown(ScreenPtr pScreen);
+
+extern RegionPtr
+saa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
+             int srcx, int srcy, int width, int height, int dstx, int dsty);
+
+extern Bool
+saa_hw_copy_nton(DrawablePtr pSrcDrawable,
+                DrawablePtr pDstDrawable,
+                GCPtr pGC,
+                BoxPtr pbox,
+                int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
+
+#ifdef RENDER
+extern void
+saa_render_setup(ScreenPtr pScreen);
+
+extern void
+saa_render_takedown(ScreenPtr pScreen);
+
+extern void
+saa_check_composite(CARD8 op,
+                   PicturePtr pSrc,
+                   PicturePtr pMask,
+                   PicturePtr pDst,
+                   INT16 xSrc,
+                   INT16 ySrc,
+                   INT16 xMask,
+                   INT16 yMask,
+                   INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
+#endif
+
+extern Bool
+saa_modify_pixmap_header(PixmapPtr pPixmap, int width, int height, int depth,
+                        int bitsPerPixel, int devKind, pointer pPixData);
+
+extern PixmapPtr
+saa_create_pixmap(ScreenPtr pScreen, int w, int h, int depth,
+                 unsigned usage_hint);
+
+extern Bool
+saa_destroy_pixmap(PixmapPtr pPixmap);
+
+static inline RegionPtr
+saa_pix_damage_pending(struct saa_pixmap *spix)
+{
+    return (spix->damage ? DamagePendingRegion(spix->damage) : NULL);
+}
+
+extern RegionPtr
+saa_boxes_to_region(ScreenPtr pScreen, int nbox, BoxPtr pbox, int ordering);
+
+#endif
diff --git a/saa/saa_render.c b/saa/saa_render.c
new file mode 100644 (file)
index 0000000..1df0dff
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright © 2001 Keith Packard
+ * Copyright 2011 VMWare, Inc. All Rights Reserved.
+ * May partly be based on code that is Copyright Â© The XFree86 Project Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Eric Anholt <eric@anholt.net>
+ * Author: Michel Dänzer <michel@tungstengraphics.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+#include "saa.h"
+#include "saa_priv.h"
+
+#ifdef RENDER
+#include <mipict.h>
+
+/**
+ * Same as miCreateAlphaPicture, except it uses
+ * saa_check_poly_fill_rect instead
+ */
+
+static PicturePtr
+saa_create_alpha_picture(ScreenPtr pScreen,
+                        PicturePtr pDst,
+                        PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
+{
+    PixmapPtr pPixmap;
+    PicturePtr pPicture;
+    GCPtr pGC;
+    int error;
+    xRectangle rect;
+
+    if (width > 32767 || height > 32767)
+       return 0;
+
+    if (!pPictFormat) {
+       if (pDst->polyEdge == PolyEdgeSharp)
+           pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
+       else
+           pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
+       if (!pPictFormat)
+           return 0;
+    }
+
+    pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
+                                       pPictFormat->depth, 0);
+    if (!pPixmap)
+       return 0;
+    pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
+    if (!pGC) {
+       (*pScreen->DestroyPixmap) (pPixmap);
+       return 0;
+    }
+    ValidateGC(&pPixmap->drawable, pGC);
+    rect.x = 0;
+    rect.y = 0;
+    rect.width = width;
+    rect.height = height;
+    saa_check_poly_fill_rect(&pPixmap->drawable, pGC, 1, &rect);
+    FreeScratchGC(pGC);
+    pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
+                            0, 0, serverClient, &error);
+    (*pScreen->DestroyPixmap) (pPixmap);
+    return pPicture;
+}
+
+/**
+ * saa_trapezoids is essentially a copy of miTrapezoids that uses
+ * saa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to RasterizeTrapezoid won't be accelerated however, which
+ * forces the pixmap to be moved out again.
+ *
+ */
+static void
+saa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+              PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+              int ntrap, xTrapezoid * traps)
+{
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+    BoxRec bounds;
+
+    if (maskFormat) {
+       PicturePtr pPicture;
+       INT16 xDst, yDst;
+       INT16 xRel, yRel;
+       saa_access_t access;
+
+       miTrapezoidBounds(ntrap, traps, &bounds);
+
+       if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+           return;
+
+       xDst = traps[0].left.p1.x >> 16;
+       yDst = traps[0].left.p1.y >> 16;
+
+       pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat,
+                                           bounds.x2 - bounds.x1,
+                                           bounds.y2 - bounds.y1);
+       if (!pPicture)
+           return;
+
+       if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) {
+           for (; ntrap; ntrap--, traps++)
+               (*ps->RasterizeTrapezoid) (pPicture, traps,
+                                          -bounds.x1, -bounds.y1);
+           saa_fad_write(pPicture->pDrawable, access);
+       }
+
+       xRel = bounds.x1 + xSrc - xDst;
+       yRel = bounds.y1 + ySrc - yDst;
+       CompositePicture(op, pSrc, pPicture, pDst,
+                        xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+                        bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+       FreePicture(pPicture, 0);
+    } else {
+       if (pDst->polyEdge == PolyEdgeSharp)
+           maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
+       else
+           maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
+       for (; ntrap; ntrap--, traps++)
+           saa_trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
+    }
+}
+
+/**
+ * saa_triangles is essentially a copy of miTriangles that uses
+ * saa_create_alpha_picture instead of miCreateAlphaPicture.
+ *
+ * The problem with miCreateAlphaPicture is that it calls PolyFillRect
+ * to initialize the contents after creating the pixmap, which
+ * causes the pixmap to be moved in for acceleration. The subsequent
+ * call to AddTriangles won't be accelerated however, which forces the pixmap
+ * to be moved out again.
+ */
+static void
+saa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
+             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
+             int ntri, xTriangle * tris)
+{
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+    BoxRec bounds;
+
+    if (maskFormat) {
+       PicturePtr pPicture;
+       INT16 xDst, yDst;
+       INT16 xRel, yRel;
+       saa_access_t access;
+
+       miTriangleBounds(ntri, tris, &bounds);
+
+       if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
+           return;
+
+       xDst = tris[0].p1.x >> 16;
+       yDst = tris[0].p1.y >> 16;
+
+       pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat,
+                                           bounds.x2 - bounds.x1,
+                                           bounds.y2 - bounds.y1);
+       if (!pPicture)
+           return;
+
+       if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) {
+           (*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
+           saa_fad_write(pPicture->pDrawable, access);
+       }
+
+       xRel = bounds.x1 + xSrc - xDst;
+       yRel = bounds.y1 + ySrc - yDst;
+       CompositePicture(op, pSrc, pPicture, pDst,
+                        xRel, yRel, 0, 0, bounds.x1, bounds.y1,
+                        bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
+       FreePicture(pPicture, 0);
+    } else {
+       if (pDst->polyEdge == PolyEdgeSharp)
+           maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
+       else
+           maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
+
+       for (; ntri; ntri--, tris++)
+           saa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
+    }
+}
+
+/*
+ * Try to turn a composite operation into an accelerated copy.
+ * We can do that in some special cases for PictOpSrc and PictOpOver.
+ */
+
+static Bool
+saa_copy_composite(CARD8 op,
+                  PicturePtr pSrc,
+                  PicturePtr pMask,
+                  PicturePtr pDst,
+                  INT16 xSrc,
+                  INT16 ySrc,
+                  INT16 xMask,
+                  INT16 yMask,
+                  INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+{
+    if (!pSrc->pDrawable || pSrc->transform ||
+       pSrc->repeat || xSrc < 0 || ySrc < 0 ||
+       xSrc + width > pSrc->pDrawable->width ||
+       ySrc + height > pSrc->pDrawable->height)
+       return FALSE;
+
+    if ((op == PictOpSrc &&
+        (pSrc->format == pDst->format ||
+         (PICT_FORMAT_COLOR(pDst->format) &&
+          PICT_FORMAT_COLOR(pSrc->format) &&
+          pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
+                                      PICT_FORMAT_TYPE(pSrc->format),
+                                      0,
+                                      PICT_FORMAT_R(pSrc->format),
+                                      PICT_FORMAT_G(pSrc->format),
+                                      PICT_FORMAT_B(pSrc->format))))) ||
+       (op == PictOpOver && pSrc->format == pDst->format &&
+        !PICT_FORMAT_A(pSrc->format))) {
+
+       Bool ret;
+       RegionRec region;
+
+       REGION_NULL(pDst->pDrawable.pScreen, &region);
+
+       xDst += pDst->pDrawable->x;
+       yDst += pDst->pDrawable->y;
+       xSrc += pSrc->pDrawable->x;
+       ySrc += pSrc->pDrawable->y;
+
+       if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
+                                     xSrc, ySrc, xMask, yMask, xDst,
+                                     yDst, width, height)) {
+           return TRUE;
+       }
+
+       ret = saa_hw_copy_nton(pSrc->pDrawable, pDst->pDrawable, NULL,
+                              RegionRects(&region),
+                              RegionNumRects(&region),
+                              xSrc - xDst, ySrc - yDst, FALSE, FALSE);
+       RegionUninit(&region);
+       if (ret)
+           return TRUE;
+    }
+    return FALSE;
+}
+
+static void
+saa_composite(CARD8 op,
+             PicturePtr pSrc,
+             PicturePtr pMask,
+             PicturePtr pDst,
+             INT16 xSrc,
+             INT16 ySrc,
+             INT16 xMask,
+             INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+{
+    if (!saa_copy_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+                           xDst, yDst, width, height))
+       saa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
+                           xDst, yDst, width, height);
+}
+
+void
+saa_render_setup(ScreenPtr pScreen)
+{
+    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    if (ps) {
+       saa_wrap(sscreen, ps, Trapezoids, saa_trapezoids);
+       saa_wrap(sscreen, ps, Triangles, saa_triangles);
+       saa_wrap(sscreen, ps, Composite, saa_composite);
+    }
+}
+
+void
+saa_render_takedown(ScreenPtr pScreen)
+{
+    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    if (ps) {
+       saa_unwrap(sscreen, ps, Trapezoids);
+       saa_unwrap(sscreen, ps, Triangles);
+       saa_unwrap(sscreen, ps, Composite);
+    }
+}
+#endif
diff --git a/saa/saa_unaccel.c b/saa/saa_unaccel.c
new file mode 100644 (file)
index 0000000..27b399d
--- /dev/null
@@ -0,0 +1,896 @@
+/*
+ * Copyright © 1999 Keith Packard
+ * Copyright 2011 VMWare, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Based on "exa_unaccel.c"
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include "saa_priv.h"
+#include "saa.h"
+#include "mipict.h"
+
+/**
+ * Calls saa_prepare_access with SAA_ACCESS_R for the tile, if that is the
+ * current fill style.
+ *
+ * Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
+ * 1bpp and never in fb, so we don't worry about them.
+ * We should worry about them for completeness sake and going forward.
+ */
+static Bool
+saa_prepare_access_gc(GCPtr pGC)
+{
+    if (pGC->stipple)
+       if (!saa_pad_read(&pGC->stipple->drawable))
+           return FALSE;
+    if (pGC->fillStyle == FillTiled)
+       if (!saa_pad_read(&pGC->tile.pixmap->drawable)) {
+           if (pGC->stipple)
+               saa_fad_read(&pGC->stipple->drawable);
+           return FALSE;
+       }
+    return TRUE;
+}
+
+/**
+ * Finishes access to the tile in the GC, if used.
+ */
+static void
+saa_finish_access_gc(GCPtr pGC)
+{
+    if (pGC->fillStyle == FillTiled)
+       saa_fad_read(&pGC->tile.pixmap->drawable);
+    if (pGC->stipple)
+       saa_fad_read(&pGC->stipple->drawable);
+}
+
+void
+saa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
+                    DDXPointPtr ppt, int *pwidth, int fSorted)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_location(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
+       if (saa_prepare_access_gc(pGC)) {
+           saa_swap(sgc, pGC, ops);
+           pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
+           saa_swap(sgc, pGC, ops);
+           saa_finish_access_gc(pGC);
+       }
+       saa_fad_write(pDrawable, access);
+    }
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+                   DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access
+       SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
+       saa_swap(sgc, pGC, ops);
+       pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+       saa_swap(sgc, pGC, ops);
+       saa_fad_write(pDrawable, access);
+    }
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
+                   int x, int y, int w, int h, int leftPad, int format,
+                   char *bits)
+{
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+    sscreen->fallback_count++;
+    if (saa_pad_write(pDrawable, pGC, TRUE, &access)) {
+       saa_swap(sgc, pGC, ops);
+       pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad,
+                          format, bits);
+       saa_swap(sgc, pGC, ops);
+       saa_fad_write(pDrawable, access);
+    }
+    sscreen->fallback_count--;
+}
+
+RegionPtr
+saa_boxes_to_region(ScreenPtr pScreen, int nbox, BoxPtr pbox, int ordering)
+{
+    xRectangle *rects = malloc(nbox * sizeof(*rects));
+    int i;
+    RegionPtr reg;
+
+    if (!rects)
+       return NULL;
+
+    for (i = 0; i < nbox; i++) {
+       rects[i].x = pbox[i].x1;
+       rects[i].y = pbox[i].y1;
+       rects[i].width = pbox[i].x2 - pbox[i].x1;
+       rects[i].height = pbox[i].y2 - pbox[i].y1;
+    }
+
+    reg = RECTS_TO_REGION(pScreen, nbox, rects, ordering);
+    free(rects);
+    return reg;
+}
+
+void
+saa_check_copy_nton(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+                   BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
+                   Bool upsidedown, Pixel bitplane, void *closure)
+{
+    ScreenPtr pScreen = pSrc->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    RegionPtr reg, readback;
+    int src_xoff, src_yoff, dst_xoff, dst_yoff;
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    PixmapPtr src_pixmap;
+    PixmapPtr dst_pixmap;
+    saa_access_t access = SAA_ACCESS_R;
+    int ordering;
+
+    sscreen->fallback_count++;
+    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+                 saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
+
+    src_pixmap = saa_get_pixmap(pSrc, &src_xoff, &src_yoff);
+    dst_pixmap = saa_get_pixmap(pDst, &dst_xoff, &dst_yoff);
+
+    ordering = (nbox == 1 || (dx > 0 && dy > 0) ||
+               (pDst != pSrc &&
+                (pDst->type != DRAWABLE_WINDOW ||
+                 pSrc->type != DRAWABLE_WINDOW))) ? CT_YXBANDED : CT_UNSORTED;
+
+    reg = saa_boxes_to_region(pScreen, nbox, pbox, ordering);
+    if (!reg)
+       return;
+
+    REGION_TRANSLATE(pScreen, reg, src_xoff + dx, src_yoff + dy);
+    if (!saa_prepare_access_pixmap(src_pixmap, SAA_ACCESS_R, reg))
+       goto out_no_access;
+
+    REGION_TRANSLATE(pScreen, reg, dst_xoff - dx - src_xoff,
+                    dst_yoff - dy - src_yoff);
+
+    if (saa_gc_reads_destination(pDst, pGC)) {
+       readback = reg;
+       access = SAA_ACCESS_RW;
+    } else {
+       readback = NULL;
+       access = SAA_ACCESS_W;
+    }
+
+    if (!saa_prepare_access_pixmap(dst_pixmap, access, readback))
+       goto out_no_dst;
+
+    saa_swap(sgc, pGC, ops);
+    while (nbox--) {
+       pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
+                          pbox->y1 - pSrc->y + dy,
+                          pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
+                          pbox->x1 - pDst->x, pbox->y1 - pDst->y);
+       pbox++;
+    }
+
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_pixmap(dst_pixmap, access);
+    saa_pixmap_dirty(dst_pixmap, FALSE, reg);
+ out_no_dst:
+    saa_fad_read(pSrc);
+ out_no_access:
+    sscreen->fallback_count--;
+    REGION_DESTROY(pScreen, reg);
+}
+
+RegionPtr
+saa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+                   int srcx, int srcy, int w, int h, int dstx, int dsty)
+{
+    RegionPtr ret = NULL;
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+                 saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
+    sscreen->fallback_count++;
+    if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
+       goto out_no_access;
+    if (!saa_pad_write(pDst, pGC, TRUE, &access))
+       goto out_no_dst;
+
+    saa_swap(sgc, pGC, ops);
+    ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+    saa_swap(sgc, pGC, ops);
+
+    saa_fad_write(pDst, access);
+ out_no_dst:
+    saa_fad_read(pSrc);
+ out_no_access:
+    sscreen->fallback_count--;
+
+    return ret;
+}
+
+static RegionPtr
+saa_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
+                    int srcx, int srcy, int w, int h, int dstx, int dsty,
+                    unsigned long bitplane)
+{
+    RegionPtr ret = NULL;
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
+                 saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
+    sscreen->fallback_count++;
+    if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
+       goto out_no_src;
+    if (!saa_pad_write(pDst, pGC, TRUE, &access))
+       goto out_no_dst;
+
+    saa_swap(sgc, pGC, ops);
+    ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
+                             bitplane);
+    saa_swap(sgc, pGC, ops);
+
+    saa_fad_write(pDst, access);
+ out_no_dst:
+    saa_fad_read(pSrc);
+ out_no_src:
+    sscreen->fallback_count--;
+
+    return ret;
+}
+
+static void
+saa_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
+                    DDXPointPtr pptInit)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    sscreen->fallback_count++;
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
+    saa_swap(sgc, pGC, ops);
+    saa_fad_write(pDrawable, access);
+
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
+                    int mode, int npt, DDXPointPtr ppt)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
+                 pDrawable, saa_drawable_loc(pDrawable),
+                 pGC->lineWidth, mode, npt));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
+                      int nsegInit, xSegment * pSegInit)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
+                 saa_drawable_loc(pDrawable), pGC->lineWidth, nsegInit));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+void
+saa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
+                        int nrect, xRectangle * prect)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, pGC, TRUE, &access))
+       goto out_no_access;;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+                         int x, int y, unsigned int nglyph,
+                         CharInfoPtr * ppci, pointer pglyphBase)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
+                        int x, int y, unsigned int nglyph,
+                        CharInfoPtr * ppci, pointer pglyphBase)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
+                 saa_drawable_loc(pDrawable), pGC->fillStyle, pGC->alu));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
+       goto out_no_access;;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
+                     DrawablePtr pDrawable, int w, int h, int x, int y)
+{
+    struct saa_gc_priv *sgc = saa_gc(pGC);
+    saa_access_t access;
+    struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
+
+    SAA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
+                 saa_drawable_loc(&pBitmap->drawable),
+                 saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pDrawable, pGC, TRUE, &access))
+       goto out_no_access;;
+    if (!saa_pad_read_box(&pBitmap->drawable, 0, 0, w, h))
+       goto out_no_src;
+    if (!saa_prepare_access_gc(pGC))
+       goto out_no_gc;
+    saa_swap(sgc, pGC, ops);
+    pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
+    saa_swap(sgc, pGC, ops);
+    saa_finish_access_gc(pGC);
+ out_no_gc:
+    saa_fad_read(&pBitmap->drawable);
+ out_no_src:
+    saa_fad_write(pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+    DrawablePtr pDrawable = &pWin->drawable;
+    ScreenPtr pScreen = pDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    int xoff, yoff;
+    PixmapPtr pPixmap = saa_get_pixmap(&pWin->drawable, &xoff, &yoff);
+    Bool ret;
+
+    SAA_FALLBACK(("from %p\n", pWin));
+
+    /* Only need the source bits, the destination region will be overwritten */
+
+    sscreen->fallback_count++;
+    REGION_TRANSLATE(pScreen, prgnSrc, xoff, yoff);
+    ret = saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_R, prgnSrc);
+    REGION_TRANSLATE(pScreen, prgnSrc, -xoff, -yoff);
+    if (!ret)
+       goto out_no_access;;
+
+    if (saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL)) {
+       saa_swap(sscreen, pScreen, CopyWindow);
+       pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
+       saa_swap(sscreen, pScreen, CopyWindow);
+       saa_fad_write(pDrawable, SAA_ACCESS_W);
+    }
+    saa_fad_read(pDrawable);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+#ifdef RENDER
+
+#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
+static void
+saa_src_validate(DrawablePtr pDrawable,
+                int x,
+                int y, int width, int height, unsigned int subWindowMode)
+#else
+static void
+saa_src_validate(DrawablePtr pDrawable, int x, int y, int width, int height)
+#endif
+{
+    ScreenPtr pScreen = pDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    PixmapPtr pPix = saa_get_drawable_pixmap(pDrawable);
+    BoxRec box;
+    RegionRec reg;
+    RegionPtr dst;
+    int xoff, yoff;
+
+    saa_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff);
+
+    box.x1 = x + xoff;
+    box.y1 = y + yoff;
+    box.x2 = box.x1 + width;
+    box.y2 = box.y1 + height;
+
+    dst = (sscreen->srcPix == pPix) ? &sscreen->srcReg : &sscreen->maskReg;
+
+    REGION_INIT(pScreen, &reg, &box, 1);
+    REGION_UNION(pScreen, dst, dst, &reg);
+    REGION_UNINIT(pScreen, &reg);
+
+    if (sscreen->saved_SourceValidate) {
+       saa_swap(sscreen, pScreen, SourceValidate);
+       pScreen->SourceValidate(pDrawable, x, y, width, height
+#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
+                               , subWindowMode
+#endif
+           );
+       saa_swap(sscreen, pScreen, SourceValidate);
+    }
+}
+
+static void
+saa_check_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
+                   unsigned int format, unsigned long planeMask, char *d)
+{
+    ScreenPtr pScreen = pDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_read_box(pDrawable, x, y, w, h))
+       goto out_no_access;;
+    saa_swap(sscreen, pScreen, GetImage);
+    pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
+    saa_swap(sscreen, pScreen, GetImage);
+    saa_fad_read(pDrawable);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static void
+saa_check_get_spans(DrawablePtr pDrawable,
+                   int wMax,
+                   DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
+{
+    ScreenPtr pScreen = pDrawable->pScreen;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_read(pDrawable))
+       goto out_no_access;;
+    saa_swap(sscreen, pScreen, GetSpans);
+    pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
+    saa_swap(sscreen, pScreen, GetSpans);
+    saa_fad_read(pDrawable);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+static Bool
+saa_prepare_composite_reg(ScreenPtr pScreen,
+                         CARD8 op,
+                         PicturePtr pSrc,
+                         PicturePtr pMask,
+                         PicturePtr pDst,
+                         INT16 xSrc,
+                         INT16 ySrc,
+                         INT16 xMask,
+                         INT16 yMask,
+                         INT16 xDst,
+                         INT16 yDst,
+                         CARD16 width,
+                         CARD16 height,
+                         RegionPtr region, saa_access_t * access)
+{
+    RegionPtr dstReg = NULL;
+    RegionPtr srcReg = NULL;
+    RegionPtr maskReg = NULL;
+    PixmapPtr pSrcPix = NULL;
+    PixmapPtr pMaskPix = NULL;
+    PixmapPtr pDstPix;
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    struct saa_pixmap *dst_spix;
+    Bool ret;
+
+    *access = SAA_ACCESS_W;
+
+    if (pSrc->pDrawable) {
+       pSrcPix = saa_get_drawable_pixmap(pSrc->pDrawable);
+       REGION_NULL(pScreen, &sscreen->srcReg);
+       srcReg = &sscreen->srcReg;
+       sscreen->srcPix = pSrcPix;
+       if (pSrc != pDst)
+           REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
+                            -pSrc->pDrawable->x, -pSrc->pDrawable->y);
+    }
+
+    if (pMask && pMask->pDrawable) {
+       pMaskPix = saa_get_drawable_pixmap(pMask->pDrawable);
+       REGION_NULL(pScreen, &sscreen->maskReg);
+       maskReg = &sscreen->maskReg;
+       if (pMask != pDst && pMask != pSrc)
+           REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
+                            -pMask->pDrawable->x, -pMask->pDrawable->y);
+    }
+
+    REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
+                    -pDst->pDrawable->x, -pDst->pDrawable->y);
+
+    sscreen->saved_SourceValidate = saa_src_validate;
+    saa_swap(sscreen, pScreen, SourceValidate);
+    ret = miComputeCompositeRegion(region, pSrc, pMask, pDst,
+                                  xSrc, ySrc, xMask, yMask,
+                                  xDst, yDst, width, height);
+    saa_swap(sscreen, pScreen, SourceValidate);
+
+    REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
+                    pDst->pDrawable->x, pDst->pDrawable->y);
+    if (pSrc->pDrawable && pSrc != pDst)
+       REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
+                        pSrc->pDrawable->x, pSrc->pDrawable->y);
+    if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
+       REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
+                        pMask->pDrawable->x, pMask->pDrawable->y);
+
+    if (!ret) {
+       if (srcReg)
+           REGION_UNINIT(pScreen, srcReg);
+       if (maskReg)
+           REGION_UNINIT(pScreen, maskReg);
+
+       return FALSE;
+    }
+
+    /*
+     * Don't limit alphamaps readbacks for now until we've figured out how that
+     * should be done.
+     */
+
+    if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
+       if (!saa_pad_read(pSrc->alphaMap->pDrawable))
+           goto out_no_src_alpha;
+    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
+       if (!saa_pad_read(pMask->alphaMap->pDrawable))
+           goto out_no_mask_alpha;
+    if (pSrcPix)
+       if (!saa_prepare_access_pixmap(pSrcPix, SAA_ACCESS_R, srcReg))
+           goto out_no_src;
+    if (pMaskPix)
+       if (!saa_prepare_access_pixmap(pMaskPix, SAA_ACCESS_R, maskReg))
+           goto out_no_mask;
+    if (srcReg)
+       REGION_UNINIT(pScreen, srcReg);
+    if (maskReg)
+       REGION_UNINIT(pScreen, maskReg);
+
+    pDstPix = saa_get_drawable_pixmap(pDst->pDrawable);
+    dst_spix = saa_get_saa_pixmap(pDstPix);
+
+    if (dst_spix->damage) {
+       int xoff, yoff;
+
+       saa_get_drawable_deltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
+       REGION_TRANSLATE(pScreen, region, pDst->pDrawable->x + xoff,
+                        pDst->pDrawable->y + yoff);
+       if (saa_op_reads_destination(op)) {
+           dstReg = region;
+           *access |= SAA_ACCESS_R;
+       }
+    }
+
+    if (pDst->alphaMap && pDst->alphaMap->pDrawable)
+       if (!saa_prepare_access_pixmap
+           (saa_get_drawable_pixmap(pDst->alphaMap->pDrawable),
+            *access, dstReg))
+           goto out_no_dst_alpha;
+
+    if (!saa_prepare_access_pixmap(pDstPix, *access, dstReg))
+       goto out_no_dst;
+
+    return TRUE;
+
+ out_no_dst:
+    LogMessage(X_ERROR, "No dst\n");
+    saa_finish_access_pixmap
+       (saa_get_drawable_pixmap(pDst->alphaMap->pDrawable), *access);
+ out_no_dst_alpha:
+    LogMessage(X_ERROR, "No dst alpha\n");
+    if (pMaskPix)
+       saa_finish_access_pixmap(pMaskPix, SAA_ACCESS_R);
+ out_no_mask:
+    LogMessage(X_ERROR, "No mask\n");
+    if (pSrcPix)
+       saa_finish_access_pixmap(pSrcPix, SAA_ACCESS_R);
+ out_no_src:
+    LogMessage(X_ERROR, "No src\n");
+    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
+       saa_fad_read(pMask->alphaMap->pDrawable);
+ out_no_mask_alpha:
+    LogMessage(X_ERROR, "No mask alpha\n");
+    if (pSrc && pSrc->alphaMap && pSrc->alphaMap->pDrawable)
+       saa_fad_read(pSrc->alphaMap->pDrawable);
+ out_no_src_alpha:
+    LogMessage(X_ERROR, "No src alpha\n");
+    if (srcReg)
+       REGION_UNINIT(pScreen, srcReg);
+    if (maskReg)
+       REGION_UNINIT(pScreen, maskReg);
+    return FALSE;
+
+}
+
+void
+saa_check_composite(CARD8 op,
+                   PicturePtr pSrc,
+                   PicturePtr pMask,
+                   PicturePtr pDst,
+                   INT16 xSrc,
+                   INT16 ySrc,
+                   INT16 xMask,
+                   INT16 yMask,
+                   INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+{
+    ScreenPtr pScreen = pDst->pDrawable->pScreen;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    saa_access_t access;
+    RegionRec reg;
+    PixmapPtr pixmap;
+
+    sscreen->fallback_count++;
+    REGION_NULL(pScreen, &reg);
+    if (!saa_prepare_composite_reg(pScreen, op, pSrc, pMask, pDst, xSrc,
+                                  ySrc, xMask, yMask, xDst, yDst, width,
+                                  height, &reg, &access)) {
+       goto out_no_access;;
+    }
+
+    saa_swap(sscreen, ps, Composite);
+    ps->Composite(op,
+                 pSrc,
+                 pMask,
+                 pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
+    saa_swap(sscreen, ps, Composite);
+    if (pMask && pMask->pDrawable != NULL)
+       saa_fad_read(pMask->pDrawable);
+    if (pSrc->pDrawable != NULL)
+       saa_fad_read(pSrc->pDrawable);
+    pixmap = saa_get_drawable_pixmap(pDst->pDrawable);
+    saa_finish_access_pixmap(pixmap, access);
+    saa_pixmap_dirty(pixmap, FALSE, &reg);
+    if (pDst->alphaMap && pDst->alphaMap->pDrawable) {
+       pixmap = saa_get_drawable_pixmap(pDst->alphaMap->pDrawable);
+       saa_finish_access_pixmap(pixmap, access);
+       saa_pixmap_dirty(pixmap, FALSE, &reg);
+    }
+    if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
+       saa_fad_read(pSrc->alphaMap->pDrawable);
+    if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
+       saa_fad_read(pMask->alphaMap->pDrawable);
+ out_no_access:
+    sscreen->fallback_count--;
+    REGION_UNINIT(pScreen, &reg);
+}
+
+static void
+saa_check_add_traps(PicturePtr pPicture,
+                   INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
+{
+    ScreenPtr pScreen = pPicture->pDrawable->pScreen;
+    PictureScreenPtr ps = GetPictureScreen(pScreen);
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+    saa_access_t access;
+
+    SAA_FALLBACK(("to pict %p (%c)\n", saa_drawable_loc(pPicture->pDrawable)));
+
+    sscreen->fallback_count++;
+    if (!saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access))
+       goto out_no_access;
+    saa_swap(sscreen, ps, AddTraps);
+    ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
+    saa_swap(sscreen, ps, AddTraps);
+    saa_fad_write(pPicture->pDrawable, access);
+ out_no_access:
+    sscreen->fallback_count--;
+}
+
+#endif
+
+void
+saa_unaccel_setup(ScreenPtr pScreen)
+{
+#ifdef RENDER
+    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    saa_wrap(sscreen, pScreen, GetImage, saa_check_get_image);
+    saa_wrap(sscreen, pScreen, GetSpans, saa_check_get_spans);
+    saa_wrap(sscreen, pScreen, CopyWindow, saa_check_copy_window);
+
+#ifdef RENDER
+    if (ps) {
+       saa_wrap(sscreen, ps, AddTraps, saa_check_add_traps);
+    }
+#endif
+}
+
+void
+saa_unaccel_takedown(ScreenPtr pScreen)
+{
+#ifdef RENDER
+    PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
+#endif
+    struct saa_screen_priv *sscreen = saa_screen(pScreen);
+
+    saa_unwrap(sscreen, pScreen, GetImage);
+    saa_unwrap(sscreen, pScreen, GetSpans);
+    saa_unwrap(sscreen, pScreen, CopyWindow);
+
+#ifdef RENDER
+    if (ps) {
+       saa_unwrap(sscreen, ps, AddTraps);
+    }
+#endif
+}
+
+GCOps saa_gc_ops = {
+    saa_check_fill_spans,
+    saa_check_set_spans,
+    saa_check_put_image,
+    saa_copy_area,
+    saa_check_copy_plane,
+    saa_check_poly_point,
+    saa_check_poly_lines,
+    saa_check_poly_segment,
+    miPolyRectangle,
+    saa_check_poly_arc,
+    miFillPolygon,
+    saa_check_poly_fill_rect,
+    miPolyFillArc,
+    miPolyText8,
+    miPolyText16,
+    miImageText8,
+    miImageText16,
+    saa_check_image_glyph_blt,
+    saa_check_poly_glyph_blt,
+    saa_check_push_pixels,
+};
index 4fa363a..5d36029 100644 (file)
@@ -1,52 +1,72 @@
-/* **********************************************************
- * Copyright 1998 VMware, Inc.  All rights reserved.
- * **********************************************************/
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
 
 /*
  * svga_reg.h --
  *
- * SVGA hardware definitions
+ *    Virtual hardware definitions for the VMware SVGA II device.
  */
 
 #ifndef _SVGA_REG_H_
 #define _SVGA_REG_H_
 
-#define INCLUDE_ALLOW_USERLEVEL
-#define INCLUDE_ALLOW_VMMEXT
-#define INCLUDE_ALLOW_VMCORE
-#include "includeCheck.h"
-
 /*
- * Memory and port addresses and fundamental constants
+ * PCI device IDs.
  */
+#define PCI_VENDOR_ID_VMWARE            0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2      0x0405
 
 /*
- * Note-- MAX_WIDTH and MAX_HEIGHT are largely ignored by the code.  This
- * isn't such a bad thing for forward compatibility. --Jeremy.
+ * Legal values for the SVGA_REG_CURSOR_ON register in old-fashioned
+ * cursor bypass mode. This is still supported, but no new guest
+ * drivers should use it.
  */
-#define SVGA_MAX_WIDTH                 2360
-#define SVGA_MAX_HEIGHT                        1770
-#define SVGA_MAX_BITS_PER_PIXEL                32
-#define SVGA_MAX_DEPTH                  24
-#define SVGA_MAX_DISPLAYS               10
+#define SVGA_CURSOR_ON_HIDE            0x0   /* Must be 0 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_SHOW            0x1   /* Must be 1 to maintain backward compatibility */
+#define SVGA_CURSOR_ON_REMOVE_FROM_FB  0x2   /* Remove the cursor from the framebuffer because we need to see what's under it */
+#define SVGA_CURSOR_ON_RESTORE_TO_FB   0x3   /* Put the cursor back in the framebuffer so the user can see it */
 
 /*
- * The maximum size of the onscreen framebuffer.  The size of the
- * changeMap in the monitor is proportional to this number since it's
- * the amount of memory we need to trace in VESA mode.  Therefore, we'd
+ * The maximum framebuffer size that can traced for e.g. guests in VESA mode.
+ * The changeMap in the monitor is proportional to this number. Therefore, we'd
  * like to keep it as small as possible to reduce monitor overhead (using
- * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area
- * by over 4k!).
+ * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area by over
+ * 4k!).
+ *
+ * NB: For compatibility reasons, this value must be greater than 0xff0000.
+ *     See bug 335072.
  */
-#define SVGA_FB_MAX_SIZE \
-   ((((SVGA_MAX_WIDTH * SVGA_MAX_HEIGHT *                                    \
-       SVGA_MAX_BITS_PER_PIXEL / 8) >> PAGE_SHIFT) + 1) << PAGE_SHIFT)
+#define SVGA_FB_MAX_TRACEABLE_SIZE      0x1000000
 
-#define SVGA_MAX_PSEUDOCOLOR_DEPTH     8
-#define SVGA_MAX_PSEUDOCOLORS          (1 << SVGA_MAX_PSEUDOCOLOR_DEPTH)
+#define SVGA_MAX_PSEUDOCOLOR_DEPTH      8
+#define SVGA_MAX_PSEUDOCOLORS           (1 << SVGA_MAX_PSEUDOCOLOR_DEPTH)
 #define SVGA_NUM_PALETTE_REGS           (3 * SVGA_MAX_PSEUDOCOLORS)
 
+/* Base and Offset gets us headed the right way for PCI Base Addr Registers */
+#define SVGA_LEGACY_BASE_PORT  0x4560
+
 #define SVGA_MAGIC         0x900000UL
 #define SVGA_MAKE_ID(ver)  (SVGA_MAGIC << 8 | (ver))
 
 #define SVGA_VERSION_0     0
 #define SVGA_ID_0          SVGA_MAKE_ID(SVGA_VERSION_0)
 
-/* Invalid SVGA_ID_ */
+/* "Invalid" value for all SVGA IDs. (Version ID, screen object ID, surface ID...) */
 #define SVGA_ID_INVALID    0xFFFFFFFF
 
-/* More backwards compatibility, old location of color map: */
-#define SVGA_OLD_PALETTE_BASE   17
-
-/* Base and Offset gets us headed the right way for PCI Base Addr Registers */
-#define SVGA_LEGACY_BASE_PORT  0x4560
-#define SVGA_INDEX_PORT                0x0
-#define SVGA_VALUE_PORT                0x1
-#define SVGA_BIOS_PORT         0x2
-#define SVGA_NUM_PORTS         0x3
-#define SVGA_IRQSTATUS_PORT    0x8
+/* Port offsets, relative to BAR0 */
+#define SVGA_INDEX_PORT         0x0
+#define SVGA_VALUE_PORT         0x1
+#define SVGA_BIOS_PORT          0x2
+#define SVGA_IRQSTATUS_PORT     0x8
 
 /*
  * Interrupt source flags for IRQSTATUS_PORT and IRQMASK.
 #define SVGA_IRQFLAG_FIFO_PROGRESS        0x2    /* Made forward progress in the FIFO */
 #define SVGA_IRQFLAG_FENCE_GOAL           0x4    /* SVGA_FIFO_FENCE_GOAL reached */
 
-/* This port is deprecated, but retained because of old drivers. */
-#define SVGA_LEGACY_ACCEL_PORT 0x3
-
-/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
-#define SVGA_CURSOR_ON_HIDE               0x0    /* Must be 0 to maintain backward compatibility */
-#define SVGA_CURSOR_ON_SHOW               0x1    /* Must be 1 to maintain backward compatibility */
-#define SVGA_CURSOR_ON_REMOVE_FROM_FB     0x2    /* Remove the cursor from the framebuffer because we need to see what's under it */
-#define SVGA_CURSOR_ON_RESTORE_TO_FB      0x3    /* Put the cursor back in the framebuffer so the user can see it */
-
 /*
  * Registers
  */
@@ -108,13 +114,13 @@ enum {
    SVGA_REG_MAX_WIDTH = 4,
    SVGA_REG_MAX_HEIGHT = 5,
    SVGA_REG_DEPTH = 6,
-   SVGA_REG_BITS_PER_PIXEL = 7,     /* Current bpp in the guest */
+   SVGA_REG_BITS_PER_PIXEL = 7,       /* Current bpp in the guest */
    SVGA_REG_PSEUDOCOLOR = 8,
    SVGA_REG_RED_MASK = 9,
    SVGA_REG_GREEN_MASK = 10,
    SVGA_REG_BLUE_MASK = 11,
    SVGA_REG_BYTES_PER_LINE = 12,
-   SVGA_REG_FB_START = 13,
+   SVGA_REG_FB_START = 13,            /* (Deprecated) */
    SVGA_REG_FB_OFFSET = 14,
    SVGA_REG_VRAM_SIZE = 15,
    SVGA_REG_FB_SIZE = 16,
@@ -122,33 +128,44 @@ enum {
    /* ID 0 implementation only had the above registers, then the palette */
 
    SVGA_REG_CAPABILITIES = 17,
-   SVGA_REG_MEM_START = 18,       /* Memory for command FIFO and bitmaps */
+   SVGA_REG_MEM_START = 18,           /* (Deprecated) */
    SVGA_REG_MEM_SIZE = 19,
-   SVGA_REG_CONFIG_DONE = 20,      /* Set when memory area configured */
-   SVGA_REG_SYNC = 21,             /* See "FIFO Synchronization Registers" */
-   SVGA_REG_BUSY = 22,             /* See "FIFO Synchronization Registers" */
-   SVGA_REG_GUEST_ID = 23,        /* Set guest OS identifier */
-   SVGA_REG_CURSOR_ID = 24,       /* ID of cursor */
-   SVGA_REG_CURSOR_X = 25,        /* Set cursor X position */
-   SVGA_REG_CURSOR_Y = 26,        /* Set cursor Y position */
-   SVGA_REG_CURSOR_ON = 27,       /* Turn cursor on/off */
-   SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */
-   SVGA_REG_SCRATCH_SIZE = 29,     /* Number of scratch registers */
-   SVGA_REG_MEM_REGS = 30,         /* Number of FIFO registers */
-   SVGA_REG_NUM_DISPLAYS = 31,     /* Number of guest displays */
-   SVGA_REG_PITCHLOCK = 32,        /* Fixed pitch for all modes */
-   SVGA_REG_IRQMASK = 33,          /* Interrupt mask */
+   SVGA_REG_CONFIG_DONE = 20,         /* Set when memory area configured */
+   SVGA_REG_SYNC = 21,                /* See "FIFO Synchronization Registers" */
+   SVGA_REG_BUSY = 22,                /* See "FIFO Synchronization Registers" */
+   SVGA_REG_GUEST_ID = 23,            /* Set guest OS identifier */
+   SVGA_REG_CURSOR_ID = 24,           /* (Deprecated) */
+   SVGA_REG_CURSOR_X = 25,            /* (Deprecated) */
+   SVGA_REG_CURSOR_Y = 26,            /* (Deprecated) */
+   SVGA_REG_CURSOR_ON = 27,           /* (Deprecated) */
+   SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* (Deprecated) */
+   SVGA_REG_SCRATCH_SIZE = 29,        /* Number of scratch registers */
+   SVGA_REG_MEM_REGS = 30,            /* Number of FIFO registers */
+   SVGA_REG_NUM_DISPLAYS = 31,        /* (Deprecated) */
+   SVGA_REG_PITCHLOCK = 32,           /* Fixed pitch for all modes */
+   SVGA_REG_IRQMASK = 33,             /* Interrupt mask */
+
+   /* Legacy multi-monitor support */
    SVGA_REG_NUM_GUEST_DISPLAYS = 34,/* Number of guest displays in X/Y direction */
-   SVGA_REG_DISPLAY_ID = 35,        /* The display ID for the following display attributes */
+   SVGA_REG_DISPLAY_ID = 35,        /* Display ID for the following display attributes */
    SVGA_REG_DISPLAY_IS_PRIMARY = 36,/* Whether this is a primary display */
    SVGA_REG_DISPLAY_POSITION_X = 37,/* The display position x */
    SVGA_REG_DISPLAY_POSITION_Y = 38,/* The display position y */
    SVGA_REG_DISPLAY_WIDTH = 39,     /* The display's width */
    SVGA_REG_DISPLAY_HEIGHT = 40,    /* The display's height */
-   SVGA_REG_TOP = 41,               /* Must be 1 more than the last register */
 
-   SVGA_PALETTE_BASE = 1024,       /* Base of SVGA color map */
+   /* See "Guest memory regions" below. */
+   SVGA_REG_GMR_ID = 41,
+   SVGA_REG_GMR_DESCRIPTOR = 42,
+   SVGA_REG_GMR_MAX_IDS = 43,
+   SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH = 44,
+
+   SVGA_REG_TRACES = 45,            /* Enable trace-based updates even when FIFO is on */
+   SVGA_REG_TOP = 46,               /* Must be 1 more than the last register */
+
+   SVGA_PALETTE_BASE = 1024,        /* Base of SVGA color map */
    /* Next 768 (== 256*3) registers exist for colormap */
+
    SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + SVGA_NUM_PALETTE_REGS
                                     /* Base of scratch registers */
    /* Next reg[SVGA_REG_SCRATCH_SIZE] registers exist for scratch usage:
@@ -156,126 +173,231 @@ enum {
       the use of the current SVGA driver. */
 };
 
+/*
+ *  Macros to compute variable length items (sizes in 32-bit words, except
+ *  for SVGA_GLYPH_SCANLINE_SIZE, which is in bytes).
+ */
+#define SVGA_BITMAP_SIZE(w,h) ((((w)+31) >> 5) * (h))
+#define SVGA_PIXMAP_SIZE(w,h,bpp) ((( ((w)*(bpp))+31 ) >> 5) * (h))
+#define SVGA_BITMAP_INCREMENT(w) ((( (w)+31 ) >> 5) * sizeof (uint32))
+#define SVGA_PIXMAP_INCREMENT(w,bpp) ((( ((w)*(bpp))+31 ) >> 5) * sizeof (uint32))
 
 /*
- *  Capabilities
+ * Guest memory regions (GMRs):
+ *
+ * This is a new memory mapping feature available in SVGA devices
+ * which have the SVGA_CAP_GMR bit set. Previously, there were two
+ * fixed memory regions available with which to share data between the
+ * device and the driver: the FIFO ('MEM') and the framebuffer. GMRs
+ * are our name for an extensible way of providing arbitrary DMA
+ * buffers for use between the driver and the SVGA device. They are a
+ * new alternative to framebuffer memory, usable for both 2D and 3D
+ * graphics operations.
+ *
+ * Since GMR mapping must be done synchronously with guest CPU
+ * execution, we use a new pair of SVGA registers:
+ *
+ *   SVGA_REG_GMR_ID --
+ *
+ *     Read/write.
+ *     This register holds the 32-bit ID (a small positive integer)
+ *     of a GMR to create, delete, or redefine. Writing this register
+ *     has no side-effects.
+ *
+ *   SVGA_REG_GMR_DESCRIPTOR --
+ *
+ *     Write-only.
+ *     Writing this register will create, delete, or redefine the GMR
+ *     specified by the above ID register. If this register is zero,
+ *     the GMR is deleted. Any pointers into this GMR (including those
+ *     currently being processed by FIFO commands) will be
+ *     synchronously invalidated.
+ *
+ *     If this register is nonzero, it must be the physical page
+ *     number (PPN) of a data structure which describes the physical
+ *     layout of the memory region this GMR should describe. The
+ *     descriptor structure will be read synchronously by the SVGA
+ *     device when this register is written. The descriptor need not
+ *     remain allocated for the lifetime of the GMR.
+ *
+ *     The guest driver should write SVGA_REG_GMR_ID first, then
+ *     SVGA_REG_GMR_DESCRIPTOR.
+ *
+ *   SVGA_REG_GMR_MAX_IDS --
+ *
+ *     Read-only.
+ *     The SVGA device may choose to support a maximum number of
+ *     user-defined GMR IDs. This register holds the number of supported
+ *     IDs. (The maximum supported ID plus 1)
+ *
+ *   SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH --
+ *
+ *     Read-only.
+ *     The SVGA device may choose to put a limit on the total number
+ *     of SVGAGuestMemDescriptor structures it will read when defining
+ *     a single GMR.
+ *
+ * The descriptor structure is an array of SVGAGuestMemDescriptor
+ * structures. Each structure may do one of three things:
+ *
+ *   - Terminate the GMR descriptor list.
+ *     (ppn==0, numPages==0)
+ *
+ *   - Add a PPN or range of PPNs to the GMR's virtual address space.
+ *     (ppn != 0, numPages != 0)
+ *
+ *   - Provide the PPN of the next SVGAGuestMemDescriptor, in order to
+ *     support multi-page GMR descriptor tables without forcing the
+ *     driver to allocate physically contiguous memory.
+ *     (ppn != 0, numPages == 0)
+ *
+ * Note that each physical page of SVGAGuestMemDescriptor structures
+ * can describe at least 2MB of guest memory. If the driver needs to
+ * use more than one page of descriptor structures, it must use one of
+ * its SVGAGuestMemDescriptors to point to an additional page.  The
+ * device will never automatically cross a page boundary.
+ *
+ * Once the driver has described a GMR, it is immediately available
+ * for use via any FIFO command that uses an SVGAGuestPtr structure.
+ * These pointers include a GMR identifier plus an offset into that
+ * GMR.
+ *
+ * The driver must check the SVGA_CAP_GMR bit before using the GMR
+ * registers.
  */
 
-#define SVGA_CAP_NONE               0x00000000
-#define SVGA_CAP_RECT_FILL         0x00000001
-#define SVGA_CAP_RECT_COPY         0x00000002
-#define SVGA_CAP_RECT_PAT_FILL      0x00000004
-#define SVGA_CAP_LEGACY_OFFSCREEN   0x00000008
-#define SVGA_CAP_RASTER_OP         0x00000010
-#define SVGA_CAP_CURSOR                    0x00000020
-#define SVGA_CAP_CURSOR_BYPASS     0x00000040
-#define SVGA_CAP_CURSOR_BYPASS_2    0x00000080
-#define SVGA_CAP_8BIT_EMULATION     0x00000100
-#define SVGA_CAP_ALPHA_CURSOR       0x00000200
-#define SVGA_CAP_GLYPH              0x00000400
-#define SVGA_CAP_GLYPH_CLIPPING     0x00000800
-#define SVGA_CAP_OFFSCREEN_1        0x00001000
-#define SVGA_CAP_ALPHA_BLEND        0x00002000
-#define SVGA_CAP_3D                 0x00004000
-#define SVGA_CAP_EXTENDED_FIFO      0x00008000
-#define SVGA_CAP_MULTIMON           0x00010000
-#define SVGA_CAP_PITCHLOCK          0x00020000
-#define SVGA_CAP_IRQMASK            0x00040000
-#define SVGA_CAP_DISPLAY_TOPOLOGY   0x00080000
+/*
+ * Special GMR IDs, allowing SVGAGuestPtrs to point to framebuffer
+ * memory as well.  In the future, these IDs could even be used to
+ * allow legacy memory regions to be redefined by the guest as GMRs.
+ *
+ * Using the guest framebuffer (GFB) at BAR1 for general purpose DMA
+ * is being phased out. Please try to use user-defined GMRs whenever
+ * possible.
+ */
+#define SVGA_GMR_NULL         ((uint32) -1)
+#define SVGA_GMR_FRAMEBUFFER  ((uint32) -2)  // Guest Framebuffer (GFB)
+
+typedef
+struct SVGAGuestMemDescriptor {
+   uint32 ppn;
+   uint32 numPages;
+} SVGAGuestMemDescriptor;
+
+typedef
+struct SVGAGuestPtr {
+   uint32 gmrId;
+   uint32 offset;
+} SVGAGuestPtr;
 
 
 /*
- *  Raster op codes (same encoding as X) used by FIFO drivers.
+ * SVGAGMRImageFormat --
+ *
+ *    This is a packed representation of the source 2D image format
+ *    for a GMR-to-screen blit. Currently it is defined as an encoding
+ *    of the screen's color depth and bits-per-pixel, however, 16 bits
+ *    are reserved for future use to identify other encodings (such as
+ *    RGBA or higher-precision images).
+ *
+ *    Currently supported formats:
+ *
+ *       bpp depth  Format Name
+ *       --- -----  -----------
+ *        32    24  32-bit BGRX
+ *        24    24  24-bit BGR
+ *        16    16  RGB 5-6-5
+ *        16    15  RGB 5-5-5
+ *
  */
 
-#define SVGA_ROP_CLEAR          0x00     /* 0 */
-#define SVGA_ROP_AND            0x01     /* src AND dst */
-#define SVGA_ROP_AND_REVERSE    0x02     /* src AND NOT dst */
-#define SVGA_ROP_COPY           0x03     /* src */
-#define SVGA_ROP_AND_INVERTED   0x04     /* NOT src AND dst */
-#define SVGA_ROP_NOOP           0x05     /* dst */
-#define SVGA_ROP_XOR            0x06     /* src XOR dst */
-#define SVGA_ROP_OR             0x07     /* src OR dst */
-#define SVGA_ROP_NOR            0x08     /* NOT src AND NOT dst */
-#define SVGA_ROP_EQUIV          0x09     /* NOT src XOR dst */
-#define SVGA_ROP_INVERT         0x0a     /* NOT dst */
-#define SVGA_ROP_OR_REVERSE     0x0b     /* src OR NOT dst */
-#define SVGA_ROP_COPY_INVERTED  0x0c     /* NOT src */
-#define SVGA_ROP_OR_INVERTED    0x0d     /* NOT src OR dst */
-#define SVGA_ROP_NAND           0x0e     /* NOT src OR NOT dst */
-#define SVGA_ROP_SET            0x0f     /* 1 */
-#define SVGA_ROP_UNSUPPORTED    0x10
+typedef
+struct SVGAGMRImageFormat {
+   union {
+      struct {
+         uint32 bitsPerPixel : 8;
+         uint32 colorDepth   : 8;
+         uint32 reserved     : 16;  // Must be zero
+      };
 
-#define SVGA_NUM_SUPPORTED_ROPS   16
-#define SVGA_ROP_ALL            (MASK(SVGA_NUM_SUPPORTED_ROPS))
-#define SVGA_IS_VALID_ROP(rop)  (rop < SVGA_NUM_SUPPORTED_ROPS)
+      uint32 value;
+   };
+} SVGAGMRImageFormat;
+
+/*
+ * SVGAColorBGRX --
+ *
+ *    A 24-bit color format (BGRX), which does not depend on the
+ *    format of the legacy guest framebuffer (GFB) or the current
+ *    GMRFB state.
+ */
+
+typedef
+struct SVGAColorBGRX {
+   union {
+      struct {
+         uint32 b : 8;
+         uint32 g : 8;
+         uint32 r : 8;
+         uint32 x : 8;  // Unused
+      };
+
+      uint32 value;
+   };
+} SVGAColorBGRX;
 
-#define SVGA_INVALID_DISPLAY_ID ((uint32)-1)
 
 /*
- *  Ops
- *  For each pixel, the four channels of the image are computed with: 
- *
- *     C = Ca * Fa + Cb * Fb
- *
- *  where C, Ca, Cb are the values of the respective channels and Fa 
- *  and Fb come from the following table: 
- *
- *     BlendOp         Fa                      Fb
- *     ------------------------------------------
- *     Clear           0                       0
- *     Src             1                       0
- *     Dst             0                       1
- *     Over            1                       1-Aa
- *     OverReverse     1-Ab                    1
- *     In              Ab                      0
- *     InReverse       0                       Aa
- *     Out             1-Ab                    0
- *     OutReverse      0                       1-Aa
- *     Atop            Ab                      1-Aa
- *     AtopReverse     1-Ab                    Aa
- *     Xor             1-Ab                    1-Aa
- *     Add             1                       1
- *     Saturate        min(1,(1-Ab)/Aa)        1
- *
- *  Flags
- *  You can use the following flags to achieve additional affects:
- * 
- *      Flag                    Effect
- *     ------------------------------------------
- *      ConstantSourceAlpha     Ca = Ca * Param0
- *      ConstantDestAlpha       Cb = Cb * Param1
- *
- *  Flag effects resolve before the op.  For example
- *  BlendOp == Add && Flags == ConstantSourceAlpha |
- *  ConstantDestAlpha results in:
- *
- *       C = (Ca * Param0) + (Cb * Param1)
- */
-
-#define SVGA_BLENDOP_CLEAR                      0
-#define SVGA_BLENDOP_SRC                        1
-#define SVGA_BLENDOP_DST                        2
-#define SVGA_BLENDOP_OVER                       3
-#define SVGA_BLENDOP_OVER_REVERSE               4
-#define SVGA_BLENDOP_IN                         5
-#define SVGA_BLENDOP_IN_REVERSE                 6
-#define SVGA_BLENDOP_OUT                        7
-#define SVGA_BLENDOP_OUT_REVERSE                8
-#define SVGA_BLENDOP_ATOP                       9 
-#define SVGA_BLENDOP_ATOP_REVERSE               10
-#define SVGA_BLENDOP_XOR                        11
-#define SVGA_BLENDOP_ADD                        12
-#define SVGA_BLENDOP_SATURATE                   13
-
-#define SVGA_NUM_BLENDOPS                       14
-#define SVGA_IS_VALID_BLENDOP(op)               (op >= 0 && op < SVGA_NUM_BLENDOPS)
-
-#define SVGA_BLENDFLAG_CONSTANT_SOURCE_ALPHA    0x01
-#define SVGA_BLENDFLAG_CONSTANT_DEST_ALPHA      0x02
-#define SVGA_NUM_BLENDFLAGS                     2
-#define SVGA_BLENDFLAG_ALL                      (MASK(SVGA_NUM_BLENDFLAGS))
-#define SVGA_IS_VALID_BLENDFLAG(flag)           ((flag & ~SVGA_BLENDFLAG_ALL) == 0)
+ * SVGASignedRect --
+ * SVGASignedPoint --
+ *
+ *    Signed rectangle and point primitives. These are used by the new
+ *    2D primitives for drawing to Screen Objects, which can occupy a
+ *    signed virtual coordinate space.
+ *
+ *    SVGASignedRect specifies a half-open interval: the (left, top)
+ *    pixel is part of the rectangle, but the (right, bottom) pixel is
+ *    not.
+ */
+
+typedef
+struct SVGASignedRect {
+   int32  left;
+   int32  top;
+   int32  right;
+   int32  bottom;
+} SVGASignedRect;
+
+typedef
+struct SVGASignedPoint {
+   int32  x;
+   int32  y;
+} SVGASignedPoint;
+
+
+/*
+ *  Capabilities
+ *
+ *  Note the holes in the bitfield. Missing bits have been deprecated,
+ *  and must not be reused. Those capabilities will never be reported
+ *  by new versions of the SVGA device.
+ */
+
+#define SVGA_CAP_NONE               0x00000000
+#define SVGA_CAP_RECT_COPY          0x00000002
+#define SVGA_CAP_CURSOR             0x00000020
+#define SVGA_CAP_CURSOR_BYPASS      0x00000040   // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_CURSOR_BYPASS_2    0x00000080   // Legacy (Use Cursor Bypass 3 instead)
+#define SVGA_CAP_8BIT_EMULATION     0x00000100
+#define SVGA_CAP_ALPHA_CURSOR       0x00000200
+#define SVGA_CAP_3D                 0x00004000
+#define SVGA_CAP_EXTENDED_FIFO      0x00008000
+#define SVGA_CAP_MULTIMON           0x00010000   // Legacy multi-monitor support
+#define SVGA_CAP_PITCHLOCK          0x00020000
+#define SVGA_CAP_IRQMASK            0x00040000
+#define SVGA_CAP_DISPLAY_TOPOLOGY   0x00080000   // Legacy multi-monitor support
+#define SVGA_CAP_GMR                0x00100000
+#define SVGA_CAP_TRACES             0x00200000
 
 
 /*
@@ -320,7 +442,7 @@ enum {
 
    SVGA_FIFO_CAPABILITIES = 4,
    SVGA_FIFO_FLAGS,
-   /* Valid with SVGA_FIFO_CAP_FENCE: */
+   // Valid with SVGA_FIFO_CAP_FENCE:
    SVGA_FIFO_FENCE,
 
    /*
@@ -332,19 +454,33 @@ enum {
     * These in block 3a, the VMX currently considers mandatory for the
     * extended FIFO.
     */
-   
-   /* Valid if exists (i.e. if extended FIFO enabled): */
+
+   // Valid if exists (i.e. if extended FIFO enabled):
    SVGA_FIFO_3D_HWVERSION,       /* See SVGA3dHardwareVersion in svga3d_reg.h */
-   /* Valid with SVGA_FIFO_CAP_PITCHLOCK: */
+   // Valid with SVGA_FIFO_CAP_PITCHLOCK:
    SVGA_FIFO_PITCHLOCK,
-   /* Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3: */
+
+   // Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3:
    SVGA_FIFO_CURSOR_ON,          /* Cursor bypass 3 show/hide register */
    SVGA_FIFO_CURSOR_X,           /* Cursor bypass 3 x register */
    SVGA_FIFO_CURSOR_Y,           /* Cursor bypass 3 y register */
    SVGA_FIFO_CURSOR_COUNT,       /* Incremented when any of the other 3 change */
    SVGA_FIFO_CURSOR_LAST_UPDATED,/* Last time the host updated the cursor */
-   /* Valid with SVGA_FIFO_CAP_RESERVE: */
+
+   // Valid with SVGA_FIFO_CAP_RESERVE:
    SVGA_FIFO_RESERVED,           /* Bytes past NEXT_CMD with real contents */
+
+   /*
+    * Valid with SVGA_FIFO_CAP_SCREEN_OBJECT:
+    *
+    * By default this is SVGA_ID_INVALID, to indicate that the cursor
+    * coordinates are specified relative to the virtual root. If this
+    * is set to a specific screen ID, cursor position is reinterpreted
+    * as a signed offset relative to that screen's origin. This is the
+    * only way to place the cursor on a non-rooted screen.
+    */
+   SVGA_FIFO_CURSOR_SCREEN_ID,
+
    /*
     * XXX: The gap here, up until SVGA_FIFO_3D_CAPS, can be used for new
     * registers, but this must be done carefully and with judicious use of
@@ -361,6 +497,7 @@ enum {
     * before 3D_CAPS, needs to reason about something other than
     * SVGA_FIFO_MIN.
     */
+
    /*
     * 3D caps block space; valid with 3D hardware version >=
     * SVGA3D_HWVERSION_WS6_B1.
@@ -382,7 +519,7 @@ enum {
     * sets SVGA_FIFO_MIN high enough to leave room for them.
     */
 
-   /* Valid if register exists: */
+   // Valid if register exists:
    SVGA_FIFO_GUEST_3D_HWVERSION, /* Guest driver's 3D version */
    SVGA_FIFO_FENCE_GOAL,         /* Matching target for SVGA_IRQFLAG_FENCE_GOAL */
    SVGA_FIFO_BUSY,               /* See "FIFO Synchronization Registers" */
@@ -533,6 +670,56 @@ enum {
  *      Pitch Lock -- Pitch lock register is supported
  *      Video -- SVGA Video overlay units are supported
  *      Escape -- Escape command is supported
+ *
+ * XXX: Add longer descriptions for each capability, including a list
+ *      of the new features that each capability provides.
+ *
+ * SVGA_FIFO_CAP_SCREEN_OBJECT --
+ *
+ *    Provides dynamic multi-screen rendering, for improved Unity and
+ *    multi-monitor modes. With Screen Object, the guest can
+ *    dynamically create and destroy 'screens', which can represent
+ *    Unity windows or virtual monitors. Screen Object also provides
+ *    strong guarantees that DMA operations happen only when
+ *    guest-initiated. Screen Object deprecates the BAR1 guest
+ *    framebuffer (GFB) and all commands that work only with the GFB.
+ *
+ *    New registers:
+ *       FIFO_CURSOR_SCREEN_ID, VIDEO_DATA_GMRID, VIDEO_DST_SCREEN_ID
+ *
+ *    New 2D commands:
+ *       DEFINE_SCREEN, DESTROY_SCREEN, DEFINE_GMRFB, BLIT_GMRFB_TO_SCREEN,
+ *       BLIT_SCREEN_TO_GMRFB, ANNOTATION_FILL, ANNOTATION_COPY
+ *
+ *    New 3D commands:
+ *       BLIT_SURFACE_TO_SCREEN
+ *
+ *    New guarantees:
+ *
+ *       - The host will not read or write guest memory, including the GFB,
+ *         except when explicitly initiated by a DMA command.
+ *
+ *       - All DMA, including legacy DMA like UPDATE and PRESENT_READBACK,
+ *         is guaranteed to complete before any subsequent FENCEs.
+ *
+ *       - All legacy commands which affect a Screen (UPDATE, PRESENT,
+ *         PRESENT_READBACK) as well as new Screen blit commands will
+ *         all behave consistently as blits, and memory will be read
+ *         or written in FIFO order.
+ *
+ *         For example, if you PRESENT from one SVGA3D surface to multiple
+ *         places on the screen, the data copied will always be from the
+ *         SVGA3D surface at the time the PRESENT was issued in the FIFO.
+ *         This was not necessarily true on devices without Screen Object.
+ *
+ *         This means that on devices that support Screen Object, the
+ *         PRESENT_READBACK command should not be necessary unless you
+ *         actually want to read back the results of 3D rendering into
+ *         system memory. (And for that, the BLIT_SCREEN_TO_GMRFB
+ *         command provides a strict superset of functionality.)
+ *
+ *       - When a screen is resized, either using Screen Object commands or
+ *         legacy multimon registers, its contents are preserved.
  */
 
 #define SVGA_FIFO_CAP_NONE                  0
@@ -543,6 +730,7 @@ enum {
 #define SVGA_FIFO_CAP_CURSOR_BYPASS_3   (1<<4)
 #define SVGA_FIFO_CAP_ESCAPE            (1<<5)
 #define SVGA_FIFO_CAP_RESERVE           (1<<6)
+#define SVGA_FIFO_CAP_SCREEN_OBJECT     (1<<7)
 
 
 /*
@@ -553,7 +741,7 @@ enum {
 
 #define SVGA_FIFO_FLAG_NONE                 0
 #define SVGA_FIFO_FLAG_ACCELFRONT       (1<<0)
-#define SVGA_FIFO_FLAG_RESERVED        (1<<31) /* Internal use only */
+#define SVGA_FIFO_FLAG_RESERVED        (1<<31) // Internal use only
 
 /*
  * FIFO reservation sentinel value
@@ -586,20 +774,22 @@ enum {
    SVGA_VIDEO_DATA_OFFSET,
    SVGA_VIDEO_FORMAT,
    SVGA_VIDEO_COLORKEY,
-   SVGA_VIDEO_SIZE,
+   SVGA_VIDEO_SIZE,          // Deprecated
    SVGA_VIDEO_WIDTH,
    SVGA_VIDEO_HEIGHT,
    SVGA_VIDEO_SRC_X,
    SVGA_VIDEO_SRC_Y,
    SVGA_VIDEO_SRC_WIDTH,
    SVGA_VIDEO_SRC_HEIGHT,
-   SVGA_VIDEO_DST_X,
-   SVGA_VIDEO_DST_Y,
+   SVGA_VIDEO_DST_X,         // Signed int32
+   SVGA_VIDEO_DST_Y,         // Signed int32
    SVGA_VIDEO_DST_WIDTH,
    SVGA_VIDEO_DST_HEIGHT,
    SVGA_VIDEO_PITCH_1,
    SVGA_VIDEO_PITCH_2,
    SVGA_VIDEO_PITCH_3,
+   SVGA_VIDEO_DATA_GMRID,    // Optional, defaults to SVGA_GMR_FRAMEBUFFER
+   SVGA_VIDEO_DST_SCREEN_ID, // Optional, defaults to virtual coords (SVGA_ID_INVALID)
    SVGA_VIDEO_NUM_REGS
 };
 
@@ -625,242 +815,545 @@ typedef struct SVGAOverlayUnit {
    uint32 srcY;
    uint32 srcWidth;
    uint32 srcHeight;
-   uint32 dstX;
-   uint32 dstY;
+   int32  dstX;
+   int32  dstY;
    uint32 dstWidth;
    uint32 dstHeight;
    uint32 pitches[3];
+   uint32 dataGMRId;
+   uint32 dstScreenId;
 } SVGAOverlayUnit;
 
 
 /*
- *  Drawing object ID's, in the range 0 to SVGA_MAX_ID
+ * SVGAScreenObject --
+ *
+ *    This is a new way to represent a guest's multi-monitor screen or
+ *    Unity window. Screen objects are only supported if the
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT capability bit is set.
+ *
+ *    If Screen Objects are supported, they can be used to fully
+ *    replace the functionality provided by the framebuffer registers
+ *    (SVGA_REG_WIDTH, HEIGHT, etc.) and by SVGA_CAP_DISPLAY_TOPOLOGY.
+ *
+ *    The screen object is a struct with guaranteed binary
+ *    compatibility. New flags can be added, and the struct may grow,
+ *    but existing fields must retain their meaning.
+ *
  */
 
-#define         SVGA_MAX_ID          499
+#define SVGA_SCREEN_HAS_ROOT    (1 << 0)  // Screen is present in the virtual coord space
+#define SVGA_SCREEN_IS_PRIMARY  (1 << 1)  // Guest considers this screen to be 'primary'
+#define SVGA_SCREEN_FULLSCREEN_HINT (1 << 2)   // Guest is running a fullscreen app here
+
+typedef
+struct SVGAScreenObject {
+   uint32 structSize;   // sizeof(SVGAScreenObject)
+   uint32 id;
+   uint32 flags;
+   struct {
+      uint32 width;
+      uint32 height;
+   } size;
+   struct {
+      int32 x;
+      int32 y;
+   } root;              // Only used if SVGA_SCREEN_HAS_ROOT is set.
+} SVGAScreenObject;
+
 
 /*
- *  Macros to compute variable length items (sizes in 32-bit words, except
- *  for SVGA_GLYPH_SCANLINE_SIZE, which is in bytes).
+ *  Commands in the command FIFO:
+ *
+ *  Command IDs defined below are used for the traditional 2D FIFO
+ *  communication (not all commands are available for all versions of the
+ *  SVGA FIFO protocol).
+ *
+ *  Note the holes in the command ID numbers: These commands have been
+ *  deprecated, and the old IDs must not be reused.
+ *
+ *  Command IDs from 1000 to 1999 are reserved for use by the SVGA3D
+ *  protocol.
+ *
+ *  Each command's parameters are described by the comments and
+ *  structs below.
  */
 
-#define SVGA_BITMAP_SIZE(w,h) ((((w)+31) >> 5) * (h))
-#define SVGA_BITMAP_SCANLINE_SIZE(w) (( (w)+31 ) >> 5)
-#define SVGA_PIXMAP_SIZE(w,h,bpp) ((( ((w)*(bpp))+31 ) >> 5) * (h))
-#define SVGA_PIXMAP_SCANLINE_SIZE(w,bpp) (( ((w)*(bpp))+31 ) >> 5)
-#define SVGA_GLYPH_SIZE(w,h) ((((((w) + 7) >> 3) * (h)) + 3) >> 2)
-#define SVGA_GLYPH_SCANLINE_SIZE(w) (((w) + 7) >> 3)
-#define SVGA_ESCAPE_SIZE(s) (((s) + 3) >> 2)
+typedef enum {
+   SVGA_CMD_INVALID_CMD           = 0,
+   SVGA_CMD_UPDATE                = 1,
+   SVGA_CMD_RECT_COPY             = 3,
+   SVGA_CMD_DEFINE_CURSOR         = 19,
+   SVGA_CMD_DEFINE_ALPHA_CURSOR   = 22,
+   SVGA_CMD_UPDATE_VERBOSE        = 25,
+   SVGA_CMD_FRONT_ROP_FILL        = 29,
+   SVGA_CMD_FENCE                 = 30,
+   SVGA_CMD_ESCAPE                = 33,
+   SVGA_CMD_DEFINE_SCREEN         = 34,
+   SVGA_CMD_DESTROY_SCREEN        = 35,
+   SVGA_CMD_DEFINE_GMRFB          = 36,
+   SVGA_CMD_BLIT_GMRFB_TO_SCREEN  = 37,
+   SVGA_CMD_BLIT_SCREEN_TO_GMRFB  = 38,
+   SVGA_CMD_ANNOTATION_FILL       = 39,
+   SVGA_CMD_ANNOTATION_COPY       = 40,
+   SVGA_CMD_MAX
+} SVGAFifoCmdId;
+
+#define SVGA_CMD_MAX_ARGS           64
+
 
 /*
- *  Increment from one scanline to the next of a bitmap or pixmap
+ * SVGA_CMD_UPDATE --
+ *
+ *    This is a DMA transfer which copies from the Guest Framebuffer
+ *    (GFB) at BAR1 + SVGA_REG_FB_OFFSET to any screens which
+ *    intersect with the provided virtual rectangle.
+ *
+ *    This command does not support using arbitrary guest memory as a
+ *    data source- it only works with the pre-defined GFB memory.
+ *    This command also does not support signed virtual coordinates.
+ *    If you have defined screens (using SVGA_CMD_DEFINE_SCREEN) with
+ *    negative root x/y coordinates, the negative portion of those
+ *    screens will not be reachable by this command.
+ *
+ *    This command is not necessary when using framebuffer
+ *    traces. Traces are automatically enabled if the SVGA FIFO is
+ *    disabled, and you may explicitly enable/disable traces using
+ *    SVGA_REG_TRACES. With traces enabled, any write to the GFB will
+ *    automatically act as if a subsequent SVGA_CMD_UPDATE was issued.
+ *
+ *    Traces and SVGA_CMD_UPDATE are the only supported ways to render
+ *    pseudocolor screen updates. The newer Screen Object commands
+ *    only support true color formats.
+ *
+ * Availability:
+ *    Always available.
  */
-#define SVGA_BITMAP_INCREMENT(w) ((( (w)+31 ) >> 5) * sizeof (uint32))
-#define SVGA_PIXMAP_INCREMENT(w,bpp) ((( ((w)*(bpp))+31 ) >> 5) * sizeof (uint32))
+
+typedef
+struct {
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+} SVGAFifoCmdUpdate;
+
 
 /*
- *  Transparent color for DRAW_GLYPH_CLIPPED
+ * SVGA_CMD_RECT_COPY --
+ *
+ *    Perform a rectangular DMA transfer from one area of the GFB to
+ *    another, and copy the result to any screens which intersect it.
+ *
+ * Availability:
+ *    SVGA_CAP_RECT_COPY
  */
-#define SVGA_COLOR_TRANSPARENT (~0)
+
+typedef
+struct {
+   uint32 srcX;
+   uint32 srcY;
+   uint32 destX;
+   uint32 destY;
+   uint32 width;
+   uint32 height;
+} SVGAFifoCmdRectCopy;
+
 
 /*
- *  Commands in the command FIFO
+ * SVGA_CMD_DEFINE_CURSOR --
+ *
+ *    Provide a new cursor image, as an AND/XOR mask.
+ *
+ *    The recommended way to position the cursor overlay is by using
+ *    the SVGA_FIFO_CURSOR_* registers, supported by the
+ *    SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ *    SVGA_CAP_CURSOR
  */
 
-#define         SVGA_CMD_INVALID_CMD              0
-        /* FIFO layout:
-            <nothing> (well, undefined) */
+typedef
+struct {
+   uint32 id;             // Reserved, must be zero.
+   uint32 hotspotX;
+   uint32 hotspotY;
+   uint32 width;
+   uint32 height;
+   uint32 andMaskDepth;   // Value must be 1 or equal to BITS_PER_PIXEL
+   uint32 xorMaskDepth;   // Value must be 1 or equal to BITS_PER_PIXEL
+   /*
+    * Followed by scanline data for AND mask, then XOR mask.
+    * Each scanline is padded to a 32-bit boundary.
+   */
+} SVGAFifoCmdDefineCursor;
+
+
+/*
+ * SVGA_CMD_DEFINE_ALPHA_CURSOR --
+ *
+ *    Provide a new cursor image, in 32-bit BGRA format.
+ *
+ *    The recommended way to position the cursor overlay is by using
+ *    the SVGA_FIFO_CURSOR_* registers, supported by the
+ *    SVGA_FIFO_CAP_CURSOR_BYPASS_3 capability.
+ *
+ * Availability:
+ *    SVGA_CAP_ALPHA_CURSOR
+ */
+
+typedef
+struct {
+   uint32 id;             // Reserved, must be zero.
+   uint32 hotspotX;
+   uint32 hotspotY;
+   uint32 width;
+   uint32 height;
+   /* Followed by scanline data */
+} SVGAFifoCmdDefineAlphaCursor;
+
+
+/*
+ * SVGA_CMD_UPDATE_VERBOSE --
+ *
+ *    Just like SVGA_CMD_UPDATE, but also provide a per-rectangle
+ *    'reason' value, an opaque cookie which is used by internal
+ *    debugging tools. Third party drivers should not use this
+ *    command.
+ *
+ * Availability:
+ *    SVGA_CAP_EXTENDED_FIFO
+ */
+
+typedef
+struct {
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+   uint32 reason;
+} SVGAFifoCmdUpdateVerbose;
+
+
+/*
+ * SVGA_CMD_FRONT_ROP_FILL --
+ *
+ *    This is a hint which tells the SVGA device that the driver has
+ *    just filled a rectangular region of the GFB with a solid
+ *    color. Instead of reading these pixels from the GFB, the device
+ *    can assume that they all equal 'color'. This is primarily used
+ *    for remote desktop protocols.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_ACCELFRONT
+ */
+
+#define  SVGA_ROP_COPY                    0x03
+
+#define SVGA_INVALID_DISPLAY_ID ((uint32)-1)
+
+typedef
+struct {
+   uint32 color;     // In the same format as the GFB
+   uint32 x;
+   uint32 y;
+   uint32 width;
+   uint32 height;
+   uint32 rop;       // Must be SVGA_ROP_COPY
+} SVGAFifoCmdFrontRopFill;
+
+
+/*
+ * SVGA_CMD_FENCE --
+ *
+ *    Insert a synchronization fence.  When the SVGA device reaches
+ *    this command, it will copy the 'fence' value into the
+ *    SVGA_FIFO_FENCE register. It will also compare the fence against
+ *    SVGA_FIFO_FENCE_GOAL. If the fence matches the goal and the
+ *    SVGA_IRQFLAG_FENCE_GOAL interrupt is enabled, the device will
+ *    raise this interrupt.
+ *
+ * Availability:
+ *    SVGA_FIFO_FENCE for this command,
+ *    SVGA_CAP_IRQMASK for SVGA_FIFO_FENCE_GOAL.
+ */
 
-#define         SVGA_CMD_UPDATE                   1
-        /* FIFO layout:
-           X, Y, Width, Height */
+typedef
+struct {
+   uint32 fence;
+} SVGAFifoCmdFence;
 
-#define         SVGA_CMD_RECT_FILL                2
-        /* FIFO layout:
-           Color, X, Y, Width, Height */
 
-#define         SVGA_CMD_RECT_COPY                3
-        /* FIFO layout:
-           Source X, Source Y, Dest X, Dest Y, Width, Height */
+/*
+ * SVGA_CMD_ESCAPE --
+ *
+ *    Send an extended or vendor-specific variable length command.
+ *    This is used for video overlay, third party plugins, and
+ *    internal debugging tools. See svga_escape.h
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_ESCAPE
+ */
 
-#define         SVGA_CMD_DEFINE_BITMAP            4
-        /* FIFO layout:
-           Pixmap ID, Width, Height, <scanlines> */
+typedef
+struct {
+   uint32 nsid;
+   uint32 size;
+   /* followed by 'size' bytes of data */
+} SVGAFifoCmdEscape;
 
-#define         SVGA_CMD_DEFINE_BITMAP_SCANLINE   5
-        /* FIFO layout:
-           Pixmap ID, Width, Height, Line #, scanline */
 
-#define         SVGA_CMD_DEFINE_PIXMAP            6
-        /* FIFO layout:
-           Pixmap ID, Width, Height, Depth, <scanlines> */
+/*
+ * SVGA_CMD_DEFINE_SCREEN --
+ *
+ *    Define or redefine an SVGAScreenObject. See the description of
+ *    SVGAScreenObject above.  The video driver is responsible for
+ *    generating new screen IDs. They should be small positive
+ *    integers. The virtual device will have an implementation
+ *    specific upper limit on the number of screen IDs
+ *    supported. Drivers are responsible for recycling IDs. The first
+ *    valid ID is zero.
+ *
+ *    - Interaction with other registers:
+ *
+ *    For backwards compatibility, when the GFB mode registers (WIDTH,
+ *    HEIGHT, PITCHLOCK, BITS_PER_PIXEL) are modified, the SVGA device
+ *    deletes all screens other than screen #0, and redefines screen
+ *    #0 according to the specified mode. Drivers that use
+ *    SVGA_CMD_DEFINE_SCREEN should destroy or redefine screen #0.
+ *
+ *    If you use screen objects, do not use the legacy multi-mon
+ *    registers (SVGA_REG_NUM_GUEST_DISPLAYS, SVGA_REG_DISPLAY_*).
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define         SVGA_CMD_DEFINE_PIXMAP_SCANLINE   7
-        /* FIFO layout:
-           Pixmap ID, Width, Height, Depth, Line #, scanline */
+typedef
+struct {
+   SVGAScreenObject screen;   // Variable-length according to version
+} SVGAFifoCmdDefineScreen;
 
-#define         SVGA_CMD_RECT_BITMAP_FILL         8
-        /* FIFO layout:
-           Bitmap ID, X, Y, Width, Height, Foreground, Background */
 
-#define         SVGA_CMD_RECT_PIXMAP_FILL         9
-        /* FIFO layout:
-           Pixmap ID, X, Y, Width, Height */
+/*
+ * SVGA_CMD_DESTROY_SCREEN --
+ *
+ *    Destroy an SVGAScreenObject. Its ID is immediately available for
+ *    re-use.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define         SVGA_CMD_RECT_BITMAP_COPY        10
-        /* FIFO layout:
-           Bitmap ID, Source X, Source Y, Dest X, Dest Y,
-           Width, Height, Foreground, Background */
+typedef
+struct {
+   uint32 screenId;
+} SVGAFifoCmdDestroyScreen;
 
-#define         SVGA_CMD_RECT_PIXMAP_COPY        11
-        /* FIFO layout:
-           Pixmap ID, Source X, Source Y, Dest X, Dest Y, Width, Height */
 
-#define         SVGA_CMD_FREE_OBJECT             12
-        /* FIFO layout:
-           Object (pixmap, bitmap, ...) ID */
+/*
+ * SVGA_CMD_DEFINE_GMRFB --
+ *
+ *    This command sets a piece of SVGA device state called the
+ *    Guest Memory Region Framebuffer, or GMRFB. The GMRFB is a
+ *    piece of light-weight state which identifies the location and
+ *    format of an image in guest memory or in BAR1. The GMRFB has
+ *    an arbitrary size, and it doesn't need to match the geometry
+ *    of the GFB or any screen object.
+ *
+ *    The GMRFB can be redefined as often as you like. You could
+ *    always use the same GMRFB, you could redefine it before
+ *    rendering from a different guest screen, or you could even
+ *    redefine it before every blit.
+ *
+ *    There are multiple ways to use this command. The simplest way is
+ *    to use it to move the framebuffer either to elsewhere in the GFB
+ *    (BAR1) memory region, or to a user-defined GMR. This lets a
+ *    driver use a framebuffer allocated entirely out of normal system
+ *    memory, which we encourage.
+ *
+ *    Another way to use this command is to set up a ring buffer of
+ *    updates in GFB memory. If a driver wants to ensure that no
+ *    frames are skipped by the SVGA device, it is important that the
+ *    driver not modify the source data for a blit until the device is
+ *    done processing the command. One efficient way to accomplish
+ *    this is to use a ring of small DMA buffers. Each buffer is used
+ *    for one blit, then we move on to the next buffer in the
+ *    ring. The FENCE mechanism is used to protect each buffer from
+ *    re-use until the device is finished with that buffer's
+ *    corresponding blit.
+ *
+ *    This command does not affect the meaning of SVGA_CMD_UPDATE.
+ *    UPDATEs always occur from the legacy GFB memory area. This
+ *    command has no support for pseudocolor GMRFBs. Currently only
+ *    true-color 15, 16, and 24-bit depths are supported. Future
+ *    devices may expose capabilities for additional framebuffer
+ *    formats.
+ *
+ *    The default GMRFB value is undefined. Drivers must always send
+ *    this command at least once before performing any blit from the
+ *    GMRFB.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define         SVGA_CMD_RECT_ROP_FILL           13
-         /* FIFO layout:
-            Color, X, Y, Width, Height, ROP */
+typedef
+struct {
+   SVGAGuestPtr        ptr;
+   uint32              bytesPerLine;
+   SVGAGMRImageFormat  format;
+} SVGAFifoCmdDefineGMRFB;
 
-#define         SVGA_CMD_RECT_ROP_COPY           14
-         /* FIFO layout:
-            Source X, Source Y, Dest X, Dest Y, Width, Height, ROP */
 
-#define         SVGA_CMD_RECT_ROP_BITMAP_FILL    15
-         /* FIFO layout:
-            ID, X, Y, Width, Height, Foreground, Background, ROP */
+/*
+ * SVGA_CMD_BLIT_GMRFB_TO_SCREEN --
+ *
+ *    This is a guest-to-host blit. It performs a DMA operation to
+ *    copy a rectangular region of pixels from the current GMRFB to
+ *    one or more Screen Objects.
+ *
+ *    The destination coordinate may be specified relative to a
+ *    screen's origin (if a screen ID is specified) or relative to the
+ *    virtual coordinate system's origin (if the screen ID is
+ *    SVGA_ID_INVALID). The actual destination may span zero or more
+ *    screens, in the case of a virtual destination rect or a rect
+ *    which extends off the edge of the specified screen.
+ *
+ *    This command writes to the screen's "base layer": the underlying
+ *    framebuffer which exists below any cursor or video overlays. No
+ *    action is necessary to explicitly hide or update any overlays
+ *    which exist on top of the updated region.
+ *
+ *    The SVGA device is guaranteed to finish reading from the GMRFB
+ *    by the time any subsequent FENCE commands are reached.
+ *
+ *    This command consumes an annotation. See the
+ *    SVGA_CMD_ANNOTATION_* commands for details.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define         SVGA_CMD_RECT_ROP_PIXMAP_FILL    16
-         /* FIFO layout:
-            ID, X, Y, Width, Height, ROP */
+typedef
+struct {
+   SVGASignedPoint  srcOrigin;
+   SVGASignedRect   destRect;
+   uint32           destScreenId;
+} SVGAFifoCmdBlitGMRFBToScreen;
 
-#define         SVGA_CMD_RECT_ROP_BITMAP_COPY    17
-         /* FIFO layout:
-            ID, Source X, Source Y,
-            Dest X, Dest Y, Width, Height, Foreground, Background, ROP */
 
-#define         SVGA_CMD_RECT_ROP_PIXMAP_COPY    18
-         /* FIFO layout:
-            ID, Source X, Source Y, Dest X, Dest Y, Width, Height, ROP */
+/*
+ * SVGA_CMD_BLIT_SCREEN_TO_GMRFB --
+ *
+ *    This is a host-to-guest blit. It performs a DMA operation to
+ *    copy a rectangular region of pixels from a single Screen Object
+ *    back to the current GMRFB.
+ *
+ *    Usage note: This command should be used rarely. It will
+ *    typically be inefficient, but it is necessary for some types of
+ *    synchronization between 3D (GPU) and 2D (CPU) rendering into
+ *    overlapping areas of a screen.
+ *
+ *    The source coordinate is specified relative to a screen's
+ *    origin. The provided screen ID must be valid. If any parameters
+ *    are invalid, the resulting pixel values are undefined.
+ *
+ *    This command reads the screen's "base layer". Overlays like
+ *    video and cursor are not included, but any data which was sent
+ *    using a blit-to-screen primitive will be available, no matter
+ *    whether the data's original source was the GMRFB or the 3D
+ *    acceleration hardware.
+ *
+ *    Note that our guest-to-host blits and host-to-guest blits aren't
+ *    symmetric in their current implementation. While the parameters
+ *    are identical, host-to-guest blits are a lot less featureful.
+ *    They do not support clipping: If the source parameters don't
+ *    fully fit within a screen, the blit fails. They must originate
+ *    from exactly one screen. Virtual coordinates are not directly
+ *    supported.
+ *
+ *    Host-to-guest blits do support the same set of GMRFB formats
+ *    offered by guest-to-host blits.
+ *
+ *    The SVGA device is guaranteed to finish writing to the GMRFB by
+ *    the time any subsequent FENCE commands are reached.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define        SVGA_CMD_DEFINE_CURSOR            19
-       /* FIFO layout:
-          ID, Hotspot X, Hotspot Y, Width, Height,
-          Depth for AND mask, Depth for XOR mask,
-          <scanlines for AND mask>, <scanlines for XOR mask> */
+typedef
+struct {
+   SVGASignedPoint  destOrigin;
+   SVGASignedRect   srcRect;
+   uint32           srcScreenId;
+} SVGAFifoCmdBlitScreenToGMRFB;
 
-#define        SVGA_CMD_DISPLAY_CURSOR           20
-       /* FIFO layout:
-          ID, On/Off (1 or 0) */
 
-#define        SVGA_CMD_MOVE_CURSOR              21
-       /* FIFO layout:
-          X, Y */
+/*
+ * SVGA_CMD_ANNOTATION_FILL --
+ *
+ *    This is a blit annotation. This command stores a small piece of
+ *    device state which is consumed by the next blit-to-screen
+ *    command. The state is only cleared by commands which are
+ *    specifically documented as consuming an annotation. Other
+ *    commands (such as ESCAPEs for debugging) may intervene between
+ *    the annotation and its associated blit.
+ *
+ *    This annotation is a promise about the contents of the next
+ *    blit: The video driver is guaranteeing that all pixels in that
+ *    blit will have the same value, specified here as a color in
+ *    SVGAColorBGRX format.
+ *
+ *    The SVGA device can still render the blit correctly even if it
+ *    ignores this annotation, but the annotation may allow it to
+ *    perform the blit more efficiently, for example by ignoring the
+ *    source data and performing a fill in hardware.
+ *
+ *    This annotation is most important for performance when the
+ *    user's display is being remoted over a network connection.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
 
-#define SVGA_CMD_DEFINE_ALPHA_CURSOR      22
-       /* FIFO layout:
-          ID, Hotspot X, Hotspot Y, Width, Height,
-          <scanlines> */
+typedef
+struct {
+   SVGAColorBGRX  color;
+} SVGAFifoCmdAnnotationFill;
 
-#define SVGA_CMD_DRAW_GLYPH               23
-       /* FIFO layout:
-          X, Y, W, H, FGCOLOR, <stencil buffer> */
-
-#define SVGA_CMD_DRAW_GLYPH_CLIPPED       24
-       /* FIFO layout:
-          X, Y, W, H, FGCOLOR, BGCOLOR, <cliprect>, <stencil buffer>
-           Transparent color expands are done by setting BGCOLOR to ~0 */
-
-#define        SVGA_CMD_UPDATE_VERBOSE           25
-        /* FIFO layout:
-          X, Y, Width, Height, Reason */
-
-#define SVGA_CMD_SURFACE_FILL             26
-        /* FIFO layout:
-          color, dstSurfaceOffset, x, y, w, h, rop */
-
-#define SVGA_CMD_SURFACE_COPY             27
-        /* FIFO layout:
-          srcSurfaceOffset, dstSurfaceOffset, srcX, srcY,
-           destX, destY, w, h, rop */
-
-#define SVGA_CMD_SURFACE_ALPHA_BLEND      28
-        /* FIFO layout:
-          srcSurfaceOffset, dstSurfaceOffset, srcX, srcY,
-           destX, destY, w, h, op (SVGA_BLENDOP*), flags (SVGA_BLENDFLAGS*), 
-           param1, param2 */
-
-#define         SVGA_CMD_FRONT_ROP_FILL          29
-         /* FIFO layout:
-            Color, X, Y, Width, Height, ROP */
-
-#define         SVGA_CMD_FENCE                   30
-         /* FIFO layout:
-            Fence value */
-
-#define SVGA_CMD_VIDEO_PLAY_OBSOLETE      31
-         /* Obsolete; do not use. */
-#define SVGA_CMD_VIDEO_END_OBSOLETE       32
-         /* Obsolete; do not use. */
-
-#define SVGA_CMD_ESCAPE                   33
-         /* FIFO layout:
-            Namespace ID, size(bytes), data */
-
-#define        SVGA_CMD_MAX                      34
-
-#define SVGA_CMD_MAX_ARGS                 64
-
-/*
- * Location and size of SVGA frame buffer and the FIFO.
- */
-#define SVGA_VRAM_MIN_SIZE   (4 * 640 * 480)  /* bytes */
-#define SVGA_VRAM_MAX_SIZE   (128 * 1024 * 1024)
-
-#define SVGA_VRAM_SIZE_WS       (16 * 1024 * 1024) /* 16 MB */
-#define SVGA_MEM_SIZE_WS        (2  * 1024 * 1024) /* 2  MB */
-#define SVGA_VRAM_SIZE_SERVER   (4  * 1024 * 1024) /* 4  MB */
-#define SVGA_MEM_SIZE_SERVER    (256 * 1024)       /* 256 KB */
-
-#if /* defined(VMX86_WGS) || */ defined(VMX86_SERVER)
-#define SVGA_VRAM_SIZE         SVGA_VRAM_SIZE_SERVER
-#define SVGA_MEM_SIZE          SVGA_MEM_SIZE_SERVER
-#else
-#define SVGA_VRAM_SIZE         SVGA_VRAM_SIZE_WS
-#define SVGA_MEM_SIZE          SVGA_MEM_SIZE_WS
-#endif
 
 /*
- * SVGA_FB_START is the default starting address of the SVGA frame
- * buffer in the guest's physical address space.
- * SVGA_FB_START_BIGMEM is the starting address of the SVGA frame
- * buffer for VMs that have a large amount of physical memory.
- *
- * The address of SVGA_FB_START is set to 2GB - (SVGA_FB_MAX_SIZE + SVGA_MEM_SIZE), 
- * thus the SVGA frame buffer sits at [SVGA_FB_START .. 2GB-1] in the
- * physical address space.  Our older SVGA drivers for NT treat the
- * address of the frame buffer as a signed integer.  For backwards
- * compatibility, we keep the default location of the frame buffer
- * at under 2GB in the address space.  This restricts VMs to have "only"
- * up to ~2031MB (i.e., up to SVGA_FB_START) of physical memory.
- *
- * For VMs that want more memory than the ~2031MB, we place the SVGA
- * frame buffer at SVGA_FB_START_BIGMEM.  This allows VMs to have up
- * to 3584MB, at least as far as the SVGA frame buffer is concerned
- * (note that there may be other issues that limit the VM memory
- * size).  PCI devices use high memory addresses, so we have to put
- * SVGA_FB_START_BIGMEM low enough so that it doesn't overlap with any
- * of these devices.  Placing SVGA_FB_START_BIGMEM at 0xE0000000
- * should leave plenty of room for the PCI devices.
- *
- * NOTE: All of that is only true for the 0710 chipset.  As of the 0405
- * chipset, the framebuffer start is determined solely based on the value
- * the guest BIOS or OS programs into the PCI base address registers.
- */
-#define SVGA_FB_LEGACY_START           0x7EFC0000
-#define SVGA_FB_LEGACY_START_BIGMEM    0xE0000000
+ * SVGA_CMD_ANNOTATION_COPY --
+ *
+ *    This is a blit annotation. See SVGA_CMD_ANNOTATION_FILL for more
+ *    information about annotations.
+ *
+ *    This annotation is a promise about the contents of the next
+ *    blit: The video driver is guaranteeing that all pixels in that
+ *    blit will have the same value as those which already exist at an
+ *    identically-sized region on the same or a different screen.
+ *
+ *    Note that the source pixels for the COPY in this annotation are
+ *    sampled before applying the anqnotation's associated blit. They
+ *    are allowed to overlap with the blit's destination pixels.
+ *
+ *    The copy source rectangle is specified the same way as the blit
+ *    destination: it can be a rectangle which spans zero or more
+ *    screens, specified relative to either a screen or to the virtual
+ *    coordinate system's origin. If the source rectangle includes
+ *    pixels which are not from exactly one screen, the results are
+ *    undefined.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ */
+
+typedef
+struct {
+   SVGASignedPoint  srcOrigin;
+   uint32           srcScreenId;
+} SVGAFifoCmdAnnotationCopy;
 
 #endif
diff --git a/vmwgfx/Makefile.am b/vmwgfx/Makefile.am
new file mode 100644 (file)
index 0000000..5efa8cd
--- /dev/null
@@ -0,0 +1,24 @@
+vmwgfx_drv_la_LTLIBRARIES = vmwgfx_drv.la
+vmwgfx_drv_la_LDFLAGS = -module -avoid-version
+vmwgfx_drv_la_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS) @LIBDRM_CFLAGS@ -I$(top_srcdir)/src -I$(top_srcdir)/saa
+vmwgfx_drv_la_LIBADD = @LIBDRM_LIBS@ $(top_srcdir)/saa/.libs/libsaa.la -lxatracker
+vmwgfx_drv_ladir = @moduledir@/drivers
+
+vmwgfx_drv_la_SOURCES = \
+       vmwgfx_driver.c \
+       vmwgfx_driver.h \
+       vmwgfx_crtc.c \
+       vmwgfx_output.c \
+       vmwgfx_dri2.c \
+       vmwgfx_tex_video.c \
+       vmwgfx_saa.c \
+       vmwgfx_saa.h \
+       vmwgfx_drmi.c \
+       vmwgfx_drmi.h \
+       vmwgfx_bootstrap.c \
+       vmwgfx_overlay.c \
+       vmwgfx_ctrl.c \
+       vmwgfx_ctrl.h
+
+
+
diff --git a/vmwgfx/svga3d_reg.h b/vmwgfx/svga3d_reg.h
new file mode 100644 (file)
index 0000000..a527d7d
--- /dev/null
@@ -0,0 +1,1801 @@
+/**********************************************************
+ * Copyright 1998-2009 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/*
+ * svga3d_reg.h --
+ *
+ *       SVGA 3D hardware definitions
+ */
+
+#ifndef _SVGA3D_REG_H_
+#define _SVGA3D_REG_H_
+
+#include "svga_reg.h"
+
+
+/*
+ * 3D Hardware Version
+ *
+ *   The hardware version is stored in the SVGA_FIFO_3D_HWVERSION fifo
+ *   register.   Is set by the host and read by the guest.  This lets
+ *   us make new guest drivers which are backwards-compatible with old
+ *   SVGA hardware revisions.  It does not let us support old guest
+ *   drivers.  Good enough for now.
+ *
+ */
+
+#define SVGA3D_MAKE_HWVERSION(major, minor)      (((major) << 16) | ((minor) & 0xFF))
+#define SVGA3D_MAJOR_HWVERSION(version)          ((version) >> 16)
+#define SVGA3D_MINOR_HWVERSION(version)          ((version) & 0xFF)
+
+typedef enum {
+   SVGA3D_HWVERSION_WS5_RC1   = SVGA3D_MAKE_HWVERSION(0, 1),
+   SVGA3D_HWVERSION_WS5_RC2   = SVGA3D_MAKE_HWVERSION(0, 2),
+   SVGA3D_HWVERSION_WS51_RC1  = SVGA3D_MAKE_HWVERSION(0, 3),
+   SVGA3D_HWVERSION_WS6_B1    = SVGA3D_MAKE_HWVERSION(1, 1),
+   SVGA3D_HWVERSION_FUSION_11 = SVGA3D_MAKE_HWVERSION(1, 4),
+   SVGA3D_HWVERSION_WS65_B1   = SVGA3D_MAKE_HWVERSION(2, 0),
+   SVGA3D_HWVERSION_CURRENT   = SVGA3D_HWVERSION_WS65_B1,
+} SVGA3dHardwareVersion;
+
+/*
+ * Generic Types
+ */
+
+typedef uint32 SVGA3dBool; /* 32-bit Bool definition */
+#define SVGA3D_NUM_CLIPPLANES                   6
+#define SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS  8
+
+
+/*
+ * Surface formats.
+ *
+ * If you modify this list, be sure to keep GLUtil.c in sync. It
+ * includes the internal format definition of each surface in
+ * GLUtil_ConvertSurfaceFormat, and it contains a table of
+ * human-readable names in GLUtil_GetFormatName.
+ */
+
+typedef enum SVGA3dSurfaceFormat {
+   SVGA3D_FORMAT_INVALID = 0,
+
+   SVGA3D_X8R8G8B8       = 1,
+   SVGA3D_A8R8G8B8       = 2,
+
+   SVGA3D_R5G6B5         = 3,
+   SVGA3D_X1R5G5B5       = 4,
+   SVGA3D_A1R5G5B5       = 5,
+   SVGA3D_A4R4G4B4       = 6,
+
+   SVGA3D_Z_D32          = 7,
+   SVGA3D_Z_D16          = 8,
+   SVGA3D_Z_D24S8        = 9,
+   SVGA3D_Z_D15S1        = 10,
+
+   SVGA3D_LUMINANCE8            = 11,
+   SVGA3D_LUMINANCE4_ALPHA4     = 12,
+   SVGA3D_LUMINANCE16           = 13,
+   SVGA3D_LUMINANCE8_ALPHA8     = 14,
+
+   SVGA3D_DXT1           = 15,
+   SVGA3D_DXT2           = 16,
+   SVGA3D_DXT3           = 17,
+   SVGA3D_DXT4           = 18,
+   SVGA3D_DXT5           = 19,
+
+   SVGA3D_BUMPU8V8       = 20,
+   SVGA3D_BUMPL6V5U5     = 21,
+   SVGA3D_BUMPX8L8V8U8   = 22,
+   SVGA3D_BUMPL8V8U8     = 23,
+
+   SVGA3D_ARGB_S10E5     = 24,   /* 16-bit floating-point ARGB */
+   SVGA3D_ARGB_S23E8     = 25,   /* 32-bit floating-point ARGB */
+
+   SVGA3D_A2R10G10B10    = 26,
+
+   /* signed formats */
+   SVGA3D_V8U8           = 27,
+   SVGA3D_Q8W8V8U8       = 28,
+   SVGA3D_CxV8U8         = 29,
+
+   /* mixed formats */
+   SVGA3D_X8L8V8U8       = 30,
+   SVGA3D_A2W10V10U10    = 31,
+
+   SVGA3D_ALPHA8         = 32,
+
+   /* Single- and dual-component floating point formats */
+   SVGA3D_R_S10E5        = 33,
+   SVGA3D_R_S23E8        = 34,
+   SVGA3D_RG_S10E5       = 35,
+   SVGA3D_RG_S23E8       = 36,
+
+   /*
+    * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
+    * the most efficient format to use when creating new surfaces
+    * expressly for index or vertex data.
+    */
+   SVGA3D_BUFFER         = 37,
+
+   SVGA3D_Z_D24X8        = 38,
+
+   SVGA3D_V16U16         = 39,
+
+   SVGA3D_G16R16         = 40,
+   SVGA3D_A16B16G16R16   = 41,
+
+   /* Packed Video formats */
+   SVGA3D_UYVY           = 42,
+   SVGA3D_YUY2           = 43,
+
+   SVGA3D_FORMAT_MAX
+} SVGA3dSurfaceFormat;
+
+typedef uint32 SVGA3dColor; /* a, r, g, b */
+
+/*
+ * These match the D3DFORMAT_OP definitions used by Direct3D. We need
+ * them so that we can query the host for what the supported surface
+ * operations are (when we're using the D3D backend, in particular),
+ * and so we can send those operations to the guest.
+ */
+typedef enum {
+   SVGA3DFORMAT_OP_TEXTURE                               = 0x00000001,
+   SVGA3DFORMAT_OP_VOLUMETEXTURE                         = 0x00000002,
+   SVGA3DFORMAT_OP_CUBETEXTURE                           = 0x00000004,
+   SVGA3DFORMAT_OP_OFFSCREEN_RENDERTARGET                = 0x00000008,
+   SVGA3DFORMAT_OP_SAME_FORMAT_RENDERTARGET              = 0x00000010,
+   SVGA3DFORMAT_OP_ZSTENCIL                              = 0x00000040,
+   SVGA3DFORMAT_OP_ZSTENCIL_WITH_ARBITRARY_COLOR_DEPTH   = 0x00000080,
+
+/*
+ * This format can be used as a render target if the current display mode
+ * is the same depth if the alpha channel is ignored. e.g. if the device
+ * can render to A8R8G8B8 when the display mode is X8R8G8B8, then the
+ * format op list entry for A8R8G8B8 should have this cap.
+ */
+   SVGA3DFORMAT_OP_SAME_FORMAT_UP_TO_ALPHA_RENDERTARGET  = 0x00000100,
+
+/*
+ * This format contains DirectDraw support (including Flip).  This flag
+ * should not to be set on alpha formats.
+ */
+   SVGA3DFORMAT_OP_DISPLAYMODE                           = 0x00000400,
+
+/*
+ * The rasterizer can support some level of Direct3D support in this format
+ * and implies that the driver can create a Context in this mode (for some
+ * render target format).  When this flag is set, the SVGA3DFORMAT_OP_DISPLAYMODE
+ * flag must also be set.
+ */
+   SVGA3DFORMAT_OP_3DACCELERATION                        = 0x00000800,
+
+/*
+ * This is set for a private format when the driver has put the bpp in
+ * the structure.
+ */
+   SVGA3DFORMAT_OP_PIXELSIZE                             = 0x00001000,
+
+/*
+ * Indicates that this format can be converted to any RGB format for which
+ * SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB is specified
+ */
+   SVGA3DFORMAT_OP_CONVERT_TO_ARGB                       = 0x00002000,
+
+/*
+ * Indicates that this format can be used to create offscreen plain surfaces.
+ */
+   SVGA3DFORMAT_OP_OFFSCREENPLAIN                        = 0x00004000,
+
+/*
+ * Indicated that this format can be read as an SRGB texture (meaning that the
+ * sampler will linearize the looked up data)
+ */
+   SVGA3DFORMAT_OP_SRGBREAD                              = 0x00008000,
+
+/*
+ * Indicates that this format can be used in the bumpmap instructions
+ */
+   SVGA3DFORMAT_OP_BUMPMAP                               = 0x00010000,
+
+/*
+ * Indicates that this format can be sampled by the displacement map sampler
+ */
+   SVGA3DFORMAT_OP_DMAP                                  = 0x00020000,
+
+/*
+ * Indicates that this format cannot be used with texture filtering
+ */
+   SVGA3DFORMAT_OP_NOFILTER                              = 0x00040000,
+
+/*
+ * Indicates that format conversions are supported to this RGB format if
+ * SVGA3DFORMAT_OP_CONVERT_TO_ARGB is specified in the source format.
+ */
+   SVGA3DFORMAT_OP_MEMBEROFGROUP_ARGB                    = 0x00080000,
+
+/*
+ * Indicated that this format can be written as an SRGB target (meaning that the
+ * pixel pipe will DE-linearize data on output to format)
+ */
+   SVGA3DFORMAT_OP_SRGBWRITE                             = 0x00100000,
+
+/*
+ * Indicates that this format cannot be used with alpha blending
+ */
+   SVGA3DFORMAT_OP_NOALPHABLEND                          = 0x00200000,
+
+/*
+ * Indicates that the device can auto-generated sublevels for resources
+ * of this format
+ */
+   SVGA3DFORMAT_OP_AUTOGENMIPMAP                         = 0x00400000,
+
+/*
+ * Indicates that this format can be used by vertex texture sampler
+ */
+   SVGA3DFORMAT_OP_VERTEXTEXTURE                         = 0x00800000,
+
+/*
+ * Indicates that this format supports neither texture coordinate wrap
+ * modes, nor mipmapping
+ */
+   SVGA3DFORMAT_OP_NOTEXCOORDWRAPNORMIP                  = 0x01000000
+} SVGA3dFormatOp;
+
+/*
+ * This structure is a conversion of SVGA3DFORMAT_OP_*.
+ * Entries must be located at the same position.
+ */
+typedef union {
+   uint32 value;
+   struct {
+      uint32 texture : 1;
+      uint32 volumeTexture : 1;
+      uint32 cubeTexture : 1;
+      uint32 offscreenRenderTarget : 1;
+      uint32 sameFormatRenderTarget : 1;
+      uint32 unknown1 : 1;
+      uint32 zStencil : 1;
+      uint32 zStencilArbitraryDepth : 1;
+      uint32 sameFormatUpToAlpha : 1;
+      uint32 unknown2 : 1;
+      uint32 displayMode : 1;
+      uint32 acceleration3d : 1;
+      uint32 pixelSize : 1;
+      uint32 convertToARGB : 1;
+      uint32 offscreenPlain : 1;
+      uint32 sRGBRead : 1;
+      uint32 bumpMap : 1;
+      uint32 dmap : 1;
+      uint32 noFilter : 1;
+      uint32 memberOfGroupARGB : 1;
+      uint32 sRGBWrite : 1;
+      uint32 noAlphaBlend : 1;
+      uint32 autoGenMipMap : 1;
+      uint32 vertexTexture : 1;
+      uint32 noTexCoordWrapNorMip : 1;
+   };
+} SVGA3dSurfaceFormatCaps;
+
+/*
+ * SVGA_3D_CMD_SETRENDERSTATE Types.  All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+   SVGA3D_RS_INVALID                   = 0,
+   SVGA3D_RS_ZENABLE                   = 1,     /* SVGA3dBool */
+   SVGA3D_RS_ZWRITEENABLE              = 2,     /* SVGA3dBool */
+   SVGA3D_RS_ALPHATESTENABLE           = 3,     /* SVGA3dBool */
+   SVGA3D_RS_DITHERENABLE              = 4,     /* SVGA3dBool */
+   SVGA3D_RS_BLENDENABLE               = 5,     /* SVGA3dBool */
+   SVGA3D_RS_FOGENABLE                 = 6,     /* SVGA3dBool */
+   SVGA3D_RS_SPECULARENABLE            = 7,     /* SVGA3dBool */
+   SVGA3D_RS_STENCILENABLE             = 8,     /* SVGA3dBool */
+   SVGA3D_RS_LIGHTINGENABLE            = 9,     /* SVGA3dBool */
+   SVGA3D_RS_NORMALIZENORMALS          = 10,    /* SVGA3dBool */
+   SVGA3D_RS_POINTSPRITEENABLE         = 11,    /* SVGA3dBool */
+   SVGA3D_RS_POINTSCALEENABLE          = 12,    /* SVGA3dBool */
+   SVGA3D_RS_STENCILREF                = 13,    /* uint32 */
+   SVGA3D_RS_STENCILMASK               = 14,    /* uint32 */
+   SVGA3D_RS_STENCILWRITEMASK          = 15,    /* uint32 */
+   SVGA3D_RS_FOGSTART                  = 16,    /* float */
+   SVGA3D_RS_FOGEND                    = 17,    /* float */
+   SVGA3D_RS_FOGDENSITY                = 18,    /* float */
+   SVGA3D_RS_POINTSIZE                 = 19,    /* float */
+   SVGA3D_RS_POINTSIZEMIN              = 20,    /* float */
+   SVGA3D_RS_POINTSIZEMAX              = 21,    /* float */
+   SVGA3D_RS_POINTSCALE_A              = 22,    /* float */
+   SVGA3D_RS_POINTSCALE_B              = 23,    /* float */
+   SVGA3D_RS_POINTSCALE_C              = 24,    /* float */
+   SVGA3D_RS_FOGCOLOR                  = 25,    /* SVGA3dColor */
+   SVGA3D_RS_AMBIENT                   = 26,    /* SVGA3dColor */
+   SVGA3D_RS_CLIPPLANEENABLE           = 27,    /* SVGA3dClipPlanes */
+   SVGA3D_RS_FOGMODE                   = 28,    /* SVGA3dFogMode */
+   SVGA3D_RS_FILLMODE                  = 29,    /* SVGA3dFillMode */
+   SVGA3D_RS_SHADEMODE                 = 30,    /* SVGA3dShadeMode */
+   SVGA3D_RS_LINEPATTERN               = 31,    /* SVGA3dLinePattern */
+   SVGA3D_RS_SRCBLEND                  = 32,    /* SVGA3dBlendOp */
+   SVGA3D_RS_DSTBLEND                  = 33,    /* SVGA3dBlendOp */
+   SVGA3D_RS_BLENDEQUATION             = 34,    /* SVGA3dBlendEquation */
+   SVGA3D_RS_CULLMODE                  = 35,    /* SVGA3dFace */
+   SVGA3D_RS_ZFUNC                     = 36,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_ALPHAFUNC                 = 37,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_STENCILFUNC               = 38,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_STENCILFAIL               = 39,    /* SVGA3dStencilOp */
+   SVGA3D_RS_STENCILZFAIL              = 40,    /* SVGA3dStencilOp */
+   SVGA3D_RS_STENCILPASS               = 41,    /* SVGA3dStencilOp */
+   SVGA3D_RS_ALPHAREF                  = 42,    /* float (0.0 .. 1.0) */
+   SVGA3D_RS_FRONTWINDING              = 43,    /* SVGA3dFrontWinding */
+   SVGA3D_RS_COORDINATETYPE            = 44,    /* SVGA3dCoordinateType */
+   SVGA3D_RS_ZBIAS                     = 45,    /* float */
+   SVGA3D_RS_RANGEFOGENABLE            = 46,    /* SVGA3dBool */
+   SVGA3D_RS_COLORWRITEENABLE          = 47,    /* SVGA3dColorMask */
+   SVGA3D_RS_VERTEXMATERIALENABLE      = 48,    /* SVGA3dBool */
+   SVGA3D_RS_DIFFUSEMATERIALSOURCE     = 49,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_SPECULARMATERIALSOURCE    = 50,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_AMBIENTMATERIALSOURCE     = 51,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_EMISSIVEMATERIALSOURCE    = 52,    /* SVGA3dVertexMaterial */
+   SVGA3D_RS_TEXTUREFACTOR             = 53,    /* SVGA3dColor */
+   SVGA3D_RS_LOCALVIEWER               = 54,    /* SVGA3dBool */
+   SVGA3D_RS_SCISSORTESTENABLE         = 55,    /* SVGA3dBool */
+   SVGA3D_RS_BLENDCOLOR                = 56,    /* SVGA3dColor */
+   SVGA3D_RS_STENCILENABLE2SIDED       = 57,    /* SVGA3dBool */
+   SVGA3D_RS_CCWSTENCILFUNC            = 58,    /* SVGA3dCmpFunc */
+   SVGA3D_RS_CCWSTENCILFAIL            = 59,    /* SVGA3dStencilOp */
+   SVGA3D_RS_CCWSTENCILZFAIL           = 60,    /* SVGA3dStencilOp */
+   SVGA3D_RS_CCWSTENCILPASS            = 61,    /* SVGA3dStencilOp */
+   SVGA3D_RS_VERTEXBLEND               = 62,    /* SVGA3dVertexBlendFlags */
+   SVGA3D_RS_SLOPESCALEDEPTHBIAS       = 63,    /* float */
+   SVGA3D_RS_DEPTHBIAS                 = 64,    /* float */
+
+
+   /*
+    * Output Gamma Level
+    *
+    * Output gamma effects the gamma curve of colors that are output from the
+    * rendering pipeline.  A value of 1.0 specifies a linear color space. If the
+    * value is <= 0.0, gamma correction is ignored and linear color space is
+    * used.
+    */
+
+   SVGA3D_RS_OUTPUTGAMMA               = 65,    /* float */
+   SVGA3D_RS_ZVISIBLE                  = 66,    /* SVGA3dBool */
+   SVGA3D_RS_LASTPIXEL                 = 67,    /* SVGA3dBool */
+   SVGA3D_RS_CLIPPING                  = 68,    /* SVGA3dBool */
+   SVGA3D_RS_WRAP0                     = 69,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP1                     = 70,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP2                     = 71,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP3                     = 72,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP4                     = 73,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP5                     = 74,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP6                     = 75,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP7                     = 76,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP8                     = 77,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP9                     = 78,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP10                    = 79,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP11                    = 80,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP12                    = 81,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP13                    = 82,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP14                    = 83,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_WRAP15                    = 84,    /* SVGA3dWrapFlags */
+   SVGA3D_RS_MULTISAMPLEANTIALIAS      = 85,    /* SVGA3dBool */
+   SVGA3D_RS_MULTISAMPLEMASK           = 86,    /* uint32 */
+   SVGA3D_RS_INDEXEDVERTEXBLENDENABLE  = 87,    /* SVGA3dBool */
+   SVGA3D_RS_TWEENFACTOR               = 88,    /* float */
+   SVGA3D_RS_ANTIALIASEDLINEENABLE     = 89,    /* SVGA3dBool */
+   SVGA3D_RS_COLORWRITEENABLE1         = 90,    /* SVGA3dColorMask */
+   SVGA3D_RS_COLORWRITEENABLE2         = 91,    /* SVGA3dColorMask */
+   SVGA3D_RS_COLORWRITEENABLE3         = 92,    /* SVGA3dColorMask */
+   SVGA3D_RS_SEPARATEALPHABLENDENABLE  = 93,    /* SVGA3dBool */
+   SVGA3D_RS_SRCBLENDALPHA             = 94,    /* SVGA3dBlendOp */
+   SVGA3D_RS_DSTBLENDALPHA             = 95,    /* SVGA3dBlendOp */
+   SVGA3D_RS_BLENDEQUATIONALPHA        = 96,    /* SVGA3dBlendEquation */
+   SVGA3D_RS_MAX
+} SVGA3dRenderStateName;
+
+typedef enum {
+   SVGA3D_VERTEXMATERIAL_NONE     = 0,    /* Use the value in the current material */
+   SVGA3D_VERTEXMATERIAL_DIFFUSE  = 1,    /* Use the value in the diffuse component */
+   SVGA3D_VERTEXMATERIAL_SPECULAR = 2,    /* Use the value in the specular component */
+} SVGA3dVertexMaterial;
+
+typedef enum {
+   SVGA3D_FILLMODE_INVALID = 0,
+   SVGA3D_FILLMODE_POINT   = 1,
+   SVGA3D_FILLMODE_LINE    = 2,
+   SVGA3D_FILLMODE_FILL    = 3,
+   SVGA3D_FILLMODE_MAX
+} SVGA3dFillModeType;
+
+
+typedef
+union {
+   struct {
+      uint16   mode;       /* SVGA3dFillModeType */
+      uint16   face;       /* SVGA3dFace */
+   };
+   uint32 uintValue;
+} SVGA3dFillMode;
+
+typedef enum {
+   SVGA3D_SHADEMODE_INVALID = 0,
+   SVGA3D_SHADEMODE_FLAT    = 1,
+   SVGA3D_SHADEMODE_SMOOTH  = 2,
+   SVGA3D_SHADEMODE_PHONG   = 3,     /* Not supported */
+   SVGA3D_SHADEMODE_MAX
+} SVGA3dShadeMode;
+
+typedef
+union {
+   struct {
+      uint16 repeat;
+      uint16 pattern;
+   };
+   uint32 uintValue;
+} SVGA3dLinePattern;
+
+typedef enum {
+   SVGA3D_BLENDOP_INVALID            = 0,
+   SVGA3D_BLENDOP_ZERO               = 1,
+   SVGA3D_BLENDOP_ONE                = 2,
+   SVGA3D_BLENDOP_SRCCOLOR           = 3,
+   SVGA3D_BLENDOP_INVSRCCOLOR        = 4,
+   SVGA3D_BLENDOP_SRCALPHA           = 5,
+   SVGA3D_BLENDOP_INVSRCALPHA        = 6,
+   SVGA3D_BLENDOP_DESTALPHA          = 7,
+   SVGA3D_BLENDOP_INVDESTALPHA       = 8,
+   SVGA3D_BLENDOP_DESTCOLOR          = 9,
+   SVGA3D_BLENDOP_INVDESTCOLOR       = 10,
+   SVGA3D_BLENDOP_SRCALPHASAT        = 11,
+   SVGA3D_BLENDOP_BLENDFACTOR        = 12,
+   SVGA3D_BLENDOP_INVBLENDFACTOR     = 13,
+   SVGA3D_BLENDOP_MAX
+} SVGA3dBlendOp;
+
+typedef enum {
+   SVGA3D_BLENDEQ_INVALID            = 0,
+   SVGA3D_BLENDEQ_ADD                = 1,
+   SVGA3D_BLENDEQ_SUBTRACT           = 2,
+   SVGA3D_BLENDEQ_REVSUBTRACT        = 3,
+   SVGA3D_BLENDEQ_MINIMUM            = 4,
+   SVGA3D_BLENDEQ_MAXIMUM            = 5,
+   SVGA3D_BLENDEQ_MAX
+} SVGA3dBlendEquation;
+
+typedef enum {
+   SVGA3D_FRONTWINDING_INVALID = 0,
+   SVGA3D_FRONTWINDING_CW      = 1,
+   SVGA3D_FRONTWINDING_CCW     = 2,
+   SVGA3D_FRONTWINDING_MAX
+} SVGA3dFrontWinding;
+
+typedef enum {
+   SVGA3D_FACE_INVALID  = 0,
+   SVGA3D_FACE_NONE     = 1,
+   SVGA3D_FACE_FRONT    = 2,
+   SVGA3D_FACE_BACK     = 3,
+   SVGA3D_FACE_FRONT_BACK = 4,
+   SVGA3D_FACE_MAX
+} SVGA3dFace;
+
+/*
+ * The order and the values should not be changed
+ */
+
+typedef enum {
+   SVGA3D_CMP_INVALID              = 0,
+   SVGA3D_CMP_NEVER                = 1,
+   SVGA3D_CMP_LESS                 = 2,
+   SVGA3D_CMP_EQUAL                = 3,
+   SVGA3D_CMP_LESSEQUAL            = 4,
+   SVGA3D_CMP_GREATER              = 5,
+   SVGA3D_CMP_NOTEQUAL             = 6,
+   SVGA3D_CMP_GREATEREQUAL         = 7,
+   SVGA3D_CMP_ALWAYS               = 8,
+   SVGA3D_CMP_MAX
+} SVGA3dCmpFunc;
+
+/*
+ * SVGA3D_FOGFUNC_* specifies the fog equation, or PER_VERTEX which allows
+ * the fog factor to be specified in the alpha component of the specular
+ * (a.k.a. secondary) vertex color.
+ */
+typedef enum {
+   SVGA3D_FOGFUNC_INVALID          = 0,
+   SVGA3D_FOGFUNC_EXP              = 1,
+   SVGA3D_FOGFUNC_EXP2             = 2,
+   SVGA3D_FOGFUNC_LINEAR           = 3,
+   SVGA3D_FOGFUNC_PER_VERTEX       = 4
+} SVGA3dFogFunction;
+
+/*
+ * SVGA3D_FOGTYPE_* specifies if fog factors are computed on a per-vertex
+ * or per-pixel basis.
+ */
+typedef enum {
+   SVGA3D_FOGTYPE_INVALID          = 0,
+   SVGA3D_FOGTYPE_VERTEX           = 1,
+   SVGA3D_FOGTYPE_PIXEL            = 2,
+   SVGA3D_FOGTYPE_MAX              = 3
+} SVGA3dFogType;
+
+/*
+ * SVGA3D_FOGBASE_* selects depth or range-based fog. Depth-based fog is
+ * computed using the eye Z value of each pixel (or vertex), whereas range-
+ * based fog is computed using the actual distance (range) to the eye.
+ */
+typedef enum {
+   SVGA3D_FOGBASE_INVALID          = 0,
+   SVGA3D_FOGBASE_DEPTHBASED       = 1,
+   SVGA3D_FOGBASE_RANGEBASED       = 2,
+   SVGA3D_FOGBASE_MAX              = 3
+} SVGA3dFogBase;
+
+typedef enum {
+   SVGA3D_STENCILOP_INVALID        = 0,
+   SVGA3D_STENCILOP_KEEP           = 1,
+   SVGA3D_STENCILOP_ZERO           = 2,
+   SVGA3D_STENCILOP_REPLACE        = 3,
+   SVGA3D_STENCILOP_INCRSAT        = 4,
+   SVGA3D_STENCILOP_DECRSAT        = 5,
+   SVGA3D_STENCILOP_INVERT         = 6,
+   SVGA3D_STENCILOP_INCR           = 7,
+   SVGA3D_STENCILOP_DECR           = 8,
+   SVGA3D_STENCILOP_MAX
+} SVGA3dStencilOp;
+
+typedef enum {
+   SVGA3D_CLIPPLANE_0              = (1 << 0),
+   SVGA3D_CLIPPLANE_1              = (1 << 1),
+   SVGA3D_CLIPPLANE_2              = (1 << 2),
+   SVGA3D_CLIPPLANE_3              = (1 << 3),
+   SVGA3D_CLIPPLANE_4              = (1 << 4),
+   SVGA3D_CLIPPLANE_5              = (1 << 5),
+} SVGA3dClipPlanes;
+
+typedef enum {
+   SVGA3D_CLEAR_COLOR              = 0x1,
+   SVGA3D_CLEAR_DEPTH              = 0x2,
+   SVGA3D_CLEAR_STENCIL            = 0x4
+} SVGA3dClearFlag;
+
+typedef enum {
+   SVGA3D_RT_DEPTH                 = 0,
+   SVGA3D_RT_STENCIL               = 1,
+   SVGA3D_RT_COLOR0                = 2,
+   SVGA3D_RT_COLOR1                = 3,
+   SVGA3D_RT_COLOR2                = 4,
+   SVGA3D_RT_COLOR3                = 5,
+   SVGA3D_RT_COLOR4                = 6,
+   SVGA3D_RT_COLOR5                = 7,
+   SVGA3D_RT_COLOR6                = 8,
+   SVGA3D_RT_COLOR7                = 9,
+   SVGA3D_RT_MAX,
+   SVGA3D_RT_INVALID               = ((uint32)-1),
+} SVGA3dRenderTargetType;
+
+#define SVGA3D_MAX_RT_COLOR (SVGA3D_RT_COLOR7 - SVGA3D_RT_COLOR0 + 1)
+
+typedef
+union {
+   struct {
+      uint32  red   : 1;
+      uint32  green : 1;
+      uint32  blue  : 1;
+      uint32  alpha : 1;
+   };
+   uint32 uintValue;
+} SVGA3dColorMask;
+
+typedef enum {
+   SVGA3D_VBLEND_DISABLE            = 0,
+   SVGA3D_VBLEND_1WEIGHT            = 1,
+   SVGA3D_VBLEND_2WEIGHT            = 2,
+   SVGA3D_VBLEND_3WEIGHT            = 3,
+} SVGA3dVertexBlendFlags;
+
+typedef enum {
+   SVGA3D_WRAPCOORD_0   = 1 << 0,
+   SVGA3D_WRAPCOORD_1   = 1 << 1,
+   SVGA3D_WRAPCOORD_2   = 1 << 2,
+   SVGA3D_WRAPCOORD_3   = 1 << 3,
+   SVGA3D_WRAPCOORD_ALL = 0xF,
+} SVGA3dWrapFlags;
+
+/*
+ * SVGA_3D_CMD_TEXTURESTATE Types.  All value types
+ * must fit in a uint32.
+ */
+
+typedef enum {
+   SVGA3D_TS_INVALID                    = 0,
+   SVGA3D_TS_BIND_TEXTURE               = 1,    /* SVGA3dSurfaceId */
+   SVGA3D_TS_COLOROP                    = 2,    /* SVGA3dTextureCombiner */
+   SVGA3D_TS_COLORARG1                  = 3,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_COLORARG2                  = 4,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAOP                    = 5,    /* SVGA3dTextureCombiner */
+   SVGA3D_TS_ALPHAARG1                  = 6,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAARG2                  = 7,    /* SVGA3dTextureArgData */
+   SVGA3D_TS_ADDRESSU                   = 8,    /* SVGA3dTextureAddress */
+   SVGA3D_TS_ADDRESSV                   = 9,    /* SVGA3dTextureAddress */
+   SVGA3D_TS_MIPFILTER                  = 10,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_MAGFILTER                  = 11,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_MINFILTER                  = 12,   /* SVGA3dTextureFilter */
+   SVGA3D_TS_BORDERCOLOR                = 13,   /* SVGA3dColor */
+   SVGA3D_TS_TEXCOORDINDEX              = 14,   /* uint32 */
+   SVGA3D_TS_TEXTURETRANSFORMFLAGS      = 15,   /* SVGA3dTexTransformFlags */
+   SVGA3D_TS_TEXCOORDGEN                = 16,   /* SVGA3dTextureCoordGen */
+   SVGA3D_TS_BUMPENVMAT00               = 17,   /* float */
+   SVGA3D_TS_BUMPENVMAT01               = 18,   /* float */
+   SVGA3D_TS_BUMPENVMAT10               = 19,   /* float */
+   SVGA3D_TS_BUMPENVMAT11               = 20,   /* float */
+   SVGA3D_TS_TEXTURE_MIPMAP_LEVEL       = 21,   /* uint32 */
+   SVGA3D_TS_TEXTURE_LOD_BIAS           = 22,   /* float */
+   SVGA3D_TS_TEXTURE_ANISOTROPIC_LEVEL  = 23,   /* uint32 */
+   SVGA3D_TS_ADDRESSW                   = 24,   /* SVGA3dTextureAddress */
+
+
+   /*
+    * Sampler Gamma Level
+    *
+    * Sampler gamma effects the color of samples taken from the sampler.  A
+    * value of 1.0 will produce linear samples.  If the value is <= 0.0 the
+    * gamma value is ignored and a linear space is used.
+    */
+
+   SVGA3D_TS_GAMMA                      = 25,   /* float */
+   SVGA3D_TS_BUMPENVLSCALE              = 26,   /* float */
+   SVGA3D_TS_BUMPENVLOFFSET             = 27,   /* float */
+   SVGA3D_TS_COLORARG0                  = 28,   /* SVGA3dTextureArgData */
+   SVGA3D_TS_ALPHAARG0                  = 29,   /* SVGA3dTextureArgData */
+   SVGA3D_TS_MAX
+} SVGA3dTextureStateName;
+
+typedef enum {
+   SVGA3D_TC_INVALID                   = 0,
+   SVGA3D_TC_DISABLE                   = 1,
+   SVGA3D_TC_SELECTARG1                = 2,
+   SVGA3D_TC_SELECTARG2                = 3,
+   SVGA3D_TC_MODULATE                  = 4,
+   SVGA3D_TC_ADD                       = 5,
+   SVGA3D_TC_ADDSIGNED                 = 6,
+   SVGA3D_TC_SUBTRACT                  = 7,
+   SVGA3D_TC_BLENDTEXTUREALPHA         = 8,
+   SVGA3D_TC_BLENDDIFFUSEALPHA         = 9,
+   SVGA3D_TC_BLENDCURRENTALPHA         = 10,
+   SVGA3D_TC_BLENDFACTORALPHA          = 11,
+   SVGA3D_TC_MODULATE2X                = 12,
+   SVGA3D_TC_MODULATE4X                = 13,
+   SVGA3D_TC_DSDT                      = 14,
+   SVGA3D_TC_DOTPRODUCT3               = 15,
+   SVGA3D_TC_BLENDTEXTUREALPHAPM       = 16,
+   SVGA3D_TC_ADDSIGNED2X               = 17,
+   SVGA3D_TC_ADDSMOOTH                 = 18,
+   SVGA3D_TC_PREMODULATE               = 19,
+   SVGA3D_TC_MODULATEALPHA_ADDCOLOR    = 20,
+   SVGA3D_TC_MODULATECOLOR_ADDALPHA    = 21,
+   SVGA3D_TC_MODULATEINVALPHA_ADDCOLOR = 22,
+   SVGA3D_TC_MODULATEINVCOLOR_ADDALPHA = 23,
+   SVGA3D_TC_BUMPENVMAPLUMINANCE       = 24,
+   SVGA3D_TC_MULTIPLYADD               = 25,
+   SVGA3D_TC_LERP                      = 26,
+   SVGA3D_TC_MAX
+} SVGA3dTextureCombiner;
+
+#define SVGA3D_TC_CAP_BIT(svga3d_tc_op) (svga3d_tc_op ? (1 << (svga3d_tc_op - 1)) : 0)
+
+typedef enum {
+   SVGA3D_TEX_ADDRESS_INVALID    = 0,
+   SVGA3D_TEX_ADDRESS_WRAP       = 1,
+   SVGA3D_TEX_ADDRESS_MIRROR     = 2,
+   SVGA3D_TEX_ADDRESS_CLAMP      = 3,
+   SVGA3D_TEX_ADDRESS_BORDER     = 4,
+   SVGA3D_TEX_ADDRESS_MIRRORONCE = 5,
+   SVGA3D_TEX_ADDRESS_EDGE       = 6,
+   SVGA3D_TEX_ADDRESS_MAX
+} SVGA3dTextureAddress;
+
+/*
+ * SVGA3D_TEX_FILTER_NONE as the minification filter means mipmapping is
+ * disabled, and the rasterizer should use the magnification filter instead.
+ */
+typedef enum {
+   SVGA3D_TEX_FILTER_NONE           = 0,
+   SVGA3D_TEX_FILTER_NEAREST        = 1,
+   SVGA3D_TEX_FILTER_LINEAR         = 2,
+   SVGA3D_TEX_FILTER_ANISOTROPIC    = 3,
+   SVGA3D_TEX_FILTER_FLATCUBIC      = 4, // Deprecated, not implemented
+   SVGA3D_TEX_FILTER_GAUSSIANCUBIC  = 5, // Deprecated, not implemented
+   SVGA3D_TEX_FILTER_PYRAMIDALQUAD  = 6, // Not currently implemented
+   SVGA3D_TEX_FILTER_GAUSSIANQUAD   = 7, // Not currently implemented
+   SVGA3D_TEX_FILTER_MAX
+} SVGA3dTextureFilter;
+
+typedef enum {
+   SVGA3D_TEX_TRANSFORM_OFF    = 0,
+   SVGA3D_TEX_TRANSFORM_S      = (1 << 0),
+   SVGA3D_TEX_TRANSFORM_T      = (1 << 1),
+   SVGA3D_TEX_TRANSFORM_R      = (1 << 2),
+   SVGA3D_TEX_TRANSFORM_Q      = (1 << 3),
+   SVGA3D_TEX_PROJECTED        = (1 << 15),
+} SVGA3dTexTransformFlags;
+
+typedef enum {
+   SVGA3D_TEXCOORD_GEN_OFF              = 0,
+   SVGA3D_TEXCOORD_GEN_EYE_POSITION     = 1,
+   SVGA3D_TEXCOORD_GEN_EYE_NORMAL       = 2,
+   SVGA3D_TEXCOORD_GEN_REFLECTIONVECTOR = 3,
+   SVGA3D_TEXCOORD_GEN_SPHERE           = 4,
+   SVGA3D_TEXCOORD_GEN_MAX
+} SVGA3dTextureCoordGen;
+
+/*
+ * Texture argument constants for texture combiner
+ */
+typedef enum {
+   SVGA3D_TA_INVALID    = 0,
+   SVGA3D_TA_CONSTANT   = 1,
+   SVGA3D_TA_PREVIOUS   = 2,
+   SVGA3D_TA_DIFFUSE    = 3,
+   SVGA3D_TA_TEXTURE    = 4,
+   SVGA3D_TA_SPECULAR   = 5,
+   SVGA3D_TA_MAX
+} SVGA3dTextureArgData;
+
+#define SVGA3D_TM_MASK_LEN 4
+
+/* Modifiers for texture argument constants defined above. */
+typedef enum {
+   SVGA3D_TM_NONE       = 0,
+   SVGA3D_TM_ALPHA      = (1 << SVGA3D_TM_MASK_LEN),
+   SVGA3D_TM_ONE_MINUS  = (2 << SVGA3D_TM_MASK_LEN),
+} SVGA3dTextureArgModifier;
+
+#define SVGA3D_INVALID_ID         ((uint32)-1)
+#define SVGA3D_MAX_CLIP_PLANES    6
+
+/*
+ * This is the limit to the number of fixed-function texture
+ * transforms and texture coordinates we can support. It does *not*
+ * correspond to the number of texture image units (samplers) we
+ * support!
+ */
+#define SVGA3D_MAX_TEXTURE_COORDS 8
+
+/*
+ * Vertex declarations
+ *
+ * Notes:
+ *
+ * SVGA3D_DECLUSAGE_POSITIONT is for pre-transformed vertices. If you
+ * draw with any POSITIONT vertex arrays, the programmable vertex
+ * pipeline will be implicitly disabled. Drawing will take place as if
+ * no vertex shader was bound.
+ */
+
+typedef enum {
+   SVGA3D_DECLUSAGE_POSITION     = 0,
+   SVGA3D_DECLUSAGE_BLENDWEIGHT,       //  1
+   SVGA3D_DECLUSAGE_BLENDINDICES,      //  2
+   SVGA3D_DECLUSAGE_NORMAL,            //  3
+   SVGA3D_DECLUSAGE_PSIZE,             //  4
+   SVGA3D_DECLUSAGE_TEXCOORD,          //  5
+   SVGA3D_DECLUSAGE_TANGENT,           //  6
+   SVGA3D_DECLUSAGE_BINORMAL,          //  7
+   SVGA3D_DECLUSAGE_TESSFACTOR,        //  8
+   SVGA3D_DECLUSAGE_POSITIONT,         //  9
+   SVGA3D_DECLUSAGE_COLOR,             // 10
+   SVGA3D_DECLUSAGE_FOG,               // 11
+   SVGA3D_DECLUSAGE_DEPTH,             // 12
+   SVGA3D_DECLUSAGE_SAMPLE,            // 13
+   SVGA3D_DECLUSAGE_MAX
+} SVGA3dDeclUsage;
+
+typedef enum {
+   SVGA3D_DECLMETHOD_DEFAULT     = 0,
+   SVGA3D_DECLMETHOD_PARTIALU,
+   SVGA3D_DECLMETHOD_PARTIALV,
+   SVGA3D_DECLMETHOD_CROSSUV,          // Normal
+   SVGA3D_DECLMETHOD_UV,
+   SVGA3D_DECLMETHOD_LOOKUP,           // Lookup a displacement map
+   SVGA3D_DECLMETHOD_LOOKUPPRESAMPLED, // Lookup a pre-sampled displacement map
+} SVGA3dDeclMethod;
+
+typedef enum {
+   SVGA3D_DECLTYPE_FLOAT1        =  0,
+   SVGA3D_DECLTYPE_FLOAT2        =  1,
+   SVGA3D_DECLTYPE_FLOAT3        =  2,
+   SVGA3D_DECLTYPE_FLOAT4        =  3,
+   SVGA3D_DECLTYPE_D3DCOLOR      =  4,
+   SVGA3D_DECLTYPE_UBYTE4        =  5,
+   SVGA3D_DECLTYPE_SHORT2        =  6,
+   SVGA3D_DECLTYPE_SHORT4        =  7,
+   SVGA3D_DECLTYPE_UBYTE4N       =  8,
+   SVGA3D_DECLTYPE_SHORT2N       =  9,
+   SVGA3D_DECLTYPE_SHORT4N       = 10,
+   SVGA3D_DECLTYPE_USHORT2N      = 11,
+   SVGA3D_DECLTYPE_USHORT4N      = 12,
+   SVGA3D_DECLTYPE_UDEC3         = 13,
+   SVGA3D_DECLTYPE_DEC3N         = 14,
+   SVGA3D_DECLTYPE_FLOAT16_2     = 15,
+   SVGA3D_DECLTYPE_FLOAT16_4     = 16,
+   SVGA3D_DECLTYPE_MAX,
+} SVGA3dDeclType;
+
+/*
+ * This structure is used for the divisor for geometry instancing;
+ * it's a direct translation of the Direct3D equivalent.
+ */
+typedef union {
+   struct {
+      /*
+       * For index data, this number represents the number of instances to draw.
+       * For instance data, this number represents the number of
+       * instances/vertex in this stream
+       */
+      uint32 count : 30;
+
+      /*
+       * This is 1 if this is supposed to be the data that is repeated for
+       * every instance.
+       */
+      uint32 indexedData : 1;
+
+      /*
+       * This is 1 if this is supposed to be the per-instance data.
+       */
+      uint32 instanceData : 1;
+   };
+
+   uint32 value;
+} SVGA3dVertexDivisor;
+
+typedef enum {
+   SVGA3D_PRIMITIVE_INVALID                     = 0,
+   SVGA3D_PRIMITIVE_TRIANGLELIST                = 1,
+   SVGA3D_PRIMITIVE_POINTLIST                   = 2,
+   SVGA3D_PRIMITIVE_LINELIST                    = 3,
+   SVGA3D_PRIMITIVE_LINESTRIP                   = 4,
+   SVGA3D_PRIMITIVE_TRIANGLESTRIP               = 5,
+   SVGA3D_PRIMITIVE_TRIANGLEFAN                 = 6,
+   SVGA3D_PRIMITIVE_MAX
+} SVGA3dPrimitiveType;
+
+typedef enum {
+   SVGA3D_COORDINATE_INVALID                   = 0,
+   SVGA3D_COORDINATE_LEFTHANDED                = 1,
+   SVGA3D_COORDINATE_RIGHTHANDED               = 2,
+   SVGA3D_COORDINATE_MAX
+} SVGA3dCoordinateType;
+
+typedef enum {
+   SVGA3D_TRANSFORM_INVALID                     = 0,
+   SVGA3D_TRANSFORM_WORLD                       = 1,
+   SVGA3D_TRANSFORM_VIEW                        = 2,
+   SVGA3D_TRANSFORM_PROJECTION                  = 3,
+   SVGA3D_TRANSFORM_TEXTURE0                    = 4,
+   SVGA3D_TRANSFORM_TEXTURE1                    = 5,
+   SVGA3D_TRANSFORM_TEXTURE2                    = 6,
+   SVGA3D_TRANSFORM_TEXTURE3                    = 7,
+   SVGA3D_TRANSFORM_TEXTURE4                    = 8,
+   SVGA3D_TRANSFORM_TEXTURE5                    = 9,
+   SVGA3D_TRANSFORM_TEXTURE6                    = 10,
+   SVGA3D_TRANSFORM_TEXTURE7                    = 11,
+   SVGA3D_TRANSFORM_WORLD1                      = 12,
+   SVGA3D_TRANSFORM_WORLD2                      = 13,
+   SVGA3D_TRANSFORM_WORLD3                      = 14,
+   SVGA3D_TRANSFORM_MAX
+} SVGA3dTransformType;
+
+typedef enum {
+   SVGA3D_LIGHTTYPE_INVALID                     = 0,
+   SVGA3D_LIGHTTYPE_POINT                       = 1,
+   SVGA3D_LIGHTTYPE_SPOT1                       = 2, /* 1-cone, in degrees */
+   SVGA3D_LIGHTTYPE_SPOT2                       = 3, /* 2-cone, in radians */
+   SVGA3D_LIGHTTYPE_DIRECTIONAL                 = 4,
+   SVGA3D_LIGHTTYPE_MAX
+} SVGA3dLightType;
+
+typedef enum {
+   SVGA3D_CUBEFACE_POSX                         = 0,
+   SVGA3D_CUBEFACE_NEGX                         = 1,
+   SVGA3D_CUBEFACE_POSY                         = 2,
+   SVGA3D_CUBEFACE_NEGY                         = 3,
+   SVGA3D_CUBEFACE_POSZ                         = 4,
+   SVGA3D_CUBEFACE_NEGZ                         = 5,
+} SVGA3dCubeFace;
+
+typedef enum {
+   SVGA3D_SHADERTYPE_COMPILED_DX8               = 0,
+   SVGA3D_SHADERTYPE_VS                         = 1,
+   SVGA3D_SHADERTYPE_PS                         = 2,
+   SVGA3D_SHADERTYPE_MAX
+} SVGA3dShaderType;
+
+typedef enum {
+   SVGA3D_CONST_TYPE_FLOAT                      = 0,
+   SVGA3D_CONST_TYPE_INT                        = 1,
+   SVGA3D_CONST_TYPE_BOOL                       = 2,
+} SVGA3dShaderConstType;
+
+#define SVGA3D_MAX_SURFACE_FACES                6
+
+typedef enum {
+   SVGA3D_STRETCH_BLT_POINT                     = 0,
+   SVGA3D_STRETCH_BLT_LINEAR                    = 1,
+   SVGA3D_STRETCH_BLT_MAX
+} SVGA3dStretchBltMode;
+
+typedef enum {
+   SVGA3D_QUERYTYPE_OCCLUSION                   = 0,
+   SVGA3D_QUERYTYPE_MAX
+} SVGA3dQueryType;
+
+typedef enum {
+   SVGA3D_QUERYSTATE_PENDING     = 0,      /* Waiting on the host (set by guest) */
+   SVGA3D_QUERYSTATE_SUCCEEDED   = 1,      /* Completed successfully (set by host) */
+   SVGA3D_QUERYSTATE_FAILED      = 2,      /* Completed unsuccessfully (set by host) */
+   SVGA3D_QUERYSTATE_NEW         = 3,      /* Never submitted (For guest use only) */
+} SVGA3dQueryState;
+
+typedef enum {
+   SVGA3D_WRITE_HOST_VRAM        = 1,
+   SVGA3D_READ_HOST_VRAM         = 2,
+} SVGA3dTransferType;
+
+/*
+ * The maximum number of vertex arrays we're guaranteed to support in
+ * SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_VERTEX_ARRAYS   32
+
+/*
+ * The maximum number of primitive ranges we're guaranteed to support
+ * in SVGA_3D_CMD_DRAWPRIMITIVES.
+ */
+#define SVGA3D_MAX_DRAW_PRIMITIVE_RANGES 32
+
+/*
+ * Identifiers for commands in the command FIFO.
+ *
+ * IDs between 1000 and 1039 (inclusive) were used by obsolete versions of
+ * the SVGA3D protocol and remain reserved; they should not be used in the
+ * future.
+ *
+ * IDs between 1040 and 1999 (inclusive) are available for use by the
+ * current SVGA3D protocol.
+ *
+ * FIFO clients other than SVGA3D should stay below 1000, or at 2000
+ * and up.
+ */
+
+#define SVGA_3D_CMD_LEGACY_BASE            1000
+#define SVGA_3D_CMD_BASE                   1040
+
+#define SVGA_3D_CMD_SURFACE_DEFINE         SVGA_3D_CMD_BASE + 0
+#define SVGA_3D_CMD_SURFACE_DESTROY        SVGA_3D_CMD_BASE + 1
+#define SVGA_3D_CMD_SURFACE_COPY           SVGA_3D_CMD_BASE + 2
+#define SVGA_3D_CMD_SURFACE_STRETCHBLT     SVGA_3D_CMD_BASE + 3
+#define SVGA_3D_CMD_SURFACE_DMA            SVGA_3D_CMD_BASE + 4
+#define SVGA_3D_CMD_CONTEXT_DEFINE         SVGA_3D_CMD_BASE + 5
+#define SVGA_3D_CMD_CONTEXT_DESTROY        SVGA_3D_CMD_BASE + 6
+#define SVGA_3D_CMD_SETTRANSFORM           SVGA_3D_CMD_BASE + 7
+#define SVGA_3D_CMD_SETZRANGE              SVGA_3D_CMD_BASE + 8
+#define SVGA_3D_CMD_SETRENDERSTATE         SVGA_3D_CMD_BASE + 9
+#define SVGA_3D_CMD_SETRENDERTARGET        SVGA_3D_CMD_BASE + 10
+#define SVGA_3D_CMD_SETTEXTURESTATE        SVGA_3D_CMD_BASE + 11
+#define SVGA_3D_CMD_SETMATERIAL            SVGA_3D_CMD_BASE + 12
+#define SVGA_3D_CMD_SETLIGHTDATA           SVGA_3D_CMD_BASE + 13
+#define SVGA_3D_CMD_SETLIGHTENABLED        SVGA_3D_CMD_BASE + 14
+#define SVGA_3D_CMD_SETVIEWPORT            SVGA_3D_CMD_BASE + 15
+#define SVGA_3D_CMD_SETCLIPPLANE           SVGA_3D_CMD_BASE + 16
+#define SVGA_3D_CMD_CLEAR                  SVGA_3D_CMD_BASE + 17
+#define SVGA_3D_CMD_PRESENT                SVGA_3D_CMD_BASE + 18    // Deprecated
+#define SVGA_3D_CMD_SHADER_DEFINE          SVGA_3D_CMD_BASE + 19
+#define SVGA_3D_CMD_SHADER_DESTROY         SVGA_3D_CMD_BASE + 20
+#define SVGA_3D_CMD_SET_SHADER             SVGA_3D_CMD_BASE + 21
+#define SVGA_3D_CMD_SET_SHADER_CONST       SVGA_3D_CMD_BASE + 22
+#define SVGA_3D_CMD_DRAW_PRIMITIVES        SVGA_3D_CMD_BASE + 23
+#define SVGA_3D_CMD_SETSCISSORRECT         SVGA_3D_CMD_BASE + 24
+#define SVGA_3D_CMD_BEGIN_QUERY            SVGA_3D_CMD_BASE + 25
+#define SVGA_3D_CMD_END_QUERY              SVGA_3D_CMD_BASE + 26
+#define SVGA_3D_CMD_WAIT_FOR_QUERY         SVGA_3D_CMD_BASE + 27
+#define SVGA_3D_CMD_PRESENT_READBACK       SVGA_3D_CMD_BASE + 28    // Deprecated
+#define SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN SVGA_3D_CMD_BASE + 29
+#define SVGA_3D_CMD_MAX                    SVGA_3D_CMD_BASE + 30
+
+#define SVGA_3D_CMD_FUTURE_MAX             2000
+
+/*
+ * Common substructures used in multiple FIFO commands:
+ */
+
+typedef struct {
+   union {
+      struct {
+         uint16  function;       // SVGA3dFogFunction
+         uint8   type;           // SVGA3dFogType
+         uint8   base;           // SVGA3dFogBase
+      };
+      uint32     uintValue;
+   };
+} SVGA3dFogMode;
+
+/*
+ * Uniquely identify one image (a 1D/2D/3D array) from a surface. This
+ * is a surface ID as well as face/mipmap indices.
+ */
+
+typedef
+struct SVGA3dSurfaceImageId {
+   uint32               sid;
+   uint32               face;
+   uint32               mipmap;
+} SVGA3dSurfaceImageId;
+
+typedef
+struct SVGA3dGuestImage {
+   SVGAGuestPtr         ptr;
+
+   /*
+    * A note on interpretation of pitch: This value of pitch is the
+    * number of bytes between vertically adjacent image
+    * blocks. Normally this is the number of bytes between the first
+    * pixel of two adjacent scanlines. With compressed textures,
+    * however, this may represent the number of bytes between
+    * compression blocks rather than between rows of pixels.
+    *
+    * XXX: Compressed textures currently must be tightly packed in guest memory.
+    *
+    * If the image is 1-dimensional, pitch is ignored.
+    *
+    * If 'pitch' is zero, the SVGA3D device calculates a pitch value
+    * assuming each row of blocks is tightly packed.
+    */
+   uint32 pitch;
+} SVGA3dGuestImage;
+
+
+/*
+ * FIFO command format definitions:
+ */
+
+/*
+ * The data size header following cmdNum for every 3d command
+ */
+typedef
+struct {
+   uint32               id;
+   uint32               size;
+} SVGA3dCmdHeader;
+
+/*
+ * A surface is a hierarchy of host VRAM surfaces: 1D, 2D, or 3D, with
+ * optional mipmaps and cube faces.
+ */
+
+typedef
+struct {
+   uint32               width;
+   uint32               height;
+   uint32               depth;
+} SVGA3dSize;
+
+typedef enum {
+   SVGA3D_SURFACE_CUBEMAP              = (1 << 0),
+   SVGA3D_SURFACE_HINT_STATIC          = (1 << 1),
+   SVGA3D_SURFACE_HINT_DYNAMIC         = (1 << 2),
+   SVGA3D_SURFACE_HINT_INDEXBUFFER     = (1 << 3),
+   SVGA3D_SURFACE_HINT_VERTEXBUFFER    = (1 << 4),
+   SVGA3D_SURFACE_HINT_TEXTURE         = (1 << 5),
+   SVGA3D_SURFACE_HINT_RENDERTARGET    = (1 << 6),
+   SVGA3D_SURFACE_HINT_DEPTHSTENCIL    = (1 << 7),
+   SVGA3D_SURFACE_HINT_WRITEONLY       = (1 << 8),
+} SVGA3dSurfaceFlags;
+
+typedef
+struct {
+   uint32               numMipLevels;
+} SVGA3dSurfaceFace;
+
+typedef
+struct {
+   uint32                      sid;
+   SVGA3dSurfaceFlags          surfaceFlags;
+   SVGA3dSurfaceFormat         format;
+   SVGA3dSurfaceFace           face[SVGA3D_MAX_SURFACE_FACES];
+   /*
+    * Followed by an SVGA3dSize structure for each mip level in each face.
+    *
+    * A note on surface sizes: Sizes are always specified in pixels,
+    * even if the true surface size is not a multiple of the minimum
+    * block size of the surface's format. For example, a 3x3x1 DXT1
+    * compressed texture would actually be stored as a 4x4x1 image in
+    * memory.
+    */
+} SVGA3dCmdDefineSurface;       /* SVGA_3D_CMD_SURFACE_DEFINE */
+
+typedef
+struct {
+   uint32               sid;
+} SVGA3dCmdDestroySurface;      /* SVGA_3D_CMD_SURFACE_DESTROY */
+
+typedef
+struct {
+   uint32               cid;
+} SVGA3dCmdDefineContext;       /* SVGA_3D_CMD_CONTEXT_DEFINE */
+
+typedef
+struct {
+   uint32               cid;
+} SVGA3dCmdDestroyContext;      /* SVGA_3D_CMD_CONTEXT_DESTROY */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dClearFlag      clearFlag;
+   uint32               color;
+   float                depth;
+   uint32               stencil;
+   /* Followed by variable number of SVGA3dRect structures */
+} SVGA3dCmdClear;               /* SVGA_3D_CMD_CLEAR */
+
+typedef
+struct SVGA3dCopyRect {
+   uint32               x;
+   uint32               y;
+   uint32               w;
+   uint32               h;
+   uint32               srcx;
+   uint32               srcy;
+} SVGA3dCopyRect;
+
+typedef
+struct SVGA3dCopyBox {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+   uint32               w;
+   uint32               h;
+   uint32               d;
+   uint32               srcx;
+   uint32               srcy;
+   uint32               srcz;
+} SVGA3dCopyBox;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               w;
+   uint32               h;
+} SVGA3dRect;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+   uint32               w;
+   uint32               h;
+   uint32               d;
+} SVGA3dBox;
+
+typedef
+struct {
+   uint32               x;
+   uint32               y;
+   uint32               z;
+} SVGA3dPoint;
+
+typedef
+struct {
+   SVGA3dLightType      type;
+   SVGA3dBool           inWorldSpace;
+   float                diffuse[4];
+   float                specular[4];
+   float                ambient[4];
+   float                position[4];
+   float                direction[4];
+   float                range;
+   float                falloff;
+   float                attenuation0;
+   float                attenuation1;
+   float                attenuation2;
+   float                theta;
+   float                phi;
+} SVGA3dLightData;
+
+typedef
+struct {
+   uint32               sid;
+   /* Followed by variable number of SVGA3dCopyRect structures */
+} SVGA3dCmdPresent;             /* SVGA_3D_CMD_PRESENT */
+
+typedef
+struct {
+   SVGA3dRenderStateName   state;
+   union {
+      uint32               uintValue;
+      float                floatValue;
+   };
+} SVGA3dRenderState;
+
+typedef
+struct {
+   uint32               cid;
+   /* Followed by variable number of SVGA3dRenderState structures */
+} SVGA3dCmdSetRenderState;      /* SVGA_3D_CMD_SETRENDERSTATE */
+
+typedef
+struct {
+   uint32                 cid;
+   SVGA3dRenderTargetType type;
+   SVGA3dSurfaceImageId   target;
+} SVGA3dCmdSetRenderTarget;     /* SVGA_3D_CMD_SETRENDERTARGET */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId  src;
+   SVGA3dSurfaceImageId  dest;
+   /* Followed by variable number of SVGA3dCopyBox structures */
+} SVGA3dCmdSurfaceCopy;               /* SVGA_3D_CMD_SURFACE_COPY */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId  src;
+   SVGA3dSurfaceImageId  dest;
+   SVGA3dBox             boxSrc;
+   SVGA3dBox             boxDest;
+   SVGA3dStretchBltMode  mode;
+} SVGA3dCmdSurfaceStretchBlt;         /* SVGA_3D_CMD_SURFACE_STRETCHBLT */
+
+typedef
+struct {
+   /*
+    * If the discard flag is present in a surface DMA operation, the host may
+    * discard the contents of the current mipmap level and face of the target
+    * surface before applying the surface DMA contents.
+    */
+   uint32 discard : 1;
+
+   /*
+    * If the unsynchronized flag is present, the host may perform this upload
+    * without syncing to pending reads on this surface.
+    */
+   uint32 unsynchronized : 1;
+
+   /*
+    * Guests *MUST* set the reserved bits to 0 before submitting the command
+    * suffix as future flags may occupy these bits.
+    */
+   uint32 reserved : 30;
+} SVGA3dSurfaceDMAFlags;
+
+typedef
+struct {
+   SVGA3dGuestImage      guest;
+   SVGA3dSurfaceImageId  host;
+   SVGA3dTransferType    transfer;
+   /*
+    * Followed by variable number of SVGA3dCopyBox structures. For consistency
+    * in all clipping logic and coordinate translation, we define the
+    * "source" in each copyBox as the guest image and the
+    * "destination" as the host image, regardless of transfer
+    * direction.
+    *
+    * For efficiency, the SVGA3D device is free to copy more data than
+    * specified. For example, it may round copy boxes outwards such
+    * that they lie on particular alignment boundaries.
+    */
+} SVGA3dCmdSurfaceDMA;                /* SVGA_3D_CMD_SURFACE_DMA */
+
+/*
+ * SVGA3dCmdSurfaceDMASuffix --
+ *
+ *    This is a command suffix that will appear after a SurfaceDMA command in
+ *    the FIFO.  It contains some extra information that hosts may use to
+ *    optimize performance or protect the guest.  This suffix exists to preserve
+ *    backwards compatibility while also allowing for new functionality to be
+ *    implemented.
+ */
+
+typedef
+struct {
+   uint32 suffixSize;
+
+   /*
+    * The maximum offset is used to determine the maximum offset from the
+    * guestPtr base address that will be accessed or written to during this
+    * surfaceDMA.  If the suffix is supported, the host will respect this
+    * boundary while performing surface DMAs.
+    *
+    * Defaults to MAX_UINT32
+    */
+   uint32 maximumOffset;
+
+   /*
+    * A set of flags that describes optimizations that the host may perform
+    * while performing this surface DMA operation.  The guest should never rely
+    * on behaviour that is different when these flags are set for correctness.
+    *
+    * Defaults to 0
+    */
+   SVGA3dSurfaceDMAFlags flags;
+} SVGA3dCmdSurfaceDMASuffix;
+
+/*
+ * SVGA_3D_CMD_DRAW_PRIMITIVES --
+ *
+ *   This command is the SVGA3D device's generic drawing entry point.
+ *   It can draw multiple ranges of primitives, optionally using an
+ *   index buffer, using an arbitrary collection of vertex buffers.
+ *
+ *   Each SVGA3dVertexDecl defines a distinct vertex array to bind
+ *   during this draw call. The declarations specify which surface
+ *   the vertex data lives in, what that vertex data is used for,
+ *   and how to interpret it.
+ *
+ *   Each SVGA3dPrimitiveRange defines a collection of primitives
+ *   to render using the same vertex arrays. An index buffer is
+ *   optional.
+ */
+
+typedef
+struct {
+   /*
+    * A range hint is an optional specification for the range of indices
+    * in an SVGA3dArray that will be used. If 'last' is zero, it is assumed
+    * that the entire array will be used.
+    *
+    * These are only hints. The SVGA3D device may use them for
+    * performance optimization if possible, but it's also allowed to
+    * ignore these values.
+    */
+   uint32               first;
+   uint32               last;
+} SVGA3dArrayRangeHint;
+
+typedef
+struct {
+   /*
+    * Define the origin and shape of a vertex or index array. Both
+    * 'offset' and 'stride' are in bytes. The provided surface will be
+    * reinterpreted as a flat array of bytes in the same format used
+    * by surface DMA operations. To avoid unnecessary conversions, the
+    * surface should be created with the SVGA3D_BUFFER format.
+    *
+    * Index 0 in the array starts 'offset' bytes into the surface.
+    * Index 1 begins at byte 'offset + stride', etc. Array indices may
+    * not be negative.
+    */
+   uint32               surfaceId;
+   uint32               offset;
+   uint32               stride;
+} SVGA3dArray;
+
+typedef
+struct {
+   /*
+    * Describe a vertex array's data type, and define how it is to be
+    * used by the fixed function pipeline or the vertex shader. It
+    * isn't useful to have two VertexDecls with the same
+    * VertexArrayIdentity in one draw call.
+    */
+   SVGA3dDeclType       type;
+   SVGA3dDeclMethod     method;
+   SVGA3dDeclUsage      usage;
+   uint32               usageIndex;
+} SVGA3dVertexArrayIdentity;
+
+typedef
+struct {
+   SVGA3dVertexArrayIdentity  identity;
+   SVGA3dArray                array;
+   SVGA3dArrayRangeHint       rangeHint;
+} SVGA3dVertexDecl;
+
+typedef
+struct {
+   /*
+    * Define a group of primitives to render, from sequential indices.
+    *
+    * The value of 'primitiveType' and 'primitiveCount' imply the
+    * total number of vertices that will be rendered.
+    */
+   SVGA3dPrimitiveType  primType;
+   uint32               primitiveCount;
+
+   /*
+    * Optional index buffer. If indexArray.surfaceId is
+    * SVGA3D_INVALID_ID, we render without an index buffer. Rendering
+    * without an index buffer is identical to rendering with an index
+    * buffer containing the sequence [0, 1, 2, 3, ...].
+    *
+    * If an index buffer is in use, indexWidth specifies the width in
+    * bytes of each index value. It must be less than or equal to
+    * indexArray.stride.
+    *
+    * (Currently, the SVGA3D device requires index buffers to be tightly
+    * packed. In other words, indexWidth == indexArray.stride)
+    */
+   SVGA3dArray          indexArray;
+   uint32               indexWidth;
+
+   /*
+    * Optional index bias. This number is added to all indices from
+    * indexArray before they are used as vertex array indices. This
+    * can be used in multiple ways:
+    *
+    *  - When not using an indexArray, this bias can be used to
+    *    specify where in the vertex arrays to begin rendering.
+    *
+    *  - A positive number here is equivalent to increasing the
+    *    offset in each vertex array.
+    *
+    *  - A negative number can be used to render using a small
+    *    vertex array and an index buffer that contains large
+    *    values. This may be used by some applications that
+    *    crop a vertex buffer without modifying their index
+    *    buffer.
+    *
+    * Note that rendering with a negative bias value may be slower and
+    * use more memory than rendering with a positive or zero bias.
+    */
+   int32                indexBias;
+} SVGA3dPrimitiveRange;
+
+typedef
+struct {
+   uint32               cid;
+   uint32               numVertexDecls;
+   uint32               numRanges;
+
+   /*
+    * There are two variable size arrays after the
+    * SVGA3dCmdDrawPrimitives structure. In order,
+    * they are:
+    *
+    * 1. SVGA3dVertexDecl, quantity 'numVertexDecls', but no more than
+    *    SVGA3D_MAX_VERTEX_ARRAYS;
+    * 2. SVGA3dPrimitiveRange, quantity 'numRanges', but no more than
+    *    SVGA3D_MAX_DRAW_PRIMITIVE_RANGES;
+    * 3. Optionally, SVGA3dVertexDivisor, quantity 'numVertexDecls' (contains
+    *    the frequency divisor for the corresponding vertex decl).
+    */
+} SVGA3dCmdDrawPrimitives;      /* SVGA_3D_CMD_DRAWPRIMITIVES */
+
+typedef
+struct {
+   uint32                   stage;
+   SVGA3dTextureStateName   name;
+   union {
+      uint32                value;
+      float                 floatValue;
+   };
+} SVGA3dTextureState;
+
+typedef
+struct {
+   uint32               cid;
+   /* Followed by variable number of SVGA3dTextureState structures */
+} SVGA3dCmdSetTextureState;      /* SVGA_3D_CMD_SETTEXTURESTATE */
+
+typedef
+struct {
+   uint32                   cid;
+   SVGA3dTransformType      type;
+   float                    matrix[16];
+} SVGA3dCmdSetTransform;          /* SVGA_3D_CMD_SETTRANSFORM */
+
+typedef
+struct {
+   float                min;
+   float                max;
+} SVGA3dZRange;
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dZRange         zRange;
+} SVGA3dCmdSetZRange;             /* SVGA_3D_CMD_SETZRANGE */
+
+typedef
+struct {
+   float                diffuse[4];
+   float                ambient[4];
+   float                specular[4];
+   float                emissive[4];
+   float                shininess;
+} SVGA3dMaterial;
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dFace           face;
+   SVGA3dMaterial       material;
+} SVGA3dCmdSetMaterial;           /* SVGA_3D_CMD_SETMATERIAL */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   SVGA3dLightData      data;
+} SVGA3dCmdSetLightData;           /* SVGA_3D_CMD_SETLIGHTDATA */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   uint32               enabled;
+} SVGA3dCmdSetLightEnabled;      /* SVGA_3D_CMD_SETLIGHTENABLED */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dRect           rect;
+} SVGA3dCmdSetViewport;           /* SVGA_3D_CMD_SETVIEWPORT */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dRect           rect;
+} SVGA3dCmdSetScissorRect;         /* SVGA_3D_CMD_SETSCISSORRECT */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               index;
+   float                plane[4];
+} SVGA3dCmdSetClipPlane;           /* SVGA_3D_CMD_SETCLIPPLANE */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               shid;
+   SVGA3dShaderType     type;
+   /* Followed by variable number of DWORDs for shader bycode */
+} SVGA3dCmdDefineShader;           /* SVGA_3D_CMD_SHADER_DEFINE */
+
+typedef
+struct {
+   uint32               cid;
+   uint32               shid;
+   SVGA3dShaderType     type;
+} SVGA3dCmdDestroyShader;         /* SVGA_3D_CMD_SHADER_DESTROY */
+
+typedef
+struct {
+   uint32                  cid;
+   uint32                  reg;     /* register number */
+   SVGA3dShaderType        type;
+   SVGA3dShaderConstType   ctype;
+   uint32                  values[4];
+} SVGA3dCmdSetShaderConst;        /* SVGA_3D_CMD_SET_SHADER_CONST */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dShaderType     type;
+   uint32               shid;
+} SVGA3dCmdSetShader;             /* SVGA_3D_CMD_SET_SHADER */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+} SVGA3dCmdBeginQuery;           /* SVGA_3D_CMD_BEGIN_QUERY */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+   SVGAGuestPtr         guestResult;  /* Points to an SVGA3dQueryResult structure */
+} SVGA3dCmdEndQuery;                  /* SVGA_3D_CMD_END_QUERY */
+
+typedef
+struct {
+   uint32               cid;          /* Same parameters passed to END_QUERY */
+   SVGA3dQueryType      type;
+   SVGAGuestPtr         guestResult;
+} SVGA3dCmdWaitForQuery;              /* SVGA_3D_CMD_WAIT_FOR_QUERY */
+
+typedef
+struct {
+   uint32               totalSize;    /* Set by guest before query is ended. */
+   SVGA3dQueryState     state;        /* Set by host or guest. See SVGA3dQueryState. */
+   union {                            /* Set by host on exit from PENDING state */
+      uint32            result32;
+   };
+} SVGA3dQueryResult;
+
+/*
+ * SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN --
+ *
+ *    This is a blit from an SVGA3D surface to a Screen Object. Just
+ *    like GMR-to-screen blits, this blit may be directed at a
+ *    specific screen or to the virtual coordinate space.
+ *
+ *    The blit copies from a rectangular region of an SVGA3D surface
+ *    image to a rectangular region of a screen or screens.
+ *
+ *    This command takes an optional variable-length list of clipping
+ *    rectangles after the body of the command. If no rectangles are
+ *    specified, there is no clipping region. The entire destRect is
+ *    drawn to. If one or more rectangles are included, they describe
+ *    a clipping region. The clip rectangle coordinates are measured
+ *    relative to the top-left corner of destRect.
+ *
+ *    This clipping region serves multiple purposes:
+ *
+ *      - It can be used to perform an irregularly shaped blit more
+ *        efficiently than by issuing many separate blit commands.
+ *
+ *      - It is equivalent to allowing blits with non-integer
+ *        source coordinates. You could blit just one half-pixel
+ *        of a source, for example, by specifying a larger
+ *        destination rectangle than you need, then removing
+ *        part of it using a clip rectangle.
+ *
+ * Availability:
+ *    SVGA_FIFO_CAP_SCREEN_OBJECT
+ *
+ * Limitations:
+ *
+ *    - Currently, no backend supports blits from a mipmap or face
+ *      other than the first one.
+ */
+
+typedef
+struct {
+   SVGA3dSurfaceImageId srcImage;
+   SVGASignedRect       srcRect;
+   uint32               destScreenId; /* Screen ID or SVGA_ID_INVALID for virt. coords */
+   SVGASignedRect       destRect;     /* Supports scaling if src/rest different size */
+   /* Clipping: zero or more SVGASignedRects follow */
+} SVGA3dCmdBlitSurfaceToScreen;         /* SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN */
+
+
+/*
+ * Capability query index.
+ *
+ * Notes:
+ *
+ *   1. SVGA3D_DEVCAP_MAX_TEXTURES reflects the maximum number of
+ *      fixed-function texture units available. Each of these units
+ *      work in both FFP and Shader modes, and they support texture
+ *      transforms and texture coordinates. The host may have additional
+ *      texture image units that are only usable with shaders.
+ *
+ *   2. The BUFFER_FORMAT capabilities are deprecated, and they always
+ *      return TRUE. Even on physical hardware that does not support
+ *      these formats natively, the SVGA3D device will provide an emulation
+ *      which should be invisible to the guest OS.
+ *
+ *      In general, the SVGA3D device should support any operation on
+ *      any surface format, it just may perform some of these
+ *      operations in software depending on the capabilities of the
+ *      available physical hardware.
+ *
+ *      XXX: In the future, we will add capabilities that describe in
+ *      detail what formats are supported in hardware for what kinds
+ *      of operations.
+ */
+
+typedef enum {
+   SVGA3D_DEVCAP_3D                                = 0,
+   SVGA3D_DEVCAP_MAX_LIGHTS                        = 1,
+   SVGA3D_DEVCAP_MAX_TEXTURES                      = 2,  /* See note (1) */
+   SVGA3D_DEVCAP_MAX_CLIP_PLANES                   = 3,
+   SVGA3D_DEVCAP_VERTEX_SHADER_VERSION             = 4,
+   SVGA3D_DEVCAP_VERTEX_SHADER                     = 5,
+   SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION           = 6,
+   SVGA3D_DEVCAP_FRAGMENT_SHADER                   = 7,
+   SVGA3D_DEVCAP_MAX_RENDER_TARGETS                = 8,
+   SVGA3D_DEVCAP_S23E8_TEXTURES                    = 9,
+   SVGA3D_DEVCAP_S10E5_TEXTURES                    = 10,
+   SVGA3D_DEVCAP_MAX_FIXED_VERTEXBLEND             = 11,
+   SVGA3D_DEVCAP_D16_BUFFER_FORMAT                 = 12, /* See note (2) */
+   SVGA3D_DEVCAP_D24S8_BUFFER_FORMAT               = 13, /* See note (2) */
+   SVGA3D_DEVCAP_D24X8_BUFFER_FORMAT               = 14, /* See note (2) */
+   SVGA3D_DEVCAP_QUERY_TYPES                       = 15,
+   SVGA3D_DEVCAP_TEXTURE_GRADIENT_SAMPLING         = 16,
+   SVGA3D_DEVCAP_MAX_POINT_SIZE                    = 17,
+   SVGA3D_DEVCAP_MAX_SHADER_TEXTURES               = 18,
+   SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH                 = 19,
+   SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT                = 20,
+   SVGA3D_DEVCAP_MAX_VOLUME_EXTENT                 = 21,
+   SVGA3D_DEVCAP_MAX_TEXTURE_REPEAT                = 22,
+   SVGA3D_DEVCAP_MAX_TEXTURE_ASPECT_RATIO          = 23,
+   SVGA3D_DEVCAP_MAX_TEXTURE_ANISOTROPY            = 24,
+   SVGA3D_DEVCAP_MAX_PRIMITIVE_COUNT               = 25,
+   SVGA3D_DEVCAP_MAX_VERTEX_INDEX                  = 26,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_INSTRUCTIONS    = 27,
+   SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_INSTRUCTIONS  = 28,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEMPS           = 29,
+   SVGA3D_DEVCAP_MAX_FRAGMENT_SHADER_TEMPS         = 30,
+   SVGA3D_DEVCAP_TEXTURE_OPS                       = 31,
+   SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8               = 32,
+   SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8               = 33,
+   SVGA3D_DEVCAP_SURFACEFMT_A2R10G10B10            = 34,
+   SVGA3D_DEVCAP_SURFACEFMT_X1R5G5B5               = 35,
+   SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5               = 36,
+   SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4               = 37,
+   SVGA3D_DEVCAP_SURFACEFMT_R5G6B5                 = 38,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE16            = 39,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8_ALPHA8      = 40,
+   SVGA3D_DEVCAP_SURFACEFMT_ALPHA8                 = 41,
+   SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8             = 42,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D16                  = 43,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8                = 44,
+   SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8                = 45,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT1                   = 46,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT2                   = 47,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT3                   = 48,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT4                   = 49,
+   SVGA3D_DEVCAP_SURFACEFMT_DXT5                   = 50,
+   SVGA3D_DEVCAP_SURFACEFMT_BUMPX8L8V8U8           = 51,
+   SVGA3D_DEVCAP_SURFACEFMT_A2W10V10U10            = 52,
+   SVGA3D_DEVCAP_SURFACEFMT_BUMPU8V8               = 53,
+   SVGA3D_DEVCAP_SURFACEFMT_Q8W8V8U8               = 54,
+   SVGA3D_DEVCAP_SURFACEFMT_CxV8U8                 = 55,
+   SVGA3D_DEVCAP_SURFACEFMT_R_S10E5                = 56,
+   SVGA3D_DEVCAP_SURFACEFMT_R_S23E8                = 57,
+   SVGA3D_DEVCAP_SURFACEFMT_RG_S10E5               = 58,
+   SVGA3D_DEVCAP_SURFACEFMT_RG_S23E8               = 59,
+   SVGA3D_DEVCAP_SURFACEFMT_ARGB_S10E5             = 60,
+   SVGA3D_DEVCAP_SURFACEFMT_ARGB_S23E8             = 61,
+   SVGA3D_DEVCAP_MAX_VERTEX_SHADER_TEXTURES        = 63,
+
+   /*
+    * Note that MAX_SIMULTANEOUS_RENDER_TARGETS is a maximum count of color
+    * render targets.  This does no include the depth or stencil targets.
+    */
+   SVGA3D_DEVCAP_MAX_SIMULTANEOUS_RENDER_TARGETS   = 64,
+
+   SVGA3D_DEVCAP_SURFACEFMT_V16U16                 = 65,
+   SVGA3D_DEVCAP_SURFACEFMT_G16R16                 = 66,
+   SVGA3D_DEVCAP_SURFACEFMT_A16B16G16R16           = 67,
+   SVGA3D_DEVCAP_SURFACEFMT_UYVY                   = 68,
+   SVGA3D_DEVCAP_SURFACEFMT_YUY2                   = 69,
+
+   /*
+    * Don't add new caps into the previous section; the values in this
+    * enumeration must not change. You can put new values right before
+    * SVGA3D_DEVCAP_MAX.
+    */
+   SVGA3D_DEVCAP_MAX                                  /* This must be the last index. */
+} SVGA3dDevCapIndex;
+
+typedef union {
+   Bool   b;
+   uint32 u;
+   int32  i;
+   float  f;
+} SVGA3dDevCapResult;
+
+#endif /* _SVGA3D_REG_H_ */
diff --git a/vmwgfx/vmwgfx_bootstrap.c b/vmwgfx/vmwgfx_bootstrap.c
new file mode 100644 (file)
index 0000000..5e8e9e1
--- /dev/null
@@ -0,0 +1,199 @@
+/**********************************************************
+ * Copyright 2008-2011 VMware, Inc.  All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * Bootstrap file for the vmwgfx xorg driver.
+ *
+ * @author Alan Hourihane <alanh@tungstengraphics.com>
+ * @author Jakob Bornecrantz <wallbraker@gmail.com>
+ * @author Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "pciaccess.h"
+
+#ifndef XSERVER_LIBPCIACCESS
+#error "libpciaccess needed"
+#endif
+
+void xorg_tracker_set_functions(ScrnInfoPtr scrn);
+const OptionInfoRec * xorg_tracker_available_options(int chipid, int busid);
+
+
+/*
+ * Defines and modinfo
+ */
+
+#define VMWGFX_DRIVER_NAME "vmwgfx"
+
+#define VMW_STRING_INNER(s) #s
+#define VMW_STRING(str) VMW_STRING_INNER(str)
+
+#define VMWGFX_VERSION_MAJOR 11
+#define VMWGFX_VERSION_MINOR 0
+#define VMWGFX_VERSION_PATCH 0
+#define VMWGFX_VERSION_STRING_MAJOR VMW_STRING(VMWGFX_VERSION_MAJOR)
+#define VMWGFX_VERSION_STRING_MINOR VMW_STRING(VMWGFX_VERSION_MINOR)
+#define VMWGFX_VERSION_STRING_PATCH VMW_STRING(VMWGFX_VERSION_PATCH)
+
+#define VMWGFX_DRIVER_VERSION \
+   (VMWGFX_VERSION_MAJOR * 65536 + VMWGFX_VERSION_MINOR * 256 + VMWGFX_VERSION_PATCH)
+#define VMWGFX_DRIVER_VERSION_STRING \
+    VMWGFX_VERSION_STRING_MAJOR "." VMWGFX_VERSION_STRING_MINOR \
+    "." VMWGFX_VERSION_STRING_PATCH
+
+/*
+ * Standard four digit version string expected by VMware Tools installer.
+ * As the driver's version is only  {major, minor, patchlevel}, simply append an
+ * extra zero for the fourth digit.
+ */
+#ifdef __GNUC__
+_X_EXPORT const char vmwgfx_drv_modinfo[] __attribute__((section(".modinfo"),unused)) =
+    "version=" VMWGFX_DRIVER_VERSION_STRING ".0";
+#endif
+
+static void vmw_xorg_identify(int flags);
+_X_EXPORT Bool vmw_xorg_pci_probe(DriverPtr driver,
+                                 int entity_num,
+                                 struct pci_device *device,
+                                 intptr_t match_data);
+
+
+/*
+ * Tables
+ */
+
+static const struct pci_id_match vmw_xorg_device_match[] = {
+    {0x15ad, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
+    {0, 0, 0, 0, 0, 0, 0},
+};
+
+static SymTabRec vmw_xorg_chipsets[] = {
+    {PCI_MATCH_ANY, "VMware SVGA Device"},
+    {-1, NULL}
+};
+
+static PciChipsets vmw_xorg_pci_devices[] = {
+    {PCI_MATCH_ANY, PCI_MATCH_ANY, NULL},
+    {-1, -1, NULL}
+};
+
+static XF86ModuleVersionInfo vmw_xorg_version = {
+    VMWGFX_DRIVER_NAME,
+    MODULEVENDORSTRING,
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XORG_VERSION_CURRENT,
+    VMWGFX_VERSION_MAJOR, VMWGFX_VERSION_MINOR, VMWGFX_VERSION_PATCH,
+    ABI_CLASS_VIDEODRV,
+    ABI_VIDEODRV_VERSION,
+    MOD_CLASS_VIDEODRV,
+    {0, 0, 0, 0}
+};
+
+/*
+ * Xorg driver exported structures
+ */
+
+_X_EXPORT DriverRec vmwgfx = {
+    1,
+    VMWGFX_DRIVER_NAME,
+    vmw_xorg_identify,
+    NULL,
+    xorg_tracker_available_options,
+    NULL,
+    0,
+    NULL,
+    vmw_xorg_device_match,
+    vmw_xorg_pci_probe
+};
+
+static MODULESETUPPROTO(vmw_xorg_setup);
+
+_X_EXPORT XF86ModuleData vmwgfxModuleData = {
+    &vmw_xorg_version,
+    vmw_xorg_setup,
+    NULL
+};
+
+
+/*
+ * Xorg driver functions
+ */
+
+static pointer
+vmw_xorg_setup(pointer module, pointer opts, int *errmaj, int *errmin)
+{
+    static Bool setupDone = 0;
+
+    /* This module should be loaded only once, but check to be sure.
+     */
+    if (!setupDone) {
+       setupDone = 1;
+       xf86AddDriver(&vmwgfx, module, HaveDriverFuncs);
+
+       /*
+        * The return value must be non-NULL on success even though there
+        * is no TearDownProc.
+        */
+       return (pointer) 1;
+    } else {
+       if (errmaj)
+           *errmaj = LDR_ONCEONLY;
+       return NULL;
+    }
+}
+
+static void
+vmw_xorg_identify(int flags)
+{
+    xf86PrintChipsets("vmwgfx", "Driver for VMware SVGA device",
+                     vmw_xorg_chipsets);
+}
+
+_X_EXPORT Bool
+vmw_xorg_pci_probe(DriverPtr driver,
+         int entity_num, struct pci_device *device, intptr_t match_data)
+{
+    ScrnInfoPtr scrn = NULL;
+    EntityInfoPtr entity;
+
+    scrn = xf86ConfigPciEntity(scrn, 0, entity_num, vmw_xorg_pci_devices,
+                              NULL, NULL, NULL, NULL, NULL);
+    if (scrn != NULL) {
+       scrn->driverVersion = 1;
+       scrn->driverName = "vmwgfx";
+       scrn->name = "vmwgfx";
+       scrn->Probe = NULL;
+
+       entity = xf86GetEntityInfo(entity_num);
+
+       /* Use all the functions from the xorg tracker */
+       xorg_tracker_set_functions(scrn);
+    }
+    return scrn != NULL;
+}
diff --git a/vmwgfx/vmwgfx_crtc.c b/vmwgfx/vmwgfx_crtc.c
new file mode 100644 (file)
index 0000000..49e84e8
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "xorg-server.h"
+#include <xf86.h>
+#include <xf86i2c.h>
+#include <xf86Crtc.h>
+#include <cursorstr.h>
+#include "vmwgfx_driver.h"
+#include "xf86Modes.h"
+#include "vmwgfx_saa.h"
+
+#ifdef HAVE_XEXTPROTO_71
+#include <X11/extensions/dpmsconst.h>
+#else
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+#endif
+
+struct crtc_private
+{
+    drmModeCrtcPtr drm_crtc;
+
+    /* hwcursor */
+    struct vmwgfx_dmabuf *cursor_bo;
+    PixmapPtr scanout;
+    uint32_t scanout_id;
+    unsigned cursor_handle;
+};
+
+static void
+crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+    struct crtc_private *crtcp = crtc->driver_private;
+    /* ScrnInfoPtr pScrn = crtc->scrn; */
+
+    switch (mode) {
+    case DPMSModeOn:
+    case DPMSModeStandby:
+    case DPMSModeSuspend:
+       break;
+    case DPMSModeOff:
+
+      /*
+       * The xf86 modesetting code uses DPMS off to turn off
+       * crtcs that are not enabled. However, the DPMS code does the same.
+       * We assume, that if we get this call with the crtc not enabled,
+       * it's a permanent switch off which will only be reversed by a
+       * major modeset.
+       *
+       * If it's a DPMS switch off, (crtc->enabled == TRUE),
+       * the crtc may be turned on again by
+       * another dpms call, so don't release the scanout pixmap ref.
+       */
+       if (!crtc->enabled && crtcp->scanout) {
+           PixmapPtr pixmap = crtcp->scanout;
+           ScreenPtr pScreen = pixmap->drawable.pScreen;
+
+           vmwgfx_scanout_unref(pixmap);
+           pScreen->DestroyPixmap(pixmap);
+           crtcp->scanout = NULL;
+           crtcp->scanout_id = -1;
+       }
+       break;
+    }
+}
+
+/*
+ * Disable outputs and crtcs and drop the scanout reference from
+ * scanout pixmaps. This will essentialy free all kms fb allocations.
+ */
+
+void
+vmwgfx_disable_scanout(ScrnInfoPtr pScrn)
+{
+    int i;
+    Bool save_enabled;
+    xf86CrtcPtr crtc;
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    xf86DPMSSet(pScrn, DPMSModeOff, 0);
+    for (i=0; i < config->num_crtc; ++i) {
+       crtc = config->crtc[i];
+       save_enabled = crtc->enabled;
+       crtc->enabled = FALSE;
+       crtc_dpms(crtc, DPMSModeOff);
+       crtc->enabled = save_enabled;
+    }
+    xf86RotateFreeShadow(pScrn);
+}
+
+static Bool
+crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
+                   Rotation rotation, int x, int y)
+{
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    ScreenPtr pScreen = crtc->scrn->pScreen;
+    xf86OutputPtr output = NULL;
+    struct crtc_private *crtcp = crtc->driver_private;
+    drmModeCrtcPtr drm_crtc = crtcp->drm_crtc;
+    drmModeModeInfo drm_mode;
+    int i, ret;
+    unsigned int connector_id;
+    PixmapPtr pixmap;
+
+    for (i = 0; i < config->num_output; output = NULL, i++) {
+       output = config->output[i];
+
+       if (output->crtc == crtc)
+           break;
+    }
+
+    if (!output) {
+       LogMessage(X_ERROR, "No output for this crtc.\n");
+       return FALSE;
+    }
+
+    connector_id = xorg_output_get_id(output);
+
+    drm_mode.clock = mode->Clock;
+    drm_mode.hdisplay = mode->HDisplay;
+    drm_mode.hsync_start = mode->HSyncStart;
+    drm_mode.hsync_end = mode->HSyncEnd;
+    drm_mode.htotal = mode->HTotal;
+    drm_mode.vdisplay = mode->VDisplay;
+    drm_mode.vsync_start = mode->VSyncStart;
+    drm_mode.vsync_end = mode->VSyncEnd;
+    drm_mode.vtotal = mode->VTotal;
+    drm_mode.flags = mode->Flags;
+    drm_mode.hskew = mode->HSkew;
+    drm_mode.vscan = mode->VScan;
+    drm_mode.vrefresh = mode->VRefresh;
+    if (!mode->name)
+       xf86SetModeDefaultName(mode);
+    strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1);
+    drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
+
+    /*
+     * Check if we need to scanout from something else than the root
+     * pixmap. In that case, xf86CrtcRotate will take care of allocating
+     * new opaque scanout buffer data "crtc->rotatedData".
+     * However, it will not wrap
+     * that data into pixmaps until the first rotated damage composite.
+     * In out case, the buffer data is actually already a pixmap.
+     */
+
+    if (!xf86CrtcRotate(crtc))
+       return FALSE;
+
+    if (crtc->transform_in_use && crtc->rotatedData)
+       pixmap = (PixmapPtr) crtc->rotatedData;
+    else
+       pixmap = pScreen->GetScreenPixmap(pScreen);
+
+    if (crtcp->scanout != pixmap) {
+       if (crtcp->scanout) {
+           vmwgfx_scanout_unref(crtcp->scanout);
+           pScreen->DestroyPixmap(crtcp->scanout);
+       }
+       crtcp->scanout_id = vmwgfx_scanout_ref(pixmap);
+       if (crtcp->scanout_id != -1) {
+           pixmap->refcnt += 1;
+           crtcp->scanout = pixmap;
+       } else {
+           crtcp->scanout = NULL;
+           LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n");
+           return FALSE;
+       }
+    }
+    ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, crtcp->scanout_id, x, y,
+                        &connector_id, 1, &drm_mode);
+    if (ret)
+       return FALSE;
+
+    vmwgfx_scanout_refresh(pixmap);
+
+    /* Only set gamma when needed, to avoid unneeded delays. */
+#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
+    if (!crtc->active && crtc->version >= 3)
+       crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
+                              crtc->gamma_blue, crtc->gamma_size);
+    crtc->active = TRUE;
+#endif
+
+    return TRUE;
+}
+
+static void
+crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue,
+              int size)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    drmModeCrtcSetGamma(ms->fd, crtcp->drm_crtc->crtc_id, size, red, green, blue);
+}
+
+static void *
+crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
+{
+    ScreenPtr pScreen = crtc->scrn->pScreen;
+    PixmapPtr rootpix = pScreen->GetScreenPixmap(pScreen);
+
+    /*
+     * Use the same depth as for the root pixmap.
+     * The associated kms fb will be created on demand once this pixmap
+     * is used as scanout by a crtc.
+     */
+
+    return pScreen->CreatePixmap(pScreen, width, height,
+                                rootpix->drawable.depth, 0);
+}
+
+static PixmapPtr
+crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
+{
+    return (PixmapPtr) data;
+}
+
+static void
+crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
+{
+    ScreenPtr pScreen = rotate_pixmap->drawable.pScreen;
+
+    pScreen->DestroyPixmap(rotate_pixmap);
+}
+
+
+/*
+ * Cursor functions
+ */
+
+static void
+crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
+{
+    /* XXX: See if this one is needed, as we only support ARGB cursors */
+}
+
+static void
+crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y);
+}
+
+static void
+crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    struct crtc_private *crtcp = crtc->driver_private;
+    unsigned char *ptr;
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    CursorPtr c = config->cursor;
+
+    if (vmwgfx_cursor_bypass(ms->fd, c->bits->xhot, c->bits->yhot) != 0) {
+       xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
+                  "Failed to set VMWare cursor bypass.\n");
+    }
+
+    if (!crtcp->cursor_bo) {
+       size_t size = 64*64*4;
+        crtcp->cursor_bo = vmwgfx_dmabuf_alloc(ms->fd, size);
+       if (!crtcp->cursor_bo)
+           return;
+       crtcp->cursor_handle = crtcp->cursor_bo->handle;
+    }
+
+    ptr = vmwgfx_dmabuf_map(crtcp->cursor_bo);
+    if (ptr) {
+       memcpy(ptr, image, 64*64*4);
+       vmwgfx_dmabuf_unmap(crtcp->cursor_bo);
+    }
+
+    if (crtc->cursor_shown)
+       drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
+                        crtcp->cursor_handle, 64, 64);
+
+    return;
+}
+
+static void
+crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
+{
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+
+    /* Older X servers have cursor reference counting bugs leading to use of
+     * freed memory and consequently random crashes. Should be fixed as of
+     * xserver 1.8, but this workaround shouldn't hurt anyway.
+     */
+    if (config->cursor)
+       config->cursor->refcnt++;
+
+    if (ms->cursor)
+       FreeCursor(ms->cursor, None);
+
+    ms->cursor = config->cursor;
+    crtc_load_cursor_argb_kms(crtc, image);
+}
+
+static void
+crtc_show_cursor(xf86CrtcPtr crtc)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    if (crtcp->cursor_bo)
+       drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
+                        crtcp->cursor_handle, 64, 64);
+}
+
+static void
+crtc_hide_cursor(xf86CrtcPtr crtc)
+{
+    modesettingPtr ms = modesettingPTR(crtc->scrn);
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0);
+}
+
+/**
+ * Called at vt leave
+ */
+void
+xorg_crtc_cursor_destroy(xf86CrtcPtr crtc)
+{
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    if (crtcp->cursor_bo) {
+       vmwgfx_dmabuf_destroy(crtcp->cursor_bo);
+       crtcp->cursor_bo = NULL;
+    }
+}
+
+/*
+ * Misc functions
+ */
+
+static void
+crtc_destroy(xf86CrtcPtr crtc)
+{
+    struct crtc_private *crtcp = crtc->driver_private;
+
+    xorg_crtc_cursor_destroy(crtc);
+
+    drmModeFreeCrtc(crtcp->drm_crtc);
+
+    free(crtcp);
+    crtc->driver_private = NULL;
+}
+
+static const xf86CrtcFuncsRec crtc_funcs = {
+    .dpms = crtc_dpms,
+    .set_mode_major = crtc_set_mode_major,
+
+    .set_cursor_colors = crtc_set_cursor_colors,
+    .set_cursor_position = crtc_set_cursor_position,
+    .show_cursor = crtc_show_cursor,
+    .hide_cursor = crtc_hide_cursor,
+    .load_cursor_argb = crtc_load_cursor_argb,
+
+    .shadow_create = crtc_shadow_create,
+    .shadow_allocate = crtc_shadow_allocate,
+    .shadow_destroy = crtc_shadow_destroy,
+
+    .gamma_set = crtc_gamma_set,
+    .destroy = crtc_destroy,
+};
+
+void
+xorg_crtc_init(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    xf86CrtcPtr crtc;
+    drmModeResPtr res;
+    drmModeCrtcPtr drm_crtc = NULL;
+    struct crtc_private *crtcp;
+    int c;
+
+    res = drmModeGetResources(ms->fd);
+    if (res == 0) {
+       ErrorF("Failed drmModeGetResources %d\n", errno);
+       return;
+    }
+
+    for (c = 0; c < res->count_crtcs; c++) {
+       drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]);
+
+       if (!drm_crtc)
+           continue;
+
+       crtc = xf86CrtcCreate(pScrn, &crtc_funcs);
+       if (crtc == NULL)
+           goto out;
+
+       crtcp = calloc(1, sizeof(struct crtc_private));
+       if (!crtcp) {
+           xf86CrtcDestroy(crtc);
+           goto out;
+       }
+
+       crtcp->drm_crtc = drm_crtc;
+
+       crtc->driver_private = crtcp;
+    }
+
+  out:
+    drmModeFreeResources(res);
+}
+
+PixmapPtr
+crtc_get_scanout(xf86CrtcPtr crtc)
+{
+    struct crtc_private *crtcp = crtc->driver_private;
+    return crtcp->scanout;
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/vmwgfx/vmwgfx_ctrl.c b/vmwgfx/vmwgfx_ctrl.c
new file mode 100644 (file)
index 0000000..5157f86
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2006-2011 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmwarectrl.c --
+ *
+ *      The implementation of the VMWARE_CTRL protocol extension that
+ *      allows X clients to communicate with the driver.
+ */
+
+#include <xorg-server.h>
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include <X11/X.h>
+#include <X11/extensions/panoramiXproto.h>
+
+#include "vmwarectrlproto.h"
+#include "xf86drm.h"
+#include "vmwgfx_driver.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlQueryVersion --
+ *
+ *      Implementation of QueryVersion command handler. Initialises and
+ *      sends a reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareCtrlQueryVersion(ClientPtr client)
+{
+   xVMwareCtrlQueryVersionReply rep = { 0, };
+   register int n;
+
+   REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
+
+   rep.type = X_Reply;
+   rep.length = 0;
+   rep.sequenceNumber = client->sequence;
+   rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION;
+   rep.minorVersion = VMWARE_CTRL_MINOR_VERSION;
+   if (client->swapped) {
+      swaps(&rep.sequenceNumber, n);
+      swapl(&rep.length, n);
+      swapl(&rep.majorVersion, n);
+      swapl(&rep.minorVersion, n);
+   }
+   WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep);
+
+   return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlDoSetRes --
+ *
+ *      Set the custom resolution into the mode list.
+ *
+ *      This is done by alternately updating one of two dynamic modes. It is
+ *      done this way because the server gets upset if you try to switch
+ *      to a new resolution that has the same index as the current one.
+ *
+ * Results:
+ *      TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ *      One dynamic mode will be updated if successful.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VMwareCtrlDoSetRes(ScrnInfoPtr pScrn,
+                   CARD32 x,
+                   CARD32 y)
+{
+#if 0
+   struct vmw_rect rect;
+   rect.x = 0;
+   rect.y = 0;
+   rect.w = x;
+   rect.h = y;
+
+   vmw_ioctl_update_layout(vmw, 1, &rect);
+#endif
+
+   return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlSetRes --
+ *
+ *      Implementation of SetRes command handler. Initialises and sends a
+ *      reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareCtrlSetRes(ClientPtr client)
+{
+   REQUEST(xVMwareCtrlSetResReq);
+   xVMwareCtrlSetResReply rep = { 0, };
+   ScrnInfoPtr pScrn;
+   ExtensionEntry *ext;
+   register int n;
+
+   REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
+
+   if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
+      return BadMatch;
+   }
+
+   pScrn = ext->extPrivate;
+   if (pScrn->scrnIndex != stuff->screen) {
+      return BadMatch;
+   }
+
+   if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y)) {
+      return BadValue;
+   }
+
+   rep.type = X_Reply;
+   rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2;
+   rep.sequenceNumber = client->sequence;
+   rep.screen = stuff->screen;
+   rep.x = stuff->x;
+   rep.y = stuff->y;
+   if (client->swapped) {
+      swaps(&rep.sequenceNumber, n);
+      swapl(&rep.length, n);
+      swapl(&rep.screen, n);
+      swapl(&rep.x, n);
+      swapl(&rep.y, n);
+   }
+   WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep);
+
+   return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlDoSetTopology --
+ *
+ *      Set the custom topology and set a dynamic mode to the bounding box
+ *      of the passed topology. If a topology is already pending, then do
+ *      nothing but do not return failure.
+ *
+ * Results:
+ *      TRUE on success, FALSE otherwise.
+ *
+ * Side effects:
+ *      One dynamic mode and the pending xinerama state will be updated if
+ *      successful.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn,
+                        xXineramaScreenInfo *extents,
+                        unsigned long number)
+{
+#if 0
+   struct vmw_rect *rects;
+   struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
+   int i;
+
+   rects = calloc(number, sizeof(*rects));
+   if (!rects)
+      return FALSE;
+
+   for (i = 0; i < number; i++) {
+      rects[i].x = extents[i].x_org;
+      rects[i].y = extents[i].y_org;
+      rects[i].w = extents[i].width;
+      rects[i].h = extents[i].height;
+   }
+
+   vmw_ioctl_update_layout(vmw, number, rects);
+
+   free(rects);
+#endif
+   return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlSetTopology --
+ *
+ *      Implementation of SetTopology command handler. Initialises and sends a
+ *      reply.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Writes reply to client
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareCtrlSetTopology(ClientPtr client)
+{
+   REQUEST(xVMwareCtrlSetTopologyReq);
+   xVMwareCtrlSetTopologyReply rep = { 0, };
+   ScrnInfoPtr pScrn;
+   ExtensionEntry *ext;
+   register int n;
+   xXineramaScreenInfo *extents;
+
+   REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq);
+
+   if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
+      return BadMatch;
+   }
+
+   pScrn = ext->extPrivate;
+   if (pScrn->scrnIndex != stuff->screen) {
+      return BadMatch;
+   }
+
+   extents = (xXineramaScreenInfo *)(stuff + 1);
+   if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) {
+      return BadValue;
+   }
+
+   rep.type = X_Reply;
+   rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2;
+   rep.sequenceNumber = client->sequence;
+   rep.screen = stuff->screen;
+   if (client->swapped) {
+      swaps(&rep.sequenceNumber, n);
+      swapl(&rep.length, n);
+      swapl(&rep.screen, n);
+   }
+   WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep);
+
+   return client->noClientException;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlDispatch --
+ *
+ *      Dispatcher for VMWARE_CTRL commands. Calls the correct handler for
+ *      each command type.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of individual command handlers.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VMwareCtrlDispatch(ClientPtr client)
+{
+   REQUEST(xReq);
+
+   switch(stuff->data) {
+   case X_VMwareCtrlQueryVersion:
+      return VMwareCtrlQueryVersion(client);
+   case X_VMwareCtrlSetRes:
+      return VMwareCtrlSetRes(client);
+   case X_VMwareCtrlSetTopology:
+      return VMwareCtrlSetTopology(client);
+   }
+   return BadRequest;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareCtrlQueryVersion --
+ *
+ *      Wrapper for QueryVersion handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareCtrlQueryVersion(ClientPtr client)
+{
+   register int n;
+
+   REQUEST(xVMwareCtrlQueryVersionReq);
+   REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
+
+   swaps(&stuff->length, n);
+
+   return VMwareCtrlQueryVersion(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareCtrlSetRes --
+ *
+ *      Wrapper for SetRes handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareCtrlSetRes(ClientPtr client)
+{
+   register int n;
+
+   REQUEST(xVMwareCtrlSetResReq);
+   REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
+
+   swaps(&stuff->length, n);
+   swapl(&stuff->screen, n);
+   swapl(&stuff->x, n);
+   swapl(&stuff->y, n);
+
+   return VMwareCtrlSetRes(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareCtrlSetTopology --
+ *
+ *      Wrapper for SetTopology handler that handles input from other-endian
+ *      clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of unswapped implementation.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareCtrlSetTopology(ClientPtr client)
+{
+   register int n;
+
+   REQUEST(xVMwareCtrlSetTopologyReq);
+   REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq);
+
+   swaps(&stuff->length, n);
+   swapl(&stuff->screen, n);
+   swapl(&stuff->number, n);
+   /* Each extent is a struct of shorts. */
+   SwapRestS(stuff);
+
+   return VMwareCtrlSetTopology(client);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * SVMwareCtrlDispatch --
+ *
+ *      Wrapper for dispatcher that handles input from other-endian clients.
+ *
+ * Results:
+ *      Standard response codes.
+ *
+ * Side effects:
+ *      Side effects of individual command handlers.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+SVMwareCtrlDispatch(ClientPtr client)
+{
+   REQUEST(xReq);
+
+   switch(stuff->data) {
+   case X_VMwareCtrlQueryVersion:
+      return SVMwareCtrlQueryVersion(client);
+   case X_VMwareCtrlSetRes:
+      return SVMwareCtrlSetRes(client);
+   case X_VMwareCtrlSetTopology:
+      return SVMwareCtrlSetTopology(client);
+   }
+   return BadRequest;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrlResetProc --
+ *
+ *      Cleanup handler called when the extension is removed.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VMwareCtrlResetProc(ExtensionEntry* extEntry)
+{
+   /* Currently, no cleanup is necessary. */
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMwareCtrl_ExitInit --
+ *
+ *      Initialiser for the VMWARE_CTRL protocol extension.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Protocol extension will be registered if successful.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+vmw_ctrl_ext_init(ScrnInfoPtr pScrn)
+{
+   ExtensionEntry *myext;
+
+   if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
+      if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0,
+                                 VMwareCtrlDispatch,
+                                 SVMwareCtrlDispatch,
+                                 VMwareCtrlResetProc,
+                                 StandardMinorOpcode))) {
+         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                    "Failed to add VMWARE_CTRL extension\n");
+        return;
+      }
+
+      /*
+       * For now, only support one screen as that's all the virtual
+       * hardware supports.
+       */
+      myext->extPrivate = pScrn;
+
+      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                 "Initialized VMWARE_CTRL extension version %d.%d\n",
+                 VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION);
+   }
+}
diff --git a/vmwgfx/vmwgfx_ctrl.h b/vmwgfx/vmwgfx_ctrl.h
new file mode 100644 (file)
index 0000000..8fedbce
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2006 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+/*
+ * vmwgfx_ctrl.h --
+ *
+ *      The definitions used by the VMWARE_CTRL protocol extension that
+ *      allows X clients to communicate with the driver.
+ */
+
+
+#ifndef _VMWGFX_CTRL_H_
+#define _VMWGFX_CTRL_H_
+
+#define VMWARE_CTRL_PROTOCOL_NAME "VMWARE_CTRL"
+
+#define VMWARE_CTRL_MAJOR_VERSION 0
+#define VMWARE_CTRL_MINOR_VERSION 2
+
+#define X_VMwareCtrlQueryVersion 0
+#define X_VMwareCtrlSetRes 1
+#define X_VMwareCtrlSetTopology 2
+
+#endif /* _VMW_CTRL_H_ */
diff --git a/vmwgfx/vmwgfx_dri2.c b/vmwgfx/vmwgfx_dri2.c
new file mode 100644 (file)
index 0000000..748cbc8
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ *
+ */
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "vmwgfx_driver.h"
+#include "../saa/saa.h"
+
+#include "dri2.h"
+#include "gcstruct.h"
+#include "gc.h"
+#include "vmwgfx_saa.h"
+
+struct vmwgfx_dri2_priv {
+    unsigned int srf_count;
+    struct xa_surface *srf[20];
+};
+
+DevPrivateKeyRec dri2_pixmap_index;
+DevPrivateKeyRec dri2_window_index;
+
+typedef struct {
+    int refcount;
+    PixmapPtr pPixmap;
+    struct xa_surface *srf;
+} *BufferPrivatePtr;
+
+static Bool
+dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int format)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    modesettingPtr ms = modesettingPTR(pScrn);
+    BufferPrivatePtr private = buffer->driverPrivate;
+    PixmapPtr pPixmap;
+    struct vmwgfx_saa_pixmap *vpix;
+    struct xa_surface *srf = NULL;
+    unsigned int cpp = 4;
+
+    if (pDraw->type == DRAWABLE_PIXMAP)
+       pPixmap = (PixmapPtr) pDraw;
+    else
+       pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw);
+
+    vpix = vmwgfx_saa_pixmap(pPixmap);
+    private->refcount = 0;
+
+    switch (buffer->attachment) {
+    default:
+       if (buffer->attachment != DRI2BufferFakeFrontLeft ||
+           &pPixmap->drawable != pDraw) {
+
+           pPixmap = (*pScreen->CreatePixmap)(pScreen,
+                                              pDraw->width,
+                                              pDraw->height,
+                                              pDraw->depth,
+                                              0);
+           if (pPixmap == NullPixmap)
+               return FALSE;
+
+           private->pPixmap = pPixmap;
+           vpix = vmwgfx_saa_pixmap(pPixmap);
+       }
+       break;
+    case DRI2BufferFrontLeft:
+      if (&pPixmap->drawable == pDraw)
+         break;
+      buffer->name = 0;
+      buffer->pitch = 0;
+      buffer->cpp = cpp;
+      buffer->driverPrivate = private;
+      buffer->flags = 0; /* not tiled */
+      buffer->format = 0;
+      if (!private->pPixmap) {
+       private->pPixmap = pPixmap;
+       pPixmap->refcnt++;
+      }
+      return TRUE;
+    case DRI2BufferStencil:
+    case DRI2BufferDepthStencil:
+       srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
+                               32, xa_type_zs, xa_format_unknown,
+                               XA_FLAG_SHARED );
+       if (!srf)
+           srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
+                                   32, xa_type_sz, xa_format_unknown,
+                                   XA_FLAG_SHARED );
+       if (!srf)
+           return FALSE;
+
+       break;
+    case DRI2BufferDepth:
+       srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
+                               (format) ? format: pDraw->depth,
+                               xa_type_z, xa_format_unknown,
+                               XA_FLAG_SHARED);
+       if (!srf)
+           return FALSE;
+       break;
+    }
+
+    if (!private->pPixmap) {
+       private->pPixmap = pPixmap;
+       pPixmap->refcnt++;
+    }
+
+    if (!srf) {
+       if (!vmwgfx_pixmap_validate_hw(pPixmap, NULL,
+                                      XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
+                                      0))
+           return FALSE;
+
+       srf = vpix->hw;
+
+       /*
+        * Compiz workaround. See vmwgfx_dirty();
+        */
+
+       vpix->hw_is_dri2_fronts++;
+       private->refcount++;
+    }
+
+    private->srf = srf;
+    if (xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0)
+       return FALSE;
+
+    buffer->cpp = cpp;
+    buffer->driverPrivate = private;
+    buffer->flags = 0; /* not tiled */
+    buffer->format = format;
+    private->refcount++;
+
+    return TRUE;
+}
+
+static void
+dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
+{
+    BufferPrivatePtr private = buffer->driverPrivate;
+    struct xa_surface *srf = private->srf;
+    ScreenPtr pScreen = pDraw->pScreen;
+
+    if (--private->refcount == 0 && srf) {
+       xa_surface_destroy(srf);
+    }
+
+    /*
+     * Compiz workaround. See vmwgfx_dirty();
+     */
+
+    if (private->refcount == 1) {
+       struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap);
+       if (--vpix->hw_is_dri2_fronts == 0)
+           vmwgfx_remove_dri2_list(vpix);
+    }
+
+    private->srf = NULL;
+    pScreen->DestroyPixmap(private->pPixmap);
+}
+
+
+static DRI2Buffer2Ptr
+dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format)
+{
+    DRI2Buffer2Ptr buffer;
+    BufferPrivatePtr private;
+
+    buffer = calloc(1, sizeof *buffer);
+    if (!buffer)
+       return NULL;
+
+    private = calloc(1, sizeof *private);
+    if (!private) {
+       goto fail;
+    }
+
+    buffer->attachment = attachment;
+    buffer->driverPrivate = private;
+
+    if (dri2_do_create_buffer(pDraw, buffer, format))
+       return buffer;
+
+    free(private);
+fail:
+    free(buffer);
+    return NULL;
+}
+
+static void
+dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
+{
+    /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
+    dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer);
+
+    free(buffer->driverPrivate);
+    free(buffer);
+}
+
+static void
+dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
+                 DRI2Buffer2Ptr pDestBuffer, DRI2Buffer2Ptr pSrcBuffer)
+{
+
+
+    ScreenPtr pScreen = pDraw->pScreen;
+    BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate;
+    BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate;
+    DrawablePtr src_draw;
+    DrawablePtr dst_draw;
+    RegionPtr myClip;
+    GCPtr gc;
+
+    if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
+       pDestBuffer->attachment == DRI2BufferFakeFrontLeft)
+      LogMessage(X_ERROR, "glxwaitx\n");
+
+    /*
+     * In driCreateBuffers we dewrap windows into the
+     * backing pixmaps in order to get to the texture.
+     * We need to use the real drawable in CopyArea
+     * so that cliprects and offsets are correct.
+     */
+    src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
+       &src_priv->pPixmap->drawable;
+    dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
+       &dst_priv->pPixmap->drawable;
+
+    /*
+     * The clients implements glXWaitX with a copy front to fake and then
+     * waiting on the server to signal its completion of it. While
+     * glXWaitGL is a client side flush and a copy from fake to front.
+     * This is how it is done in the DRI2 protocol, how ever depending
+     * which type of drawables the server does things a bit differently
+     * then what the protocol says as the fake and front are the same.
+     *
+     * for pixmaps glXWaitX is a server flush.
+     * for pixmaps glXWaitGL is a client flush.
+     * for windows glXWaitX is a copy from front to fake then a server flush.
+     * for windows glXWaitGL is a client flush then a copy from fake to front.
+     *
+     * XXX in the windows case this code always flushes but that isn't a
+     * must in the glXWaitGL case but we don't know if this is a glXWaitGL
+     * or a glFlush/glFinish call.
+     */
+    if (dst_priv->pPixmap == src_priv->pPixmap) {
+       /* pixmap glXWaitX */
+       if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
+           pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
+           LogMessage(X_INFO, "dri2 Validate hw.\n");
+           vmwgfx_pixmap_validate_hw(src_priv->pPixmap, NULL,
+                                     XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
+                                     0);
+           return;
+       }
+       /* pixmap glXWaitGL */
+       if (pDestBuffer->attachment == DRI2BufferFrontLeft &&
+           pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) {
+           return;
+       } else {
+           vmwgfx_flush_dri2(pScreen);
+           return;
+       }
+    }
+
+    gc = GetScratchGC(pDraw->depth, pScreen);
+    myClip = REGION_CREATE(pScreen, REGION_RECTS(pRegion),
+                          REGION_NUM_RECTS(pRegion));
+    (*gc->funcs->ChangeClip) (gc, CT_REGION, myClip, 0);
+    ValidateGC(dst_draw, gc);
+
+    /*
+     * Damage the src drawable in order for damageCopyArea to pick up
+     * that something changed.
+     */
+    DamageRegionAppend(src_draw, pRegion);
+    saa_drawable_dirty(src_draw, TRUE, pRegion);
+    DamageRegionProcessPending(src_draw);
+
+    /*
+     * Call CopyArea. This usually means a call to damageCopyArea that
+     * is wrapping saa_copy_area. The damageCopyArea function will make
+     * sure the destination drawable is appropriately damaged.
+     */
+    (*gc->ops->CopyArea)(src_draw, dst_draw, gc,
+                        0, 0, pDraw->width, pDraw->height, 0, 0);
+
+    /*
+     * FreeScratchGC will free myClip as well.
+     */
+    myClip = NULL;
+    FreeScratchGC(gc);
+}
+
+
+Bool
+xorg_dri2_init(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    modesettingPtr ms = modesettingPTR(pScrn);
+    DRI2InfoRec dri2info;
+    int major, minor;
+
+    if (xf86LoaderCheckSymbol("DRI2Version")) {
+       DRI2Version(&major, &minor);
+    } else {
+       /* Assume version 1.0 */
+       major = 1;
+       minor = 0;
+    }
+
+    if (!dixRegisterPrivateKey(&dri2_pixmap_index, PRIVATE_PIXMAP, 0)) {
+       LogMessage(X_ERROR, "Failed to register vmwgfx dri2 private.\n");
+       return FALSE;
+    }
+
+    if (!dixRegisterPrivateKey(&dri2_window_index, PRIVATE_WINDOW, 0)) {
+       LogMessage(X_ERROR, "Failed to register vmwgfx dri2 private.\n");
+       return FALSE;
+    }
+
+    dri2info.version = min(DRI2INFOREC_VERSION, 3);
+    dri2info.fd = ms->fd;
+
+    dri2info.driverName = pScrn->driverName;
+    dri2info.deviceName = "/dev/dri/card0"; /* FIXME */
+
+    dri2info.CreateBuffer = dri2_create_buffer;
+    dri2info.DestroyBuffer = dri2_destroy_buffer;
+
+    dri2info.CopyRegion = dri2_copy_region;
+    dri2info.Wait = NULL;
+
+    return DRI2ScreenInit(pScreen, &dri2info);
+}
+
+void
+xorg_dri2_close(ScreenPtr pScreen)
+{
+    DRI2CloseScreen(pScreen);
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/vmwgfx/vmwgfx_driver.c b/vmwgfx/vmwgfx_driver.c
new file mode 100644 (file)
index 0000000..edf384d
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+
+#include "xorg-server.h"
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "compiler.h"
+#include "xf86PciInfo.h"
+#include "xf86Pci.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include <X11/extensions/randr.h>
+#include "fb.h"
+#include "edid.h"
+#include "xf86i2c.h"
+#include "xf86Crtc.h"
+#include "miscstruct.h"
+#include "dixstruct.h"
+#include "xf86cmap.h"
+#include "xf86xv.h"
+#include "xorgVersion.h"
+#ifndef XSERVER_LIBPCIACCESS
+#error "libpciaccess needed"
+#endif
+
+#include <pciaccess.h>
+
+#include "vmwgfx_driver.h"
+
+#include <saa.h>
+#include "vmwgfx_saa.h"
+
+/*
+ * Some macros to deal with function wrapping.
+ */
+#define vmwgfx_wrap(priv, real, mem, func) {\
+       (priv)->saved_##mem = (real)->mem;      \
+       (real)->mem = func;                     \
+}
+
+#define vmwgfx_unwrap(priv, real, mem) {\
+       (real)->mem = (priv)->saved_##mem;      \
+}
+
+#define vmwgfx_swap(priv, real, mem) {\
+       void *tmp = (priv)->saved_##mem;                \
+       (priv)->saved_##mem = (real)->mem;      \
+       (real)->mem = tmp;                      \
+}
+
+/*
+ * Functions and symbols exported to Xorg via pointers.
+ */
+
+static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
+static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
+                           char **argv);
+static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
+static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
+static Bool drv_enter_vt(int scrnIndex, int flags);
+static void drv_leave_vt(int scrnIndex, int flags);
+static void drv_free_screen(int scrnIndex, int flags);
+static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
+                                int flags);
+
+extern void xorg_tracker_set_functions(ScrnInfoPtr scrn);
+extern const OptionInfoRec * xorg_tracker_available_options(int chipid,
+                                                          int busid);
+
+
+typedef enum
+{
+    OPTION_SW_CURSOR,
+    OPTION_2D_ACCEL,
+    OPTION_DEBUG_FALLBACK,
+    OPTION_THROTTLE_SWAP,
+    OPTION_THROTTLE_DIRTY,
+    OPTION_3D_ACCEL
+} drv_option_enums;
+
+static const OptionInfoRec drv_options[] = {
+    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_3D_ACCEL, "3DAccel", OPTV_BOOLEAN, {0}, FALSE},
+    {-1, NULL, OPTV_NONE, {0}, FALSE}
+};
+
+
+/*
+ * Exported Xorg driver functions to winsys
+ */
+
+const OptionInfoRec *
+xorg_tracker_available_options(int chipid, int busid)
+{
+    return drv_options;
+}
+
+void
+xorg_tracker_set_functions(ScrnInfoPtr scrn)
+{
+    scrn->PreInit = drv_pre_init;
+    scrn->ScreenInit = drv_screen_init;
+    scrn->SwitchMode = drv_switch_mode;
+    scrn->FreeScreen = drv_free_screen;
+    scrn->ValidMode = drv_valid_mode;
+}
+
+/*
+ * Internal function definitions
+ */
+
+static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
+
+/*
+ * Internal functions
+ */
+
+static Bool
+drv_get_rec(ScrnInfoPtr pScrn)
+{
+    if (pScrn->driverPrivate)
+       return TRUE;
+
+    pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec));
+
+    return TRUE;
+}
+
+static void
+drv_free_rec(ScrnInfoPtr pScrn)
+{
+    if (!pScrn)
+       return;
+
+    if (!pScrn->driverPrivate)
+       return;
+
+    free(pScrn->driverPrivate);
+
+    pScrn->driverPrivate = NULL;
+}
+
+static void
+drv_probe_ddc(ScrnInfoPtr pScrn, int index)
+{
+    ConfiguredMonitor = NULL;
+}
+
+static Bool
+drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    ScreenPtr pScreen = pScrn->pScreen;
+    int old_width, old_height;
+    PixmapPtr rootPixmap;
+
+    if (width == pScrn->virtualX && height == pScrn->virtualY)
+       return TRUE;
+
+    if (ms->check_fb_size) {
+       size_t size = width*(pScrn->bitsPerPixel / 8) * height + 1024;
+
+       if (size > ms->max_fb_size) {
+           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                      "Requested framebuffer size %dx%dx%d will not fit "
+                      "in display memory.\n",
+                      width, height, pScrn->bitsPerPixel);
+           return FALSE;
+       }
+    }
+
+    old_width = pScrn->virtualX;
+    old_height = pScrn->virtualY;
+    pScrn->virtualX = width;
+    pScrn->virtualY = height;
+
+    /* ms->create_front_buffer will remove the old front buffer */
+
+    rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    vmwgfx_disable_scanout(pScrn);
+    if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
+       goto error_modify;
+
+    pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
+
+    xf86SetDesiredModes(pScrn);
+    return TRUE;
+
+    /*
+     * FIXME: Try out this error recovery path and fix problems.
+
+     */
+    //error_create:
+    if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL))
+       FatalError("failed to resize rootPixmap error path\n");
+
+    pScrn->displayWidth = rootPixmap->devKind /
+       (rootPixmap->drawable.bitsPerPixel / 8);
+
+
+error_modify:
+    pScrn->virtualX = old_width;
+    pScrn->virtualY = old_height;
+
+    if (xf86SetDesiredModes(pScrn))
+       return FALSE;
+
+    FatalError("failed to setup old framebuffer\n");
+    return FALSE;
+}
+
+static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
+    .resize = drv_crtc_resize
+};
+
+static Bool
+drv_init_drm(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    /* deal with server regeneration */
+    if (ms->fd < 0) {
+       char *BusID;
+
+       BusID = malloc(64);
+       sprintf(BusID, "PCI:%d:%d:%d",
+               ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
+               ms->PciInfo->dev, ms->PciInfo->func
+           );
+
+
+       ms->fd = drmOpen("vmwgfx", BusID);
+       ms->isMaster = TRUE;
+       free(BusID);
+
+       if (ms->fd >= 0)
+           return TRUE;
+
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+static Bool
+drv_pre_init(ScrnInfoPtr pScrn, int flags)
+{
+    xf86CrtcConfigPtr xf86_config;
+    modesettingPtr ms;
+    rgb defaultWeight = { 0, 0, 0 };
+    EntityInfoPtr pEnt;
+    EntPtr msEnt = NULL;
+    Bool use3D;
+
+    if (pScrn->numEntities != 1)
+       return FALSE;
+
+    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+
+    if (flags & PROBE_DETECT) {
+       drv_probe_ddc(pScrn, pEnt->index);
+       return TRUE;
+    }
+
+    pScrn->driverPrivate = NULL;
+
+    /* Allocate driverPrivate */
+    if (!drv_get_rec(pScrn))
+       return FALSE;
+
+    ms = modesettingPTR(pScrn);
+    ms->pEnt = pEnt;
+
+    pScrn->displayWidth = 640;        /* default it */
+
+    if (ms->pEnt->location.type != BUS_PCI)
+       return FALSE;
+
+    ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
+
+    /* Allocate an entity private if necessary */
+    if (xf86IsEntityShared(pScrn->entityList[0])) {
+       FatalError("Entity");
+#if 0
+       msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
+                                    modesettingEntityIndex)->ptr;
+       ms->entityPrivate = msEnt;
+#else
+       (void)msEnt;
+#endif
+    } else
+       ms->entityPrivate = NULL;
+
+    if (xf86IsEntityShared(pScrn->entityList[0])) {
+       if (xf86IsPrimInitDone(pScrn->entityList[0])) {
+           /* do something */
+       } else {
+           xf86SetPrimInitDone(pScrn->entityList[0]);
+       }
+    }
+
+    ms->fd = -1;
+    if (!drv_init_drm(pScrn))
+       return FALSE;
+
+    ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0);
+
+    pScrn->monitor = pScrn->confScreen->monitor;
+    pScrn->progClock = TRUE;
+    pScrn->rgbBits = 8;
+
+    if (!xf86SetDepthBpp
+       (pScrn, 0, 0, 0,
+        PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
+       return FALSE;
+
+    switch (pScrn->depth) {
+    case 8:
+    case 15:
+    case 16:
+    case 24:
+       break;
+    default:
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                  "Given depth (%d) is not supported by the driver\n",
+                  pScrn->depth);
+       return FALSE;
+    }
+    xf86PrintDepthBpp(pScrn);
+
+    if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
+       return FALSE;
+    if (!xf86SetDefaultVisual(pScrn, -1))
+       return FALSE;
+
+    /* Process the options */
+    xf86CollectOptions(pScrn, NULL);
+    if (!(ms->Options = malloc(sizeof(drv_options))))
+       return FALSE;
+    memcpy(ms->Options, drv_options, sizeof(drv_options));
+    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
+
+    use3D = TRUE;
+    ms->from_3D = xf86GetOptValBool(ms->Options, OPTION_3D_ACCEL,
+                                   &use3D) ?
+       X_CONFIG : X_PROBED;
+
+    ms->no3D = !use3D;
+
+    /* Allocate an xf86CrtcConfig */
+    xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
+    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+
+    /* get max width and height */
+    {
+       drmModeResPtr res;
+       int max_width, max_height;
+
+       res = drmModeGetResources(ms->fd);
+       max_width = res->max_width;
+       max_height = res->max_height;
+
+#if 0 /* Gallium fix */
+       if (ms->screen) {
+           int max;
+
+           max = ms->screen->get_param(ms->screen,
+                                       PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
+           max = 1 << (max - 1);
+           max_width = max < max_width ? max : max_width;
+           max_height = max < max_height ? max : max_height;
+       }
+#endif
+
+       xf86CrtcSetSizeRange(pScrn, res->min_width,
+                            res->min_height, max_width, max_height);
+       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+                  "Min width %d, Max Width %d.\n",
+                  res->min_width, max_width);
+       xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+                  "Min height %d, Max Height %d.\n",
+                  res->min_height, max_height);
+       drmModeFreeResources(res);
+    }
+
+
+    if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
+       ms->SWCursor = TRUE;
+    }
+
+    xorg_crtc_init(pScrn);
+    xorg_output_init(pScrn);
+
+    if (!xf86InitialConfiguration(pScrn, TRUE)) {
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
+       return FALSE;
+    }
+
+    /*
+     * If the driver can do gamma correction, it should call xf86SetGamma() here.
+     */
+    {
+       Gamma zeros = { 0.0, 0.0, 0.0 };
+
+       if (!xf86SetGamma(pScrn, zeros)) {
+           return FALSE;
+       }
+    }
+
+    if (pScrn->modes == NULL) {
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
+       return FALSE;
+    }
+
+    pScrn->currentMode = pScrn->modes;
+
+    /* Set display resolution */
+    xf86SetDpi(pScrn, 0, 0);
+
+    /* Load the required sub modules */
+    if (!xf86LoadSubModule(pScrn, "fb"))
+       return FALSE;
+
+#ifdef DRI2
+    if (!xf86LoadSubModule(pScrn, "dri2"))
+       return FALSE;
+#endif
+
+    return TRUE;
+}
+
+static Bool
+vmwgfx_scanout_update(int drm_fd, int fb_id, RegionPtr dirty)
+{
+    unsigned num_cliprects = REGION_NUM_RECTS(dirty);
+    drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
+    BoxPtr rect = REGION_RECTS(dirty);
+    int i, ret;
+
+    if (!num_cliprects)
+       return TRUE;
+
+    for (i = 0; i < num_cliprects; i++, rect++) {
+       clip[i].x1 = rect->x1;
+       clip[i].y1 = rect->y1;
+       clip[i].x2 = rect->x2;
+       clip[i].y2 = rect->y2;
+    }
+
+    ret = drmModeDirtyFB(drm_fd, fb_id, clip, num_cliprects);
+    if (ret)
+       LogMessage(X_ERROR, "%s: failed to send dirty (%i, %s)\n",
+                  __func__, ret, strerror(-ret));
+    return (ret == 0);
+}
+
+static Bool
+vmwgfx_scanout_present(ScreenPtr pScreen, int drm_fd,
+                      struct vmwgfx_saa_pixmap *vpix,
+                      RegionPtr dirty)
+{
+    uint32_t handle;
+    unsigned int dummy;
+
+    if (!REGION_NOTEMPTY(pScreen, dirty))
+       return TRUE;
+
+    if (!vpix->hw) {
+       LogMessage(X_ERROR, "No surface to present from.\n");
+       return FALSE;
+    }
+
+    if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) {
+       LogMessage(X_ERROR, "Could not get present surface handle.\n");
+       return FALSE;
+    }
+
+    if (vmwgfx_present(drm_fd, 0, 0, dirty, handle) != 0) {
+       LogMessage(X_ERROR, "Could not get present surface handle.\n");
+       return FALSE;
+    }
+
+    return TRUE;
+}
+
+void xorg_flush(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    modesettingPtr ms = modesettingPTR(pScrn);
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+    PixmapPtr pixmap = NULL;
+    struct vmwgfx_saa_pixmap *vpix;
+    int i;
+    xf86CrtcPtr crtc;
+    PixmapPtr *pixmaps = calloc(config->num_crtc, sizeof(*pixmaps));
+    unsigned int num_scanout = 0;
+    unsigned int j;
+
+    if (!pixmaps) {
+       LogMessage(X_ERROR, "Failed memory allocation during screen "
+                  "update.\n");
+       return;
+    }
+
+    /*
+     * Get an array of pixmaps from which we scan out.
+     */
+    for (i=0; i<config->num_crtc; ++i) {
+       crtc = config->crtc[i];
+       if (crtc->enabled) {
+           pixmap = crtc_get_scanout(crtc);
+           if (pixmap) {
+               unsigned int j;
+
+               /*
+                * Remove duplicates.
+                */
+               for (j=0; j<num_scanout; ++j) {
+                   if (pixmap == pixmaps[j])
+                       break;
+               }
+
+               if (j == num_scanout)
+                   pixmaps[num_scanout++] = pixmap;
+           }
+       }
+    }
+
+    if (!num_scanout)
+       return;
+
+    for (j=0; j<num_scanout; ++j) {
+       pixmap = pixmaps[j];
+       vpix = vmwgfx_saa_pixmap(pixmap);
+
+       if (vpix->fb_id != -1) {
+           if (vpix->pending_update) {
+               (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id,
+                                            vpix->pending_update);
+               REGION_SUBTRACT(pScreen, vpix->dirty_present,
+                               vpix->dirty_present, vpix->pending_update);
+               REGION_EMPTY(pScreen, vpix->pending_update);
+           }
+           if (vpix->pending_present) {
+               (void) vmwgfx_scanout_present(pScreen, ms->fd, vpix,
+                                             vpix->pending_present);
+               REGION_SUBTRACT(pScreen, vpix->dirty_present,
+                               vpix->dirty_present, vpix->pending_present);
+               REGION_EMPTY(pScreen, vpix->pending_present);
+           }
+       }
+    }
+    free(pixmaps);
+}
+
+static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
+                              pointer pReadmask)
+{
+    ScreenPtr pScreen = screenInfo.screens[i];
+    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
+
+    vmwgfx_swap(ms, pScreen, BlockHandler);
+    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
+    vmwgfx_swap(ms, pScreen, BlockHandler);
+
+    xorg_flush(pScreen);
+}
+
+static Bool
+drv_create_screen_resources(ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    modesettingPtr ms = modesettingPTR(pScrn);
+    Bool ret;
+
+    vmwgfx_swap(ms, pScreen, CreateScreenResources);
+    ret = pScreen->CreateScreenResources(pScreen);
+    vmwgfx_swap(ms, pScreen, CreateScreenResources);
+
+    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+    return drv_enter_vt(pScreen->myNum, 1);
+}
+
+static Bool
+drv_set_master(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    if (!ms->isMaster && drmSetMaster(ms->fd) != 0) {
+       if (errno == EINVAL) {
+           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                      "drmSetMaster failed: 2.6.29 or newer kernel required for "
+                      "multi-server DRI\n");
+       } else {
+           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                      "drmSetMaster failed: %s\n", strerror(errno));
+       }
+       return FALSE;
+    }
+
+    ms->isMaster = TRUE;
+    return TRUE;
+}
+
+
+static void drv_load_palette(ScrnInfoPtr pScrn, int numColors,
+                            int *indices, LOCO *colors, VisualPtr pVisual)
+{
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+    modesettingPtr ms = modesettingPTR(pScrn);
+    int index, j, i;
+    int c;
+
+    switch(pScrn->depth) {
+    case 15:
+       for (i = 0; i < numColors; i++) {
+           index = indices[i];
+           for (j = 0; j < 8; j++) {
+               ms->lut_r[index * 8 + j] = colors[index].red << 8;
+               ms->lut_g[index * 8 + j] = colors[index].green << 8;
+               ms->lut_b[index * 8 + j] = colors[index].blue << 8;
+           }
+       }
+       break;
+    case 16:
+       for (i = 0; i < numColors; i++) {
+           index = indices[i];
+
+           if (index < 32) {
+               for (j = 0; j < 8; j++) {
+                   ms->lut_r[index * 8 + j] = colors[index].red << 8;
+                   ms->lut_b[index * 8 + j] = colors[index].blue << 8;
+               }
+           }
+
+           for (j = 0; j < 4; j++) {
+               ms->lut_g[index * 4 + j] = colors[index].green << 8;
+           }
+       }
+       break;
+    default:
+       for (i = 0; i < numColors; i++) {
+           index = indices[i];
+           ms->lut_r[index] = colors[index].red << 8;
+           ms->lut_g[index] = colors[index].green << 8;
+           ms->lut_b[index] = colors[index].blue << 8;
+       }
+       break;
+    }
+
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+       xf86CrtcPtr crtc = xf86_config->crtc[c];
+
+       /* Make the change through RandR */
+#ifdef RANDR_12_INTERFACE
+       if (crtc->randr_crtc)
+           RRCrtcGammaSet(crtc->randr_crtc, ms->lut_r, ms->lut_g, ms->lut_b);
+       else
+#endif
+           crtc->funcs->gamma_set(crtc, ms->lut_r, ms->lut_g, ms->lut_b, 256);
+    }
+}
+
+
+static Bool
+drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+{
+    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+    modesettingPtr ms = modesettingPTR(pScrn);
+    VisualPtr visual;
+
+    if (!drv_set_master(pScrn))
+       return FALSE;
+
+    pScrn->pScreen = pScreen;
+
+    /* HW dependent - FIXME */
+    pScrn->displayWidth = pScrn->virtualX;
+
+    miClearVisualTypes();
+
+    if (!miSetVisualTypes(pScrn->depth,
+                         miGetDefaultVisualMask(pScrn->depth),
+                         pScrn->rgbBits, pScrn->defaultVisual))
+       return FALSE;
+
+    if (!miSetPixmapDepths())
+       return FALSE;
+
+    pScrn->memPhysBase = 0;
+    pScrn->fbOffset = 0;
+
+    if (!fbScreenInit(pScreen, NULL,
+                     pScrn->virtualX, pScrn->virtualY,
+                     pScrn->xDpi, pScrn->yDpi,
+                     pScrn->displayWidth, pScrn->bitsPerPixel))
+       return FALSE;
+
+    if (pScrn->bitsPerPixel > 8) {
+       /* Fixup RGB ordering */
+       visual = pScreen->visuals + pScreen->numVisuals;
+       while (--visual >= pScreen->visuals) {
+           if ((visual->class | DynamicClass) == DirectColor) {
+               visual->offsetRed = pScrn->offset.red;
+               visual->offsetGreen = pScrn->offset.green;
+               visual->offsetBlue = pScrn->offset.blue;
+               visual->redMask = pScrn->mask.red;
+               visual->greenMask = pScrn->mask.green;
+               visual->blueMask = pScrn->mask.blue;
+           }
+       }
+    }
+
+    fbPictureInit(pScreen, NULL, 0);
+
+    vmwgfx_wrap(ms, pScreen, BlockHandler, drv_block_handler);
+    vmwgfx_wrap(ms, pScreen, CreateScreenResources,
+               drv_create_screen_resources);
+
+    xf86SetBlackWhitePixels(pScreen);
+
+    ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
+    ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
+
+    vmw_ctrl_ext_init(pScrn);
+
+    ms->xat = xa_tracker_create(ms->fd);
+    if (!ms->xat)
+       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                  "Failed to initialize Gallium3D Xa. No 3D available.\n");
+
+    if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush)) {
+       FatalError("Failed to initialize SAA.\n");
+    }
+
+#ifdef DRI2
+    ms->dri2_available = FALSE;
+    if (ms->xat) {
+       ms->dri2_available = xorg_dri2_init(pScreen);
+       if (!ms->dri2_available)
+           xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                      "Failed to initialize DRI2. "
+                      "No direct rendring available.\n");
+    }
+#endif
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "#################################\n");
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Useful debugging info follows #\n");
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "#################################\n");
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using libkms backend.\n");
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s.\n",
+              ms->accelerate_2d ? "enabled" : "disabled");
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s.\n",
+              ms->debug_fallback ? "enabled" : "disabled");
+#ifdef DRI2
+    xf86DrvMsg(pScrn->scrnIndex, ms->from_3D, "3D Acceleration is disabled.\n");
+#else
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled.\n");
+#endif
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
+
+    miInitializeBackingStore(pScreen);
+    xf86SetBackingStore(pScreen);
+    xf86SetSilkenMouse(pScreen);
+    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+    /* Need to extend HWcursor support to handle mask interleave */
+    if (!ms->SWCursor)
+       xf86_cursors_init(pScreen, 64, 64,
+                         HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
+                         HARDWARE_CURSOR_ARGB |
+                         HARDWARE_CURSOR_UPDATE_UNHIDDEN);
+
+    /* Must force it before EnterVT, so we are in control of VT and
+     * later memory should be bound when allocating, e.g rotate_mem */
+    pScrn->vtSema = TRUE;
+
+    pScreen->SaveScreen = xf86SaveScreen;
+    vmwgfx_wrap(ms, pScreen, CloseScreen, drv_close_screen);
+
+    if (!xf86CrtcScreenInit(pScreen))
+       return FALSE;
+
+    if (!miCreateDefColormap(pScreen))
+       return FALSE;
+    if (!xf86HandleColormaps(pScreen, 256, 8, drv_load_palette, NULL,
+                            CMAP_PALETTED_TRUECOLOR |
+                            CMAP_RELOAD_ON_MODE_SWITCH))
+       return FALSE;
+
+    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+    if (serverGeneration == 1)
+       xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+
+
+    vmwgfx_wrap(ms, pScrn, EnterVT, drv_enter_vt);
+    vmwgfx_wrap(ms, pScrn, LeaveVT, drv_leave_vt);
+    vmwgfx_wrap(ms, pScrn, AdjustFrame, drv_adjust_frame);
+
+    /*
+     * Must be called _after_ function wrapping.
+     */
+    xorg_xv_init(pScreen);
+
+    return TRUE;
+}
+
+static void
+drv_adjust_frame(int scrnIndex, int x, int y, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+    xf86OutputPtr output = config->output[config->compat_output];
+    xf86CrtcPtr crtc = output->crtc;
+
+    if (crtc && crtc->enabled) {
+      //       crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
+      //                                   RR_Rotate_0, x, y);
+       crtc->x = output->initial_x + x;
+       crtc->y = output->initial_y + y;
+    }
+}
+
+static void
+drv_free_screen(int scrnIndex, int flags)
+{
+    drv_free_rec(xf86Screens[scrnIndex]);
+}
+
+static void
+drv_leave_vt(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    vmwgfx_cursor_bypass(ms->fd, 0, 0);
+    vmwgfx_disable_scanout(pScrn);
+
+    if (drmDropMaster(ms->fd))
+       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                  "drmDropMaster failed: %s\n", strerror(errno));
+
+    ms->isMaster = FALSE;
+    pScrn->vtSema = FALSE;
+}
+
+/*
+ * This gets called when gaining control of the VT, and from ScreenInit().
+ */
+static Bool
+drv_enter_vt(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+    if (!drv_set_master(pScrn))
+       return FALSE;
+
+    if (!xf86SetDesiredModes(pScrn))
+       return FALSE;
+
+    return TRUE;
+}
+
+static Bool
+drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
+}
+
+static Bool
+drv_close_screen(int scrnIndex, ScreenPtr pScreen)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    if (ms->cursor) {
+       FreeCursor(ms->cursor, None);
+       ms->cursor = NULL;
+    }
+
+#ifdef DRI2
+    if (ms->dri2_available)
+       xorg_dri2_close(pScreen);
+#endif
+
+    if (pScrn->vtSema)
+       pScrn->LeaveVT(scrnIndex, 0);
+
+    pScrn->vtSema = FALSE;
+
+    vmwgfx_unwrap(ms, pScrn, EnterVT);
+    vmwgfx_unwrap(ms, pScrn, LeaveVT);
+    vmwgfx_unwrap(ms, pScrn, AdjustFrame);
+    vmwgfx_unwrap(ms, pScreen, CloseScreen);
+    vmwgfx_unwrap(ms, pScreen, BlockHandler);
+    vmwgfx_unwrap(ms, pScreen, CreateScreenResources);
+
+    if (ms->xat)
+       xa_tracker_destroy(ms->xat);
+
+    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
+}
+
+static ModeStatus
+drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+{
+    return MODE_OK;
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/vmwgfx/vmwgfx_driver.h b/vmwgfx/vmwgfx_driver.h
new file mode 100644 (file)
index 0000000..4339fb7
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright n<otice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifndef _VMWGFX_DRIVER_H_
+#define _VMWGFX_DRIVER_H_
+
+
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+#include <drm.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <xorg-server.h>
+#include <xf86.h>
+#include <xf86Crtc.h>
+#include <xf86xv.h>
+#include <xa_tracker.h>
+
+#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg);
+#define debug_printf(...)
+
+typedef struct
+{
+    int lastInstance;
+    int refCount;
+    ScrnInfoPtr pScrn_1;
+    ScrnInfoPtr pScrn_2;
+} EntRec, *EntPtr;
+
+#define XORG_NR_FENCES 3
+
+enum xorg_throttling_reason {
+    THROTTLE_RENDER,
+    THROTTLE_SWAP
+};
+
+typedef struct _modesettingRec
+{
+    /* drm */
+    int fd;
+
+    /* X */
+    EntPtr entityPrivate;
+
+    int Chipset;
+    EntityInfoPtr pEnt;
+    struct pci_device *PciInfo;
+
+    /* Accel */
+    Bool accelerate_2d;
+    Bool debug_fallback;
+
+    Bool noAccel;
+    Bool SWCursor;
+    CursorPtr cursor;
+    Bool no3D;
+    Bool from_3D;
+    Bool isMaster;
+
+    /* Broken-out options. */
+    OptionInfoPtr Options;
+
+    ScreenBlockHandlerProcPtr saved_BlockHandler;
+    CreateScreenResourcesProcPtr saved_CreateScreenResources;
+    CloseScreenProcPtr saved_CloseScreen;
+    Bool (*saved_EnterVT)(int, int);
+    void (*saved_LeaveVT)(int, int);
+    void (*saved_AdjustFrame)(int, int, int, int);
+
+    uint16_t lut_r[256], lut_g[256], lut_b[256];
+
+    Bool check_fb_size;
+    size_t max_fb_size;
+
+    struct xa_tracker *xat;
+#ifdef DRI2
+    Bool dri2_available;
+#endif
+} modesettingRec, *modesettingPtr;
+
+#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate))
+
+void xorg_flush(ScreenPtr pScreen);
+/***********************************************************************
+ * xorg_dri2.c
+ */
+Bool
+xorg_dri2_init(ScreenPtr pScreen);
+
+void
+xorg_dri2_close(ScreenPtr pScreen);
+
+
+/***********************************************************************
+ * xorg_crtc.c
+ */
+void
+xorg_crtc_init(ScrnInfoPtr pScrn);
+
+void
+xorg_crtc_cursor_destroy(xf86CrtcPtr crtc);
+
+void
+vmwgfx_disable_scanout(ScrnInfoPtr pScrn);
+
+PixmapPtr
+crtc_get_scanout(xf86CrtcPtr crtc);
+
+
+/***********************************************************************
+ * xorg_output.c
+ */
+void
+xorg_output_init(ScrnInfoPtr pScrn);
+
+unsigned
+xorg_output_get_id(xf86OutputPtr output);
+
+
+/***********************************************************************
+ * xorg_xv.c
+ */
+void
+xorg_xv_init(ScreenPtr pScreen);
+
+XF86VideoAdaptorPtr
+vmw_video_init_adaptor(ScrnInfoPtr pScrn);
+void
+vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports);
+
+int
+vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
+              RegionPtr region, uint32_t handle);
+
+void
+vmw_ctrl_ext_init(ScrnInfoPtr pScrn);
+
+#endif /* _XORG_TRACKER_H_ */
diff --git a/vmwgfx/vmwgfx_drmi.c b/vmwgfx/vmwgfx_drmi.c
new file mode 100644 (file)
index 0000000..3add305
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <drm/vmwgfx_drm.h>
+#include <xf86drm.h>
+#include "vmwgfx_drmi.h"
+
+#define uint32 uint32_t
+#define int32 int32_t
+#define uint16 uint16_t
+#define uint8 uint8_t
+
+#include "svga3d_reg.h"
+#include "vmwgfx_driver.h"
+
+static int
+vmwgfx_fence_wait(int drm_fd, uint64_t seq)
+{
+       struct drm_vmw_fence_wait_arg farg;
+       memset(&farg, 0, sizeof(farg));
+
+       farg.sequence = seq;
+       farg.cookie_valid = 0;
+
+       return drmCommandWriteRead(drm_fd, DRM_VMW_FENCE_WAIT, &farg,
+                                  sizeof(farg));
+}
+
+int
+vmwgfx_present_readback(int drm_fd, RegionPtr region)
+{
+    BoxPtr clips = REGION_RECTS(region);
+    unsigned int num_clips = REGION_NUM_RECTS(region);
+    struct drm_vmw_execbuf_arg arg;
+    struct drm_vmw_fence_rep rep;
+    int ret;
+    unsigned int size;
+    unsigned i;
+    SVGA3dRect *cr;
+
+    struct {
+       SVGA3dCmdHeader header;
+       SVGA3dRect cr;
+    } *cmd;
+
+    if (num_clips == 0)
+       return 0;
+
+    size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr);
+    cmd = malloc(size);
+    if (!cmd)
+       return -1;
+
+    cmd->header.id = SVGA_3D_CMD_PRESENT_READBACK;
+    cmd->header.size = num_clips * sizeof(cmd->cr);
+
+    for (i=0, cr = &cmd->cr; i < num_clips; i++, cr++, clips++) {
+       cr->x = (uint16_t) clips->x1;
+       cr->y = (uint16_t) clips->y1;
+       cr->w = (uint16_t) (clips->x2 - clips->x1);
+       cr->h = (uint16_t) (clips->y2 - clips->y1);
+#if 0
+       LogMessage(X_INFO,
+                  "Readback x: %u y: %u srcx: %u srcy: %u w: %u h: %u\n",
+                  cr->x, cr->y, cr->x, cr->y, cr->w, cr->h);
+#endif
+    }
+
+
+    memset(&arg, 0, sizeof(arg));
+    memset(&rep, 0, sizeof(rep));
+
+    rep.error = -EFAULT;
+    arg.fence_rep = (unsigned long)&rep;
+    arg.commands = (unsigned long)cmd;
+    arg.command_size = size;
+    arg.throttle_us = 0;
+
+    ret = drmCommandWrite(drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
+    if (ret)
+       LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret));
+
+    free(cmd);
+
+    /*
+     * Sync to avoid racing with Xorg SW rendering.
+     */
+
+    if (rep.error == 0) {
+       ret = vmwgfx_fence_wait(drm_fd, rep.fence_seq);
+       if (ret)
+           LogMessage(X_ERROR, "Present readback fence wait error %s.\n",
+                      strerror(-ret));
+    }
+
+    return 0;
+}
+
+int
+vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
+              RegionPtr region, uint32_t handle)
+{
+    BoxPtr clips = REGION_RECTS(region);
+    unsigned int num_clips = REGION_NUM_RECTS(region);
+    struct drm_vmw_execbuf_arg arg;
+    struct drm_vmw_fence_rep rep;
+    int ret;
+    unsigned int size;
+    unsigned i;
+    SVGA3dCopyRect *cr;
+
+    struct {
+       SVGA3dCmdHeader header;
+       SVGA3dCmdPresent body;
+       SVGA3dCopyRect cr;
+    } *cmd;
+
+    if (num_clips == 0)
+       return 0;
+
+    size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr);
+    cmd = malloc(size);
+    if (!cmd)
+       return -1;
+
+    cmd->header.id = SVGA_3D_CMD_PRESENT;
+    cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cr);
+    cmd->body.sid = handle;
+
+
+    for (i=0, cr = &cmd->cr; i < num_clips; i++, cr++, clips++) {
+       cr->x = (uint16_t) clips->x1 + dst_x;
+       cr->y = (uint16_t) clips->y1 + dst_y;
+       cr->srcx = (uint16_t) clips->x1;
+       cr->srcy = (uint16_t) clips->y1;
+       cr->w = (uint16_t) (clips->x2 - clips->x1);
+       cr->h = (uint16_t) (clips->y2 - clips->y1);
+#if 0
+       LogMessage(X_INFO, "Present: x: %u y: %u srcx: %u srcy: %u w: %u h: %u\n",
+                  cr->x, cr->y, cr->srcx, cr->srcy, cr->w, cr->h);
+#endif
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    memset(&rep, 0, sizeof(rep));
+
+    rep.error = -EFAULT;
+    arg.fence_rep = (unsigned long)&rep;
+    arg.commands = (unsigned long)cmd;
+    arg.command_size = size;
+    arg.throttle_us = 0;
+
+    ret = drmCommandWrite(drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
+    if (ret) {
+       LogMessage(X_ERROR, "Present error %s.\n", strerror(-ret));
+    }
+
+    free(cmd);
+    return 0;
+}
+
+struct vmwgfx_int_dmabuf {
+    struct vmwgfx_dmabuf buf;
+    uint64_t map_handle;
+    uint64_t sync_handle;
+    int sync_valid;
+    int drm_fd;
+    uint32_t map_count;
+    void *addr;
+};
+
+static inline struct vmwgfx_int_dmabuf *
+vmwgfx_int_dmabuf(struct vmwgfx_dmabuf *buf)
+{
+    return (struct vmwgfx_int_dmabuf *) buf;
+}
+
+struct vmwgfx_dmabuf*
+vmwgfx_dmabuf_alloc(int drm_fd, size_t size)
+{
+    union drm_vmw_alloc_dmabuf_arg arg;
+    struct vmwgfx_dmabuf *buf;
+    struct vmwgfx_int_dmabuf *ibuf;
+    int ret;
+
+    ibuf = calloc(1, sizeof(*ibuf));
+    if (!ibuf)
+       return NULL;
+
+    buf = &ibuf->buf;
+    memset(&arg, 0, sizeof(arg));
+    arg.req.size = size;
+
+    ret = drmCommandWriteRead(drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
+                             sizeof(arg));
+    if (ret)
+       goto out_kernel_fail;
+
+    ibuf = vmwgfx_int_dmabuf(buf);
+    ibuf->map_handle = arg.rep.map_handle;
+    ibuf->drm_fd = drm_fd;
+    buf->handle = arg.rep.handle;
+    buf->gmr_id = arg.rep.cur_gmr_id;
+    buf->gmr_offset = arg.rep.cur_gmr_offset;
+    buf->size = size;
+
+    return buf;
+  out_kernel_fail:
+    free(buf);
+    return NULL;
+}
+
+void *
+vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf)
+{
+    struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
+
+    if (ibuf->addr)
+       return ibuf->addr;
+
+    ibuf->addr =  mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+                      ibuf->drm_fd, ibuf->map_handle);
+
+    if (ibuf->addr == MAP_FAILED) {
+       ibuf->addr = NULL;
+       return NULL;
+    }
+
+    ibuf->map_count++;
+    return ibuf->addr;
+}
+
+void
+vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf)
+{
+    struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
+
+    if (--ibuf->map_count)
+       return;
+
+    /*
+     * It's a pretty important performance optimzation not to call
+     * munmap here, although we should watch out for cases where we might fill
+     * the virtual memory space of the process.
+     */
+}
+
+void
+vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf)
+{
+    struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
+    struct drm_vmw_unref_dmabuf_arg arg;
+
+    if (ibuf->addr) {
+       munmap(ibuf->addr, buf->size);
+       ibuf->addr = NULL;
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    arg.handle = buf->handle;
+
+    (void) drmCommandWrite(ibuf->drm_fd, DRM_VMW_UNREF_DMABUF, &arg,
+                          sizeof(arg));
+    free(buf);
+}
+
+int
+vmwgfx_dma(unsigned int host_x, unsigned int host_y,
+          RegionPtr region, struct vmwgfx_dmabuf *buf,
+          uint32_t buf_pitch, uint32_t surface_handle, int to_surface)
+{
+    BoxPtr clips = REGION_RECTS(region);
+    unsigned int num_clips = REGION_NUM_RECTS(region);
+    struct drm_vmw_execbuf_arg arg;
+    struct drm_vmw_fence_rep rep;
+    int ret;
+    unsigned int size;
+    unsigned i;
+    SVGA3dCopyBox *cb;
+    SVGA3dCmdSurfaceDMASuffix *suffix;
+    SVGA3dCmdSurfaceDMA *body;
+    struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
+
+    struct {
+       SVGA3dCmdHeader header;
+       SVGA3dCmdSurfaceDMA body;
+       SVGA3dCopyBox cb;
+    } *cmd;
+
+    if (num_clips == 0)
+       return 0;
+
+    size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cb) +
+       sizeof(*suffix);
+    cmd = malloc(size);
+    if (!cmd)
+       return -1;
+
+    cmd->header.id = SVGA_3D_CMD_SURFACE_DMA;
+    cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cb) +
+       sizeof(*suffix);
+    cb = &cmd->cb;
+
+    suffix = (SVGA3dCmdSurfaceDMASuffix *) &cb[num_clips];
+    suffix->suffixSize = sizeof(*suffix);
+    suffix->maximumOffset = (uint32_t) -1;
+    suffix->flags.discard = 0;
+    suffix->flags.unsynchronized = 0;
+    suffix->flags.reserved = 0;
+
+    body = &cmd->body;
+    body->guest.ptr.gmrId = buf->gmr_id;
+    body->guest.ptr.offset = buf->gmr_offset;
+    body->guest.pitch = buf_pitch;
+    body->host.sid = surface_handle;
+    body->host.face = 0;
+    body->host.mipmap = 0;
+
+    body->transfer =  (to_surface ? SVGA3D_WRITE_HOST_VRAM :
+                      SVGA3D_READ_HOST_VRAM);
+
+
+    for (i=0; i < num_clips; i++, cb++, clips++) {
+       cb->x = (uint16_t) clips->x1 + host_x;
+       cb->y = (uint16_t) clips->y1 + host_y;
+       cb->z = 0;
+       cb->srcx = (uint16_t) clips->x1;
+       cb->srcy = (uint16_t) clips->y1;
+       cb->srcz = 0;
+       cb->w = (uint16_t) (clips->x2 - clips->x1);
+       cb->h = (uint16_t) (clips->y2 - clips->y1);
+       cb->d = 1;
+#if 0
+       LogMessage(X_INFO, "DMA! x: %u y: %u srcx: %u srcy: %u w: %u h: %u %s\n",
+                  cb->x, cb->y, cb->srcx, cb->srcy, cb->w, cb->h,
+                  to_surface ? "to" : "from");
+#endif
+
+    }
+
+    memset(&arg, 0, sizeof(arg));
+    memset(&rep, 0, sizeof(rep));
+
+    rep.error = -EFAULT;
+    arg.fence_rep = (unsigned long)&rep;
+    arg.commands = (unsigned long)cmd;
+    arg.command_size = size;
+    arg.throttle_us = 0;
+
+    ret = drmCommandWrite(ibuf->drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
+    if (ret) {
+       LogMessage(X_ERROR, "DMA error %s.\n", strerror(-ret));
+    }
+
+    free(cmd);
+
+    if (!to_surface && rep.error == 0) {
+       ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.fence_seq);
+       if (ret)
+           LogMessage(X_ERROR, "DMA from host fence wait error %s.\n",
+                      strerror(-ret));
+    }
+
+    return 0;
+}
+
+static int
+vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out)
+{
+    struct drm_vmw_getparam_arg gp_arg;
+    int ret;
+
+    memset(&gp_arg, 0, sizeof(gp_arg));
+    gp_arg.param = param;
+    ret = drmCommandWriteRead(drm_fd, DRM_VMW_GET_PARAM,
+           &gp_arg, sizeof(gp_arg));
+
+    if (ret == 0) {
+       *out = gp_arg.value;
+    }
+
+    return ret;
+}
+
+int
+vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree)
+{
+    uint64_t v1, v2;
+    int ret;
+
+    ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_STREAMS, &v1);
+    if (ret)
+       return ret;
+
+    ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_FREE_STREAMS, &v2);
+    if (ret)
+       return ret;
+
+    *ntot = (uint32_t)v1;
+    *nfree = (uint32_t)v2;
+
+    return 0;
+}
+
+int
+vmwgfx_claim_stream(int drm_fd, uint32_t *out)
+{
+    struct drm_vmw_stream_arg s_arg;
+    int ret;
+
+    ret = drmCommandRead(drm_fd, DRM_VMW_CLAIM_STREAM,
+                        &s_arg, sizeof(s_arg));
+
+    if (ret)
+       return -1;
+
+    *out = s_arg.stream_id;
+    return 0;
+}
+
+int
+vmwgfx_unref_stream(int drm_fd, uint32_t stream_id)
+{
+    struct drm_vmw_stream_arg s_arg;
+    int ret;
+
+    memset(&s_arg, 0, sizeof(s_arg));
+    s_arg.stream_id = stream_id;
+
+    ret = drmCommandWrite(drm_fd, DRM_VMW_UNREF_STREAM,
+                         &s_arg, sizeof(s_arg));
+
+    return 0;
+}
+
+int
+vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot)
+{
+    struct drm_vmw_cursor_bypass_arg arg;
+    int ret;
+
+    memset(&arg, 0, sizeof(arg));
+    arg.flags = DRM_VMW_CURSOR_BYPASS_ALL;
+    arg.xhot = xhot;
+    arg.yhot = yhot;
+
+    ret = drmCommandWrite(drm_fd, DRM_VMW_CURSOR_BYPASS,
+                         &arg, sizeof(arg));
+
+    return ret;
+}
+
+int
+vmwgfx_max_fb_size(int drm_fd, size_t *size)
+{
+    drmVersionPtr ver;
+    int ret = -1;
+    uint64_t tmp_size;
+
+    ver = drmGetVersion(drm_fd);
+    if (ver == NULL ||
+       !(ver->version_major > 1 ||
+         (ver->version_major == 1 && ver->version_minor >= 3)))
+       goto out;
+
+    if (vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_MAX_FB_SIZE, &tmp_size) != 0)
+       goto out;
+
+    *size = tmp_size;
+    ret = 0;
+
+  out:
+    drmFreeVersion(ver);
+    return ret;
+}
diff --git a/vmwgfx/vmwgfx_drmi.h b/vmwgfx/vmwgfx_drmi.h
new file mode 100644 (file)
index 0000000..0c92719
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifndef _VMWGFX_DRMI_H_
+#define _VMWGFX_DRMI_H_
+
+#include <xorg-server.h>
+#include <regionstr.h>
+#include <stdint.h>
+
+struct vmwgfx_dma_ctx;
+
+extern int
+vmwgfx_present_readback(int drm_fd, RegionPtr region);
+
+extern int
+vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
+              RegionPtr region, uint32_t handle);
+
+struct vmwgfx_dmabuf {
+  uint32_t handle;
+  uint32_t gmr_id;
+  uint32_t gmr_offset;
+  size_t size;
+};
+
+extern struct vmwgfx_dmabuf*
+vmwgfx_dmabuf_alloc(int drm_fd, size_t size);
+extern void
+vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf);
+extern void *
+vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf);
+extern void
+vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf);
+
+extern int
+vmwgfx_dma(unsigned int host_x, unsigned int host_y,
+          RegionPtr region, struct vmwgfx_dmabuf *buf,
+          uint32_t buf_pitch, uint32_t surface_handle, int to_surface);
+
+extern int
+vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree);
+
+extern int
+vmwgfx_claim_stream(int drm_fd, uint32_t *out);
+
+extern int
+vmwgfx_unref_stream(int drm_fd, uint32_t stream_id);
+
+int
+vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot);
+
+int
+vmwgfx_max_fb_size(int drm_fd, size_t *size);
+
+#endif
diff --git a/vmwgfx/vmwgfx_output.c b/vmwgfx/vmwgfx_output.c
new file mode 100644 (file)
index 0000000..2081f2a
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ * Author: Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ */
+
+#include "xorg-server.h"
+#include <xf86.h>
+#include <xf86i2c.h>
+#include <xf86Crtc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef HAVE_XEXTPROTO_71
+#include <X11/extensions/dpmsconst.h>
+#else
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+#endif
+
+#include "vmwgfx_driver.h"
+
+struct output_private
+{
+    drmModeConnectorPtr drm_connector;
+
+    int c;
+};
+
+static char *output_enum_list[] = {
+    "Unknown",
+    "VGA",
+    "DVI",
+    "DVI",
+    "DVI",
+    "Composite",
+    "SVIDEO",
+    "LVDS",
+    "CTV",
+    "DIN",
+    "DP",
+    "HDMI",
+    "HDMI",
+};
+
+static void
+output_create_resources(xf86OutputPtr output)
+{
+#ifdef RANDR_12_INTERFACE
+#endif /* RANDR_12_INTERFACE */
+}
+
+static void
+output_dpms(xf86OutputPtr output, int mode)
+{
+}
+
+static xf86OutputStatus
+output_detect(xf86OutputPtr output)
+{
+    modesettingPtr ms = modesettingPTR(output->scrn);
+    struct output_private *priv = output->driver_private;
+    drmModeConnectorPtr drm_connector;
+    xf86OutputStatus status;
+
+    drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
+    if (drm_connector) {
+       drmModeFreeConnector(priv->drm_connector);
+       priv->drm_connector = drm_connector;
+    } else {
+       drm_connector = priv->drm_connector;
+    }
+
+    switch (drm_connector->connection) {
+    case DRM_MODE_CONNECTED:
+       status = XF86OutputStatusConnected;
+       break;
+    case DRM_MODE_DISCONNECTED:
+       status = XF86OutputStatusDisconnected;
+       break;
+    default:
+       status = XF86OutputStatusUnknown;
+    }
+
+    return status;
+}
+
+static DisplayModePtr
+output_get_modes(xf86OutputPtr output)
+{
+    struct output_private *priv = output->driver_private;
+    drmModeConnectorPtr drm_connector = priv->drm_connector;
+    drmModeModeInfoPtr drm_mode = NULL;
+    DisplayModePtr modes = NULL, mode = NULL;
+    int i;
+
+    for (i = 0; i < drm_connector->count_modes; i++) {
+       drm_mode = &drm_connector->modes[i];
+       if (drm_mode) {
+           mode = calloc(1, sizeof(DisplayModeRec));
+           if (!mode)
+               continue;
+           mode->Clock = drm_mode->clock;
+           mode->HDisplay = drm_mode->hdisplay;
+           mode->HSyncStart = drm_mode->hsync_start;
+           mode->HSyncEnd = drm_mode->hsync_end;
+           mode->HTotal = drm_mode->htotal;
+           mode->VDisplay = drm_mode->vdisplay;
+           mode->VSyncStart = drm_mode->vsync_start;
+           mode->VSyncEnd = drm_mode->vsync_end;
+           mode->VTotal = drm_mode->vtotal;
+           mode->Flags = drm_mode->flags;
+           mode->HSkew = drm_mode->hskew;
+           mode->VScan = drm_mode->vscan;
+           mode->VRefresh = xf86ModeVRefresh(mode);
+           mode->Private = (void *)drm_mode;
+           mode->type = 0;
+           if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
+               mode->type |= M_T_PREFERRED;
+           if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
+               mode->type |= M_T_DRIVER;
+           xf86SetModeDefaultName(mode);
+           modes = xf86ModesAdd(modes, mode);
+           xf86PrintModeline(0, mode);
+       }
+    }
+
+    return modes;
+}
+
+static int
+output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
+{
+  //    modesettingPtr ms = modesettingPTR(output->scrn);
+    //    CustomizerPtr cust = ms->cust;
+
+#if 0
+    if (cust && cust->winsys_check_fb_size &&
+       !cust->winsys_check_fb_size(cust, pMode->HDisplay *
+                                   output->scrn->bitsPerPixel / 8,
+                                   pMode->VDisplay))
+       return MODE_BAD;
+#endif
+    return MODE_OK;
+}
+
+#ifdef RANDR_12_INTERFACE
+static Bool
+output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
+{
+    return TRUE;
+}
+#endif /* RANDR_12_INTERFACE */
+
+#ifdef RANDR_13_INTERFACE
+static Bool
+output_get_property(xf86OutputPtr output, Atom property)
+{
+    return TRUE;
+}
+#endif /* RANDR_13_INTERFACE */
+
+static void
+output_destroy(xf86OutputPtr output)
+{
+    struct output_private *priv = output->driver_private;
+    drmModeFreeConnector(priv->drm_connector);
+    free(priv);
+    output->driver_private = NULL;
+}
+
+static const xf86OutputFuncsRec output_funcs = {
+    .create_resources = output_create_resources,
+#ifdef RANDR_12_INTERFACE
+    .set_property = output_set_property,
+#endif
+#ifdef RANDR_13_INTERFACE
+    .get_property = output_get_property,
+#endif
+    .dpms = output_dpms,
+    .detect = output_detect,
+
+    .get_modes = output_get_modes,
+    .mode_valid = output_mode_valid,
+    .destroy = output_destroy,
+};
+
+void
+xorg_output_init(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    xf86OutputPtr output;
+    drmModeResPtr res;
+    drmModeConnectorPtr drm_connector = NULL;
+    drmModeEncoderPtr drm_encoder = NULL;
+    struct output_private *priv;
+    char name[32];
+    int c, v, p;
+
+    res = drmModeGetResources(ms->fd);
+    if (res == 0) {
+       DRV_ERROR("Failed drmModeGetResources\n");
+       return;
+    }
+
+    for (c = 0; c < res->count_connectors; c++) {
+       drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]);
+       if (!drm_connector)
+           goto out;
+
+#if 0
+       for (p = 0; p < drm_connector->count_props; p++) {
+           drmModePropertyPtr prop;
+
+           prop = drmModeGetProperty(ms->fd, drm_connector->props[p]);
+
+           name = NULL;
+           if (prop) {
+               ErrorF("VALUES %d\n", prop->count_values);
+
+               for (v = 0; v < prop->count_values; v++)
+                   ErrorF("%s %lld\n", prop->name, prop->values[v]);
+           }
+       }
+#else
+       (void)p;
+       (void)v;
+#endif
+
+       snprintf(name, 32, "%s%d",
+                output_enum_list[drm_connector->connector_type],
+                drm_connector->connector_type_id);
+
+
+       priv = calloc(sizeof(*priv), 1);
+       if (!priv) {
+           continue;
+       }
+
+       output = xf86OutputCreate(pScrn, &output_funcs, name);
+       if (!output) {
+           free(priv);
+           continue;
+       }
+
+       drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
+       if (drm_encoder) {
+           output->possible_crtcs = drm_encoder->possible_crtcs;
+           output->possible_clones = drm_encoder->possible_clones;
+       } else {
+           output->possible_crtcs = 0;
+           output->possible_clones = 0;
+       }
+       priv->c = c;
+       priv->drm_connector = drm_connector;
+       output->driver_private = priv;
+       output->subpixel_order = SubPixelHorizontalRGB;
+       output->interlaceAllowed = FALSE;
+       output->doubleScanAllowed = FALSE;
+    }
+
+  out:
+    drmModeFreeResources(res);
+}
+
+unsigned
+xorg_output_get_id(xf86OutputPtr output)
+{
+    struct output_private *priv = output->driver_private;
+    return priv->drm_connector->connector_id;
+}
+
+/* vim: set sw=4 ts=8 sts=4: */
diff --git a/vmwgfx/vmwgfx_overlay.c b/vmwgfx/vmwgfx_overlay.c
new file mode 100644 (file)
index 0000000..d161023
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * Copyright 2007-2011 by VMware, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ *
+ */
+
+/*
+ * vmwarevideo.c --
+ *
+ *      Xv extension support.
+ *      See http://www.xfree86.org/current/DESIGN16.html
+ *
+ */
+
+
+#include "xf86xv.h"
+#include "fourcc.h"
+#define debug_printf(...)
+
+/*
+ * We can't incude svga_types.h due to conflicting types for Bool.
+ */
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+typedef int32_t int32;
+typedef uint32_t uint32;
+
+typedef int16_t int16;
+typedef uint16_t uint16;
+
+typedef int8_t int8;
+typedef uint8_t uint8;
+
+#include "../src/svga_reg.h"
+#include "../src/svga_escape.h"
+#include "../src/svga_overlay.h"
+
+#include <X11/extensions/Xv.h>
+
+#include "xf86drm.h"
+#include <drm/vmwgfx_drm.h>
+#include "vmwgfx_drmi.h"
+#include "vmwgfx_driver.h"
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+/*
+ * Number of videos that can be played simultaneously
+ */
+#define VMWARE_VID_NUM_PORTS 1
+
+/*
+ * Using a dark shade as the default colorKey
+ */
+#define VMWARE_VIDEO_COLORKEY 0x100701
+
+/*
+ * Maximum dimensions
+ */
+#define VMWARE_VID_MAX_WIDTH    2048
+#define VMWARE_VID_MAX_HEIGHT   2048
+
+#define VMWARE_VID_NUM_ENCODINGS 1
+static XF86VideoEncodingRec vmwareVideoEncodings[] =
+{
+    {
+       0,
+       "XV_IMAGE",
+       VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT,
+       {1, 1}
+    }
+};
+
+#define VMWARE_VID_NUM_FORMATS 2
+static XF86VideoFormatRec vmwareVideoFormats[] =
+{
+    { 16, TrueColor},
+    { 24, TrueColor}
+};
+
+#define VMWARE_VID_NUM_IMAGES 3
+static XF86ImageRec vmwareVideoImages[] =
+{
+    XVIMAGE_YV12,
+    XVIMAGE_YUY2,
+    XVIMAGE_UYVY
+};
+
+#define VMWARE_VID_NUM_ATTRIBUTES 2
+static XF86AttributeRec vmwareVideoAttributes[] =
+{
+    {
+        XvGettable | XvSettable,
+        0x000000,
+        0xffffff,
+        "XV_COLORKEY"
+    },
+    {
+        XvGettable | XvSettable,
+        0,
+        1,
+        "XV_AUTOPAINT_COLORKEY"
+    }
+};
+
+/*
+ * Video frames are stored in a circular list of buffers.
+ * Must be power or two, See vmw_video_port_play.
+ */
+#define VMWARE_VID_NUM_BUFFERS 1
+
+/*
+ * Defines the structure used to hold and pass video data to the host
+ */
+struct vmw_video_buffer
+{
+    int size;
+    void *data;
+    struct vmwgfx_dmabuf *buf;
+};
+
+
+/**
+ * Structure representing a single video stream, aka port.
+ *
+ * Ports maps one to one to a SVGA stream. Port is just
+ * what Xv calls a SVGA stream.
+ */
+struct vmwgfx_overlay_port
+{
+    /*
+     * Function prototype same as XvPutImage.
+     *
+     * This is either set to vmw_video_port_init or vmw_video_port_play.
+     * At init this function is set to port_init. In port_init we set it
+     * to port_play and call it, after initializing the struct.
+     */
+    int (*play)(ScrnInfoPtr, struct vmwgfx_overlay_port *,
+                short, short, short, short, short,
+                short, short, short, int, unsigned char*,
+                short, short, RegionPtr);
+
+    /* values to go into the SVGAOverlayUnit */
+    uint32 streamId;
+    uint32 colorKey;
+    uint32 flags;
+
+    /* round robin of buffers */
+    unsigned currBuf;
+    struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS];
+
+    /* properties that applies to all buffers */
+    int size;
+    int pitches[3];
+    int offsets[3];
+
+    /* things for X */
+    RegionRec clipBoxes;
+    Bool isAutoPaintColorkey;
+    int drm_fd;
+};
+
+/*
+ * Callback functions exported to Xv, prefixed with vmw_xv_*.
+ */
+static int vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
+                            short drw_x, short drw_y, short src_w, short src_h,
+                            short drw_w, short drw_h, int image,
+                            unsigned char *buf, short width, short height,
+                            Bool sync, RegionPtr clipBoxes, pointer data,
+                            DrawablePtr dst);
+static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
+static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
+                                         unsigned short *width,
+                                         unsigned short *height, int *pitches,
+                                         int *offsets);
+static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+                                     INT32 value, pointer data);
+static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+                                     INT32 *value, pointer data);
+static void vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
+                                short vid_w, short vid_h, short drw_w,
+                                short drw_h, unsigned int *p_w,
+                                unsigned int *p_h, pointer data);
+
+
+/*
+ * Local functions.
+ */
+static int vmw_video_port_init(ScrnInfoPtr pScrn,
+                               struct vmwgfx_overlay_port *port,
+                               short src_x, short src_y, short drw_x,
+                               short drw_y, short src_w, short src_h,
+                               short drw_w, short drw_h, int format,
+                               unsigned char *buf, short width,
+                               short height, RegionPtr clipBoxes);
+static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
+                               short src_x, short src_y, short drw_x,
+                               short drw_y, short src_w, short src_h,
+                               short drw_w, short drw_h, int format,
+                               unsigned char *buf, short width,
+                               short height, RegionPtr clipBoxes);
+static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port);
+
+static int vmw_video_buffer_alloc(int drm_fd, int size,
+                                  struct vmw_video_buffer *out);
+static int vmw_video_buffer_free(struct vmw_video_buffer *out);
+
+
+static struct vmwgfx_overlay_port *
+vmwgfx_overlay_port_create(int drm_fd, ScreenPtr pScreen)
+{
+    struct vmwgfx_overlay_port *port = calloc(1, sizeof(*port));
+
+    if (!port)
+       return NULL;
+
+    port->drm_fd = drm_fd;
+    port->play = vmw_video_port_init;
+    port->flags = SVGA_VIDEO_FLAG_COLORKEY;
+    port->colorKey = VMWARE_VIDEO_COLORKEY;
+    port->isAutoPaintColorkey = TRUE;
+    return port;
+}
+
+void
+vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports)
+{
+    if (free_ports) {
+       int i;
+
+       for(i=0; i<adaptor->nPorts; ++i) {
+           free(adaptor->pPortPrivates[i].ptr);
+       }
+    }
+
+    free(adaptor->pPortPrivates);
+    xf86XVFreeVideoAdaptorRec(adaptor);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_init_adaptor --
+ *
+ *    Initializes a XF86VideoAdaptor structure with the capabilities and
+ *    functions supported by this video driver.
+ *
+ * Results:
+ *    On success initialized XF86VideoAdaptor struct or NULL on error
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+XF86VideoAdaptorPtr
+vmw_video_init_adaptor(ScrnInfoPtr pScrn)
+{
+    XF86VideoAdaptorPtr adaptor;
+    modesettingPtr ms = modesettingPTR(pScrn);
+    int i;
+    DevUnion *dev_unions;
+    uint32_t ntot, nfree;
+
+    if (vmwgfx_num_streams(ms->fd, &ntot, &nfree) != 0) {
+        debug_printf("No stream ioctl support\n");
+        return NULL;
+    }
+    if (nfree == 0) {
+        debug_printf("No free streams\n");
+        return NULL;
+    }
+    adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
+    dev_unions = calloc(VMWARE_VID_NUM_PORTS, sizeof(DevUnion));
+    if (adaptor == NULL || dev_unions == NULL) {
+       xf86XVFreeVideoAdaptorRec(adaptor);
+       free(dev_unions);
+       return NULL;
+    }
+
+    adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
+
+    /**
+     * Note: CLIP_TO_VIEWPORT was removed from the flags, since with the
+     * crtc/output based modesetting, the viewport is not updated on
+     * RandR modeswitches. Hence the video may incorrectly be clipped away.
+     * The correct approach, (if needed) would be to clip against the
+     * scanout area union of all active crtcs. Revisit if needed.
+     */
+
+    adaptor->flags = VIDEO_OVERLAID_IMAGES;
+    adaptor->name = "VMware Overlay Video Engine";
+    adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
+    adaptor->pEncodings = vmwareVideoEncodings;
+    adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
+    adaptor->pFormats = vmwareVideoFormats;
+    adaptor->nPorts = VMWARE_VID_NUM_PORTS;
+    adaptor->pPortPrivates = dev_unions;
+
+    for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
+       struct vmwgfx_overlay_port *priv =
+           vmwgfx_overlay_port_create(ms->fd, pScrn->pScreen);
+
+        adaptor->pPortPrivates[i].ptr = (pointer) priv;
+    }
+
+    adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
+    adaptor->pAttributes = vmwareVideoAttributes;
+    adaptor->nImages = VMWARE_VID_NUM_IMAGES;
+    adaptor->pImages = vmwareVideoImages;
+
+    adaptor->PutVideo = NULL;
+    adaptor->PutStill = NULL;
+    adaptor->GetVideo = NULL;
+    adaptor->GetStill = NULL;
+    adaptor->StopVideo = vmw_xv_stop_video;
+    adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
+    adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
+    adaptor->QueryBestSize = vmw_xv_query_best_size;
+    adaptor->PutImage = vmw_xv_put_image;
+    adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
+
+    return adaptor;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_init --
+ *
+ *    Initializes a video stream in response to the first PutImage() on a
+ *    video stream. The process goes as follows:
+ *    - Figure out characteristics according to format
+ *    - Allocate offscreen memory
+ *    - Pass on video to Play() functions
+ *
+ * Results:
+ *    Success or XvBadAlloc on failure.
+ *
+ * Side effects:
+ *    Video stream is initialized and its first frame sent to the host
+ *    (done by VideoPlay() function called at the end)
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_port_init(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
+                    short src_x, short src_y, short drw_x,
+                    short drw_y, short src_w, short src_h,
+                    short drw_w, short drw_h, int format,
+                    unsigned char *buf, short width,
+                    short height, RegionPtr clipBoxes)
+{
+    unsigned short w, h;
+    int i, ret;
+
+    debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
+
+    ret = vmwgfx_claim_stream(port->drm_fd, &port->streamId);
+    if (ret != 0)
+       return XvBadAlloc;
+
+    w = width;
+    h = height;
+    /* init all the format attributes, used for buffers */
+    port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
+                                               port->pitches, port->offsets);
+
+    if (port->size == -1) {
+       ret = XvBadAlloc;
+       goto out_bad_size;
+    }
+
+    for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
+       ret = vmw_video_buffer_alloc(port->drm_fd, port->size, &port->bufs[i]);
+       if (ret != Success)
+           goto out_no_buffer;
+    }
+
+    port->currBuf = 0;
+    REGION_NULL(pScrn->pScreen, &port->clipBoxes);
+    port->play = vmw_video_port_play;
+    return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
+                      drw_w, drw_h, format, buf, width, height, clipBoxes);
+
+  out_bad_size:
+    (void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
+
+  out_no_buffer:
+    while(i-- != 0) {
+       vmw_video_buffer_free(&port->bufs[i]);
+    }
+    return ret;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_play --
+ *
+ *    Sends all the attributes associated with the video frame using the
+ *    FIFO ESCAPE mechanism to the host.
+ *
+ * Results:
+ *    Always returns Success.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
+                    short src_x, short src_y, short drw_x,
+                    short drw_y, short src_w, short src_h,
+                    short drw_w, short drw_h, int format,
+                    unsigned char *buf, short width,
+                    short height, RegionPtr clipBoxes)
+{
+    struct drm_vmw_control_stream_arg arg;
+    unsigned short w, h;
+    int size;
+    int ret;
+
+    debug_printf("\t%s: enter\n", __func__);
+
+    w = width;
+    h = height;
+
+    /* we don't update the ports size */
+    size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
+                                         port->pitches, port->offsets);
+
+    if (size != port->size) {
+        vmw_xv_stop_video(pScrn, port, TRUE);
+        return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
+                          src_h, drw_w, drw_h, format, buf, width, height,
+                          clipBoxes);
+    }
+
+    memcpy(port->bufs[port->currBuf].data, buf, port->size);
+
+    memset(&arg, 0, sizeof(arg));
+
+    arg.stream_id = port->streamId;
+    arg.enabled = TRUE;
+    arg.flags = port->flags;
+    arg.color_key = port->colorKey;
+    arg.handle = port->bufs[port->currBuf].buf->handle;
+    arg.format = format;
+    arg.size = port->size;
+    arg.width = w;
+    arg.height = h;
+    arg.src.x = src_x;
+    arg.src.y = src_y;
+    arg.src.w = src_w;
+    arg.src.h = src_h;
+    arg.dst.x = drw_x;
+    arg.dst.y = drw_y;
+    arg.dst.w = drw_w;
+    arg.dst.h = drw_h;
+    arg.pitch[0] = port->pitches[0];
+    arg.pitch[1] = port->pitches[1];
+    arg.pitch[2] = port->pitches[2];
+    arg.offset = 0;
+
+    /*
+     *  Update the clipList and paint the colorkey, if required.
+     */
+    if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
+        REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
+        if (port->isAutoPaintColorkey)
+            xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
+    }
+
+    xorg_flush(pScrn->pScreen);
+    ret = drmCommandWrite(port->drm_fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
+    if (ret) {
+       vmw_video_port_cleanup(pScrn, port);
+       return XvBadAlloc;
+    }
+
+    if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
+       port->currBuf = 0;
+
+    return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_cleanup --
+ *
+ *    Frees up all resources (if any) taken by a video stream.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    Same as above.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port)
+{
+    int i;
+
+    debug_printf("\t%s: enter\n", __func__);
+
+    if (port->play == vmw_video_port_init)
+       return;
+
+    port->play = vmw_video_port_init;
+    (void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
+
+    for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
+       vmw_video_buffer_free(&port->bufs[i]);
+    }
+
+    REGION_UNINIT(pScreen->pScreen, &port->clipBoxes);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_buffer_alloc --
+ *
+ *    Allocates and map a kernel buffer to be used as data storage.
+ *
+ * Results:
+ *    XvBadAlloc on failure, otherwise Success.
+ *
+ * Side effects:
+ *    Calls into the kernel, sets members of out.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_buffer_alloc(int drm_fd, int size,
+                       struct vmw_video_buffer *out)
+{
+    out->buf = vmwgfx_dmabuf_alloc(drm_fd, size);
+    if (!out->buf)
+       return XvBadAlloc;
+
+    out->data = vmwgfx_dmabuf_map(out->buf);
+    if (!out->data) {
+       vmwgfx_dmabuf_destroy(out->buf);
+       out->buf = NULL;
+       return XvBadAlloc;
+    }
+
+    out->size = size;
+    debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
+
+    return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_buffer_free --
+ *
+ *    Frees and unmaps an allocated kernel buffer.
+ *
+ * Results:
+ *    Success.
+ *
+ * Side effects:
+ *    Calls into the kernel, sets members of out to 0.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_buffer_free(struct vmw_video_buffer *out)
+{
+    if (out->size == 0)
+       return Success;
+
+    vmwgfx_dmabuf_unmap(out->buf);
+    vmwgfx_dmabuf_destroy(out->buf);
+
+    out->buf = NULL;
+    out->data = NULL;
+    out->size = 0;
+
+    debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
+
+    return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_put_image --
+ *
+ *    Main video playback function. It copies the passed data which is in
+ *    the specified format (e.g. FOURCC_YV12) into the overlay.
+ *
+ *    If sync is TRUE the driver should not return from this
+ *    function until it is through reading the data from buf.
+ *
+ * Results:
+ *    Success or XvBadAlloc on failure
+ *
+ * Side effects:
+ *    Video port will be played(initialized if 1st frame) on success
+ *    or will fail on error.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
+                 short drw_x, short drw_y, short src_w, short src_h,
+                 short drw_w, short drw_h, int format,
+                 unsigned char *buf, short width, short height,
+                 Bool sync, RegionPtr clipBoxes, pointer data,
+                 DrawablePtr dst)
+{
+    struct vmwgfx_overlay_port *port = data;
+
+    debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
+                src_x, src_y, src_w, src_h,
+                drw_x, drw_y, drw_w, drw_h,
+                width, height);
+
+    return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
+                      drw_w, drw_h, format, buf, width, height, clipBoxes);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_stop_video --
+ *
+ *    Called when we should stop playing video for a particular stream. If
+ *    Cleanup is FALSE, the "stop" operation is only temporary, and thus we
+ *    don't do anything. If Cleanup is TRUE we kill the video port by
+ *    sending a message to the host and freeing up the stream.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    See above.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+{
+    struct vmwgfx_overlay_port *port = data;
+
+    debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
+    REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
+
+    if (!cleanup)
+        return;
+
+    vmw_video_port_cleanup(pScrn, port);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_query_image_attributes --
+ *
+ *    From the spec: This function is called to let the driver specify how data
+ *    for a particular image of size width by height should be stored.
+ *    Sometimes only the size and corrected width and height are needed. In
+ *    that case pitches and offsets are NULL.
+ *
+ * Results:
+ *    The size of the memory required for the image, or -1 on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
+                              unsigned short *width, unsigned short *height,
+                              int *pitches, int *offsets)
+{
+    INT32 size, tmp;
+
+    if (*width > VMWARE_VID_MAX_WIDTH) {
+        *width = VMWARE_VID_MAX_WIDTH;
+    }
+    if (*height > VMWARE_VID_MAX_HEIGHT) {
+        *height = VMWARE_VID_MAX_HEIGHT;
+    }
+
+    *width = (*width + 1) & ~1;
+    if (offsets != NULL) {
+        offsets[0] = 0;
+    }
+
+    switch (format) {
+       case FOURCC_YV12:
+           *height = (*height + 1) & ~1;
+           size = (*width + 3) & ~3;
+           if (pitches) {
+               pitches[0] = size;
+           }
+           size *= *height;
+           if (offsets) {
+               offsets[1] = size;
+           }
+           tmp = ((*width >> 1) + 3) & ~3;
+           if (pitches) {
+                pitches[1] = pitches[2] = tmp;
+           }
+           tmp *= (*height >> 1);
+           size += tmp;
+           if (offsets) {
+               offsets[2] = size;
+           }
+           size += tmp;
+           break;
+       case FOURCC_UYVY:
+       case FOURCC_YUY2:
+           size = *width * 2;
+           if (pitches) {
+               pitches[0] = size;
+           }
+           size *= *height;
+           break;
+       default:
+           debug_printf("Query for invalid video format %d\n", format);
+           return -1;
+    }
+    return size;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_set_port_attribute --
+ *
+ *    From the spec: A port may have particular attributes such as colorKey, hue,
+ *    saturation, brightness or contrast. Xv clients set these
+ *    attribute values by sending attribute strings (Atoms) to the server.
+ *
+ * Results:
+ *    Success if the attribute exists and XvBadAlloc otherwise.
+ *
+ * Side effects:
+ *    The respective attribute gets the new value.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+                          INT32 value, pointer data)
+{
+    struct vmwgfx_overlay_port *port = data;
+    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
+    Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
+
+    if (attribute == xvColorKey) {
+        debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
+        port->colorKey = value;
+    } else if (attribute == xvAutoPaint) {
+        debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
+        port->isAutoPaintColorkey = value;
+    } else {
+        return XvBadAlloc;
+    }
+
+    return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_get_port_attribute --
+ *
+ *    From the spec: A port may have particular attributes such as hue,
+ *    saturation, brightness or contrast. Xv clients get these
+ *    attribute values by sending attribute strings (Atoms) to the server
+ *
+ * Results:
+ *    Success if the attribute exists and XvBadAlloc otherwise.
+ *
+ * Side effects:
+ *    "value" contains the requested attribute on success.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+                          INT32 *value, pointer data)
+{
+    struct vmwgfx_overlay_port *port = data;
+    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
+    Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
+
+    if (attribute == xvColorKey) {
+        *value = port->colorKey;
+    } else if (attribute == xvAutoPaint) {
+        *value = port->isAutoPaintColorkey;
+    } else {
+        return XvBadAlloc;
+    }
+
+    return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_query_best_size --
+ *
+ *    From the spec: QueryBestSize provides the client with a way to query what
+ *    the destination dimensions would end up being if they were to request
+ *    that an area vid_w by vid_h from the video stream be scaled to rectangle
+ *    of drw_w by drw_h on the screen. Since it is not expected that all
+ *    hardware will be able to get the target dimensions exactly, it is
+ *    important that the driver provide this function.
+ *
+ *    This function seems to never be called, but to be on the safe side
+ *    we apply the same logic that QueryImageAttributes has for width
+ *    and height.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
+                       short vid_w, short vid_h, short drw_w,
+                       short drw_h, unsigned int *p_w,
+                       unsigned int *p_h, pointer data)
+{
+    *p_w = (drw_w + 1) & ~1;
+    *p_h = drw_h;
+
+    return;
+}
diff --git a/vmwgfx/vmwgfx_saa.c b/vmwgfx/vmwgfx_saa.c
new file mode 100644 (file)
index 0000000..3122353
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#include <xorg-server.h>
+#include <mi.h>
+#include <fb.h>
+#include <xf86drmMode.h>
+#include <xa_context.h>
+#include "vmwgfx_saa.h"
+#include "vmwgfx_drmi.h"
+
+
+#define VMWGFX_PIX_MALLOC  (1 << 0)
+#define VMWGFX_PIX_GMR     (1 << 1)
+#define VMWGFX_PIX_SURFACE (1 << 2)
+
+struct vmwgfx_saa {
+    struct saa_driver driver;
+    struct vmwgfx_dma_ctx *ctx;
+    struct xa_tracker *xat;
+    struct xa_context *xa_ctx;
+    ScreenPtr pScreen;
+    int drm_fd;
+    struct vmwgfx_saa_pixmap *src_vpix;
+    struct vmwgfx_saa_pixmap *dst_vpix;
+    Bool present_copy;
+    Bool diff_valid;
+    int xdiff;
+    int ydiff;
+    RegionRec present_region;
+    uint32_t src_handle;
+    Bool can_optimize_dma;
+    void (*present_flush) (ScreenPtr pScreen);
+    struct vmwgfx_saa_pixmap *dri2_flush_list;
+};
+
+static inline struct vmwgfx_saa *
+to_vmwgfx_saa(struct saa_driver *driver) {
+    return (struct vmwgfx_saa *) driver;
+}
+
+static Bool
+vmwgfx_pixmap_add_damage(PixmapPtr pixmap)
+{
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+    DrawablePtr draw = &pixmap->drawable;
+    BoxRec box;
+
+    if (spix->damage)
+       return TRUE;
+
+    if (!saa_add_damage(pixmap))
+       return FALSE;
+
+    box.x1 = 0;
+    box.x2 = draw->width;
+    box.y1 = 0;
+    box.y2 = draw->height;
+
+    if (vpix->hw)
+       REGION_INIT(draw->pScreen, &spix->dirty_hw, &box, 1);
+    else
+       REGION_INIT(draw->pScreen, &spix->dirty_shadow, &box, 1);
+
+    return TRUE;
+}
+
+static void
+vmwgfx_pixmap_remove_damage(PixmapPtr pixmap)
+{
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+
+    if (!spix->damage || (vpix->hw && vpix->gmr))
+       return;
+
+    DamageUnregister(&pixmap->drawable, spix->damage);
+    DamageDestroy(spix->damage);
+    spix->damage = NULL;
+}
+
+static void
+vmwgfx_pixmap_remove_present(struct vmwgfx_saa_pixmap *vpix)
+{
+    if (vpix->dirty_present)
+       REGION_DESTROY(pixmap->drawable.pScreen, vpix->dirty_present);
+    if (vpix->present_damage)
+       REGION_DESTROY(pixmap->drawable.pScreen, vpix->present_damage);
+    if (vpix->pending_update)
+       REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_update);
+    if (vpix->pending_present)
+       REGION_DESTROY(pixmap->drawable.pScreen, vpix->pending_present);
+    vpix->dirty_present = NULL;
+    vpix->present_damage = NULL;
+    vpix->pending_update = NULL;
+    vpix->pending_present = NULL;
+}
+
+static Bool
+vmwgfx_pixmap_add_present(PixmapPtr pixmap)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    ScreenPtr pScreen = pixmap->drawable.pScreen;
+    (void) pScreen;
+
+    vpix->dirty_present = REGION_CREATE(pScreen, NULL, 0);
+    if (!vpix->dirty_present)
+       return FALSE;
+    vpix->present_damage = REGION_CREATE(pScreen, NULL, 0);
+    if (!vpix->present_damage)
+       goto out_no_present_damage;
+    vpix->pending_update = REGION_CREATE(pScreen, NULL, 0);
+    if (!vpix->pending_update)
+       goto out_no_pending_update;
+    vpix->pending_present = REGION_CREATE(pScreen, NULL, 0);
+    if (!vpix->pending_present)
+       goto out_no_pending_present;
+    if (!vmwgfx_pixmap_add_damage(pixmap))
+       goto out_no_damage;
+
+    return TRUE;
+  out_no_damage:
+    REGION_DESTROY(pScreen, vpix->pending_present);
+  out_no_pending_present:
+    REGION_DESTROY(pScreen, vpix->pending_update);
+  out_no_pending_update:
+    REGION_DESTROY(pScreen, vpix->present_damage);
+  out_no_present_damage:
+    REGION_DESTROY(pScreen, vpix->dirty_present);
+    return FALSE;
+}
+
+static void
+vmwgfx_pixmap_free_storage(struct vmwgfx_saa_pixmap *vpix)
+{
+    if (!(vpix->backing & VMWGFX_PIX_MALLOC) && vpix->malloc) {
+       free(vpix->malloc);
+       vpix->malloc = NULL;
+    }
+    if (!(vpix->backing & VMWGFX_PIX_SURFACE) && vpix->hw) {
+       xa_surface_destroy(vpix->hw);
+       vpix->hw = NULL;
+    }
+    if (!(vpix->backing & VMWGFX_PIX_GMR) && vpix->gmr) {
+       vmwgfx_dmabuf_destroy(vpix->gmr);
+       vpix->gmr = NULL;
+    }
+}
+
+static Bool
+vmwgfx_pixmap_create_gmr(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    size_t size;
+    struct vmwgfx_dmabuf *gmr;
+    void *addr;
+
+    if (vpix->gmr)
+       return TRUE;
+
+    size = pixmap->devKind * pixmap->drawable.height;
+    gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
+    if (!gmr)
+       return FALSE;
+
+    if (vpix->malloc) {
+
+       addr = vmwgfx_dmabuf_map(gmr);
+       if (!addr)
+           goto out_no_transfer;
+       memcpy(addr, vpix->malloc, size);
+       vmwgfx_dmabuf_unmap(gmr);
+
+    } else if (vpix->hw && !vmwgfx_pixmap_add_damage(pixmap))
+       goto out_no_transfer;
+
+    vpix->backing |= VMWGFX_PIX_GMR;
+    vpix->backing &= ~VMWGFX_PIX_MALLOC;
+    vpix->gmr = gmr;
+
+    vmwgfx_pixmap_free_storage(vpix);
+
+    return TRUE;
+
+  out_no_transfer:
+    vmwgfx_dmabuf_destroy(gmr);
+    return FALSE;
+}
+
+static Bool
+vmwgfx_pixmap_create_sw(struct vmwgfx_saa *vsaa, PixmapPtr pixmap)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+
+    if (!(vpix->backing & (VMWGFX_PIX_MALLOC | VMWGFX_PIX_GMR)))
+       return FALSE;
+
+    if (!vpix->malloc && (vpix->backing & VMWGFX_PIX_MALLOC)) {
+       vpix->malloc = malloc(pixmap->devKind * pixmap->drawable.height);
+       return (vpix->malloc != NULL);
+    } else if (vpix->backing & VMWGFX_PIX_GMR)
+       return vmwgfx_pixmap_create_gmr(vsaa, pixmap);
+
+    return TRUE;
+}
+
+
+/**
+ *
+ * Makes sure all presented contents covered by @region are read
+ * back and are present in a valid GMR.
+ */
+
+static Bool
+vmwgfx_pixmap_present_readback(struct vmwgfx_saa *vsaa,
+                              PixmapPtr pixmap,
+                              RegionPtr region)
+{
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+    RegionRec intersection;
+
+
+    if (!spix->damage || !REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw) ||
+       !vpix->dirty_present)
+       return TRUE;
+
+    REGION_NULL(vsaa->pScreen, &intersection);
+    REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_hw);
+    REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection,
+                    vpix->dirty_present);
+
+    if (region)
+       REGION_INTERSECT(vsaa->pScreen, &intersection, &intersection, region);
+
+    if (!REGION_NOTEMPTY(vsaa->pScreen, &intersection))
+       goto out;
+
+    vsaa->present_flush(vsaa->pScreen);
+    if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap))
+       goto out_err;
+
+    /*
+     * FIXME: Cliprects may not overlap screen boundaries.
+     */
+
+    if (vmwgfx_present_readback(vsaa->drm_fd, &intersection) != 0)
+       goto out_err;
+
+    REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw,
+                   &spix->dirty_hw, &intersection);
+  out:
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+    return TRUE;
+
+  out_err:
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+    return FALSE;
+}
+
+static Bool
+vmwgfx_saa_dma(struct vmwgfx_saa *vsaa,
+              PixmapPtr pixmap,
+              RegionPtr reg,
+              Bool to_hw)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+
+    if (!vpix->hw || (!vpix->gmr && !vpix->malloc))
+       return TRUE;
+
+    if (vpix->gmr && vsaa->can_optimize_dma) {
+       uint32_t handle, dummy;
+
+       if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0)
+           goto out_err;
+       if (vmwgfx_dma(0, 0, reg, vpix->gmr, pixmap->devKind, handle,
+                      to_hw) != 0)
+           goto out_err;
+    } else {
+       void *data = vpix->malloc;
+       int ret;
+
+       if (vpix->gmr) {
+           data = vmwgfx_dmabuf_map(vpix->gmr);
+           if (!data)
+               goto out_err;
+       }
+
+       ret = xa_surface_dma(vsaa->xa_ctx, vpix->hw, data, pixmap->devKind,
+                            (int) to_hw,
+                            (struct xa_box *) REGION_RECTS(reg),
+                            REGION_NUM_RECTS(reg));
+       if (vpix->gmr)
+           vmwgfx_dmabuf_unmap(vpix->gmr);
+       if (ret)
+           goto out_err;
+    }
+    return TRUE;
+  out_err:
+    LogMessage(X_ERROR, "DMA %s surface failed.\n",
+              to_hw ? "to" : "from");
+    return FALSE;
+}
+
+
+static Bool
+vmwgfx_download_from_hw(struct saa_driver *driver, PixmapPtr pixmap,
+                       RegionPtr readback)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+
+    RegionRec intersection;
+
+    if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, readback))
+       return FALSE;
+
+    if (!REGION_NOTEMPTY(vsaa->pScreen, &spix->dirty_hw))
+       return TRUE;
+
+    if (!vpix->hw)
+       return TRUE;
+
+    REGION_NULL(vsaa->pScreen, &intersection);
+    REGION_INTERSECT(vsaa->pScreen, &intersection, readback,
+                    &spix->dirty_hw);
+    readback = &intersection;
+
+    if (!vmwgfx_pixmap_create_sw(vsaa, pixmap))
+       goto out_err;
+
+    if (!vmwgfx_saa_dma(vsaa, pixmap, readback, FALSE))
+       goto out_err;
+    REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_hw, &spix->dirty_hw, readback);
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+    return TRUE;
+ out_err:
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+    return FALSE;
+}
+
+
+static Bool
+vmwgfx_upload_to_hw(struct saa_driver *driver, PixmapPtr pixmap,
+                   RegionPtr upload)
+{
+    return vmwgfx_saa_dma(to_vmwgfx_saa(driver), pixmap, upload, TRUE);
+}
+
+static void
+vmwgfx_release_from_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
+{
+  //    LogMessage(X_INFO, "Release 0x%08lx access 0x%08x\n",
+  //          (unsigned long) pixmap, (unsigned) access);
+}
+
+static void *
+vmwgfx_sync_for_cpu(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
+{
+    /*
+     * Errors in this functions will turn up in subsequent map
+     * calls.
+     */
+
+    (void) vmwgfx_pixmap_create_sw(to_vmwgfx_saa(driver), pixmap);
+
+    return NULL;
+}
+
+static void *
+vmwgfx_map(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+
+    if (vpix->malloc)
+       return vpix->malloc;
+    else if (vpix->gmr)
+       return vmwgfx_dmabuf_map(vpix->gmr);
+    else
+       return NULL;
+}
+
+static void
+vmwgfx_unmap(struct saa_driver *driver, PixmapPtr pixmap, saa_access_t access)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+
+    if (vpix->gmr)
+       return vmwgfx_dmabuf_unmap(vpix->gmr);
+
+//    LogMessage(X_INFO, "Unmap 0x%08lx access 0x%08x\n",
+    //       (unsigned long) pixmap, (unsigned) access);
+    ;
+}
+
+static Bool
+vmwgfx_create_pixmap(struct saa_driver *driver, struct saa_pixmap *spix,
+                    int w, int h, int depth,
+                    unsigned int usage_hint, int bpp, int *new_pitch)
+{
+    *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
+
+
+    return TRUE;
+}
+
+
+static void
+vmwgfx_add_dri2_list(struct vmwgfx_saa *vsaa,
+                    struct vmwgfx_saa_pixmap *vpix)
+{
+    vpix->next_dri2 = vsaa->dri2_flush_list;
+    vpix->prevnext_dri2 = &vsaa->dri2_flush_list;
+    vsaa->dri2_flush_list = vpix;
+    if (vpix->next_dri2)
+       vpix->next_dri2->prevnext_dri2 = &vpix->next_dri2;
+}
+
+void
+vmwgfx_remove_dri2_list(struct vmwgfx_saa_pixmap *vpix)
+{
+    if (vpix->next_dri2)
+       vpix->next_dri2->prevnext_dri2 = vpix->prevnext_dri2;
+
+    if (vpix->prevnext_dri2)
+       *vpix->prevnext_dri2  = vpix->next_dri2;
+
+    vpix->next_dri2 = NULL;
+    vpix->prevnext_dri2 = NULL;
+}
+
+
+void
+vmwgfx_flush_dri2(ScreenPtr pScreen)
+{
+    struct vmwgfx_saa *vsaa =
+       to_vmwgfx_saa(saa_get_driver(pScreen));
+    struct vmwgfx_saa_pixmap *next = vsaa->dri2_flush_list;
+    struct vmwgfx_saa_pixmap *cur;
+
+    while(next) {
+       struct saa_pixmap *spix = &next->base;
+       PixmapPtr pixmap = spix->pixmap;
+
+       if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) {
+           REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
+           cur = next;
+           next = next->next_dri2;
+           vmwgfx_remove_dri2_list(cur);
+       } else
+           next = next->next_dri2;
+    }
+}
+
+
+static void
+vmwgfx_destroy_pixmap(struct saa_driver *driver, PixmapPtr pixmap)
+{
+    ScreenPtr pScreen = to_vmwgfx_saa(driver)->pScreen;
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    (void) pScreen;
+
+    vpix->backing = 0;
+    vmwgfx_pixmap_free_storage(vpix);
+
+    /*
+     * Any damage we've registered has already been removed by the server
+     * at this point. Any attempt to unregister / destroy it will result
+     * in a double free.
+     */
+
+    vmwgfx_pixmap_remove_present(vpix);
+    vmwgfx_remove_dri2_list(vpix);
+
+    if (vpix->hw_is_dri2_fronts)
+       LogMessage(X_ERROR, "Incorrect dri2 front count.\n");
+}
+
+static Bool
+vmwgfx_pixmap_create_hw(struct vmwgfx_saa *vsaa,
+                       PixmapPtr pixmap, unsigned int flags)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    struct xa_surface *hw;
+
+    if (!vsaa->xat)
+       return FALSE;
+
+    if (vpix->hw)
+       return TRUE;
+
+    hw = xa_surface_create(vsaa->xat,
+                          pixmap->drawable.width,
+                          pixmap->drawable.height,
+                          pixmap->drawable.depth,
+                          xa_type_argb, xa_format_unknown,
+                          XA_FLAG_RENDER_TARGET | flags);
+    if (hw == NULL)
+       return FALSE;
+
+    if ((vpix->gmr || vpix->malloc) && !vmwgfx_pixmap_add_damage(pixmap))
+       goto out_no_damage;
+
+    /*
+     * Even if we don't have a GMR yet, indicate that when needed it
+     * should be created.
+     */
+
+    vpix->hw = hw;
+    vpix->backing |= VMWGFX_PIX_SURFACE;
+    vmwgfx_pixmap_free_storage(vpix);
+
+    return TRUE;
+
+out_no_damage:
+    xa_surface_destroy(hw);
+    return FALSE;
+}
+
+
+/**
+ *
+ * Makes sure we have a surface with valid contents.
+ */
+
+Bool
+vmwgfx_pixmap_validate_hw(PixmapPtr pixmap, RegionPtr region,
+                         unsigned int add_flags,
+                         unsigned int remove_flags)
+{
+    struct vmwgfx_saa *vsaa =
+       to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+    RegionRec intersection;
+
+    if (!vsaa->xat)
+       return FALSE;
+
+    if (vpix->hw) {
+       if (xa_surface_redefine(vpix->hw,
+                               pixmap->drawable.width,
+                               pixmap->drawable.height,
+                               pixmap->drawable.depth,
+                               xa_type_argb, xa_format_unknown,
+                               XA_FLAG_RENDER_TARGET | add_flags,
+                               remove_flags, 1) != 0)
+           return FALSE;
+    } else if (!vmwgfx_pixmap_create_hw(vsaa, pixmap, add_flags))
+       return FALSE;
+
+
+    if (!vmwgfx_pixmap_present_readback(vsaa, pixmap, region))
+       return FALSE;
+
+    REGION_NULL(vsaa->pScreen, &intersection);
+    REGION_COPY(vsaa->pScreen, &intersection, &spix->dirty_shadow);
+
+    if (vpix->dirty_present)
+       REGION_UNION(vsaa->pScreen, &intersection, vpix->dirty_present,
+                    &spix->dirty_shadow);
+
+    if (spix->damage && REGION_NOTEMPTY(vsaa->pScreen, &intersection)) {
+       RegionPtr upload = &intersection;
+
+       /*
+        * Check whether we need to upload from GMR.
+        */
+
+       if (region) {
+           REGION_INTERSECT(vsaa->pScreen, &intersection, region,
+                            &intersection);
+           upload = &intersection;
+       }
+
+       if (REGION_NOTEMPTY(vsaa->pScreen, upload)) {
+           Bool ret = vmwgfx_upload_to_hw(&vsaa->driver, pixmap, upload);
+           if (ret) {
+               REGION_SUBTRACT(vsaa->pScreen, &spix->dirty_shadow,
+                               &spix->dirty_shadow, upload);
+               if (vpix->dirty_present)
+                   REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present,
+                                   vpix->dirty_present, upload);
+           } else {
+               REGION_UNINIT(vsaa->pScreen, &intersection);
+               return FALSE;
+           }
+       }
+    }
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+    return TRUE;
+}
+
+static void
+vmwgfx_copy_stride(uint8_t *dst, uint8_t *src, unsigned int dst_pitch,
+                  unsigned int src_pitch, unsigned int dst_height,
+                  unsigned int src_height)
+{
+    unsigned int i;
+    unsigned int height = (dst_height < src_height) ? dst_height : src_height;
+    unsigned int pitch = (dst_pitch < src_pitch) ? dst_pitch : src_pitch;
+
+    for(i=0; i<height; ++i) {
+       memcpy(dst, src, pitch);
+       dst += dst_pitch;
+       src += src_pitch;
+    }
+}
+
+
+static Bool
+vmwgfx_pix_resize(PixmapPtr pixmap, unsigned int old_pitch,
+                 unsigned int old_height, unsigned int old_width)
+{
+    ScreenPtr pScreen = pixmap->drawable.pScreen;
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(pScreen));
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    DrawablePtr draw = &pixmap->drawable;
+    unsigned int size = pixmap->devKind * draw->height;
+
+    /*
+     * Ignore copying errors. At worst they will show up as rendering
+     * artefacts.
+     */
+
+    if (vpix->malloc) {
+
+       void *new_malloc = malloc(size);
+       if (!new_malloc)
+           return FALSE;
+
+       vmwgfx_copy_stride(new_malloc, vpix->malloc, pixmap->devKind,
+                          old_pitch, draw->height,
+                          old_height);
+       free(vpix->malloc);
+       vpix->malloc = new_malloc;
+    }
+
+    if (vpix->gmr) {
+       struct vmwgfx_dmabuf *gmr;
+       void *new_addr;
+       void *old_addr;
+
+       gmr = vmwgfx_dmabuf_alloc(vsaa->drm_fd, size);
+       if (!gmr)
+           return FALSE;
+
+       new_addr = vmwgfx_dmabuf_map(gmr);
+       old_addr = vmwgfx_dmabuf_map(vpix->gmr);
+
+       if (new_addr && old_addr)
+           vmwgfx_copy_stride(new_addr, old_addr, pixmap->devKind,
+                              old_pitch, draw->height,
+                              old_height);
+       else
+           LogMessage(X_ERROR, "Failed pixmap resize copy.\n");
+
+       if (old_addr)
+           vmwgfx_dmabuf_unmap(vpix->gmr);
+       if (new_addr)
+           vmwgfx_dmabuf_unmap(gmr);
+       vmwgfx_dmabuf_destroy(vpix->gmr);
+       vpix->gmr = gmr;
+    }
+
+    if (vpix->hw) {
+       if (xa_surface_redefine(vpix->hw, draw->width, draw->height,
+                               draw->depth, xa_type_argb,
+                               xa_format_unknown, 0, 0, 1) != 0)
+           return FALSE;
+    }
+    return TRUE;
+}
+
+
+static Bool
+vmwgfx_modify_pixmap_header (PixmapPtr pixmap, int w, int h, int depth,
+                            int bpp, int devkind, void *pixdata)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    unsigned int old_height;
+    unsigned int old_width;
+    unsigned int old_pitch;
+
+    if (!vpix) {
+       LogMessage(X_ERROR, "Not an SAA pixmap.\n");
+       return FALSE;
+    }
+
+    if (pixdata) {
+       vpix->backing = 0;
+       vmwgfx_pixmap_free_storage(vpix);
+       return FALSE;
+    }
+
+    if (depth <= 0)
+       depth = pixmap->drawable.depth;
+
+    if (bpp <= 0)
+       bpp = pixmap->drawable.bitsPerPixel;
+
+    if (w <= 0)
+       w = pixmap->drawable.width;
+
+    if (h <= 0)
+       h = pixmap->drawable.height;
+
+    if (w <= 0 || h <= 0 || depth <= 0)
+       return FALSE;
+
+    old_height = pixmap->drawable.height;
+    old_width = pixmap->drawable.width;
+    old_pitch = pixmap->devKind;
+
+    if (!miModifyPixmapHeader(pixmap, w, h, depth,
+                             bpp, devkind, NULL))
+       goto out_no_modify;
+
+    if (!vpix->backing)
+       vpix->backing = VMWGFX_PIX_MALLOC;
+
+    vmwgfx_pix_resize(pixmap, old_pitch, old_height, old_width);
+    vmwgfx_pixmap_add_damage(pixmap);
+    vmwgfx_pixmap_free_storage(vpix);
+    return TRUE;
+
+  out_no_modify:
+    return FALSE;
+}
+
+static Bool
+vmwgfx_present_prepare(struct vmwgfx_saa *vsaa,
+                      struct vmwgfx_saa_pixmap *src_vpix,
+                      struct vmwgfx_saa_pixmap *dst_vpix)
+{
+    ScreenPtr pScreen = vsaa->pScreen;
+    unsigned int dummy;
+
+    (void) pScreen;
+    if (src_vpix == dst_vpix || !src_vpix->hw ||
+       xa_surface_handle(src_vpix->hw, &vsaa->src_handle, &dummy) != 0)
+       return FALSE;
+
+    REGION_NULL(pScreen, &vsaa->present_region);
+    vsaa->diff_valid = FALSE;
+    vsaa->dst_vpix = dst_vpix;
+    vsaa->present_flush(pScreen);
+
+    return TRUE;
+}
+
+/**
+ * Determine whether we should try present copies on this pixmap.
+ */
+
+static Bool
+vmwgfx_is_present_hw(PixmapPtr pixmap)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    return (vpix->dirty_present != NULL);
+}
+
+static void
+vmwgfx_check_hw_contents(struct vmwgfx_saa *vsaa,
+                        struct vmwgfx_saa_pixmap *vpix,
+                        RegionPtr region,
+                        Bool *has_dirty_hw,
+                        Bool *has_valid_hw)
+{
+    RegionRec intersection;
+
+
+    if (!vpix->hw) {
+       *has_dirty_hw = FALSE;
+       *has_valid_hw = FALSE;
+       return;
+    }
+
+    if (!region) {
+       *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen,
+                                       &vpix->base.dirty_hw);
+       *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen,
+                                        &vpix->base.dirty_shadow);
+       return;
+    }
+
+    REGION_NULL(vsaa->pScreen, &intersection);
+    REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_hw,
+                    region);
+    *has_dirty_hw = REGION_NOTEMPTY(vsaa->pScreen, &intersection);
+    REGION_INTERSECT(vsaa->pScreen, &intersection, &vpix->base.dirty_shadow,
+                    region);
+    *has_valid_hw = !REGION_NOTEMPTY(vsaa->pScreen, &intersection);
+    REGION_UNINIT(vsaa->pScreen, &intersection);
+}
+
+static Bool
+vmwgfx_copy_prepare(struct saa_driver *driver,
+                   PixmapPtr src_pixmap,
+                   PixmapPtr dst_pixmap,
+                   int dx,
+                   int dy,
+                   int alu,
+                   RegionPtr src_reg,
+                   uint32_t plane_mask)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+    struct vmwgfx_saa_pixmap *src_vpix;
+    struct vmwgfx_saa_pixmap *dst_vpix;
+    Bool has_dirty_hw;
+    Bool has_valid_hw;
+
+    if (!vsaa->xat || !SAA_PM_IS_SOLID(&dst_pixmap->drawable, plane_mask) ||
+       alu != GXcopy)
+       return FALSE;
+
+    src_vpix = vmwgfx_saa_pixmap(src_pixmap);
+    dst_vpix = vmwgfx_saa_pixmap(dst_pixmap);
+
+    vmwgfx_check_hw_contents(vsaa, src_vpix, src_reg,
+                            &has_dirty_hw, &has_valid_hw);
+
+    if (vmwgfx_is_present_hw(dst_pixmap) &&
+       src_vpix->backing & VMWGFX_PIX_SURFACE) {
+
+       if (!has_dirty_hw && !has_valid_hw)
+           return FALSE;
+
+       if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) {
+           if (!vmwgfx_pixmap_validate_hw(src_pixmap, src_reg, 0, 0))
+               return FALSE;
+           vsaa->present_copy = TRUE;
+           return TRUE;
+       }
+       return FALSE;
+    }
+
+    vsaa->present_copy = FALSE;
+    if (src_vpix->hw != NULL && src_vpix != dst_vpix) {
+
+       /*
+        * Use hardware acceleration either if source is partially only
+        * in hardware, or if source is entirely in hardware and destination
+        * has a hardware surface.
+        */
+
+       if (!has_dirty_hw && !(has_valid_hw && (dst_vpix->hw != NULL)))
+           return FALSE;
+       if (!vmwgfx_pixmap_validate_hw(src_pixmap, src_reg, 0, 0))
+           return FALSE;
+       if (!vmwgfx_pixmap_create_hw(vsaa, dst_pixmap, XA_FLAG_RENDER_TARGET))
+           return FALSE;
+
+       if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) == 0)
+           return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+static void
+vmwgfx_present_done(struct vmwgfx_saa *vsaa)
+{
+    ScreenPtr pScreen = vsaa->pScreen;
+    struct vmwgfx_saa_pixmap *dst_vpix = vsaa->dst_vpix;
+
+    (void) pScreen;
+    if (!vsaa->diff_valid)
+       return;
+
+    (void) vmwgfx_present(vsaa->drm_fd, vsaa->xdiff, vsaa->ydiff,
+                         &vsaa->present_region, vsaa->src_handle);
+
+    REGION_TRANSLATE(pScreen, &vsaa->present_region, vsaa->xdiff, vsaa->ydiff);
+    REGION_UNION(pScreen, dst_vpix->present_damage, dst_vpix->present_damage,
+                &vsaa->present_region);
+    vsaa->diff_valid = FALSE;
+    REGION_UNINIT(pScreen, &vsaa->present_region);
+}
+
+static void
+vmwgfx_present_copy(struct vmwgfx_saa *vsaa,
+                   int src_x,
+                   int src_y,
+                   int dst_x,
+                   int dst_y,
+                   int w,
+                   int h)
+{
+    int xdiff = dst_x - src_x;
+    int ydiff = dst_y - src_y;
+    BoxRec box;
+    RegionRec reg;
+
+    if (vsaa->diff_valid && ((xdiff != vsaa->xdiff) || (ydiff != vsaa->ydiff)))
+       (void) vmwgfx_present_done(vsaa);
+
+    if (!vsaa->diff_valid) {
+       vsaa->xdiff = xdiff;
+       vsaa->ydiff = ydiff;
+       vsaa->diff_valid = TRUE;
+    }
+
+    box.x1 = src_x;
+    box.x2 = src_x + w;
+    box.y1 = src_y;
+    box.y2 = src_y + h;
+
+    REGION_INIT(pScreen, &reg, &box, 1);
+    REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, &reg);
+    REGION_UNINIT(pScreen, &reg);
+}
+
+static void
+vmwgfx_copy(struct saa_driver *driver,
+           int src_x,
+           int src_y,
+           int dst_x,
+           int dst_y,
+           int w,
+           int h)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+
+    if (vsaa->present_copy) {
+       vmwgfx_present_copy(vsaa, src_x, src_y, dst_x, dst_y, w, h);
+       return;
+    }
+    xa_copy(vsaa->xa_ctx, dst_x, dst_y, src_x, src_y, w, h);
+}
+
+static void
+vmwgfx_copy_done(struct saa_driver *driver)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+
+    if (vsaa->present_copy) {
+       vmwgfx_present_done(vsaa);
+    }
+    xa_copy_done(vsaa->xa_ctx);
+}
+
+static void
+vmwgfx_takedown(struct saa_driver *driver)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+
+    free(vsaa);
+}
+
+static void
+vmwgfx_operation_complete(struct saa_driver *driver,
+                         PixmapPtr pixmap)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+
+    /*
+     * Make dri2 drawables up to date, or add them to the flush list
+     * executed at glxWaitX().
+     */
+
+    if (vpix->hw && vpix->hw_is_dri2_fronts) {
+       if (1) {
+           if (!vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow))
+               return;
+           REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow);
+       } else {
+           if (!vpix->prevnext_dri2)
+               vmwgfx_add_dri2_list(vsaa, vpix);
+       }
+    }
+}
+
+
+static Bool
+vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap,
+            Bool hw, RegionPtr damage)
+{
+    struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver);
+    struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
+    struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix);
+    BoxPtr rects;
+    int num_rects;
+
+    if (!vmwgfx_is_present_hw(pixmap))
+       return TRUE;
+
+    rects = REGION_RECTS(damage);
+    num_rects = REGION_NUM_RECTS(damage);
+
+    /*
+     * Is the new scanout damage hw or sw?
+     */
+
+    if (hw) {
+       /*
+        * Dump pending present into present tracking region.
+        */
+       if (REGION_NOTEMPTY(vsaa->pScreen, vpix->present_damage)) {
+           REGION_UNION(vsaa->pScreen, vpix->dirty_present,
+                        vpix->dirty_present, damage);
+           REGION_EMPTY(vsaa->pScreen, vpix->present_damage);
+       } else {
+           if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_update)) {
+               RegionRec reg;
+
+               REGION_NULL(vsaa->pScreen, &reg);
+               REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_update,
+                                damage);
+               if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
+                   vsaa->present_flush(vsaa->pScreen);
+               REGION_UNINIT(pScreen, &reg);
+           }
+           REGION_UNION(vsaa->pScreen, vpix->pending_present,
+                        vpix->pending_present, damage);
+       }
+    } else {
+           if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) {
+               RegionRec reg;
+
+               REGION_NULL(vsaa->pScreen, &reg);
+               REGION_INTERSECT(vsaa->pScreen, &reg, vpix->pending_present,
+                                damage);
+               if (REGION_NOTEMPTY(vsaa->pScreen, &reg))
+                   vsaa->present_flush(vsaa->pScreen);
+               REGION_UNINIT(pScreen, &reg);
+           }
+           REGION_UNION(vsaa->pScreen, vpix->pending_update,
+                        vpix->pending_update, damage);
+    }
+
+    return TRUE;
+}
+
+
+static const struct saa_driver vmwgfx_saa_driver = {
+    .saa_major = SAA_VERSION_MAJOR,
+    .saa_minor = SAA_VERSION_MINOR,
+    .pixmap_size = sizeof(struct vmwgfx_saa_pixmap),
+    .damage = vmwgfx_dirty,
+    .operation_complete = vmwgfx_operation_complete,
+    .download_from_hw = vmwgfx_download_from_hw,
+    .release_from_cpu = vmwgfx_release_from_cpu,
+    .sync_for_cpu = vmwgfx_sync_for_cpu,
+    .map = vmwgfx_map,
+    .unmap = vmwgfx_unmap,
+    .create_pixmap = vmwgfx_create_pixmap,
+    .destroy_pixmap = vmwgfx_destroy_pixmap,
+    .modify_pixmap_header = vmwgfx_modify_pixmap_header,
+    .copy_prepare = vmwgfx_copy_prepare,
+    .copy = vmwgfx_copy,
+    .copy_done = vmwgfx_copy_done,
+    .takedown = vmwgfx_takedown,
+};
+
+
+Bool
+vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
+               void (*present_flush)(ScreenPtr pScreen))
+{
+    struct vmwgfx_saa *vsaa;
+
+    vsaa = calloc(1, sizeof(*vsaa));
+    if (!vsaa)
+       return FALSE;
+
+    vsaa->pScreen = pScreen;
+    vsaa->xat = xat;
+    if (xat)
+       vsaa->xa_ctx = xa_context_default(xat);
+    vsaa->drm_fd = drm_fd;
+    vsaa->present_flush = present_flush;
+    vsaa->can_optimize_dma = FALSE;
+
+    vsaa->driver = vmwgfx_saa_driver;
+    if (!saa_driver_init(pScreen, &vsaa->driver))
+       goto out_no_saa;
+
+    return TRUE;
+  out_no_saa:
+    free(vsaa);
+    return FALSE;
+}
+
+/*
+ * *************************************************************************
+ * Scanout functions.
+ * These do not strictly belong here, but we choose to hide the scanout
+ * pixmap private data in the saa pixmaps. Might want to revisit this.
+ */
+
+/*
+ * Make sure we flush / update this scanout on next update run.
+ */
+
+void
+vmwgfx_scanout_refresh(PixmapPtr pixmap)
+{
+    ScreenPtr pScreen = pixmap->drawable.pScreen;
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    BoxRec box;
+
+    (void) pScreen;
+    box.x1 = 0;
+    box.y1 = 0;
+    box.x2 = pixmap->drawable.width;
+    box.y2 = pixmap->drawable.height;
+
+    REGION_RESET(vsaa->pScreen, vpix->pending_update, &box);
+    REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present,
+                   &vpix->base.dirty_hw, vpix->dirty_present);
+    REGION_SUBTRACT(vsaa->pScreen, vpix->pending_update,
+                   vpix->pending_update, &vpix->base.dirty_hw);
+}
+
+/*
+ * Take a "scanout reference" on a pixmap. If this is the first scanout
+ * reference, allocate resources needed for scanout, like proper
+ * damage tracking and kms fbs.
+ */
+
+uint32_t
+vmwgfx_scanout_ref(PixmapPtr pixmap)
+{
+    struct vmwgfx_saa *vsaa =
+       to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap);
+    int ret;
+
+    if (vpix->scanout_refcnt++ == 0) {
+       ret = !vmwgfx_pixmap_create_gmr(vsaa, pixmap);
+       if (!ret)
+           ret = !vmwgfx_pixmap_add_present(pixmap);
+       if (!ret)
+           ret = drmModeAddFB(vsaa->drm_fd,
+                              pixmap->drawable.width,
+                              pixmap->drawable.height,
+                              pixmap->drawable.depth,
+                              pixmap->drawable.bitsPerPixel,
+                              pixmap->devKind,
+                              vpix->gmr->handle,
+                              &vpix->fb_id);
+       if (!ret) {
+//         vmwgfx_scanout_refresh(pixmap);
+       }
+       if (ret) {
+           vpix->fb_id = -1;
+           --vpix->scanout_refcnt;
+       }
+    }
+    return vpix->fb_id;
+}
+
+/*
+ * Free a "scanout reference" on a pixmap. If this was the last scanout
+ * reference, free pixmap resources needed for scanout, like
+ * damage tracking and kms fbs.
+ */
+void
+vmwgfx_scanout_unref(PixmapPtr pixmap)
+{
+    struct vmwgfx_saa *vsaa;
+    struct vmwgfx_saa_pixmap *vpix;
+
+    if (!pixmap)
+       return;
+
+    vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen));
+    vpix = vmwgfx_saa_pixmap(pixmap);
+    if (--vpix->scanout_refcnt == 0) {
+       REGION_EMPTY(vsaa->pScreen, vpix->pending_update);
+       drmModeRmFB(vsaa->drm_fd, vpix->fb_id);
+       vpix->fb_id = -1;
+       vmwgfx_pixmap_present_readback(vsaa, pixmap, NULL);
+       vmwgfx_pixmap_remove_present(vpix);
+       vmwgfx_pixmap_remove_damage(pixmap);
+    }
+}
diff --git a/vmwgfx/vmwgfx_saa.h b/vmwgfx/vmwgfx_saa.h
new file mode 100644 (file)
index 0000000..1a42cac
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ */
+
+#ifndef _VMWGFX_SAA_H_
+#define _VMWGFX_SAA_H_
+
+#include "saa.h"
+#include <xa_tracker.h>
+#include "vmwgfx_drmi.h"
+
+#define VMWGFX_FLAG_FORCE_GMR     (1 << 0) /* Create with GMR as backing store */
+#define VMWGFX_FLAG_FORCE_SURFACE (1 << 1) /* Create with surface as backing store */
+#define VMWGFX_FLAG_AVOID_HWACCEL (1 << 2) /* Avoid Hardware acceleration on this pixmap */
+#define VMWGFX_FLAG_USE_PRESENT   (1 << 3) /* Use presents when copying to this pixmap */
+
+struct vmwgfx_saa_pixmap {
+    struct saa_pixmap base;
+    RegionPtr dirty_present;
+    RegionPtr present_damage;
+    RegionPtr pending_update;
+    RegionPtr pending_present;
+    uint32_t usage_flags;
+    uint32_t backing;
+    void *malloc;
+    struct vmwgfx_dmabuf *gmr;
+    struct xa_surface *hw;
+    int scanout_refcnt;
+    uint32_t fb_id;
+    int hw_is_dri2_fronts;
+    struct vmwgfx_saa_pixmap *next_dri2;
+    struct vmwgfx_saa_pixmap **prevnext_dri2;
+};
+
+static inline struct vmwgfx_saa_pixmap *
+to_vmwgfx_saa_pixmap(struct saa_pixmap *spix)
+{
+    return (struct vmwgfx_saa_pixmap *) spix;
+}
+
+extern Bool
+vmwgfx_pixmap_validate_hw(PixmapPtr pixmap, RegionPtr region,
+                         unsigned int add_flags,
+                         unsigned int remove_flags);
+
+static inline struct vmwgfx_saa_pixmap*
+vmwgfx_saa_pixmap(PixmapPtr pix)
+{
+    return to_vmwgfx_saa_pixmap(saa_get_saa_pixmap(pix));
+}
+
+extern Bool
+vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
+               void (*present_flush)(ScreenPtr pScreen));
+
+extern uint32_t
+vmwgfx_scanout_ref(PixmapPtr pixmap);
+
+extern void
+vmwgfx_scanout_unref(PixmapPtr pixmap);
+
+extern void
+vmwgfx_scanout_refresh(PixmapPtr pixmap);
+
+extern void
+vmwgfx_remove_dri2_list(struct vmwgfx_saa_pixmap *vpix);
+
+extern void
+vmwgfx_flush_dri2(ScreenPtr pScreen);
+
+#endif
diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c
new file mode 100644 (file)
index 0000000..fb8f41e
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2009-2011 VMWare, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Thomas Hellstrom <thellstrom@vmware.com>
+ * Author: Zack Rusin <zackr@vmware.com>
+ */
+
+#include "vmwgfx_driver.h"
+#include "vmwgfx_drmi.h"
+#include "vmwgfx_saa.h"
+
+#include <xf86xv.h>
+#include <X11/extensions/Xv.h>
+#include <fourcc.h>
+#include <xa_tracker.h>
+#include <xa_context.h>
+
+
+/*XXX get these from pipe's texture limits */
+#define IMAGE_MAX_WIDTH                2048
+#define IMAGE_MAX_HEIGHT       2048
+
+#define RES_720P_X 1280
+#define RES_720P_Y 720
+
+
+/* The ITU-R BT.601 conversion matrix for SDTV. */
+/* original, matrix, but we transpose it to
+ * make the shader easier
+static const float bt_601[] = {
+    1.0, 0.0, 1.4075,   ,
+    1.0, -0.3455, -0.7169, 0,
+    1.0, 1.7790, 0., 0,
+};*/
+static const float bt_601[] = {
+    1.0, 1.0, 1.0,        0.5,
+    0.0, -0.3455, 1.7790, 0,
+    1.4075, -0.7169, 0.,  0,
+};
+
+/* The ITU-R BT.709 conversion matrix for HDTV. */
+/* original, but we transpose to make the conversion
+ * in the shader easier
+static const float bt_709[] = {
+    1.0, 0.0, 1.581, 0,
+    1.0, -0.1881, -0.47, 0,
+    1.0, 1.8629, 0., 0,
+};*/
+static const float bt_709[] = {
+    1.0,   1.0,     1.0,     0.5,
+    0.0,  -0.1881,  1.8629,  0,
+    1.581,-0.47   , 0.0,     0,
+};
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static Atom xvBrightness, xvContrast;
+
+#define NUM_TEXTURED_ATTRIBUTES 2
+static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = {
+   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
+   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
+};
+
+#define NUM_FORMATS 3
+static XF86VideoFormatRec Formats[NUM_FORMATS] = {
+   {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+};
+
+static XF86VideoEncodingRec DummyEncoding[1] = {
+   {
+      0,
+      "XV_IMAGE",
+      IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
+      {1, 1}
+   }
+};
+
+#define NUM_IMAGES 3
+static XF86ImageRec Images[NUM_IMAGES] = {
+   XVIMAGE_UYVY,
+   XVIMAGE_YUY2,
+   XVIMAGE_YV12,
+};
+
+struct xorg_xv_port_priv {
+    struct xa_tracker *xat;
+    struct xa_context *r;
+    struct xa_fence *fence;
+
+    RegionRec clip;
+
+    int brightness;
+    int contrast;
+
+    int current_set;
+    struct vmwgfx_dmabuf *bounce[2][3];
+    struct xa_surface *yuv[3];
+
+    int drm_fd;
+};
+
+
+static void
+stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
+{
+   struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+   int i, j;
+
+   REGION_EMPTY(pScrn->pScreen, &priv->clip);
+   if (shutdown) {
+
+       /*
+       * No need to destroy the xa context or xa tracker since
+       * they are copied from the screen resources.
+       */
+
+       xa_fence_destroy(priv->fence);
+       priv->fence = NULL;
+
+       for (i=0; i<3; ++i) {
+          if (priv->yuv[i]) {
+              xa_surface_destroy(priv->yuv[i]);
+              priv->yuv[i] = NULL;
+          }
+          for (j=0; j<2; ++j) {
+              if (priv->bounce[j][i]) {
+                  vmwgfx_dmabuf_destroy(priv->bounce[j][i]);
+                  priv->bounce[0][i] = NULL;
+              }
+          }
+       }
+   }
+}
+
+static int
+set_port_attribute(ScrnInfoPtr pScrn,
+                   Atom attribute, INT32 value, pointer data)
+{
+   struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+
+   if (attribute == xvBrightness) {
+      if ((value < -128) || (value > 127))
+         return BadValue;
+      priv->brightness = value;
+   } else if (attribute == xvContrast) {
+      if ((value < 0) || (value > 255))
+         return BadValue;
+      priv->contrast = value;
+   } else
+      return BadMatch;
+
+   return Success;
+}
+
+static int
+get_port_attribute(ScrnInfoPtr pScrn,
+                   Atom attribute, INT32 * value, pointer data)
+{
+   struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
+
+   if (attribute == xvBrightness)
+      *value = priv->brightness;
+  else if (attribute == xvContrast)
+      *value = priv->contrast;
+   else
+      return BadMatch;
+
+   return Success;
+}
+
+static void
+query_best_size(ScrnInfoPtr pScrn,
+                Bool motion,
+                short vid_w, short vid_h,
+                short drw_w, short drw_h,
+                unsigned int *p_w, unsigned int *p_h, pointer data)
+{
+   if (vid_w > (drw_w << 1))
+      drw_w = vid_w >> 1;
+   if (vid_h > (drw_h << 1))
+      drw_h = vid_h >> 1;
+
+   *p_w = drw_w;
+   *p_h = drw_h;
+}
+
+static int
+check_yuv_surfaces(struct xorg_xv_port_priv *priv,  int width, int height)
+{
+    struct xa_surface **yuv = priv->yuv;
+    struct vmwgfx_dmabuf **bounce = priv->bounce[priv->current_set];
+    int ret = 0;
+    int i;
+    size_t size;
+
+    for (i=0; i<3; ++i) {
+       if (!yuv[i])
+           yuv[i] = xa_surface_create(priv->xat, width, height, 8,
+                                      xa_type_yuv_component,
+                                      xa_format_unknown, 0);
+       else
+           ret = xa_surface_redefine(yuv[i], width, height, 8,
+                                     xa_type_yuv_component,
+                                     xa_format_unknown, 0, 0, 0);
+       if (ret || !yuv[i])
+           return BadAlloc;
+
+       size = width * height;
+
+       if (bounce[i] && (bounce[i]->size < size ||
+                         bounce[i]->size > 2*size)) {
+           vmwgfx_dmabuf_destroy(bounce[i]);
+           bounce[i] = NULL;
+       }
+
+       if (!bounce[i]) {
+           bounce[i] = vmwgfx_dmabuf_alloc(priv->drm_fd, size);
+           if (!bounce[i])
+               return BadAlloc;
+       }
+    }
+    return Success;
+}
+
+static int
+query_image_attributes(ScrnInfoPtr pScrn,
+                       int id,
+                       unsigned short *w, unsigned short *h,
+                       int *pitches, int *offsets)
+{
+   int size, tmp;
+
+   if (*w > IMAGE_MAX_WIDTH)
+      *w = IMAGE_MAX_WIDTH;
+   if (*h > IMAGE_MAX_HEIGHT)
+      *h = IMAGE_MAX_HEIGHT;
+
+   *w = (*w + 1) & ~1;
+   if (offsets)
+      offsets[0] = 0;
+
+   switch (id) {
+   case FOURCC_YV12:
+      *h = (*h + 1) & ~1;
+      size = (*w + 3) & ~3;
+      if (pitches) {
+         pitches[0] = size;
+      }
+      size *= *h;
+      if (offsets) {
+         offsets[1] = size;
+      }
+      tmp = ((*w >> 1) + 3) & ~3;
+      if (pitches) {
+         pitches[1] = pitches[2] = tmp;
+      }
+      tmp *= (*h >> 1);
+      size += tmp;
+      if (offsets) {
+         offsets[2] = size;
+      }
+      size += tmp;
+      break;
+   case FOURCC_UYVY:
+   case FOURCC_YUY2:
+   default:
+      size = *w << 1;
+      if (pitches)
+        pitches[0] = size;
+      size *= *h;
+      break;
+   }
+
+   return size;
+}
+
+static int
+copy_packed_data(ScrnInfoPtr pScrn,
+                 struct xorg_xv_port_priv *port,
+                 int id,
+                 unsigned char *buf,
+                 int left,
+                 int top,
+                 unsigned short w, unsigned short h)
+{
+   int i, j;
+   struct vmwgfx_dmabuf **bounce = port->bounce[port->current_set];
+   char *ymap, *vmap, *umap;
+   unsigned char y1, y2, u, v;
+   int yidx, uidx, vidx;
+   int y_array_size = w * h;
+   int ret = BadAlloc;
+
+   /*
+    * Here, we could use xa_surface_[map|unmap], but given the size of
+    * the yuv textures, that could stress the xa tracker dma buffer pool,
+    * particularaly with multiple videos rendering simultaneously.
+    *
+    * Instead, cheat and allocate vmwgfx dma buffers directly.
+    */
+
+   ymap = (char *)vmwgfx_dmabuf_map(bounce[0]);
+   if (!ymap)
+       return BadAlloc;
+   umap = (char *)vmwgfx_dmabuf_map(bounce[1]);
+   if (!umap)
+       goto out_no_umap;
+   vmap = (char *)vmwgfx_dmabuf_map(bounce[2]);
+   if (!vmap)
+       goto out_no_vmap;
+
+
+   yidx = uidx = vidx = 0;
+
+   switch (id) {
+   case FOURCC_YV12: {
+      int pitches[3], offsets[3];
+      unsigned char *y, *u, *v;
+      query_image_attributes(pScrn, FOURCC_YV12,
+                             &w, &h, pitches, offsets);
+
+      y = buf + offsets[0];
+      v = buf + offsets[1];
+      u = buf + offsets[2];
+      for (i = 0; i < h; ++i) {
+         for (j = 0; j < w; ++j) {
+            int yoffset = (w*i+j);
+            int ii = (i|1), jj = (j|1);
+            int vuoffset = (w/2)*(ii/2) + (jj/2);
+            ymap[yidx++] = y[yoffset];
+            umap[uidx++] = u[vuoffset];
+            vmap[vidx++] = v[vuoffset];
+         }
+      }
+   }
+      break;
+   case FOURCC_UYVY:
+      for (i = 0; i < y_array_size; i +=2 ) {
+         /* extracting two pixels */
+         u  = buf[0];
+         y1 = buf[1];
+         v  = buf[2];
+         y2 = buf[3];
+         buf += 4;
+
+         ymap[yidx++] = y1;
+         ymap[yidx++] = y2;
+         umap[uidx++] = u;
+         umap[uidx++] = u;
+         vmap[vidx++] = v;
+         vmap[vidx++] = v;
+      }
+      break;
+   case FOURCC_YUY2:
+      for (i = 0; i < y_array_size; i +=2 ) {
+         /* extracting two pixels */
+         y1 = buf[0];
+         u  = buf[1];
+         y2 = buf[2];
+         v  = buf[3];
+
+         buf += 4;
+
+         ymap[yidx++] = y1;
+         ymap[yidx++] = y2;
+         umap[uidx++] = u;
+         umap[uidx++] = u;
+         vmap[vidx++] = v;
+         vmap[vidx++] = v;
+      }
+      break;
+   default:
+       ret = BadAlloc;
+       break;
+   }
+
+   ret = Success;
+   vmwgfx_dmabuf_unmap(bounce[2]);
+  out_no_vmap:
+   vmwgfx_dmabuf_unmap(bounce[1]);
+  out_no_umap:
+   vmwgfx_dmabuf_unmap(bounce[0]);
+
+   if (ret == Success) {
+       struct xa_surface *srf;
+       struct vmwgfx_dmabuf *buf;
+       uint32_t handle;
+       unsigned int stride;
+       BoxRec box;
+       RegionRec reg;
+
+       box.x1 = 0;
+       box.x2 = w;
+       box.y1 = 0;
+       box.y2 = h;
+
+       REGION_INIT(pScrn->pScreen, &reg, &box, 1);
+
+       for (i=0; i<3; ++i) {
+          srf = port->yuv[i];
+          buf = bounce[i];
+
+          if (xa_surface_handle(srf, &handle, &stride) != 0) {
+              ret = BadAlloc;
+              break;
+          }
+
+          if (vmwgfx_dma(0, 0, &reg, buf, w, handle, 1) != 0) {
+              ret = BadAlloc;
+              break;
+          }
+       }
+       REGION_UNINIT(pScrn->pScreen, &reg);
+   }
+
+   return ret;
+}
+
+
+static int
+display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id,
+              RegionPtr dstRegion,
+              int src_x, int src_y, int src_w, int src_h,
+              int dst_x, int dst_y, int dst_w, int dst_h,
+              PixmapPtr pPixmap)
+{
+    struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap);
+    Bool hdtv;
+    RegionRec reg;
+    int ret = BadAlloc;
+    int blit_ret;
+    const float *conv_matrix;
+
+    REGION_NULL(pScreen, &reg);
+
+    if (!vmwgfx_pixmap_validate_hw(pPixmap, &reg, XA_FLAG_RENDER_TARGET, 0))
+       goto out_no_dst;
+
+   hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y));
+   conv_matrix = (hdtv ? bt_709 : bt_601);
+
+#ifdef COMPOSITE
+
+   /*
+    * For redirected windows, we need to fix up the destination coordinates.
+    */
+
+   REGION_TRANSLATE(pScreen, dstRegion, -pPixmap->screen_x,
+                   -pPixmap->screen_y);
+   dst_x -= pPixmap->screen_x;
+   dst_y -= pPixmap->screen_y;
+#endif
+
+   /*
+    * Throttle on previous blit.
+    */
+
+   if (pPriv->fence) {
+       (void) xa_fence_wait(pPriv->fence, 1000000000ULL);
+       xa_fence_destroy(pPriv->fence);
+       pPriv->fence = NULL;
+   }
+
+   DamageRegionAppend(&pPixmap->drawable, dstRegion);
+
+   blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h,
+                                dst_x, dst_y, dst_w, dst_h,
+                                (struct xa_box *)REGION_RECTS(dstRegion),
+                                REGION_NUM_RECTS(dstRegion),
+                                conv_matrix,
+                                vpix->hw, pPriv->yuv);
+
+   saa_pixmap_dirty(pPixmap, TRUE, dstRegion);
+   DamageRegionProcessPending(&pPixmap->drawable);
+   ret = Success;
+
+   if (!blit_ret) {
+       ret = Success;
+       pPriv->fence = xa_fence_get(pPriv->r);
+   } else
+       ret = BadAlloc;
+
+   out_no_dst:
+   REGION_UNINIT(pScreen, &reg);
+   return ret;
+}
+
+static int
+put_image(ScrnInfoPtr pScrn,
+          short src_x, short src_y,
+          short drw_x, short drw_y,
+          short src_w, short src_h,
+          short drw_w, short drw_h,
+          int id, unsigned char *buf,
+          short width, short height,
+          Bool sync, RegionPtr clipBoxes, pointer data,
+          DrawablePtr pDraw)
+{
+   struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data;
+   ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
+   PixmapPtr pPixmap;
+   INT32 x1, x2, y1, y2;
+   BoxRec dstBox;
+   int ret;
+
+   /* Clip */
+   x1 = src_x;
+   x2 = src_x + src_w;
+   y1 = src_y;
+   y2 = src_y + src_h;
+
+   dstBox.x1 = drw_x;
+   dstBox.x2 = drw_x + drw_w;
+   dstBox.y1 = drw_y;
+   dstBox.y2 = drw_y + drw_h;
+
+   if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
+                             width, height))
+      return Success;
+
+   ret = check_yuv_surfaces(pPriv, width, height);
+   if (ret)
+       return ret;
+
+   ret = copy_packed_data(pScrn, pPriv, id, buf,
+                         src_x, src_y, width, height);
+   if (ret)
+       return ret;
+
+   if (pDraw->type == DRAWABLE_WINDOW) {
+      pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
+   } else {
+      pPixmap = (PixmapPtr)pDraw;
+   }
+
+   display_video(pScrn->pScreen, pPriv, id, clipBoxes,
+                 src_x, src_y, src_w, src_h,
+                 drw_x, drw_y,
+                 drw_w, drw_h, pPixmap);
+
+   pPriv->current_set = (pPriv->current_set + 1) & 1;
+   return Success;
+}
+
+static struct xorg_xv_port_priv *
+port_priv_create(struct xa_tracker *xat, struct xa_context *r,
+                int drm_fd)
+{
+   struct xorg_xv_port_priv *priv = NULL;
+
+   priv = calloc(1, sizeof(struct xorg_xv_port_priv));
+
+   if (!priv)
+      return NULL;
+
+   priv->r = r;
+   priv->xat = xat;
+   priv->drm_fd = drm_fd;
+   REGION_NULL(pScreen, &priv->clip);
+
+   return priv;
+}
+
+static void
+vmwgfx_free_textured_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports)
+{
+    if (free_ports) {
+       int i;
+
+       for(i=0; i<adaptor->nPorts; ++i) {
+           free(adaptor->pPortPrivates[i].ptr);
+       }
+    }
+
+    free(adaptor->pAttributes);
+    free(adaptor->pPortPrivates);
+    xf86XVFreeVideoAdaptorRec(adaptor);
+}
+
+static XF86VideoAdaptorPtr
+xorg_setup_textured_adapter(ScreenPtr pScreen)
+{
+   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+   modesettingPtr ms = modesettingPTR(pScrn);
+   XF86VideoAdaptorPtr adapt;
+   XF86AttributePtr attrs;
+   DevUnion *dev_unions;
+   int nports = 16, i;
+   int nattributes;
+   struct xa_context *xar;
+
+   /*
+    * Use the XA default context since we don't expect the X server
+    * to render from multiple threads.
+    */
+
+   xar = xa_context_default(ms->xat);
+   nattributes = NUM_TEXTURED_ATTRIBUTES;
+
+   adapt = calloc(1, sizeof(XF86VideoAdaptorRec));
+   dev_unions = calloc(nports, sizeof(DevUnion));
+   attrs = calloc(nattributes, sizeof(XF86AttributeRec));
+   if (adapt == NULL || dev_unions == NULL || attrs == NULL) {
+      free(adapt);
+      free(dev_unions);
+      free(attrs);
+      return NULL;
+   }
+
+   adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+   adapt->flags = 0;
+   adapt->name = "XA G3D Textured Video";
+   adapt->nEncodings = 1;
+   adapt->pEncodings = DummyEncoding;
+   adapt->nFormats = NUM_FORMATS;
+   adapt->pFormats = Formats;
+   adapt->nPorts = 0;
+   adapt->pPortPrivates = dev_unions;
+   adapt->nAttributes = nattributes;
+   adapt->pAttributes = attrs;
+   memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec));
+   adapt->nImages = NUM_IMAGES;
+   adapt->pImages = Images;
+   adapt->PutVideo = NULL;
+   adapt->PutStill = NULL;
+   adapt->GetVideo = NULL;
+   adapt->GetStill = NULL;
+   adapt->StopVideo = stop_video;
+   adapt->SetPortAttribute = set_port_attribute;
+   adapt->GetPortAttribute = get_port_attribute;
+   adapt->QueryBestSize = query_best_size;
+   adapt->PutImage = put_image;
+   adapt->QueryImageAttributes = query_image_attributes;
+
+
+   for (i = 0; i < nports; i++) {
+       struct xorg_xv_port_priv *priv =
+         port_priv_create(ms->xat, xar, ms->fd);
+
+      adapt->pPortPrivates[i].ptr = (pointer) (priv);
+      adapt->nPorts++;
+   }
+
+   return adapt;
+}
+
+void
+xorg_xv_init(ScreenPtr pScreen)
+{
+   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+   modesettingPtr ms = modesettingPTR(pScrn);
+   XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL;
+   XF86VideoAdaptorPtr textured_adapter = NULL, overlay_adaptor = NULL;
+   int num_adaptors;
+
+   num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
+   new_adaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
+   if (new_adaptors == NULL)
+       return;
+
+   memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
+   adaptors = new_adaptors;
+
+   /* Add the adaptors supported by our hardware.  First, set up the atoms
+    * that will be used by both output adaptors.
+    */
+   xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
+   xvContrast = MAKE_ATOM("XV_CONTRAST");
+
+   if (ms->xat) {
+       textured_adapter = xorg_setup_textured_adapter(pScreen);
+       if (textured_adapter)
+          adaptors[num_adaptors++] = textured_adapter;
+   } else {
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                 "No 3D acceleration. Not setting up textured video.\n");
+   }
+
+   overlay_adaptor = vmw_video_init_adaptor(pScrn);
+   if (overlay_adaptor)
+       adaptors[num_adaptors++] = overlay_adaptor;
+
+   if (num_adaptors) {
+       Bool ret;
+       ret = xf86XVScreenInit(pScreen, adaptors, num_adaptors);
+       if (textured_adapter)
+          vmwgfx_free_textured_adaptor(textured_adapter, !ret);
+       if (overlay_adaptor)
+          vmw_video_free_adaptor(overlay_adaptor, !ret);
+       if (!ret)
+          xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                     "Failed to initialize Xv.\n");
+   } else {
+       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                 "Disabling Xv because no adaptors could be initialized.\n");
+   }
+
+
+  out_err_mem:
+   free(adaptors);
+}