diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2011-12-19 20:25:43 +0100 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2011-12-19 20:25:43 +0100 |
commit | b5546fb1de3f3859151a91e98ab0bd24b6789e2e (patch) | |
tree | 8e5283d6610e87d796e0d64b0a06c42469422b0d | |
parent | abf9cb75630cb27bb4741d194cb23014fe3d09b1 (diff) | |
parent | 5748c33535bc7d3009b9758653885e6ae0e73002 (diff) |
Merge branch 'vmwgfx_branch'
38 files changed, 15548 insertions, 1161 deletions
diff --git a/Makefile.am b/Makefile.am index 093e9f5..1203715 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 = @VMWGFX_DIRS@ src man vmwarectrl MAINTAINERCLEANFILES = ChangeLog INSTALL .PHONY: ChangeLog INSTALL diff --git a/configure.ac b/configure.ac index 74fd1b9..3aec9af 100644 --- a/configure.ac +++ b/configure.ac @@ -72,11 +72,6 @@ XORG_DRIVER_CHECK_EXT(XV, videoproto) # Obtain compiler/linker options for the driver dependencies PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.1 xproto fontsproto $REQUIRED_MODULES]) -PKG_CHECK_MODULES(LIBDRM, - [libdrm], - [AC_DEFINE([HAVE_LIBDRM], 1, [Has libdrm])], - [echo "Will not try support for 3D or kernel modesetting."]) - PKG_CHECK_EXISTS([xorg-server >= 1.1.0], [AC_DEFINE([HAVE_XORG_SERVER_1_1_0], 1, [Has version 1.1.0 or greater of the Xserver])]) @@ -91,7 +86,8 @@ PKG_CHECK_EXISTS([xorg-server >= 1.4.99], PKG_CHECK_EXISTS([xorg-server >= 1.7.0], [AC_DEFINE([HAVE_XORG_SERVER_1_7_0], 1, - [Has version 1.7.0 or greater of the Xserver])]) + [Has version 1.7.0 or greater of the Xserver]) + BUILD_VMWGFX=yes],[BUILD_VMWGFX=no]) # Obtain compiler/linker options for the vmwarectrl client tool PKG_CHECK_MODULES(X11, x11 xext) @@ -113,13 +109,40 @@ AM_CONDITIONAL(XSERVER_LIBPCIACCESS, test "x$XSERVER_LIBPCIACCESS" = xyes) AC_SUBST([moduledir]) +if test x$BUILD_VMWGFX = xyes; then + PKG_CHECK_MODULES([LIBDRM], [libdrm],[],[BUILD_VMWGFX=no]) +fi +if test x$BUILD_VMWGFX = xyes; then + PKG_CHECK_MODULES([XATRACKER], [xatracker >= 0.4.0],[],[BUILD_VMWGFX=no]) +fi + DRIVER_NAME=vmware AC_SUBST([DRIVER_NAME]) +AC_MSG_CHECKING([whether to build Kernel Mode Setting and 3D]) +VMWGFX_DIRS= +if test x$BUILD_VMWGFX = xyes; then + AC_MSG_RESULT([yes]) + AC_SYS_LARGEFILE + VMWGFX_DIRS="saa vmwgfx" + VMWGFX_LIBADD='$(top_srcdir)/vmwgfx/libvmwgfx.la' + AC_CONFIG_FILES([ + saa/Makefile + vmwgfx/Makefile + ]) + AC_DEFINE([BUILD_VMWGFX], 1, + [Building the vmwgfx driver path]) +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST([VMWGFX_DIRS]) +AC_SUBST([VMWGFX_LIBADD]) AC_CONFIG_FILES([ Makefile src/Makefile vmwarectrl/Makefile man/Makefile ]) + AC_OUTPUT diff --git a/saa/Makefile.am b/saa/Makefile.am new file mode 100644 index 0000000..849ced9 --- /dev/null +++ b/saa/Makefile.am @@ -0,0 +1,13 @@ +noinst_LTLIBRARIES = libsaa.la + +libsaa_la_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS) +libsaa_la_LDFLAGS = -static +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..173c090 --- /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 "regionstr.h" +#include "saa.h" +#include "saa_priv.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..c7aa3b6 --- /dev/null +++ b/saa/saa.h @@ -0,0 +1,209 @@ +/* + * + * 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> +#include <picturestr.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; + PictFormatShort src_format; + PictFormatShort dst_format; + 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); + Bool (*composite_prepare) (struct saa_driver *driver, CARD8 op, + PicturePtr src_pict, PicturePtr mask_pict, + PicturePtr dst_pict, + PixmapPtr src_pix, PixmapPtr mask_pix, + PixmapPtr dst_pix, + RegionPtr src_region, + RegionPtr mask_region, + RegionPtr dst_region); + void (*composite) (struct saa_driver *driver, + int src_x, int src_y, int mask_x, int mask_y, + int dst_x, int dst_y, + int width, int height); + void (*composite_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..5e1501b --- /dev/null +++ b/saa/saa_accel.c @@ -0,0 +1,153 @@ +/* + * 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" +#include <mi.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); + + if (src_spix->auth_loc != saa_loc_driver || + dst_spix->auth_loc != saa_loc_driver) + return FALSE; + + + 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); + } + +#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 6) + return miDoCopy(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, saa_copy_nton, 0, NULL); +#else + return fbDoCopy(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, + dstx, dsty, saa_copy_nton, 0, NULL); +#endif +} 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..6652054 --- /dev/null +++ b/saa/saa_priv.h @@ -0,0 +1,279 @@ +/* + * + * 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" +#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; + DrawablePtr srcDraw; +}; + +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 * +saa_pixmap(PixmapPtr pix) +{ + return (struct saa_pixmap *)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, + RegionPtr src_region, + RegionPtr mask_region, + RegionPtr dst_region); +#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); + + +Bool +saa_compute_composite_regions(ScreenPtr pScreen, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, + INT16 yDst, INT16 width, INT16 height, + RegionPtr dst_reg, + RegionPtr *src_reg, + RegionPtr *mask_reg); + +#endif diff --git a/saa/saa_render.c b/saa/saa_render.c new file mode 100644 index 0000000..c69f2c9 --- /dev/null +++ b/saa/saa_render.c @@ -0,0 +1,424 @@ +/* + * 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); + } +} + +static Bool +saa_driver_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, + RegionPtr src_reg, + RegionPtr mask_reg, + RegionPtr dst_reg) +{ + struct saa_screen_priv *sscreen = saa_screen(pDst->pDrawable->pScreen); + BoxPtr pbox; + int nbox; + int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y; + PixmapPtr src_pix = NULL, mask_pix = NULL, dst_pix; + struct saa_driver *driver = sscreen->driver; + + if (!driver->composite_prepare) + return FALSE; + + dst_pix = saa_get_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y); + if (saa_pixmap(dst_pix)->auth_loc != saa_loc_driver) + return FALSE; + + if (pMask && pMask->pDrawable) { + mask_pix = saa_get_pixmap(pMask->pDrawable, &mask_off_x, &mask_off_y); + if (saa_pixmap(mask_pix)->auth_loc != saa_loc_driver) + return FALSE; + } + if (pSrc->pDrawable) { + src_pix = saa_get_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); + if (saa_pixmap(src_pix)->auth_loc != saa_loc_driver) + return FALSE; + } + + if (!driver->composite_prepare(driver, op, pSrc, pMask, pDst, + src_pix, mask_pix, dst_pix, + src_reg, mask_reg, dst_reg)) + return FALSE; + + nbox = REGION_NUM_RECTS(dst_reg); + pbox = REGION_RECTS(dst_reg); + + xDst += pDst->pDrawable->x + dst_off_x; + yDst += pDst->pDrawable->y + dst_off_y; + + if (src_pix) { + xSrc += pSrc->pDrawable->x + src_off_x - xDst; + ySrc += pSrc->pDrawable->y + src_off_y - yDst; + } + if (mask_pix) { + xMask += pMask->pDrawable->x + mask_off_x - xDst; + yMask += pMask->pDrawable->y + mask_off_y - yDst; + } + + while (nbox--) { + driver->composite(driver, + pbox->x1 + xSrc, + pbox->y1 + ySrc, + pbox->x1 + xMask, + pbox->y1 + yMask, + pbox->x1, + pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + + driver->composite_done(driver); + saa_pixmap_dirty(dst_pix, TRUE, dst_reg); + + return TRUE; +} + +/* + * 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, + RegionPtr dst_region) +{ + 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 || + (op == PictOpOver && PICT_FORMAT_A(pSrc->format) == 0 && + pMask == NULL)) { + + int xoff, yoff; + PixmapPtr dst_pix = saa_get_pixmap(pDst->pDrawable, &xoff, &yoff); + struct saa_pixmap *dst_spix = saa_pixmap(dst_pix); + struct saa_pixmap *src_spix = + saa_pixmap(saa_get_drawable_pixmap(pSrc->pDrawable)); + int ret; + + if (src_spix->auth_loc != saa_loc_driver || + dst_spix->auth_loc != saa_loc_driver) + return FALSE; + + src_spix->src_format = pSrc->format; + dst_spix->dst_format = pDst->format; + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + + /* + * Dst region is in backing pixmap space. We need to + * translate it. + */ + REGION_TRANSLATE(pScreen, dst_region, -xoff, -yoff); + ret = saa_hw_copy_nton(pSrc->pDrawable, pDst->pDrawable, NULL, + REGION_RECTS(dst_region), + REGION_NUM_RECTS(dst_region), + xSrc - xDst, ySrc - yDst, FALSE, FALSE); + REGION_TRANSLATE(pScreen, dst_region, xoff, yoff); + + src_spix->src_format = 0; + dst_spix->dst_format = 0; + + 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) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + RegionRec dst_region; + RegionPtr src_region; + RegionPtr mask_region; + + REGION_NULL(pScreen, &dst_region); + if (!saa_compute_composite_regions(pScreen, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, + yDst, width, height, + &dst_region, &src_region, &mask_region)) + goto out; + + if (saa_copy_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height, &dst_region)) + goto out; + + if (saa_driver_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height, src_region, + mask_region, &dst_region)) + goto out; + + saa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height, + src_region, mask_region, &dst_region); + out: + if (src_region) + REGION_UNINIT(pScreen, src_region); + if (mask_region && mask_region != src_region) + REGION_UNINIT(pScreen, mask_region); + REGION_UNINIT(pScreen, &dst_region); +} + +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..deaf5aa --- /dev/null +++ b/saa/saa_unaccel.c @@ -0,0 +1,935 @@ +/* + * 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++; + + /* + * TODO: Use @prect for readback / damaging instead of + * the damage region. This may fragment the dirty regions more + * but should avoid unnecessary readbacks. + */ + if (!saa_pad_write(pDrawable, pGC, FALSE, &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); + int xoff, yoff; + BoxRec box; + RegionRec reg; + RegionPtr dst; + + (void) saa_get_pixmap(pDrawable, &xoff, &yoff); + box.x1 = x + xoff; + box.y1 = y + yoff; + box.x2 = box.x1 + width; + box.y2 = box.y1 + height; + + dst = (sscreen->srcDraw == pDrawable) ? + &sscreen->srcReg : &sscreen->maskReg; + + REGION_INIT(pScreen, ®, &box, 1); + REGION_UNION(pScreen, dst, dst, ®); + REGION_UNINIT(pScreen, ®); + + 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--; +} + +/* + * Compute composite regions taking transforms into account. + * The caller must provide a pointer to an initialized dst_reg, + * and the function returns pointers to set up source- and mask regions. + * The source and mask regions must be uninitialized after use. + */ + +Bool +saa_compute_composite_regions(ScreenPtr pScreen, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, + INT16 yMask, INT16 xDst, + INT16 yDst, INT16 width, INT16 height, + RegionPtr dst_reg, + RegionPtr *src_reg, + RegionPtr *mask_reg) +{ + struct saa_screen_priv *sscreen = saa_screen(pScreen); + PixmapPtr dst_pixmap; + RegionPtr srcReg = NULL; + RegionPtr maskReg = NULL; + Bool ret; + int xoff, yoff; + + *src_reg = NULL; + *mask_reg = NULL; + + if (pSrc->pDrawable) { + REGION_NULL(pScreen, &sscreen->srcReg); + srcReg = &sscreen->srcReg; + sscreen->srcDraw = pSrc->pDrawable; + if (pSrc != pDst) + REGION_TRANSLATE(pScreen, pSrc->pCompositeClip, + -pSrc->pDrawable->x, -pSrc->pDrawable->y); + } + + if (pMask && 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(dst_reg, 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; + } + + *src_reg = srcReg; + *mask_reg = maskReg; + + /* + * Translate dst region to pixmap space. + */ + dst_pixmap = saa_get_pixmap(pDst->pDrawable, &xoff, &yoff); + REGION_TRANSLATE(pScreen, dst_reg, pDst->pDrawable->x + xoff, + pDst->pDrawable->y + yoff); + + + return TRUE; +} + +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 src_region, + RegionPtr mask_region, + RegionPtr dst_region, + saa_access_t * access) +{ + RegionPtr dstReg = NULL; + PixmapPtr pSrcPix = NULL; + PixmapPtr pMaskPix = NULL; + PixmapPtr pDstPix; + struct saa_pixmap *dst_spix; + + *access = SAA_ACCESS_W; + + if (pSrc->pDrawable) + pSrcPix = saa_get_drawable_pixmap(pSrc->pDrawable); + if (pMask && pMask->pDrawable) + pMaskPix = saa_get_drawable_pixmap(pMask->pDrawable); + + /* + * 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, src_region)) + goto out_no_src; + if (pMaskPix) + if (!saa_prepare_access_pixmap(pMaskPix, SAA_ACCESS_R, mask_region)) + goto out_no_mask; + + pDstPix = saa_get_drawable_pixmap(pDst->pDrawable); + dst_spix = saa_get_saa_pixmap(pDstPix); + + if (dst_spix->damage && saa_op_reads_destination(op)) { + dstReg = dst_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"); + 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, + RegionPtr src_region, + RegionPtr mask_region, + RegionPtr dst_region) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + struct saa_screen_priv *sscreen = saa_screen(pScreen); + saa_access_t access; + PixmapPtr pixmap; + + sscreen->fallback_count++; + if (!saa_prepare_composite_reg(pScreen, op, pSrc, pMask, pDst, xSrc, + ySrc, xMask, yMask, xDst, yDst, width, + height, + src_region, + mask_region, + dst_region, + &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, dst_region); + 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, dst_region); + } + 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--; +} + +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/Makefile.am b/src/Makefile.am index 7c972cf..64a9069 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,12 +24,14 @@ # _ladir passes a dummy rpath to libtool so the thing will actually link # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. -vmwlegacy_drv_la_LTLIBRARIES = vmwlegacy_drv.la -vmwlegacy_drv_la_LDFLAGS = -module -avoid-version -vmwlegacy_drv_la_CFLAGS = @XORG_CFLAGS@ -vmwlegacy_drv_ladir = @moduledir@/drivers +vmware_drv_la_LTLIBRARIES = vmware_drv.la +vmware_drv_la_LDFLAGS = -module -avoid-version +vmware_drv_la_CFLAGS = @XORG_CFLAGS@ +vmware_drv_ladir = @moduledir@/drivers +vmware_drv_la_LIBADD = @VMWGFX_LIBADD@ +vmware_drv_la_DEPENDENCIES = @VMWGFX_LIBADD@ -vmwlegacy_drv_la_SOURCES = \ +vmware_drv_la_SOURCES = \ bits2pixels.c \ bits2pixels.h \ guest_os.h \ @@ -50,13 +52,8 @@ vmwlegacy_drv_la_SOURCES = \ vmwarectrlproto.h \ vmwarexinerama.c \ vmwarevideo.c \ - vmwaremodes.c - -vmware_drv_la_LTLIBRARIES = vmware_drv.la -vmware_drv_la_LDFLAGS = -module -avoid-version -vmware_drv_la_CFLAGS = @XORG_CFLAGS@ @LIBDRM_CFLAGS@ -vmware_drv_la_LIBADD = @LIBDRM_LIBS@ -vmware_drv_ladir = @moduledir@/drivers - -vmware_drv_la_SOURCES = \ - vmwaremodule.c + vmwaremodes.c \ + vmware_bootstrap.h \ + vmware_bootstrap.c \ + vmware_common.c \ + vmware_common.h diff --git a/src/svga_reg.h b/src/svga_reg.h index 4fa363a..6757aa6 100644 --- a/src/svga_reg.h +++ b/src/svga_reg.h @@ -1,52 +1,81 @@ -/* ********************************************************** - * 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" +/* + * PCI device IDs. + */ +#define PCI_VENDOR_ID_VMWARE 0x15AD +#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 /* - * Memory and port addresses and fundamental constants + * SVGA_REG_ENABLE bit definitions. */ +#define SVGA_REG_ENABLE_DISABLE 0 +#define SVGA_REG_ENABLE_ENABLE 1 +#define SVGA_REG_ENABLE_HIDE 2 +#define SVGA_REG_ENABLE_ENABLE_HIDE (SVGA_REG_ENABLE_ENABLE |\ + SVGA_REG_ENABLE_HIDE) /* - * 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 +92,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 +111,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 +123,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 +137,46 @@ 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_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */ + SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ + SVGA_REG_TOP = 48, /* 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 +184,264 @@ 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; -#define SVGA_INVALID_DISPLAY_ID ((uint32)-1) +typedef +struct SVGAGuestImage { + 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; +} SVGAGuestImage; /* - * 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) + * 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; + + +/* + * 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. + * + * SVGA_CAP_GMR2 -- + * Provides asynchronous commands to define and remap guest memory + * regions. Adds device registers SVGA_REG_GMRS_MAX_PAGES and + * SVGA_REG_MEMORY_SIZE. + * + * SVGA_CAP_SCREEN_OBJECT_2 -- + * Allow screen object support, and require backing stores from the + * guest for each screen object. + */ + +#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 +#define SVGA_CAP_GMR2 0x00400000 +#define SVGA_CAP_SCREEN_OBJECT_2 0x00800000 /* @@ -332,19 +498,47 @@ enum { * These in block 3a, the VMX currently considers mandatory for the * extended FIFO. */ - + /* 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: */ SVGA_FIFO_PITCHLOCK, + /* 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: */ SVGA_FIFO_RESERVED, /* Bytes past NEXT_CMD with real contents */ + + /* + * Valid with SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2: + * + * 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. + */ + SVGA_FIFO_CURSOR_SCREEN_ID, + + /* + * Valid with SVGA_FIFO_CAP_DEAD + * + * An arbitrary value written by the host, drivers should not use it. + */ + SVGA_FIFO_DEAD, + + /* + * Valid with SVGA_FIFO_CAP_3D_HWVERSION_REVISED: + * + * Contains 3D HWVERSION (see SVGA3dHardwareVersion in svga3d_reg.h) + * on platforms that can enforce graphics resource limits. + */ + SVGA_FIFO_3D_HWVERSION_REVISED, + /* * 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 +555,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. @@ -533,6 +728,87 @@ 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. + * + * SVGA_FIFO_CAP_GMR2 -- + * + * Provides new commands to define and remap guest memory regions (GMR). + * + * New 2D commands: + * DEFINE_GMR2, REMAP_GMR2. + * + * SVGA_FIFO_CAP_3D_HWVERSION_REVISED -- + * + * Indicates new register SVGA_FIFO_3D_HWVERSION_REVISED exists. + * This register may replace SVGA_FIFO_3D_HWVERSION on platforms + * that enforce graphics resource limits. This allows the platform + * to clear SVGA_FIFO_3D_HWVERSION and disable 3D in legacy guest + * drivers that do not limit their resources. + * + * Note this is an alias to SVGA_FIFO_CAP_GMR2 because these indicators + * are codependent (and thus we use a single capability bit). + * + * SVGA_FIFO_CAP_SCREEN_OBJECT_2 -- + * + * Modifies the DEFINE_SCREEN command to include a guest provided + * backing store in GMR memory and the bytesPerLine for the backing + * store. This capability requires the use of a backing store when + * creating screen objects. However if SVGA_FIFO_CAP_SCREEN_OBJECT + * is present then backing stores are optional. + * + * SVGA_FIFO_CAP_DEAD -- + * + * Drivers should not use this cap bit. This cap bit can not be + * reused since some hosts already expose it. */ #define SVGA_FIFO_CAP_NONE 0 @@ -543,6 +819,11 @@ 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) +#define SVGA_FIFO_CAP_GMR2 (1<<8) +#define SVGA_FIFO_CAP_3D_HWVERSION_REVISED SVGA_FIFO_CAP_GMR2 +#define SVGA_FIFO_CAP_SCREEN_OBJECT_2 (1<<9) +#define SVGA_FIFO_CAP_DEAD (1<<10) /* @@ -586,20 +867,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 +908,658 @@ 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. + * + * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2 are required fields of + * a SVGAGuestPtr that is used to back the screen contents. This + * memory must come from the GFB. The guest is not allowed to + * access the memory and doing so will have undefined results. The + * backing store is required to be page aligned and the size is + * padded to the next page boundry. The number of pages is: + * (bytesPerLine * size.width * 4 + PAGE_SIZE - 1) / PAGE_SIZE + * + * The pitch in the backingStore is required to be at least large + * enough to hold a 32bbp scanline. It is recommended that the + * driver pad bytesPerLine for a potential performance win. + * + * The cloneCount field is treated as a hint from the guest that + * the user wants this display to be cloned, countCount times. A + * value of zero means no cloning should happen. */ -#define SVGA_MAX_ID 499 +#define SVGA_SCREEN_MUST_BE_SET (1 << 0) /* Must be set or results undefined */ +#define SVGA_SCREEN_HAS_ROOT SVGA_SCREEN_MUST_BE_SET /* Deprecated */ +#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 */ /* - * Macros to compute variable length items (sizes in 32-bit words, except - * for SVGA_GLYPH_SCANLINE_SIZE, which is in bytes). + * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2. When the screen is + * deactivated the base layer is defined to lose all contents and + * become black. When a screen is deactivated the backing store is + * optional. When set backingPtr and bytesPerLine will be ignored. */ +#define SVGA_SCREEN_DEACTIVATE (1 << 3) + +/* + * Added with SVGA_FIFO_CAP_SCREEN_OBJECT_2. When this flag is set + * the screen contents will be outputted as all black to the user + * though the base layer contents is preserved. The screen base layer + * can still be read and written to like normal though the no visible + * effect will be seen by the user. When the flag is changed the + * screen will be blanked or redrawn to the current contents as needed + * without any extra commands from the driver. This flag only has an + * effect when the screen is not deactivated. + */ +#define SVGA_SCREEN_BLANKING (1 << 4) + +typedef +struct SVGAScreenObject { + uint32 structSize; /* sizeof(SVGAScreenObject) */ + uint32 id; + uint32 flags; + struct { + uint32 width; + uint32 height; + } size; + struct { + int32 x; + int32 y; + } root; + + /* + * Added and required by SVGA_FIFO_CAP_SCREEN_OBJECT_2, optional + * with SVGA_FIFO_CAP_SCREEN_OBJECT. + */ + SVGAGuestImage backingStore; + uint32 cloneCount; +} SVGAScreenObject; -#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) /* - * Increment from one scanline to the next of a bitmap or pixmap + * 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_INCREMENT(w) ((( (w)+31 ) >> 5) * sizeof (uint32)) -#define SVGA_PIXMAP_INCREMENT(w,bpp) ((( ((w)*(bpp))+31 ) >> 5) * sizeof (uint32)) + +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_DEFINE_GMR2 = 41, + SVGA_CMD_REMAP_GMR2 = 42, + SVGA_CMD_MAX +} SVGAFifoCmdId; + +#define SVGA_CMD_MAX_ARGS 64 + /* - * Transparent color for DRAW_GLYPH_CLIPPED + * 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_COLOR_TRANSPARENT (~0) + +typedef +struct SVGAFifoCmdUpdate { + uint32 x; + uint32 y; + uint32 width; + uint32 height; +} SVGAFifoCmdUpdate; + /* - * Commands in the command FIFO + * 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_CMD_INVALID_CMD 0 - /* FIFO layout: - <nothing> (well, undefined) */ +typedef +struct SVGAFifoCmdRectCopy { + uint32 srcX; + uint32 srcY; + uint32 destX; + uint32 destY; + uint32 width; + uint32 height; +} SVGAFifoCmdRectCopy; -#define SVGA_CMD_UPDATE 1 - /* FIFO layout: - X, Y, Width, Height */ -#define SVGA_CMD_RECT_FILL 2 - /* FIFO layout: - Color, X, Y, Width, Height */ +/* + * 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_RECT_COPY 3 - /* FIFO layout: - Source X, Source Y, Dest X, Dest Y, Width, Height */ +typedef +struct SVGAFifoCmdDefineCursor { + 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; -#define SVGA_CMD_DEFINE_BITMAP 4 - /* FIFO layout: - Pixmap ID, Width, Height, <scanlines> */ -#define SVGA_CMD_DEFINE_BITMAP_SCANLINE 5 - /* FIFO layout: - Pixmap ID, Width, Height, Line #, scanline */ +/* + * 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 + */ -#define SVGA_CMD_DEFINE_PIXMAP 6 - /* FIFO layout: - Pixmap ID, Width, Height, Depth, <scanlines> */ +typedef +struct SVGAFifoCmdDefineAlphaCursor { + uint32 id; /* Reserved, must be zero. */ + uint32 hotspotX; + uint32 hotspotY; + uint32 width; + uint32 height; + /* Followed by scanline data */ +} SVGAFifoCmdDefineAlphaCursor; -#define SVGA_CMD_DEFINE_PIXMAP_SCANLINE 7 - /* FIFO layout: - Pixmap ID, Width, Height, Depth, Line #, scanline */ -#define SVGA_CMD_RECT_BITMAP_FILL 8 - /* FIFO layout: - Bitmap ID, X, Y, Width, Height, Foreground, Background */ +/* + * 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 + */ -#define SVGA_CMD_RECT_PIXMAP_FILL 9 - /* FIFO layout: - Pixmap ID, X, Y, Width, Height */ +typedef +struct SVGAFifoCmdUpdateVerbose { + uint32 x; + uint32 y; + uint32 width; + uint32 height; + uint32 reason; +} SVGAFifoCmdUpdateVerbose; -#define SVGA_CMD_RECT_BITMAP_COPY 10 - /* FIFO layout: - Bitmap ID, Source X, Source Y, Dest X, Dest Y, - Width, Height, Foreground, Background */ -#define SVGA_CMD_RECT_PIXMAP_COPY 11 - /* FIFO layout: - Pixmap ID, Source X, Source Y, Dest X, Dest Y, Width, Height */ +/* + * 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_CMD_FREE_OBJECT 12 - /* FIFO layout: - Object (pixmap, bitmap, ...) ID */ +#define SVGA_INVALID_DISPLAY_ID ((uint32)-1) -#define SVGA_CMD_RECT_ROP_FILL 13 - /* FIFO layout: - Color, X, Y, Width, Height, ROP */ +typedef +struct SVGAFifoCmdFrontRopFill { + 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; -#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_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_RECT_ROP_PIXMAP_FILL 16 - /* FIFO layout: - ID, X, Y, Width, Height, ROP */ +typedef +struct { + uint32 fence; +} SVGAFifoCmdFence; -#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_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_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 SVGAFifoCmdEscape { + uint32 nsid; + uint32 size; + /* followed by 'size' bytes of data */ +} SVGAFifoCmdEscape; -#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_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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ -#define SVGA_CMD_DEFINE_ALPHA_CURSOR 22 - /* FIFO layout: - ID, Hotspot X, Hotspot Y, Width, Height, - <scanlines> */ +typedef +struct { + SVGAScreenObject screen; /* Variable-length according to version */ +} SVGAFifoCmdDefineScreen; -#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_DESTROY_SCREEN -- + * + * Destroy an SVGAScreenObject. Its ID is immediately available for + * re-use. + * + * Availability: + * SVGA_FIFO_CAP_SCREEN_OBJECT or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + uint32 screenId; +} SVGAFifoCmdDestroyScreen; + + +/* + * 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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + SVGAGuestPtr ptr; + uint32 bytesPerLine; + SVGAGMRImageFormat format; +} SVGAFifoCmdDefineGMRFB; + + +/* + * 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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + SVGASignedPoint srcOrigin; + SVGASignedRect destRect; + uint32 destScreenId; +} SVGAFifoCmdBlitGMRFBToScreen; + + +/* + * 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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + SVGASignedPoint destOrigin; + SVGASignedRect srcRect; + uint32 srcScreenId; +} SVGAFifoCmdBlitScreenToGMRFB; + + +/* + * 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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + SVGAColorBGRX color; +} SVGAFifoCmdAnnotationFill; + + +/* + * 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 or SVGA_FIFO_CAP_SCREEN_OBJECT_2 + */ + +typedef +struct { + SVGASignedPoint srcOrigin; + uint32 srcScreenId; +} SVGAFifoCmdAnnotationCopy; + + +/* + * SVGA_CMD_DEFINE_GMR2 -- + * + * Define guest memory region v2. See the description of GMRs above. + * + * Availability: + * SVGA_CAP_GMR2 + */ + +typedef +struct { + uint32 gmrId; + uint32 numPages; +} SVGAFifoCmdDefineGMR2; + + +/* + * SVGA_CMD_REMAP_GMR2 -- + * + * Remap guest memory region v2. See the description of GMRs above. + * + * This command allows guest to modify a portion of an existing GMR by + * invalidating it or reassigning it to different guest physical pages. + * The pages are identified by physical page number (PPN). The pages + * are assumed to be pinned and valid for DMA operations. + * + * Description of command flags: + * + * SVGA_REMAP_GMR2_VIA_GMR: If enabled, references a PPN list in a GMR. + * The PPN list must not overlap with the remap region (this can be + * handled trivially by referencing a separate GMR). If flag is + * disabled, PPN list is appended to SVGARemapGMR command. + * + * SVGA_REMAP_GMR2_PPN64: If set, PPN list is in PPN64 format, otherwise + * it is in PPN32 format. + * + * SVGA_REMAP_GMR2_SINGLE_PPN: If set, PPN list contains a single entry. + * A single PPN can be used to invalidate a portion of a GMR or + * map it to to a single guest scratch page. + * + * Availability: + * SVGA_CAP_GMR2 + */ + +typedef enum { + SVGA_REMAP_GMR2_PPN32 = 0, + SVGA_REMAP_GMR2_VIA_GMR = (1 << 0), + SVGA_REMAP_GMR2_PPN64 = (1 << 1), + SVGA_REMAP_GMR2_SINGLE_PPN = (1 << 2), +} SVGARemapGMR2Flags; + +typedef +struct { + uint32 gmrId; + SVGARemapGMR2Flags flags; + uint32 offsetPages; /* offset in pages to begin remap */ + uint32 numPages; /* number of pages to remap */ + /* + * Followed by additional data depending on SVGARemapGMR2Flags. + * + * If flag SVGA_REMAP_GMR2_VIA_GMR is set, single SVGAGuestPtr follows. + * Otherwise an array of page descriptors in PPN32 or PPN64 format + * (according to flag SVGA_REMAP_GMR2_PPN64) follows. If flag + * SVGA_REMAP_GMR2_SINGLE_PPN is set, array contains a single entry. + */ +} SVGAFifoCmdRemapGMR2; #endif diff --git a/src/vmware.c b/src/vmware.c index fa01dca..9160cf2 100644 --- a/src/vmware.c +++ b/src/vmware.c @@ -39,195 +39,17 @@ char rcsId_vmware[] = #include "guest_os.h" #include "vm_device_version.h" #include "svga_modes.h" +#include "vmware_bootstrap.h" +#include "vmware_common.h" #ifndef HAVE_XORG_SERVER_1_5_0 #include <xf86_ansic.h> #include <xf86_libc.h> #endif -#ifdef HaveDriverFuncs -#define VMWARE_DRIVER_FUNC HaveDriverFuncs -#else -#define VMWARE_DRIVER_FUNC 0 -#endif - -/* - * So that the file compiles unmodified when dropped in to a < 6.9 source tree. - */ -#ifndef _X_EXPORT -#define _X_EXPORT -#endif -/* - * So that the file compiles unmodified when dropped into an xfree source tree. - */ -#ifndef XORG_VERSION_CURRENT -#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT -#endif - -/* - * Sanity check that xf86PciInfo.h has the correct values (which come from - * the VMware source tree in vm_device_version.h. - */ -#if PCI_CHIP_VMWARE0405 != PCI_DEVICE_ID_VMWARE_SVGA2 -#error "PCI_CHIP_VMWARE0405 is wrong, update it from vm_device_version.h" -#endif -#if PCI_CHIP_VMWARE0710 != PCI_DEVICE_ID_VMWARE_SVGA -#error "PCI_CHIP_VMWARE0710 is wrong, update it from vm_device_version.h" -#endif -#if PCI_VENDOR_VMWARE != PCI_VENDOR_ID_VMWARE -#error "PCI_VENDOR_VMWARE is wrong, update it from vm_device_version.h" -#endif - -#define VMWARE_INCHTOMM 25.4 - -/* - * This is the only way I know to turn a #define of an integer constant into - * a constant string. - */ -#define VMW_INNERSTRINGIFY(s) #s -#define VMW_STRING(str) VMW_INNERSTRINGIFY(str) - -#define VMWARE_NAME "vmwlegacy" -#define VMWARE_DRIVER_NAME "vmwlegacy" -#define VMWARE_DRIVER_VERSION \ - (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL) -#define VMWARE_DRIVER_VERSION_STRING \ - VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \ - "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL) - -static const char VMWAREBuildStr[] = "VMware Guest X Server " - VMWARE_DRIVER_VERSION_STRING " - build=$Name$\n"; - -/* - * Standard four digit version string expected by VMware Tools installer. - * As the driver's version is only {major, minor, patchlevel}, - * The fourth digit may describe the commit number relative to the - * last version tag as output from `git describe` - */ - -#ifdef __GNUC__ -#ifdef VMW_SUBPATCH -const char vmwlegacy_drv_modinfo[] -__attribute__((section(".modinfo"),unused)) = - "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH); -#else -const char vmwlegacy_drv_modinfo[] -__attribute__((section(".modinfo"),unused)) = - "version=" VMWARE_DRIVER_VERSION_STRING ".0"; -#endif /*VMW_SUBPATCH*/ -#endif - -static SymTabRec VMWAREChipsets[] = { - { PCI_CHIP_VMWARE0405, "vmware0405" }, - { PCI_CHIP_VMWARE0710, "vmware0710" }, - { -1, NULL } -}; - -#ifndef XSERVER_LIBPCIACCESS -static resRange vmwareLegacyRes[] = { - { ResExcIoBlock, SVGA_LEGACY_BASE_PORT, - SVGA_LEGACY_BASE_PORT + SVGA_NUM_PORTS*sizeof(uint32)}, - _VGA_EXCLUSIVE, _END -}; -#else -#define vmwareLegacyRes NULL -#endif - -#if XSERVER_LIBPCIACCESS - -#define VMWARE_DEVICE_MATCH(d, i) \ - {PCI_VENDOR_VMWARE, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) } - -static const struct pci_id_match VMwareDeviceMatch[] = { - VMWARE_DEVICE_MATCH (PCI_CHIP_VMWARE0405, 0 ), - VMWARE_DEVICE_MATCH (PCI_CHIP_VMWARE0710, 0 ), - { 0, 0, 0 }, -}; -#endif - -/* - * Currently, even the PCI obedient 0405 chip still only obeys IOSE and - * MEMSE for the SVGA resources. Thus, RES_EXCLUSIVE_VGA is required. - * - * The 0710 chip also uses hardcoded IO ports that aren't disablable. - */ - -static PciChipsets VMWAREPciChipsets[] = { - { PCI_CHIP_VMWARE0405, PCI_CHIP_VMWARE0405, RES_EXCLUSIVE_VGA }, - { PCI_CHIP_VMWARE0710, PCI_CHIP_VMWARE0710, vmwareLegacyRes }, - { -1, -1, RES_UNDEFINED } -}; - -#if HAVE_XORG_SERVER_1_7_0 - +#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5) #define xf86LoaderReqSymLists(...) do {} while (0) -#define LoaderRefSymLists(...) do {} while (0) - -#else - -static const char *vgahwSymbols[] = { - "vgaHWGetHWRec", - "vgaHWGetIOBase", - "vgaHWGetIndex", - "vgaHWInit", - "vgaHWProtect", - "vgaHWRestore", - "vgaHWSave", - "vgaHWSaveScreen", - "vgaHWUnlock", - NULL -}; - -static const char *fbSymbols[] = { - "fbCreateDefColormap", - "fbPictureInit", - "fbScreenInit", - NULL -}; - -static const char *ramdacSymbols[] = { - "xf86CreateCursorInfoRec", - "xf86DestroyCursorInfoRec", - "xf86InitCursor", - NULL -}; - -static const char *shadowfbSymbols[] = { - "ShadowFBInit2", - NULL -}; - -#endif /* HAVE_XORG_SERVER_1_7_0 */ - -#ifdef XFree86LOADER -static XF86ModuleVersionInfo vmwlegacyVersRec = { - VMWARE_DRIVER_NAME, - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, - ABI_CLASS_VIDEODRV, - ABI_VIDEODRV_VERSION, - MOD_CLASS_VIDEODRV, - { 0, 0, 0, 0} -}; -#endif /* XFree86LOADER */ - -typedef enum { - OPTION_HW_CURSOR, - OPTION_XINERAMA, - OPTION_STATIC_XINERAMA, - OPTION_DEFAULT_MODE, -} VMWAREOpts; - -static const OptionInfoRec VMWAREOptions[] = { - { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_XINERAMA, "Xinerama", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_STRING, {0}, FALSE }, - { OPTION_DEFAULT_MODE, "AddDefaultMode", OPTV_BOOLEAN, {0}, FALSE }, - { -1, NULL, OPTV_NONE, {0}, FALSE } -}; +#endif /* Table of default modes to always add to the mode list. */ @@ -466,141 +288,6 @@ RewriteTagString(const char *istr, char *ostr, int osize) } #endif -static void -VMWAREIdentify(int flags) -{ - xf86PrintChipsets(VMWARE_NAME, "driver for VMware SVGA", VMWAREChipsets); -} - -static const OptionInfoRec * -VMWAREAvailableOptions(int chipid, int busid) -{ - return VMWAREOptions; -} - -static int -VMWAREParseTopologyElement(ScrnInfoPtr pScrn, - unsigned int output, - const char *elementName, - const char *element, - const char *expectedTerminators, - Bool needTerminator, - unsigned int *outValue) -{ - char buf[10] = {0, }; - size_t i = 0; - int retVal = -1; - const char *str = element; - - for (i = 0; str[i] >= '0' && str[i] <= '9'; i++); - if (i == 0) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: unable to parse %s.\n", - output, elementName); - goto exit; - } - - strncpy(buf, str, i); - *outValue = atoi(buf); - - if (*outValue > (unsigned short)-1) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: %s must be less than %hu.\n", - output, elementName, (unsigned short)-1); - goto exit; - } - - str += i; - - if (needTerminator || str[0] != '\0') { - Bool unexpected = TRUE; - - for (i = 0; i < strlen(expectedTerminators); i++) { - if (str[0] == expectedTerminators[i]) { - unexpected = FALSE; - } - } - - if (unexpected) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Output %u: unexpected character '%c' after %s.\n", - output, str[0], elementName); - goto exit; - } else { - str++; - } - } - - retVal = str - element; - - exit: - return retVal; -} - -static xXineramaScreenInfo * -VMWAREParseTopologyString(ScrnInfoPtr pScrn, - const char *topology, - unsigned int *retNumOutputs) -{ - xXineramaScreenInfo *extents = NULL; - unsigned int numOutputs = 0; - const char *str = topology; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing static Xinerama topology: Starting...\n"); - - do { - unsigned int x, y, width, height; - int i; - - i = VMWAREParseTopologyElement(pScrn, numOutputs, "width", str, "xX", TRUE, &width); - if (i == -1) { - goto error; - } - str += i; - - i = VMWAREParseTopologyElement(pScrn, numOutputs, "height", str, "+", TRUE, &height); - if (i == -1) { - goto error; - } - str += i; - - i= VMWAREParseTopologyElement(pScrn, numOutputs, "X offset", str, "+", TRUE, &x); - if (i == -1) { - goto error; - } - str += i; - - i = VMWAREParseTopologyElement(pScrn, numOutputs, "Y offset", str, ";", FALSE, &y); - if (i == -1) { - goto error; - } - str += i; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: %ux%u+%u+%u\n", - numOutputs, width, height, x, y); - - numOutputs++; - extents = realloc(extents, numOutputs * sizeof (xXineramaScreenInfo)); - extents[numOutputs - 1].x_org = x; - extents[numOutputs - 1].y_org = y; - extents[numOutputs - 1].width = width; - extents[numOutputs - 1].height = height; - } while (*str != 0); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing static Xinerama topology: Succeeded.\n"); - goto exit; - - error: - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing static Xinerama topology: Failed.\n"); - - free(extents); - extents = NULL; - numOutputs = 0; - - exit: - *retNumOutputs = numOutputs; - return extents; -} - - static Bool VMWAREPreInit(ScrnInfoPtr pScrn, int flags) { @@ -899,18 +586,14 @@ VMWAREPreInit(ScrnInfoPtr pScrn, int flags) #endif xf86CollectOptions(pScrn, NULL); - if (!(options = malloc(sizeof(VMWAREOptions)))) + if (!(options = VMWARECopyOptions())) return FALSE; - memcpy(options, VMWAREOptions, sizeof(VMWAREOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); if (pScrn->depth <= 8) { pScrn->rgbBits = 8; } - from = X_PROBED; - pScrn->chipset = (char*)xf86TokenToString(VMWAREChipsets, DEVICE_ID(pVMWARE->PciInfo)); - if (!pScrn->chipset) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04x is not recognised\n", DEVICE_ID(pVMWARE->PciInfo)); return FALSE; @@ -1608,46 +1291,6 @@ vmwareIsRegionEqual(const RegionPtr reg1, return TRUE; } -#if VMWARE_DRIVER_FUNC -static Bool -VMWareDriverFunc(ScrnInfoPtr pScrn, - xorgDriverFuncOp op, - pointer data) -{ - CARD32 *flag; - xorgRRModeMM *modemm; - - switch (op) { - case GET_REQUIRED_HW_INTERFACES: - flag = (CARD32 *)data; - - if (flag) { - *flag = HW_IO | HW_MMIO; - } - return TRUE; - case RR_GET_MODE_MM: - modemm = (xorgRRModeMM *)data; - - /* - * Because changing the resolution of the guest is usually changing the size - * of a window on the host desktop, the real physical DPI will not change. To - * keep the guest in sync, we scale the 'physical' screen dimensions to - * keep the DPI constant. - */ - if (modemm && modemm->mode) { - modemm->mmWidth = (modemm->mode->HDisplay * VMWARE_INCHTOMM + - pScrn->xDpi / 2) / pScrn->xDpi; - modemm->mmHeight = (modemm->mode->VDisplay * VMWARE_INCHTOMM + - pScrn->yDpi / 2) / pScrn->yDpi; - } - return TRUE; - default: - return FALSE; - } -} -#endif - - static Bool VMWAREScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { @@ -1663,9 +1306,8 @@ VMWAREScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) xf86CollectOptions(pScrn, NULL); - if (!(options = malloc(sizeof(VMWAREOptions)))) + if (!(options = VMWARECopyOptions())) return FALSE; - memcpy(options, VMWAREOptions, sizeof(VMWAREOptions)); xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options); /* @@ -1680,11 +1322,25 @@ VMWAREScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) } - if (useXinerama && xf86IsOptionSet(options, OPTION_STATIC_XINERAMA)) { + if (useXinerama && xf86IsOptionSet(options, OPTION_GUI_LAYOUT)) { + char *topology = xf86GetOptValString(options, OPTION_GUI_LAYOUT); + if (topology) { + pVMWARE->xineramaState = + VMWAREParseTopologyString(pScrn, topology, + &pVMWARE->xineramaNumOutputs, "gui"); + + pVMWARE->xineramaStatic = pVMWARE->xineramaState != NULL; + + free(topology); + } + } else if (useXinerama && + xf86IsOptionSet(options, OPTION_STATIC_XINERAMA)) { char *topology = xf86GetOptValString(options, OPTION_STATIC_XINERAMA); if (topology) { pVMWARE->xineramaState = - VMWAREParseTopologyString(pScrn, topology, &pVMWARE->xineramaNumOutputs); + VMWAREParseTopologyString(pScrn, topology, + &pVMWARE->xineramaNumOutputs, + "static Xinerama"); pVMWARE->xineramaStatic = pVMWARE->xineramaState != NULL; @@ -1986,155 +1642,14 @@ VMWAREValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) return MODE_OK; } -#if XSERVER_LIBPCIACCESS -static Bool -VMwarePciProbe (DriverPtr drv, - int entity_num, - struct pci_device *device, - intptr_t match_data) -{ - ScrnInfoPtr scrn = NULL; - EntityInfoPtr entity; - - scrn = xf86ConfigPciEntity(scrn, 0, entity_num, VMWAREPciChipsets, - NULL, NULL, NULL, NULL, NULL); - if (scrn != NULL) { - scrn->driverVersion = VMWARE_DRIVER_VERSION; - scrn->driverName = VMWARE_DRIVER_NAME; - scrn->name = VMWARE_NAME; - scrn->Probe = NULL; - } - - entity = xf86GetEntityInfo(entity_num); - switch (DEVICE_ID(device)) { - case PCI_CHIP_VMWARE0405: - case PCI_CHIP_VMWARE0710: - xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Valid device\n"); - scrn->PreInit = VMWAREPreInit; - scrn->ScreenInit = VMWAREScreenInit; - scrn->SwitchMode = VMWARESwitchMode; - scrn->EnterVT = VMWAREEnterVT; - scrn->LeaveVT = VMWARELeaveVT; - scrn->FreeScreen = VMWAREFreeScreen; - scrn->ValidMode = VMWAREValidMode; - break; - default: - xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Unknown device\n"); - } - return scrn != NULL; -} -#else - -static Bool -VMWAREProbe(DriverPtr drv, int flags) -{ - int numDevSections, numUsed; - GDevPtr *devSections; - int *usedChips; - int i; - Bool foundScreen = FALSE; - char buildString[sizeof(VMWAREBuildStr)]; - - RewriteTagString(VMWAREBuildStr, buildString, sizeof(VMWAREBuildStr)); - xf86MsgVerb(X_PROBED, 4, "%s", buildString); - - numDevSections = xf86MatchDevice(VMWARE_DRIVER_NAME, &devSections); - if (numDevSections <= 0) { -#ifdef DEBUG - xf86MsgVerb(X_ERROR, 0, "No vmware driver section\n"); -#endif - return FALSE; - } - if (xf86GetPciVideoInfo()) { - VmwareLog(("Some PCI Video Info Exists\n")); - numUsed = xf86MatchPciInstances(VMWARE_NAME, PCI_VENDOR_VMWARE, - VMWAREChipsets, VMWAREPciChipsets, devSections, - numDevSections, drv, &usedChips); - free(devSections); - if (numUsed <= 0) - return FALSE; - if (flags & PROBE_DETECT) - foundScreen = TRUE; - else - for (i = 0; i < numUsed; i++) { - ScrnInfoPtr pScrn = NULL; - - VmwareLog(("Even some VMware SVGA PCI instances exists\n")); - pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i], - VMWAREPciChipsets, NULL, NULL, NULL, - NULL, NULL); - if (pScrn) { - VmwareLog(("And even configuration suceeded\n")); - pScrn->driverVersion = VMWARE_DRIVER_VERSION; - pScrn->driverName = VMWARE_DRIVER_NAME; - pScrn->name = VMWARE_NAME; - pScrn->Probe = VMWAREProbe; - pScrn->PreInit = VMWAREPreInit; - pScrn->ScreenInit = VMWAREScreenInit; - pScrn->SwitchMode = VMWARESwitchMode; - pScrn->AdjustFrame = VMWAREAdjustFrame; - pScrn->EnterVT = VMWAREEnterVT; - pScrn->LeaveVT = VMWARELeaveVT; - pScrn->FreeScreen = VMWAREFreeScreen; - pScrn->ValidMode = VMWAREValidMode; - foundScreen = TRUE; - } - } - free(usedChips); - } - return foundScreen; -} -#endif - - -_X_EXPORT DriverRec vmwlegacy = { - VMWARE_DRIVER_VERSION, - VMWARE_DRIVER_NAME, - VMWAREIdentify, -#if XSERVER_LIBPCIACCESS - NULL, -#else - VMWAREProbe, -#endif - VMWAREAvailableOptions, - NULL, - 0, -#if VMWARE_DRIVER_FUNC - VMWareDriverFunc, -#endif -#if XSERVER_LIBPCIACCESS - VMwareDeviceMatch, - VMwarePciProbe, -#endif -}; - -#ifdef XFree86LOADER -static MODULESETUPPROTO(vmwlegacySetup); - -_X_EXPORT XF86ModuleData vmwlegacyModuleData = { - &vmwlegacyVersRec, - vmwlegacySetup, - NULL -}; - -static pointer -vmwlegacySetup(pointer module, pointer opts, int *errmaj, int *errmin) +void +vmwlegacy_hookup(ScrnInfoPtr pScrn) { - static Bool setupDone = FALSE; - - if (!setupDone) { - setupDone = TRUE; - - xf86AddDriver(&vmwlegacy, module, VMWARE_DRIVER_FUNC); - - LoaderRefSymLists(vgahwSymbols, fbSymbols, ramdacSymbols, - shadowfbSymbols, NULL); - - return (pointer)1; - } - if (errmaj) { - *errmaj = LDR_ONCEONLY; - } - return NULL; + pScrn->PreInit = VMWAREPreInit; + pScrn->ScreenInit = VMWAREScreenInit; + pScrn->SwitchMode = VMWARESwitchMode; + pScrn->EnterVT = VMWAREEnterVT; + pScrn->LeaveVT = VMWARELeaveVT; + pScrn->FreeScreen = VMWAREFreeScreen; + pScrn->ValidMode = VMWAREValidMode; } -#endif /* XFree86LOADER */ diff --git a/src/vmware_bootstrap.c b/src/vmware_bootstrap.c new file mode 100644 index 0000000..522fec0 --- /dev/null +++ b/src/vmware_bootstrap.c @@ -0,0 +1,503 @@ +/* + * 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: Unknown at vmware + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" +#include "compiler.h" +#include "xf86PciInfo.h" /* pci vendor id */ +#include "xf86Pci.h" /* pci */ +#include "vm_device_version.h" +#include "vmware_bootstrap.h" + +#ifndef HAVE_XORG_SERVER_1_5_0 +#include <xf86_ansic.h> +#include <xf86_libc.h> +#endif + +#ifdef HaveDriverFuncs +#define VMWARE_DRIVER_FUNC HaveDriverFuncs +#else +#define VMWARE_DRIVER_FUNC 0 +#endif + +/* + * So that the file compiles unmodified when dropped in to a < 6.9 source tree. + */ +#ifndef _X_EXPORT +#define _X_EXPORT +#endif +/* + * So that the file compiles unmodified when dropped into an xfree source tree. + */ +#ifndef XORG_VERSION_CURRENT +#define XORG_VERSION_CURRENT XF86_VERSION_CURRENT +#endif + +/* + * Sanity check that xf86PciInfo.h has the correct values (which come from + * the VMware source tree in vm_device_version.h. + */ +#if PCI_CHIP_VMWARE0405 != PCI_DEVICE_ID_VMWARE_SVGA2 +#error "PCI_CHIP_VMWARE0405 is wrong, update it from vm_device_version.h" +#endif +#if PCI_CHIP_VMWARE0710 != PCI_DEVICE_ID_VMWARE_SVGA +#error "PCI_CHIP_VMWARE0710 is wrong, update it from vm_device_version.h" +#endif +#if PCI_VENDOR_VMWARE != PCI_VENDOR_ID_VMWARE +#error "PCI_VENDOR_VMWARE is wrong, update it from vm_device_version.h" +#endif + +/* + * This is the only way I know to turn a #define of an integer constant into + * a constant string. + */ +#define VMW_INNERSTRINGIFY(s) #s +#define VMW_STRING(str) VMW_INNERSTRINGIFY(str) + +#define VMWARE_NAME "vmware" +#define VMWARE_DRIVER_NAME "vmware" +#define VMWARE_DRIVER_VERSION \ + (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL) +#define VMWARE_DRIVER_VERSION_STRING \ + VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \ + "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL) + +static const char VMWAREBuildStr[] = "VMware Guest X Server " + VMWARE_DRIVER_VERSION_STRING " - build=$Name$\n"; + +/* + * Standard four digit version string expected by VMware Tools installer. + * As the driver's version is only {major, minor, patchlevel}, + * The fourth digit may describe the commit number relative to the + * last version tag as output from `git describe` + */ + +#ifdef __GNUC__ +#ifdef VMW_SUBPATCH +const char vmware_drv_modinfo[] +__attribute__((section(".modinfo"),unused)) = + "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH); +#else +const char vmware_drv_modinfo[] +__attribute__((section(".modinfo"),unused)) = + "version=" VMWARE_DRIVER_VERSION_STRING ".0"; +#endif /*VMW_SUBPATCH*/ +#endif + +#ifndef XSERVER_LIBPCIACCESS +static resRange vmwareLegacyRes[] = { + { ResExcIoBlock, SVGA_LEGACY_BASE_PORT, + SVGA_LEGACY_BASE_PORT + SVGA_NUM_PORTS*sizeof(uint32)}, + _VGA_EXCLUSIVE, _END +}; +#else +#define vmwareLegacyRes NULL +#endif + +#if XSERVER_LIBPCIACCESS +#define VENDOR_ID(p) (p)->vendor_id +#define DEVICE_ID(p) (p)->device_id +#define SUBVENDOR_ID(p) (p)->subvendor_id +#define SUBSYS_ID(p) (p)->subdevice_id +#define CHIP_REVISION(p) (p)->revision +#else +#define VENDOR_ID(p) (p)->vendor +#define DEVICE_ID(p) (p)->chipType +#define SUBVENDOR_ID(p) (p)->subsysVendor +#define SUBSYS_ID(p) (p)->subsysCard +#define CHIP_REVISION(p) (p)->chipRev +#endif + +#if XSERVER_LIBPCIACCESS + +#define VMWARE_DEVICE_MATCH(d, i) \ + {PCI_VENDOR_VMWARE, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) } + +static const struct pci_id_match VMwareDeviceMatch[] = { + VMWARE_DEVICE_MATCH (PCI_CHIP_VMWARE0405, 0 ), + VMWARE_DEVICE_MATCH (PCI_CHIP_VMWARE0710, 0 ), + { 0, 0, 0 }, +}; +#endif + +/* + * Currently, even the PCI obedient 0405 chip still only obeys IOSE and + * MEMSE for the SVGA resources. Thus, RES_EXCLUSIVE_VGA is required. + * + * The 0710 chip also uses hardcoded IO ports that aren't disablable. + */ + +static PciChipsets VMWAREPciChipsets[] = { + { PCI_CHIP_VMWARE0405, PCI_CHIP_VMWARE0405, RES_EXCLUSIVE_VGA }, + { PCI_CHIP_VMWARE0710, PCI_CHIP_VMWARE0710, vmwareLegacyRes }, + { -1, -1, RES_UNDEFINED } +}; + +static SymTabRec VMWAREChipsets[] = { + { PCI_CHIP_VMWARE0405, "vmware0405" }, + { PCI_CHIP_VMWARE0710, "vmware0710" }, + { -1, NULL } +}; + +#ifdef XFree86LOADER +static XF86ModuleVersionInfo vmwareVersRec = { + VMWARE_DRIVER_NAME, + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + { 0, 0, 0, 0} +}; +#endif /* XFree86LOADER */ + +static const OptionInfoRec VMWAREOptions[] = { + { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_XINERAMA, "Xinerama", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_STATIC_XINERAMA, "StaticXinerama", OPTV_STRING, {0}, FALSE }, + { OPTION_GUI_LAYOUT, "GuiLayout", OPTV_STRING, {0}, FALSE }, + { OPTION_DEFAULT_MODE, "AddDefaultMode", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_RENDER_ACCEL, "RenderAccel", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_DIRECT_PRESENTS, "DirectPresents", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_HW_PRESENTS, "HWPresents", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_RENDERCHECK, "RenderCheck", OPTV_BOOLEAN, {0}, FALSE}, + { -1, NULL, OPTV_NONE, {0}, FALSE } +}; + +OptionInfoPtr VMWARECopyOptions(void) +{ + OptionInfoPtr options; + if (!(options = malloc(sizeof(VMWAREOptions)))) + return NULL; + + memcpy(options, VMWAREOptions, sizeof(VMWAREOptions)); + return options; +} + +static Bool +VMwarePreinitStub(ScrnInfoPtr pScrn, int flags) +{ +#if XSERVER_LIBPCIACCESS + struct pci_device *pciInfo; +#else + pciVideoPtr pciInfo; +#endif /* XSERVER_LIBPCIACCESS */ + EntityInfoPtr pEnt; + + pScrn->PreInit = pScrn->driverPrivate; + +#ifdef BUILD_VMWGFX + pScrn->driverPrivate = NULL; + + /* + * Try vmwgfx path. + */ + if ((*pScrn->PreInit)(pScrn, flags)) + return TRUE; + +#else + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Driver was compiled without KMS- and 3D support.\n"); +#endif /* defined(BUILD_VMWGFX) */ + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling 3D support.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling Render Acceleration.\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Disabling RandR12+ support.\n"); + + pScrn->driverPrivate = NULL; + vmwlegacy_hookup(pScrn); + + pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + if (pEnt->location.type != BUS_PCI) + return FALSE; + + pciInfo = xf86GetPciInfoForEntity(pEnt->index); + if (pciInfo == NULL) + return FALSE; + + pScrn->chipset = (char*)xf86TokenToString(VMWAREChipsets, + DEVICE_ID(pciInfo)); + + return (*pScrn->PreInit)(pScrn, flags); +}; + +#if XSERVER_LIBPCIACCESS +static Bool +VMwarePciProbe (DriverPtr drv, + int entity_num, + struct pci_device *device, + intptr_t match_data) +{ + ScrnInfoPtr scrn = NULL; + EntityInfoPtr entity; + + scrn = xf86ConfigPciEntity(scrn, 0, entity_num, VMWAREPciChipsets, + NULL, NULL, NULL, NULL, NULL); + if (scrn != NULL) { + scrn->driverVersion = VMWARE_DRIVER_VERSION; + scrn->driverName = VMWARE_DRIVER_NAME; + scrn->name = VMWARE_NAME; + scrn->Probe = NULL; + } + + entity = xf86GetEntityInfo(entity_num); + switch (DEVICE_ID(device)) { + case PCI_CHIP_VMWARE0405: + case PCI_CHIP_VMWARE0710: + xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Valid device\n"); + +#ifdef BUILD_VMWGFX + vmwgfx_hookup(scrn); +#else + vmwlegacy_hookup(scrn); +#endif /* defined(BUILD_VMWGFX) */ + + scrn->driverPrivate = scrn->PreInit; + scrn->PreInit = VMwarePreinitStub; + break; + default: + xf86MsgVerb(X_INFO, 4, "VMwarePciProbe: Unknown device\n"); + } + return scrn != NULL; +} +#else + +static Bool +VMWAREProbe(DriverPtr drv, int flags) +{ + int numDevSections, numUsed; + GDevPtr *devSections; + int *usedChips; + int i; + Bool foundScreen = FALSE; + char buildString[sizeof(VMWAREBuildStr)]; + + RewriteTagString(VMWAREBuildStr, buildString, sizeof(VMWAREBuildStr)); + xf86MsgVerb(X_PROBED, 4, "%s", buildString); + + numDevSections = xf86MatchDevice(VMWARE_DRIVER_NAME, &devSections); + if (numDevSections <= 0) { +#ifdef DEBUG + xf86MsgVerb(X_ERROR, 0, "No vmware driver section\n"); +#endif + return FALSE; + } + if (xf86GetPciVideoInfo()) { + VmwareLog(("Some PCI Video Info Exists\n")); + numUsed = xf86MatchPciInstances(VMWARE_NAME, PCI_VENDOR_VMWARE, + VMWAREChipsets, VMWAREPciChipsets, devSections, + numDevSections, drv, &usedChips); + free(devSections); + if (numUsed <= 0) + return FALSE; + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else + for (i = 0; i < numUsed; i++) { + ScrnInfoPtr pScrn = NULL; + + VmwareLog(("Even some VMware SVGA PCI instances exists\n")); + pScrn = xf86ConfigPciEntity(pScrn, flags, usedChips[i], + VMWAREPciChipsets, NULL, NULL, NULL, + NULL, NULL); + if (pScrn) { + VmwareLog(("And even configuration suceeded\n")); + pScrn->driverVersion = VMWARE_DRIVER_VERSION; + pScrn->driverName = VMWARE_DRIVER_NAME; + pScrn->name = VMWARE_NAME; + pScrn->Probe = VMWAREProbe; + pScrn->PreInit = VMWAREPreInit; + +#ifdef BUILD_VMWGFX + vmwgfx_hookup(scrn); +#else + vmwlegacy_hookup(scrn); +#endif /* defined(BUILD_VMWGFX) */ + + scrn->driverPrivate = scrn->PreInit; + scrn->PreInit = VMwarePreinitStub; + foundScreen = TRUE; + } + } + free(usedChips); + } + return foundScreen; +} +#endif + +static void +VMWAREIdentify(int flags) +{ + xf86PrintChipsets(VMWARE_NAME, "driver for VMware SVGA", VMWAREChipsets); +} + +static const OptionInfoRec * +VMWAREAvailableOptions(int chipid, int busid) +{ + return VMWAREOptions; +} + +#if VMWARE_DRIVER_FUNC +static Bool +VMWareDriverFunc(ScrnInfoPtr pScrn, + xorgDriverFuncOp op, + pointer data) +{ + CARD32 *flag; + xorgRRModeMM *modemm; + + switch (op) { + case GET_REQUIRED_HW_INTERFACES: + flag = (CARD32 *)data; + + if (flag) { + *flag = HW_IO | HW_MMIO; + } + return TRUE; + case RR_GET_MODE_MM: + modemm = (xorgRRModeMM *)data; + + /* + * Because changing the resolution of the guest is usually changing the size + * of a window on the host desktop, the real physical DPI will not change. To + * keep the guest in sync, we scale the 'physical' screen dimensions to + * keep the DPI constant. + */ + if (modemm && modemm->mode) { + modemm->mmWidth = (modemm->mode->HDisplay * VMWARE_INCHTOMM + + pScrn->xDpi / 2) / pScrn->xDpi; + modemm->mmHeight = (modemm->mode->VDisplay * VMWARE_INCHTOMM + + pScrn->yDpi / 2) / pScrn->yDpi; + } + return TRUE; + default: + return FALSE; + } +} +#endif + + +_X_EXPORT DriverRec vmware = { + VMWARE_DRIVER_VERSION, + VMWARE_DRIVER_NAME, + VMWAREIdentify, +#if XSERVER_LIBPCIACCESS + NULL, +#else + VMWAREProbe, +#endif + VMWAREAvailableOptions, + NULL, + 0, +#if VMWARE_DRIVER_FUNC + VMWareDriverFunc, +#endif +#if XSERVER_LIBPCIACCESS + VMwareDeviceMatch, + VMwarePciProbe, +#endif +}; + +#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 5) + +#define xf86LoaderReqSymLists(...) do {} while (0) +#define LoaderRefSymLists(...) do {} while (0) + +#else + +const char *vgahwSymbols[] = { + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSaveScreen", + "vgaHWUnlock", + NULL +}; + +static const char *fbSymbols[] = { + "fbCreateDefColormap", + "fbPictureInit", + "fbScreenInit", + NULL +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86DestroyCursorInfoRec", + "xf86InitCursor", + NULL +}; + +static const char *shadowfbSymbols[] = { + "ShadowFBInit2", + NULL +}; +#endif + +#ifdef XFree86LOADER +static MODULESETUPPROTO(vmwareSetup); + +_X_EXPORT XF86ModuleData vmwareModuleData = { + &vmwareVersRec, + vmwareSetup, + NULL +}; + +static pointer +vmwareSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + if (!setupDone) { + setupDone = TRUE; + + xf86AddDriver(&vmware, module, VMWARE_DRIVER_FUNC); + + LoaderRefSymLists(vgahwSymbols, fbSymbols, ramdacSymbols, + shadowfbSymbols, NULL); + + return (pointer)1; + } + if (errmaj) { + *errmaj = LDR_ONCEONLY; + } + return NULL; +} +#endif /* XFree86LOADER */ diff --git a/src/vmware_bootstrap.h b/src/vmware_bootstrap.h new file mode 100644 index 0000000..172deb8 --- /dev/null +++ b/src/vmware_bootstrap.h @@ -0,0 +1,59 @@ +/* + * 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 _VMWARE_BOOTSTRAP_H_ +#define _VMWARE_BOOTSTRAP_H_ + +#include <xf86.h> + +#define VMWARE_INCHTOMM 25.4 + +typedef enum { + OPTION_HW_CURSOR, + OPTION_XINERAMA, + OPTION_STATIC_XINERAMA, + OPTION_GUI_LAYOUT, + OPTION_DEFAULT_MODE, + OPTION_RENDER_ACCEL, + OPTION_DRI, + OPTION_DIRECT_PRESENTS, + OPTION_HW_PRESENTS, + OPTION_RENDERCHECK +} VMWAREOpts; + +OptionInfoPtr VMWARECopyOptions(void); +const char **vgahwSymbols; + +void +vmwlegacy_hookup(ScrnInfoPtr pScrn); + +#ifdef BUILD_VMWGFX +void +vmwgfx_hookup(ScrnInfoPtr pScrn); +#endif /* defined(BUILD_VMWGFX) */ + + +#endif diff --git a/src/vmware_common.c b/src/vmware_common.c new file mode 100644 index 0000000..6ef7ca6 --- /dev/null +++ b/src/vmware_common.c @@ -0,0 +1,163 @@ +/* + * 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: Unknown at vmware + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <xf86.h> +#include "vmware_common.h" + +#ifndef HAVE_XORG_SERVER_1_5_0 +#include <xf86_ansic.h> +#include <xf86_libc.h> +#endif + +static int +VMWAREParseTopologyElement(ScrnInfoPtr pScrn, + unsigned int output, + const char *elementName, + const char *element, + const char *expectedTerminators, + Bool needTerminator, + unsigned int *outValue) +{ + char buf[10] = {0, }; + size_t i = 0; + int retVal = -1; + const char *str = element; + + for (i = 0; str[i] >= '0' && str[i] <= '9'; i++); + if (i == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: unable to parse %s.\n", + output, elementName); + goto exit; + } + + strncpy(buf, str, i); + *outValue = atoi(buf); + + if (*outValue > (unsigned short)-1) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: %s must be less than %hu.\n", + output, elementName, (unsigned short)-1); + goto exit; + } + + str += i; + + if (needTerminator || str[0] != '\0') { + Bool unexpected = TRUE; + + for (i = 0; i < strlen(expectedTerminators); i++) { + if (str[0] == expectedTerminators[i]) { + unexpected = FALSE; + } + } + + if (unexpected) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Output %u: unexpected character '%c' after %s.\n", + output, str[0], elementName); + goto exit; + } else { + str++; + } + } + + retVal = str - element; + + exit: + return retVal; +} + +xXineramaScreenInfo * +VMWAREParseTopologyString(ScrnInfoPtr pScrn, + const char *topology, + unsigned int *retNumOutputs, + const char info[]) +{ + xXineramaScreenInfo *extents = NULL; + unsigned int numOutputs = 0; + const char *str = topology; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing %s topology: Starting...\n", + info); + + do { + unsigned int x, y, width, height; + int i; + + i = VMWAREParseTopologyElement(pScrn, numOutputs, "width", str, "xX", TRUE, &width); + if (i == -1) { + goto error; + } + str += i; + + i = VMWAREParseTopologyElement(pScrn, numOutputs, "height", str, "+", TRUE, &height); + if (i == -1) { + goto error; + } + str += i; + + i= VMWAREParseTopologyElement(pScrn, numOutputs, "X offset", str, "+", TRUE, &x); + if (i == -1) { + goto error; + } + str += i; + + i = VMWAREParseTopologyElement(pScrn, numOutputs, "Y offset", str, ";", FALSE, &y); + if (i == -1) { + goto error; + } + str += i; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output %u: %ux%u+%u+%u\n", + numOutputs, width, height, x, y); + + numOutputs++; + extents = realloc(extents, numOutputs * sizeof (xXineramaScreenInfo)); + extents[numOutputs - 1].x_org = x; + extents[numOutputs - 1].y_org = y; + extents[numOutputs - 1].width = width; + extents[numOutputs - 1].height = height; + } while (*str != 0); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing %s topology: Succeeded.\n", + info); + goto exit; + + error: + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Parsing %s topology: Failed.\n", + info); + + free(extents); + extents = NULL; + numOutputs = 0; + + exit: + *retNumOutputs = numOutputs; + return extents; +} diff --git a/src/vmware_common.h b/src/vmware_common.h new file mode 100644 index 0000000..9cd7194 --- /dev/null +++ b/src/vmware_common.h @@ -0,0 +1,41 @@ +/* + * 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: Unknown at vmware + * Author: Thomas Hellstrom <thellstrom@vmware.com> + */ + +#ifndef _VMWARE_COMMON_H_ +#define _VMWARE_COMMON_H_ + +#include <X11/extensions/panoramiXproto.h> +#include <xf86.h> + +xXineramaScreenInfo * +VMWAREParseTopologyString(ScrnInfoPtr pScrn, + const char *topology, + unsigned int *retNumOutputs, + const char info[]); + +#endif diff --git a/src/vmwaremodule.c b/src/vmwaremodule.c deleted file mode 100644 index 0da2440..0000000 --- a/src/vmwaremodule.c +++ /dev/null @@ -1,256 +0,0 @@ -/********************************************************** - * Copyright 2010 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. - * - **********************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_LIBDRM -#include <xf86drm.h> -#endif - -#include <xorg-server.h> -#include <xf86.h> - -#ifndef HAVE_XORG_SERVER_1_5_0 -#include <xf86_ansic.h> -#include <xf86_libc.h> -#endif - -/* - * Defines and exported module info. - */ - -#define VMWARE_DRIVER_NAME "vmware" -#define VMWGFX_DRIVER_NAME "vmwgfx" -#define VMWGFX_MODULE_NAME "vmwgfx" -#define VMWGFX_COMPAT_MAJOR 11 -#define VMWGFX_REQUIRED_MAJOR 11 -#define VMWGFX_REQUIRED_MINOR 0 -#define VMWLEGACY_DRIVER_NAME "vmwlegacy" - -#define VMW_STRING_INNER(s) #s -#define VMW_STRING(str) VMW_STRING_INNER(str) - -#define VMWARE_DRIVER_VERSION \ - (PACKAGE_VERSION_MAJOR * 65536 + PACKAGE_VERSION_MINOR * 256 + PACKAGE_VERSION_PATCHLEVEL) -#define VMWARE_DRIVER_VERSION_STRING \ - VMW_STRING(PACKAGE_VERSION_MAJOR) "." VMW_STRING(PACKAGE_VERSION_MINOR) \ - "." VMW_STRING(PACKAGE_VERSION_PATCHLEVEL) - -/* - * Standard four digit version string expected by VMware Tools installer. - * As the driver's version is only {major, minor, patchlevel}, - * the fourth digit may describe the commit number relative to the - * last version tag as output from `git describe` - */ - -#ifdef __GNUC__ -#ifdef VMW_SUBPATCH -const char vmware_drv_modinfo[] __attribute__((section(".modinfo"),unused)) = - "version=" VMWARE_DRIVER_VERSION_STRING "." VMW_STRING(VMW_SUBPATCH); -#else -const char vmware_drv_modinfo[] __attribute__((section(".modinfo"),unused)) = - "version=" VMWARE_DRIVER_VERSION_STRING ".0"; -#endif /*VMW_SUBPATCH*/ -#endif - -static XF86ModuleVersionInfo vmware_version; -static MODULESETUPPROTO(vmware_setup); - -_X_EXPORT XF86ModuleData vmwareModuleData = { - &vmware_version, - vmware_setup, - NULL -}; - -extern XF86ModuleData *VMWGFX_MODULE_DATA; - -/* - * Chain loading functions - */ - -static Bool -vmware_check_kernel_module() -{ -#ifdef HAVE_LIBDRM - /* Super simple way of knowing if the kernel driver is loaded */ - int ret = drmOpen(VMWGFX_MODULE_NAME, NULL); - if (ret < 0) { - /* This shouldn't go in the log as the original message does not */ - fprintf(stderr, "%s: Please ignore above \"FATAL: Module %s not found." - "\"\n", VMWARE_DRIVER_NAME, VMWGFX_MODULE_NAME); - /* This is what goes into the log on the other hand */ - xf86DrvMsg(-1, X_PROBED, "%s: Please ignore above \"[drm] failed to " - "load kernel module \"%s\"\"\n", VMWARE_DRIVER_NAME, - VMWGFX_MODULE_NAME); - return FALSE; - } - - drmClose(ret); - - return TRUE; -#else - return FALSE; -#endif /* HAVE_LIBDRM */ -} - -static Bool -vmware_check_vmwgfx_driver(int matched, pointer opts) -{ -#ifdef HAVE_LIBDRM - int major; int minor; - pointer module; - CARD32 version; - - if (matched) { - xf86DrvMsg(-1, X_PROBED, "%s: X configured to use %s X driver assume " - "who ever did that knows what they are doing\n", - VMWARE_DRIVER_NAME, VMWGFX_DRIVER_NAME); - /* Also how did they end up here, if the configured X to use vmwgfx and - * X should load that driver for that hardware. And since there is only - * one SVGA device this driver shouldn't be loaded. Weird... - */ - return TRUE; - } - - module = xf86LoadOneModule(VMWGFX_DRIVER_NAME, opts); - if (!module) { - xf86DrvMsg(-1, X_ERROR, "%s: Please ignore the above warnings about " - "not being able to to load module/driver %s\n", - VMWARE_DRIVER_NAME, VMWGFX_DRIVER_NAME); - return FALSE; - } - - version = xf86GetModuleVersion(module); - major = GET_MODULE_MAJOR_VERSION(version); - minor = GET_MODULE_MINOR_VERSION(version); - - if (major > VMWGFX_COMPAT_MAJOR || - major < VMWGFX_REQUIRED_MAJOR || - (major == VMWGFX_REQUIRED_MAJOR && minor < VMWGFX_REQUIRED_MINOR)) { - xf86DrvMsg(-1, X_PROBED, "%s: The %s X driver failed version " - "checking.\n", VMWARE_DRIVER_NAME, VMWGFX_DRIVER_NAME); - goto err; - } - - return TRUE; - -err: - /* XXX We should drop the reference on the module here */ -#endif /* HAVE_LIBDRM */ - return FALSE; -} - -static Bool -vmware_chain_module(pointer opts) -{ - int vmwlegacy_devices; - int vmwgfx_devices; - int vmware_devices; - int matched; - char *driver_name; - GDevPtr *gdevs; - GDevPtr gdev; - int i; - - vmware_devices = xf86MatchDevice(VMWARE_DRIVER_NAME, &gdevs); - vmwgfx_devices = xf86MatchDevice(VMWGFX_DRIVER_NAME, NULL); - vmwlegacy_devices = xf86MatchDevice(VMWLEGACY_DRIVER_NAME, NULL); - - if (vmware_check_vmwgfx_driver(vmwgfx_devices, opts) && - vmware_check_kernel_module()) { - xf86DrvMsg(-1, X_INFO, "%s: Using %s X driver.\n", - VMWARE_DRIVER_NAME, VMWGFX_DRIVER_NAME); - driver_name = VMWGFX_DRIVER_NAME; - matched = 1; - } else { - xf86DrvMsg(-1, X_INFO, "%s: Using %s driver everything is fine.\n", - VMWARE_DRIVER_NAME, VMWLEGACY_DRIVER_NAME); - driver_name = VMWLEGACY_DRIVER_NAME; - matched = vmwlegacy_devices; - } - - /* Xorg -configure returns 1 from xf86MatchDevice with NULL gdevs */ - for (i = 0; gdevs && i < vmware_devices; i++) { - gdev = gdevs[i]; - gdev->driver = driver_name; - } - - free(gdevs); - - if (!matched) { - if (xf86LoadOneModule(driver_name, opts) == NULL) { - xf86DrvMsg(-1, X_ERROR, "%s: Unexpected failure while " - "loading the \"%s\" driver. Giving up.\n", - VMWARE_DRIVER_NAME, driver_name); - return FALSE; - } - } - - return TRUE; -} - - -/* - * Module info - */ - -static XF86ModuleVersionInfo vmware_version = { - VMWARE_DRIVER_NAME, - MODULEVENDORSTRING, - MODINFOSTRING1, - MODINFOSTRING2, - XORG_VERSION_CURRENT, - PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL, - ABI_CLASS_VIDEODRV, - ABI_VIDEODRV_VERSION, - MOD_CLASS_VIDEODRV, - {0, 0, 0, 0} -}; - -static pointer -vmware_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; - - /* Chain load the real driver */ - if (vmware_chain_module(opts)) - return (pointer) 1; - else { - if (errmaj) - *errmaj = LDR_NOSUBENT; - return NULL; - } - } else { - if (errmaj) - *errmaj = LDR_ONCEONLY; - return NULL; - } -} diff --git a/vmwgfx/Makefile.am b/vmwgfx/Makefile.am new file mode 100644 index 0000000..1ee6582 --- /dev/null +++ b/vmwgfx/Makefile.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES = libvmwgfx.la +libvmwgfx_la_CFLAGS = $(CWARNFLAGS) $(XORG_CFLAGS) @LIBDRM_CFLAGS@ @XATRACKER_CFLAGS@ -I$(top_srcdir)/src -I$(top_srcdir)/saa +libvmwgfx_la_LIBADD = @LIBDRM_LIBS@ $(top_srcdir)/saa/libsaa.la\ + @XATRACKER_LIBS@ +libvmwgfx_la_DEPENDENCIES = $(top_srcdir)/saa/libsaa.la + +libvmwgfx_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_overlay.c \ + vmwgfx_ctrl.c \ + vmwgfx_ctrl.h \ + vmwgfx_xa_composite.c \ + vmwgfx_xa_surface.c \ + wsbm_util.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_crtc.c b/vmwgfx/vmwgfx_crtc.c new file mode 100644 index 0000000..eaf87b2 --- /dev/null +++ b/vmwgfx/vmwgfx_crtc.c @@ -0,0 +1,455 @@ +/* + * 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; + uint32_t scanout_id; + unsigned cursor_handle; + + /* Scanout info for pixmaps */ + struct vmwgfx_screen_entry entry; +}; + +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->entry.pixmap) { + vmwgfx_scanout_unref(&crtcp->entry); + } + 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) { + x = 0; + y = 0; + pixmap = (PixmapPtr) crtc->rotatedData; + } else + pixmap = pScreen->GetScreenPixmap(pScreen); + + if (crtcp->entry.pixmap != pixmap) { + if (crtcp->entry.pixmap) + vmwgfx_scanout_unref(&crtcp->entry); + + crtcp->entry.pixmap = pixmap; + crtcp->scanout_id = vmwgfx_scanout_ref(&crtcp->entry); + if (crtcp->scanout_id == -1) { + 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; + + if (!WSBMLISTEMPTY(&crtcp->entry.scanout_head)) + vmwgfx_scanout_unref(&crtcp->entry); + + 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; + crtcp->entry.pixmap = NULL; + WSBMINITLISTHEAD(&crtcp->entry.scanout_head); + + crtc->driver_private = crtcp; + } + + out: + drmModeFreeResources(res); +} + +PixmapPtr +crtc_get_scanout(xf86CrtcPtr crtc) +{ + struct crtc_private *crtcp = crtc->driver_private; + return crtcp->entry.pixmap; +} + +/* 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..3185879 --- /dev/null +++ b/vmwgfx/vmwgfx_ctrl.c @@ -0,0 +1,523 @@ +/* + * 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 "vmwgfx_driver.h" +#include "vmwgfx_drmi.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) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct drm_vmw_rect rect; + int ret; + + rect.x = 0; + rect.y = 0; + rect.w = x; + rect.h = y; + + ret = vmwgfx_update_gui_layout(ms->fd, 1, &rect); + return (ret == 0); +} + + +/* + *---------------------------------------------------------------------------- + * + * 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) +{ + modesettingPtr ms = modesettingPTR(pScrn); + struct drm_vmw_rect *rects; + int i; + int ret; + + 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; + } + + ret = vmwgfx_update_gui_layout(ms->fd, number, rects); + + free(rects); + return (ret == 0); +} + + +/* + *---------------------------------------------------------------------------- + * + * 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..1b82ac4 --- /dev/null +++ b/vmwgfx/vmwgfx_dri2.c @@ -0,0 +1,426 @@ +/* + * 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" +#include "wsbm_util.h" +#include <unistd.h> + +#define VMWGFX_FD_PATH_LEN 80 + +typedef struct { + int refcount; + PixmapPtr pPixmap; + struct xa_surface *srf; + unsigned int dri2_depth; +} *BufferPrivatePtr; + + +/* + * Attempt to guess what the dri state tracker is up to. + * Currently it sends only bpp as format. + */ + +static unsigned int +vmwgfx_color_format_to_depth(unsigned int format) +{ + return format; +} + +static unsigned int +vmwgfx_zs_format_to_depth(unsigned int format) +{ + if (format == 24) + return 32; + return format; +} + +static unsigned int +vmwgfx_z_format_to_depth(unsigned int format) +{ + return format; +} + +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 depth; + + + 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: + depth = (format) ? vmwgfx_color_format_to_depth(format) : + pDraw->depth; + + if (buffer->attachment != DRI2BufferFakeFrontLeft || + &pPixmap->drawable != pDraw) { + + pPixmap = (*pScreen->CreatePixmap)(pScreen, + pDraw->width, + pDraw->height, + depth, + 0); + if (pPixmap == NullPixmap) + return FALSE; + + private->pPixmap = pPixmap; + private->dri2_depth = depth; + vpix = vmwgfx_saa_pixmap(pPixmap); + } + break; + case DRI2BufferFrontLeft: + if (&pPixmap->drawable == pDraw) + break; + buffer->name = 0; + buffer->pitch = 0; + buffer->cpp = pDraw->bitsPerPixel / 8; + buffer->driverPrivate = private; + buffer->flags = 0; /* not tiled */ + buffer->format = pDraw->bitsPerPixel; + if (!private->pPixmap) { + private->dri2_depth = 0; + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + return TRUE; + case DRI2BufferStencil: + case DRI2BufferDepthStencil: + + depth = (format) ? vmwgfx_zs_format_to_depth(format) : 32; + + /* + * The SVGA device uses the zs ordering. + */ + + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, xa_type_zs, xa_format_unknown, + XA_FLAG_SHARED ); + if (!srf) + return FALSE; + + private->dri2_depth = depth; + + break; + case DRI2BufferDepth: + depth = (format) ? vmwgfx_z_format_to_depth(format) : + pDraw->bitsPerPixel; + + if (depth == 24) + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, xa_type_zs, xa_format_unknown, + XA_FLAG_SHARED ); + else + srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, + depth, + xa_type_z, xa_format_unknown, + XA_FLAG_SHARED); + if (!srf) + return FALSE; + + private->dri2_depth = depth; + + break; + } + + if (!private->pPixmap) { + private->pPixmap = pPixmap; + pPixmap->refcnt++; + } + + if (!srf) { + depth = (format) ? vmwgfx_color_format_to_depth(format) : + pDraw->depth; + + if (!vmwgfx_hw_dri2_validate(pPixmap, depth)) + return FALSE; + + srf = vpix->hw; + private->refcount++; + private->dri2_depth = depth; + + /* + * Compiz workaround. See vmwgfx_dirty(); + */ + + if (buffer->attachment == DRI2BufferFrontLeft || + buffer->attachment == DRI2BufferFakeFrontLeft) + vpix->hw_is_dri2_fronts++; + } + + private->srf = srf; + if (xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0) + return FALSE; + + buffer->cpp = xa_format_depth(xa_surface_format(srf)) / 8; + 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; + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap); + + if (--private->refcount == 0 && srf) { + xa_surface_destroy(srf); + } + + /* + * Compiz workaround. See vmwgfx_dirty(); + */ + + if ((buffer->attachment == DRI2BufferFrontLeft || + buffer->attachment == DRI2BufferFakeFrontLeft) && + private->refcount == 1 && + --vpix->hw_is_dri2_fronts == 0) + WSBMLISTDELINIT(&vpix->sync_x_head); + + 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; + + /* + * 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) { + + if (!vmwgfx_hw_dri2_validate(dst_priv->pPixmap, + dst_priv->dri2_depth)) + 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); + if (pSrcBuffer->attachment != DRI2BufferFrontLeft) + 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; + char fdPath[VMWGFX_FD_PATH_LEN]; + ssize_t numChar; + + if (xf86LoaderCheckSymbol("DRI2Version")) { + DRI2Version(&major, &minor); + } else { + /* Assume version 1.0 */ + major = 1; + minor = 0; + } + + dri2info.version = min(DRI2INFOREC_VERSION, 3); + dri2info.fd = ms->fd; + dri2info.driverName = "vmwgfx"; + + /* + * This way of obtaining the DRM device name is a bit + * os-specific. It would be better to obtain it from + * drmOpen. Currently this works only for Linux. + */ + memset(fdPath, 0, VMWGFX_FD_PATH_LEN); + snprintf(fdPath, VMWGFX_FD_PATH_LEN - 1, "/proc/self/fd/%d", ms->fd); + numChar = readlink(fdPath, ms->dri2_device_name, VMWGFX_DRI_DEVICE_LEN); + if (numChar <= 0 || numChar >= VMWGFX_DRI_DEVICE_LEN) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not find the drm device name. Disabling dri2.\n"); + return FALSE; + } + ms->dri2_device_name[numChar] = 0; + dri2info.deviceName = ms->dri2_device_name; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Path of drm device is \"%s\".\n", ms->dri2_device_name); + + 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..dcb6c83 --- /dev/null +++ b/vmwgfx/vmwgfx_driver.c @@ -0,0 +1,1200 @@ +/* + * 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 "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" +#include "../src/vmware_bootstrap.h" +#include "../src/vmware_common.h" + +/* + * 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" + +#define XA_VERSION_MINOR_REQUIRED 6 +#define DRM_VERSION_MAJOR_REQUIRED 2 +#define DRM_VERSION_MINOR_REQUIRED 3 + +/* + * 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); + +void +vmwgfx_hookup(ScrnInfoPtr pScrn) +{ + pScrn->PreInit = drv_pre_init; + pScrn->ScreenInit = drv_screen_init; + pScrn->SwitchMode = drv_switch_mode; + pScrn->FreeScreen = drv_free_screen; + pScrn->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) { + drmVersionPtr ver = drmGetVersion(ms->fd); + + if (ver == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Could not determine DRM version.\n"); + return FALSE; + } + + ms->drm_major = ver->version_major; + ms->drm_minor = ver->version_minor; + ms->drm_patch = ver->version_patchlevel; + + drmFreeVersion(ver); + return TRUE; + } + + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to open drm.\n"); + + return FALSE; + } + + return TRUE; +} + +/** + * vmwgfx_set_topology - Set the GUI topology according to an option string + * + * @pScrn: Pointer to a ScrnInfo struct. + * @topology: String containing the topology description. + * @info: Info describing the option used to invoke this function. + * + * This function reads a GUI topology according from @topology, and + * calls into the kernel to set that topology. + */ +static Bool +vmwgfx_set_topology(ScrnInfoPtr pScrn, const char *topology, const char *info) +{ + modesettingPtr ms = modesettingPTR(pScrn); + unsigned int num_outputs; + xXineramaScreenInfo *screen_info; + struct drm_vmw_rect *rects; + int ret; + unsigned int i; + + screen_info = VMWAREParseTopologyString(pScrn, topology, &num_outputs, + info); + + if (screen_info == NULL) + return FALSE; + + rects = calloc(num_outputs, sizeof(*rects)); + if (rects == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate topology data.\n"); + goto out_no_rects; + } + + for(i = 0; i < num_outputs; ++i) { + rects[i].x = screen_info[i].x_org; + rects[i].y = screen_info[i].y_org; + rects[i].w = screen_info[i].width; + rects[i].h = screen_info[i].height; + } + + ret = vmwgfx_update_gui_layout(ms->fd, num_outputs, rects); + free(rects); + free(screen_info); + + return (ret == 0); + + out_no_rects: + free(screen_info); + return FALSE; +} + +static Bool +drv_pre_init(ScrnInfoPtr pScrn, int flags) +{ + xf86CrtcConfigPtr xf86_config; + modesettingPtr ms; + rgb defaultWeight = { 0, 0, 0 }; + EntityInfoPtr pEnt; + uint64_t cap; + Bool ret = TRUE; + + 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)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to allocate driver private.\n"); + } + + ms = modesettingPTR(pScrn); + ms->pEnt = pEnt; + + pScrn->displayWidth = 640; /* default it */ + + if (ms->pEnt->location.type != BUS_PCI) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Incorrect bus for device.\n"); + goto out_err_bus; + } + + ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index); + xf86SetPrimInitDone(pScrn->entityList[0]); + + ms->fd = -1; + if (!drv_init_drm(pScrn)) + goto out_err_bus; + + if (ms->drm_major != DRM_VERSION_MAJOR_REQUIRED || + ms->drm_minor < DRM_VERSION_MINOR_REQUIRED) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "DRM driver version is %d.%d.%d\n", + ms->drm_major, ms->drm_minor, ms->drm_patch); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "But KMS- and 3D functionality needs at least " + "%d.%d.0 to work.\n", + DRM_VERSION_MAJOR_REQUIRED, + DRM_VERSION_MINOR_REQUIRED); + goto out_drm_version; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, + "DRM driver version is %d.%d.%d\n", + ms->drm_major, ms->drm_minor, ms->drm_patch); + } + + 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)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set depth and bpp.\n"); + goto out_depth; + } + + if (vmwgfx_get_param(ms->fd, DRM_VMW_PARAM_HW_CAPS, &cap) != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to detect device " + "screen object capability.\n"); + goto out_depth; + } + + if ((cap & SVGA_CAP_SCREEN_OBJECT_2) == 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Device is not screen object " + "capable.\n"); + goto out_depth; + } + + switch (pScrn->depth) { + case 15: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported with KMS enabled.\n", + pScrn->depth); + goto out_depth; + } + xf86PrintDepthBpp(pScrn); + + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + goto out_depth; + if (!xf86SetDefaultVisual(pScrn, -1)) + goto out_depth; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(ms->Options = VMWARECopyOptions())) + goto out_depth; + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options); + + ms->accelerate_render = TRUE; + ms->from_render = xf86GetOptValBool(ms->Options, OPTION_RENDER_ACCEL, + &ms->accelerate_render) ? + X_CONFIG : X_PROBED; + + ms->rendercheck = FALSE; + ms->from_rendercheck = xf86GetOptValBool(ms->Options, OPTION_RENDERCHECK, + &ms->rendercheck) ? + X_CONFIG : X_DEFAULT; + + ms->enable_dri = ms->accelerate_render; + ms->from_dri = xf86GetOptValBool(ms->Options, OPTION_DRI, + &ms->enable_dri) ? + X_CONFIG : X_PROBED; + + ms->direct_presents = FALSE; + ms->from_dp = xf86GetOptValBool(ms->Options, OPTION_DIRECT_PRESENTS, + &ms->direct_presents) ? + X_CONFIG : X_DEFAULT; + + ms->only_hw_presents = FALSE; + ms->from_hwp = xf86GetOptValBool(ms->Options, OPTION_HW_PRESENTS, + &ms->only_hw_presents) ? + X_CONFIG : X_DEFAULT; + + /* 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; + + 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_HW_CURSOR, TRUE)) { + ms->SWCursor = TRUE; + } + + if (xf86IsOptionSet(ms->Options, OPTION_GUI_LAYOUT)) { + char *topology = + xf86GetOptValString(ms->Options, OPTION_GUI_LAYOUT); + + ret = FALSE; + if (topology) { + ret = vmwgfx_set_topology(pScrn, topology, "gui"); + free(topology); + } + + } else if (xf86IsOptionSet(ms->Options, OPTION_STATIC_XINERAMA)) { + char *topology = + xf86GetOptValString(ms->Options, OPTION_STATIC_XINERAMA); + + ret = FALSE; + if (topology) { + ret = vmwgfx_set_topology(pScrn, topology, "static Xinerama"); + free(topology); + } + } + + if (!ret) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Falied parsing or setting " + "gui topology from config file.\n"); + + xorg_crtc_init(pScrn); + xorg_output_init(pScrn); + + if (!xf86InitialConfiguration(pScrn, TRUE)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + goto out_modes; + } + + /* + * If the driver can do gamma correction, it should call xf86SetGamma() here. + */ + { + Gamma zeros = { 0.0, 0.0, 0.0 }; + + if (!xf86SetGamma(pScrn, zeros)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to set gamma.\n"); + goto out_modes; + } + } + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No available modes.\n"); + goto out_modes; + } + + pScrn->currentMode = pScrn->modes; + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); + + /* Load the required sub modules */ + if (!xf86LoadSubModule(pScrn, "fb")) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load fb module.\n"); + goto out_modes; + } + + if (!xf86LoadSubModule(pScrn, "dri2")) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load dri2 module.\n"); + goto out_modes; + } + + return TRUE; + + out_modes: + free(ms->Options); + out_depth: + out_drm_version: + close(ms->fd); + out_err_bus: + drv_free_rec(pScrn); + return FALSE; + +} + +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, vpix->fb_id, 0, 0, dirty, handle) != 0) { + LogMessage(X_ERROR, "Failed present kernel call.\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) { + if (ms->only_hw_presents && + REGION_NOTEMPTY(pscreen, vpix->pending_update)) { + (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, + 0, NULL); + REGION_UNION(pScreen, vpix->pending_present, + vpix->pending_present, vpix->pending_update); + } else + (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, + vpix->pending_update); + REGION_EMPTY(pScreen, vpix->pending_update); + } + if (vpix->pending_present) { + if (ms->only_hw_presents) + (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, + vpix->pending_present); + else + (void) vmwgfx_scanout_present(pScreen, ms->fd, vpix, + 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); + + vmwgfx_flush_dri2(pScreen); + 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; +} + +/** + * vmwgfx_use_hw_cursor_argb - wrapper around hw argb cursor check. + * + * screen: Pointer to the current screen metadata. + * cursor: Pointer to the current cursor metadata. + * + * In addition to the default test, also check whether we might be + * needing more than one hw cursor (which we don't support). + */ +static Bool +vmwgfx_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr pScrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + Bool ret; + + vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); + ret = cursor_info->UseHWCursorARGB(screen, cursor); + vmwgfx_swap(ms, cursor_info, UseHWCursorARGB); + if (!ret) + return FALSE; + + /* + * If there is a chance we might need two cursors, + * revert to sw cursor. + */ + return !vmwgfx_output_explicit_overlap(pScrn); +} + +/** + * vmwgfx_use_hw_cursor - wrapper around hw cursor check. + * + * screen: Pointer to the current screen metadata. + * cursor: Pointer to the current cursor metadata. + * + * In addition to the default test, also check whether we might be + * needing more than one hw cursor (which we don't support). + */ +static Bool +vmwgfx_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) +{ + ScrnInfoPtr pScrn = xf86Screens[screen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + Bool ret; + + vmwgfx_swap(ms, cursor_info, UseHWCursor); + ret = cursor_info->UseHWCursor(screen, cursor); + vmwgfx_swap(ms, cursor_info, UseHWCursor); + if (!ret) + return FALSE; + + /* + * If there is a chance we might need two simultaneous cursors, + * revert to sw cursor. + */ + return !vmwgfx_output_explicit_overlap(pScrn); +} + +/** + * vmwgfx_wrap_use_hw_cursor - Wrap functions that check for hw cursor + * support. + * + * pScrn: Pointer to current screen info. + * + * Enables the device-specific hw cursor support check functions. + */ +static void vmwgfx_wrap_use_hw_cursor(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; + modesettingPtr ms = modesettingPTR(pScrn); + + vmwgfx_wrap(ms, cursor_info, UseHWCursor, vmwgfx_use_hw_cursor); + vmwgfx_wrap(ms, cursor_info, UseHWCursorARGB, vmwgfx_use_hw_cursor_argb); +} + + +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); + + vmw_ctrl_ext_init(pScrn); + + if (ms->accelerate_render) { + ms->xat = xa_tracker_create(ms->fd); + if (!ms->xat) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to initialize Gallium3D Xa. " + "No render acceleration available.\n"); + ms->from_render = X_PROBED; + } else { + int major, minor, patch; + + xa_tracker_version(&major, &minor, &patch); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Gallium3D XA version: %d.%d.%d.\n", + major, minor, patch); + + if (XA_TRACKER_VERSION_MAJOR == 0) { + if (minor != XA_TRACKER_VERSION_MINOR) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Expecting XA version 0.%d.x.\n", + XA_TRACKER_VERSION_MINOR); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No render acceleration available.\n"); + xa_tracker_destroy(ms->xat); + ms->xat = NULL; + ms->from_render = X_PROBED; + } + } + if (major != XA_TRACKER_VERSION_MAJOR || + minor < XA_VERSION_MINOR_REQUIRED) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Expecting %d.%d.x >= XA version < %d.0.0.\n", + XA_TRACKER_VERSION_MAJOR, + XA_VERSION_MINOR_REQUIRED, + XA_TRACKER_VERSION_MAJOR + 1); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No render acceleration available.\n"); + xa_tracker_destroy(ms->xat); + ms->xat = NULL; + ms->from_render = X_PROBED; + } + } + if (ms->xat == NULL && ms->rendercheck) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Turning off renercheck mode.\n"); + ms->rendercheck = FALSE; + ms->from_rendercheck = X_PROBED; + } + } + + if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, + ms->direct_presents, + ms->only_hw_presents, + ms->rendercheck)) { + FatalError("Failed to initialize SAA.\n"); + } + + ms->dri2_available = FALSE; + if (ms->enable_dri) { + if (ms->xat) { + ms->dri2_available = xorg_dri2_init(pScreen); + if (!ms->dri2_available) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize direct rendering.\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Skipped initialization of direct rendering due " + "to lack of render acceleration.\n"); + ms->from_dri = X_PROBED; + } + } + + xf86DrvMsg(pScrn->scrnIndex, ms->from_render, "Render acceleration is %s.\n", + (ms->xat != NULL) ? "enabled" : "disabled"); + + xf86DrvMsg(pScrn->scrnIndex, ms->from_rendercheck, + "Rendercheck mode is %s.\n", + (ms->rendercheck) ? "enabled" : "disabled"); + + xf86DrvMsg(pScrn->scrnIndex, ms->from_dri, "Direct rendering (3D) is %s.\n", + (ms->dri2_available) ? "enabled" : "disabled"); + if (ms->xat != NULL) { + xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", + (ms->direct_presents) ? "enabled" : "disabled"); + xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " + "are %s.\n", + (ms->only_hw_presents) ? "enabled" : "disabled"); + } + + 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); + vmwgfx_wrap_use_hw_cursor(pScrn); + } + + /* 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; + } + + if (ms->dri2_available) + xorg_dri2_close(pScreen); + + 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..3290f0e --- /dev/null +++ b/vmwgfx/vmwgfx_driver.h @@ -0,0 +1,186 @@ +/* + * 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> + +#ifdef DRI2 +#include <dri2.h> +#if (!defined(DRI2INFOREC_VERSION) || (DRI2INFOREC_VERSION < 3)) +#undef DRI2 +#endif +#endif + +#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg); +#define debug_printf(...) + +#define VMWGFX_DRI_DEVICE_LEN 80 + +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; + int drm_major; + int drm_minor; + int drm_patch; + + /* X */ + EntPtr entityPrivate; + + int Chipset; + EntityInfoPtr pEnt; + struct pci_device *PciInfo; + + /* Accel */ + Bool accelerate_render; + MessageType from_render; + Bool rendercheck; + MessageType from_rendercheck; + Bool SWCursor; + CursorPtr cursor; + Bool enable_dri; + MessageType from_dri; + Bool direct_presents; + MessageType from_dp; + Bool only_hw_presents; + MessageType from_hwp; + 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); + Bool (*saved_UseHWCursor)(ScreenPtr, CursorPtr); + Bool (*saved_UseHWCursorARGB)(ScreenPtr, CursorPtr); + + 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; + char dri2_device_name[VMWGFX_DRI_DEVICE_LEN]; +#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); + +Bool +vmwgfx_output_explicit_overlap(ScrnInfoPtr pScrn); + + +/*********************************************************************** + * 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); + +void +vmw_ctrl_ext_init(ScrnInfoPtr pScrn); + +#endif /* _XORG_TRACKER_H_ */ diff --git a/vmwgfx/vmwgfx_drm.h b/vmwgfx/vmwgfx_drm.h new file mode 100644 index 0000000..906a41c --- /dev/null +++ b/vmwgfx/vmwgfx_drm.h @@ -0,0 +1,792 @@ +/************************************************************************** + * + * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + **************************************************************************/ + +#ifndef __VMWGFX_DRM_H__ +#define __VMWGFX_DRM_H__ +#include <drm.h> + +#define DRM_VMW_MAX_SURFACE_FACES 6 +#define DRM_VMW_MAX_MIP_LEVELS 24 + + +#define DRM_VMW_GET_PARAM 0 +#define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_UNREF_DMABUF 2 +#define DRM_VMW_CURSOR_BYPASS 3 +/* guarded by DRM_VMW_PARAM_NUM_STREAMS != 0*/ +#define DRM_VMW_CONTROL_STREAM 4 +#define DRM_VMW_CLAIM_STREAM 5 +#define DRM_VMW_UNREF_STREAM 6 +/* guarded by DRM_VMW_PARAM_3D == 1 */ +#define DRM_VMW_CREATE_CONTEXT 7 +#define DRM_VMW_UNREF_CONTEXT 8 +#define DRM_VMW_CREATE_SURFACE 9 +#define DRM_VMW_UNREF_SURFACE 10 +#define DRM_VMW_REF_SURFACE 11 +#define DRM_VMW_EXECBUF 12 +#define DRM_VMW_GET_3D_CAP 13 +#define DRM_VMW_FENCE_WAIT 14 +#define DRM_VMW_FENCE_SIGNALED 15 +#define DRM_VMW_FENCE_UNREF 16 +#define DRM_VMW_FENCE_EVENT 17 +#define DRM_VMW_PRESENT 18 +#define DRM_VMW_PRESENT_READBACK 19 +#define DRM_VMW_UPDATE_LAYOUT 20 + +/*************************************************************************/ +/** + * DRM_VMW_GET_PARAM - get device information. + * + * DRM_VMW_PARAM_FIFO_OFFSET: + * Offset to use to map the first page of the FIFO read-only. + * The fifo is mapped using the mmap() system call on the drm device. + * + * DRM_VMW_PARAM_OVERLAY_IOCTL: + * Does the driver support the overlay ioctl. + */ + +#define DRM_VMW_PARAM_NUM_STREAMS 0 +#define DRM_VMW_PARAM_NUM_FREE_STREAMS 1 +#define DRM_VMW_PARAM_3D 2 +#define DRM_VMW_PARAM_HW_CAPS 3 +#define DRM_VMW_PARAM_FIFO_CAPS 4 +#define DRM_VMW_PARAM_MAX_FB_SIZE 5 +#define DRM_VMW_PARAM_FIFO_HW_VERSION 6 + +/** + * struct drm_vmw_getparam_arg + * + * @value: Returned value. //Out + * @param: Parameter to query. //In. + * + * Argument to the DRM_VMW_GET_PARAM Ioctl. + */ + +struct drm_vmw_getparam_arg { + uint64_t value; + uint32_t param; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_CONTEXT - Create a host context. + * + * Allocates a device unique context id, and queues a create context command + * for the host. Does not wait for host completion. + */ + +/** + * struct drm_vmw_context_arg + * + * @cid: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_context_arg { + int32_t cid; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_CONTEXT - Create a host context. + * + * Frees a global context id, and queues a destroy host command for the host. + * Does not wait for host completion. The context ID can be used directly + * in the command stream and shows up as the same context ID on the host. + */ + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_SURFACE - Create a host suface. + * + * Allocates a device unique surface id, and queues a create surface command + * for the host. Does not wait for host completion. The surface ID can be + * used directly in the command stream and shows up as the same surface + * ID on the host. + */ + +/** + * struct drm_wmv_surface_create_req + * + * @flags: Surface flags as understood by the host. + * @format: Surface format as understood by the host. + * @mip_levels: Number of mip levels for each face. + * An unused face should have 0 encoded. + * @size_addr: Address of a user-space array of sruct drm_vmw_size + * cast to an uint64_t for 32-64 bit compatibility. + * The size of the array should equal the total number of mipmap levels. + * @shareable: Boolean whether other clients (as identified by file descriptors) + * may reference this surface. + * @scanout: Boolean whether the surface is intended to be used as a + * scanout. + * + * Input data to the DRM_VMW_CREATE_SURFACE Ioctl. + * Output data from the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_create_req { + uint32_t flags; + uint32_t format; + uint32_t mip_levels[DRM_VMW_MAX_SURFACE_FACES]; + uint64_t size_addr; + int32_t shareable; + int32_t scanout; +}; + +/** + * struct drm_wmv_surface_arg + * + * @sid: Surface id of created surface or surface to destroy or reference. + * + * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. + * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. + * Input argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_arg { + int32_t sid; + uint32_t pad64; +}; + +/** + * struct drm_vmw_size ioctl. + * + * @width - mip level width + * @height - mip level height + * @depth - mip level depth + * + * Description of a mip level. + * Input data to the DRM_WMW_CREATE_SURFACE Ioctl. + */ + +struct drm_vmw_size { + uint32_t width; + uint32_t height; + uint32_t depth; + uint32_t pad64; +}; + +/** + * union drm_vmw_surface_create_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_CREATE_SURFACE Ioctl. + */ + +union drm_vmw_surface_create_arg { + struct drm_vmw_surface_arg rep; + struct drm_vmw_surface_create_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_REF_SURFACE - Reference a host surface. + * + * Puts a reference on a host surface with a give sid, as previously + * returned by the DRM_VMW_CREATE_SURFACE ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface ID in the command + * stream. + * + * On successful return, the Ioctl returns the surface information given + * in the DRM_VMW_CREATE_SURFACE ioctl. + */ + +/** + * union drm_vmw_surface_reference_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +union drm_vmw_surface_reference_arg { + struct drm_vmw_surface_create_req rep; + struct drm_vmw_surface_arg req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_SURFACE - Unreference a host surface. + * + * Clear a reference previously put on a host surface. + * When all references are gone, including the one implicitly placed + * on creation, + * a destroy surface command will be queued for the host. + * Does not wait for completion. + */ + +/*************************************************************************/ +/** + * DRM_VMW_EXECBUF + * + * Submit a command buffer for execution on the host, and return a + * fence seqno that when signaled, indicates that the command buffer has + * executed. + */ + +/** + * struct drm_vmw_execbuf_arg + * + * @commands: User-space address of a command buffer cast to an uint64_t. + * @command-size: Size in bytes of the command buffer. + * @throttle-us: Sleep until software is less than @throttle_us + * microseconds ahead of hardware. The driver may round this value + * to the nearest kernel tick. + * @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an + * uint64_t. + * @version: Allows expanding the execbuf ioctl parameters without breaking + * backwards compatibility, since user-space will always tell the kernel + * which version it uses. + * @flags: Execbuf flags. None currently. + * + * Argument to the DRM_VMW_EXECBUF Ioctl. + */ + +#define DRM_VMW_EXECBUF_VERSION 1 + +struct drm_vmw_execbuf_arg { + uint64_t commands; + uint32_t command_size; + uint32_t throttle_us; + uint64_t fence_rep; + uint32_t version; + uint32_t flags; +}; + +/** + * struct drm_vmw_fence_rep + * + * @handle: Fence object handle for fence associated with a command submission. + * @mask: Fence flags relevant for this fence object. + * @seqno: Fence sequence number in fifo. A fence object with a lower + * seqno will signal the EXEC flag before a fence object with a higher + * seqno. This can be used by user-space to avoid kernel calls to determine + * whether a fence has signaled the EXEC flag. Note that @seqno will + * wrap at 32-bit. + * @passed_seqno: The highest seqno number processed by the hardware + * so far. This can be used to mark user-space fence objects as signaled, and + * to determine whether a fence seqno might be stale. + * @error: This member should've been set to -EFAULT on submission. + * The following actions should be take on completion: + * error == -EFAULT: Fence communication failed. The host is synchronized. + * Use the last fence id read from the FIFO fence register. + * error != 0 && error != -EFAULT: + * Fence submission failed. The host is synchronized. Use the fence_seq member. + * error == 0: All is OK, The host may not be synchronized. + * Use the fence_seq member. + * + * Input / Output data to the DRM_VMW_EXECBUF Ioctl. + */ + +struct drm_vmw_fence_rep { + uint32_t handle; + uint32_t mask; + uint32_t seqno; + uint32_t passed_seqno; + uint32_t pad64; + int32_t error; +}; + +/*************************************************************************/ +/** + * DRM_VMW_ALLOC_DMABUF + * + * Allocate a DMA buffer that is visible also to the host. + * NOTE: The buffer is + * identified by a handle and an offset, which are private to the guest, but + * useable in the command stream. The guest kernel may translate these + * and patch up the command stream accordingly. In the future, the offset may + * be zero at all times, or it may disappear from the interface before it is + * fixed. + * + * The DMA buffer may stay user-space mapped in the guest at all times, + * and is thus suitable for sub-allocation. + * + * DMA buffers are mapped using the mmap() syscall on the drm device. + */ + +/** + * struct drm_vmw_alloc_dmabuf_req + * + * @size: Required minimum size of the buffer. + * + * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_alloc_dmabuf_req { + uint32_t size; + uint32_t pad64; +}; + +/** + * struct drm_vmw_dmabuf_rep + * + * @map_handle: Offset to use in the mmap() call used to map the buffer. + * @handle: Handle unique to this buffer. Used for unreferencing. + * @cur_gmr_id: GMR id to use in the command stream when this buffer is + * referenced. See not above. + * @cur_gmr_offset: Offset to use in the command stream when this buffer is + * referenced. See note above. + * + * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_dmabuf_rep { + uint64_t map_handle; + uint32_t handle; + uint32_t cur_gmr_id; + uint32_t cur_gmr_offset; + uint32_t pad64; +}; + +/** + * union drm_vmw_dmabuf_arg + * + * @req: Input data as described above. + * @rep: Output data as described above. + * + * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +union drm_vmw_alloc_dmabuf_arg { + struct drm_vmw_alloc_dmabuf_req req; + struct drm_vmw_dmabuf_rep rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. + * + */ + +/** + * struct drm_vmw_unref_dmabuf_arg + * + * @handle: Handle indicating what buffer to free. Obtained from the + * DRM_VMW_ALLOC_DMABUF Ioctl. + * + * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. + */ + +struct drm_vmw_unref_dmabuf_arg { + uint32_t handle; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams. + * + * This IOCTL controls the overlay units of the svga device. + * The SVGA overlay units does not work like regular hardware units in + * that they do not automaticaly read back the contents of the given dma + * buffer. But instead only read back for each call to this ioctl, and + * at any point between this call being made and a following call that + * either changes the buffer or disables the stream. + */ + +/** + * struct drm_vmw_rect + * + * Defines a rectangle. Used in the overlay ioctl to define + * source and destination rectangle. + */ + +struct drm_vmw_rect { + int32_t x; + int32_t y; + uint32_t w; + uint32_t h; +}; + +/** + * struct drm_vmw_control_stream_arg + * + * @stream_id: Stearm to control + * @enabled: If false all following arguments are ignored. + * @handle: Handle to buffer for getting data from. + * @format: Format of the overlay as understood by the host. + * @width: Width of the overlay. + * @height: Height of the overlay. + * @size: Size of the overlay in bytes. + * @pitch: Array of pitches, the two last are only used for YUV12 formats. + * @offset: Offset from start of dma buffer to overlay. + * @src: Source rect, must be within the defined area above. + * @dst: Destination rect, x and y may be negative. + * + * Argument to the DRM_VMW_CONTROL_STREAM Ioctl. + */ + +struct drm_vmw_control_stream_arg { + uint32_t stream_id; + uint32_t enabled; + + uint32_t flags; + uint32_t color_key; + + uint32_t handle; + uint32_t offset; + int32_t format; + uint32_t size; + uint32_t width; + uint32_t height; + uint32_t pitch[3]; + + uint32_t pad64; + struct drm_vmw_rect src; + struct drm_vmw_rect dst; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CURSOR_BYPASS - Give extra information about cursor bypass. + * + */ + +#define DRM_VMW_CURSOR_BYPASS_ALL (1 << 0) +#define DRM_VMW_CURSOR_BYPASS_FLAGS (1) + +/** + * struct drm_vmw_cursor_bypass_arg + * + * @flags: Flags. + * @crtc_id: Crtc id, only used if DMR_CURSOR_BYPASS_ALL isn't passed. + * @xpos: X position of cursor. + * @ypos: Y position of cursor. + * @xhot: X hotspot. + * @yhot: Y hotspot. + * + * Argument to the DRM_VMW_CURSOR_BYPASS Ioctl. + */ + +struct drm_vmw_cursor_bypass_arg { + uint32_t flags; + uint32_t crtc_id; + int32_t xpos; + int32_t ypos; + int32_t xhot; + int32_t yhot; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CLAIM_STREAM - Claim a single stream. + */ + +/** + * struct drm_vmw_context_arg + * + * @stream_id: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_stream_arg { + uint32_t stream_id; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_STREAM - Unclaim a stream. + * + * Return a single stream that was claimed by this process. Also makes + * sure that the stream has been stopped. + */ + +/*************************************************************************/ +/** + * DRM_VMW_GET_3D_CAP + * + * Read 3D capabilities from the FIFO + * + */ + +/** + * struct drm_vmw_get_3d_cap_arg + * + * @buffer: Pointer to a buffer for capability data, cast to an uint64_t + * @size: Max size to copy + * + * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL + * ioctls. + */ + +struct drm_vmw_get_3d_cap_arg { + uint64_t buffer; + uint32_t max_size; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_WAIT + * + * Waits for a fence object to signal. The wait is interruptible, so that + * signals may be delivered during the interrupt. The wait may timeout, + * in which case the calls returns -EBUSY. If the wait is restarted, + * that is restarting without resetting @cookie_valid to zero, + * the timeout is computed from the first call. + * + * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait + * on: + * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command + * stream + * have executed. + * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish + * commands + * in the buffer given to the EXECBUF ioctl returning the fence object handle + * are available to user-space. + * + * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the + * fenc wait ioctl returns 0, the fence object has been unreferenced after + * the wait. + */ + +#define DRM_VMW_FENCE_FLAG_EXEC (1 << 0) +#define DRM_VMW_FENCE_FLAG_QUERY (1 << 1) + +#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0) + +/** + * struct drm_vmw_fence_wait_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @cookie_valid: Must be reset to 0 on first call. Left alone on restart. + * @kernel_cookie: Set to 0 on first call. Left alone on restart. + * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout. + * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick + * before returning. + * @flags: Fence flags to wait on. + * @wait_options: Options that control the behaviour of the wait ioctl. + * + * Input argument to the DRM_VMW_FENCE_WAIT ioctl. + */ + +struct drm_vmw_fence_wait_arg { + uint32_t handle; + int32_t cookie_valid; + uint64_t kernel_cookie; + uint64_t timeout_us; + int32_t lazy; + int32_t flags; + int32_t wait_options; + int32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_SIGNALED + * + * Checks if a fence object is signaled.. + */ + +/** + * struct drm_vmw_fence_signaled_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl + * @signaled: Out: Flags signaled. + * @sequence: Out: Highest sequence passed so far. Can be used to signal the + * EXEC flag of user-space fence objects. + * + * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF + * ioctls. + */ + +struct drm_vmw_fence_signaled_arg { + uint32_t handle; + uint32_t flags; + int32_t signaled; + uint32_t passed_seqno; + uint32_t signaled_flags; + uint32_t pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_UNREF + * + * Unreferences a fence object, and causes it to be destroyed if there are no + * other references to it. + * + */ + +/** + * struct drm_vmw_fence_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * + * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl.. + */ + +struct drm_vmw_fence_arg { + uint32_t handle; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_EVENT + * + * Queues an event on a fence to be delivered on the drm character device + * when the fence has signaled the DRM_VMW_FENCE_FLAG_EXEC flag. + * Optionally the approximate time when the fence signaled is + * given by the event. + */ + +/* + * The event type + */ +#define DRM_VMW_EVENT_FENCE_SIGNALED 0x80000000 + +struct drm_vmw_event_fence { + struct drm_event base; + uint64_t user_data; + uint32_t tv_sec; + uint32_t tv_usec; +}; + +/* + * Flags that may be given to the command. + */ +/* Request fence signaled time on the event. */ +#define DRM_VMW_FE_FLAG_REQ_TIME (1 << 0) + +/** + * struct drm_vmw_fence_event_arg + * + * @fence_rep: Pointer to fence_rep structure cast to uint64_t or 0 if + * the fence is not supposed to be referenced by user-space. + * @user_info: Info to be delivered with the event. + * @handle: Attach the event to this fence only. + * @flags: A set of flags as defined above. + */ +struct drm_vmw_fence_event_arg { + uint64_t fence_rep; + uint64_t user_data; + uint32_t handle; + uint32_t flags; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT + * + * Executes an SVGA present on a given fb for a given surface. The surface + * is placed on the framebuffer. Cliprects are given relative to the given + * point (the point disignated by dest_{x|y}). + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: framebuffer id to present / read back from. + * @sid: Surface id to present from. + * @dest_x: X placement coordinate for surface. + * @dest_y: Y placement coordinate for surface. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @num_clips: Number of cliprects given relative to the framebuffer origin, + * in the same coordinate space as the frame buffer. + * @pad64: Unused 64-bit padding. + * + * Input argument to the DRM_VMW_PRESENT ioctl. + */ + +struct drm_vmw_present_arg { + uint32_t fb_id; + uint32_t sid; + int32_t dest_x; + int32_t dest_y; + uint64_t clips_ptr; + uint32_t num_clips; + uint32_t pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT_READBACK + * + * Executes an SVGA present readback from a given fb to the dma buffer + * currently bound as the fb. If there is no dma buffer bound to the fb, + * an error will be returned. + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: fb_id to present / read back from. + * @num_clips: Number of cliprects. + * @clips_ptr: Pointer to an array of clip rects cast to an uint64_t. + * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an uint64_t. + * If this member is NULL, then the ioctl should not return a fence. + */ + +struct drm_vmw_present_readback_arg { + uint32_t fb_id; + uint32_t num_clips; + uint64_t clips_ptr; + uint64_t fence_rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UPDATE_LAYOUT - Update layout + * + * Updates the preferred modes and connection status for connectors. The + * command consists of one drm_vmw_update_layout_arg pointing to an array + * of num_outputs drm_vmw_rect's. + */ + +/** + * struct drm_vmw_update_layout_arg + * + * @num_outputs: number of active connectors + * @rects: pointer to array of drm_vmw_rect cast to an uint64_t + * + * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl. + */ +struct drm_vmw_update_layout_arg { + uint32_t num_outputs; + uint32_t pad64; + uint64_t rects; +}; + +#endif diff --git a/vmwgfx/vmwgfx_drmi.c b/vmwgfx/vmwgfx_drmi.c new file mode 100644 index 0000000..e326d31 --- /dev/null +++ b/vmwgfx/vmwgfx_drmi.c @@ -0,0 +1,502 @@ +/* + * 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 "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, uint32_t handle, Bool unref) +{ + struct drm_vmw_fence_wait_arg farg; + memset(&farg, 0, sizeof(farg)); + + farg.handle = handle; + farg.flags = DRM_VMW_FENCE_FLAG_EXEC; + farg.timeout_us = 10*1000000; + farg.cookie_valid = 0; + + if (unref) + farg.wait_options |= DRM_VMW_WAIT_OPTION_UNREF; + + return drmCommandWriteRead(drm_fd, DRM_VMW_FENCE_WAIT, &farg, + sizeof(farg)); +} + +static void +vmwgfx_fence_unref(int drm_fd, uint32_t handle) +{ + struct drm_vmw_fence_arg farg; + memset(&farg, 0, sizeof(farg)); + + farg.handle = handle; + + (void) drmCommandWrite(drm_fd, DRM_VMW_FENCE_UNREF, &farg, + sizeof(farg)); +} + + +int +vmwgfx_present_readback(int drm_fd, uint32_t fb_id, RegionPtr region) +{ + BoxPtr clips = REGION_RECTS(region); + unsigned int num_clips = REGION_NUM_RECTS(region); + struct drm_vmw_fence_rep rep; + struct drm_vmw_present_readback_arg arg; + int ret; + unsigned i; + struct drm_vmw_rect *rects, *r; + + rects = calloc(num_clips, sizeof(*rects)); + if (!rects) { + LogMessage(X_ERROR, "Failed to alloc cliprects for " + "present readback.\n"); + return -1; + } + + memset(&arg, 0, sizeof(arg)); + memset(&rep, 0, sizeof(rep)); + + arg.fb_id = fb_id; + arg.num_clips = num_clips; + arg.clips_ptr = (unsigned long) rects; + arg.fence_rep = (unsigned long) &rep; + rep.error = -EFAULT; + + for (i = 0, r = rects; i < num_clips; ++i, ++r, ++clips) { + r->x = clips->x1; + r->y = clips->y1; + r->w = clips->x2 - clips->x1; + r->h = clips->y2 - clips->y1; + } + + ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT_READBACK, &arg, sizeof(arg)); + if (ret) + LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret)); + free(rects); + + /* + * Sync to avoid racing with Xorg SW rendering. + */ + + if (rep.error == 0) { + ret = vmwgfx_fence_wait(drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "Present readback fence wait error %s.\n", + strerror(-ret)); + vmwgfx_fence_unref(drm_fd, rep.handle); + } + } + + return 0; +} + + +int +vmwgfx_present(int drm_fd, uint32_t fb_id, 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_present_arg arg; + unsigned int i; + struct drm_vmw_rect *rects, *r; + int ret; + + if (num_clips == 0) + return 0; + + rects = calloc(num_clips, sizeof(*rects)); + if (!rects) { + LogMessage(X_ERROR, "Failed to alloc cliprects for " + "present.\n"); + return -1; + } + + memset(&arg, 0, sizeof(arg)); + arg.fb_id = fb_id; + arg.sid = handle; + arg.dest_x = dst_x; + arg.dest_y = dst_y; + arg.num_clips = num_clips; + arg.clips_ptr = (unsigned long) rects; + + for (i = 0, r = rects; i < num_clips; ++i, ++r, ++clips) { + r->x = clips->x1; + r->y = clips->y1; + r->w = clips->x2 - clips->x1; + r->h = clips->y2 - clips->y1; + } + + ret = drmCommandWrite(drm_fd, DRM_VMW_PRESENT, &arg, sizeof(arg)); + if (ret) { + LogMessage(X_ERROR, "Present error %s.\n", strerror(-ret)); + } + + free(rects); + return ((ret != 0) ? -1 : 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 = ((to_surface) ? 0UL : (unsigned long)&rep); + arg.commands = (unsigned long)cmd; + arg.command_size = size; + arg.throttle_us = 0; + arg.version = DRM_VMW_EXECBUF_VERSION; + + 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 (rep.error == 0) { + ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.handle, TRUE); + if (ret) { + LogMessage(X_ERROR, "DMA from host fence wait error %s.\n", + strerror(-ret)); + vmwgfx_fence_unref(ibuf->drm_fd, rep.handle); + } + } + + return 0; +} + +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_update_gui_layout(int drm_fd, unsigned int num_rects, + struct drm_vmw_rect *rects) +{ + struct drm_vmw_update_layout_arg arg; + + memset(&arg, 0, sizeof(arg)); + + arg.num_outputs = num_rects; + arg.rects = (unsigned long) rects; + + return drmCommandWrite(drm_fd, DRM_VMW_UPDATE_LAYOUT, &arg, + sizeof(arg)); +} + + +int +vmwgfx_max_fb_size(int drm_fd, size_t *size) +{ + uint64_t tmp_size; + + if (vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_MAX_FB_SIZE, &tmp_size) != 0) + return -1; + + *size = tmp_size; + + return 0; +} diff --git a/vmwgfx/vmwgfx_drmi.h b/vmwgfx/vmwgfx_drmi.h new file mode 100644 index 0000000..2435009 --- /dev/null +++ b/vmwgfx/vmwgfx_drmi.h @@ -0,0 +1,87 @@ +/* + * 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> +#include "vmwgfx_drm.h" + +struct vmwgfx_dma_ctx; + +extern int +vmwgfx_present_readback(int drm_fd, uint32_t fb_id, RegionPtr region); + +extern int +vmwgfx_present(int drm_fd, uint32_t fb_id, 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); + +int +vmwgfx_update_gui_layout(int drm_fd, unsigned int num_rects, + struct drm_vmw_rect *rects); +int +vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out); +#endif diff --git a/vmwgfx/vmwgfx_output.c b/vmwgfx/vmwgfx_output.c new file mode 100644 index 0000000..4f52f1d --- /dev/null +++ b/vmwgfx/vmwgfx_output.c @@ -0,0 +1,393 @@ +/* + * 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; + + Bool is_implicit; +}; + +static char *output_enum_list[] = { + "Unknown", + "VGA", + "DVI", + "DVI", + "DVI", + "Composite", + "SVIDEO", + "LVDS", + "CTV", + "DIN", + "DP", + "HDMI", + "HDMI", + "TV", + "EDP", + "Virtual", +}; + +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, +}; + +/** + * vmwgfx_output_explicit_overlap -- Check for explicit output overlaps + * + * This function returns TRUE iff the bounding box in screen space of an + * exlplicit output overlaps the bounding box in screen space of any other + * output. + */ +Bool +vmwgfx_output_explicit_overlap(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + ScreenPtr pScreen = pScrn->pScreen; + RegionRec output_union; + RegionRec cur_output; + RegionRec result; + struct output_private *priv; + xf86CrtcPtr crtc; + Bool overlap = FALSE; + int i; + + (void) pScreen; + REGION_NULL(pScreen, &output_union); + REGION_NULL(pScreen, &cur_output); + REGION_NULL(pScreen, &result); + + /* + * Collect a region of implicit outputs. These may overlap. + */ + for (i = 0; i < config->num_output; i++) { + output = config->output[i]; + priv = output->driver_private; + crtc = output->crtc; + + if (!crtc || !crtc->enabled || !priv->is_implicit) + continue; + + REGION_RESET(pScreen, &cur_output, &crtc->bounds); + REGION_UNION(pScreen, &output_union, &output_union, &cur_output); + } + + /* + * Explicit outputs may not overlap any other output. + */ + for (i = 0; i < config->num_output; i++) { + output = config->output[i]; + priv = output->driver_private; + crtc = output->crtc; + + if (!crtc || !crtc->enabled || priv->is_implicit) + continue; + + REGION_RESET(pScreen, &cur_output, &crtc->bounds); + REGION_NULL(pScreen, &result); + REGION_INTERSECT(pScreen, &result, &output_union, &cur_output); + overlap = REGION_NOTEMPTY(vsaa->pScreen, &result); + if (overlap) + break; + + REGION_UNION(pScreen, &output_union, &output_union, &cur_output); + } + + REGION_UNINIT(pScreen, &output_union); + REGION_UNINIT(pScreen, &cur_output); + REGION_UNINIT(pScreen, &result); + + return overlap; +} + +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, p; + + res = drmModeGetResources(ms->fd); + if (res == 0) { + DRV_ERROR("Failed drmModeGetResources\n"); + return; + } + + for (c = 0; c < res->count_connectors; c++) { + Bool is_implicit = TRUE; + + drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]); + if (!drm_connector) + goto out; + + + for (p = 0; p < drm_connector->count_props; p++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(ms->fd, drm_connector->props[p]); + + if (prop) { + +#if 0 + /* + * Disabled until we sort out what the interface should + * look like. + */ + + if (strcmp(prop->name, "implicit placement") == 0) { + drmModeConnectorSetProperty(ms->fd, + drm_connector->connector_id, + prop->prop_id, + 0); + is_implicit = FALSE; + } +#endif + drmModeFreeProperty(prop); + } + } + + if (drm_connector->connector_type >= + sizeof(output_enum_list) / sizeof(output_enum_list[0])) + drm_connector->connector_type = 0; + + 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; + } + + priv->is_implicit = is_implicit; + + 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..6624a10 --- /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 "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_no_buffer: + while(i-- != 0) { + vmw_video_buffer_free(&port->bufs[i]); + } + out_bad_size: + (void) vmwgfx_unref_stream(port->drm_fd, port->streamId); + + 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..0a6b98f --- /dev/null +++ b/vmwgfx/vmwgfx_saa.c @@ -0,0 +1,1514 @@ +/* + * 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" +#include "vmwgfx_saa_priv.h" + +/* + * Damage to be added as soon as we attach storage to the pixmap. + */ +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_RESET(draw->pScreen, &spix->dirty_hw, &box); + REGION_EMPTY(draw->pScreen, &spix->dirty_shadow); + } else { + REGION_RESET(draw->pScreen, &spix->dirty_shadow, &box); + REGION_EMPTY(draw->pScreen, &spix->dirty_hw); + } + + 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 || vpix->malloc) + 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, Bool present_opt) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + ScreenPtr pScreen = pixmap->drawable.pScreen; + (void) pScreen; + + if (present_opt) { + 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; + + return TRUE; + out_no_pending_present: + REGION_DESTROY(pScreen, vpix->pending_update); + out_no_pending_update: + if (vpix->present_damage) + REGION_DESTROY(pScreen, vpix->present_damage); + out_no_present_damage: + if (vpix->dirty_present) + 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 (!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); + if (!vpix->malloc) + goto out_no_malloc; + if (!vmwgfx_pixmap_add_damage(pixmap)) + goto out_no_damage; + } else if (vpix->backing & VMWGFX_PIX_GMR) + return vmwgfx_pixmap_create_gmr(vsaa, pixmap); + + return TRUE; + + out_no_damage: + free(vpix->malloc); + vpix->malloc = NULL; + out_no_malloc: + return FALSE; +} + + +/** + * + * 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; + + /* + * Intersect dirty region with region to be read back, if any. + */ + + 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; + + /* + * Make really sure there is a GMR to read back to. + */ + + if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) + goto out_err; + + if (vmwgfx_present_readback(vsaa->drm_fd, vpix->fb_id, + &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) +{ + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + *new_pitch = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits); + + WSBMINITLISTHEAD(&vpix->sync_x_head); + WSBMINITLISTHEAD(&vpix->scanout_list); + + return TRUE; +} + +Bool +vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, + struct saa_pixmap *spix) +{ + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + + if (!vpix->hw) + return TRUE; + + /* + * Read back any dirty regions from hardware. + */ + + if (!vmwgfx_download_from_hw(&vsaa->driver, spix->pixmap, + &spix->dirty_hw)) + return FALSE; + + xa_surface_destroy(vpix->hw); + vpix->hw = NULL; + + /* + * Remove damage tracking if this is not a scanout pixmap. + */ + + if (WSBMLISTEMPTY(&vpix->scanout_list)) + vmwgfx_pixmap_remove_damage(spix->pixmap); + + return TRUE; +} + +void +vmwgfx_flush_dri2(ScreenPtr pScreen) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pScreen)); + struct _WsbmListHead *list, *next; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + + if (!pScrn->vtSema) + return; + + WSBMLISTFOREACHSAFE(list, next, &vsaa->sync_x_list) { + struct vmwgfx_saa_pixmap *vpix = + WSBMLISTENTRY(list, struct vmwgfx_saa_pixmap, sync_x_head); + struct saa_pixmap *spix = &vpix->base; + PixmapPtr pixmap = spix->pixmap; + + if (vmwgfx_upload_to_hw(&vsaa->driver, pixmap, &spix->dirty_shadow)) { + REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); + WSBMLISTDELINIT(list); + } + } +} + + +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); + WSBMLISTDELINIT(&vpix->sync_x_head); + + if (vpix->hw_is_dri2_fronts) + LogMessage(X_ERROR, "Incorrect dri2 front count.\n"); +} + + + +/** + * + * Makes sure we have a surface with valid contents. + */ + +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 saa_pixmap *spix = saa_get_saa_pixmap(pixmap); + struct vmwgfx_saa_pixmap *vpix = to_vmwgfx_saa_pixmap(spix); + DrawablePtr draw = &pixmap->drawable; + unsigned int size = pixmap->devKind * draw->height; + BoxRec b_box; + RegionRec b_reg; + + /* + * 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, vpix->xa_flags, 1) != 0) + return FALSE; + } + + b_box.x1 = 0; + b_box.x2 = draw->width; + b_box.y1 = 0; + b_box.y2 = draw->height; + + REGION_INIT(pScreen, &b_reg, &b_box, 1); + REGION_INTERSECT(pScreen, &spix->dirty_shadow, &spix->dirty_shadow, + &b_reg); + REGION_INTERSECT(pScreen, &spix->dirty_hw, &spix->dirty_hw, &b_reg); + if (vpix->dirty_present) + REGION_INTERSECT(pScreen, vpix->dirty_present, vpix->dirty_present, + &b_reg); + if (vpix->pending_update) + REGION_INTERSECT(pScreen, vpix->pending_update, vpix->pending_update, + &b_reg); + if (vpix->pending_present) + REGION_INTERSECT(pScreen, vpix->pending_present, + vpix->pending_present, &b_reg); + if (vpix->present_damage) + REGION_INTERSECT(pScreen, vpix->present_damage, vpix->present_damage, + &b_reg); + + REGION_UNINIT(pScreen, &b_reg); + + 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_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); +} + + +Bool +vmwgfx_create_hw(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + struct xa_surface *hw; + uint32_t new_flags; + + if (!vsaa->xat) + return FALSE; + + if (vpix->hw) + return TRUE; + + new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | + vpix->staging_add_flags; + + hw = xa_surface_create(vsaa->xat, + pixmap->drawable.width, + pixmap->drawable.height, + 0, + xa_type_other, + vpix->staging_format, + new_flags); + if (hw == NULL) + return FALSE; + + vpix->xa_flags = new_flags; + + if (!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; +} + + +Bool +vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region) +{ + 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 (!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 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_hw_accel_validate(src_pixmap, 0, 0, 0, src_reg)) + return FALSE; + if (vmwgfx_present_prepare(vsaa, src_vpix, dst_vpix)) { + vsaa->present_copy = TRUE; + return TRUE; + } + return FALSE; + } + + vsaa->present_copy = FALSE; + if (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; + + /* + * Determine surface formats. + */ + + if (src_vpix->base.src_format == 0) { + if (!vmwgfx_hw_accel_stage(src_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) + return FALSE; + } else { + if (PICT_FORMAT_TYPE(src_vpix->base.src_format) != PICT_TYPE_ARGB || + !vmwgfx_hw_composite_src_stage(src_pixmap, src_vpix->base.src_format)) + return FALSE; + } + + if (dst_vpix->base.dst_format == 0) { + if (!vmwgfx_hw_accel_stage(dst_pixmap, 0, XA_FLAG_RENDER_TARGET, 0)) + return FALSE; + } else { + if (PICT_FORMAT_TYPE(dst_vpix->base.dst_format) != PICT_TYPE_ARGB || + !vmwgfx_hw_composite_dst_stage(dst_pixmap, dst_vpix->base.dst_format)) + return FALSE; + } + + /* + * Create hardware surfaces. + */ + + if (!vmwgfx_hw_commit(src_pixmap)) + return FALSE; + if (!vmwgfx_hw_commit(dst_pixmap)) + return FALSE; + + /* + * Migrate data. + */ + + if (!vmwgfx_hw_validate(src_pixmap, src_reg)) { + xa_copy_done(vsaa->xa_ctx); + return FALSE; + } + + /* + * Setup copy state. + */ + + if (xa_copy_prepare(vsaa->xa_ctx, dst_vpix->hw, src_vpix->hw) != + XA_ERR_NONE) + return FALSE; + + 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, dst_vpix->fb_id, + 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, ®, &box, 1); + REGION_UNION(pScreen, &vsaa->present_region, &vsaa->present_region, ®); + REGION_UNINIT(pScreen, ®); +} + +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); + return; + } + xa_copy_done(vsaa->xa_ctx); +} + +static Bool +vmwgfx_composite_prepare(struct saa_driver *driver, CARD8 op, + PicturePtr src_pict, PicturePtr mask_pict, + PicturePtr dst_pict, + PixmapPtr src_pix, PixmapPtr mask_pix, + PixmapPtr dst_pix, + RegionPtr src_region, + RegionPtr mask_region, + RegionPtr dst_region) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + struct vmwgfx_saa_pixmap *src_vpix; + struct vmwgfx_saa_pixmap *dst_vpix; + struct vmwgfx_saa_pixmap *mask_vpix; + Bool tmp_valid_hw; + Bool dirty_hw; + Bool valid_hw; + RegionRec empty; + struct xa_composite *xa_comp; + + REGION_NULL(pScreen, &empty); + + /* + * First we define our migration policy. We accelerate only if there + * are dirty hw regions to be read or if all source data is + * available in hw, and the destination has a hardware surface. + */ + dst_vpix = vmwgfx_saa_pixmap(dst_pix); + valid_hw = (dst_vpix->hw != NULL); + if (saa_op_reads_destination(op)) { + vmwgfx_check_hw_contents(vsaa, dst_vpix, dst_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } else { + dirty_hw = FALSE; + dst_region = ∅ + } + + if (src_pix && !dirty_hw) { + src_vpix = vmwgfx_saa_pixmap(src_pix); + vmwgfx_check_hw_contents(vsaa, src_vpix, src_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } + + if (mask_pict && mask_pix && !dirty_hw) { + mask_vpix = vmwgfx_saa_pixmap(mask_pix); + vmwgfx_check_hw_contents(vsaa, mask_vpix, mask_region, + &dirty_hw, &tmp_valid_hw); + valid_hw = (valid_hw && tmp_valid_hw); + } + + /* + * In rendercheck mode we try to accelerate all supported + * composite operations. + */ + + if (!valid_hw && !dirty_hw && !vsaa->rendercheck) + goto out_err; + + /* + * Then, setup most of the XA composite state (except hardware surfaces) + * and check whether XA can accelerate. + */ + + xa_comp = vmwgfx_xa_setup_comp(vsaa->vcomp, op, + src_pict, mask_pict, dst_pict); + if (!xa_comp) + goto out_err; + + if (xa_composite_check_accelerated(xa_comp) != XA_ERR_NONE) + goto out_err; + + /* + * Check that we can create the needed hardware surfaces. + */ + if (src_pix && !vmwgfx_hw_composite_src_stage(src_pix, src_pict->format)) + goto out_err; + if (mask_pict && mask_pix && + !vmwgfx_hw_composite_src_stage(mask_pix, mask_pict->format)) + goto out_err; + if (!vmwgfx_hw_composite_dst_stage(dst_pix, dst_pict->format)) + goto out_err; + + /* + * Seems OK. Commit the changes, creating hardware surfaces. + */ + if (src_pix && !vmwgfx_hw_commit(src_pix)) + goto out_err; + if (mask_pict && mask_pix && !vmwgfx_hw_commit(mask_pix)) + goto out_err; + if (!vmwgfx_hw_commit(dst_pix)) + goto out_err; + + /* + * Update the XA state with our hardware surfaces and + * surface formats + */ + if (!vmwgfx_xa_update_comp(xa_comp, src_pix, mask_pix, dst_pix)) + goto out_err; + + /* + * Migrate data to surfaces. + */ + if (src_pix && src_region && !vmwgfx_hw_validate(src_pix, NULL)) + goto out_err; + if (mask_pict && mask_pix && mask_region && + !vmwgfx_hw_validate(mask_pix, NULL)) + goto out_err; + if (dst_region && !vmwgfx_hw_validate(dst_pix, NULL)) + goto out_err; + + + /* + * Bind the XA state. This must be done after data migration, since + * migration may change the hardware surfaces. + */ + if (xa_composite_prepare(vsaa->xa_ctx, xa_comp)) + goto out_err; + + REGION_UNINIT(pScreen, &empty); + return TRUE; + + out_err: + REGION_UNINIT(pScreen, &empty); + return FALSE; +} + +static void +vmwgfx_composite(struct saa_driver *driver, + int src_x, int src_y, int mask_x, int mask_y, + int dst_x, int dst_y, + int width, int height) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + xa_composite_rect(vsaa->xa_ctx, src_x, src_y, mask_x, mask_y, + dst_x, dst_y, width, height); +} + +static void +vmwgfx_composite_done(struct saa_driver *driver) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + xa_composite_done(vsaa->xa_ctx); +} + +static void +vmwgfx_takedown(struct saa_driver *driver) +{ + struct vmwgfx_saa *vsaa = to_vmwgfx_saa(driver); + + if (vsaa->vcomp) + vmwgfx_free_composite(vsaa->vcomp); + free(vsaa); +} + +/* + * This function call originates from the damage layer (outside SAA) + * to indicate that an operation is complete, and that damage is being + * processed. + */ +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); + ScrnInfoPtr pScrn = xf86Screens[vsaa->pScreen->myNum]; + + /* + * Make dri2 drawables up to date, or add them to the flush list + * executed at glxWaitX(). Currently glxWaitX() is broken, so + * we flush immediately, unless we're VT-switched away, in which + * case a flush would deadlock in the kernel. + */ + + if (vpix->hw && vpix->hw_is_dri2_fronts) { + if (1 && pScrn->vtSema && + vmwgfx_upload_to_hw(driver, pixmap, &spix->dirty_shadow)) { + + REGION_EMPTY(vsaa->pScreen, &spix->dirty_shadow); + return; + } + + if (WSBMLISTEMPTY(&vpix->sync_x_head)) + WSBMLISTADDTAIL(&vpix->sync_x_head, &vsaa->sync_x_list); + } +} + +/* + * This function is called by SAA to indicate that SAA has + * dirtied a region of a pixmap, either as hw (accelerated) or as + * !hw (not accelerated). + */ +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); + + /* + * Return if this is not a scanout pixmap. + */ + if (WSBMLISTEMPTY(&vpix->scanout_list)) + return TRUE; + +#if 0 + /* + * This code can be enabled to immediately upload scanout sw + * contents to the hw surface. Otherwise this is done + * just before we call the kms update function for the hw + * surface. + */ + if (vsaa->only_hw_presents) { + if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) + return FALSE; + + REGION_SUBTRACT(&vsaa->pScreen, &spix->dirty_shadow, + &spix->dirty_shadow, damage); + hw = TRUE; + } +#endif + + /* + * Is the new scanout damage hw or sw? + */ + if (hw) { + /* + * Dump pending present into present tracking region. + */ + if (vpix->dirty_present && + 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, ®); + REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_update, + damage); + if (REGION_NOTEMPTY(vsaa->pScreen, ®)) + vsaa->present_flush(vsaa->pScreen); + REGION_UNINIT(pScreen, ®); + } + REGION_UNION(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, damage); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, damage); + } + } else { + if (REGION_NOTEMPTY(vsaa->pScreen, vpix->pending_present)) { + RegionRec reg; + + REGION_NULL(vsaa->pScreen, ®); + REGION_INTERSECT(vsaa->pScreen, ®, vpix->pending_present, + damage); + if (REGION_NOTEMPTY(vsaa->pScreen, ®)) + vsaa->present_flush(vsaa->pScreen); + REGION_UNINIT(pScreen, ®); + } + REGION_UNION(vsaa->pScreen, vpix->pending_update, + vpix->pending_update, damage); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->dirty_present, + vpix->dirty_present, 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, + .composite_prepare = vmwgfx_composite_prepare, + .composite = vmwgfx_composite, + .composite_done = vmwgfx_composite_done, + .takedown = vmwgfx_takedown, +}; + + +Bool +vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, + void (*present_flush)(ScreenPtr pScreen), + Bool direct_presents, + Bool only_hw_presents, + Bool rendercheck) +{ + struct vmwgfx_saa *vsaa; + + vsaa = calloc(1, sizeof(*vsaa)); + if (!vsaa) + return FALSE; + + if (xat == NULL) { + direct_presents = FALSE; + only_hw_presents = 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->use_present_opt = direct_presents; + vsaa->only_hw_presents = only_hw_presents; + vsaa->rendercheck = rendercheck; + WSBMINITLISTHEAD(&vsaa->sync_x_list); + + vsaa->driver = vmwgfx_saa_driver; + vsaa->vcomp = vmwgfx_alloc_composite(); + + if (!vsaa->vcomp) + vsaa->driver.composite_prepare = NULL; + + 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_present, &box); + if (vpix->dirty_present) + REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, vpix->dirty_present); + REGION_SUBTRACT(vsaa->pScreen, vpix->pending_present, + vpix->pending_present, &vpix->base.dirty_shadow); + REGION_COPY(vsaa->pScreen, vpix->pending_update, + &vpix->base.dirty_shadow); +} + +/* + * 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(struct vmwgfx_screen_entry *entry) +{ + PixmapPtr pixmap = entry->pixmap; + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + + if (WSBMLISTEMPTY(&vpix->scanout_list)) { + uint32_t handle, dummy; + unsigned int depth; + + if (vsaa->only_hw_presents) { + /* + * The KMS fb will be a HW surface. Create it, add damage + * and get the handle. + */ + if (!vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 0, NULL)) + goto out_err; + if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) + goto out_err; + depth = xa_format_depth(xa_surface_format(vpix->hw)); + + } else { + /* + * The KMS fb will be a Guest Memory Region. Create it, + * add damage and get the handle. + */ + if (!vmwgfx_pixmap_create_gmr(vsaa, pixmap)) + goto out_err; + + handle = vpix->gmr->handle; + depth = pixmap->drawable.depth; + + } + + if (!vmwgfx_pixmap_add_present(pixmap, vsaa->use_present_opt)) + goto out_no_present; + + if (drmModeAddFB(vsaa->drm_fd, + pixmap->drawable.width, + pixmap->drawable.height, + depth, + pixmap->drawable.bitsPerPixel, + pixmap->devKind, + handle, + &vpix->fb_id) != 0) + goto out_no_fb;; + } + pixmap->refcnt += 1; + WSBMLISTADDTAIL(&entry->scanout_head, &vpix->scanout_list); + return vpix->fb_id; + + out_no_fb: + vmwgfx_pixmap_remove_present(vpix); + out_no_present: + vmwgfx_pixmap_remove_damage(pixmap); + out_err: + vpix->fb_id = -1; + return -1; +} + +/* + * 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(struct vmwgfx_screen_entry *entry) +{ + struct vmwgfx_saa *vsaa; + struct vmwgfx_saa_pixmap *vpix; + PixmapPtr pixmap = entry->pixmap; + + if (!pixmap) + return; + + vsaa = to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + vpix = vmwgfx_saa_pixmap(pixmap); + WSBMLISTDELINIT(&entry->scanout_head); + + if (WSBMLISTEMPTY(&vpix->scanout_list)) { + 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); + } + + entry->pixmap = NULL; + pixmap->drawable.pScreen->DestroyPixmap(pixmap); +} diff --git a/vmwgfx/vmwgfx_saa.h b/vmwgfx/vmwgfx_saa.h new file mode 100644 index 0000000..bb8ec96 --- /dev/null +++ b/vmwgfx/vmwgfx_saa.h @@ -0,0 +1,110 @@ +/* + * 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_composite.h> +#include "vmwgfx_drmi.h" +#include "wsbm_util.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; + uint32_t fb_id; + int hw_is_dri2_fronts; + struct _WsbmListHead sync_x_head; + struct _WsbmListHead scanout_list; + + uint32_t xa_flags; + uint32_t staging_add_flags; + uint32_t staging_remove_flags; + enum xa_formats staging_format; +}; + +struct vmwgfx_screen_entry { + struct _WsbmListHead scanout_head; + PixmapPtr pixmap; +}; + +static inline struct vmwgfx_saa_pixmap * +to_vmwgfx_saa_pixmap(struct saa_pixmap *spix) +{ + return (struct vmwgfx_saa_pixmap *) spix; +} + +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), + Bool direct_presents, + Bool only_hw_presents, + Bool rendercheck); + +extern uint32_t +vmwgfx_scanout_ref(struct vmwgfx_screen_entry *box); + +extern void +vmwgfx_scanout_unref(struct vmwgfx_screen_entry *box); + +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); + +extern Bool +vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth); + +Bool +vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags, + RegionPtr region); +#endif diff --git a/vmwgfx/vmwgfx_saa_priv.h b/vmwgfx/vmwgfx_saa_priv.h new file mode 100644 index 0000000..5f46dee --- /dev/null +++ b/vmwgfx/vmwgfx_saa_priv.h @@ -0,0 +1,125 @@ +/* + * 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_PRIV_H_ +#define _VMWGFX_SAA_PRIV_H_ + +#define VMWGFX_PIX_MALLOC (1 << 0) +#define VMWGFX_PIX_GMR (1 << 1) +#define VMWGFX_PIX_SURFACE (1 << 2) + +#include <xorg-server.h> +#include <picturestr.h> +#include "vmwgfx_saa.h" + +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; + Bool use_present_opt; + Bool only_hw_presents; + Bool rendercheck; + void (*present_flush) (ScreenPtr pScreen); + struct _WsbmListHead sync_x_list; + struct vmwgfx_composite *vcomp; +}; + +static inline struct vmwgfx_saa * +to_vmwgfx_saa(struct saa_driver *driver) { + return (struct vmwgfx_saa *) driver; +} + +/* + * In vmwgfx_saa.c + */ + +Bool +vmwgfx_hw_kill(struct vmwgfx_saa *vsaa, + struct saa_pixmap *spix); +Bool +vmwgfx_create_hw(struct vmwgfx_saa *vsaa, + PixmapPtr pixmap); + + +/* + * vmwgfx_xa_surface.c + */ + +enum xa_formats +vmwgfx_xa_format(enum _PictFormatShort format); +Bool +vmwgfx_hw_validate(PixmapPtr pixmap, RegionPtr region); + +Bool +vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags); +Bool +vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format); +Bool +vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format); +Bool +vmwgfx_hw_commit(PixmapPtr pixmap); + +/* + * vmwgfx_xa_composite.c + */ + +struct vmwgfx_composite; + +void +vmwgfx_free_composite(struct vmwgfx_composite *vcomp); +struct vmwgfx_composite * +vmwgfx_alloc_composite(void); + +Bool +vmwgfx_xa_update_comp(struct xa_composite *comp, + PixmapPtr src_pix, + PixmapPtr mask_pix, + PixmapPtr dst_pix); + +struct xa_composite * +vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp, + int op, + PicturePtr src_pict, + PicturePtr mask_pict, + PicturePtr dst_pict); + + +#endif diff --git a/vmwgfx/vmwgfx_tex_video.c b/vmwgfx/vmwgfx_tex_video.c new file mode 100644 index 0000000..cc94c20 --- /dev/null +++ b/vmwgfx/vmwgfx_tex_video.c @@ -0,0 +1,855 @@ +/* + * 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> +#include <math.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 + + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +/* + * ITU-R BT.601, BT.709 transfer matrices. + * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1] + * and [Pb, Pr] components are in the range [-0.5, 0.5]. + * + * The matrices are transposed to fit the xa conversion matrix format. + */ + +static const float bt_601[] = { + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.344136f, 1.772f, 0.f, + 1.402f, -0.714136f, 0.f, 0.f +}; + +static const float bt_709[] = { + 1.f, 1.f, 1.f, 0.f, + 0.f, -0.187324f, 1.8556f, 0.f, + 1.5748f, -0.468124f, 0.f, 0.f +}; + +static Atom xvBrightness, xvContrast, xvSaturation, xvHue; + +#define NUM_TEXTURED_ATTRIBUTES 4 +static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { + {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, + {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, + {XvSettable | XvGettable, -1000, 1000, "XV_HUE"} +}; + +#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 saturation; + int hue; + + int current_set; + struct vmwgfx_dmabuf *bounce[2][3]; + struct xa_surface *yuv[3]; + + int drm_fd; + + Bool hdtv; + float uv_offset; + float uv_scale; + float y_offset; + float y_scale; + float rgb_offset; + float rgb_scale; + float sinhue; + float coshue; + float cm[16]; +}; + +/* + * vmwgfx_update_conversion_matrix - Compute the effective color conversion + * matrix. + * + * Applies yuv- and resulting rgb scales and offsets to compute the correct + * color conversion matrix. These scales and offsets are properties of the + * video stream and can be adjusted using XV properties as well. + */ +static void +vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv) +{ + int i; + float *cm = priv->cm; + static const float *bt; + + bt = (priv->hdtv) ? bt_709 : bt_601; + + memcpy(cm, bt, sizeof(bt_601)); + + /* + * Apply hue rotation + */ + cm[4] = priv->coshue * bt[4] - priv->sinhue * bt[8]; + cm[8] = priv->sinhue * bt[4] + priv->coshue * bt[8]; + cm[5] = priv->coshue * bt[5] - priv->sinhue * bt[9]; + cm[9] = priv->sinhue * bt[5] + priv->coshue * bt[9]; + cm[6] = priv->coshue * bt[6] - priv->sinhue * bt[10]; + cm[10] = priv->sinhue * bt[6] + priv->coshue * bt[10]; + + /* + * Adjust for yuv scales in input and rgb scale in the converted output. + */ + for(i = 0; i < 3; ++i) { + cm[i] *= (priv->y_scale*priv->rgb_scale); + cm[i+4] *= (priv->uv_scale*priv->rgb_scale); + cm[i+8] *= (priv->uv_scale*priv->rgb_scale); + } + + /* + * Adjust for yuv offsets in input and rgb offset in the converted output. + */ + for (i = 0; i < 3; ++i) + cm[i+12] = -cm[i]*priv->y_offset - (cm[i+4] + cm[i+8])*priv->uv_offset + - priv->rgb_offset*priv->rgb_scale; + + /* + * Alpha is 1, unconditionally. + */ + cm[15] = 1.f; +} + + +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 < -1000) || (value > 1000)) + return BadValue; + + priv->brightness = value; + priv->y_offset = -((float) value)/1000.f; + + } else if (attribute == xvContrast) { + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->contrast = value; + priv->rgb_scale = ((float) value + 1000.f)/1000.f; + + } else if (attribute == xvSaturation) { + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->saturation = value; + priv->uv_scale = ((float) value + 1000.f)/1000.f; + + } else if (attribute == xvHue) { + double hue_angle; + + if ((value < -1000) || (value > 1000)) + return BadValue; + + priv->hue = value; + hue_angle = (double) value * M_PI / 1000.; + priv->sinhue = sin(hue_angle); + priv->coshue = cos(hue_angle); + + } else + return BadMatch; + + vmwgfx_update_conversion_matrix(priv); + 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 if (attribute == xvSaturation) + *value = priv->saturation; + else if (attribute == xvHue) + *value = priv->hue; + 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 id, + 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) { + + /* + * Adjust u,v texture size and DMA buffer to what's required by + * the format. + */ + if (i == 1) { + switch(id) { + case FOURCC_YV12: + height /= 2; + /* Fall through */ + case FOURCC_YUY2: + case FOURCC_UYVY: + width /= 2; + break; + default: + break; + } + } + + 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); + 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; + 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]; + memcpy(ymap, y, w*h); + memcpy(vmap, v, w*h/4); + memcpy(umap, u, w*h/4); + 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; + 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; + 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, ®, &box, 1); + + for (i=0; i<3; ++i) { + srf = port->yuv[i]; + buf = bounce[i]; + + if (i == 1) { + switch(id) { + case FOURCC_YV12: + h /= 2; + /* Fall through */ + case FOURCC_YUY2: + case FOURCC_UYVY: + w /= 2; + break; + default: + break; + } + + box.x1 = 0; + box.x2 = w; + box.y1 = 0; + box.y2 = h; + + REGION_RESET(pScrn->pScreen, ®, &box); + } + + if (xa_surface_handle(srf, &handle, &stride) != 0) { + ret = BadAlloc; + break; + } + + if (vmwgfx_dma(0, 0, ®, buf, w, handle, 1) != 0) { + ret = BadAlloc; + break; + } + } + REGION_UNINIT(pScrn->pScreen, ®); + } + + 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; + + REGION_NULL(pScreen, ®); + + if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, ®)) + goto out_no_dst; + + hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); + if (hdtv != pPriv->hdtv) { + pPriv->hdtv = hdtv; + vmwgfx_update_conversion_matrix(pPriv); + } + +#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), + pPriv->cm, + 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, ®); + 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, id, 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); + priv->hdtv = FALSE; + priv->uv_offset = 0.5f; + priv->uv_scale = 1.f; + priv->y_offset = 0.f; + priv->y_scale = 1.f; + priv->rgb_offset = 0.f; + priv->rgb_scale = 1.f; + priv->sinhue = 0.f; + priv->coshue = 1.f; + + vmwgfx_update_conversion_matrix(priv); + + 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"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + xvHue = MAKE_ATOM("XV_HUE"); + + 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); +} diff --git a/vmwgfx/vmwgfx_xa_composite.c b/vmwgfx/vmwgfx_xa_composite.c new file mode 100644 index 0000000..a2e3970 --- /dev/null +++ b/vmwgfx/vmwgfx_xa_composite.c @@ -0,0 +1,277 @@ +/* + * 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 Ruzin <zackr@vmware.com> + * + * The code in this file translates XRender PICT composite stuff + * to fit the libxatracker API. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <picturestr.h> +#include <X11/extensions/Xrender.h> +#include "xa_composite.h" +#include "vmwgfx_saa.h" +#include "vmwgfx_saa_priv.h" + + +struct vmwgfx_composite { + union xa_source_pict *src_spict; + union xa_source_pict *mask_spict; + union xa_source_pict *dst_spict; + struct xa_picture *src_pict; + struct xa_picture *mask_pict; + struct xa_picture *dst_pict; + struct xa_composite *comp; +}; + +static const enum xa_composite_op vmwgfx_op_map[] = { + [PictOpClear] = xa_op_clear, + [PictOpSrc] = xa_op_src, + [PictOpDst] = xa_op_dst, + [PictOpOver] = xa_op_over, + [PictOpOverReverse] = xa_op_over_reverse, + [PictOpIn] = xa_op_in, + [PictOpInReverse] = xa_op_in_reverse, + [PictOpOut] = xa_op_out, + [PictOpOutReverse] = xa_op_out_reverse, + [PictOpAtop] = xa_op_atop, + [PictOpAtopReverse] = xa_op_atop_reverse, + [PictOpXor] = xa_op_xor, + [PictOpAdd] = xa_op_add +}; + +static const unsigned int vmwgfx_op_map_size = + sizeof(vmwgfx_op_map) / sizeof(enum xa_composite_op); + +static Bool +vmwgfx_matrix_from_pict_transform(PictTransform *trans, float *matrix) +{ + if (!trans) + return FALSE; + + matrix[0] = XFixedToDouble(trans->matrix[0][0]); + matrix[3] = XFixedToDouble(trans->matrix[0][1]); + matrix[6] = XFixedToDouble(trans->matrix[0][2]); + + matrix[1] = XFixedToDouble(trans->matrix[1][0]); + matrix[4] = XFixedToDouble(trans->matrix[1][1]); + matrix[7] = XFixedToDouble(trans->matrix[1][2]); + + matrix[2] = XFixedToDouble(trans->matrix[2][0]); + matrix[5] = XFixedToDouble(trans->matrix[2][1]); + matrix[8] = XFixedToDouble(trans->matrix[2][2]); + + return TRUE; +} + +static enum xa_composite_wrap +vmwgfx_xa_setup_wrap(Bool pict_has_repeat, int pict_repeat) +{ + enum xa_composite_wrap wrap = xa_wrap_clamp_to_border; + + if (!pict_has_repeat) + return wrap; + + switch(pict_repeat) { + case RepeatNormal: + wrap = xa_wrap_repeat; + break; + case RepeatReflect: + wrap = xa_wrap_mirror_repeat; + break; + case RepeatPad: + wrap = xa_wrap_clamp_to_edge; + break; + default: + break; + } + return wrap; +} + +static Bool +vmwgfx_render_filter_to_xa(int xrender_filter, + enum xa_composite_filter *out_filter) +{ + switch (xrender_filter) { + case PictFilterConvolution: + case PictFilterNearest: + case PictFilterFast: + *out_filter = xa_filter_nearest; + break; + case PictFilterBest: + case PictFilterGood: + case PictFilterBilinear: + *out_filter = xa_filter_linear; + break; + default: + *out_filter = xa_filter_nearest; + return FALSE; + } + return TRUE; +} + +static Bool +vmwgfx_xa_setup_pict(PicturePtr pict, + struct xa_picture *xa_pict, + union xa_source_pict *src_pict) +{ + if (!pict) + return FALSE; + + memset(xa_pict, 0, sizeof(*xa_pict)); + + xa_pict->pict_format = vmwgfx_xa_format(pict->format); + if (xa_pict->pict_format == xa_format_unknown) + return FALSE; + + /* + * Saa doesn't let drivers accelerate alpha maps. + */ + xa_pict->alpha_map = NULL; + xa_pict->component_alpha = pict->componentAlpha; + + xa_pict->has_transform = + vmwgfx_matrix_from_pict_transform(pict->transform, + xa_pict->transform); + + xa_pict->wrap = vmwgfx_xa_setup_wrap(pict->repeat, + pict->repeatType); + + (void) vmwgfx_render_filter_to_xa(pict->filter, &xa_pict->filter); + + if (pict->pSourcePict) { + if (pict->pSourcePict->type != SourcePictTypeSolidFill) + return FALSE; + + src_pict->type = xa_src_pict_solid_fill; + src_pict->solid_fill.color = pict->pSourcePict->solidFill.color; + xa_pict->src_pict = src_pict; + } + + return TRUE; +} + +struct xa_composite * +vmwgfx_xa_setup_comp(struct vmwgfx_composite *vcomp, + int op, + PicturePtr src_pict, + PicturePtr mask_pict, + PicturePtr dst_pict) +{ + struct xa_composite *comp = vcomp->comp; + + if (op >= vmwgfx_op_map_size) + return NULL; + + comp->op = vmwgfx_op_map[op]; + if (comp->op == xa_op_clear && op != PictOpClear) + return NULL; + + if (!vmwgfx_xa_setup_pict(dst_pict, vcomp->dst_pict, + vcomp->dst_spict)) + return NULL; + if (!vmwgfx_xa_setup_pict(src_pict, vcomp->src_pict, + vcomp->src_spict)) + return NULL; + if (mask_pict && !vmwgfx_xa_setup_pict(mask_pict, + vcomp->mask_pict, + vcomp->mask_spict)) + return NULL; + + comp->dst = vcomp->dst_pict; + comp->src = vcomp->src_pict; + comp->mask = (mask_pict) ? vcomp->mask_pict : NULL; + + return comp; +} + +Bool +vmwgfx_xa_update_comp(struct xa_composite *comp, + PixmapPtr src_pix, + PixmapPtr mask_pix, + PixmapPtr dst_pix) +{ + comp->dst->srf = vmwgfx_saa_pixmap(dst_pix)->hw; + if (src_pix) + comp->src->srf = vmwgfx_saa_pixmap(src_pix)->hw; + if (mask_pix && comp->mask) + comp->mask->srf = vmwgfx_saa_pixmap(mask_pix)->hw; + return TRUE; +} + + +void +vmwgfx_free_composite(struct vmwgfx_composite *vcomp) +{ + if (!vcomp) + return; + + if (vcomp->src_spict) + free(vcomp->src_spict); + if (vcomp->mask_spict) + free(vcomp->mask_spict); + if (vcomp->dst_spict) + free(vcomp->dst_spict); + if (vcomp->src_pict) + free(vcomp->src_pict); + if (vcomp->mask_pict) + free(vcomp->mask_pict); + if (vcomp->dst_pict) + free(vcomp->dst_pict); + if (vcomp->comp) + free(vcomp->comp); + free(vcomp); +} + +struct vmwgfx_composite * +vmwgfx_alloc_composite(void) +{ + const struct xa_composite_allocation *a = xa_composite_allocation(); + struct vmwgfx_composite *vcomp = calloc(1, sizeof(*vcomp)); + + if (!vcomp) + return NULL; + + vcomp->src_spict = calloc(1, a->xa_source_pict_size); + vcomp->mask_spict = calloc(1, a->xa_source_pict_size); + vcomp->dst_spict = calloc(1, a->xa_source_pict_size); + vcomp->src_pict = calloc(1, a->xa_picture_size); + vcomp->mask_pict = calloc(1, a->xa_picture_size); + vcomp->dst_pict = calloc(1, a->xa_picture_size); + vcomp->comp = calloc(1, a->xa_composite_size); + + if (!vcomp->src_spict || !vcomp->mask_spict || !vcomp->dst_spict || + !vcomp->src_pict || !vcomp->mask_pict || !vcomp->dst_pict || + !vcomp->comp) { + vmwgfx_free_composite(vcomp); + return NULL; + } + + return vcomp; +} diff --git a/vmwgfx/vmwgfx_xa_surface.c b/vmwgfx/vmwgfx_xa_surface.c new file mode 100644 index 0000000..2a18762 --- /dev/null +++ b/vmwgfx/vmwgfx_xa_surface.c @@ -0,0 +1,368 @@ +/* + * 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> + */ +#ifdef _HAVE_CONFIG_H_ +#include "config.h" +#endif + +#include <xorg-server.h> +#include "vmwgfx_saa_priv.h" + + +static const enum xa_surface_type vmwgfx_stype_map[] = { + [PICT_TYPE_OTHER] = xa_type_other, + [PICT_TYPE_A] = xa_type_a, + [PICT_TYPE_ARGB] = xa_type_argb, + [PICT_TYPE_ABGR] = xa_type_abgr, + [PICT_TYPE_BGRA] = xa_type_bgra +}; + +static const unsigned int vmwgfx_stype_map_size = + sizeof(vmwgfx_stype_map) / sizeof(enum xa_surface_type); + + +/* + * Create an xa format from a PICT format. + */ +enum xa_formats +vmwgfx_xa_format(enum _PictFormatShort format) +{ + uint32_t ptype = PICT_FORMAT_TYPE(format); + + if (ptype >= vmwgfx_stype_map_size || + vmwgfx_stype_map[ptype] == 0 || + vmwgfx_stype_map[ptype] == xa_type_other) + return xa_format_unknown; + + return xa_format(PICT_FORMAT_BPP(format), + vmwgfx_stype_map[ptype], + PICT_FORMAT_A(format), + PICT_FORMAT_R(format), + PICT_FORMAT_G(format), + PICT_FORMAT_B(format)); +} + +/* + * Choose formats and flags for a dri2 surface. + */ +static Bool +vmwgfx_hw_dri2_stage(PixmapPtr pixmap, unsigned int depth) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format; + + if (depth == 0) + depth = pixmap->drawable.depth; + + switch(depth) { + case 32: + format = xa_format_a8r8g8b8; + break; + case 24: + format = xa_format_x8r8g8b8; + break; + case 16: + format = xa_format_r5g6b5; + break; + case 15: + format = xa_format_x1r5g5b5; + break; + default: + return FALSE; + } + + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED; + + return TRUE; +} + +/* + * Is composite old format compatible? Only difference is that old format + * has more alpha bits? + */ +static inline Bool +vmwgfx_old_format_compatible(enum xa_formats format, + enum xa_formats old_format) +{ + return (format == old_format || + (xa_format_type(format) == xa_format_type(old_format) && + xa_format_a(format) <= xa_format_a(old_format) && + xa_format_r(format) == xa_format_r(old_format) && + xa_format_g(format) == xa_format_g(old_format) && + xa_format_b(format) == xa_format_b(old_format))); +} + + +/* + * Choose format and flags for a composite dst surface. + */ +Bool +vmwgfx_hw_composite_dst_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = vmwgfx_xa_format(pict_format); + + /* + * Check if we can reuse old hardware format. + */ + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vmwgfx_old_format_compatible(format, old_format)) + format = old_format; + } + + if (xa_format_check_supported(vsaa->xat, format, + vpix->xa_flags | XA_FLAG_RENDER_TARGET) != + XA_ERR_NONE) { + return FALSE; + } + + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = XA_FLAG_RENDER_TARGET; + + return TRUE; +} + +/* + * Choose format and flags for a composite src surface. + */ +Bool +vmwgfx_hw_composite_src_stage(PixmapPtr pixmap, + enum _PictFormatShort pict_format) +{ + struct vmwgfx_saa *vsaa = + to_vmwgfx_saa(saa_get_driver(pixmap->drawable.pScreen)); + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = vmwgfx_xa_format(pict_format); + enum xa_formats swizzle_format = xa_format_unknown; + enum xa_surface_type ftype; + + if (format == xa_format_unknown) + return FALSE; + + ftype = xa_format_type(format); + if (ftype == xa_type_abgr) { + + swizzle_format = xa_format(xa_format_bpp(format), + xa_type_argb, + xa_format_a(format), + xa_format_r(format), + xa_format_g(format), + xa_format_b(format)); + } + + /* + * Check if we can reuse old format. + */ + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vmwgfx_old_format_compatible(format, old_format) || + (swizzle_format != xa_format_unknown && + vmwgfx_old_format_compatible(swizzle_format, old_format))) { + format = old_format; + goto have_format; + } + } + + if (swizzle_format != xa_format_unknown && + xa_format_check_supported(vsaa->xat, swizzle_format, vpix->xa_flags) == + XA_ERR_NONE) { + format = swizzle_format; + goto have_format; + } + + if (xa_format_check_supported(vsaa->xat, format, vpix->xa_flags) == + XA_ERR_NONE) { + goto have_format; + } + + return FALSE; + have_format: + vpix->staging_format = format; + vpix->staging_remove_flags = 0; + vpix->staging_add_flags = 0; + + return TRUE; +} + +/* + * Choose accel format given depth. + */ +static enum xa_formats +vmwgfx_choose_accel_format(unsigned int depth) +{ + switch(depth) { + case 32: + return xa_format_a8r8g8b8; + case 24: + return xa_format_x8r8g8b8; + case 16: + return xa_format_r5g6b5; + case 15: + return xa_format_x1r5g5b5; + case 8: + return xa_format_a8; + default: + break; + } + return xa_format_unknown; +} + + +/* + * Determine xa format and flags for an ordinary accel surface. + */ +Bool +vmwgfx_hw_accel_stage(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags) +{ + struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); + enum xa_formats format = xa_format_unknown; + + if (depth == 0) + depth = pixmap->drawable.depth; + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + enum xa_surface_type ftype = xa_format_type(old_format); + + if (ftype != xa_type_argb && + ftype != xa_type_a) { + LogMessage(X_ERROR, + "Acceleration fallback due to strange hw format.\n"); + return FALSE; + } + + if (xa_format_depth(old_format) == depth || + (xa_format_depth(old_format) == 32 && + depth == 24)) + format = old_format; + } + + if (format == xa_format_unknown) + format = vmwgfx_choose_accel_format(depth); + + if (format == xa_format_unknown) + return FALSE; + + vpix->staging_add_flags = add_flags; + vpix->staging_remove_flags = remove_flags; + vpix->staging_format = format; + + return TRUE; +} + +/* + * Create a surface with a format and flags determined by one of + * the staging functions. + */ +Bool +vmwgfx_hw_commit(PixmapPtr pixmap) +{ + 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); + enum xa_formats format = vpix->staging_format; + + if (vpix->hw) { + enum xa_formats old_format = xa_surface_format(vpix->hw); + + if (vpix->staging_format != old_format) { + if (xa_format_type(format) != xa_format_type(old_format) || + xa_format_r(format) != xa_format_r(old_format) || + xa_format_g(format) != xa_format_g(old_format) || + xa_format_b(format) != xa_format_b(old_format)) { + + LogMessage(X_INFO, "Killing old hw surface.\n"); + + if (!vmwgfx_hw_kill(vsaa, spix)) + return FALSE; + } + } + } + + if (vpix->hw) { + uint32_t new_flags; + + new_flags = (vpix->xa_flags & ~vpix->staging_remove_flags) | + vpix->staging_add_flags; + + if (vpix->staging_format != xa_surface_format(vpix->hw)) + LogMessage(X_INFO, "Changing hardware format.\n"); + + if (xa_surface_redefine(vpix->hw, + pixmap->drawable.width, + pixmap->drawable.height, + 0, + xa_type_other, + vpix->staging_format, + new_flags, 1) != XA_ERR_NONE) + return FALSE; + vpix->xa_flags = new_flags; + } else if (!vmwgfx_create_hw(vsaa, pixmap)) + return FALSE; + + return TRUE; +} + +/* + * Create an accel surface if there is none, and make sure the region + * given by @region is valid. If @region is NULL, the whole surface + * will be valid. This is a utility convenience function only. + */ +Bool +vmwgfx_hw_accel_validate(PixmapPtr pixmap, unsigned int depth, + uint32_t add_flags, uint32_t remove_flags, + RegionPtr region) +{ + return (vmwgfx_hw_accel_stage(pixmap, depth, add_flags, remove_flags) && + vmwgfx_hw_commit(pixmap) && + vmwgfx_hw_validate(pixmap, region)); +} + + +/* + * Create a dri2 surface if there is none, + * and make sure the whole surfade is valid. + * This is a utility convenience function only. + */ +Bool +vmwgfx_hw_dri2_validate(PixmapPtr pixmap, unsigned int depth) +{ + return (vmwgfx_hw_dri2_stage(pixmap, depth) && + vmwgfx_hw_commit(pixmap) && + vmwgfx_hw_validate(pixmap, NULL)); +} diff --git a/vmwgfx/wsbm_util.h b/vmwgfx/wsbm_util.h new file mode 100644 index 0000000..2a2613b --- /dev/null +++ b/vmwgfx/wsbm_util.h @@ -0,0 +1,79 @@ +/* + * This file is not copyrighted. + */ + +#ifndef _WSBM_UTIL_H_ +#define _WSBM_UTIL_H_ + +#include <stddef.h> + +#ifndef containerOf +#define containerOf(__item, __type, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) +#endif + +struct _WsbmListHead +{ + struct _WsbmListHead *prev; + struct _WsbmListHead *next; +}; + +#define WSBMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define WSBMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define WSBMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define WSBMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define WSBMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define WSBMLISTFOREACH(__item, __list) \ + for((__item) = (__list)->next; (__item) != (__list); (__item) = (__item)->next) + +#define WSBMLISTFOREACHPREV(__item, __list) \ + for((__item) = (__list)->prev; (__item) != (__list); (__item) = (__item)->prev) + +#define WSBMLISTFOREACHSAFE(__item, __next, __list) \ + for((__item) = (__list)->next, (__next) = (__item)->next; \ + (__item) != (__list); \ + (__item) = (__next), (__next) = (__item)->next) + +#define WSBMLISTFOREACHPREVSAFE(__item, __prev, __list) \ + for((__item) = (__list)->prev, (__prev) = (__item->prev); \ + (__item) != (__list); \ + (__item) = (__prev), (__prev) = (__item)->prev) + +#define WSBMLISTENTRY(__item, __type, __field) \ + containerOf(__item, __type, __field) + +#define WSBMLISTEMPTY(__item) \ + ((__item)->next == (__item)) + +#endif |