vmwgfx, saa: Initial import

This imports the vmwgfx driver, based on the Gallium3D Xorg state tracker,
as well as the saa library. A "Shadow Acceleration Architecture", which is
optimized for the case where transfers between system (shadow) and hw memory
is very costly.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
This commit is contained in:
Thomas Hellstrom
2011-06-16 15:55:07 +02:00
parent 0142bb8d10
commit 84166d4b45
27 changed files with 12047 additions and 414 deletions

View File

@@ -18,7 +18,7 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SUBDIRS = src man vmwarectrl
SUBDIRS = src man vmwarectrl saa vmwgfx
MAINTAINERCLEANFILES = ChangeLog INSTALL
.PHONY: ChangeLog INSTALL

View File

@@ -121,5 +121,7 @@ AC_CONFIG_FILES([
src/Makefile
vmwarectrl/Makefile
man/Makefile
saa/Makefile
vmwgfx/Makefile
])
AC_OUTPUT

13
saa/Makefile.am Normal file
View File

@@ -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

748
saa/saa.c Normal file
View File

@@ -0,0 +1,748 @@
/*
* Copyright © 2001 Keith Packard
*
* Partly based on code that is Copyright © The XFree86 Project Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/** @file
* This file covers the initialization and teardown of SAA, and has various
* functions not responsible for performing rendering, pixmap migration, or
* memory management.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stdlib.h>
#include "saa_priv.h"
#include <X11/fonts/fontstruct.h>
#include "dixfontstr.h"
#include "regionstr.h"
#include "saa.h"
#ifdef SAA_DEVPRIVATEKEYREC
DevPrivateKeyRec saa_screen_index;
DevPrivateKeyRec saa_pixmap_index;
DevPrivateKeyRec saa_gc_index;
#else
int saa_screen_index = -1;
int saa_pixmap_index = -1;
int saa_gc_index = -1;
#endif
/**
* saa_get_drawable_pixmap() returns a backing pixmap for a given drawable.
*
* @param pDrawable the drawable being requested.
*
* This function returns the backing pixmap for a drawable, whether it is a
* redirected window, unredirected window, or already a pixmap. Note that
* coordinate translation is needed when drawing to the backing pixmap of a
* redirected window, and the translation coordinates are provided by calling
* saa_get_drawable_pixmap() on the drawable.
*/
PixmapPtr
saa_get_drawable_pixmap(DrawablePtr pDrawable)
{
if (pDrawable->type == DRAWABLE_WINDOW)
return pDrawable->pScreen->GetWindowPixmap((WindowPtr) pDrawable);
else
return (PixmapPtr) pDrawable;
}
/**
* Sets the offsets to add to coordinates to make them address the same bits in
* the backing drawable. These coordinates are nonzero only for redirected
* windows.
*/
void
saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
int *xp, int *yp)
{
#ifdef COMPOSITE
if (pDrawable->type == DRAWABLE_WINDOW) {
*xp = -pPixmap->screen_x;
*yp = -pPixmap->screen_y;
return;
}
#endif
*xp = 0;
*yp = 0;
}
/**
* Returns the pixmap which backs a drawable, and the offsets to add to
* coordinates to make them address the same bits in the backing drawable.
*/
PixmapPtr
saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp)
{
PixmapPtr pixmap = saa_get_drawable_pixmap(drawable);
saa_get_drawable_deltas(drawable, pixmap, xp, yp);
return pixmap;
}
static Bool
saa_download_from_hw(PixmapPtr pix, RegionPtr readback)
{
struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
struct saa_driver *driver = sscreen->driver;
struct saa_pixmap *spix = saa_pixmap(pix);
void *addr;
Bool ret;
if (spix->mapped_access)
driver->release_from_cpu(driver, pix, spix->mapped_access);
ret = driver->download_from_hw(driver, pix, readback);
if (spix->mapped_access) {
addr = driver->sync_for_cpu(driver, pix, spix->mapped_access);
if (addr != NULL)
spix->addr = addr;
}
return ret;
}
Bool
saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
RegionPtr read_reg)
{
ScreenPtr pScreen = pix->drawable.pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
struct saa_driver *driver = sscreen->driver;
struct saa_pixmap *spix = saa_pixmap(pix);
saa_access_t map_access = 0;
Bool ret = TRUE;
if (read_reg && REGION_NOTEMPTY(pScreen, read_reg))
ret = saa_download_from_hw(pix, read_reg);
if (!ret) {
LogMessage(X_ERROR, "Prepare access pixmap failed.\n");
return ret;
}
if ((access & SAA_ACCESS_R) != 0 && spix->read_access++ == 0)
map_access = SAA_ACCESS_R;
if ((access & SAA_ACCESS_W) != 0 && spix->write_access++ == 0)
map_access |= SAA_ACCESS_W;
if (map_access) {
if (spix->auth_loc != saa_loc_override) {
(void)driver->sync_for_cpu(driver, pix, map_access);
spix->addr = driver->map(driver, pix, map_access);
} else
spix->addr = spix->override;
spix->mapped_access |= map_access;
}
pix->devPrivate.ptr = spix->addr;
return TRUE;
}
void
saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access)
{
struct saa_screen_priv *sscreen = saa_screen(pix->drawable.pScreen);
struct saa_driver *driver = sscreen->driver;
struct saa_pixmap *spix = saa_pixmap(pix);
saa_access_t unmap_access = 0;
if ((access & SAA_ACCESS_R) != 0 && --spix->read_access == 0)
unmap_access = SAA_ACCESS_R;
if ((access & SAA_ACCESS_W) != 0 && --spix->write_access == 0)
unmap_access |= SAA_ACCESS_W;
if (spix->read_access < 0)
LogMessage(X_ERROR, "Incorrect read access.\n");
if (spix->write_access < 0)
LogMessage(X_ERROR, "Incorrect write access.\n");
if (unmap_access) {
if (spix->auth_loc != saa_loc_override) {
driver->unmap(driver, pix, unmap_access);
driver->release_from_cpu(driver, pix, unmap_access);
}
spix->mapped_access &= ~unmap_access;
}
if (!spix->mapped_access) {
spix->addr = NULL;
pix->devPrivate.ptr = SAA_INVALID_ADDRESS;
}
}
/*
* Callback that is called after a rendering operation. We try to
* determine whether it's a shadow damage or a hw damage and call the
* driver callback.
*/
static void
saa_report_damage(DamagePtr damage, RegionPtr reg, void *closure)
{
PixmapPtr pixmap = (PixmapPtr) closure;
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
struct saa_driver *driver = saa_screen(pixmap->drawable.pScreen)->driver;
if (spix->read_access || spix->write_access)
LogMessage(X_ERROR, "Damage report inside prepare access.\n");
driver->operation_complete(driver, pixmap);
DamageEmpty(damage);
}
Bool
saa_add_damage(PixmapPtr pixmap)
{
ScreenPtr pScreen = pixmap->drawable.pScreen;
struct saa_pixmap *spix = saa_get_saa_pixmap(pixmap);
if (spix->damage)
return TRUE;
spix->damage = DamageCreate(saa_report_damage, NULL,
DamageReportRawRegion, TRUE, pScreen, pixmap);
if (!spix->damage)
return FALSE;
DamageRegister(&pixmap->drawable, spix->damage);
DamageSetReportAfterOp(spix->damage, TRUE);
return TRUE;
}
static inline RegionPtr
saa_pix_damage_region(struct saa_pixmap *spix)
{
return (spix->damage ? DamageRegion(spix->damage) : NULL);
}
Bool
saa_pad_read(DrawablePtr draw)
{
ScreenPtr pScreen = draw->pScreen;
PixmapPtr pix;
int xp;
int yp;
BoxRec box;
RegionRec entire;
Bool ret;
(void)pScreen;
pix = saa_get_pixmap(draw, &xp, &yp);
box.x1 = draw->x + xp;
box.y1 = draw->y + yp;
box.x2 = box.x1 + draw->width;
box.y2 = box.y1 + draw->height;
REGION_INIT(pScreen, &entire, &box, 1);
ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
REGION_UNINIT(pScreen, &entire);
return ret;
}
Bool
saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h)
{
ScreenPtr pScreen = draw->pScreen;
PixmapPtr pix;
int xp;
int yp;
BoxRec box;
RegionRec entire;
Bool ret;
(void)pScreen;
pix = saa_get_pixmap(draw, &xp, &yp);
box.x1 = x + xp;
box.y1 = y + yp;
box.x2 = box.x1 + w;
box.y2 = box.y1 + h;
REGION_INIT(pScreen, &entire, &box, 1);
ret = saa_prepare_access_pixmap(pix, SAA_ACCESS_R, &entire);
REGION_UNINIT(pScreen, &entire);
return ret;
}
/**
* Prepares a drawable destination for access, and maps it read-write.
* If check_read is TRUE, pGC should point to a valid GC. The drawable
* may then be mapped write-only if the pending operation admits.
*/
Bool
saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
saa_access_t * access)
{
int xp;
int yp;
PixmapPtr pixmap = saa_get_pixmap(draw, &xp, &yp);
struct saa_pixmap *spix = saa_pixmap(pixmap);
*access = SAA_ACCESS_W;
/*
* If the to-be-damaged area doesn't depend at all on previous
* rendered contents, we don't need to do any readback.
*/
if (check_read && !saa_gc_reads_destination(draw, pGC))
return saa_prepare_access_pixmap(pixmap, *access, NULL);
*access |= SAA_ACCESS_R;
/*
* Read back the area to be damaged.
*/
return saa_prepare_access_pixmap(pixmap, *access,
saa_pix_damage_pending(spix));
}
void
saa_fad_read(DrawablePtr draw)
{
saa_finish_access_pixmap(saa_get_drawable_pixmap(draw), SAA_ACCESS_R);
}
void
saa_fad_write(DrawablePtr draw, saa_access_t access)
{
PixmapPtr pix = saa_get_drawable_pixmap(draw);
struct saa_pixmap *spix = saa_pixmap(pix);
saa_finish_access_pixmap(pix, access);
if (spix->damage)
saa_pixmap_dirty(pix, FALSE, saa_pix_damage_pending(spix));
}
Bool
saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC)
{
return ((pGC->alu != GXcopy && pGC->alu != GXclear && pGC->alu != GXset &&
pGC->alu != GXcopyInverted) || pGC->fillStyle == FillStippled ||
pGC->clientClipType != CT_NONE ||
!SAA_PM_IS_SOLID(pDrawable, pGC->planemask));
}
Bool
saa_op_reads_destination(CARD8 op)
{
/* FALSE (does not read destination) is the list of ops in the protocol
* document with "0" in the "Fb" column and no "Ab" in the "Fa" column.
* That's just Clear and Src. ReduceCompositeOp() will already have
* converted con/disjoint clear/src to Clear or Src.
*/
switch (op) {
case PictOpClear:
case PictOpSrc:
return FALSE;
default:
return TRUE;
}
}
static void
saa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
{
/* fbValidateGC will do direct access to pixmaps if the tiling has changed.
* Do a few smart things so fbValidateGC can do it's work.
*/
ScreenPtr pScreen = pDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
struct saa_gc_priv *sgc = saa_gc(pGC);
PixmapPtr pTile = NULL;
Bool finish_current_tile = FALSE;
/* Either of these conditions is enough to trigger access to a tile pixmap. */
/* With pGC->tileIsPixel == 1, you run the risk of dereferencing an invalid tile pixmap pointer. */
if (pGC->fillStyle == FillTiled
|| ((changes & GCTile) && !pGC->tileIsPixel)) {
pTile = pGC->tile.pixmap;
/* Sometimes tile pixmaps are swapped, you need access to:
* - The current tile if it depth matches.
* - Or the rotated tile if that one matches depth and !(changes & GCTile).
* - Or the current tile pixmap and a newly created one.
*/
if (pTile && pTile->drawable.depth != pDrawable->depth
&& !(changes & GCTile)) {
PixmapPtr pRotatedTile = fbGetRotatedPixmap(pGC);
if (pRotatedTile
&& pRotatedTile->drawable.depth == pDrawable->depth)
pTile = pRotatedTile;
else
finish_current_tile = TRUE; /* CreatePixmap will be called. */
}
}
if (pGC->stipple && !saa_pad_read(&pGC->stipple->drawable)) {
LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
return;
}
if (pTile && !saa_pad_read(&pTile->drawable)) {
LogMessage(X_ERROR, "Failed stipple prepareaccess.\n");
goto out_no_tile;
}
/* Calls to Create/DestroyPixmap have to be identified as special, so
* up sscreen->fallback_count.
*/
sscreen->fallback_count++;
saa_swap(sgc, pGC, funcs);
(*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
saa_swap(sgc, pGC, funcs);
if (finish_current_tile && pGC->tile.pixmap)
saa_fad_write(&pGC->tile.pixmap->drawable, SAA_ACCESS_W);
sscreen->fallback_count--;
if (pTile)
saa_fad_read(&pTile->drawable);
out_no_tile:
if (pGC->stipple)
saa_fad_read(&pGC->stipple->drawable);
}
static void
saa_destroy_gc(GCPtr pGC)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_swap(sgc, pGC, funcs);
(*pGC->funcs->DestroyGC) (pGC);
saa_swap(sgc, pGC, funcs);
}
static void
saa_change_gc(GCPtr pGC, unsigned long mask)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_swap(sgc, pGC, funcs);
(*pGC->funcs->ChangeGC) (pGC, mask);
saa_swap(sgc, pGC, funcs);
}
static void
saa_copy_gc(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
{
struct saa_gc_priv *sgc = saa_gc(pGCDst);
saa_swap(sgc, pGCDst, funcs);
(*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
saa_swap(sgc, pGCDst, funcs);
}
static void
saa_change_clip(GCPtr pGC, int type, pointer pvalue, int nrects)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_swap(sgc, pGC, funcs);
(*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
saa_swap(sgc, pGC, funcs);
}
static void
saa_copy_clip(GCPtr pGCDst, GCPtr pGCSrc)
{
struct saa_gc_priv *sgc = saa_gc(pGCDst);
saa_swap(sgc, pGCDst, funcs);
(*pGCDst->funcs->CopyClip) (pGCDst, pGCSrc);
saa_swap(sgc, pGCDst, funcs);
}
static void
saa_destroy_clip(GCPtr pGC)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_swap(sgc, pGC, funcs);
(*pGC->funcs->DestroyClip) (pGC);
saa_swap(sgc, pGC, funcs);
}
static GCFuncs saa_gc_funcs = {
saa_validate_gc,
saa_change_gc,
saa_copy_gc,
saa_destroy_gc,
saa_change_clip,
saa_destroy_clip,
saa_copy_clip
};
/**
* saa_create_gc makes a new GC and hooks up its funcs handler, so that
* saa_validate_gc() will get called.
*/
int
saa_create_gc(GCPtr pGC)
{
ScreenPtr pScreen = pGC->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
struct saa_gc_priv *sgc = saa_gc(pGC);
Bool ret;
saa_swap(sscreen, pScreen, CreateGC);
ret = pScreen->CreateGC(pGC);
if (ret) {
saa_wrap(sgc, pGC, funcs, &saa_gc_funcs);
saa_wrap(sgc, pGC, ops, &saa_gc_ops);
}
saa_swap(sscreen, pScreen, CreateGC);
return ret;
}
static Bool
saa_prepare_access_window(WindowPtr pWin)
{
if (pWin->backgroundState == BackgroundPixmap) {
if (!saa_pad_read(&pWin->background.pixmap->drawable))
return FALSE;
}
if (pWin->borderIsPixel == FALSE) {
if (!saa_pad_read(&pWin->border.pixmap->drawable)) {
if (pWin->backgroundState == BackgroundPixmap)
saa_fad_read(&pWin->background.pixmap->drawable);
return FALSE;
}
}
return TRUE;
}
static void
saa_finish_access_window(WindowPtr pWin)
{
if (pWin->backgroundState == BackgroundPixmap)
saa_fad_read(&pWin->background.pixmap->drawable);
if (pWin->borderIsPixel == FALSE)
saa_fad_read(&pWin->border.pixmap->drawable);
}
static Bool
saa_change_window_attributes(WindowPtr pWin, unsigned long mask)
{
Bool ret;
if (!saa_prepare_access_window(pWin))
return FALSE;
ret = fbChangeWindowAttributes(pWin, mask);
saa_finish_access_window(pWin);
return ret;
}
RegionPtr
saa_bitmap_to_region(PixmapPtr pPix)
{
RegionPtr ret;
if (!saa_pad_read(&pPix->drawable))
return NULL;
ret = fbPixmapToRegion(pPix);
saa_fad_read(&pPix->drawable);
return ret;
}
void
saa_set_fallback_debug(ScreenPtr screen, Bool enable)
{
struct saa_screen_priv *sscreen = saa_screen(screen);
sscreen->fallback_debug = enable;
}
/**
* saa_close_screen() unwraps its wrapped screen functions and tears down SAA's
* screen private, before calling down to the next CloseScreen.
*/
Bool
saa_close_screen(int i, ScreenPtr pScreen)
{
struct saa_screen_priv *sscreen = saa_screen(pScreen);
struct saa_driver *driver = sscreen->driver;
if (pScreen->devPrivate) {
/* Destroy the pixmap created by miScreenInit() *before*
* chaining up as we finalize ourselves here and so this
* is the last chance we have of releasing our resources
* associated with the Pixmap. So do it first.
*/
(void)(*pScreen->DestroyPixmap) (pScreen->devPrivate);
pScreen->devPrivate = NULL;
}
saa_unwrap(sscreen, pScreen, CloseScreen);
saa_unwrap(sscreen, pScreen, CreateGC);
saa_unwrap(sscreen, pScreen, ChangeWindowAttributes);
saa_unwrap(sscreen, pScreen, CreatePixmap);
saa_unwrap(sscreen, pScreen, DestroyPixmap);
saa_unwrap(sscreen, pScreen, ModifyPixmapHeader);
saa_unwrap(sscreen, pScreen, BitmapToRegion);
#ifdef RENDER
saa_render_takedown(pScreen);
#endif
saa_unaccel_takedown(pScreen);
driver->takedown(driver);
free(sscreen);
return (*pScreen->CloseScreen) (i, pScreen);
}
struct saa_driver *
saa_get_driver(ScreenPtr pScreen)
{
return saa_screen(pScreen)->driver;
}
/**
* @param pScreen screen being initialized
* @param pScreenInfo SAA driver record
*
* saa_driver_init sets up SAA given a driver record filled in by the driver.
* pScreenInfo should have been allocated by saa_driver_alloc(). See the
* comments in _SaaDriver for what must be filled in and what is optional.
*
* @return TRUE if SAA was successfully initialized.
*/
Bool
saa_driver_init(ScreenPtr screen, struct saa_driver * saa_driver)
{
struct saa_screen_priv *sscreen;
if (!saa_driver)
return FALSE;
if (saa_driver->saa_major != SAA_VERSION_MAJOR ||
saa_driver->saa_minor > SAA_VERSION_MINOR) {
LogMessage(X_ERROR,
"SAA(%d): driver's SAA version requirements "
"(%d.%d) are incompatible with SAA version (%d.%d)\n",
screen->myNum, saa_driver->saa_major,
saa_driver->saa_minor, SAA_VERSION_MAJOR, SAA_VERSION_MINOR);
return FALSE;
}
#if 0
if (!saa_driver->prepare_solid) {
LogMessage(X_ERROR,
"SAA(%d): saa_driver_t::prepare_solid must be "
"non-NULL\n", screen->myNum);
return FALSE;
}
if (!saa_driver->prepare_copy) {
LogMessage(X_ERROR,
"SAA(%d): saa_driver_t::prepare_copy must be "
"non-NULL\n", screen->myNum);
return FALSE;
}
#endif
#ifdef SAA_DEVPRIVATEKEYREC
if (!dixRegisterPrivateKey(&saa_screen_index, PRIVATE_SCREEN, 0)) {
LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
return FALSE;
}
if (!dixRegisterPrivateKey(&saa_pixmap_index, PRIVATE_PIXMAP,
saa_driver->pixmap_size)) {
LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
return FALSE;
}
if (!dixRegisterPrivateKey(&saa_gc_index, PRIVATE_GC,
sizeof(struct saa_gc_priv))) {
LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
return FALSE;
}
#else
if (!dixRequestPrivate(&saa_screen_index, 0)) {
LogMessage(X_ERROR, "Failed to register SAA screen private.\n");
return FALSE;
}
if (!dixRequestPrivate(&saa_pixmap_index, saa_driver->pixmap_size)) {
LogMessage(X_ERROR, "Failed to register SAA pixmap private.\n");
return FALSE;
}
if (!dixRequestPrivate(&saa_gc_index, sizeof(struct saa_gc_priv))) {
LogMessage(X_ERROR, "Failed to register SAA gc private.\n");
return FALSE;
}
#endif
sscreen = calloc(1, sizeof(*sscreen));
if (!sscreen) {
LogMessage(X_WARNING,
"SAA(%d): Failed to allocate screen private\n",
screen->myNum);
return FALSE;
}
sscreen->driver = saa_driver;
dixSetPrivate(&screen->devPrivates, &saa_screen_index, sscreen);
/*
* Replace various fb screen functions
*/
saa_wrap(sscreen, screen, CloseScreen, saa_close_screen);
saa_wrap(sscreen, screen, CreateGC, saa_create_gc);
saa_wrap(sscreen, screen, ChangeWindowAttributes,
saa_change_window_attributes);
saa_wrap(sscreen, screen, CreatePixmap, saa_create_pixmap);
saa_wrap(sscreen, screen, DestroyPixmap, saa_destroy_pixmap);
saa_wrap(sscreen, screen, ModifyPixmapHeader, saa_modify_pixmap_header);
saa_wrap(sscreen, screen, BitmapToRegion, saa_bitmap_to_region);
saa_unaccel_setup(screen);
#ifdef RENDER
saa_render_setup(screen);
#endif
return TRUE;
}
Bool
saa_resources_init(ScreenPtr screen)
{
/* if (!saa_glyphs_init(screen))
return FALSE;
*/
return TRUE;
}

192
saa/saa.h Normal file
View File

@@ -0,0 +1,192 @@
/*
*
* Copyright (C) 2000 Keith Packard
* 2004 Eric Anholt
* 2005 Zack Rusin
*
* Copyright 2011 VMWare, Inc. All rights reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of copyright holders not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Copyright holders make no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Author: Based on "exa.h"
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifndef _SAA_H_
#define _SAA_H_
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#else
#include <xorg-server.h>
#endif
#include <xf86.h>
#include <damage.h>
#define SAA_VERSION_MAJOR 0
#define SAA_VERSION_MINOR 1
#define SAA_ACCESS_R (1 << 0)
#define SAA_ACCESS_W (1 << 1)
#define SAA_ACCESS_RW (SAA_ACCESS_R | SAA_ACCESS_W)
#define SAA_PIXMAP_HINT_CREATE_HW (1 << 25)
#define SAA_PIXMAP_PREFER_SHADOW (1 << 0)
typedef unsigned int saa_access_t;
enum saa_pixmap_loc {
saa_loc_driver,
saa_loc_override,
};
struct saa_pixmap {
PixmapPtr pixmap;
int read_access;
int write_access;
unsigned int mapped_access;
Bool fallback_created;
RegionRec dirty_shadow;
RegionRec dirty_hw;
RegionRec shadow_damage;
DamagePtr damage;
void *addr;
void *override;
enum saa_pixmap_loc auth_loc;
uint32_t pad[16];
};
struct saa_driver {
unsigned int saa_major;
unsigned int saa_minor;
size_t pixmap_size;
Bool(*damage) (struct saa_driver * driver, PixmapPtr pixmap,
Bool hw, RegionPtr damage);
void (*operation_complete) (struct saa_driver * driver, PixmapPtr pixmap);
Bool(*download_from_hw) (struct saa_driver * driver, PixmapPtr pixmap,
RegionPtr readback);
void (*release_from_cpu) (struct saa_driver * driver, PixmapPtr pixmap,
saa_access_t access);
void *(*sync_for_cpu) (struct saa_driver * driver, PixmapPtr pixmap,
saa_access_t access);
void *(*map) (struct saa_driver * driver, PixmapPtr pixmap,
saa_access_t access);
void (*unmap) (struct saa_driver * driver, PixmapPtr pixmap,
saa_access_t access);
Bool(*create_pixmap) (struct saa_driver * driver, struct saa_pixmap * spix,
int w, int h, int depth, unsigned int usage_hint,
int bpp, int *new_pitch);
void (*destroy_pixmap) (struct saa_driver * driver, PixmapPtr pixmap);
Bool(*modify_pixmap_header) (PixmapPtr pixmap, int w, int h, int depth,
int bpp, int devkind, void *pPixData);
Bool(*copy_prepare) (struct saa_driver * driver, PixmapPtr src_pixmap,
PixmapPtr dst_pixmap, int dx, int dy, int alu,
RegionPtr scr_reg, uint32_t plane_mask);
void (*copy) (struct saa_driver * driver, int src_x, int src_y, int dst_x,
int dst_y, int w, int h);
void (*copy_done) (struct saa_driver * driver);
void (*takedown) (struct saa_driver * driver);
uint32_t pad[16];
};
extern _X_EXPORT PixmapPtr
saa_get_drawable_pixmap(DrawablePtr pDrawable);
extern _X_EXPORT void
saa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
int *xp, int *yp);
extern _X_EXPORT PixmapPtr
saa_get_pixmap(DrawablePtr drawable, int *xp, int *yp);
extern _X_EXPORT Bool
saa_prepare_access_pixmap(PixmapPtr pix, saa_access_t access,
RegionPtr read_reg);
extern _X_EXPORT Bool
saa_pad_read(DrawablePtr draw);
Bool
saa_pad_read_box(DrawablePtr draw, int x, int y, int w, int h);
extern _X_EXPORT Bool
saa_pad_write(DrawablePtr draw, GCPtr pGC, Bool check_read,
saa_access_t * access);
extern _X_EXPORT void
saa_finish_access_pixmap(PixmapPtr pix, saa_access_t access);
extern _X_EXPORT void
saa_fad_read(DrawablePtr draw);
extern _X_EXPORT void
saa_fad_write(DrawablePtr draw, saa_access_t access);
extern _X_EXPORT Bool
saa_resources_init(ScreenPtr screen);
extern _X_EXPORT void
saa_driver_fini(ScreenPtr pScreen);
extern _X_EXPORT int
saa_create_gc(GCPtr pGC);
extern _X_EXPORT RegionPtr
saa_bitmap_to_region(PixmapPtr pPix);
extern _X_EXPORT Bool
saa_close_screen(int i, ScreenPtr pScreen);
extern _X_EXPORT Bool
saa_gc_reads_destination(DrawablePtr pDrawable, GCPtr pGC);
extern _X_EXPORT Bool
saa_op_reads_destination(CARD8 op);
extern _X_EXPORT void
saa_set_fallback_debug(ScreenPtr screen, Bool enable);
extern _X_EXPORT
struct saa_pixmap *saa_get_saa_pixmap(PixmapPtr pPixmap);
extern _X_EXPORT Bool
saa_add_damage(PixmapPtr pixmap);
extern _X_EXPORT struct saa_driver *
saa_get_driver(ScreenPtr pScreen);
extern _X_EXPORT Bool
saa_driver_init(ScreenPtr screen, struct saa_driver *saa_driver);
extern _X_EXPORT void
saa_pixmap_dirty(PixmapPtr pixmap, Bool hw, RegionPtr reg);
extern _X_EXPORT void
saa_drawable_dirty(DrawablePtr draw, Bool hw, RegionPtr reg);
#define SAA_PM_IS_SOLID(_pDrawable, _pm) \
(((_pm) & FbFullMask((_pDrawable)->depth)) == \
FbFullMask((_pDrawable)->depth))
#endif

141
saa/saa_accel.c Normal file
View File

@@ -0,0 +1,141 @@
/*
* Copyright © 2001 Keith Packard
* Copyright 2011 VMWare, Inc. All Rights Reserved.
* May partly be based on code that is Copyright © The XFree86 Project Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Eric Anholt <eric@anholt.net>
* Author: Michel Dänzer <michel@tungstengraphics.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "saa.h"
#include "saa_priv.h"
Bool
saa_hw_copy_nton(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox, int dx, int dy, Bool reverse, Bool upsidedown)
{
ScreenPtr pScreen = pDstDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pDstDrawable->pScreen);
struct saa_driver *driver = sscreen->driver;
PixmapPtr pSrcPixmap, pDstPixmap;
struct saa_pixmap *src_spix, *dst_spix;
int src_off_x, src_off_y;
int dst_off_x, dst_off_y;
RegionRec dst_reg, *src_reg;
int ordering;
Bool ret = TRUE;
(void)pScreen;
/* avoid doing copy operations if no boxes */
if (nbox == 0)
return TRUE;
pSrcPixmap = saa_get_pixmap(pSrcDrawable, &src_off_x, &src_off_y);
pDstPixmap = saa_get_pixmap(pDstDrawable, &dst_off_x, &dst_off_y);
src_spix = saa_pixmap(pSrcPixmap);
dst_spix = saa_pixmap(pDstPixmap);
ordering = (nbox == 1 || (dx > 0 && dy > 0) ||
(pDstDrawable != pSrcDrawable &&
(pDstDrawable->type != DRAWABLE_WINDOW ||
pSrcDrawable->type != DRAWABLE_WINDOW))) ?
CT_YXBANDED : CT_UNSORTED;
src_reg = saa_boxes_to_region(pScreen, nbox, pbox, ordering);
if (!src_reg)
return FALSE;
REGION_NULL(pScreen, &dst_reg);
REGION_COPY(pScreen, &dst_reg, src_reg);
REGION_TRANSLATE(pScreen, src_reg, dx + src_off_x, dy + src_off_y);
REGION_TRANSLATE(pScreen, &dst_reg, dst_off_x, dst_off_y);
if (!(driver->copy_prepare) (driver, pSrcPixmap, pDstPixmap,
reverse ? -1 : 1,
upsidedown ? -1 : 1,
pGC ? pGC->alu : GXcopy,
src_reg, pGC ? pGC->planemask : FB_ALLONES)) {
goto fallback;
}
while (nbox--) {
(driver->copy) (driver,
pbox->x1 + dx + src_off_x,
pbox->y1 + dy + src_off_y,
pbox->x1 + dst_off_x, pbox->y1 + dst_off_y,
pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
pbox++;
}
(driver->copy_done) (driver);
saa_pixmap_dirty(pDstPixmap, TRUE, &dst_reg);
goto out;
fallback:
ret = FALSE;
out:
REGION_UNINIT(pScreen, &dst_reg);
REGION_DESTROY(pScreen, src_reg);
return ret;
}
static void
saa_copy_nton(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
{
if (saa_hw_copy_nton(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
reverse, upsidedown))
return;
saa_check_copy_nton(pSrcDrawable, pDstDrawable, pGC, pbox, nbox, dx, dy,
reverse, upsidedown, bitplane, closure);
}
RegionPtr
saa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty)
{
struct saa_screen_priv *sscreen = saa_screen(pDstDrawable->pScreen);
if (sscreen->fallback_count) {
return saa_check_copy_area(pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height, dstx, dsty);
}
return miDoCopy(pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, saa_copy_nton, 0, NULL);
}

222
saa/saa_pixmap.c Normal file
View File

@@ -0,0 +1,222 @@
/*
* Copyright © 2009 Maarten Maathuis
* Copyright 2011 VMWare, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Based on "exa_driver.c"
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "saa_priv.h"
#include "saa.h"
PixmapPtr
saa_create_pixmap(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint)
{
PixmapPtr pPixmap;
struct saa_pixmap *spix;
int bpp;
size_t paddedWidth;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
int new_pitch = 0;
struct saa_driver *driver = sscreen->driver;
if (w > 32767 || h > 32767)
return NullPixmap;
/*
* Create a scratch pixmap without backing storage (w and h are zero)
*/
saa_swap(sscreen, pScreen, CreatePixmap);
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
saa_swap(sscreen, pScreen, CreatePixmap);
if (!pPixmap)
goto out_no_pix;
spix = saa_pixmap(pPixmap);
memset(spix, 0, driver->pixmap_size);
REGION_NULL(pScreen, &spix->dirty_shadow);
REGION_NULL(pScreen, &spix->dirty_hw);
REGION_NULL(pScreen, &spix->shadow_damage);
spix->read_access = 0;
spix->write_access = 0;
spix->mapped_access = 0;
spix->addr = NULL;
spix->auth_loc = saa_loc_override;
spix->override = SAA_INVALID_ADDRESS;
spix->pixmap = pPixmap;
bpp = pPixmap->drawable.bitsPerPixel;
if (!driver->create_pixmap(driver, spix, w, h, depth,
usage_hint, bpp, &new_pitch))
goto out_no_driver_priv;
paddedWidth = new_pitch;
spix->damage = NULL;
/*
* Now set w and h to the correct value. This might allocate
* backing store if w and h are NON-NULL.
*/
if (!(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0,
paddedWidth, NULL))
goto out_no_pixmap_header;
/*
* During a fallback we must prepare access. This hack is initially used
* for pixmaps created during ValidateGC.
*/
spix->fallback_created = FALSE;
if (sscreen->fallback_count) {
if (!saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL))
goto out_no_access;
spix->fallback_created = TRUE;
}
return pPixmap;
out_no_access:
out_no_pixmap_header:
driver->destroy_pixmap(driver, pPixmap);
out_no_driver_priv:
saa_swap(sscreen, pScreen, DestroyPixmap);
pScreen->DestroyPixmap(pPixmap);
saa_swap(sscreen, pScreen, DestroyPixmap);
out_no_pix:
LogMessage(X_ERROR, "Failing pixmap creation.\n");
return NullPixmap;
}
Bool
saa_destroy_pixmap(PixmapPtr pPixmap)
{
ScreenPtr pScreen = pPixmap->drawable.pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
Bool ret;
struct saa_driver *driver = sscreen->driver;
if (pPixmap->refcnt == 1) {
struct saa_pixmap *spix = saa_pixmap(pPixmap);
if (spix->fallback_created) {
if (!sscreen->fallback_count)
LogMessage(X_ERROR, "Fallback pixmap destroyed outside "
"fallback.\n");
saa_finish_access_pixmap(pPixmap, SAA_ACCESS_W);
}
driver->destroy_pixmap(driver, pPixmap);
REGION_UNINIT(pScreen, &spix->dirty_hw);
REGION_UNINIT(pScreen, &spix->dirty_shadow);
spix->damage = NULL;
}
saa_swap(sscreen, pScreen, DestroyPixmap);
ret = pScreen->DestroyPixmap(pPixmap);
saa_swap(sscreen, pScreen, DestroyPixmap);
return ret;
}
Bool
saa_modify_pixmap_header(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, pointer pPixData)
{
ScreenPtr pScreen;
struct saa_screen_priv *sscreen;
struct saa_pixmap *spix;
struct saa_driver *driver;
Bool ret = TRUE;
if (!pPixmap)
return FALSE;
pScreen = pPixmap->drawable.pScreen;
sscreen = saa_screen(pScreen);
spix = saa_pixmap(pPixmap);
driver = sscreen->driver;
if (spix && driver->modify_pixmap_header &&
driver->modify_pixmap_header(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData)) {
spix->auth_loc = saa_loc_driver;
spix->override = SAA_INVALID_ADDRESS;
goto out;
}
saa_swap(sscreen, pScreen, ModifyPixmapHeader);
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
bitsPerPixel, devKind, pPixData);
saa_swap(sscreen, pScreen, ModifyPixmapHeader);
spix->override = pPixmap->devPrivate.ptr;
spix->auth_loc = saa_loc_override;
out:
pPixmap->devPrivate.ptr = NULL;
return ret;
}
struct saa_pixmap *
saa_get_saa_pixmap(PixmapPtr pPixmap)
{
return saa_pixmap(pPixmap);
}
void
saa_pixmap_dirty(PixmapPtr pixmap, Bool hw, RegionPtr reg)
{
struct saa_pixmap *spix = saa_pixmap(pixmap);
struct saa_screen_priv *sscreen = saa_screen(pixmap->drawable.pScreen);
if (hw) {
REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_hw,
&spix->dirty_hw, reg);
REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_shadow,
&spix->dirty_shadow, reg);
} else {
REGION_UNION(pixmap->drawable.pScreen, &spix->dirty_shadow,
&spix->dirty_shadow, reg);
REGION_SUBTRACT(pixmap->drawable.pScreen, &spix->dirty_hw,
&spix->dirty_hw, reg);
}
sscreen->driver->damage(sscreen->driver, pixmap, hw, reg);
}
void
saa_drawable_dirty(DrawablePtr draw, Bool hw, RegionPtr reg)
{
PixmapPtr pixmap;
int x_offset, y_offset;
pixmap = saa_get_pixmap(draw, &x_offset, &y_offset);
REGION_TRANSLATE(draw->pScreen, reg, x_offset, y_offset);
saa_pixmap_dirty(pixmap, hw, reg);
REGION_TRANSLATE(draw->pScreen, reg, -x_offset, -y_offset);
}

