diff options
Diffstat (limited to 'nx-X11/lib/XvMC/hw/via/viaXvMC.c')
-rw-r--r-- | nx-X11/lib/XvMC/hw/via/viaXvMC.c | 1964 |
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; +} |