summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2011-06-16 15:55:07 +0200
committerThomas Hellstrom <thellstrom@vmware.com>2011-06-16 16:04:47 +0200
commit84166d4b457244bcc2f5ace63702d594d602d0c2 (patch)
tree892d9ee8de7a45b4d21505f9949a8424e3c81a44
parent0142bb8d10edb153c9ce79a2ea3ff92a7fb15ac5 (diff)
vmwgfx, saa: Initial import
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>
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac2
-rw-r--r--saa/Makefile.am13
-rw-r--r--saa/saa.c748
-rw-r--r--saa/saa.h192
-rw-r--r--saa/saa_accel.c141
-rw-r--r--saa/saa_pixmap.c222
-rw-r--r--saa/saa_priv.h263
-rw-r--r--saa/saa_render.c313
-rw-r--r--saa/saa_unaccel.c896
-rw-r--r--src/svga_reg.h1243
-rw-r--r--vmwgfx/Makefile.am24
-rw-r--r--vmwgfx/svga3d_reg.h1801
-rw-r--r--vmwgfx/vmwgfx_bootstrap.c199
-rw-r--r--vmwgfx/vmwgfx_crtc.c456
-rw-r--r--vmwgfx/vmwgfx_ctrl.c525
-rw-r--r--vmwgfx/vmwgfx_ctrl.h48
-rw-r--r--vmwgfx/vmwgfx_dri2.c373
-rw-r--r--vmwgfx/vmwgfx_driver.c947
-rw-r--r--vmwgfx/vmwgfx_driver.h167
-rw-r--r--vmwgfx/vmwgfx_drmi.c507
-rw-r--r--vmwgfx/vmwgfx_drmi.h81
-rw-r--r--vmwgfx/vmwgfx_output.c304
-rw-r--r--vmwgfx/vmwgfx_overlay.c893
-rw-r--r--vmwgfx/vmwgfx_saa.c1208
-rw-r--r--vmwgfx/vmwgfx_saa.h94
-rw-r--r--vmwgfx/vmwgfx_tex_video.c723
27 files changed, 12009 insertions, 376 deletions
diff --git a/Makefile.am b/Makefile.am
index 093e9f5..fff57f6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/configure.ac b/configure.ac
index cd2854e..bbb530a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
index 0000000..4f56d3f
--- /dev/null
+++ b/saa/Makefile.am
@@ -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
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
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
index 0000000..be33170
--- /dev/null
+++ b/saa/saa_accel.c
@@ -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
index 0000000..0d63091
--- /dev/null
+++ b/saa/saa_pixmap.c
@@ -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
index 0000000..f86f196
--- /dev/null
+++ b/saa/saa_priv.h
@@ -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
index 0000000..1df0dff
--- /dev/null
+++ b/saa/saa_render.c
@@ -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
index 0000000..27b399d
--- /dev/null
+++ b/saa/saa_unaccel.c
@@ -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,
+};
diff --git a/src/svga_reg.h b/src/svga_reg.h
index 4fa363a..5d36029 100644
--- a/src/svga_reg.h
+++ b/src/svga_reg.h
@@ -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))
@@ -63,19 +83,14 @@
#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.
@@ -87,15 +102,6 @@
#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
index 0000000..5efa8cd
--- /dev/null
+++ b/vmwgfx/Makefile.am
@@ -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
index 0000000..a527d7d
--- /dev/null
+++ b/vmwgfx/svga3d_reg.h
@@ -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
index 0000000..5e8e9e1
--- /dev/null
+++ b/vmwgfx/vmwgfx_bootstrap.c
@@ -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
index 0000000..49e84e8
--- /dev/null
+++ b/vmwgfx/vmwgfx_crtc.c
@@ -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
index 0000000..5157f86
--- /dev/null
+++ b/vmwgfx/vmwgfx_ctrl.c
@@ -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
index 0000000..8fedbce
--- /dev/null
+++ b/vmwgfx/vmwgfx_ctrl.h
@@ -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
index 0000000..748cbc8
--- /dev/null
+++ b/vmwgfx/vmwgfx_dri2.c
@@ -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
index 0000000..edf384d
--- /dev/null
+++ b/vmwgfx/vmwgfx_driver.c
@@ -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
index 0000000..4339fb7
--- /dev/null
+++ b/vmwgfx/vmwgfx_driver.h
@@ -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
index 0000000..3add305
--- /dev/null
+++ b/vmwgfx/vmwgfx_drmi.c
@@ -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
index 0000000..0c92719
--- /dev/null
+++ b/vmwgfx/vmwgfx_drmi.h
@@ -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
index 0000000..2081f2a
--- /dev/null
+++ b/vmwgfx/vmwgfx_output.c
@@ -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
index 0000000..d161023
--- /dev/null
+++ b/vmwgfx/vmwgfx_overlay.c
@@ -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
index 0000000..3122353
--- /dev/null
+++ b/vmwgfx/vmwgfx_saa.c
@@ -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
index 0000000..1a42cac
--- /dev/null
+++ b/vmwgfx/vmwgfx_saa.h
@@ -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
index 0000000..fb8f41e
--- /dev/null
+++ b/vmwgfx/vmwgfx_tex_video.c
@@ -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);
+}