263
saa/saa_priv.h Normal file
View File

@@ -0,0 +1,263 @@
/*
*
* Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
* 2005 Zack Rusin, Trolltech
* Copyright 2011 VMWare, inc. All rights reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Authors: Based on exa_priv.h
* Authors: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifndef _SAA_PRIV_H
#define _SAA_PRIV_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#else
#include <xorg-server.h>
#endif
#include "xf86.h"
#include "saa.h"
#include <X11/X.h>
#include <X11/Xproto.h>
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "windowstr.h"
#include "servermd.h"
#include "mibstore.h"
#include "colormapst.h"
#include "gcstruct.h"
#include "input.h"
#include "mipointer.h"
#include "mi.h"
#include "dix.h"
#include "fb.h"
#include "fboverlay.h"
#ifdef RENDER
#include "glyphstr.h"
#endif
#include "damage.h"
#define SAA_INVALID_ADDRESS \
((void *) ((unsigned long) 0xFFFFFFFF - 1024*1024))
struct saa_gc_priv {
/* GC values from the layer below. */
GCOps *saved_ops;
GCFuncs *saved_funcs;
};
struct saa_screen_priv {
struct saa_driver *driver;
CreateGCProcPtr saved_CreateGC;
CloseScreenProcPtr saved_CloseScreen;
GetImageProcPtr saved_GetImage;
GetSpansProcPtr saved_GetSpans;
CreatePixmapProcPtr saved_CreatePixmap;
DestroyPixmapProcPtr saved_DestroyPixmap;
CopyWindowProcPtr saved_CopyWindow;
ChangeWindowAttributesProcPtr saved_ChangeWindowAttributes;
BitmapToRegionProcPtr saved_BitmapToRegion;
ModifyPixmapHeaderProcPtr saved_ModifyPixmapHeader;
#ifdef RENDER
CompositeProcPtr saved_Composite;
CompositeRectsProcPtr saved_CompositeRects;
TrianglesProcPtr saved_Triangles;
GlyphsProcPtr saved_Glyphs;
TrapezoidsProcPtr saved_Trapezoids;
AddTrapsProcPtr saved_AddTraps;
UnrealizeGlyphProcPtr saved_UnrealizeGlyph;
SourceValidateProcPtr saved_SourceValidate;
#endif
Bool fallback_debug;
unsigned int fallback_count;
RegionRec srcReg;
RegionRec maskReg;
PixmapPtr srcPix;
};
extern GCOps saa_gc_ops;
#if DEBUG_TRACE_FALL
#define SAA_FALLBACK(x) \
do { \
ErrorF("SAA fallback at %s: ", __FUNCTION__); \
ErrorF x; \
} while (0)
#define saa_drawable_location() ("u")
#else
#define SAA_FALLBACK(x)
#endif
/*
* Some macros to deal with function wrapping.
*/
#define saa_wrap(priv, real, mem, func) {\
(priv)->saved_##mem = (real)->mem; \
(real)->mem = func; \
}
#define saa_unwrap(priv, real, mem) {\
(real)->mem = (priv)->saved_##mem; \
}
#define saa_swap(priv, real, mem) {\
void *tmp = (priv)->saved_##mem; \
(priv)->saved_##mem = (real)->mem; \
(real)->mem = tmp; \
}
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 8)
#define SAA_DEVPRIVATEKEYREC 1
extern DevPrivateKeyRec saa_screen_index;
extern DevPrivateKeyRec saa_pixmap_index;
extern DevPrivateKeyRec saa_gc_index;
static inline struct saa_screen_priv *
saa_screen(ScreenPtr screen)
{
return (struct saa_screen_priv *)dixGetPrivate(&screen->devPrivates,
&saa_screen_index);
}
static inline struct saa_gc_priv *
saa_gc(GCPtr gc)
{
return (struct saa_gc_priv *)dixGetPrivateAddr(&gc->devPrivates,
&saa_gc_index);
}
static inline struct saa_pixmap *
saa_pixmap(PixmapPtr pix)
{
return (struct saa_pixmap *)dixGetPrivateAddr(&pix->devPrivates,
&saa_pixmap_index);
}
#else
#undef SAA_DEVPRIVATEKEYREC
extern int saa_screen_index;
extern int saa_pixmap_index;
extern int saa_gc_index;
static inline struct saa_screen_priv *
saa_screen(ScreenPtr screen)
{
return (struct saa_screen_priv *)dixLookupPrivate(&screen->devPrivates,
&saa_screen_index);
}
static inline struct saa_gc_priv *
saa_gc(GCPtr gc)
{
return (struct saa_gc_priv *)dixLookupPrivateAddr(&gc->devPrivates,
&saa_gc_index);
}
static inline struct saa_pixmap_priv *
saa_pixmap(PixmapPtr pix)
{
return (struct saa_pixmap_priv *)dixLookupPrivateAddr(&pix->devPrivates,
&saa_pixmap_index);
}
#endif
extern void
saa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted);
extern void
saa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle * prect);
extern RegionPtr
saa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty);
extern void
saa_check_copy_nton(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure);
extern void
saa_unaccel_setup(ScreenPtr pScreen);
extern void
saa_unaccel_takedown(ScreenPtr pScreen);
extern RegionPtr
saa_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty);
extern Bool
saa_hw_copy_nton(DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
#ifdef RENDER
extern void
saa_render_setup(ScreenPtr pScreen);
extern void
saa_render_takedown(ScreenPtr pScreen);
extern void
saa_check_composite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
#endif
extern Bool
saa_modify_pixmap_header(PixmapPtr pPixmap, int width, int height, int depth,
int bitsPerPixel, int devKind, pointer pPixData);
extern PixmapPtr
saa_create_pixmap(ScreenPtr pScreen, int w, int h, int depth,
unsigned usage_hint);
extern Bool
saa_destroy_pixmap(PixmapPtr pPixmap);
static inline RegionPtr
saa_pix_damage_pending(struct saa_pixmap *spix)
{
return (spix->damage ? DamagePendingRegion(spix->damage) : NULL);
}
extern RegionPtr
saa_boxes_to_region(ScreenPtr pScreen, int nbox, BoxPtr pbox, int ordering);
#endif

313
saa/saa_render.c Normal file
View File

@@ -0,0 +1,313 @@
/*
* Copyright © 2001 Keith Packard
* Copyright 2011 VMWare, Inc. All Rights Reserved.
* May partly be based on code that is Copyright © The XFree86 Project Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Eric Anholt <eric@anholt.net>
* Author: Michel Dänzer <michel@tungstengraphics.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "saa.h"
#include "saa_priv.h"
#ifdef RENDER
#include <mipict.h>
/**
* Same as miCreateAlphaPicture, except it uses
* saa_check_poly_fill_rect instead
*/
static PicturePtr
saa_create_alpha_picture(ScreenPtr pScreen,
PicturePtr pDst,
PictFormatPtr pPictFormat, CARD16 width, CARD16 height)
{
PixmapPtr pPixmap;
PicturePtr pPicture;
GCPtr pGC;
int error;
xRectangle rect;
if (width > 32767 || height > 32767)
return 0;
if (!pPictFormat) {
if (pDst->polyEdge == PolyEdgeSharp)
pPictFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
else
pPictFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
if (!pPictFormat)
return 0;
}
pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
pPictFormat->depth, 0);
if (!pPixmap)
return 0;
pGC = GetScratchGC(pPixmap->drawable.depth, pScreen);
if (!pGC) {
(*pScreen->DestroyPixmap) (pPixmap);
return 0;
}
ValidateGC(&pPixmap->drawable, pGC);
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
saa_check_poly_fill_rect(&pPixmap->drawable, pGC, 1, &rect);
FreeScratchGC(pGC);
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
0, 0, serverClient, &error);
(*pScreen->DestroyPixmap) (pPixmap);
return pPicture;
}
/**
* saa_trapezoids is essentially a copy of miTrapezoids that uses
* saa_create_alpha_picture instead of miCreateAlphaPicture.
*
* The problem with miCreateAlphaPicture is that it calls PolyFillRect
* to initialize the contents after creating the pixmap, which
* causes the pixmap to be moved in for acceleration. The subsequent
* call to RasterizeTrapezoid won't be accelerated however, which
* forces the pixmap to be moved out again.
*
*/
static void
saa_trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntrap, xTrapezoid * traps)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
BoxRec bounds;
if (maskFormat) {
PicturePtr pPicture;
INT16 xDst, yDst;
INT16 xRel, yRel;
saa_access_t access;
miTrapezoidBounds(ntrap, traps, &bounds);
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
return;
xDst = traps[0].left.p1.x >> 16;
yDst = traps[0].left.p1.y >> 16;
pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
if (!pPicture)
return;
if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) {
for (; ntrap; ntrap--, traps++)
(*ps->RasterizeTrapezoid) (pPicture, traps,
-bounds.x1, -bounds.y1);
saa_fad_write(pPicture->pDrawable, access);
}
xRel = bounds.x1 + xSrc - xDst;
yRel = bounds.y1 + ySrc - yDst;
CompositePicture(op, pSrc, pPicture, pDst,
xRel, yRel, 0, 0, bounds.x1, bounds.y1,
bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
FreePicture(pPicture, 0);
} else {
if (pDst->polyEdge == PolyEdgeSharp)
maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
else
maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
for (; ntrap; ntrap--, traps++)
saa_trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, traps);
}
}
/**
* saa_triangles is essentially a copy of miTriangles that uses
* saa_create_alpha_picture instead of miCreateAlphaPicture.
*
* The problem with miCreateAlphaPicture is that it calls PolyFillRect
* to initialize the contents after creating the pixmap, which
* causes the pixmap to be moved in for acceleration. The subsequent
* call to AddTriangles won't be accelerated however, which forces the pixmap
* to be moved out again.
*/
static void
saa_triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
int ntri, xTriangle * tris)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
BoxRec bounds;
if (maskFormat) {
PicturePtr pPicture;
INT16 xDst, yDst;
INT16 xRel, yRel;
saa_access_t access;
miTriangleBounds(ntri, tris, &bounds);
if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2)
return;
xDst = tris[0].p1.x >> 16;
yDst = tris[0].p1.y >> 16;
pPicture = saa_create_alpha_picture(pScreen, pDst, maskFormat,
bounds.x2 - bounds.x1,
bounds.y2 - bounds.y1);
if (!pPicture)
return;
if (saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access)) {
(*ps->AddTriangles) (pPicture, -bounds.x1, -bounds.y1, ntri, tris);
saa_fad_write(pPicture->pDrawable, access);
}
xRel = bounds.x1 + xSrc - xDst;
yRel = bounds.y1 + ySrc - yDst;
CompositePicture(op, pSrc, pPicture, pDst,
xRel, yRel, 0, 0, bounds.x1, bounds.y1,
bounds.x2 - bounds.x1, bounds.y2 - bounds.y1);
FreePicture(pPicture, 0);
} else {
if (pDst->polyEdge == PolyEdgeSharp)
maskFormat = PictureMatchFormat(pScreen, 1, PICT_a1);
else
maskFormat = PictureMatchFormat(pScreen, 8, PICT_a8);
for (; ntri; ntri--, tris++)
saa_triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, 1, tris);
}
}
/*
* Try to turn a composite operation into an accelerated copy.
* We can do that in some special cases for PictOpSrc and PictOpOver.
*/
static Bool
saa_copy_composite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
if (!pSrc->pDrawable || pSrc->transform ||
pSrc->repeat || xSrc < 0 || ySrc < 0 ||
xSrc + width > pSrc->pDrawable->width ||
ySrc + height > pSrc->pDrawable->height)
return FALSE;
if ((op == PictOpSrc &&
(pSrc->format == pDst->format ||
(PICT_FORMAT_COLOR(pDst->format) &&
PICT_FORMAT_COLOR(pSrc->format) &&
pDst->format == PICT_FORMAT(PICT_FORMAT_BPP(pSrc->format),
PICT_FORMAT_TYPE(pSrc->format),
0,
PICT_FORMAT_R(pSrc->format),
PICT_FORMAT_G(pSrc->format),
PICT_FORMAT_B(pSrc->format))))) ||
(op == PictOpOver && pSrc->format == pDst->format &&
!PICT_FORMAT_A(pSrc->format))) {
Bool ret;
RegionRec region;
REGION_NULL(pDst->pDrawable.pScreen, &region);
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
if (!miComputeCompositeRegion(&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst,
yDst, width, height)) {
return TRUE;
}
ret = saa_hw_copy_nton(pSrc->pDrawable, pDst->pDrawable, NULL,
RegionRects(&region),
RegionNumRects(&region),
xSrc - xDst, ySrc - yDst, FALSE, FALSE);
RegionUninit(&region);
if (ret)
return TRUE;
}
return FALSE;
}
static void
saa_composite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
if (!saa_copy_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height))
saa_check_composite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
}
void
saa_render_setup(ScreenPtr pScreen)
{
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
struct saa_screen_priv *sscreen = saa_screen(pScreen);
if (ps) {
saa_wrap(sscreen, ps, Trapezoids, saa_trapezoids);
saa_wrap(sscreen, ps, Triangles, saa_triangles);
saa_wrap(sscreen, ps, Composite, saa_composite);
}
}
void
saa_render_takedown(ScreenPtr pScreen)
{
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
struct saa_screen_priv *sscreen = saa_screen(pScreen);
if (ps) {
saa_unwrap(sscreen, ps, Trapezoids);
saa_unwrap(sscreen, ps, Triangles);
saa_unwrap(sscreen, ps, Composite);
}
}
#endif

