aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/lib/XvMC/hw/via/viaXvMC.c
diff options
context:
space:
mode:
authorReinhard Tartler <siretart@tauware.de>2011-10-10 17:43:39 +0200
committerReinhard Tartler <siretart@tauware.de>2011-10-10 17:43:39 +0200
commitf4092abdf94af6a99aff944d6264bc1284e8bdd4 (patch)
tree2ac1c9cc16ceb93edb2c4382c088dac5aeafdf0f /nx-X11/lib/XvMC/hw/via/viaXvMC.c
parenta840692edc9c6d19cd7c057f68e39c7d95eb767d (diff)
downloadnx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.gz
nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.tar.bz2
nx-libs-f4092abdf94af6a99aff944d6264bc1284e8bdd4.zip
Imported nx-X11-3.1.0-1.tar.gznx-X11/3.1.0-1
Summary: Imported nx-X11-3.1.0-1.tar.gz Keywords: Imported nx-X11-3.1.0-1.tar.gz into Git repository
Diffstat (limited to 'nx-X11/lib/XvMC/hw/via/viaXvMC.c')
-rw-r--r--nx-X11/lib/XvMC/hw/via/viaXvMC.c1964
1 files changed, 1964 insertions, 0 deletions
diff --git a/nx-X11/lib/XvMC/hw/via/viaXvMC.c b/nx-X11/lib/XvMC/hw/via/viaXvMC.c
new file mode 100644
index 000000000..eebc87ea8
--- /dev/null
+++ b/nx-X11/lib/XvMC/hw/via/viaXvMC.c
@@ -0,0 +1,1964 @@
+/*****************************************************************************
+ * VIA Unichrome XvMC extension client lib.
+ *
+ * Copyright (c) 2004-2005 Thomas Hellström. 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
+ * AUTHOR(S) OR COPYRIGHT HOLDER(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.
+ */
+
+
+/*
+ *Author: Thomas Hellström, 2004.
+ *Bugfixes by among others Pascal Brisset and Terry Barnaby.
+ *DRI protocol support by Thomas Hellström, 2005.
+ */
+
+#undef WAITPAUSE
+
+#include "viaXvMCPriv.h"
+#include "viaLowLevel.h"
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fourcc.h>
+#include <X11/extensions/Xv.h>
+#include <xf86drm.h>
+#include <pthread.h>
+#include <X11/extensions/vldXvMC.h>
+#include "xf86dri.h"
+#include "driDrawable.h"
+
+#define SAREAPTR(ctx) ((ViaXvMCSAreaPriv *) \
+ (((CARD8 *)(ctx)->sAreaAddress) + \
+ (ctx)->sAreaPrivOffset))
+
+
+
+static int error_base;
+static int event_base;
+static unsigned numContexts = 0;
+static int globalFD;
+static drmAddress sAreaAddress;
+static drmAddress fbAddress;
+static drmAddress mmioAddress;
+
+
+#define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
+
+#define ppthread_mutex_lock(arg) \
+ { \
+ pthread_mutex_lock(arg); \
+ } \
+
+#define ppthread_mutex_unlock(arg) \
+ { \
+ pthread_mutex_unlock(arg); \
+ } \
+
+static unsigned yOffs (ViaXvMCSurface *srf)
+{
+ return srf->offsets[0];
+}
+
+static unsigned vOffs (ViaXvMCSurface *srf)
+{
+ return srf->offsets[0] + srf->yStride * srf->height;
+}
+
+static unsigned uOffs (ViaXvMCSurface *srf)
+{
+ return srf->offsets[0] + ( srf->yStride * srf->height) +
+ (srf->yStride >> 1) * (srf->height >> 1);
+}
+
+
+static void defaultQMatrices(ViaXvMCContext *ctx)
+{
+ int i;
+
+ static const char intra[64] = {
+ 8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37,
+ 19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40,
+ 22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58,
+ 26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83
+ };
+
+ for( i=0; i<64; ++i) {
+ ctx->intra_quantiser_matrix[i] = intra[i];
+ ctx->non_intra_quantiser_matrix[i] = 16;
+ }
+ ctx->intraLoaded = 0;
+ ctx->nonIntraLoaded = 0;
+}
+
+
+static void releaseDecoder(ViaXvMCContext *ctx,int clearCtx)
+{
+ volatile ViaXvMCSAreaPriv *sAPriv;
+
+ sAPriv = SAREAPTR(ctx);
+ UNICHROME_UNLOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv, ctx->drmcontext);
+}
+
+
+static int grabDecoder( ViaXvMCContext *ctx, int *hadLastLock)
+{
+ volatile ViaXvMCSAreaPriv *sAPriv = SAREAPTR(ctx);
+ int retFtx, lc;
+
+ /*
+ * Try to grab the decoder. If it is not available we will sleep until
+ * it becomes available or for a maximum of 20 ms.
+ * Then try to grab it again, unless a timeout occured. If the decoder is
+ * available, the lock should be reasonably fast.
+ */
+
+ if (ctx->haveDecoder) {
+ flushXvMCLowLevel(ctx->xl); /* Ignore errors here. */
+
+ /*fprintf(stderr,"ViaXvMC: ERROR: Trying to re-lock decoder.\n"); */
+ *hadLastLock = 1;
+ return 0;
+ }
+ UNICHROME_LOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv, ctx->drmcontext, lc,
+ retFtx);
+ *hadLastLock = (ctx->drmcontext == lc);
+
+ return retFtx;
+}
+
+static void setupAttribDesc(Display *display, XvPortID port,
+ const ViaXvMCAttrHolder *attrib,
+ XvAttribute attribDesc[])
+{
+ XvAttribute *XvAttribs,*curAD;
+ int num;
+ unsigned i,j;
+
+ XLockDisplay(display);
+ XvAttribs = XvQueryPortAttributes(display, port, &num);
+ for(i=0; i<attrib->numAttr; ++i) {
+ curAD = attribDesc + i;
+ curAD->flags = 0;
+ curAD->min_value = 0;
+ curAD->max_value = 0;
+ curAD->name = NULL;
+ for(j=0; j<num; ++j) {
+ if (attrib->attributes[i].attribute ==
+ XInternAtom(display,XvAttribs[j].name,TRUE)) {
+ *curAD = XvAttribs[j];
+ curAD->name = strdup(XvAttribs[j].name);
+ break;
+ }
+ }
+ }
+ if (XvAttribs) XFree(XvAttribs);
+ XUnlockDisplay(display);
+
+}
+
+static void releaseAttribDesc(int numAttr, XvAttribute attribDesc[])
+{
+ int i;
+
+ for (i=0; i<numAttr; ++i) {
+ if (attribDesc[i].name)
+ free(attribDesc[i].name);
+ }
+}
+
+static Status releaseContextResources(Display *display, XvMCContext *context,
+ int freePrivate, Status errType)
+{
+ ViaXvMCContext *pViaXvMC = (ViaXvMCContext *) context->privData;
+
+ switch(pViaXvMC->resources) {
+ case context_drawHash:
+ driDestroyHashContents( pViaXvMC->drawHash );
+ drmHashDestroy( pViaXvMC->drawHash );
+ case context_lowLevel:
+ closeXvMCLowLevel(pViaXvMC->xl);
+ case context_mutex:
+ pthread_mutex_destroy(&pViaXvMC->ctxMutex);
+ case context_drmContext:
+ XLockDisplay(display);
+ uniDRIDestroyContext(display, pViaXvMC->screen, pViaXvMC->id);
+ XUnlockDisplay(display);
+ case context_sAreaMap:
+ numContexts--;
+ if (numContexts == 0)
+ drmUnmap(pViaXvMC->sAreaAddress,pViaXvMC->sAreaSize);
+ case context_fbMap:
+ if (numContexts == 0)
+ drmUnmap(pViaXvMC->fbAddress,pViaXvMC->fbSize);
+ case context_mmioMap:
+ if (numContexts == 0)
+ drmUnmap(pViaXvMC->mmioAddress,pViaXvMC->mmioSize);
+ case context_fd:
+ if (numContexts == 0) {
+ if (pViaXvMC->fd >= 0)
+ drmClose(pViaXvMC->fd);
+ }
+ pViaXvMC->fd = -1;
+ case context_driConnection:
+ if (numContexts == 0) {
+ XLockDisplay(display);
+ uniDRICloseConnection(display, pViaXvMC->screen);
+ XUnlockDisplay(display);
+ }
+ case context_context:
+ XLockDisplay(display);
+ _xvmc_destroy_context(display, context);
+ XUnlockDisplay(display);
+ if (!freePrivate) break;
+ default:
+ free(pViaXvMC);
+ }
+ return errType;
+}
+
+Status XvMCCreateContext(Display *display, XvPortID port,
+ int surface_type_id, int width, int height, int flags,
+ XvMCContext *context)
+{
+ ViaXvMCContext *pViaXvMC;
+ int priv_count;
+ uint *priv_data;
+ uint magic;
+ unsigned i;
+ Status ret;
+ int major, minor;
+ ViaXvMCCreateContextRec *tmpComm;
+ drmVersionPtr drmVer;
+ char *curBusID;
+ int isCapable;
+
+ /*
+ * Verify Obvious things first
+ */
+
+ if(context == NULL) {
+ return XvMCBadContext;
+ }
+
+ if(!(flags & XVMC_DIRECT)) {
+ fprintf(stderr,"Indirect Rendering not supported! Using Direct.\n");
+ }
+
+ /*
+ *FIXME: Check $DISPLAY for legal values here
+ */
+
+ context->surface_type_id = surface_type_id;
+ context->width = (unsigned short)((width + 15) & ~15);
+ context->height = (unsigned short)((height + 15) & ~15);
+ context->flags = flags;
+ context->port = port;
+
+ /*
+ * Width, Height, and flags are checked against surface_type_id
+ * and port for validity inside the X server, no need to check
+ * here.
+ */
+
+ /* Allocate private Context data */
+ context->privData = (void *)malloc(sizeof(ViaXvMCContext));
+ if(!context->privData) {
+ fprintf(stderr,"Unable to allocate resources for XvMC context.\n");
+ return BadAlloc;
+ }
+
+ pViaXvMC = (ViaXvMCContext *)context->privData;
+ pViaXvMC->resources = context_none;
+
+ /* Verify the XvMC extension exists */
+
+ XLockDisplay(display);
+ if(! XvMCQueryExtension(display, &event_base,
+ &error_base)) {
+ fprintf(stderr,"XvMC Extension is not available!\n");
+ free(pViaXvMC);
+ XUnlockDisplay(display);
+ return BadAlloc;
+ }
+
+ /* Verify XvMC version */
+ ret = XvMCQueryVersion(display, &major, &minor);
+ if(ret) {
+ fprintf(stderr,"XvMCQuery Version Failed, unable to determine "
+ "protocol version!\n");
+ }
+ XUnlockDisplay(display);
+
+ /* FIXME: Check Major and Minor here */
+
+ XLockDisplay(display);
+ if((ret = _xvmc_create_context(display, context, &priv_count,
+ &priv_data))) {
+ XUnlockDisplay(display);
+ fprintf(stderr,"Unable to create XvMC Context.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ XUnlockDisplay(display);
+
+ /*
+ * Check size and version of returned data.
+ */
+
+ tmpComm = ( ViaXvMCCreateContextRec *) priv_data;
+ if(priv_count != (sizeof(ViaXvMCCreateContextRec) >> 2)) {
+ fprintf(stderr,"_xvmc_create_context() returned incorrect "
+ "data size!\n");
+ fprintf(stderr,"\tExpected %d, got %d\n",
+ (int) (sizeof(ViaXvMCCreateContextRec) >> 2),
+ (int) priv_count);
+ XFree(priv_data);
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ pViaXvMC->resources = context_context;
+
+ if ((tmpComm->major != VIAXVMC_MAJOR) ||
+ (tmpComm->minor != VIAXVMC_MINOR)) {
+ fprintf(stderr,"Version mismatch between the X via driver\n"
+ "and the XvMC library. Cannot continue!\n");
+ XFree(priv_data);
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+
+ pViaXvMC->ctxNo = tmpComm->ctxNo;
+ pViaXvMC->fbOffset = tmpComm->fbOffset;
+ pViaXvMC->fbSize = tmpComm->fbSize;
+ pViaXvMC->mmioOffset = tmpComm->mmioOffset;
+ pViaXvMC->mmioSize = tmpComm->mmioSize;
+ pViaXvMC->sAreaSize = tmpComm->sAreaSize;
+ pViaXvMC->sAreaPrivOffset = tmpComm->sAreaPrivOffset;
+ pViaXvMC->decoderOn = 0;
+ pViaXvMC->xvMCPort = tmpComm->xvmc_port;
+ pViaXvMC->useAGP = tmpComm->useAGP;
+ pViaXvMC->attrib = tmpComm->initAttrs;
+ pViaXvMC->screen = tmpComm->screen;
+ pViaXvMC->depth = tmpComm->depth;
+ pViaXvMC->stride = tmpComm->stride;
+ pViaXvMC->chipId = tmpComm->chipId;
+
+ /*
+ * Must free the private data we were passed from X
+ */
+
+ XFree(priv_data);
+
+ /*
+ * Check for direct rendering capable, establish DRI and DRM connections,
+ * map framebuffer, DRI shared area and read-only register areas.
+ * Initial checking for drm has already been done by the server.
+ * Only do this for the first context we create.
+ */
+
+ if (numContexts == 0) {
+ XLockDisplay(display);
+ ret = uniDRIQueryDirectRenderingCapable(display, pViaXvMC->screen, &isCapable);
+ if (!ret || !isCapable) {
+ XUnlockDisplay(display);
+ fprintf(stderr,"Direct Rendering is not available on this system!\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+
+ if (!uniDRIOpenConnection(display, pViaXvMC->screen, &pViaXvMC->sAreaOffset,
+ &curBusID)) {
+ XUnlockDisplay(display);
+ fprintf(stderr,"Could not open DRI connection to X server!\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ XUnlockDisplay(display);
+
+ strncpy(pViaXvMC->busIdString,curBusID,20);
+ pViaXvMC->busIdString[20] = '\0';
+ XFree(curBusID);
+
+ pViaXvMC->resources = context_driConnection;
+
+ if((pViaXvMC->fd = drmOpen("via",pViaXvMC->busIdString)) < 0) {
+ fprintf(stderr,"DRM Device for via could not be opened.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ globalFD = pViaXvMC->fd;
+ pViaXvMC->resources = context_fd;
+
+ if (NULL == (drmVer = drmGetVersion(pViaXvMC->fd))) {
+ fprintf(stderr,
+ "viaXvMC: Could not get drm version.");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ if (((drmVer->version_major != 2 ) || (drmVer->version_minor < 0))) {
+ fprintf(stderr,
+ "viaXvMC: Kernel drm is not compatible with XvMC.\n");
+ fprintf(stderr,
+ "viaXvMC: Kernel drm version: %d.%d.%d "
+ "and I need at least version 2.0.0.\n"
+ "Please update.\n",
+ drmVer->version_major,drmVer->version_minor,
+ drmVer->version_patchlevel);
+ drmFreeVersion(drmVer);
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ drmFreeVersion(drmVer);
+ drmGetMagic(pViaXvMC->fd,&magic);
+
+ XLockDisplay(display);
+ if (!uniDRIAuthConnection(display, pViaXvMC->screen, magic)) {
+ XUnlockDisplay(display);
+ fprintf(stderr, "viaXvMC: X server did not allow DRI. Check permissions.\n");
+ XFree(priv_data);
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ XUnlockDisplay(display);
+
+ /*
+ * Map the register memory
+ */
+
+ if(drmMap(pViaXvMC->fd,pViaXvMC->mmioOffset,
+ pViaXvMC->mmioSize,&mmioAddress) < 0) {
+ fprintf(stderr,"Unable to map the display chip mmio registers.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ pViaXvMC->mmioAddress = mmioAddress;
+ pViaXvMC->resources = context_mmioMap;
+
+ /*
+ * Map Framebuffer memory
+ */
+
+ if(drmMap(pViaXvMC->fd,pViaXvMC->fbOffset,
+ pViaXvMC->fbSize,&fbAddress) < 0) {
+ fprintf(stderr,"Unable to map XvMC Framebuffer.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ pViaXvMC->fbAddress = fbAddress;
+ pViaXvMC->resources = context_fbMap;
+
+
+ /*
+ * Map DRI Sarea.
+ */
+
+ if(drmMap(pViaXvMC->fd,pViaXvMC->sAreaOffset,
+ pViaXvMC->sAreaSize,&sAreaAddress) < 0) {
+ fprintf(stderr,"Unable to map DRI SAREA.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ } else {
+ pViaXvMC->fd = globalFD;
+ pViaXvMC->mmioAddress = mmioAddress;
+ pViaXvMC->fbAddress = fbAddress;
+ }
+
+ pViaXvMC->sAreaAddress = sAreaAddress;
+ pViaXvMC->resources = context_sAreaMap;
+ numContexts++;
+
+ /*
+ * Find a matching visual. Important only for direct drawing to the visible
+ * frame-buffer.
+ */
+
+ XLockDisplay(display);
+ ret = XMatchVisualInfo(display, pViaXvMC->screen,
+ (pViaXvMC->depth == 32) ? 24 : pViaXvMC->depth, TrueColor,
+ &pViaXvMC->visualInfo);
+ XUnlockDisplay(display);
+ if (!ret) {
+ fprintf(stderr, "viaXvMC: Could not find a matching TrueColor visual.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+
+ if (!uniDRICreateContext(display, pViaXvMC->screen, pViaXvMC->visualInfo.visual,
+ &pViaXvMC->id, &pViaXvMC->drmcontext)) {
+
+ fprintf(stderr, "viaXvMC: Could not create DRI context.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+
+ pViaXvMC->resources = context_drmContext;
+
+ for (i=0; i<VIA_MAX_RENDSURF; ++i) {
+ pViaXvMC->rendSurf[i] = 0;
+ }
+ pViaXvMC->lastSrfDisplaying = ~0;
+ setupAttribDesc(display, port, &pViaXvMC->attrib, pViaXvMC->attribDesc);
+
+ pViaXvMC->hwLock = (drmLockPtr) pViaXvMC->sAreaAddress;
+ defaultQMatrices(pViaXvMC);
+ pViaXvMC->chromaIntraLoaded = 1;
+ pViaXvMC->chromaNonIntraLoaded = 1;
+ pViaXvMC->yStride = (width + 31) & ~31;
+ pViaXvMC->haveDecoder = 0;
+ pViaXvMC->attribChanged = 1;
+ pViaXvMC->haveXv = 0;
+ pViaXvMC->port = context->port;
+ pthread_mutex_init(&pViaXvMC->ctxMutex,NULL);
+ pViaXvMC->resources = context_mutex;
+ pViaXvMC->timeStamp = 0;
+ setRegion(0,0,-1,-1,pViaXvMC->sRegion);
+ setRegion(0,0,-1,-1,pViaXvMC->dRegion);
+
+ if (NULL == (pViaXvMC->xl =
+ initXvMCLowLevel(pViaXvMC->fd, &pViaXvMC->drmcontext,
+ pViaXvMC->hwLock, pViaXvMC->mmioAddress,
+ pViaXvMC->fbAddress, pViaXvMC->stride, pViaXvMC->depth,
+ context->width, context->height,
+ pViaXvMC->useAGP, pViaXvMC->chipId))) {
+
+ fprintf(stderr,"ViaXvMC: Could not allocate timestamp blit area.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ pViaXvMC->resources = context_lowLevel;
+ setAGPSyncLowLevel(pViaXvMC->xl, 1, 0);
+
+ if (NULL == (pViaXvMC->drawHash = drmHashCreate())) {
+ fprintf(stderr,"ViaXvMC: Could not allocate drawable hash table.\n");
+ return releaseContextResources(display, context, 1, BadAlloc);
+ }
+ pViaXvMC->resources = context_drawHash;
+
+
+ if (numContexts == 1) {
+ hwlLock(pViaXvMC->xl,1);
+ setLowLevelLocking(pViaXvMC->xl,0);
+ viaVideoSubPictureOffLocked(pViaXvMC->xl);
+ flushXvMCLowLevel(pViaXvMC->xl);
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+ }
+
+ return Success;
+}
+
+
+Status XvMCDestroyContext(Display *display, XvMCContext *context)
+{
+ ViaXvMCContext *pViaXvMC;
+
+
+ if(context == NULL) {
+ return (error_base + XvMCBadContext);
+ }
+ if(NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ /*
+ * Release decoder if we have it. In case of crash or termination
+ * before XvMCDestroyContext, the X server will take care of this.
+ */
+
+ releaseAttribDesc(pViaXvMC->attrib.numAttr,pViaXvMC->attribDesc);
+ releaseDecoder(pViaXvMC,1);
+ return releaseContextResources(display, context, 1, Success);
+}
+
+Status XvMCCreateSurface( Display *display, XvMCContext *context,
+ XvMCSurface *surface)
+{
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSurface *pViaSurface;
+ int priv_count;
+ unsigned *priv_data;
+ unsigned i;
+ Status ret;
+
+ if((surface == NULL) || (context == NULL) || (display == NULL)){
+ return BadValue;
+ }
+
+ pViaXvMC = (ViaXvMCContext *)context->privData;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+ if(pViaXvMC == NULL) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return (error_base + XvMCBadContext);
+ }
+
+ pViaSurface = surface->privData = (ViaXvMCSurface *)malloc(sizeof(ViaXvMCSurface));
+ if(!surface->privData) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAlloc;
+ }
+ XLockDisplay(display);
+ if((ret = _xvmc_create_surface(display, context, surface,
+ &priv_count, &priv_data))) {
+ XUnlockDisplay(display);
+ free(pViaSurface);
+ fprintf(stderr,"Unable to create XvMC Surface.\n");
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+ }
+ XUnlockDisplay(display);
+
+ pViaSurface->srfNo = priv_data[0];
+
+ /*
+ * Store framebuffer offsets to the buffers allocated for this surface.
+ * For some chipset revisions, surfaces may be double-buffered.
+ */
+
+ pViaSurface->numBuffers = priv_data[1];
+ for (i=0; i < pViaSurface->numBuffers; ++i) {
+ pViaSurface->offsets[i] = priv_data[i+2];
+ }
+ pViaSurface->curBuf = 0;
+
+
+ /* Free data returned from xvmc_create_surface */
+
+ XFree(priv_data);
+
+ pViaSurface->width = context->width;
+ pViaSurface->height = context->height;
+ pViaSurface->yStride = pViaXvMC->yStride;
+ pViaSurface->privContext = pViaXvMC;
+ pViaSurface->privSubPic = NULL;
+ pViaSurface->needsSync = 0;
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+Status XvMCDestroySurface(Display *display, XvMCSurface *surface)
+{
+ ViaXvMCSurface *pViaSurface;
+
+ if((display == NULL) || (surface == NULL)) {
+ return BadValue;
+ }
+ if(surface->privData == NULL) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ pViaSurface = (ViaXvMCSurface *)surface->privData;
+
+ XLockDisplay(display);
+ _xvmc_destroy_surface(display,surface);
+ XUnlockDisplay(display);
+
+ free(pViaSurface);
+ surface->privData = NULL;
+ return Success;
+}
+
+Status XvMCPutSlice2(Display *display,XvMCContext *context, char *slice,
+ int nBytes, int sliceCode)
+{
+ ViaXvMCContext *pViaXvMC;
+ CARD32 sCode = 0x00010000 | (sliceCode & 0xFF) << 24;
+
+ if((display == NULL) || (context == NULL)) {
+ return BadValue;
+ }
+ if(NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (!pViaXvMC->haveDecoder) {
+ fprintf(stderr,"XvMCPutSlice: This context does not own decoder!\n");
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAlloc;
+ }
+
+ viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *)slice, nBytes, sCode);
+
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+Status XvMCPutSlice(Display *display,XvMCContext *context, char *slice,
+ int nBytes)
+{
+ ViaXvMCContext *pViaXvMC;
+
+ if((display == NULL) || (context == NULL)) {
+ return BadValue;
+ }
+ if(NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+ if (!pViaXvMC->haveDecoder) {
+ fprintf(stderr,"XvMCPutSlice: This context does not own decoder!\n");
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAlloc;
+ }
+
+ viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *)slice, nBytes, 0);
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+static Status updateXVOverlay(Display *display,ViaXvMCContext *pViaXvMC,
+ ViaXvMCSurface *pViaSurface, Drawable draw,
+ short srcx, short srcy, unsigned short srcw,
+ unsigned short srch,short destx,short desty,
+ unsigned short destw,unsigned short desth)
+{
+ ViaXvMCCommandBuffer buf;
+ ViaXvMCSubPicture *pViaSubPic;
+ Status ret;
+
+ if (!pViaXvMC->haveXv) {
+ pViaXvMC->xvImage =
+ XvCreateImage(display,pViaXvMC->port,FOURCC_XVMC,
+ (char *)&buf,pViaSurface->width,
+ pViaSurface->height);
+ pViaXvMC->gc = XCreateGC(display,draw,0,0);
+ pViaXvMC->haveXv = 1;
+ }
+ pViaXvMC->draw = draw;
+ pViaXvMC->xvImage->data = (char *)&buf;
+
+ buf.command = (pViaXvMC->attribChanged) ?
+ VIA_XVMC_COMMAND_FDISPLAY : VIA_XVMC_COMMAND_DISPLAY;
+ buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
+ buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
+ pViaSubPic = pViaSurface->privSubPic;
+ buf.subPicNo = ((NULL == pViaSubPic) ? 0 : pViaSubPic->srfNo )
+ | VIA_XVMC_VALID;
+ buf.attrib = pViaXvMC->attrib;
+
+ XLockDisplay(display);
+
+ if ((ret = XvPutImage(display,pViaXvMC->port,draw,pViaXvMC->gc,
+ pViaXvMC->xvImage,srcx,srcy,srcw,srch,
+ destx,desty,destw,desth))) {
+ XUnlockDisplay(display);
+ return ret;
+ }
+ XSync(display, 0);
+ XUnlockDisplay(display);
+ pViaXvMC->attribChanged = 0;
+ return Success;
+}
+
+
+Status XvMCPutSurface(Display *display,XvMCSurface *surface,Drawable draw,
+ short srcx, short srcy, unsigned short srcw,
+ unsigned short srch,short destx,short desty,
+ unsigned short destw,unsigned short desth, int flags)
+{
+ /*
+ * This function contains some hairy locking logic. What we really want to
+ * do is to flip the picture ASAP, to get a low latency and smooth playback.
+ * However, if somebody else used the overlay since we used it last or if it is
+ * our first time, we'll have to call X to update the overlay first. Otherwise
+ * we'll do the overlay update once we've flipped. Since we release the hardware
+ * lock when we call X, X needs to verify using the SAREA that nobody else flipped
+ * in a picture between the lock release and the X server control. Similarly
+ * when the overlay update returns, we have to make sure that we still own the
+ * overlay.
+ */
+
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSubPicture *pViaSubPic;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+ Status ret;
+ unsigned dispSurface, lastSurface;
+ int overlayUpdated;
+ drawableInfo *drawInfo;
+ XvMCRegion sReg, dReg;
+ Bool forceUpdate = FALSE;
+
+ if((display == NULL) || (surface == NULL)) {
+ return BadValue;
+ }
+ if(NULL == (pViaSurface = surface->privData )) {
+ return (error_base + XvMCBadSurface);
+ }
+ if (NULL == (pViaXvMC = pViaSurface->privContext)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ pViaSubPic = pViaSurface->privSubPic;
+ sAPriv = SAREAPTR( pViaXvMC );
+
+ setRegion(srcx, srcy, srcw, srch, sReg);
+ setRegion(destx, desty, destw, desth, dReg);
+
+
+ if ((!regionEqual(sReg, pViaXvMC->sRegion)) ||
+ (!regionEqual(dReg, pViaXvMC->dRegion))) {
+
+ /*
+ * Force update of the video overlay to match the new format.
+ */
+
+ pViaXvMC->sRegion = sReg;
+ pViaXvMC->dRegion = dReg;
+ forceUpdate = TRUE;
+ }
+
+
+ hwlLock(pViaXvMC->xl,1);
+
+ if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display, pViaXvMC->screen, draw, 0,
+ pViaXvMC->fd, pViaXvMC->drmcontext, pViaXvMC->sAreaAddress,
+ FALSE, &drawInfo, sizeof(*drawInfo))) {
+
+ hwlUnlock(pViaXvMC->xl,1);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAccess;
+ }
+
+ setLowLevelLocking(pViaXvMC->xl,0);
+
+
+ /*
+ * Put a surface ID in the SAREA to "authenticate" to the
+ * X server.
+ */
+
+ dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
+ lastSurface = pViaXvMC->lastSrfDisplaying;
+ sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] =
+ pViaXvMC->lastSrfDisplaying = pViaSurface->srfNo | VIA_XVMC_VALID;
+ overlayUpdated = 0;
+
+ viaVideoSetSWFLipLocked(pViaXvMC->xl, yOffs(pViaSurface), uOffs(pViaSurface),
+ vOffs(pViaSurface), pViaSurface->yStride, pViaSurface->yStride >> 1);
+
+ while ((lastSurface != dispSurface) || forceUpdate) {
+
+ forceUpdate = FALSE;
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+
+ /*
+ * We weren't the last to display. Update the overlay before flipping.
+ */
+
+ ret = updateXVOverlay(display,pViaXvMC,pViaSurface,draw,srcx,srcy,srcw,
+ srch,destx,desty,destw,desth);
+ if (ret) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+ }
+
+ hwlLock(pViaXvMC->xl,1);
+
+ if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display, pViaXvMC->screen, draw, 0,
+ pViaXvMC->fd, pViaXvMC->drmcontext, pViaXvMC->sAreaAddress,
+ FALSE, &drawInfo, sizeof(*drawInfo))) {
+
+ hwlUnlock(pViaXvMC->xl,1);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAccess;
+ }
+
+ setLowLevelLocking(pViaXvMC->xl,0);
+ lastSurface = pViaSurface->srfNo | VIA_XVMC_VALID;
+ dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
+ overlayUpdated = 1;
+ }
+
+
+ /*
+ * Subpictures
+ */
+
+ if (NULL != pViaSubPic) {
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort]
+ != (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
+ sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] =
+ pViaSubPic->srfNo | VIA_XVMC_VALID;
+ viaVideoSubPictureLocked(pViaXvMC->xl, pViaSubPic);
+ }
+ } else {
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] & VIA_XVMC_VALID) {
+ viaVideoSubPictureOffLocked(pViaXvMC->xl);
+ sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
+ }
+ }
+
+ /*
+ * Flip
+ */
+
+ viaVideoSWFlipLocked(pViaXvMC->xl, flags, pViaSurface->progressiveSequence);
+ flushXvMCLowLevel(pViaXvMC->xl);
+
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+
+ if (overlayUpdated || !drawInfo->touched ) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+
+ /*
+ * Update overlay
+ */
+
+ ret = updateXVOverlay(display,pViaXvMC,pViaSurface,draw,srcx,srcy,srcw,
+ srch,destx,desty,destw,desth);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+
+}
+
+Status XvMCBeginSurface(Display *display,
+ XvMCContext *context,
+ XvMCSurface *target_surface,
+ XvMCSurface *past_surface,
+ XvMCSurface *future_surface,
+ const XvMCMpegControl *control)
+{
+ ViaXvMCSurface *targS,*futS,*pastS;
+ ViaXvMCContext *pViaXvMC;
+ int hadDecoderLast;
+ CARD32 timeStamp;
+
+ if((display == NULL) || (context == NULL) || (target_surface == NULL)) {
+ return BadValue;
+ }
+
+ pViaXvMC = context->privData;
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (grabDecoder(pViaXvMC, &hadDecoderLast)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAlloc;
+ }
+ pViaXvMC->haveDecoder = 1;
+
+ /*
+ * We need to wait for decoder idle at next flush, since hardware doesn't queue
+ * beginsurface requests until the decoder is idle. This is
+ * done by waiting on the last previous timestamp, or if there was another context
+ * having the decoder before us, by emitting a new one.
+ */
+
+ if (pViaXvMC->useAGP) {
+ if (!hadDecoderLast || pViaXvMC->timeStamp == 0) {
+ timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
+ if (flushXvMCLowLevel(pViaXvMC->xl)) {
+ releaseDecoder(pViaXvMC, 0);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadAlloc;
+ }
+ pViaXvMC->timeStamp = timeStamp;
+ } else {
+ timeStamp = pViaXvMC->timeStamp;
+ }
+ setAGPSyncLowLevel(pViaXvMC->xl, 1, timeStamp);
+ }
+
+ if (!hadDecoderLast || !pViaXvMC->decoderOn) {
+ pViaXvMC->intraLoaded = 0;
+ pViaXvMC->nonIntraLoaded = 0;
+ }
+
+ viaMpegReset(pViaXvMC->xl);
+
+ targS = (ViaXvMCSurface *)target_surface->privData;
+ futS = NULL;
+ pastS = NULL;
+
+
+ pViaXvMC->rendSurf[0] = targS->srfNo | VIA_XVMC_VALID;
+ if (future_surface) {
+ futS = (ViaXvMCSurface *)future_surface->privData;
+ futS->needsSync = 0;
+ }
+ if (past_surface) {
+ pastS = (ViaXvMCSurface *)past_surface->privData;
+ pastS->needsSync = 0;
+ }
+
+
+ targS->progressiveSequence = (control->flags & XVMC_PROGRESSIVE_SEQUENCE);
+ targS->topFieldFirst = (control->flags & XVMC_TOP_FIELD_FIRST);
+ targS->privSubPic = NULL;
+
+ viaMpegSetSurfaceStride(pViaXvMC->xl,pViaXvMC);
+
+ viaMpegSetFB(pViaXvMC->xl,0,yOffs(targS),uOffs(targS),vOffs(targS));
+ if (past_surface) {
+ viaMpegSetFB(pViaXvMC->xl,1,yOffs(pastS),uOffs(pastS),vOffs(pastS));
+ } else {
+ viaMpegSetFB(pViaXvMC->xl,1,0,0,0);
+ }
+
+ if (future_surface) {
+ viaMpegSetFB(pViaXvMC->xl,2,yOffs(futS),uOffs(futS),vOffs(futS));
+ } else {
+ viaMpegSetFB(pViaXvMC->xl,2,0,0,0);
+ }
+
+ viaMpegBeginPicture(pViaXvMC->xl,pViaXvMC,context->width,context->height,control);
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ targS->needsSync = 1;
+ targS->syncMode = LL_MODE_DECODER_IDLE;
+ pViaXvMC->decoderOn = 1;
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+Status XvMCSyncSurface(Display *display,XvMCSurface *surface)
+{
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCContext *pViaXvMC;
+ unsigned i;
+
+ if((display == NULL) || (surface == NULL)) {
+ return BadValue;
+ }
+ if(surface->privData == NULL) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ pViaSurface = (ViaXvMCSurface *)surface->privData;
+ pViaXvMC = pViaSurface->privContext;
+
+ if(pViaXvMC == NULL) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+ if (pViaSurface->needsSync) {
+ CARD32 timeStamp = pViaSurface->timeStamp;
+ int syncMode = pViaSurface->syncMode;
+
+ if (pViaXvMC->useAGP) {
+
+ syncMode = (pViaSurface->syncMode == LL_MODE_2D ||
+ pViaSurface->timeStamp < pViaXvMC->timeStamp) ?
+ LL_MODE_2D : LL_MODE_DECODER_IDLE;
+ if (pViaSurface->syncMode != LL_MODE_2D)
+ timeStamp = pViaXvMC->timeStamp;
+
+ } else if (syncMode != LL_MODE_2D &&
+ pViaXvMC->rendSurf[0] != (pViaSurface->srfNo | VIA_XVMC_VALID)) {
+
+ pViaSurface->needsSync = 0;
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+
+ if (syncXvMCLowLevel(pViaXvMC->xl, syncMode, 1,
+ pViaSurface->timeStamp)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadValue;
+ }
+ pViaSurface->needsSync = 0;
+ }
+
+ if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
+ pViaSurface->needsSync = 0;
+ for (i=0; i<VIA_MAX_RENDSURF; ++i) {
+ pViaXvMC->rendSurf[i] = 0;
+ }
+ }
+
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+Status XvMCLoadQMatrix(Display *display, XvMCContext *context,
+ const XvMCQMatrix *qmx)
+{
+ ViaXvMCContext
+ *pViaXvMC;
+
+ if((display == NULL) || (context == NULL)) {
+ return BadValue;
+ }
+ if(NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (qmx->load_intra_quantiser_matrix) {
+ memcpy(pViaXvMC->intra_quantiser_matrix,
+ qmx->intra_quantiser_matrix,
+ sizeof(qmx->intra_quantiser_matrix));
+ pViaXvMC->intraLoaded = 0;
+ }
+
+ if (qmx->load_non_intra_quantiser_matrix) {
+ memcpy(pViaXvMC->non_intra_quantiser_matrix,
+ qmx->non_intra_quantiser_matrix,
+ sizeof(qmx->non_intra_quantiser_matrix));
+ pViaXvMC->nonIntraLoaded = 0;
+ }
+
+ if (qmx->load_chroma_intra_quantiser_matrix) {
+ memcpy(pViaXvMC->chroma_intra_quantiser_matrix,
+ qmx->chroma_intra_quantiser_matrix,
+ sizeof(qmx->chroma_intra_quantiser_matrix));
+ pViaXvMC->chromaIntraLoaded = 0;
+ }
+
+ if (qmx->load_chroma_non_intra_quantiser_matrix) {
+ memcpy(pViaXvMC->chroma_non_intra_quantiser_matrix,
+ qmx->chroma_non_intra_quantiser_matrix,
+ sizeof(qmx->chroma_non_intra_quantiser_matrix));
+ pViaXvMC->chromaNonIntraLoaded = 0;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+
+ return Success;
+}
+
+/*
+ * Below, we provide functions unusable for this implementation, but for
+ * standard completeness.
+ */
+
+
+Status XvMCRenderSurface
+(
+ Display *display,
+ XvMCContext *context,
+ unsigned int picture_structure,
+ XvMCSurface *target_surface,
+ XvMCSurface *past_surface,
+ XvMCSurface *future_surface,
+ unsigned int flags,
+ unsigned int num_macroblocks,
+ unsigned int first_macroblock,
+ XvMCMacroBlockArray *macroblock_array,
+ XvMCBlockArray *blocks
+ )
+{
+ return (error_base + XvMCBadContext);
+}
+
+Status XvMCCreateBlocks
+(
+ Display *display,
+ XvMCContext *context,
+ unsigned int num_blocks,
+ XvMCBlockArray * block
+ )
+{
+ return (error_base + XvMCBadContext);
+}
+
+Status XvMCDestroyBlocks (Display *display, XvMCBlockArray * block)
+{
+ return Success;
+}
+
+Status XvMCCreateMacroBlocks
+(
+ Display *display,
+ XvMCContext *context,
+ unsigned int num_blocks,
+ XvMCMacroBlockArray * blocks
+ )
+{
+ return (error_base + XvMCBadContext);
+}
+
+Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray * block)
+{
+ return (error_base + XvMCBadContext);
+}
+
+Status XvMCCreateSubpicture( Display *display,
+ XvMCContext *context,
+ XvMCSubpicture *subpicture,
+ unsigned short width,
+ unsigned short height,
+ int xvimage_id)
+{
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSubPicture *pViaSubPic;
+ int priv_count;
+ unsigned *priv_data;
+ Status ret;
+
+ if((subpicture == NULL) || (context == NULL) || (display == NULL)){
+ return BadValue;
+ }
+
+ pViaXvMC = (ViaXvMCContext *)context->privData;
+ if(pViaXvMC == NULL) {
+ return (error_base + XvMCBadContext);
+ }
+
+ subpicture->privData = (ViaXvMCSubPicture *)
+ malloc(sizeof(ViaXvMCSubPicture));
+ if(!subpicture->privData) {
+ return BadAlloc;
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ subpicture->width = context->width;
+ subpicture->height = context->height;
+ subpicture->xvimage_id = xvimage_id;
+ pViaSubPic = (ViaXvMCSubPicture *)subpicture->privData;
+
+ XLockDisplay(display);
+ if((ret = _xvmc_create_subpicture(display, context, subpicture,
+ &priv_count, &priv_data))) {
+ XUnlockDisplay(display);
+ free(pViaSubPic);
+ fprintf(stderr,"Unable to create XvMC Subpicture.\n");
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+ }
+ XUnlockDisplay(display);
+
+
+ subpicture->num_palette_entries = VIA_SUBPIC_PALETTE_SIZE;
+ subpicture->entry_bytes = 3;
+ strncpy(subpicture->component_order,"YUV",4);
+ pViaSubPic->srfNo = priv_data[0];
+ pViaSubPic->offset = priv_data[1];
+ pViaSubPic->stride = (subpicture->width + 31) & ~31;
+ pViaSubPic->privContext = pViaXvMC;
+ pViaSubPic->ia44 = (xvimage_id == FOURCC_IA44);
+ pViaSubPic->needsSync = 0;
+
+ /* Free data returned from _xvmc_create_subpicture */
+
+ XFree(priv_data);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+Status
+XvMCSetSubpicturePalette (Display *display, XvMCSubpicture *subpicture,
+ unsigned char *palette)
+{
+ ViaXvMCSubPicture *pViaSubPic;
+ ViaXvMCContext *pViaXvMC;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+ unsigned i;
+ CARD32 tmp;
+
+ if((subpicture == NULL) || (display == NULL)){
+ return BadValue;
+ }
+ if(subpicture->privData == NULL) {
+ return (error_base + XvMCBadSubpicture);
+ }
+ pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
+ for (i=0; i < VIA_SUBPIC_PALETTE_SIZE; ++i) {
+ tmp = *palette++ << 8;
+ tmp |= *palette++ << 16;
+ tmp |= *palette++ << 24;
+ tmp |= ((i & 0x0f) << 4) | 0x07;
+ pViaSubPic->palette[i] = tmp;
+ }
+
+ pViaXvMC = pViaSubPic->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ sAPriv = SAREAPTR( pViaXvMC );
+ hwlLock(pViaXvMC->xl,1);
+ setLowLevelLocking(pViaXvMC->xl,0);
+
+ /*
+ * If the subpicture is displaying, Immeadiately update it with the
+ * new palette.
+ */
+
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
+ (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
+ viaVideoSubPictureLocked(pViaXvMC->xl,pViaSubPic);
+ }
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+static int findOverlap(unsigned width,unsigned height,
+ short *dstX, short *dstY,
+ short *srcX, short *srcY,
+ unsigned short *areaW, unsigned short *areaH)
+{
+ int
+ w,h;
+ unsigned
+ mWidth,mHeight;
+
+ w = *areaW;
+ h = *areaH;
+
+ if ((*dstX >= width) || (*dstY >= height))
+ return 1;
+ if (*dstX < 0) {
+ w += *dstX;
+ *srcX -= *dstX;
+ *dstX = 0;
+ }
+ if (*dstY < 0) {
+ h += *dstY;
+ *srcY -= *dstY;
+ *dstY = 0;
+ }
+ if ((w <= 0) || ((h <= 0)))
+ return 1;
+ mWidth = width - *dstX;
+ mHeight = height - *dstY;
+ *areaW = (w <= mWidth) ? w : mWidth;
+ *areaH = (h <= mHeight) ? h : mHeight;
+ return 0;
+}
+
+
+
+Status XvMCClearSubpicture (
+ Display *display,
+ XvMCSubpicture *subpicture,
+ short x,
+ short y,
+ unsigned short width,
+ unsigned short height,
+ unsigned int color
+ )
+{
+
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSubPicture *pViaSubPic;
+ short dummyX,dummyY;
+ unsigned long bOffs;
+
+ if((subpicture == NULL) || (display == NULL)) {
+ return BadValue;
+ }
+ if(subpicture->privData == NULL) {
+ return (error_base + XvMCBadSubpicture);
+ }
+ pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
+ pViaXvMC = pViaSubPic->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+ /* Clip clearing area so that it fits inside subpicture. */
+
+ if (findOverlap(subpicture->width, subpicture->height, &x, &y,
+ &dummyX, &dummyY, &width, &height)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+
+ bOffs = pViaSubPic->offset + y*pViaSubPic->stride + x;
+ viaBlit(pViaXvMC->xl, 8, 0, pViaSubPic->stride, bOffs, pViaSubPic->stride,
+ width, height, 1, 1, VIABLIT_FILL, color);
+ pViaSubPic->needsSync = 1;
+ pViaSubPic->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
+ if (flushXvMCLowLevel(pViaXvMC->xl)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadValue;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+Status
+XvMCCompositeSubpicture (
+ Display *display,
+ XvMCSubpicture *subpicture,
+ XvImage *image,
+ short srcx,
+ short srcy,
+ unsigned short width,
+ unsigned short height,
+ short dstx,
+ short dsty
+ )
+{
+
+ unsigned i;
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSubPicture *pViaSubPic;
+ CARD8 *dAddr, *sAddr;
+
+ if((subpicture == NULL) || (display == NULL) || (image == NULL)){
+ return BadValue;
+ }
+ if(NULL == (pViaSubPic = (ViaXvMCSubPicture *)subpicture->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+
+ pViaXvMC = pViaSubPic->privContext;
+
+
+ if (image->id != subpicture->xvimage_id)
+ return BadMatch;
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+
+ /*
+ * Clip copy area so that it fits inside subpicture and image.
+ */
+
+ if (findOverlap(subpicture->width, subpicture->height,
+ &dstx, &dsty, &srcx, &srcy, &width, &height)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+ if (findOverlap(image->width, image->height,
+ &srcx, &srcy, &dstx, &dsty, &width, &height)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+
+ if (pViaSubPic->needsSync) {
+ if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D, 0, pViaSubPic->timeStamp)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadValue;
+ }
+ pViaSubPic->needsSync = 0;
+ }
+
+ for(i=0; i<height; ++i) {
+ dAddr = (((CARD8 *)pViaXvMC->fbAddress) +
+ (pViaSubPic->offset + (dsty+i)*pViaSubPic->stride + dstx));
+ sAddr = (((CARD8 *)image->data) +
+ (image->offsets[0] + (srcy+i)*image->pitches[0] + srcx));
+ memcpy(dAddr,sAddr,width);
+ }
+
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+
+Status
+XvMCBlendSubpicture (
+ Display *display,
+ XvMCSurface *target_surface,
+ XvMCSubpicture *subpicture,
+ short subx,
+ short suby,
+ unsigned short subw,
+ unsigned short subh,
+ short surfx,
+ short surfy,
+ unsigned short surfw,
+ unsigned short surfh
+ )
+{
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCSubPicture *pViaSubPic;
+
+ if((display == NULL) || target_surface == NULL){
+ return BadValue;
+ }
+
+ if (subx || suby || surfx || surfy ||
+ (subw != surfw) || (subh != surfh)) {
+ fprintf(stderr,"ViaXvMC: Only completely overlapping subpicture "
+ "supported.\n");
+ return BadValue;
+ }
+
+ if(NULL == (pViaSurface = target_surface->privData)) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ if (subpicture) {
+
+ if(NULL == (pViaSubPic = subpicture->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+
+ pViaSurface->privSubPic = pViaSubPic;
+ } else {
+ pViaSurface->privSubPic = NULL;
+ }
+ return Success;
+}
+
+Status
+XvMCBlendSubpicture2 (
+ Display *display,
+ XvMCSurface *source_surface,
+ XvMCSurface *target_surface,
+ XvMCSubpicture *subpicture,
+ short subx,
+ short suby,
+ unsigned short subw,
+ unsigned short subh,
+ short surfx,
+ short surfy,
+ unsigned short surfw,
+ unsigned short surfh
+ )
+{
+ ViaXvMCSurface *pViaSurface,*pViaSSurface;
+ ViaXvMCSubPicture *pViaSubPic;
+ ViaXvMCContext *pViaXvMC;
+
+ unsigned width,height;
+
+ if((display == NULL) || target_surface == NULL || source_surface == NULL){
+ return BadValue;
+ }
+
+ if (subx || suby || surfx || surfy ||
+ (subw != surfw) || (subh != surfh)) {
+ fprintf(stderr,"ViaXvMC: Only completely overlapping subpicture "
+ "supported.\n");
+ return BadMatch;
+ }
+
+ if(NULL == (pViaSurface = target_surface->privData)) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ if(NULL == (pViaSSurface = source_surface->privData)) {
+ return (error_base + XvMCBadSurface);
+ }
+ pViaXvMC = pViaSurface->privContext;
+ width = pViaSSurface->width;
+ height = pViaSSurface->height;
+ if (width != pViaSurface->width || height != pViaSSurface->height) {
+ return BadMatch;
+ }
+
+ if (XvMCSyncSurface(display,source_surface)) {
+ return BadValue;
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ viaBlit(pViaXvMC->xl, 8, yOffs(pViaSSurface), pViaSSurface->yStride,
+ yOffs(pViaSurface), pViaSurface->yStride,
+ width, height, 1, 1, VIABLIT_COPY, 0);
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ if (pViaXvMC->chipId != PCI_CHIP_VT3259) {
+
+ /*
+ * YV12 Chroma blit.
+ */
+
+ viaBlit(pViaXvMC->xl, 8, uOffs(pViaSSurface), pViaSSurface->yStride >> 1,
+ uOffs(pViaSurface), pViaSurface->yStride >> 1,
+ width >> 1, height >> 1, 1, 1, VIABLIT_COPY, 0);
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface), pViaSSurface->yStride >> 1,
+ vOffs(pViaSurface), pViaSurface->yStride >> 1,
+ width >> 1, height >> 1, 1, 1, VIABLIT_COPY, 0);
+ } else {
+
+ /*
+ * NV12 Chroma blit.
+ */
+
+ viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface), pViaSSurface->yStride,
+ vOffs(pViaSurface), pViaSurface->yStride,
+ width, height >> 1, 1, 1, VIABLIT_COPY, 0);
+ }
+ pViaSurface->needsSync = 1;
+ pViaSurface->syncMode = LL_MODE_2D;
+ pViaSurface->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
+ if (flushXvMCLowLevel(pViaXvMC->xl)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadValue;
+ }
+ if (subpicture) {
+
+ if(NULL == (pViaSubPic = subpicture->privData)) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return (error_base + XvMCBadSubpicture);
+ }
+
+ pViaSurface->privSubPic = pViaSubPic;
+ } else {
+ pViaSurface->privSubPic = NULL;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+Status
+XvMCSyncSubpicture (Display *display, XvMCSubpicture *subpicture)
+{
+ ViaXvMCSubPicture *pViaSubPic;
+ ViaXvMCContext *pViaXvMC;
+ Status retVal=0;
+
+ if((display == NULL) || subpicture == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSubPic = subpicture->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+
+ pViaXvMC = pViaSubPic->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (pViaSubPic->needsSync) {
+ if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D,
+ 0, pViaSubPic->timeStamp)) {
+ retVal = BadValue;
+ }
+ pViaSubPic->needsSync = 0;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return retVal;
+}
+
+Status
+XvMCFlushSubpicture (Display *display, XvMCSubpicture *subpicture)
+{
+ ViaXvMCSubPicture *pViaSubPic;
+
+ if((display == NULL) || subpicture == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSubPic = subpicture->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+
+ return Success;
+}
+
+Status
+XvMCDestroySubpicture (Display *display, XvMCSubpicture *subpicture)
+{
+ ViaXvMCSubPicture *pViaSubPic;
+ ViaXvMCContext *pViaXvMC;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+
+ if((display == NULL) || subpicture == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSubPic = subpicture->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+ pViaXvMC = pViaSubPic->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+
+ sAPriv = SAREAPTR(pViaXvMC);
+ hwlLock(pViaXvMC->xl,1);
+ setLowLevelLocking(pViaXvMC->xl,0);
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
+ ( pViaSubPic->srfNo | VIA_XVMC_VALID )) {
+ viaVideoSubPictureOffLocked(pViaXvMC->xl);
+ sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] = 0;
+ }
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+
+ XLockDisplay(display);
+ _xvmc_destroy_subpicture(display,subpicture);
+ XUnlockDisplay(display);
+
+ free(pViaSubPic);
+ subpicture->privData = NULL;
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+
+ return Success;
+}
+
+Status
+XvMCGetSubpictureStatus (Display *display, XvMCSubpicture *subpic, int *stat)
+{
+ ViaXvMCSubPicture *pViaSubPic;
+ ViaXvMCContext *pViaXvMC;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+
+
+ if((display == NULL) || subpic == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSubPic = subpic->privData)) {
+ return (error_base + XvMCBadSubpicture);
+ }
+ if (stat) {
+ *stat = 0;
+ pViaXvMC = pViaSubPic->privContext;
+ sAPriv = SAREAPTR( pViaXvMC );
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
+ (pViaSubPic->srfNo | VIA_XVMC_VALID))
+ *stat |= XVMC_DISPLAYING;
+ }
+ return Success;
+}
+
+Status
+XvMCFlushSurface (Display *display, XvMCSurface *surface)
+{
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCContext *pViaXvMC;
+ Status ret;
+
+ if((display == NULL) || surface == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSurface = surface->privData)) {
+ return (error_base + XvMCBadSurface);
+ }
+
+ pViaXvMC = pViaSurface->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (pViaSurface->needsSync)
+ pViaSurface->timeStamp = pViaXvMC->timeStamp =
+ viaDMATimeStampLowLevel(pViaXvMC->xl);
+ ret = (flushXvMCLowLevel(pViaXvMC->xl)) ? BadValue : Success;
+ if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
+ hwlLock(pViaXvMC->xl,0);
+ pViaXvMC->haveDecoder = 0;
+ releaseDecoder(pViaXvMC, 0);
+ hwlUnlock(pViaXvMC->xl,0);
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+}
+
+Status
+XvMCGetSurfaceStatus (Display *display, XvMCSurface *surface, int *stat)
+{
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCContext *pViaXvMC;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+ unsigned i;
+ int ret = 0;
+
+ if((display == NULL) || surface == NULL){
+ return BadValue;
+ }
+ if(NULL == (pViaSurface = surface->privData)) {
+ return (error_base + XvMCBadSurface);
+ }
+ if (stat) {
+ *stat = 0;
+ pViaXvMC = pViaSurface->privContext;
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ sAPriv = SAREAPTR( pViaXvMC );
+ if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort]
+ == (pViaSurface->srfNo | VIA_XVMC_VALID))
+ *stat |= XVMC_DISPLAYING;
+ for (i=0; i<VIA_MAX_RENDSURF; ++i) {
+ if(pViaXvMC->rendSurf[i] ==
+ (pViaSurface->srfNo | VIA_XVMC_VALID)) {
+ *stat |= XVMC_RENDERING;
+ break;
+ }
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ }
+ return ret;
+}
+
+XvAttribute *
+XvMCQueryAttributes (
+ Display *display,
+ XvMCContext *context,
+ int *number
+ )
+{
+ ViaXvMCContext *pViaXvMC;
+ XvAttribute *ret;
+ unsigned long siz;
+
+ *number = 0;
+ if ((display == NULL) || (context == NULL)) {
+ return NULL;
+ }
+
+ if (NULL == (pViaXvMC = context->privData)) {
+ return NULL;
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (NULL != (ret = (XvAttribute *)
+ malloc(siz = VIA_NUM_XVMC_ATTRIBUTES*sizeof(XvAttribute)))) {
+ memcpy(ret,pViaXvMC->attribDesc,siz);
+ *number = VIA_NUM_XVMC_ATTRIBUTES;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+
+ return ret;
+}
+
+Status
+XvMCSetAttribute (
+ Display *display,
+ XvMCContext *context,
+ Atom attribute,
+ int value
+ )
+{
+ int found;
+ unsigned i;
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCCommandBuffer buf;
+
+ if ((display == NULL) || (context == NULL)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ if (NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+
+ found = 0;
+ for (i=0; i < pViaXvMC->attrib.numAttr; ++i) {
+ if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
+ if ((!(pViaXvMC->attribDesc[i].flags & XvSettable)) ||
+ value < pViaXvMC->attribDesc[i].min_value ||
+ value > pViaXvMC->attribDesc[i].max_value)
+ return BadValue;
+ pViaXvMC->attrib.attributes[i].value = value;
+ found = 1;
+ pViaXvMC->attribChanged = 1;
+ break;
+ }
+ }
+ if (!found) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return BadMatch;
+ }
+ if (pViaXvMC->haveXv) {
+ buf.command = VIA_XVMC_COMMAND_ATTRIBUTES;
+ pViaXvMC->xvImage->data = (char *)&buf;
+ buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
+ buf.attrib = pViaXvMC->attrib;
+ XLockDisplay(display);
+ pViaXvMC->attribChanged =
+ XvPutImage(display,pViaXvMC->port,pViaXvMC->draw,
+ pViaXvMC->gc,
+ pViaXvMC->xvImage,0,0,1,1,0,0,1,1);
+ XUnlockDisplay(display);
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}
+
+
+Status
+XvMCGetAttribute (
+ Display *display,
+ XvMCContext *context,
+ Atom attribute,
+ int *value
+ )
+{
+ int found;
+ unsigned i;
+ ViaXvMCContext *pViaXvMC;
+
+ if ((display == NULL) || (context == NULL)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ if (NULL == (pViaXvMC = context->privData)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ found = 0;
+ for (i=0; i < pViaXvMC->attrib.numAttr; ++i) {
+ if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
+ if (pViaXvMC->attribDesc[i].flags & XvGettable) {
+ *value = pViaXvMC->attrib.attributes[i].value;
+ found = 1;
+ break;
+ }
+ }
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+
+ if (!found)
+ return BadMatch;
+ return Success;
+}
+
+
+Status XvMCHideSurface(Display *display,XvMCSurface *surface)
+{
+
+ ViaXvMCSurface *pViaSurface;
+ ViaXvMCContext *pViaXvMC;
+ ViaXvMCSubPicture *pViaSubPic;
+ volatile ViaXvMCSAreaPriv *sAPriv;
+ ViaXvMCCommandBuffer buf;
+ Status ret;
+
+ if ((display == NULL) || (surface == NULL)) {
+ return BadValue;
+ }
+ if (NULL == (pViaSurface = surface->privData )) {
+ return (error_base + XvMCBadSurface);
+ }
+ if (NULL == (pViaXvMC = pViaSurface->privContext)) {
+ return (error_base + XvMCBadContext);
+ }
+
+ ppthread_mutex_lock( &pViaXvMC->ctxMutex );
+ if (!pViaXvMC->haveXv) {
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+
+ sAPriv = SAREAPTR( pViaXvMC );
+ hwlLock(pViaXvMC->xl,1);
+
+ if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] !=
+ (pViaSurface->srfNo | VIA_XVMC_VALID)) {
+ hwlUnlock(pViaXvMC->xl,1);
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+ }
+ setLowLevelLocking(pViaXvMC->xl,0);
+ if (NULL != (pViaSubPic = pViaSurface->privSubPic)) {
+ if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
+ (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
+ sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
+ viaVideoSubPictureOffLocked(pViaXvMC->xl);
+ }
+ }
+ flushPCIXvMCLowLevel(pViaXvMC->xl);
+ setLowLevelLocking(pViaXvMC->xl,1);
+ hwlUnlock(pViaXvMC->xl,1);
+
+ buf.command = VIA_XVMC_COMMAND_UNDISPLAY;
+ buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
+ buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
+ pViaXvMC->xvImage->data = (char *)&buf;
+ if ((ret = XvPutImage(display,pViaXvMC->port,pViaXvMC->draw,
+ pViaXvMC->gc,
+ pViaXvMC->xvImage,0,0,1,1,0,0,1,1))) {
+ fprintf(stderr,"XvMCPutSurface: Hiding overlay failed.\n");
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return ret;
+ }
+ ppthread_mutex_unlock( &pViaXvMC->ctxMutex );
+ return Success;
+}