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