896
saa/saa_unaccel.c Normal file
View File

@@ -0,0 +1,896 @@
/*
* Copyright © 1999 Keith Packard
* Copyright 2011 VMWare, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Based on "exa_unaccel.c"
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "saa_priv.h"
#include "saa.h"
#include "mipict.h"
/**
* Calls saa_prepare_access with SAA_ACCESS_R for the tile, if that is the
* current fill style.
*
* Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
* 1bpp and never in fb, so we don't worry about them.
* We should worry about them for completeness sake and going forward.
*/
static Bool
saa_prepare_access_gc(GCPtr pGC)
{
if (pGC->stipple)
if (!saa_pad_read(&pGC->stipple->drawable))
return FALSE;
if (pGC->fillStyle == FillTiled)
if (!saa_pad_read(&pGC->tile.pixmap->drawable)) {
if (pGC->stipple)
saa_fad_read(&pGC->stipple->drawable);
return FALSE;
}
return TRUE;
}
/**
* Finishes access to the tile in the GC, if used.
*/
static void
saa_finish_access_gc(GCPtr pGC)
{
if (pGC->fillStyle == FillTiled)
saa_fad_read(&pGC->tile.pixmap->drawable);
if (pGC->stipple)
saa_fad_read(&pGC->stipple->drawable);
}
void
saa_check_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_location(pDrawable)));
sscreen->fallback_count++;
if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
if (saa_prepare_access_gc(pGC)) {
saa_swap(sgc, pGC, ops);
pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
}
saa_fad_write(pDrawable, access);
}
sscreen->fallback_count--;
}
static void
saa_check_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
{
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (saa_pad_write(pDrawable, NULL, FALSE, &access)) {
saa_swap(sgc, pGC, ops);
pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
saa_swap(sgc, pGC, ops);
saa_fad_write(pDrawable, access);
}
sscreen->fallback_count--;
}
static void
saa_check_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth,
int x, int y, int w, int h, int leftPad, int format,
char *bits)
{
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (saa_pad_write(pDrawable, pGC, TRUE, &access)) {
saa_swap(sgc, pGC, ops);
pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad,
format, bits);
saa_swap(sgc, pGC, ops);
saa_fad_write(pDrawable, access);
}
sscreen->fallback_count--;
}
RegionPtr
saa_boxes_to_region(ScreenPtr pScreen, int nbox, BoxPtr pbox, int ordering)
{
xRectangle *rects = malloc(nbox * sizeof(*rects));
int i;
RegionPtr reg;
if (!rects)
return NULL;
for (i = 0; i < nbox; i++) {
rects[i].x = pbox[i].x1;
rects[i].y = pbox[i].y1;
rects[i].width = pbox[i].x2 - pbox[i].x1;
rects[i].height = pbox[i].y2 - pbox[i].y1;
}
reg = RECTS_TO_REGION(pScreen, nbox, rects, ordering);
free(rects);
return reg;
}
void
saa_check_copy_nton(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
Bool upsidedown, Pixel bitplane, void *closure)
{
ScreenPtr pScreen = pSrc->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
RegionPtr reg, readback;
int src_xoff, src_yoff, dst_xoff, dst_yoff;
struct saa_gc_priv *sgc = saa_gc(pGC);
PixmapPtr src_pixmap;
PixmapPtr dst_pixmap;
saa_access_t access = SAA_ACCESS_R;
int ordering;
sscreen->fallback_count++;
SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
src_pixmap = saa_get_pixmap(pSrc, &src_xoff, &src_yoff);
dst_pixmap = saa_get_pixmap(pDst, &dst_xoff, &dst_yoff);
ordering = (nbox == 1 || (dx > 0 && dy > 0) ||
(pDst != pSrc &&
(pDst->type != DRAWABLE_WINDOW ||
pSrc->type != DRAWABLE_WINDOW))) ? CT_YXBANDED : CT_UNSORTED;
reg = saa_boxes_to_region(pScreen, nbox, pbox, ordering);
if (!reg)
return;
REGION_TRANSLATE(pScreen, reg, src_xoff + dx, src_yoff + dy);
if (!saa_prepare_access_pixmap(src_pixmap, SAA_ACCESS_R, reg))
goto out_no_access;
REGION_TRANSLATE(pScreen, reg, dst_xoff - dx - src_xoff,
dst_yoff - dy - src_yoff);
if (saa_gc_reads_destination(pDst, pGC)) {
readback = reg;
access = SAA_ACCESS_RW;
} else {
readback = NULL;
access = SAA_ACCESS_W;
}
if (!saa_prepare_access_pixmap(dst_pixmap, access, readback))
goto out_no_dst;
saa_swap(sgc, pGC, ops);
while (nbox--) {
pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
pbox->y1 - pSrc->y + dy,
pbox->x2 - pbox->x1, pbox->y2 - pbox->y1,
pbox->x1 - pDst->x, pbox->y1 - pDst->y);
pbox++;
}
saa_swap(sgc, pGC, ops);
saa_finish_access_pixmap(dst_pixmap, access);
saa_pixmap_dirty(dst_pixmap, FALSE, reg);
out_no_dst:
saa_fad_read(pSrc);
out_no_access:
sscreen->fallback_count--;
REGION_DESTROY(pScreen, reg);
}
RegionPtr
saa_check_copy_area(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty)
{
RegionPtr ret = NULL;
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
sscreen->fallback_count++;
if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
goto out_no_access;
if (!saa_pad_write(pDst, pGC, TRUE, &access))
goto out_no_dst;
saa_swap(sgc, pGC, ops);
ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
saa_swap(sgc, pGC, ops);
saa_fad_write(pDst, access);
out_no_dst:
saa_fad_read(pSrc);
out_no_access:
sscreen->fallback_count--;
return ret;
}
static RegionPtr
saa_check_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
int srcx, int srcy, int w, int h, int dstx, int dsty,
unsigned long bitplane)
{
RegionPtr ret = NULL;
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
saa_drawable_loc(pSrc), saa_drawable_loc(pDst)));
sscreen->fallback_count++;
if (!saa_pad_read_box(pSrc, srcx, srcy, w, h))
goto out_no_src;
if (!saa_pad_write(pDst, pGC, TRUE, &access))
goto out_no_dst;
saa_swap(sgc, pGC, ops);
ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
bitplane);
saa_swap(sgc, pGC, ops);
saa_fad_write(pDst, access);
out_no_dst:
saa_fad_read(pSrc);
out_no_src:
sscreen->fallback_count--;
return ret;
}
static void
saa_check_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
DDXPointPtr pptInit)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
sscreen->fallback_count++;
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;
saa_swap(sgc, pGC, ops);
pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
saa_swap(sgc, pGC, ops);
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_poly_lines(DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
pDrawable, saa_drawable_loc(pDrawable),
pGC->lineWidth, mode, npt));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_poly_segment(DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment * pSegInit)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
saa_drawable_loc(pDrawable), pGC->lineWidth, nsegInit));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_poly_arc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
void
saa_check_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC,
int nrect, xRectangle * prect)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, pGC, TRUE, &access))
goto out_no_access;;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, pointer pglyphBase)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC,
int x, int y, unsigned int nglyph,
CharInfoPtr * ppci, pointer pglyphBase)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
saa_drawable_loc(pDrawable), pGC->fillStyle, pGC->alu));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, NULL, FALSE, &access))
goto out_no_access;;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_push_pixels(GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable, int w, int h, int x, int y)
{
struct saa_gc_priv *sgc = saa_gc(pGC);
saa_access_t access;
struct saa_screen_priv *sscreen = saa_screen(pGC->pScreen);
SAA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
saa_drawable_loc(&pBitmap->drawable),
saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_write(pDrawable, pGC, TRUE, &access))
goto out_no_access;;
if (!saa_pad_read_box(&pBitmap->drawable, 0, 0, w, h))
goto out_no_src;
if (!saa_prepare_access_gc(pGC))
goto out_no_gc;
saa_swap(sgc, pGC, ops);
pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
saa_swap(sgc, pGC, ops);
saa_finish_access_gc(pGC);
out_no_gc:
saa_fad_read(&pBitmap->drawable);
out_no_src:
saa_fad_write(pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
DrawablePtr pDrawable = &pWin->drawable;
ScreenPtr pScreen = pDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
int xoff, yoff;
PixmapPtr pPixmap = saa_get_pixmap(&pWin->drawable, &xoff, &yoff);
Bool ret;
SAA_FALLBACK(("from %p\n", pWin));
/* Only need the source bits, the destination region will be overwritten */
sscreen->fallback_count++;
REGION_TRANSLATE(pScreen, prgnSrc, xoff, yoff);
ret = saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_R, prgnSrc);
REGION_TRANSLATE(pScreen, prgnSrc, -xoff, -yoff);
if (!ret)
goto out_no_access;;
if (saa_prepare_access_pixmap(pPixmap, SAA_ACCESS_W, NULL)) {
saa_swap(sscreen, pScreen, CopyWindow);
pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
saa_swap(sscreen, pScreen, CopyWindow);
saa_fad_write(pDrawable, SAA_ACCESS_W);
}
saa_fad_read(pDrawable);
out_no_access:
sscreen->fallback_count--;
}
#ifdef RENDER
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
static void
saa_src_validate(DrawablePtr pDrawable,
int x,
int y, int width, int height, unsigned int subWindowMode)
#else
static void
saa_src_validate(DrawablePtr pDrawable, int x, int y, int width, int height)
#endif
{
ScreenPtr pScreen = pDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
PixmapPtr pPix = saa_get_drawable_pixmap(pDrawable);
BoxRec box;
RegionRec reg;
RegionPtr dst;
int xoff, yoff;
saa_get_drawable_deltas(pDrawable, pPix, &xoff, &yoff);
box.x1 = x + xoff;
box.y1 = y + yoff;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
dst = (sscreen->srcPix == pPix) ? &sscreen->srcReg : &sscreen->maskReg;
REGION_INIT(pScreen, &reg, &box, 1);
REGION_UNION(pScreen, dst, dst, &reg);
REGION_UNINIT(pScreen, &reg);
if (sscreen->saved_SourceValidate) {
saa_swap(sscreen, pScreen, SourceValidate);
pScreen->SourceValidate(pDrawable, x, y, width, height
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10)
, subWindowMode
#endif
);
saa_swap(sscreen, pScreen, SourceValidate);
}
}
static void
saa_check_get_image(DrawablePtr pDrawable, int x, int y, int w, int h,
unsigned int format, unsigned long planeMask, char *d)
{
ScreenPtr pScreen = pDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_read_box(pDrawable, x, y, w, h))
goto out_no_access;;
saa_swap(sscreen, pScreen, GetImage);
pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
saa_swap(sscreen, pScreen, GetImage);
saa_fad_read(pDrawable);
out_no_access:
sscreen->fallback_count--;
}
static void
saa_check_get_spans(DrawablePtr pDrawable,
int wMax,
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
{
ScreenPtr pScreen = pDrawable->pScreen;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
SAA_FALLBACK(("from %p (%c)\n", pDrawable, saa_drawable_loc(pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_read(pDrawable))
goto out_no_access;;
saa_swap(sscreen, pScreen, GetSpans);
pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
saa_swap(sscreen, pScreen, GetSpans);
saa_fad_read(pDrawable);
out_no_access:
sscreen->fallback_count--;
}
static Bool
saa_prepare_composite_reg(ScreenPtr pScreen,
CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height,
RegionPtr region, saa_access_t * access)
{
RegionPtr dstReg = NULL;
RegionPtr srcReg = NULL;
RegionPtr maskReg = NULL;
PixmapPtr pSrcPix = NULL;
PixmapPtr pMaskPix = NULL;
PixmapPtr pDstPix;
struct saa_screen_priv *sscreen = saa_screen(pScreen);
struct saa_pixmap *dst_spix;
Bool ret;
*access = SAA_ACCESS_W;
if (pSrc->pDrawable) {
pSrcPix = saa_get_drawable_pixmap(pSrc->pDrawable);
REGION_NULL(pScreen, &sscreen->srcReg);
srcReg = &sscreen->srcReg;
sscreen->srcPix = pSrcPix;
if (pSrc != pDst)
REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
-pSrc->pDrawable->x, -pSrc->pDrawable->y);
}
if (pMask && pMask->pDrawable) {
pMaskPix = saa_get_drawable_pixmap(pMask->pDrawable);
REGION_NULL(pScreen, &sscreen->maskReg);
maskReg = &sscreen->maskReg;
if (pMask != pDst && pMask != pSrc)
REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
-pMask->pDrawable->x, -pMask->pDrawable->y);
}
REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
-pDst->pDrawable->x, -pDst->pDrawable->y);
sscreen->saved_SourceValidate = saa_src_validate;
saa_swap(sscreen, pScreen, SourceValidate);
ret = miComputeCompositeRegion(region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask,
xDst, yDst, width, height);
saa_swap(sscreen, pScreen, SourceValidate);
REGION_TRANSLATE(pScreen, pDst->pCompositeClip,
pDst->pDrawable->x, pDst->pDrawable->y);
if (pSrc->pDrawable && pSrc != pDst)
REGION_TRANSLATE(pScreen, pSrc->pCompositeClip,
pSrc->pDrawable->x, pSrc->pDrawable->y);
if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
REGION_TRANSLATE(pScreen, pMask->pCompositeClip,
pMask->pDrawable->x, pMask->pDrawable->y);
if (!ret) {
if (srcReg)
REGION_UNINIT(pScreen, srcReg);
if (maskReg)
REGION_UNINIT(pScreen, maskReg);
return FALSE;
}
/*
* Don't limit alphamaps readbacks for now until we've figured out how that
* should be done.
*/
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
if (!saa_pad_read(pSrc->alphaMap->pDrawable))
goto out_no_src_alpha;
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
if (!saa_pad_read(pMask->alphaMap->pDrawable))
goto out_no_mask_alpha;
if (pSrcPix)
if (!saa_prepare_access_pixmap(pSrcPix, SAA_ACCESS_R, srcReg))
goto out_no_src;
if (pMaskPix)
if (!saa_prepare_access_pixmap(pMaskPix, SAA_ACCESS_R, maskReg))
goto out_no_mask;
if (srcReg)
REGION_UNINIT(pScreen, srcReg);
if (maskReg)
REGION_UNINIT(pScreen, maskReg);
pDstPix = saa_get_drawable_pixmap(pDst->pDrawable);
dst_spix = saa_get_saa_pixmap(pDstPix);
if (dst_spix->damage) {
int xoff, yoff;
saa_get_drawable_deltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
REGION_TRANSLATE(pScreen, region, pDst->pDrawable->x + xoff,
pDst->pDrawable->y + yoff);
if (saa_op_reads_destination(op)) {
dstReg = region;
*access |= SAA_ACCESS_R;
}
}
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
if (!saa_prepare_access_pixmap
(saa_get_drawable_pixmap(pDst->alphaMap->pDrawable),
*access, dstReg))
goto out_no_dst_alpha;
if (!saa_prepare_access_pixmap(pDstPix, *access, dstReg))
goto out_no_dst;
return TRUE;
out_no_dst:
LogMessage(X_ERROR, "No dst\n");
saa_finish_access_pixmap
(saa_get_drawable_pixmap(pDst->alphaMap->pDrawable), *access);
out_no_dst_alpha:
LogMessage(X_ERROR, "No dst alpha\n");
if (pMaskPix)
saa_finish_access_pixmap(pMaskPix, SAA_ACCESS_R);
out_no_mask:
LogMessage(X_ERROR, "No mask\n");
if (pSrcPix)
saa_finish_access_pixmap(pSrcPix, SAA_ACCESS_R);
out_no_src:
LogMessage(X_ERROR, "No src\n");
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
saa_fad_read(pMask->alphaMap->pDrawable);
out_no_mask_alpha:
LogMessage(X_ERROR, "No mask alpha\n");
if (pSrc && pSrc->alphaMap && pSrc->alphaMap->pDrawable)
saa_fad_read(pSrc->alphaMap->pDrawable);
out_no_src_alpha:
LogMessage(X_ERROR, "No src alpha\n");
if (srcReg)
REGION_UNINIT(pScreen, srcReg);
if (maskReg)
REGION_UNINIT(pScreen, maskReg);
return FALSE;
}
void
saa_check_composite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
ScreenPtr pScreen = pDst->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
struct saa_screen_priv *sscreen = saa_screen(pScreen);
saa_access_t access;
RegionRec reg;
PixmapPtr pixmap;
sscreen->fallback_count++;
REGION_NULL(pScreen, &reg);
if (!saa_prepare_composite_reg(pScreen, op, pSrc, pMask, pDst, xSrc,
ySrc, xMask, yMask, xDst, yDst, width,
height, &reg, &access)) {
goto out_no_access;;
}
saa_swap(sscreen, ps, Composite);
ps->Composite(op,
pSrc,
pMask,
pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
saa_swap(sscreen, ps, Composite);
if (pMask && pMask->pDrawable != NULL)
saa_fad_read(pMask->pDrawable);
if (pSrc->pDrawable != NULL)
saa_fad_read(pSrc->pDrawable);
pixmap = saa_get_drawable_pixmap(pDst->pDrawable);
saa_finish_access_pixmap(pixmap, access);
saa_pixmap_dirty(pixmap, FALSE, &reg);
if (pDst->alphaMap && pDst->alphaMap->pDrawable) {
pixmap = saa_get_drawable_pixmap(pDst->alphaMap->pDrawable);
saa_finish_access_pixmap(pixmap, access);
saa_pixmap_dirty(pixmap, FALSE, &reg);
}
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
saa_fad_read(pSrc->alphaMap->pDrawable);
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
saa_fad_read(pMask->alphaMap->pDrawable);
out_no_access:
sscreen->fallback_count--;
REGION_UNINIT(pScreen, &reg);
}
static void
saa_check_add_traps(PicturePtr pPicture,
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
{
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
PictureScreenPtr ps = GetPictureScreen(pScreen);
struct saa_screen_priv *sscreen = saa_screen(pScreen);
saa_access_t access;
SAA_FALLBACK(("to pict %p (%c)\n", saa_drawable_loc(pPicture->pDrawable)));
sscreen->fallback_count++;
if (!saa_pad_write(pPicture->pDrawable, NULL, FALSE, &access))
goto out_no_access;
saa_swap(sscreen, ps, AddTraps);
ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
saa_swap(sscreen, ps, AddTraps);
saa_fad_write(pPicture->pDrawable, access);
out_no_access:
sscreen->fallback_count--;
}
#endif
void
saa_unaccel_setup(ScreenPtr pScreen)
{
#ifdef RENDER
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
#endif
struct saa_screen_priv *sscreen = saa_screen(pScreen);
saa_wrap(sscreen, pScreen, GetImage, saa_check_get_image);
saa_wrap(sscreen, pScreen, GetSpans, saa_check_get_spans);
saa_wrap(sscreen, pScreen, CopyWindow, saa_check_copy_window);
#ifdef RENDER
if (ps) {
saa_wrap(sscreen, ps, AddTraps, saa_check_add_traps);
}
#endif
}
void
saa_unaccel_takedown(ScreenPtr pScreen)
{
#ifdef RENDER
PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
#endif
struct saa_screen_priv *sscreen = saa_screen(pScreen);
saa_unwrap(sscreen, pScreen, GetImage);
saa_unwrap(sscreen, pScreen, GetSpans);
saa_unwrap(sscreen, pScreen, CopyWindow);
#ifdef RENDER
if (ps) {
saa_unwrap(sscreen, ps, AddTraps);
}
#endif
}
GCOps saa_gc_ops = {
saa_check_fill_spans,
saa_check_set_spans,
saa_check_put_image,
saa_copy_area,
saa_check_copy_plane,
saa_check_poly_point,
saa_check_poly_lines,
saa_check_poly_segment,
miPolyRectangle,
saa_check_poly_arc,
miFillPolygon,
saa_check_poly_fill_rect,
miPolyFillArc,
miPolyText8,
miPolyText16,
miImageText8,
miImageText16,
saa_check_image_glyph_blt,
saa_check_poly_glyph_blt,
saa_check_push_pixels,
};

File diff suppressed because it is too large Load Diff

24
vmwgfx/Makefile.am Normal file
View File

@@ -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

1801
vmwgfx/svga3d_reg.h Normal file

File diff suppressed because it is too large Load Diff

199
vmwgfx/vmwgfx_bootstrap.c Normal file
View File

@@ -0,0 +1,199 @@
/**********************************************************
* Copyright 2008-2011 VMware, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************/
/**
* @file
* Bootstrap file for the vmwgfx xorg driver.
*
* @author Alan Hourihane <alanh@tungstengraphics.com>
* @author Jakob Bornecrantz <wallbraker@gmail.com>
* @author Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "xorg-server.h"
#include "xf86.h"
#include "pciaccess.h"
#ifndef XSERVER_LIBPCIACCESS
#error "libpciaccess needed"
#endif
void xorg_tracker_set_functions(ScrnInfoPtr scrn);
const OptionInfoRec * xorg_tracker_available_options(int chipid, int busid);
/*
* Defines and modinfo
*/
#define VMWGFX_DRIVER_NAME "vmwgfx"
#define VMW_STRING_INNER(s) #s
#define VMW_STRING(str) VMW_STRING_INNER(str)
#define VMWGFX_VERSION_MAJOR 11
#define VMWGFX_VERSION_MINOR 0
#define VMWGFX_VERSION_PATCH 0
#define VMWGFX_VERSION_STRING_MAJOR VMW_STRING(VMWGFX_VERSION_MAJOR)
#define VMWGFX_VERSION_STRING_MINOR VMW_STRING(VMWGFX_VERSION_MINOR)
#define VMWGFX_VERSION_STRING_PATCH VMW_STRING(VMWGFX_VERSION_PATCH)
#define VMWGFX_DRIVER_VERSION \
(VMWGFX_VERSION_MAJOR * 65536 + VMWGFX_VERSION_MINOR * 256 + VMWGFX_VERSION_PATCH)
#define VMWGFX_DRIVER_VERSION_STRING \
VMWGFX_VERSION_STRING_MAJOR "." VMWGFX_VERSION_STRING_MINOR \
"." VMWGFX_VERSION_STRING_PATCH
/*
* Standard four digit version string expected by VMware Tools installer.
* As the driver's version is only {major, minor, patchlevel}, simply append an
* extra zero for the fourth digit.
*/
#ifdef __GNUC__
_X_EXPORT const char vmwgfx_drv_modinfo[] __attribute__((section(".modinfo"),unused)) =
"version=" VMWGFX_DRIVER_VERSION_STRING ".0";
#endif
static void vmw_xorg_identify(int flags);
_X_EXPORT Bool vmw_xorg_pci_probe(DriverPtr driver,
int entity_num,
struct pci_device *device,
intptr_t match_data);
/*
* Tables
*/
static const struct pci_id_match vmw_xorg_device_match[] = {
{0x15ad, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0},
};
static SymTabRec vmw_xorg_chipsets[] = {
{PCI_MATCH_ANY, "VMware SVGA Device"},
{-1, NULL}
};
static PciChipsets vmw_xorg_pci_devices[] = {
{PCI_MATCH_ANY, PCI_MATCH_ANY, NULL},
{-1, -1, NULL}
};
static XF86ModuleVersionInfo vmw_xorg_version = {
VMWGFX_DRIVER_NAME,
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
VMWGFX_VERSION_MAJOR, VMWGFX_VERSION_MINOR, VMWGFX_VERSION_PATCH,
ABI_CLASS_VIDEODRV,
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0, 0, 0, 0}
};
/*
* Xorg driver exported structures
*/
_X_EXPORT DriverRec vmwgfx = {
1,
VMWGFX_DRIVER_NAME,
vmw_xorg_identify,
NULL,
xorg_tracker_available_options,
NULL,
0,
NULL,
vmw_xorg_device_match,
vmw_xorg_pci_probe
};
static MODULESETUPPROTO(vmw_xorg_setup);
_X_EXPORT XF86ModuleData vmwgfxModuleData = {
&vmw_xorg_version,
vmw_xorg_setup,
NULL
};
/*
* Xorg driver functions
*/
static pointer
vmw_xorg_setup(pointer module, pointer opts, int *errmaj, int *errmin)
{
static Bool setupDone = 0;
/* This module should be loaded only once, but check to be sure.
*/
if (!setupDone) {
setupDone = 1;
xf86AddDriver(&vmwgfx, module, HaveDriverFuncs);
/*
* The return value must be non-NULL on success even though there
* is no TearDownProc.
*/
return (pointer) 1;
} else {
if (errmaj)
*errmaj = LDR_ONCEONLY;
return NULL;
}
}
static void
vmw_xorg_identify(int flags)
{
xf86PrintChipsets("vmwgfx", "Driver for VMware SVGA device",
vmw_xorg_chipsets);
}
_X_EXPORT Bool
vmw_xorg_pci_probe(DriverPtr driver,
int entity_num, struct pci_device *device, intptr_t match_data)
{
ScrnInfoPtr scrn = NULL;
EntityInfoPtr entity;
scrn = xf86ConfigPciEntity(scrn, 0, entity_num, vmw_xorg_pci_devices,
NULL, NULL, NULL, NULL, NULL);
if (scrn != NULL) {
scrn->driverVersion = 1;
scrn->driverName = "vmwgfx";
scrn->name = "vmwgfx";
scrn->Probe = NULL;
entity = xf86GetEntityInfo(entity_num);
/* Use all the functions from the xorg tracker */
xorg_tracker_set_functions(scrn);
}
return scrn != NULL;
}

456
vmwgfx/vmwgfx_crtc.c Normal file
View File

@@ -0,0 +1,456 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Author: Alan Hourihane <alanh@tungstengraphics.com>
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "xorg-server.h"
#include <xf86.h>
#include <xf86i2c.h>
#include <xf86Crtc.h>
#include <cursorstr.h>
#include "vmwgfx_driver.h"
#include "xf86Modes.h"
#include "vmwgfx_saa.h"
#ifdef HAVE_XEXTPROTO_71
#include <X11/extensions/dpmsconst.h>
#else
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#endif
struct crtc_private
{
drmModeCrtcPtr drm_crtc;
/* hwcursor */
struct vmwgfx_dmabuf *cursor_bo;
PixmapPtr scanout;
uint32_t scanout_id;
unsigned cursor_handle;
};
static void
crtc_dpms(xf86CrtcPtr crtc, int mode)
{
struct crtc_private *crtcp = crtc->driver_private;
/* ScrnInfoPtr pScrn = crtc->scrn; */
switch (mode) {
case DPMSModeOn:
case DPMSModeStandby:
case DPMSModeSuspend:
break;
case DPMSModeOff:
/*
* The xf86 modesetting code uses DPMS off to turn off
* crtcs that are not enabled. However, the DPMS code does the same.
* We assume, that if we get this call with the crtc not enabled,
* it's a permanent switch off which will only be reversed by a
* major modeset.
*
* If it's a DPMS switch off, (crtc->enabled == TRUE),
* the crtc may be turned on again by
* another dpms call, so don't release the scanout pixmap ref.
*/
if (!crtc->enabled && crtcp->scanout) {
PixmapPtr pixmap = crtcp->scanout;
ScreenPtr pScreen = pixmap->drawable.pScreen;
vmwgfx_scanout_unref(pixmap);
pScreen->DestroyPixmap(pixmap);
crtcp->scanout = NULL;
crtcp->scanout_id = -1;
}
break;
}
}
/*
* Disable outputs and crtcs and drop the scanout reference from
* scanout pixmaps. This will essentialy free all kms fb allocations.
*/
void
vmwgfx_disable_scanout(ScrnInfoPtr pScrn)
{
int i;
Bool save_enabled;
xf86CrtcPtr crtc;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
xf86DPMSSet(pScrn, DPMSModeOff, 0);
for (i=0; i < config->num_crtc; ++i) {
crtc = config->crtc[i];
save_enabled = crtc->enabled;
crtc->enabled = FALSE;
crtc_dpms(crtc, DPMSModeOff);
crtc->enabled = save_enabled;
}
xf86RotateFreeShadow(pScrn);
}
static Bool
crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
modesettingPtr ms = modesettingPTR(crtc->scrn);
ScreenPtr pScreen = crtc->scrn->pScreen;
xf86OutputPtr output = NULL;
struct crtc_private *crtcp = crtc->driver_private;
drmModeCrtcPtr drm_crtc = crtcp->drm_crtc;
drmModeModeInfo drm_mode;
int i, ret;
unsigned int connector_id;
PixmapPtr pixmap;
for (i = 0; i < config->num_output; output = NULL, i++) {
output = config->output[i];
if (output->crtc == crtc)
break;
}
if (!output) {
LogMessage(X_ERROR, "No output for this crtc.\n");
return FALSE;
}
connector_id = xorg_output_get_id(output);
drm_mode.clock = mode->Clock;
drm_mode.hdisplay = mode->HDisplay;
drm_mode.hsync_start = mode->HSyncStart;
drm_mode.hsync_end = mode->HSyncEnd;
drm_mode.htotal = mode->HTotal;
drm_mode.vdisplay = mode->VDisplay;
drm_mode.vsync_start = mode->VSyncStart;
drm_mode.vsync_end = mode->VSyncEnd;
drm_mode.vtotal = mode->VTotal;
drm_mode.flags = mode->Flags;
drm_mode.hskew = mode->HSkew;
drm_mode.vscan = mode->VScan;
drm_mode.vrefresh = mode->VRefresh;
if (!mode->name)
xf86SetModeDefaultName(mode);
strncpy(drm_mode.name, mode->name, DRM_DISPLAY_MODE_LEN - 1);
drm_mode.name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
/*
* Check if we need to scanout from something else than the root
* pixmap. In that case, xf86CrtcRotate will take care of allocating
* new opaque scanout buffer data "crtc->rotatedData".
* However, it will not wrap
* that data into pixmaps until the first rotated damage composite.
* In out case, the buffer data is actually already a pixmap.
*/
if (!xf86CrtcRotate(crtc))
return FALSE;
if (crtc->transform_in_use && crtc->rotatedData)
pixmap = (PixmapPtr) crtc->rotatedData;
else
pixmap = pScreen->GetScreenPixmap(pScreen);
if (crtcp->scanout != pixmap) {
if (crtcp->scanout) {
vmwgfx_scanout_unref(crtcp->scanout);
pScreen->DestroyPixmap(crtcp->scanout);
}
crtcp->scanout_id = vmwgfx_scanout_ref(pixmap);
if (crtcp->scanout_id != -1) {
pixmap->refcnt += 1;
crtcp->scanout = pixmap;
} else {
crtcp->scanout = NULL;
LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n");
return FALSE;
}
}
ret = drmModeSetCrtc(ms->fd, drm_crtc->crtc_id, crtcp->scanout_id, x, y,
&connector_id, 1, &drm_mode);
if (ret)
return FALSE;
vmwgfx_scanout_refresh(pixmap);
/* Only set gamma when needed, to avoid unneeded delays. */
#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
if (!crtc->active && crtc->version >= 3)
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
crtc->active = TRUE;
#endif
return TRUE;
}
static void
crtc_gamma_set(xf86CrtcPtr crtc, CARD16 * red, CARD16 * green, CARD16 * blue,
int size)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
struct crtc_private *crtcp = crtc->driver_private;
drmModeCrtcSetGamma(ms->fd, crtcp->drm_crtc->crtc_id, size, red, green, blue);
}
static void *
crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
{
ScreenPtr pScreen = crtc->scrn->pScreen;
PixmapPtr rootpix = pScreen->GetScreenPixmap(pScreen);
/*
* Use the same depth as for the root pixmap.
* The associated kms fb will be created on demand once this pixmap
* is used as scanout by a crtc.
*/
return pScreen->CreatePixmap(pScreen, width, height,
rootpix->drawable.depth, 0);
}
static PixmapPtr
crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
{
return (PixmapPtr) data;
}
static void
crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
{
ScreenPtr pScreen = rotate_pixmap->drawable.pScreen;
pScreen->DestroyPixmap(rotate_pixmap);
}
/*
* Cursor functions
*/
static void
crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
{
/* XXX: See if this one is needed, as we only support ARGB cursors */
}
static void
crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
struct crtc_private *crtcp = crtc->driver_private;
drmModeMoveCursor(ms->fd, crtcp->drm_crtc->crtc_id, x, y);
}
static void
crtc_load_cursor_argb_kms(xf86CrtcPtr crtc, CARD32 * image)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
struct crtc_private *crtcp = crtc->driver_private;
unsigned char *ptr;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
CursorPtr c = config->cursor;
if (vmwgfx_cursor_bypass(ms->fd, c->bits->xhot, c->bits->yhot) != 0) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"Failed to set VMWare cursor bypass.\n");
}
if (!crtcp->cursor_bo) {
size_t size = 64*64*4;
crtcp->cursor_bo = vmwgfx_dmabuf_alloc(ms->fd, size);
if (!crtcp->cursor_bo)
return;
crtcp->cursor_handle = crtcp->cursor_bo->handle;
}
ptr = vmwgfx_dmabuf_map(crtcp->cursor_bo);
if (ptr) {
memcpy(ptr, image, 64*64*4);
vmwgfx_dmabuf_unmap(crtcp->cursor_bo);
}
if (crtc->cursor_shown)
drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
crtcp->cursor_handle, 64, 64);
return;
}
static void
crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
modesettingPtr ms = modesettingPTR(crtc->scrn);
/* Older X servers have cursor reference counting bugs leading to use of
* freed memory and consequently random crashes. Should be fixed as of
* xserver 1.8, but this workaround shouldn't hurt anyway.
*/
if (config->cursor)
config->cursor->refcnt++;
if (ms->cursor)
FreeCursor(ms->cursor, None);
ms->cursor = config->cursor;
crtc_load_cursor_argb_kms(crtc, image);
}
static void
crtc_show_cursor(xf86CrtcPtr crtc)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
struct crtc_private *crtcp = crtc->driver_private;
if (crtcp->cursor_bo)
drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id,
crtcp->cursor_handle, 64, 64);
}
static void
crtc_hide_cursor(xf86CrtcPtr crtc)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
struct crtc_private *crtcp = crtc->driver_private;
drmModeSetCursor(ms->fd, crtcp->drm_crtc->crtc_id, 0, 0, 0);
}
/**
* Called at vt leave
*/
void
xorg_crtc_cursor_destroy(xf86CrtcPtr crtc)
{
struct crtc_private *crtcp = crtc->driver_private;
if (crtcp->cursor_bo) {
vmwgfx_dmabuf_destroy(crtcp->cursor_bo);
crtcp->cursor_bo = NULL;
}
}
/*
* Misc functions
*/
static void
crtc_destroy(xf86CrtcPtr crtc)
{
struct crtc_private *crtcp = crtc->driver_private;
xorg_crtc_cursor_destroy(crtc);
drmModeFreeCrtc(crtcp->drm_crtc);
free(crtcp);
crtc->driver_private = NULL;
}
static const xf86CrtcFuncsRec crtc_funcs = {
.dpms = crtc_dpms,
.set_mode_major = crtc_set_mode_major,
.set_cursor_colors = crtc_set_cursor_colors,
.set_cursor_position = crtc_set_cursor_position,
.show_cursor = crtc_show_cursor,
.hide_cursor = crtc_hide_cursor,
.load_cursor_argb = crtc_load_cursor_argb,
.shadow_create = crtc_shadow_create,
.shadow_allocate = crtc_shadow_allocate,
.shadow_destroy = crtc_shadow_destroy,
.gamma_set = crtc_gamma_set,
.destroy = crtc_destroy,
};
void
xorg_crtc_init(ScrnInfoPtr pScrn)
{
modesettingPtr ms = modesettingPTR(pScrn);
xf86CrtcPtr crtc;
drmModeResPtr res;
drmModeCrtcPtr drm_crtc = NULL;
struct crtc_private *crtcp;
int c;
res = drmModeGetResources(ms->fd);
if (res == 0) {
ErrorF("Failed drmModeGetResources %d\n", errno);
return;
}
for (c = 0; c < res->count_crtcs; c++) {
drm_crtc = drmModeGetCrtc(ms->fd, res->crtcs[c]);
if (!drm_crtc)
continue;
crtc = xf86CrtcCreate(pScrn, &crtc_funcs);
if (crtc == NULL)
goto out;
crtcp = calloc(1, sizeof(struct crtc_private));
if (!crtcp) {
xf86CrtcDestroy(crtc);
goto out;
}
crtcp->drm_crtc = drm_crtc;
crtc->driver_private = crtcp;
}
out:
drmModeFreeResources(res);
}
PixmapPtr
crtc_get_scanout(xf86CrtcPtr crtc)
{
struct crtc_private *crtcp = crtc->driver_private;
return crtcp->scanout;
}
/* vim: set sw=4 ts=8 sts=4: */

525
vmwgfx/vmwgfx_ctrl.c Normal file
View File

@@ -0,0 +1,525 @@
/*
* Copyright 2006-2011 by VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
/*
* vmwarectrl.c --
*
* The implementation of the VMWARE_CTRL protocol extension that
* allows X clients to communicate with the driver.
*/
#include <xorg-server.h>
#include "dixstruct.h"
#include "extnsionst.h"
#include <X11/X.h>
#include <X11/extensions/panoramiXproto.h>
#include "vmwarectrlproto.h"
#include "xf86drm.h"
#include "vmwgfx_driver.h"
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlQueryVersion --
*
* Implementation of QueryVersion command handler. Initialises and
* sends a reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlQueryVersion(ClientPtr client)
{
xVMwareCtrlQueryVersionReply rep = { 0, };
register int n;
REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = VMWARE_CTRL_MAJOR_VERSION;
rep.minorVersion = VMWARE_CTRL_MINOR_VERSION;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.majorVersion, n);
swapl(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xVMwareCtrlQueryVersionReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDoSetRes --
*
* Set the custom resolution into the mode list.
*
* This is done by alternately updating one of two dynamic modes. It is
* done this way because the server gets upset if you try to switch
* to a new resolution that has the same index as the current one.
*
* Results:
* TRUE on success, FALSE otherwise.
*
* Side effects:
* One dynamic mode will be updated if successful.
*
*----------------------------------------------------------------------------
*/
static Bool
VMwareCtrlDoSetRes(ScrnInfoPtr pScrn,
CARD32 x,
CARD32 y)
{
#if 0
struct vmw_rect rect;
rect.x = 0;
rect.y = 0;
rect.w = x;
rect.h = y;
vmw_ioctl_update_layout(vmw, 1, &rect);
#endif
return TRUE;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlSetRes --
*
* Implementation of SetRes command handler. Initialises and sends a
* reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlSetRes(ClientPtr client)
{
REQUEST(xVMwareCtrlSetResReq);
xVMwareCtrlSetResReply rep = { 0, };
ScrnInfoPtr pScrn;
ExtensionEntry *ext;
register int n;
REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
return BadMatch;
}
pScrn = ext->extPrivate;
if (pScrn->scrnIndex != stuff->screen) {
return BadMatch;
}
if (!VMwareCtrlDoSetRes(pScrn, stuff->x, stuff->y)) {
return BadValue;
}
rep.type = X_Reply;
rep.length = (sizeof(xVMwareCtrlSetResReply) - sizeof(xGenericReply)) >> 2;
rep.sequenceNumber = client->sequence;
rep.screen = stuff->screen;
rep.x = stuff->x;
rep.y = stuff->y;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.screen, n);
swapl(&rep.x, n);
swapl(&rep.y, n);
}
WriteToClient(client, sizeof(xVMwareCtrlSetResReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDoSetTopology --
*
* Set the custom topology and set a dynamic mode to the bounding box
* of the passed topology. If a topology is already pending, then do
* nothing but do not return failure.
*
* Results:
* TRUE on success, FALSE otherwise.
*
* Side effects:
* One dynamic mode and the pending xinerama state will be updated if
* successful.
*
*----------------------------------------------------------------------------
*/
static Bool
VMwareCtrlDoSetTopology(ScrnInfoPtr pScrn,
xXineramaScreenInfo *extents,
unsigned long number)
{
#if 0
struct vmw_rect *rects;
struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
int i;
rects = calloc(number, sizeof(*rects));
if (!rects)
return FALSE;
for (i = 0; i < number; i++) {
rects[i].x = extents[i].x_org;
rects[i].y = extents[i].y_org;
rects[i].w = extents[i].width;
rects[i].h = extents[i].height;
}
vmw_ioctl_update_layout(vmw, number, rects);
free(rects);
#endif
return TRUE;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlSetTopology --
*
* Implementation of SetTopology command handler. Initialises and sends a
* reply.
*
* Results:
* Standard response codes.
*
* Side effects:
* Writes reply to client
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlSetTopology(ClientPtr client)
{
REQUEST(xVMwareCtrlSetTopologyReq);
xVMwareCtrlSetTopologyReply rep = { 0, };
ScrnInfoPtr pScrn;
ExtensionEntry *ext;
register int n;
xXineramaScreenInfo *extents;
REQUEST_AT_LEAST_SIZE(xVMwareCtrlSetTopologyReq);
if (!(ext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
return BadMatch;
}
pScrn = ext->extPrivate;
if (pScrn->scrnIndex != stuff->screen) {
return BadMatch;
}
extents = (xXineramaScreenInfo *)(stuff + 1);
if (!VMwareCtrlDoSetTopology(pScrn, extents, stuff->number)) {
return BadValue;
}
rep.type = X_Reply;
rep.length = (sizeof(xVMwareCtrlSetTopologyReply) - sizeof(xGenericReply)) >> 2;
rep.sequenceNumber = client->sequence;
rep.screen = stuff->screen;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swapl(&rep.screen, n);
}
WriteToClient(client, sizeof(xVMwareCtrlSetTopologyReply), (char *)&rep);
return client->noClientException;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlDispatch --
*
* Dispatcher for VMWARE_CTRL commands. Calls the correct handler for
* each command type.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of individual command handlers.
*
*----------------------------------------------------------------------------
*/
static int
VMwareCtrlDispatch(ClientPtr client)
{
REQUEST(xReq);
switch(stuff->data) {
case X_VMwareCtrlQueryVersion:
return VMwareCtrlQueryVersion(client);
case X_VMwareCtrlSetRes:
return VMwareCtrlSetRes(client);
case X_VMwareCtrlSetTopology:
return VMwareCtrlSetTopology(client);
}
return BadRequest;
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlQueryVersion --
*
* Wrapper for QueryVersion handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlQueryVersion(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlQueryVersionReq);
REQUEST_SIZE_MATCH(xVMwareCtrlQueryVersionReq);
swaps(&stuff->length, n);
return VMwareCtrlQueryVersion(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlSetRes --
*
* Wrapper for SetRes handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlSetRes(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlSetResReq);
REQUEST_SIZE_MATCH(xVMwareCtrlSetResReq);
swaps(&stuff->length, n);
swapl(&stuff->screen, n);
swapl(&stuff->x, n);
swapl(&stuff->y, n);
return VMwareCtrlSetRes(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlSetTopology --
*
* Wrapper for SetTopology handler that handles input from other-endian
* clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of unswapped implementation.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlSetTopology(ClientPtr client)
{
register int n;
REQUEST(xVMwareCtrlSetTopologyReq);
REQUEST_SIZE_MATCH(xVMwareCtrlSetTopologyReq);
swaps(&stuff->length, n);
swapl(&stuff->screen, n);
swapl(&stuff->number, n);
/* Each extent is a struct of shorts. */
SwapRestS(stuff);
return VMwareCtrlSetTopology(client);
}
/*
*----------------------------------------------------------------------------
*
* SVMwareCtrlDispatch --
*
* Wrapper for dispatcher that handles input from other-endian clients.
*
* Results:
* Standard response codes.
*
* Side effects:
* Side effects of individual command handlers.
*
*----------------------------------------------------------------------------
*/
static int
SVMwareCtrlDispatch(ClientPtr client)
{
REQUEST(xReq);
switch(stuff->data) {
case X_VMwareCtrlQueryVersion:
return SVMwareCtrlQueryVersion(client);
case X_VMwareCtrlSetRes:
return SVMwareCtrlSetRes(client);
case X_VMwareCtrlSetTopology:
return SVMwareCtrlSetTopology(client);
}
return BadRequest;
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrlResetProc --
*
* Cleanup handler called when the extension is removed.
*
* Results:
* None
*
* Side effects:
* None
*
*----------------------------------------------------------------------------
*/
static void
VMwareCtrlResetProc(ExtensionEntry* extEntry)
{
/* Currently, no cleanup is necessary. */
}
/*
*----------------------------------------------------------------------------
*
* VMwareCtrl_ExitInit --
*
* Initialiser for the VMWARE_CTRL protocol extension.
*
* Results:
* None.
*
* Side effects:
* Protocol extension will be registered if successful.
*
*----------------------------------------------------------------------------
*/
void
vmw_ctrl_ext_init(ScrnInfoPtr pScrn)
{
ExtensionEntry *myext;
if (!(myext = CheckExtension(VMWARE_CTRL_PROTOCOL_NAME))) {
if (!(myext = AddExtension(VMWARE_CTRL_PROTOCOL_NAME, 0, 0,
VMwareCtrlDispatch,
SVMwareCtrlDispatch,
VMwareCtrlResetProc,
StandardMinorOpcode))) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to add VMWARE_CTRL extension\n");
return;
}
/*
* For now, only support one screen as that's all the virtual
* hardware supports.
*/
myext->extPrivate = pScrn;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Initialized VMWARE_CTRL extension version %d.%d\n",
VMWARE_CTRL_MAJOR_VERSION, VMWARE_CTRL_MINOR_VERSION);
}
}

48
vmwgfx/vmwgfx_ctrl.h Normal file
View File

@@ -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_ */

373
vmwgfx/vmwgfx_dri2.c Normal file
View File

@@ -0,0 +1,373 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Author: Alan Hourihane <alanh@tungstengraphics.com>
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*
*/
#include "xorg-server.h"
#include "xf86.h"
#include "xf86_OSproc.h"
#include "vmwgfx_driver.h"
#include "../saa/saa.h"
#include "dri2.h"
#include "gcstruct.h"
#include "gc.h"
#include "vmwgfx_saa.h"
struct vmwgfx_dri2_priv {
unsigned int srf_count;
struct xa_surface *srf[20];
};
DevPrivateKeyRec dri2_pixmap_index;
DevPrivateKeyRec dri2_window_index;
typedef struct {
int refcount;
PixmapPtr pPixmap;
struct xa_surface *srf;
} *BufferPrivatePtr;
static Bool
dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int format)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
BufferPrivatePtr private = buffer->driverPrivate;
PixmapPtr pPixmap;
struct vmwgfx_saa_pixmap *vpix;
struct xa_surface *srf = NULL;
unsigned int cpp = 4;
if (pDraw->type == DRAWABLE_PIXMAP)
pPixmap = (PixmapPtr) pDraw;
else
pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw);
vpix = vmwgfx_saa_pixmap(pPixmap);
private->refcount = 0;
switch (buffer->attachment) {
default:
if (buffer->attachment != DRI2BufferFakeFrontLeft ||
&pPixmap->drawable != pDraw) {
pPixmap = (*pScreen->CreatePixmap)(pScreen,
pDraw->width,
pDraw->height,
pDraw->depth,
0);
if (pPixmap == NullPixmap)
return FALSE;
private->pPixmap = pPixmap;
vpix = vmwgfx_saa_pixmap(pPixmap);
}
break;
case DRI2BufferFrontLeft:
if (&pPixmap->drawable == pDraw)
break;
buffer->name = 0;
buffer->pitch = 0;
buffer->cpp = cpp;
buffer->driverPrivate = private;
buffer->flags = 0; /* not tiled */
buffer->format = 0;
if (!private->pPixmap) {
private->pPixmap = pPixmap;
pPixmap->refcnt++;
}
return TRUE;
case DRI2BufferStencil:
case DRI2BufferDepthStencil:
srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
32, xa_type_zs, xa_format_unknown,
XA_FLAG_SHARED );
if (!srf)
srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
32, xa_type_sz, xa_format_unknown,
XA_FLAG_SHARED );
if (!srf)
return FALSE;
break;
case DRI2BufferDepth:
srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
(format) ? format: pDraw->depth,
xa_type_z, xa_format_unknown,
XA_FLAG_SHARED);
if (!srf)
return FALSE;
break;
}
if (!private->pPixmap) {
private->pPixmap = pPixmap;
pPixmap->refcnt++;
}
if (!srf) {
if (!vmwgfx_pixmap_validate_hw(pPixmap, NULL,
XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
0))
return FALSE;
srf = vpix->hw;
/*
* Compiz workaround. See vmwgfx_dirty();
*/
vpix->hw_is_dri2_fronts++;
private->refcount++;
}
private->srf = srf;
if (xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0)
return FALSE;
buffer->cpp = cpp;
buffer->driverPrivate = private;
buffer->flags = 0; /* not tiled */
buffer->format = format;
private->refcount++;
return TRUE;
}
static void
dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
{
BufferPrivatePtr private = buffer->driverPrivate;
struct xa_surface *srf = private->srf;
ScreenPtr pScreen = pDraw->pScreen;
if (--private->refcount == 0 && srf) {
xa_surface_destroy(srf);
}
/*
* Compiz workaround. See vmwgfx_dirty();
*/
if (private->refcount == 1) {
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap);
if (--vpix->hw_is_dri2_fronts == 0)
vmwgfx_remove_dri2_list(vpix);
}
private->srf = NULL;
pScreen->DestroyPixmap(private->pPixmap);
}
static DRI2Buffer2Ptr
dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format)
{
DRI2Buffer2Ptr buffer;
BufferPrivatePtr private;
buffer = calloc(1, sizeof *buffer);
if (!buffer)
return NULL;
private = calloc(1, sizeof *private);
if (!private) {
goto fail;
}
buffer->attachment = attachment;
buffer->driverPrivate = private;
if (dri2_do_create_buffer(pDraw, buffer, format))
return buffer;
free(private);
fail:
free(buffer);
return NULL;
}
static void
dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
{
/* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer);
free(buffer->driverPrivate);
free(buffer);
}
static void
dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
DRI2Buffer2Ptr pDestBuffer, DRI2Buffer2Ptr pSrcBuffer)
{
ScreenPtr pScreen = pDraw->pScreen;
BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate;
BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate;
DrawablePtr src_draw;
DrawablePtr dst_draw;
RegionPtr myClip;
GCPtr gc;
if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
pDestBuffer->attachment == DRI2BufferFakeFrontLeft)
LogMessage(X_ERROR, "glxwaitx\n");
/*
* In driCreateBuffers we dewrap windows into the
* backing pixmaps in order to get to the texture.
* We need to use the real drawable in CopyArea
* so that cliprects and offsets are correct.
*/
src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
&src_priv->pPixmap->drawable;
dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
&dst_priv->pPixmap->drawable;
/*
* The clients implements glXWaitX with a copy front to fake and then
* waiting on the server to signal its completion of it. While
* glXWaitGL is a client side flush and a copy from fake to front.
* This is how it is done in the DRI2 protocol, how ever depending
* which type of drawables the server does things a bit differently
* then what the protocol says as the fake and front are the same.
*
* for pixmaps glXWaitX is a server flush.
* for pixmaps glXWaitGL is a client flush.
* for windows glXWaitX is a copy from front to fake then a server flush.
* for windows glXWaitGL is a client flush then a copy from fake to front.
*
* XXX in the windows case this code always flushes but that isn't a
* must in the glXWaitGL case but we don't know if this is a glXWaitGL
* or a glFlush/glFinish call.
*/
if (dst_priv->pPixmap == src_priv->pPixmap) {
/* pixmap glXWaitX */
if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
LogMessage(X_INFO, "dri2 Validate hw.\n");
vmwgfx_pixmap_validate_hw(src_priv->pPixmap, NULL,
XA_FLAG_SHARED | XA_FLAG_RENDER_TARGET,
0);
return;
}
/* pixmap glXWaitGL */
if (pDestBuffer->attachment == DRI2BufferFrontLeft &&
pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) {
return;
} else {
vmwgfx_flush_dri2(pScreen);
return;
}
}
gc = GetScratchGC(pDraw->depth, pScreen);
myClip = REGION_CREATE(pScreen, REGION_RECTS(pRegion),
REGION_NUM_RECTS(pRegion));
(*gc->funcs->ChangeClip) (gc, CT_REGION, myClip, 0);
ValidateGC(dst_draw, gc);
/*
* Damage the src drawable in order for damageCopyArea to pick up
* that something changed.
*/
DamageRegionAppend(src_draw, pRegion);
saa_drawable_dirty(src_draw, TRUE, pRegion);
DamageRegionProcessPending(src_draw);
/*
* Call CopyArea. This usually means a call to damageCopyArea that
* is wrapping saa_copy_area. The damageCopyArea function will make
* sure the destination drawable is appropriately damaged.
*/
(*gc->ops->CopyArea)(src_draw, dst_draw, gc,
0, 0, pDraw->width, pDraw->height, 0, 0);
/*
* FreeScratchGC will free myClip as well.
*/
myClip = NULL;
FreeScratchGC(gc);
}
Bool
xorg_dri2_init(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
DRI2InfoRec dri2info;
int major, minor;
if (xf86LoaderCheckSymbol("DRI2Version")) {
DRI2Version(&major, &minor);
} else {
/* Assume version 1.0 */
major = 1;
minor = 0;
}
if (!dixRegisterPrivateKey(&dri2_pixmap_index, PRIVATE_PIXMAP, 0)) {
LogMessage(X_ERROR, "Failed to register vmwgfx dri2 private.\n");
return FALSE;
}
if (!dixRegisterPrivateKey(&dri2_window_index, PRIVATE_WINDOW, 0)) {
LogMessage(X_ERROR, "Failed to register vmwgfx dri2 private.\n");
return FALSE;
}
dri2info.version = min(DRI2INFOREC_VERSION, 3);
dri2info.fd = ms->fd;
dri2info.driverName = pScrn->driverName;
dri2info.deviceName = "/dev/dri/card0"; /* FIXME */
dri2info.CreateBuffer = dri2_create_buffer;
dri2info.DestroyBuffer = dri2_destroy_buffer;
dri2info.CopyRegion = dri2_copy_region;
dri2info.Wait = NULL;
return DRI2ScreenInit(pScreen, &dri2info);
}
void
xorg_dri2_close(ScreenPtr pScreen)
{
DRI2CloseScreen(pScreen);
}
/* vim: set sw=4 ts=8 sts=4: */

947
vmwgfx/vmwgfx_driver.c Normal file
View File

@@ -0,0 +1,947 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Author: Alan Hourihane <alanh@tungstengraphics.com>
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#include "xorg-server.h"
#include "xf86.h"
#include "xf86_OSproc.h"
#include "compiler.h"
#include "xf86PciInfo.h"
#include "xf86Pci.h"
#include "mipointer.h"
#include "micmap.h"
#include <X11/extensions/randr.h>
#include "fb.h"
#include "edid.h"
#include "xf86i2c.h"
#include "xf86Crtc.h"
#include "miscstruct.h"
#include "dixstruct.h"
#include "xf86cmap.h"
#include "xf86xv.h"
#include "xorgVersion.h"
#ifndef XSERVER_LIBPCIACCESS
#error "libpciaccess needed"
#endif
#include <pciaccess.h>
#include "vmwgfx_driver.h"
#include <saa.h>
#include "vmwgfx_saa.h"
/*
* Some macros to deal with function wrapping.
*/
#define vmwgfx_wrap(priv, real, mem, func) {\
(priv)->saved_##mem = (real)->mem; \
(real)->mem = func; \
}
#define vmwgfx_unwrap(priv, real, mem) {\
(real)->mem = (priv)->saved_##mem; \
}
#define vmwgfx_swap(priv, real, mem) {\
void *tmp = (priv)->saved_##mem; \
(priv)->saved_##mem = (real)->mem; \
(real)->mem = tmp; \
}
/*
* Functions and symbols exported to Xorg via pointers.
*/
static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
char **argv);
static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
static Bool drv_enter_vt(int scrnIndex, int flags);
static void drv_leave_vt(int scrnIndex, int flags);
static void drv_free_screen(int scrnIndex, int flags);
static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
int flags);
extern void xorg_tracker_set_functions(ScrnInfoPtr scrn);
extern const OptionInfoRec * xorg_tracker_available_options(int chipid,
int busid);
typedef enum
{
OPTION_SW_CURSOR,
OPTION_2D_ACCEL,
OPTION_DEBUG_FALLBACK,
OPTION_THROTTLE_SWAP,
OPTION_THROTTLE_DIRTY,
OPTION_3D_ACCEL
} drv_option_enums;
static const OptionInfoRec drv_options[] = {
{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_THROTTLE_SWAP, "SwapThrottling", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_THROTTLE_DIRTY, "DirtyThrottling", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_3D_ACCEL, "3DAccel", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
/*
* Exported Xorg driver functions to winsys
*/
const OptionInfoRec *
xorg_tracker_available_options(int chipid, int busid)
{
return drv_options;
}
void
xorg_tracker_set_functions(ScrnInfoPtr scrn)
{
scrn->PreInit = drv_pre_init;
scrn->ScreenInit = drv_screen_init;
scrn->SwitchMode = drv_switch_mode;
scrn->FreeScreen = drv_free_screen;
scrn->ValidMode = drv_valid_mode;
}
/*
* Internal function definitions
*/
static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
/*
* Internal functions
*/
static Bool
drv_get_rec(ScrnInfoPtr pScrn)
{
if (pScrn->driverPrivate)
return TRUE;
pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec));
return TRUE;
}
static void
drv_free_rec(ScrnInfoPtr pScrn)
{
if (!pScrn)
return;
if (!pScrn->driverPrivate)
return;
free(pScrn->driverPrivate);
pScrn->driverPrivate = NULL;
}
static void
drv_probe_ddc(ScrnInfoPtr pScrn, int index)
{
ConfiguredMonitor = NULL;
}
static Bool
drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
{
modesettingPtr ms = modesettingPTR(pScrn);
ScreenPtr pScreen = pScrn->pScreen;
int old_width, old_height;
PixmapPtr rootPixmap;
if (width == pScrn->virtualX && height == pScrn->virtualY)
return TRUE;
if (ms->check_fb_size) {
size_t size = width*(pScrn->bitsPerPixel / 8) * height + 1024;
if (size > ms->max_fb_size) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Requested framebuffer size %dx%dx%d will not fit "
"in display memory.\n",
width, height, pScrn->bitsPerPixel);
return FALSE;
}
}
old_width = pScrn->virtualX;
old_height = pScrn->virtualY;
pScrn->virtualX = width;
pScrn->virtualY = height;
/* ms->create_front_buffer will remove the old front buffer */
rootPixmap = pScreen->GetScreenPixmap(pScreen);
vmwgfx_disable_scanout(pScrn);
if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
goto error_modify;
pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
xf86SetDesiredModes(pScrn);
return TRUE;
/*
* FIXME: Try out this error recovery path and fix problems.
*/
//error_create:
if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL))
FatalError("failed to resize rootPixmap error path\n");
pScrn->displayWidth = rootPixmap->devKind /
(rootPixmap->drawable.bitsPerPixel / 8);
error_modify:
pScrn->virtualX = old_width;
pScrn->virtualY = old_height;
if (xf86SetDesiredModes(pScrn))
return FALSE;
FatalError("failed to setup old framebuffer\n");
return FALSE;
}
static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
.resize = drv_crtc_resize
};
static Bool
drv_init_drm(ScrnInfoPtr pScrn)
{
modesettingPtr ms = modesettingPTR(pScrn);
/* deal with server regeneration */
if (ms->fd < 0) {
char *BusID;
BusID = malloc(64);
sprintf(BusID, "PCI:%d:%d:%d",
((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
ms->PciInfo->dev, ms->PciInfo->func
);
ms->fd = drmOpen("vmwgfx", BusID);
ms->isMaster = TRUE;
free(BusID);
if (ms->fd >= 0)
return TRUE;
return FALSE;
}
return TRUE;
}
static Bool
drv_pre_init(ScrnInfoPtr pScrn, int flags)
{
xf86CrtcConfigPtr xf86_config;
modesettingPtr ms;
rgb defaultWeight = { 0, 0, 0 };
EntityInfoPtr pEnt;
EntPtr msEnt = NULL;
Bool use3D;
if (pScrn->numEntities != 1)
return FALSE;
pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
if (flags & PROBE_DETECT) {
drv_probe_ddc(pScrn, pEnt->index);
return TRUE;
}
pScrn->driverPrivate = NULL;
/* Allocate driverPrivate */
if (!drv_get_rec(pScrn))
return FALSE;
ms = modesettingPTR(pScrn);
ms->pEnt = pEnt;
pScrn->displayWidth = 640; /* default it */
if (ms->pEnt->location.type != BUS_PCI)
return FALSE;
ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
/* Allocate an entity private if necessary */
if (xf86IsEntityShared(pScrn->entityList[0])) {
FatalError("Entity");
#if 0
msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
modesettingEntityIndex)->ptr;
ms->entityPrivate = msEnt;
#else
(void)msEnt;
#endif
} else
ms->entityPrivate = NULL;
if (xf86IsEntityShared(pScrn->entityList[0])) {
if (xf86IsPrimInitDone(pScrn->entityList[0])) {
/* do something */
} else {
xf86SetPrimInitDone(pScrn->entityList[0]);
}
}
ms->fd = -1;
if (!drv_init_drm(pScrn))
return FALSE;
ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0);
pScrn->monitor = pScrn->confScreen->monitor;
pScrn->progClock = TRUE;
pScrn->rgbBits = 8;
if (!xf86SetDepthBpp
(pScrn, 0, 0, 0,
PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
return FALSE;
switch (pScrn->depth) {
case 8:
case 15:
case 16:
case 24:
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Given depth (%d) is not supported by the driver\n",
pScrn->depth);
return FALSE;
}
xf86PrintDepthBpp(pScrn);
if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
return FALSE;
if (!xf86SetDefaultVisual(pScrn, -1))
return FALSE;
/* Process the options */
xf86CollectOptions(pScrn, NULL);
if (!(ms->Options = malloc(sizeof(drv_options))))
return FALSE;
memcpy(ms->Options, drv_options, sizeof(drv_options));
xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
use3D = TRUE;
ms->from_3D = xf86GetOptValBool(ms->Options, OPTION_3D_ACCEL,
&use3D) ?
X_CONFIG : X_PROBED;
ms->no3D = !use3D;
/* Allocate an xf86CrtcConfig */
xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
/* get max width and height */
{
drmModeResPtr res;
int max_width, max_height;
res = drmModeGetResources(ms->fd);
max_width = res->max_width;
max_height = res->max_height;
#if 0 /* Gallium fix */
if (ms->screen) {
int max;
max = ms->screen->get_param(ms->screen,
PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
max = 1 << (max - 1);
max_width = max < max_width ? max : max_width;
max_height = max < max_height ? max : max_height;
}
#endif
xf86CrtcSetSizeRange(pScrn, res->min_width,
res->min_height, max_width, max_height);
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"Min width %d, Max Width %d.\n",
res->min_width, max_width);
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"Min height %d, Max Height %d.\n",
res->min_height, max_height);
drmModeFreeResources(res);
}
if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
ms->SWCursor = TRUE;
}
xorg_crtc_init(pScrn);
xorg_output_init(pScrn);
if (!xf86InitialConfiguration(pScrn, TRUE)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
return FALSE;
}
/*
* If the driver can do gamma correction, it should call xf86SetGamma() here.
*/
{
Gamma zeros = { 0.0, 0.0, 0.0 };
if (!xf86SetGamma(pScrn, zeros)) {
return FALSE;
}
}
if (pScrn->modes == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
return FALSE;
}
pScrn->currentMode = pScrn->modes;
/* Set display resolution */
xf86SetDpi(pScrn, 0, 0);
/* Load the required sub modules */
if (!xf86LoadSubModule(pScrn, "fb"))
return FALSE;
#ifdef DRI2
if (!xf86LoadSubModule(pScrn, "dri2"))
return FALSE;
#endif
return TRUE;
}
static Bool
vmwgfx_scanout_update(int drm_fd, int fb_id, RegionPtr dirty)
{
unsigned num_cliprects = REGION_NUM_RECTS(dirty);
drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
BoxPtr rect = REGION_RECTS(dirty);
int i, ret;
if (!num_cliprects)
return TRUE;
for (i = 0; i < num_cliprects; i++, rect++) {
clip[i].x1 = rect->x1;
clip[i].y1 = rect->y1;
clip[i].x2 = rect->x2;
clip[i].y2 = rect->y2;
}
ret = drmModeDirtyFB(drm_fd, fb_id, clip, num_cliprects);
if (ret)
LogMessage(X_ERROR, "%s: failed to send dirty (%i, %s)\n",
__func__, ret, strerror(-ret));
return (ret == 0);
}
static Bool
vmwgfx_scanout_present(ScreenPtr pScreen, int drm_fd,
struct vmwgfx_saa_pixmap *vpix,
RegionPtr dirty)
{
uint32_t handle;
unsigned int dummy;
if (!REGION_NOTEMPTY(pScreen, dirty))
return TRUE;
if (!vpix->hw) {
LogMessage(X_ERROR, "No surface to present from.\n");
return FALSE;
}
if (xa_surface_handle(vpix->hw, &handle, &dummy) != 0) {
LogMessage(X_ERROR, "Could not get present surface handle.\n");
return FALSE;
}
if (vmwgfx_present(drm_fd, 0, 0, dirty, handle) != 0) {
LogMessage(X_ERROR, "Could not get present surface handle.\n");
return FALSE;
}
return TRUE;
}
void xorg_flush(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
PixmapPtr pixmap = NULL;
struct vmwgfx_saa_pixmap *vpix;
int i;
xf86CrtcPtr crtc;
PixmapPtr *pixmaps = calloc(config->num_crtc, sizeof(*pixmaps));
unsigned int num_scanout = 0;
unsigned int j;
if (!pixmaps) {
LogMessage(X_ERROR, "Failed memory allocation during screen "
"update.\n");
return;
}
/*
* Get an array of pixmaps from which we scan out.
*/
for (i=0; i<config->num_crtc; ++i) {
crtc = config->crtc[i];
if (crtc->enabled) {
pixmap = crtc_get_scanout(crtc);
if (pixmap) {
unsigned int j;
/*
* Remove duplicates.
*/
for (j=0; j<num_scanout; ++j) {
if (pixmap == pixmaps[j])
break;
}
if (j == num_scanout)
pixmaps[num_scanout++] = pixmap;
}
}
}
if (!num_scanout)
return;
for (j=0; j<num_scanout; ++j) {
pixmap = pixmaps[j];
vpix = vmwgfx_saa_pixmap(pixmap);
if (vpix->fb_id != -1) {
if (vpix->pending_update) {
(void) vmwgfx_scanout_update(ms->fd, vpix->fb_id,
vpix->pending_update);
REGION_SUBTRACT(pScreen, vpix->dirty_present,
vpix->dirty_present, vpix->pending_update);
REGION_EMPTY(pScreen, vpix->pending_update);
}
if (vpix->pending_present) {
(void) vmwgfx_scanout_present(pScreen, ms->fd, vpix,
vpix->pending_present);
REGION_SUBTRACT(pScreen, vpix->dirty_present,
vpix->dirty_present, vpix->pending_present);
REGION_EMPTY(pScreen, vpix->pending_present);
}
}
}
free(pixmaps);
}
static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
pointer pReadmask)
{
ScreenPtr pScreen = screenInfo.screens[i];
modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
vmwgfx_swap(ms, pScreen, BlockHandler);
pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
vmwgfx_swap(ms, pScreen, BlockHandler);
xorg_flush(pScreen);
}
static Bool
drv_create_screen_resources(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
Bool ret;
vmwgfx_swap(ms, pScreen, CreateScreenResources);
ret = pScreen->CreateScreenResources(pScreen);
vmwgfx_swap(ms, pScreen, CreateScreenResources);
drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
return drv_enter_vt(pScreen->myNum, 1);
}
static Bool
drv_set_master(ScrnInfoPtr pScrn)
{
modesettingPtr ms = modesettingPTR(pScrn);
if (!ms->isMaster && drmSetMaster(ms->fd) != 0) {
if (errno == EINVAL) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"drmSetMaster failed: 2.6.29 or newer kernel required for "
"multi-server DRI\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"drmSetMaster failed: %s\n", strerror(errno));
}
return FALSE;
}
ms->isMaster = TRUE;
return TRUE;
}
static void drv_load_palette(ScrnInfoPtr pScrn, int numColors,
int *indices, LOCO *colors, VisualPtr pVisual)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
modesettingPtr ms = modesettingPTR(pScrn);
int index, j, i;
int c;
switch(pScrn->depth) {
case 15:
for (i = 0; i < numColors; i++) {
index = indices[i];
for (j = 0; j < 8; j++) {
ms->lut_r[index * 8 + j] = colors[index].red << 8;
ms->lut_g[index * 8 + j] = colors[index].green << 8;
ms->lut_b[index * 8 + j] = colors[index].blue << 8;
}
}
break;
case 16:
for (i = 0; i < numColors; i++) {
index = indices[i];
if (index < 32) {
for (j = 0; j < 8; j++) {
ms->lut_r[index * 8 + j] = colors[index].red << 8;
ms->lut_b[index * 8 + j] = colors[index].blue << 8;
}
}
for (j = 0; j < 4; j++) {
ms->lut_g[index * 4 + j] = colors[index].green << 8;
}
}
break;
default:
for (i = 0; i < numColors; i++) {
index = indices[i];
ms->lut_r[index] = colors[index].red << 8;
ms->lut_g[index] = colors[index].green << 8;
ms->lut_b[index] = colors[index].blue << 8;
}
break;
}
for (c = 0; c < xf86_config->num_crtc; c++) {
xf86CrtcPtr crtc = xf86_config->crtc[c];
/* Make the change through RandR */
#ifdef RANDR_12_INTERFACE
if (crtc->randr_crtc)
RRCrtcGammaSet(crtc->randr_crtc, ms->lut_r, ms->lut_g, ms->lut_b);
else
#endif
crtc->funcs->gamma_set(crtc, ms->lut_r, ms->lut_g, ms->lut_b, 256);
}
}
static Bool
drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
VisualPtr visual;
if (!drv_set_master(pScrn))
return FALSE;
pScrn->pScreen = pScreen;
/* HW dependent - FIXME */
pScrn->displayWidth = pScrn->virtualX;
miClearVisualTypes();
if (!miSetVisualTypes(pScrn->depth,
miGetDefaultVisualMask(pScrn->depth),
pScrn->rgbBits, pScrn->defaultVisual))
return FALSE;
if (!miSetPixmapDepths())
return FALSE;
pScrn->memPhysBase = 0;
pScrn->fbOffset = 0;
if (!fbScreenInit(pScreen, NULL,
pScrn->virtualX, pScrn->virtualY,
pScrn->xDpi, pScrn->yDpi,
pScrn->displayWidth, pScrn->bitsPerPixel))
return FALSE;
if (pScrn->bitsPerPixel > 8) {
/* Fixup RGB ordering */
visual = pScreen->visuals + pScreen->numVisuals;
while (--visual >= pScreen->visuals) {
if ((visual->class | DynamicClass) == DirectColor) {
visual->offsetRed = pScrn->offset.red;
visual->offsetGreen = pScrn->offset.green;
visual->offsetBlue = pScrn->offset.blue;
visual->redMask = pScrn->mask.red;
visual->greenMask = pScrn->mask.green;
visual->blueMask = pScrn->mask.blue;
}
}
}
fbPictureInit(pScreen, NULL, 0);
vmwgfx_wrap(ms, pScreen, BlockHandler, drv_block_handler);
vmwgfx_wrap(ms, pScreen, CreateScreenResources,
drv_create_screen_resources);
xf86SetBlackWhitePixels(pScreen);
ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
vmw_ctrl_ext_init(pScrn);
ms->xat = xa_tracker_create(ms->fd);
if (!ms->xat)
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Failed to initialize Gallium3D Xa. No 3D available.\n");
if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush)) {
FatalError("Failed to initialize SAA.\n");
}
#ifdef DRI2
ms->dri2_available = FALSE;
if (ms->xat) {
ms->dri2_available = xorg_dri2_init(pScreen);
if (!ms->dri2_available)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to initialize DRI2. "
"No direct rendring available.\n");
}
#endif
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "#################################\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Useful debugging info follows #\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "#################################\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using libkms backend.\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s.\n",
ms->accelerate_2d ? "enabled" : "disabled");
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s.\n",
ms->debug_fallback ? "enabled" : "disabled");
#ifdef DRI2
xf86DrvMsg(pScrn->scrnIndex, ms->from_3D, "3D Acceleration is disabled.\n");
#else
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled.\n");
#endif
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
miInitializeBackingStore(pScreen);
xf86SetBackingStore(pScreen);
xf86SetSilkenMouse(pScreen);
miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
/* Need to extend HWcursor support to handle mask interleave */
if (!ms->SWCursor)
xf86_cursors_init(pScreen, 64, 64,
HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
HARDWARE_CURSOR_ARGB |
HARDWARE_CURSOR_UPDATE_UNHIDDEN);
/* Must force it before EnterVT, so we are in control of VT and
* later memory should be bound when allocating, e.g rotate_mem */
pScrn->vtSema = TRUE;
pScreen->SaveScreen = xf86SaveScreen;
vmwgfx_wrap(ms, pScreen, CloseScreen, drv_close_screen);
if (!xf86CrtcScreenInit(pScreen))
return FALSE;
if (!miCreateDefColormap(pScreen))
return FALSE;
if (!xf86HandleColormaps(pScreen, 256, 8, drv_load_palette, NULL,
CMAP_PALETTED_TRUECOLOR |
CMAP_RELOAD_ON_MODE_SWITCH))
return FALSE;
xf86DPMSInit(pScreen, xf86DPMSSet, 0);
if (serverGeneration == 1)
xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
vmwgfx_wrap(ms, pScrn, EnterVT, drv_enter_vt);
vmwgfx_wrap(ms, pScrn, LeaveVT, drv_leave_vt);
vmwgfx_wrap(ms, pScrn, AdjustFrame, drv_adjust_frame);
/*
* Must be called _after_ function wrapping.
*/
xorg_xv_init(pScreen);
return TRUE;
}
static void
drv_adjust_frame(int scrnIndex, int x, int y, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
xf86OutputPtr output = config->output[config->compat_output];
xf86CrtcPtr crtc = output->crtc;
if (crtc && crtc->enabled) {
// crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
// RR_Rotate_0, x, y);
crtc->x = output->initial_x + x;
crtc->y = output->initial_y + y;
}
}
static void
drv_free_screen(int scrnIndex, int flags)
{
drv_free_rec(xf86Screens[scrnIndex]);
}
static void
drv_leave_vt(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
modesettingPtr ms = modesettingPTR(pScrn);
vmwgfx_cursor_bypass(ms->fd, 0, 0);
vmwgfx_disable_scanout(pScrn);
if (drmDropMaster(ms->fd))
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"drmDropMaster failed: %s\n", strerror(errno));
ms->isMaster = FALSE;
pScrn->vtSema = FALSE;
}
/*
* This gets called when gaining control of the VT, and from ScreenInit().
*/
static Bool
drv_enter_vt(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
if (!drv_set_master(pScrn))
return FALSE;
if (!xf86SetDesiredModes(pScrn))
return FALSE;
return TRUE;
}
static Bool
drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
}
static Bool
drv_close_screen(int scrnIndex, ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
modesettingPtr ms = modesettingPTR(pScrn);
if (ms->cursor) {
FreeCursor(ms->cursor, None);
ms->cursor = NULL;
}
#ifdef DRI2
if (ms->dri2_available)
xorg_dri2_close(pScreen);
#endif
if (pScrn->vtSema)
pScrn->LeaveVT(scrnIndex, 0);
pScrn->vtSema = FALSE;
vmwgfx_unwrap(ms, pScrn, EnterVT);
vmwgfx_unwrap(ms, pScrn, LeaveVT);
vmwgfx_unwrap(ms, pScrn, AdjustFrame);
vmwgfx_unwrap(ms, pScreen, CloseScreen);
vmwgfx_unwrap(ms, pScreen, BlockHandler);
vmwgfx_unwrap(ms, pScreen, CreateScreenResources);
if (ms->xat)
xa_tracker_destroy(ms->xat);
return (*pScreen->CloseScreen) (scrnIndex, pScreen);
}
static ModeStatus
drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
return MODE_OK;
}
/* vim: set sw=4 ts=8 sts=4: */

167
vmwgfx/vmwgfx_driver.h Normal file
View File

@@ -0,0 +1,167 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright n<otice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Author: Alan Hourihane <alanh@tungstengraphics.com>
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifndef _VMWGFX_DRIVER_H_
#define _VMWGFX_DRIVER_H_
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <drm.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <xorg-server.h>
#include <xf86.h>
#include <xf86Crtc.h>
#include <xf86xv.h>
#include <xa_tracker.h>
#define DRV_ERROR(msg) xf86DrvMsg(pScrn->scrnIndex, X_ERROR, msg);
#define debug_printf(...)
typedef struct
{
int lastInstance;
int refCount;
ScrnInfoPtr pScrn_1;
ScrnInfoPtr pScrn_2;
} EntRec, *EntPtr;
#define XORG_NR_FENCES 3
enum xorg_throttling_reason {
THROTTLE_RENDER,
THROTTLE_SWAP
};
typedef struct _modesettingRec
{
/* drm */
int fd;
/* X */
EntPtr entityPrivate;
int Chipset;
EntityInfoPtr pEnt;
struct pci_device *PciInfo;
/* Accel */
Bool accelerate_2d;
Bool debug_fallback;
Bool noAccel;
Bool SWCursor;
CursorPtr cursor;
Bool no3D;
Bool from_3D;
Bool isMaster;
/* Broken-out options. */
OptionInfoPtr Options;
ScreenBlockHandlerProcPtr saved_BlockHandler;
CreateScreenResourcesProcPtr saved_CreateScreenResources;
CloseScreenProcPtr saved_CloseScreen;
Bool (*saved_EnterVT)(int, int);
void (*saved_LeaveVT)(int, int);
void (*saved_AdjustFrame)(int, int, int, int);
uint16_t lut_r[256], lut_g[256], lut_b[256];
Bool check_fb_size;
size_t max_fb_size;
struct xa_tracker *xat;
#ifdef DRI2
Bool dri2_available;
#endif
} modesettingRec, *modesettingPtr;
#define modesettingPTR(p) ((modesettingPtr)((p)->driverPrivate))
void xorg_flush(ScreenPtr pScreen);
/***********************************************************************
* xorg_dri2.c
*/
Bool
xorg_dri2_init(ScreenPtr pScreen);
void
xorg_dri2_close(ScreenPtr pScreen);
/***********************************************************************
* xorg_crtc.c
*/
void
xorg_crtc_init(ScrnInfoPtr pScrn);
void
xorg_crtc_cursor_destroy(xf86CrtcPtr crtc);
void
vmwgfx_disable_scanout(ScrnInfoPtr pScrn);
PixmapPtr
crtc_get_scanout(xf86CrtcPtr crtc);
/***********************************************************************
* xorg_output.c
*/
void
xorg_output_init(ScrnInfoPtr pScrn);
unsigned
xorg_output_get_id(xf86OutputPtr output);
/***********************************************************************
* xorg_xv.c
*/
void
xorg_xv_init(ScreenPtr pScreen);
XF86VideoAdaptorPtr
vmw_video_init_adaptor(ScrnInfoPtr pScrn);
void
vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports);
int
vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
RegionPtr region, uint32_t handle);
void
vmw_ctrl_ext_init(ScrnInfoPtr pScrn);
#endif /* _XORG_TRACKER_H_ */

507
vmwgfx/vmwgfx_drmi.c Normal file
View File

@@ -0,0 +1,507 @@
/*
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdint.h>
#include <errno.h>
#include <sys/mman.h>
#include <drm/vmwgfx_drm.h>
#include <xf86drm.h>
#include "vmwgfx_drmi.h"
#define uint32 uint32_t
#define int32 int32_t
#define uint16 uint16_t
#define uint8 uint8_t
#include "svga3d_reg.h"
#include "vmwgfx_driver.h"
static int
vmwgfx_fence_wait(int drm_fd, uint64_t seq)
{
struct drm_vmw_fence_wait_arg farg;
memset(&farg, 0, sizeof(farg));
farg.sequence = seq;
farg.cookie_valid = 0;
return drmCommandWriteRead(drm_fd, DRM_VMW_FENCE_WAIT, &farg,
sizeof(farg));
}
int
vmwgfx_present_readback(int drm_fd, RegionPtr region)
{
BoxPtr clips = REGION_RECTS(region);
unsigned int num_clips = REGION_NUM_RECTS(region);
struct drm_vmw_execbuf_arg arg;
struct drm_vmw_fence_rep rep;
int ret;
unsigned int size;
unsigned i;
SVGA3dRect *cr;
struct {
SVGA3dCmdHeader header;
SVGA3dRect cr;
} *cmd;
if (num_clips == 0)
return 0;
size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr);
cmd = malloc(size);
if (!cmd)
return -1;
cmd->header.id = SVGA_3D_CMD_PRESENT_READBACK;
cmd->header.size = num_clips * sizeof(cmd->cr);
for (i=0, cr = &cmd->cr; i < num_clips; i++, cr++, clips++) {
cr->x = (uint16_t) clips->x1;
cr->y = (uint16_t) clips->y1;
cr->w = (uint16_t) (clips->x2 - clips->x1);
cr->h = (uint16_t) (clips->y2 - clips->y1);
#if 0
LogMessage(X_INFO,
"Readback x: %u y: %u srcx: %u srcy: %u w: %u h: %u\n",
cr->x, cr->y, cr->x, cr->y, cr->w, cr->h);
#endif
}
memset(&arg, 0, sizeof(arg));
memset(&rep, 0, sizeof(rep));
rep.error = -EFAULT;
arg.fence_rep = (unsigned long)&rep;
arg.commands = (unsigned long)cmd;
arg.command_size = size;
arg.throttle_us = 0;
ret = drmCommandWrite(drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
if (ret)
LogMessage(X_ERROR, "Present readback error %s.\n", strerror(-ret));
free(cmd);
/*
* Sync to avoid racing with Xorg SW rendering.
*/
if (rep.error == 0) {
ret = vmwgfx_fence_wait(drm_fd, rep.fence_seq);
if (ret)
LogMessage(X_ERROR, "Present readback fence wait error %s.\n",
strerror(-ret));
}
return 0;
}
int
vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
RegionPtr region, uint32_t handle)
{
BoxPtr clips = REGION_RECTS(region);
unsigned int num_clips = REGION_NUM_RECTS(region);
struct drm_vmw_execbuf_arg arg;
struct drm_vmw_fence_rep rep;
int ret;
unsigned int size;
unsigned i;
SVGA3dCopyRect *cr;
struct {
SVGA3dCmdHeader header;
SVGA3dCmdPresent body;
SVGA3dCopyRect cr;
} *cmd;
if (num_clips == 0)
return 0;
size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr);
cmd = malloc(size);
if (!cmd)
return -1;
cmd->header.id = SVGA_3D_CMD_PRESENT;
cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cr);
cmd->body.sid = handle;
for (i=0, cr = &cmd->cr; i < num_clips; i++, cr++, clips++) {
cr->x = (uint16_t) clips->x1 + dst_x;
cr->y = (uint16_t) clips->y1 + dst_y;
cr->srcx = (uint16_t) clips->x1;
cr->srcy = (uint16_t) clips->y1;
cr->w = (uint16_t) (clips->x2 - clips->x1);
cr->h = (uint16_t) (clips->y2 - clips->y1);
#if 0
LogMessage(X_INFO, "Present: x: %u y: %u srcx: %u srcy: %u w: %u h: %u\n",
cr->x, cr->y, cr->srcx, cr->srcy, cr->w, cr->h);
#endif
}
memset(&arg, 0, sizeof(arg));
memset(&rep, 0, sizeof(rep));
rep.error = -EFAULT;
arg.fence_rep = (unsigned long)&rep;
arg.commands = (unsigned long)cmd;
arg.command_size = size;
arg.throttle_us = 0;
ret = drmCommandWrite(drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
if (ret) {
LogMessage(X_ERROR, "Present error %s.\n", strerror(-ret));
}
free(cmd);
return 0;
}
struct vmwgfx_int_dmabuf {
struct vmwgfx_dmabuf buf;
uint64_t map_handle;
uint64_t sync_handle;
int sync_valid;
int drm_fd;
uint32_t map_count;
void *addr;
};
static inline struct vmwgfx_int_dmabuf *
vmwgfx_int_dmabuf(struct vmwgfx_dmabuf *buf)
{
return (struct vmwgfx_int_dmabuf *) buf;
}
struct vmwgfx_dmabuf*
vmwgfx_dmabuf_alloc(int drm_fd, size_t size)
{
union drm_vmw_alloc_dmabuf_arg arg;
struct vmwgfx_dmabuf *buf;
struct vmwgfx_int_dmabuf *ibuf;
int ret;
ibuf = calloc(1, sizeof(*ibuf));
if (!ibuf)
return NULL;
buf = &ibuf->buf;
memset(&arg, 0, sizeof(arg));
arg.req.size = size;
ret = drmCommandWriteRead(drm_fd, DRM_VMW_ALLOC_DMABUF, &arg,
sizeof(arg));
if (ret)
goto out_kernel_fail;
ibuf = vmwgfx_int_dmabuf(buf);
ibuf->map_handle = arg.rep.map_handle;
ibuf->drm_fd = drm_fd;
buf->handle = arg.rep.handle;
buf->gmr_id = arg.rep.cur_gmr_id;
buf->gmr_offset = arg.rep.cur_gmr_offset;
buf->size = size;
return buf;
out_kernel_fail:
free(buf);
return NULL;
}
void *
vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf)
{
struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
if (ibuf->addr)
return ibuf->addr;
ibuf->addr = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
ibuf->drm_fd, ibuf->map_handle);
if (ibuf->addr == MAP_FAILED) {
ibuf->addr = NULL;
return NULL;
}
ibuf->map_count++;
return ibuf->addr;
}
void
vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf)
{
struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
if (--ibuf->map_count)
return;
/*
* It's a pretty important performance optimzation not to call
* munmap here, although we should watch out for cases where we might fill
* the virtual memory space of the process.
*/
}
void
vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf)
{
struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
struct drm_vmw_unref_dmabuf_arg arg;
if (ibuf->addr) {
munmap(ibuf->addr, buf->size);
ibuf->addr = NULL;
}
memset(&arg, 0, sizeof(arg));
arg.handle = buf->handle;
(void) drmCommandWrite(ibuf->drm_fd, DRM_VMW_UNREF_DMABUF, &arg,
sizeof(arg));
free(buf);
}
int
vmwgfx_dma(unsigned int host_x, unsigned int host_y,
RegionPtr region, struct vmwgfx_dmabuf *buf,
uint32_t buf_pitch, uint32_t surface_handle, int to_surface)
{
BoxPtr clips = REGION_RECTS(region);
unsigned int num_clips = REGION_NUM_RECTS(region);
struct drm_vmw_execbuf_arg arg;
struct drm_vmw_fence_rep rep;
int ret;
unsigned int size;
unsigned i;
SVGA3dCopyBox *cb;
SVGA3dCmdSurfaceDMASuffix *suffix;
SVGA3dCmdSurfaceDMA *body;
struct vmwgfx_int_dmabuf *ibuf = vmwgfx_int_dmabuf(buf);
struct {
SVGA3dCmdHeader header;
SVGA3dCmdSurfaceDMA body;
SVGA3dCopyBox cb;
} *cmd;
if (num_clips == 0)
return 0;
size = sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cb) +
sizeof(*suffix);
cmd = malloc(size);
if (!cmd)
return -1;
cmd->header.id = SVGA_3D_CMD_SURFACE_DMA;
cmd->header.size = sizeof(cmd->body) + num_clips * sizeof(cmd->cb) +
sizeof(*suffix);
cb = &cmd->cb;
suffix = (SVGA3dCmdSurfaceDMASuffix *) &cb[num_clips];
suffix->suffixSize = sizeof(*suffix);
suffix->maximumOffset = (uint32_t) -1;
suffix->flags.discard = 0;
suffix->flags.unsynchronized = 0;
suffix->flags.reserved = 0;
body = &cmd->body;
body->guest.ptr.gmrId = buf->gmr_id;
body->guest.ptr.offset = buf->gmr_offset;
body->guest.pitch = buf_pitch;
body->host.sid = surface_handle;
body->host.face = 0;
body->host.mipmap = 0;
body->transfer = (to_surface ? SVGA3D_WRITE_HOST_VRAM :
SVGA3D_READ_HOST_VRAM);
for (i=0; i < num_clips; i++, cb++, clips++) {
cb->x = (uint16_t) clips->x1 + host_x;
cb->y = (uint16_t) clips->y1 + host_y;
cb->z = 0;
cb->srcx = (uint16_t) clips->x1;
cb->srcy = (uint16_t) clips->y1;
cb->srcz = 0;
cb->w = (uint16_t) (clips->x2 - clips->x1);
cb->h = (uint16_t) (clips->y2 - clips->y1);
cb->d = 1;
#if 0
LogMessage(X_INFO, "DMA! x: %u y: %u srcx: %u srcy: %u w: %u h: %u %s\n",
cb->x, cb->y, cb->srcx, cb->srcy, cb->w, cb->h,
to_surface ? "to" : "from");
#endif
}
memset(&arg, 0, sizeof(arg));
memset(&rep, 0, sizeof(rep));
rep.error = -EFAULT;
arg.fence_rep = (unsigned long)&rep;
arg.commands = (unsigned long)cmd;
arg.command_size = size;
arg.throttle_us = 0;
ret = drmCommandWrite(ibuf->drm_fd, DRM_VMW_EXECBUF, &arg, sizeof(arg));
if (ret) {
LogMessage(X_ERROR, "DMA error %s.\n", strerror(-ret));
}
free(cmd);
if (!to_surface && rep.error == 0) {
ret = vmwgfx_fence_wait(ibuf->drm_fd, rep.fence_seq);
if (ret)
LogMessage(X_ERROR, "DMA from host fence wait error %s.\n",
strerror(-ret));
}
return 0;
}
static int
vmwgfx_get_param(int drm_fd, uint32_t param, uint64_t *out)
{
struct drm_vmw_getparam_arg gp_arg;
int ret;
memset(&gp_arg, 0, sizeof(gp_arg));
gp_arg.param = param;
ret = drmCommandWriteRead(drm_fd, DRM_VMW_GET_PARAM,
&gp_arg, sizeof(gp_arg));
if (ret == 0) {
*out = gp_arg.value;
}
return ret;
}
int
vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree)
{
uint64_t v1, v2;
int ret;
ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_STREAMS, &v1);
if (ret)
return ret;
ret = vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_NUM_FREE_STREAMS, &v2);
if (ret)
return ret;
*ntot = (uint32_t)v1;
*nfree = (uint32_t)v2;
return 0;
}
int
vmwgfx_claim_stream(int drm_fd, uint32_t *out)
{
struct drm_vmw_stream_arg s_arg;
int ret;
ret = drmCommandRead(drm_fd, DRM_VMW_CLAIM_STREAM,
&s_arg, sizeof(s_arg));
if (ret)
return -1;
*out = s_arg.stream_id;
return 0;
}
int
vmwgfx_unref_stream(int drm_fd, uint32_t stream_id)
{
struct drm_vmw_stream_arg s_arg;
int ret;
memset(&s_arg, 0, sizeof(s_arg));
s_arg.stream_id = stream_id;
ret = drmCommandWrite(drm_fd, DRM_VMW_UNREF_STREAM,
&s_arg, sizeof(s_arg));
return 0;
}
int
vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot)
{
struct drm_vmw_cursor_bypass_arg arg;
int ret;
memset(&arg, 0, sizeof(arg));
arg.flags = DRM_VMW_CURSOR_BYPASS_ALL;
arg.xhot = xhot;
arg.yhot = yhot;
ret = drmCommandWrite(drm_fd, DRM_VMW_CURSOR_BYPASS,
&arg, sizeof(arg));
return ret;
}
int
vmwgfx_max_fb_size(int drm_fd, size_t *size)
{
drmVersionPtr ver;
int ret = -1;
uint64_t tmp_size;
ver = drmGetVersion(drm_fd);
if (ver == NULL ||
!(ver->version_major > 1 ||
(ver->version_major == 1 && ver->version_minor >= 3)))
goto out;
if (vmwgfx_get_param(drm_fd, DRM_VMW_PARAM_MAX_FB_SIZE, &tmp_size) != 0)
goto out;
*size = tmp_size;
ret = 0;
out:
drmFreeVersion(ver);
return ret;
}

81
vmwgfx/vmwgfx_drmi.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifndef _VMWGFX_DRMI_H_
#define _VMWGFX_DRMI_H_
#include <xorg-server.h>
#include <regionstr.h>
#include <stdint.h>
struct vmwgfx_dma_ctx;
extern int
vmwgfx_present_readback(int drm_fd, RegionPtr region);
extern int
vmwgfx_present(int drm_fd, unsigned int dst_x, unsigned int dst_y,
RegionPtr region, uint32_t handle);
struct vmwgfx_dmabuf {
uint32_t handle;
uint32_t gmr_id;
uint32_t gmr_offset;
size_t size;
};
extern struct vmwgfx_dmabuf*
vmwgfx_dmabuf_alloc(int drm_fd, size_t size);
extern void
vmwgfx_dmabuf_destroy(struct vmwgfx_dmabuf *buf);
extern void *
vmwgfx_dmabuf_map(struct vmwgfx_dmabuf *buf);
extern void
vmwgfx_dmabuf_unmap(struct vmwgfx_dmabuf *buf);
extern int
vmwgfx_dma(unsigned int host_x, unsigned int host_y,
RegionPtr region, struct vmwgfx_dmabuf *buf,
uint32_t buf_pitch, uint32_t surface_handle, int to_surface);
extern int
vmwgfx_num_streams(int drm_fd, uint32_t *ntot, uint32_t *nfree);
extern int
vmwgfx_claim_stream(int drm_fd, uint32_t *out);
extern int
vmwgfx_unref_stream(int drm_fd, uint32_t stream_id);
int
vmwgfx_cursor_bypass(int drm_fd, int xhot, int yhot);
int
vmwgfx_max_fb_size(int drm_fd, size_t *size);
#endif

304
vmwgfx/vmwgfx_output.c Normal file
View File

@@ -0,0 +1,304 @@
/*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*
* Author: Alan Hourihane <alanh@tungstengraphics.com>
* Author: Jakob Bornecrantz <wallbraker@gmail.com>
*
*/
#include "xorg-server.h"
#include <xf86.h>
#include <xf86i2c.h>
#include <xf86Crtc.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef HAVE_XEXTPROTO_71
#include <X11/extensions/dpmsconst.h>
#else
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#endif
#include "vmwgfx_driver.h"
struct output_private
{
drmModeConnectorPtr drm_connector;
int c;
};
static char *output_enum_list[] = {
"Unknown",
"VGA",
"DVI",
"DVI",
"DVI",
"Composite",
"SVIDEO",
"LVDS",
"CTV",
"DIN",
"DP",
"HDMI",
"HDMI",
};
static void
output_create_resources(xf86OutputPtr output)
{
#ifdef RANDR_12_INTERFACE
#endif /* RANDR_12_INTERFACE */
}
static void
output_dpms(xf86OutputPtr output, int mode)
{
}
static xf86OutputStatus
output_detect(xf86OutputPtr output)
{
modesettingPtr ms = modesettingPTR(output->scrn);
struct output_private *priv = output->driver_private;
drmModeConnectorPtr drm_connector;
xf86OutputStatus status;
drm_connector = drmModeGetConnector(ms->fd, priv->drm_connector->connector_id);
if (drm_connector) {
drmModeFreeConnector(priv->drm_connector);
priv->drm_connector = drm_connector;
} else {
drm_connector = priv->drm_connector;
}
switch (drm_connector->connection) {
case DRM_MODE_CONNECTED:
status = XF86OutputStatusConnected;
break;
case DRM_MODE_DISCONNECTED:
status = XF86OutputStatusDisconnected;
break;
default:
status = XF86OutputStatusUnknown;
}
return status;
}
static DisplayModePtr
output_get_modes(xf86OutputPtr output)
{
struct output_private *priv = output->driver_private;
drmModeConnectorPtr drm_connector = priv->drm_connector;
drmModeModeInfoPtr drm_mode = NULL;
DisplayModePtr modes = NULL, mode = NULL;
int i;
for (i = 0; i < drm_connector->count_modes; i++) {
drm_mode = &drm_connector->modes[i];
if (drm_mode) {
mode = calloc(1, sizeof(DisplayModeRec));
if (!mode)
continue;
mode->Clock = drm_mode->clock;
mode->HDisplay = drm_mode->hdisplay;
mode->HSyncStart = drm_mode->hsync_start;
mode->HSyncEnd = drm_mode->hsync_end;
mode->HTotal = drm_mode->htotal;
mode->VDisplay = drm_mode->vdisplay;
mode->VSyncStart = drm_mode->vsync_start;
mode->VSyncEnd = drm_mode->vsync_end;
mode->VTotal = drm_mode->vtotal;
mode->Flags = drm_mode->flags;
mode->HSkew = drm_mode->hskew;
mode->VScan = drm_mode->vscan;
mode->VRefresh = xf86ModeVRefresh(mode);
mode->Private = (void *)drm_mode;
mode->type = 0;
if (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
mode->type |= M_T_PREFERRED;
if (drm_mode->type & DRM_MODE_TYPE_DRIVER)
mode->type |= M_T_DRIVER;
xf86SetModeDefaultName(mode);
modes = xf86ModesAdd(modes, mode);
xf86PrintModeline(0, mode);
}
}
return modes;
}
static int
output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
{
// modesettingPtr ms = modesettingPTR(output->scrn);
// CustomizerPtr cust = ms->cust;
#if 0
if (cust && cust->winsys_check_fb_size &&
!cust->winsys_check_fb_size(cust, pMode->HDisplay *
output->scrn->bitsPerPixel / 8,
pMode->VDisplay))
return MODE_BAD;
#endif
return MODE_OK;
}
#ifdef RANDR_12_INTERFACE
static Bool
output_set_property(xf86OutputPtr output, Atom property, RRPropertyValuePtr value)
{
return TRUE;
}
#endif /* RANDR_12_INTERFACE */
#ifdef RANDR_13_INTERFACE
static Bool
output_get_property(xf86OutputPtr output, Atom property)
{
return TRUE;
}
#endif /* RANDR_13_INTERFACE */
static void
output_destroy(xf86OutputPtr output)
{
struct output_private *priv = output->driver_private;
drmModeFreeConnector(priv->drm_connector);
free(priv);
output->driver_private = NULL;
}
static const xf86OutputFuncsRec output_funcs = {
.create_resources = output_create_resources,
#ifdef RANDR_12_INTERFACE
.set_property = output_set_property,
#endif
#ifdef RANDR_13_INTERFACE
.get_property = output_get_property,
#endif
.dpms = output_dpms,
.detect = output_detect,
.get_modes = output_get_modes,
.mode_valid = output_mode_valid,
.destroy = output_destroy,
};
void
xorg_output_init(ScrnInfoPtr pScrn)
{
modesettingPtr ms = modesettingPTR(pScrn);
xf86OutputPtr output;
drmModeResPtr res;
drmModeConnectorPtr drm_connector = NULL;
drmModeEncoderPtr drm_encoder = NULL;
struct output_private *priv;
char name[32];
int c, v, p;
res = drmModeGetResources(ms->fd);
if (res == 0) {
DRV_ERROR("Failed drmModeGetResources\n");
return;
}
for (c = 0; c < res->count_connectors; c++) {
drm_connector = drmModeGetConnector(ms->fd, res->connectors[c]);
if (!drm_connector)
goto out;
#if 0
for (p = 0; p < drm_connector->count_props; p++) {
drmModePropertyPtr prop;
prop = drmModeGetProperty(ms->fd, drm_connector->props[p]);
name = NULL;
if (prop) {
ErrorF("VALUES %d\n", prop->count_values);
for (v = 0; v < prop->count_values; v++)
ErrorF("%s %lld\n", prop->name, prop->values[v]);
}
}
#else
(void)p;
(void)v;
#endif
snprintf(name, 32, "%s%d",
output_enum_list[drm_connector->connector_type],
drm_connector->connector_type_id);
priv = calloc(sizeof(*priv), 1);
if (!priv) {
continue;
}
output = xf86OutputCreate(pScrn, &output_funcs, name);
if (!output) {
free(priv);
continue;
}
drm_encoder = drmModeGetEncoder(ms->fd, drm_connector->encoders[0]);
if (drm_encoder) {
output->possible_crtcs = drm_encoder->possible_crtcs;
output->possible_clones = drm_encoder->possible_clones;
} else {
output->possible_crtcs = 0;
output->possible_clones = 0;
}
priv->c = c;
priv->drm_connector = drm_connector;
output->driver_private = priv;
output->subpixel_order = SubPixelHorizontalRGB;
output->interlaceAllowed = FALSE;
output->doubleScanAllowed = FALSE;
}
out:
drmModeFreeResources(res);
}
unsigned
xorg_output_get_id(xf86OutputPtr output)
{
struct output_private *priv = output->driver_private;
return priv->drm_connector->connector_id;
}
/* vim: set sw=4 ts=8 sts=4: */

893
vmwgfx/vmwgfx_overlay.c Normal file
View File

@@ -0,0 +1,893 @@
/*
* Copyright 2007-2011 by VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*
*/
/*
* vmwarevideo.c --
*
* Xv extension support.
* See http://www.xfree86.org/current/DESIGN16.html
*
*/
#include "xf86xv.h"
#include "fourcc.h"
#define debug_printf(...)
/*
* We can't incude svga_types.h due to conflicting types for Bool.
*/
typedef int64_t int64;
typedef uint64_t uint64;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int8_t int8;
typedef uint8_t uint8;
#include "../src/svga_reg.h"
#include "../src/svga_escape.h"
#include "../src/svga_overlay.h"
#include <X11/extensions/Xv.h>
#include "xf86drm.h"
#include <drm/vmwgfx_drm.h>
#include "vmwgfx_drmi.h"
#include "vmwgfx_driver.h"
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
/*
* Number of videos that can be played simultaneously
*/
#define VMWARE_VID_NUM_PORTS 1
/*
* Using a dark shade as the default colorKey
*/
#define VMWARE_VIDEO_COLORKEY 0x100701
/*
* Maximum dimensions
*/
#define VMWARE_VID_MAX_WIDTH 2048
#define VMWARE_VID_MAX_HEIGHT 2048
#define VMWARE_VID_NUM_ENCODINGS 1
static XF86VideoEncodingRec vmwareVideoEncodings[] =
{
{
0,
"XV_IMAGE",
VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT,
{1, 1}
}
};
#define VMWARE_VID_NUM_FORMATS 2
static XF86VideoFormatRec vmwareVideoFormats[] =
{
{ 16, TrueColor},
{ 24, TrueColor}
};
#define VMWARE_VID_NUM_IMAGES 3
static XF86ImageRec vmwareVideoImages[] =
{
XVIMAGE_YV12,
XVIMAGE_YUY2,
XVIMAGE_UYVY
};
#define VMWARE_VID_NUM_ATTRIBUTES 2
static XF86AttributeRec vmwareVideoAttributes[] =
{
{
XvGettable | XvSettable,
0x000000,
0xffffff,
"XV_COLORKEY"
},
{
XvGettable | XvSettable,
0,
1,
"XV_AUTOPAINT_COLORKEY"
}
};
/*
* Video frames are stored in a circular list of buffers.
* Must be power or two, See vmw_video_port_play.
*/
#define VMWARE_VID_NUM_BUFFERS 1
/*
* Defines the structure used to hold and pass video data to the host
*/
struct vmw_video_buffer
{
int size;
void *data;
struct vmwgfx_dmabuf *buf;
};
/**
* Structure representing a single video stream, aka port.
*
* Ports maps one to one to a SVGA stream. Port is just
* what Xv calls a SVGA stream.
*/
struct vmwgfx_overlay_port
{
/*
* Function prototype same as XvPutImage.
*
* This is either set to vmw_video_port_init or vmw_video_port_play.
* At init this function is set to port_init. In port_init we set it
* to port_play and call it, after initializing the struct.
*/
int (*play)(ScrnInfoPtr, struct vmwgfx_overlay_port *,
short, short, short, short, short,
short, short, short, int, unsigned char*,
short, short, RegionPtr);
/* values to go into the SVGAOverlayUnit */
uint32 streamId;
uint32 colorKey;
uint32 flags;
/* round robin of buffers */
unsigned currBuf;
struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS];
/* properties that applies to all buffers */
int size;
int pitches[3];
int offsets[3];
/* things for X */
RegionRec clipBoxes;
Bool isAutoPaintColorkey;
int drm_fd;
};
/*
* Callback functions exported to Xv, prefixed with vmw_xv_*.
*/
static int vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int image,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data,
DrawablePtr dst);
static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
unsigned short *width,
unsigned short *height, int *pitches,
int *offsets);
static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 value, pointer data);
static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 *value, pointer data);
static void vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
short vid_w, short vid_h, short drw_w,
short drw_h, unsigned int *p_w,
unsigned int *p_h, pointer data);
/*
* Local functions.
*/
static int vmw_video_port_init(ScrnInfoPtr pScrn,
struct vmwgfx_overlay_port *port,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes);
static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes);
static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port);
static int vmw_video_buffer_alloc(int drm_fd, int size,
struct vmw_video_buffer *out);
static int vmw_video_buffer_free(struct vmw_video_buffer *out);
static struct vmwgfx_overlay_port *
vmwgfx_overlay_port_create(int drm_fd, ScreenPtr pScreen)
{
struct vmwgfx_overlay_port *port = calloc(1, sizeof(*port));
if (!port)
return NULL;
port->drm_fd = drm_fd;
port->play = vmw_video_port_init;
port->flags = SVGA_VIDEO_FLAG_COLORKEY;
port->colorKey = VMWARE_VIDEO_COLORKEY;
port->isAutoPaintColorkey = TRUE;
return port;
}
void
vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports)
{
if (free_ports) {
int i;
for(i=0; i<adaptor->nPorts; ++i) {
free(adaptor->pPortPrivates[i].ptr);
}
}
free(adaptor->pPortPrivates);
xf86XVFreeVideoAdaptorRec(adaptor);
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_init_adaptor --
*
* Initializes a XF86VideoAdaptor structure with the capabilities and
* functions supported by this video driver.
*
* Results:
* On success initialized XF86VideoAdaptor struct or NULL on error
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
XF86VideoAdaptorPtr
vmw_video_init_adaptor(ScrnInfoPtr pScrn)
{
XF86VideoAdaptorPtr adaptor;
modesettingPtr ms = modesettingPTR(pScrn);
int i;
DevUnion *dev_unions;
uint32_t ntot, nfree;
if (vmwgfx_num_streams(ms->fd, &ntot, &nfree) != 0) {
debug_printf("No stream ioctl support\n");
return NULL;
}
if (nfree == 0) {
debug_printf("No free streams\n");
return NULL;
}
adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
dev_unions = calloc(VMWARE_VID_NUM_PORTS, sizeof(DevUnion));
if (adaptor == NULL || dev_unions == NULL) {
xf86XVFreeVideoAdaptorRec(adaptor);
free(dev_unions);
return NULL;
}
adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
/**
* Note: CLIP_TO_VIEWPORT was removed from the flags, since with the
* crtc/output based modesetting, the viewport is not updated on
* RandR modeswitches. Hence the video may incorrectly be clipped away.
* The correct approach, (if needed) would be to clip against the
* scanout area union of all active crtcs. Revisit if needed.
*/
adaptor->flags = VIDEO_OVERLAID_IMAGES;
adaptor->name = "VMware Overlay Video Engine";
adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
adaptor->pEncodings = vmwareVideoEncodings;
adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
adaptor->pFormats = vmwareVideoFormats;
adaptor->nPorts = VMWARE_VID_NUM_PORTS;
adaptor->pPortPrivates = dev_unions;
for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
struct vmwgfx_overlay_port *priv =
vmwgfx_overlay_port_create(ms->fd, pScrn->pScreen);
adaptor->pPortPrivates[i].ptr = (pointer) priv;
}
adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
adaptor->pAttributes = vmwareVideoAttributes;
adaptor->nImages = VMWARE_VID_NUM_IMAGES;
adaptor->pImages = vmwareVideoImages;
adaptor->PutVideo = NULL;
adaptor->PutStill = NULL;
adaptor->GetVideo = NULL;
adaptor->GetStill = NULL;
adaptor->StopVideo = vmw_xv_stop_video;
adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
adaptor->QueryBestSize = vmw_xv_query_best_size;
adaptor->PutImage = vmw_xv_put_image;
adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
return adaptor;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_port_init --
*
* Initializes a video stream in response to the first PutImage() on a
* video stream. The process goes as follows:
* - Figure out characteristics according to format
* - Allocate offscreen memory
* - Pass on video to Play() functions
*
* Results:
* Success or XvBadAlloc on failure.
*
* Side effects:
* Video stream is initialized and its first frame sent to the host
* (done by VideoPlay() function called at the end)
*
*-----------------------------------------------------------------------------
*/
static int
vmw_video_port_init(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes)
{
unsigned short w, h;
int i, ret;
debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
ret = vmwgfx_claim_stream(port->drm_fd, &port->streamId);
if (ret != 0)
return XvBadAlloc;
w = width;
h = height;
/* init all the format attributes, used for buffers */
port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
port->pitches, port->offsets);
if (port->size == -1) {
ret = XvBadAlloc;
goto out_bad_size;
}
for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
ret = vmw_video_buffer_alloc(port->drm_fd, port->size, &port->bufs[i]);
if (ret != Success)
goto out_no_buffer;
}
port->currBuf = 0;
REGION_NULL(pScrn->pScreen, &port->clipBoxes);
port->play = vmw_video_port_play;
return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
drw_w, drw_h, format, buf, width, height, clipBoxes);
out_bad_size:
(void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
out_no_buffer:
while(i-- != 0) {
vmw_video_buffer_free(&port->bufs[i]);
}
return ret;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_port_play --
*
* Sends all the attributes associated with the video frame using the
* FIFO ESCAPE mechanism to the host.
*
* Results:
* Always returns Success.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes)
{
struct drm_vmw_control_stream_arg arg;
unsigned short w, h;
int size;
int ret;
debug_printf("\t%s: enter\n", __func__);
w = width;
h = height;
/* we don't update the ports size */
size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
port->pitches, port->offsets);
if (size != port->size) {
vmw_xv_stop_video(pScrn, port, TRUE);
return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
src_h, drw_w, drw_h, format, buf, width, height,
clipBoxes);
}
memcpy(port->bufs[port->currBuf].data, buf, port->size);
memset(&arg, 0, sizeof(arg));
arg.stream_id = port->streamId;
arg.enabled = TRUE;
arg.flags = port->flags;
arg.color_key = port->colorKey;
arg.handle = port->bufs[port->currBuf].buf->handle;
arg.format = format;
arg.size = port->size;
arg.width = w;
arg.height = h;
arg.src.x = src_x;
arg.src.y = src_y;
arg.src.w = src_w;
arg.src.h = src_h;
arg.dst.x = drw_x;
arg.dst.y = drw_y;
arg.dst.w = drw_w;
arg.dst.h = drw_h;
arg.pitch[0] = port->pitches[0];
arg.pitch[1] = port->pitches[1];
arg.pitch[2] = port->pitches[2];
arg.offset = 0;
/*
* Update the clipList and paint the colorkey, if required.
*/
if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
if (port->isAutoPaintColorkey)
xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
}
xorg_flush(pScrn->pScreen);
ret = drmCommandWrite(port->drm_fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
if (ret) {
vmw_video_port_cleanup(pScrn, port);
return XvBadAlloc;
}
if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
port->currBuf = 0;
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_port_cleanup --
*
* Frees up all resources (if any) taken by a video stream.
*
* Results:
* None.
*
* Side effects:
* Same as above.
*
*-----------------------------------------------------------------------------
*/
static void
vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port)
{
int i;
debug_printf("\t%s: enter\n", __func__);
if (port->play == vmw_video_port_init)
return;
port->play = vmw_video_port_init;
(void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
vmw_video_buffer_free(&port->bufs[i]);
}
REGION_UNINIT(pScreen->pScreen, &port->clipBoxes);
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_buffer_alloc --
*
* Allocates and map a kernel buffer to be used as data storage.
*
* Results:
* XvBadAlloc on failure, otherwise Success.
*
* Side effects:
* Calls into the kernel, sets members of out.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_video_buffer_alloc(int drm_fd, int size,
struct vmw_video_buffer *out)
{
out->buf = vmwgfx_dmabuf_alloc(drm_fd, size);
if (!out->buf)
return XvBadAlloc;
out->data = vmwgfx_dmabuf_map(out->buf);
if (!out->data) {
vmwgfx_dmabuf_destroy(out->buf);
out->buf = NULL;
return XvBadAlloc;
}
out->size = size;
debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_video_buffer_free --
*
* Frees and unmaps an allocated kernel buffer.
*
* Results:
* Success.
*
* Side effects:
* Calls into the kernel, sets members of out to 0.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_video_buffer_free(struct vmw_video_buffer *out)
{
if (out->size == 0)
return Success;
vmwgfx_dmabuf_unmap(out->buf);
vmwgfx_dmabuf_destroy(out->buf);
out->buf = NULL;
out->data = NULL;
out->size = 0;
debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_put_image --
*
* Main video playback function. It copies the passed data which is in
* the specified format (e.g. FOURCC_YV12) into the overlay.
*
* If sync is TRUE the driver should not return from this
* function until it is through reading the data from buf.
*
* Results:
* Success or XvBadAlloc on failure
*
* Side effects:
* Video port will be played(initialized if 1st frame) on success
* or will fail on error.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data,
DrawablePtr dst)
{
struct vmwgfx_overlay_port *port = data;
debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
src_x, src_y, src_w, src_h,
drw_x, drw_y, drw_w, drw_h,
width, height);
return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
drw_w, drw_h, format, buf, width, height, clipBoxes);
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_stop_video --
*
* Called when we should stop playing video for a particular stream. If
* Cleanup is FALSE, the "stop" operation is only temporary, and thus we
* don't do anything. If Cleanup is TRUE we kill the video port by
* sending a message to the host and freeing up the stream.
*
* Results:
* None.
*
* Side effects:
* See above.
*
*-----------------------------------------------------------------------------
*/
static void
vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
{
struct vmwgfx_overlay_port *port = data;
debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
if (!cleanup)
return;
vmw_video_port_cleanup(pScrn, port);
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_query_image_attributes --
*
* From the spec: This function is called to let the driver specify how data
* for a particular image of size width by height should be stored.
* Sometimes only the size and corrected width and height are needed. In
* that case pitches and offsets are NULL.
*
* Results:
* The size of the memory required for the image, or -1 on error.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
unsigned short *width, unsigned short *height,
int *pitches, int *offsets)
{
INT32 size, tmp;
if (*width > VMWARE_VID_MAX_WIDTH) {
*width = VMWARE_VID_MAX_WIDTH;
}
if (*height > VMWARE_VID_MAX_HEIGHT) {
*height = VMWARE_VID_MAX_HEIGHT;
}
*width = (*width + 1) & ~1;
if (offsets != NULL) {
offsets[0] = 0;
}
switch (format) {
case FOURCC_YV12:
*height = (*height + 1) & ~1;
size = (*width + 3) & ~3;
if (pitches) {
pitches[0] = size;
}
size *= *height;
if (offsets) {
offsets[1] = size;
}
tmp = ((*width >> 1) + 3) & ~3;
if (pitches) {
pitches[1] = pitches[2] = tmp;
}
tmp *= (*height >> 1);
size += tmp;
if (offsets) {
offsets[2] = size;
}
size += tmp;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
size = *width * 2;
if (pitches) {
pitches[0] = size;
}
size *= *height;
break;
default:
debug_printf("Query for invalid video format %d\n", format);
return -1;
}
return size;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_set_port_attribute --
*
* From the spec: A port may have particular attributes such as colorKey, hue,
* saturation, brightness or contrast. Xv clients set these
* attribute values by sending attribute strings (Atoms) to the server.
*
* Results:
* Success if the attribute exists and XvBadAlloc otherwise.
*
* Side effects:
* The respective attribute gets the new value.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 value, pointer data)
{
struct vmwgfx_overlay_port *port = data;
Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
if (attribute == xvColorKey) {
debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
port->colorKey = value;
} else if (attribute == xvAutoPaint) {
debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
port->isAutoPaintColorkey = value;
} else {
return XvBadAlloc;
}
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_get_port_attribute --
*
* From the spec: A port may have particular attributes such as hue,
* saturation, brightness or contrast. Xv clients get these
* attribute values by sending attribute strings (Atoms) to the server
*
* Results:
* Success if the attribute exists and XvBadAlloc otherwise.
*
* Side effects:
* "value" contains the requested attribute on success.
*
*-----------------------------------------------------------------------------
*/
static int
vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 *value, pointer data)
{
struct vmwgfx_overlay_port *port = data;
Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
if (attribute == xvColorKey) {
*value = port->colorKey;
} else if (attribute == xvAutoPaint) {
*value = port->isAutoPaintColorkey;
} else {
return XvBadAlloc;
}
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmw_xv_query_best_size --
*
* From the spec: QueryBestSize provides the client with a way to query what
* the destination dimensions would end up being if they were to request
* that an area vid_w by vid_h from the video stream be scaled to rectangle
* of drw_w by drw_h on the screen. Since it is not expected that all
* hardware will be able to get the target dimensions exactly, it is
* important that the driver provide this function.
*
* This function seems to never be called, but to be on the safe side
* we apply the same logic that QueryImageAttributes has for width
* and height.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static void
vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
short vid_w, short vid_h, short drw_w,
short drw_h, unsigned int *p_w,
unsigned int *p_h, pointer data)
{
*p_w = (drw_w + 1) & ~1;
*p_h = drw_h;
return;
}

1208
vmwgfx/vmwgfx_saa.c Normal file

File diff suppressed because it is too large Load Diff

94
vmwgfx/vmwgfx_saa.h Normal file
View File

@@ -0,0 +1,94 @@
/*
* Copyright 2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Thomas Hellstrom <thellstrom@vmware.com>
*/
#ifndef _VMWGFX_SAA_H_
#define _VMWGFX_SAA_H_
#include "saa.h"
#include <xa_tracker.h>
#include "vmwgfx_drmi.h"
#define VMWGFX_FLAG_FORCE_GMR (1 << 0) /* Create with GMR as backing store */
#define VMWGFX_FLAG_FORCE_SURFACE (1 << 1) /* Create with surface as backing store */
#define VMWGFX_FLAG_AVOID_HWACCEL (1 << 2) /* Avoid Hardware acceleration on this pixmap */
#define VMWGFX_FLAG_USE_PRESENT (1 << 3) /* Use presents when copying to this pixmap */
struct vmwgfx_saa_pixmap {
struct saa_pixmap base;
RegionPtr dirty_present;
RegionPtr present_damage;
RegionPtr pending_update;
RegionPtr pending_present;
uint32_t usage_flags;
uint32_t backing;
void *malloc;
struct vmwgfx_dmabuf *gmr;
struct xa_surface *hw;
int scanout_refcnt;
uint32_t fb_id;
int hw_is_dri2_fronts;
struct vmwgfx_saa_pixmap *next_dri2;
struct vmwgfx_saa_pixmap **prevnext_dri2;
};
static inline struct vmwgfx_saa_pixmap *
to_vmwgfx_saa_pixmap(struct saa_pixmap *spix)
{
return (struct vmwgfx_saa_pixmap *) spix;
}
extern Bool
vmwgfx_pixmap_validate_hw(PixmapPtr pixmap, RegionPtr region,
unsigned int add_flags,
unsigned int remove_flags);
static inline struct vmwgfx_saa_pixmap*
vmwgfx_saa_pixmap(PixmapPtr pix)
{
return to_vmwgfx_saa_pixmap(saa_get_saa_pixmap(pix));
}
extern Bool
vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
void (*present_flush)(ScreenPtr pScreen));
extern uint32_t
vmwgfx_scanout_ref(PixmapPtr pixmap);
extern void
vmwgfx_scanout_unref(PixmapPtr pixmap);
extern void
vmwgfx_scanout_refresh(PixmapPtr pixmap);
extern void
vmwgfx_remove_dri2_list(struct vmwgfx_saa_pixmap *vpix);
extern void
vmwgfx_flush_dri2(ScreenPtr pScreen);
#endif

723
vmwgfx/vmwgfx_tex_video.c Normal file
View File

@@ -0,0 +1,723 @@
/*
* Copyright 2009-2011 VMWare, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Thomas Hellstrom <thellstrom@vmware.com>
* Author: Zack Rusin <zackr@vmware.com>
*/
#include "vmwgfx_driver.h"
#include "vmwgfx_drmi.h"
#include "vmwgfx_saa.h"
#include <xf86xv.h>
#include <X11/extensions/Xv.h>
#include <fourcc.h>
#include <xa_tracker.h>
#include <xa_context.h>
/*XXX get these from pipe's texture limits */
#define IMAGE_MAX_WIDTH 2048
#define IMAGE_MAX_HEIGHT 2048
#define RES_720P_X 1280
#define RES_720P_Y 720
/* The ITU-R BT.601 conversion matrix for SDTV. */
/* original, matrix, but we transpose it to
* make the shader easier
static const float bt_601[] = {
1.0, 0.0, 1.4075, ,
1.0, -0.3455, -0.7169, 0,
1.0, 1.7790, 0., 0,
};*/
static const float bt_601[] = {
1.0, 1.0, 1.0, 0.5,
0.0, -0.3455, 1.7790, 0,
1.4075, -0.7169, 0., 0,
};
/* The ITU-R BT.709 conversion matrix for HDTV. */
/* original, but we transpose to make the conversion
* in the shader easier
static const float bt_709[] = {
1.0, 0.0, 1.581, 0,
1.0, -0.1881, -0.47, 0,
1.0, 1.8629, 0., 0,
};*/
static const float bt_709[] = {
1.0, 1.0, 1.0, 0.5,
0.0, -0.1881, 1.8629, 0,
1.581,-0.47 , 0.0, 0,
};
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
static Atom xvBrightness, xvContrast;
#define NUM_TEXTURED_ATTRIBUTES 2
static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = {
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
};
#define NUM_FORMATS 3
static XF86VideoFormatRec Formats[NUM_FORMATS] = {
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
};
static XF86VideoEncodingRec DummyEncoding[1] = {
{
0,
"XV_IMAGE",
IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
{1, 1}
}
};
#define NUM_IMAGES 3
static XF86ImageRec Images[NUM_IMAGES] = {
XVIMAGE_UYVY,
XVIMAGE_YUY2,
XVIMAGE_YV12,
};
struct xorg_xv_port_priv {
struct xa_tracker *xat;
struct xa_context *r;
struct xa_fence *fence;
RegionRec clip;
int brightness;
int contrast;
int current_set;
struct vmwgfx_dmabuf *bounce[2][3];
struct xa_surface *yuv[3];
int drm_fd;
};
static void
stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
{
struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
int i, j;
REGION_EMPTY(pScrn->pScreen, &priv->clip);
if (shutdown) {
/*
* No need to destroy the xa context or xa tracker since
* they are copied from the screen resources.
*/
xa_fence_destroy(priv->fence);
priv->fence = NULL;
for (i=0; i<3; ++i) {
if (priv->yuv[i]) {
xa_surface_destroy(priv->yuv[i]);
priv->yuv[i] = NULL;
}
for (j=0; j<2; ++j) {
if (priv->bounce[j][i]) {
vmwgfx_dmabuf_destroy(priv->bounce[j][i]);
priv->bounce[0][i] = NULL;
}
}
}
}
}
static int
set_port_attribute(ScrnInfoPtr pScrn,
Atom attribute, INT32 value, pointer data)
{
struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
if (attribute == xvBrightness) {
if ((value < -128) || (value > 127))
return BadValue;
priv->brightness = value;
} else if (attribute == xvContrast) {
if ((value < 0) || (value > 255))
return BadValue;
priv->contrast = value;
} else
return BadMatch;
return Success;
}
static int
get_port_attribute(ScrnInfoPtr pScrn,
Atom attribute, INT32 * value, pointer data)
{
struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data;
if (attribute == xvBrightness)
*value = priv->brightness;
else if (attribute == xvContrast)
*value = priv->contrast;
else
return BadMatch;
return Success;
}
static void
query_best_size(ScrnInfoPtr pScrn,
Bool motion,
short vid_w, short vid_h,
short drw_w, short drw_h,
unsigned int *p_w, unsigned int *p_h, pointer data)
{
if (vid_w > (drw_w << 1))
drw_w = vid_w >> 1;
if (vid_h > (drw_h << 1))
drw_h = vid_h >> 1;
*p_w = drw_w;
*p_h = drw_h;
}
static int
check_yuv_surfaces(struct xorg_xv_port_priv *priv, int width, int height)
{
struct xa_surface **yuv = priv->yuv;
struct vmwgfx_dmabuf **bounce = priv->bounce[priv->current_set];
int ret = 0;
int i;
size_t size;
for (i=0; i<3; ++i) {
if (!yuv[i])
yuv[i] = xa_surface_create(priv->xat, width, height, 8,
xa_type_yuv_component,
xa_format_unknown, 0);
else
ret = xa_surface_redefine(yuv[i], width, height, 8,
xa_type_yuv_component,
xa_format_unknown, 0, 0, 0);
if (ret || !yuv[i])
return BadAlloc;
size = width * height;
if (bounce[i] && (bounce[i]->size < size ||
bounce[i]->size > 2*size)) {
vmwgfx_dmabuf_destroy(bounce[i]);
bounce[i] = NULL;
}
if (!bounce[i]) {
bounce[i] = vmwgfx_dmabuf_alloc(priv->drm_fd, size);
if (!bounce[i])
return BadAlloc;
}
}
return Success;
}
static int
query_image_attributes(ScrnInfoPtr pScrn,
int id,
unsigned short *w, unsigned short *h,
int *pitches, int *offsets)
{
int size, tmp;
if (*w > IMAGE_MAX_WIDTH)
*w = IMAGE_MAX_WIDTH;
if (*h > IMAGE_MAX_HEIGHT)
*h = IMAGE_MAX_HEIGHT;
*w = (*w + 1) & ~1;
if (offsets)
offsets[0] = 0;
switch (id) {
case FOURCC_YV12:
*h = (*h + 1) & ~1;
size = (*w + 3) & ~3;
if (pitches) {
pitches[0] = size;
}
size *= *h;
if (offsets) {
offsets[1] = size;
}
tmp = ((*w >> 1) + 3) & ~3;
if (pitches) {
pitches[1] = pitches[2] = tmp;
}
tmp *= (*h >> 1);
size += tmp;
if (offsets) {
offsets[2] = size;
}
size += tmp;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
default:
size = *w << 1;
if (pitches)
pitches[0] = size;
size *= *h;
break;
}
return size;
}
static int
copy_packed_data(ScrnInfoPtr pScrn,
struct xorg_xv_port_priv *port,
int id,
unsigned char *buf,
int left,
int top,
unsigned short w, unsigned short h)
{
int i, j;
struct vmwgfx_dmabuf **bounce = port->bounce[port->current_set];
char *ymap, *vmap, *umap;
unsigned char y1, y2, u, v;
int yidx, uidx, vidx;
int y_array_size = w * h;
int ret = BadAlloc;
/*
* Here, we could use xa_surface_[map|unmap], but given the size of
* the yuv textures, that could stress the xa tracker dma buffer pool,
* particularaly with multiple videos rendering simultaneously.
*
* Instead, cheat and allocate vmwgfx dma buffers directly.
*/
ymap = (char *)vmwgfx_dmabuf_map(bounce[0]);
if (!ymap)
return BadAlloc;
umap = (char *)vmwgfx_dmabuf_map(bounce[1]);
if (!umap)
goto out_no_umap;
vmap = (char *)vmwgfx_dmabuf_map(bounce[2]);
if (!vmap)
goto out_no_vmap;
yidx = uidx = vidx = 0;
switch (id) {
case FOURCC_YV12: {
int pitches[3], offsets[3];
unsigned char *y, *u, *v;
query_image_attributes(pScrn, FOURCC_YV12,
&w, &h, pitches, offsets);
y = buf + offsets[0];
v = buf + offsets[1];
u = buf + offsets[2];
for (i = 0; i < h; ++i) {
for (j = 0; j < w; ++j) {
int yoffset = (w*i+j);
int ii = (i|1), jj = (j|1);
int vuoffset = (w/2)*(ii/2) + (jj/2);
ymap[yidx++] = y[yoffset];
umap[uidx++] = u[vuoffset];
vmap[vidx++] = v[vuoffset];
}
}
}
break;
case FOURCC_UYVY:
for (i = 0; i < y_array_size; i +=2 ) {
/* extracting two pixels */
u = buf[0];
y1 = buf[1];
v = buf[2];
y2 = buf[3];
buf += 4;
ymap[yidx++] = y1;
ymap[yidx++] = y2;
umap[uidx++] = u;
umap[uidx++] = u;
vmap[vidx++] = v;
vmap[vidx++] = v;
}
break;
case FOURCC_YUY2:
for (i = 0; i < y_array_size; i +=2 ) {
/* extracting two pixels */
y1 = buf[0];
u = buf[1];
y2 = buf[2];
v = buf[3];
buf += 4;
ymap[yidx++] = y1;
ymap[yidx++] = y2;
umap[uidx++] = u;
umap[uidx++] = u;
vmap[vidx++] = v;
vmap[vidx++] = v;
}
break;
default:
ret = BadAlloc;
break;
}
ret = Success;
vmwgfx_dmabuf_unmap(bounce[2]);
out_no_vmap:
vmwgfx_dmabuf_unmap(bounce[1]);
out_no_umap:
vmwgfx_dmabuf_unmap(bounce[0]);
if (ret == Success) {
struct xa_surface *srf;
struct vmwgfx_dmabuf *buf;
uint32_t handle;
unsigned int stride;
BoxRec box;
RegionRec reg;
box.x1 = 0;
box.x2 = w;
box.y1 = 0;
box.y2 = h;
REGION_INIT(pScrn->pScreen, &reg, &box, 1);
for (i=0; i<3; ++i) {
srf = port->yuv[i];
buf = bounce[i];
if (xa_surface_handle(srf, &handle, &stride) != 0) {
ret = BadAlloc;
break;
}
if (vmwgfx_dma(0, 0, &reg, buf, w, handle, 1) != 0) {
ret = BadAlloc;
break;
}
}
REGION_UNINIT(pScrn->pScreen, &reg);
}
return ret;
}
static int
display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id,
RegionPtr dstRegion,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h,
PixmapPtr pPixmap)
{
struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap);
Bool hdtv;
RegionRec reg;
int ret = BadAlloc;
int blit_ret;
const float *conv_matrix;
REGION_NULL(pScreen, &reg);
if (!vmwgfx_pixmap_validate_hw(pPixmap, &reg, XA_FLAG_RENDER_TARGET, 0))
goto out_no_dst;
hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y));
conv_matrix = (hdtv ? bt_709 : bt_601);
#ifdef COMPOSITE
/*
* For redirected windows, we need to fix up the destination coordinates.
*/
REGION_TRANSLATE(pScreen, dstRegion, -pPixmap->screen_x,
-pPixmap->screen_y);
dst_x -= pPixmap->screen_x;
dst_y -= pPixmap->screen_y;
#endif
/*
* Throttle on previous blit.
*/
if (pPriv->fence) {
(void) xa_fence_wait(pPriv->fence, 1000000000ULL);
xa_fence_destroy(pPriv->fence);
pPriv->fence = NULL;
}
DamageRegionAppend(&pPixmap->drawable, dstRegion);
blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h,
(struct xa_box *)REGION_RECTS(dstRegion),
REGION_NUM_RECTS(dstRegion),
conv_matrix,
vpix->hw, pPriv->yuv);
saa_pixmap_dirty(pPixmap, TRUE, dstRegion);
DamageRegionProcessPending(&pPixmap->drawable);
ret = Success;
if (!blit_ret) {
ret = Success;
pPriv->fence = xa_fence_get(pPriv->r);
} else
ret = BadAlloc;
out_no_dst:
REGION_UNINIT(pScreen, &reg);
return ret;
}
static int
put_image(ScrnInfoPtr pScrn,
short src_x, short src_y,
short drw_x, short drw_y,
short src_w, short src_h,
short drw_w, short drw_h,
int id, unsigned char *buf,
short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data,
DrawablePtr pDraw)
{
struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data;
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
PixmapPtr pPixmap;
INT32 x1, x2, y1, y2;
BoxRec dstBox;
int ret;
/* Clip */
x1 = src_x;
x2 = src_x + src_w;
y1 = src_y;
y2 = src_y + src_h;
dstBox.x1 = drw_x;
dstBox.x2 = drw_x + drw_w;
dstBox.y1 = drw_y;
dstBox.y2 = drw_y + drw_h;
if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
width, height))
return Success;
ret = check_yuv_surfaces(pPriv, width, height);
if (ret)
return ret;
ret = copy_packed_data(pScrn, pPriv, id, buf,
src_x, src_y, width, height);
if (ret)
return ret;
if (pDraw->type == DRAWABLE_WINDOW) {
pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
} else {
pPixmap = (PixmapPtr)pDraw;
}
display_video(pScrn->pScreen, pPriv, id, clipBoxes,
src_x, src_y, src_w, src_h,
drw_x, drw_y,
drw_w, drw_h, pPixmap);
pPriv->current_set = (pPriv->current_set + 1) & 1;
return Success;
}
static struct xorg_xv_port_priv *
port_priv_create(struct xa_tracker *xat, struct xa_context *r,
int drm_fd)
{
struct xorg_xv_port_priv *priv = NULL;
priv = calloc(1, sizeof(struct xorg_xv_port_priv));
if (!priv)
return NULL;
priv->r = r;
priv->xat = xat;
priv->drm_fd = drm_fd;
REGION_NULL(pScreen, &priv->clip);
return priv;
}
static void
vmwgfx_free_textured_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports)
{
if (free_ports) {
int i;
for(i=0; i<adaptor->nPorts; ++i) {
free(adaptor->pPortPrivates[i].ptr);
}
}
free(adaptor->pAttributes);
free(adaptor->pPortPrivates);
xf86XVFreeVideoAdaptorRec(adaptor);
}
static XF86VideoAdaptorPtr
xorg_setup_textured_adapter(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
XF86VideoAdaptorPtr adapt;
XF86AttributePtr attrs;
DevUnion *dev_unions;
int nports = 16, i;
int nattributes;
struct xa_context *xar;
/*
* Use the XA default context since we don't expect the X server
* to render from multiple threads.
*/
xar = xa_context_default(ms->xat);
nattributes = NUM_TEXTURED_ATTRIBUTES;
adapt = calloc(1, sizeof(XF86VideoAdaptorRec));
dev_unions = calloc(nports, sizeof(DevUnion));
attrs = calloc(nattributes, sizeof(XF86AttributeRec));
if (adapt == NULL || dev_unions == NULL || attrs == NULL) {
free(adapt);
free(dev_unions);
free(attrs);
return NULL;
}
adapt->type = XvWindowMask | XvInputMask | XvImageMask;
adapt->flags = 0;
adapt->name = "XA G3D Textured Video";
adapt->nEncodings = 1;
adapt->pEncodings = DummyEncoding;
adapt->nFormats = NUM_FORMATS;
adapt->pFormats = Formats;
adapt->nPorts = 0;
adapt->pPortPrivates = dev_unions;
adapt->nAttributes = nattributes;
adapt->pAttributes = attrs;
memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec));
adapt->nImages = NUM_IMAGES;
adapt->pImages = Images;
adapt->PutVideo = NULL;
adapt->PutStill = NULL;
adapt->GetVideo = NULL;
adapt->GetStill = NULL;
adapt->StopVideo = stop_video;
adapt->SetPortAttribute = set_port_attribute;
adapt->GetPortAttribute = get_port_attribute;
adapt->QueryBestSize = query_best_size;
adapt->PutImage = put_image;
adapt->QueryImageAttributes = query_image_attributes;
for (i = 0; i < nports; i++) {
struct xorg_xv_port_priv *priv =
port_priv_create(ms->xat, xar, ms->fd);
adapt->pPortPrivates[i].ptr = (pointer) (priv);
adapt->nPorts++;
}
return adapt;
}
void
xorg_xv_init(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
modesettingPtr ms = modesettingPTR(pScrn);
XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL;
XF86VideoAdaptorPtr textured_adapter = NULL, overlay_adaptor = NULL;
int num_adaptors;
num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
new_adaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
if (new_adaptors == NULL)
return;
memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
adaptors = new_adaptors;
/* Add the adaptors supported by our hardware. First, set up the atoms
* that will be used by both output adaptors.
*/
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
xvContrast = MAKE_ATOM("XV_CONTRAST");
if (ms->xat) {
textured_adapter = xorg_setup_textured_adapter(pScreen);
if (textured_adapter)
adaptors[num_adaptors++] = textured_adapter;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"No 3D acceleration. Not setting up textured video.\n");
}
overlay_adaptor = vmw_video_init_adaptor(pScrn);
if (overlay_adaptor)
adaptors[num_adaptors++] = overlay_adaptor;
if (num_adaptors) {
Bool ret;
ret = xf86XVScreenInit(pScreen, adaptors, num_adaptors);
if (textured_adapter)
vmwgfx_free_textured_adaptor(textured_adapter, !ret);
if (overlay_adaptor)
vmw_video_free_adaptor(overlay_adaptor, !ret);
if (!ret)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to initialize Xv.\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Disabling Xv because no adaptors could be initialized.\n");
}
out_err_mem:
free(adaptors);
}