190b17f1bSmrg/*****************************************************************************
290b17f1bSmrg * VIA Unichrome XvMC extension client lib.
390b17f1bSmrg *
490b17f1bSmrg * Copyright (c) 2004-2005 Thomas Hellstr�m. All rights reserved.
590b17f1bSmrg *
690b17f1bSmrg * Permission is hereby granted, free of charge, to any person obtaining a
790b17f1bSmrg * copy of this software and associated documentation files (the "Software"),
890b17f1bSmrg * to deal in the Software without restriction, including without limitation
990b17f1bSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1090b17f1bSmrg * and/or sell copies of the Software, and to permit persons to whom the
1190b17f1bSmrg * Software is furnished to do so, subject to the following conditions:
1290b17f1bSmrg *
1390b17f1bSmrg * The above copyright notice and this permission notice shall be included in
1490b17f1bSmrg * all copies or substantial portions of the Software.
1590b17f1bSmrg *
1690b17f1bSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1790b17f1bSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1890b17f1bSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1990b17f1bSmrg * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2090b17f1bSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2190b17f1bSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2290b17f1bSmrg * DEALINGS IN THE SOFTWARE.
2390b17f1bSmrg */
2490b17f1bSmrg
2590b17f1bSmrg/*
2690b17f1bSmrg *Author: Thomas Hellstr�m, 2004.
2790b17f1bSmrg *Bugfixes by among others Pascal Brisset and Terry Barnaby.
2890b17f1bSmrg *DRI protocol support by Thomas Hellstr�m, 2005.
2990b17f1bSmrg */
3090b17f1bSmrg
3190b17f1bSmrg#undef WAITPAUSE
3290b17f1bSmrg
3390b17f1bSmrg#include "viaXvMCPriv.h"
3490b17f1bSmrg#include "viaLowLevel.h"
3590b17f1bSmrg#include <stdio.h>
3690b17f1bSmrg#include <sys/ioctl.h>
3790b17f1bSmrg#include <sys/time.h>
3890b17f1bSmrg#include <time.h>
3990b17f1bSmrg#include <fourcc.h>
4090b17f1bSmrg#include <X11/extensions/Xv.h>
4190b17f1bSmrg#include <xf86drm.h>
4290b17f1bSmrg#include <pthread.h>
4390b17f1bSmrg#include "vldXvMC.h"
4490b17f1bSmrg#include "xf86dri.h"
4590b17f1bSmrg#include "driDrawable.h"
4690b17f1bSmrg
4790b17f1bSmrg#define SAREAPTR(ctx) ((ViaXvMCSAreaPriv *)			\
4890b17f1bSmrg		       (((CARD8 *)(ctx)->sAreaAddress) +	\
4990b17f1bSmrg			(ctx)->sAreaPrivOffset))
5090b17f1bSmrg
5190b17f1bSmrgtypedef struct
5290b17f1bSmrg{
5390b17f1bSmrg    int major;
5490b17f1bSmrg    int minor;
5590b17f1bSmrg    int patchlevel;
5690b17f1bSmrg} ViaDRMVersion;
5790b17f1bSmrg
5890b17f1bSmrgstatic int error_base;
5990b17f1bSmrgstatic int event_base;
6090b17f1bSmrgstatic unsigned numContexts = 0;
6190b17f1bSmrgstatic int globalFD;
6290b17f1bSmrgstatic drmAddress sAreaAddress;
6390b17f1bSmrgstatic drmAddress fbAddress;
6490b17f1bSmrgstatic drmAddress mmioAddress;
6590b17f1bSmrgstatic const ViaDRMVersion drmExpected = { 2, 0, 0 };
6690b17f1bSmrgstatic const ViaDRMVersion drmCompat = { 2, 0, 0 };
6790b17f1bSmrg
6890b17f1bSmrg#define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
6990b17f1bSmrg
7090b17f1bSmrg#define ppthread_mutex_lock(arg)		\
7190b17f1bSmrg  {						\
7290b17f1bSmrg    pthread_mutex_lock(arg);			\
7390b17f1bSmrg  }						\
7490b17f1bSmrg
7590b17f1bSmrg#define ppthread_mutex_unlock(arg)		\
7690b17f1bSmrg  {						\
7790b17f1bSmrg    pthread_mutex_unlock(arg);			\
7890b17f1bSmrg  }						\
7990b17f1bSmrg
8090b17f1bSmrgstatic unsigned
8190b17f1bSmrgyOffs(ViaXvMCSurface * srf)
8290b17f1bSmrg{
8390b17f1bSmrg    return srf->offsets[0];
8490b17f1bSmrg}
8590b17f1bSmrg
8690b17f1bSmrgstatic unsigned
8790b17f1bSmrgvOffs(ViaXvMCSurface * srf)
8890b17f1bSmrg{
8990b17f1bSmrg    return srf->offsets[0] + srf->yStride * srf->height;
9090b17f1bSmrg}
9190b17f1bSmrg
9290b17f1bSmrgstatic unsigned
9390b17f1bSmrguOffs(ViaXvMCSurface * srf)
9490b17f1bSmrg{
9590b17f1bSmrg    return srf->offsets[0] + (srf->yStride * srf->height) +
9690b17f1bSmrg	(srf->yStride >> 1) * (srf->height >> 1);
9790b17f1bSmrg}
9890b17f1bSmrg
9990b17f1bSmrgstatic void
10090b17f1bSmrgdefaultQMatrices(ViaXvMCContext * ctx)
10190b17f1bSmrg{
10290b17f1bSmrg    int i;
10390b17f1bSmrg
10490b17f1bSmrg    static const char intra[64] = {
10590b17f1bSmrg	8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37,
10690b17f1bSmrg	19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40,
10790b17f1bSmrg	22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58,
10890b17f1bSmrg	26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83
10990b17f1bSmrg    };
11090b17f1bSmrg
11190b17f1bSmrg    for (i = 0; i < 64; ++i) {
11290b17f1bSmrg	ctx->intra_quantiser_matrix[i] = intra[i];
11390b17f1bSmrg	ctx->non_intra_quantiser_matrix[i] = 16;
11490b17f1bSmrg    }
11590b17f1bSmrg    ctx->intraLoaded = 0;
11690b17f1bSmrg    ctx->nonIntraLoaded = 0;
11790b17f1bSmrg}
11890b17f1bSmrg
11990b17f1bSmrgstatic void
12090b17f1bSmrgreleaseDecoder(ViaXvMCContext * ctx, int clearCtx)
12190b17f1bSmrg{
12290b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
12390b17f1bSmrg
12490b17f1bSmrg    sAPriv = SAREAPTR(ctx);
12590b17f1bSmrg    UNICHROME_UNLOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv,
12690b17f1bSmrg	ctx->drmcontext);
12790b17f1bSmrg}
12890b17f1bSmrg
12990b17f1bSmrgstatic int
13090b17f1bSmrggrabDecoder(ViaXvMCContext * ctx, int *hadLastLock)
13190b17f1bSmrg{
13290b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv = SAREAPTR(ctx);
13390b17f1bSmrg    int retFtx, lc;
13490b17f1bSmrg
13590b17f1bSmrg    /*
13690b17f1bSmrg     * Try to grab the decoder. If it is not available we will sleep until
13790b17f1bSmrg     * it becomes available or for a maximum of 20 ms.
13890b17f1bSmrg     * Then try to grab it again, unless a timeout occured. If the decoder is
13990b17f1bSmrg     * available, the lock should be reasonably fast.
14090b17f1bSmrg     */
14190b17f1bSmrg
14290b17f1bSmrg    if (ctx->haveDecoder) {
14390b17f1bSmrg	flushXvMCLowLevel(ctx->xl);    /* Ignore errors here. */
14490b17f1bSmrg
14590b17f1bSmrg	/*fprintf(stderr,"ViaXvMC: ERROR: Trying to re-lock decoder.\n"); */
14690b17f1bSmrg	*hadLastLock = 1;
14790b17f1bSmrg	return 0;
14890b17f1bSmrg    }
14990b17f1bSmrg    UNICHROME_LOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv, ctx->drmcontext,
15090b17f1bSmrg	lc, retFtx);
15190b17f1bSmrg    *hadLastLock = (ctx->drmcontext == lc);
15290b17f1bSmrg
15390b17f1bSmrg    return retFtx;
15490b17f1bSmrg}
15590b17f1bSmrg
15690b17f1bSmrgstatic void
15790b17f1bSmrgsetupAttribDesc(Display * display, XvPortID port,
15890b17f1bSmrg    const ViaXvMCAttrHolder * attrib, XvAttribute attribDesc[])
15990b17f1bSmrg{
16090b17f1bSmrg    XvAttribute *XvAttribs, *curAD;
16190b17f1bSmrg    int num;
16290b17f1bSmrg    unsigned i, j;
16390b17f1bSmrg
16490b17f1bSmrg    XLockDisplay(display);
16590b17f1bSmrg    XvAttribs = XvQueryPortAttributes(display, port, &num);
16690b17f1bSmrg    for (i = 0; i < attrib->numAttr; ++i) {
16790b17f1bSmrg	curAD = attribDesc + i;
16890b17f1bSmrg	curAD->flags = 0;
16990b17f1bSmrg	curAD->min_value = 0;
17090b17f1bSmrg	curAD->max_value = 0;
17190b17f1bSmrg	curAD->name = NULL;
17290b17f1bSmrg	for (j = 0; j < num; ++j) {
17390b17f1bSmrg	    if (attrib->attributes[i].attribute ==
17490b17f1bSmrg		XInternAtom(display, XvAttribs[j].name, TRUE)) {
17590b17f1bSmrg		*curAD = XvAttribs[j];
17690b17f1bSmrg		curAD->name = strdup(XvAttribs[j].name);
17790b17f1bSmrg		break;
17890b17f1bSmrg	    }
17990b17f1bSmrg	}
18090b17f1bSmrg    }
18190b17f1bSmrg    if (XvAttribs)
18290b17f1bSmrg	XFree(XvAttribs);
18390b17f1bSmrg    XUnlockDisplay(display);
18490b17f1bSmrg
18590b17f1bSmrg}
18690b17f1bSmrg
18790b17f1bSmrgstatic void
18890b17f1bSmrgreleaseAttribDesc(int numAttr, XvAttribute attribDesc[])
18990b17f1bSmrg{
19090b17f1bSmrg    int i;
19190b17f1bSmrg
19290b17f1bSmrg    for (i = 0; i < numAttr; ++i) {
19390b17f1bSmrg	if (attribDesc[i].name)
19490b17f1bSmrg	    free(attribDesc[i].name);
19590b17f1bSmrg    }
19690b17f1bSmrg}
19790b17f1bSmrg
19890b17f1bSmrgstatic Status
19990b17f1bSmrgreleaseContextResources(Display * display, XvMCContext * context,
20090b17f1bSmrg    int freePrivate, Status errType)
20190b17f1bSmrg{
20290b17f1bSmrg    ViaXvMCContext *pViaXvMC = (ViaXvMCContext *) context->privData;
20390b17f1bSmrg
20490b17f1bSmrg    switch (pViaXvMC->resources) {
20590b17f1bSmrg    case context_drawHash:
20690b17f1bSmrg	driDestroyHashContents(pViaXvMC->drawHash);
20790b17f1bSmrg	drmHashDestroy(pViaXvMC->drawHash);
20890b17f1bSmrg    case context_lowLevel:
20990b17f1bSmrg	closeXvMCLowLevel(pViaXvMC->xl);
21090b17f1bSmrg    case context_mutex:
21190b17f1bSmrg	pthread_mutex_destroy(&pViaXvMC->ctxMutex);
21290b17f1bSmrg    case context_drmContext:
21390b17f1bSmrg	XLockDisplay(display);
21490b17f1bSmrg	uniDRIDestroyContext(display, pViaXvMC->screen, pViaXvMC->id);
21590b17f1bSmrg	XUnlockDisplay(display);
21690b17f1bSmrg    case context_sAreaMap:
21790b17f1bSmrg	numContexts--;
21890b17f1bSmrg	if (numContexts == 0)
21990b17f1bSmrg	    drmUnmap(pViaXvMC->sAreaAddress, pViaXvMC->sAreaSize);
22090b17f1bSmrg    case context_fbMap:
22190b17f1bSmrg	if (numContexts == 0)
22290b17f1bSmrg	    drmUnmap(pViaXvMC->fbAddress, pViaXvMC->fbSize);
22390b17f1bSmrg    case context_mmioMap:
22490b17f1bSmrg	if (numContexts == 0)
22590b17f1bSmrg	    drmUnmap(pViaXvMC->mmioAddress, pViaXvMC->mmioSize);
22690b17f1bSmrg    case context_fd:
22790b17f1bSmrg	if (numContexts == 0) {
22890b17f1bSmrg	    if (pViaXvMC->fd >= 0)
22990b17f1bSmrg		drmClose(pViaXvMC->fd);
23090b17f1bSmrg	}
23190b17f1bSmrg	pViaXvMC->fd = -1;
23290b17f1bSmrg    case context_driConnection:
23390b17f1bSmrg	if (numContexts == 0) {
23490b17f1bSmrg	    XLockDisplay(display);
23590b17f1bSmrg	    uniDRICloseConnection(display, pViaXvMC->screen);
23690b17f1bSmrg	    XUnlockDisplay(display);
23790b17f1bSmrg	}
23890b17f1bSmrg    case context_context:
23990b17f1bSmrg	XLockDisplay(display);
24090b17f1bSmrg	_xvmc_destroy_context(display, context);
24190b17f1bSmrg	XUnlockDisplay(display);
24290b17f1bSmrg	if (!freePrivate)
24390b17f1bSmrg	    break;
24490b17f1bSmrg    default:
24590b17f1bSmrg	free(pViaXvMC);
24690b17f1bSmrg	context->privData = NULL;
24790b17f1bSmrg    }
24890b17f1bSmrg    return errType;
24990b17f1bSmrg}
25090b17f1bSmrg
25190b17f1bSmrg_X_EXPORT Status
25290b17f1bSmrgXvMCCreateContext(Display * display, XvPortID port,
25390b17f1bSmrg    int surface_type_id, int width, int height, int flags,
25490b17f1bSmrg    XvMCContext * context)
25590b17f1bSmrg{
25690b17f1bSmrg    ViaXvMCContext *pViaXvMC;
25790b17f1bSmrg    int priv_count;
25890b17f1bSmrg    uint *priv_data;
25990b17f1bSmrg    uint magic;
26090b17f1bSmrg    unsigned i;
26190b17f1bSmrg    Status ret;
26290b17f1bSmrg    int major, minor;
26390b17f1bSmrg    ViaXvMCCreateContextRec *tmpComm;
26490b17f1bSmrg    drmVersionPtr drmVer;
26590b17f1bSmrg    char *curBusID;
26690b17f1bSmrg    int isCapable;
26790b17f1bSmrg
26890b17f1bSmrg    /*
26990b17f1bSmrg     * Verify Obvious things first
27090b17f1bSmrg     */
27190b17f1bSmrg
27290b17f1bSmrg    if (context == NULL) {
27390b17f1bSmrg	return XvMCBadContext;
27490b17f1bSmrg    }
27590b17f1bSmrg
27690b17f1bSmrg    if (!(flags & XVMC_DIRECT)) {
27790b17f1bSmrg	fprintf(stderr, "Indirect Rendering not supported! Using Direct.\n");
27890b17f1bSmrg    }
27990b17f1bSmrg
28090b17f1bSmrg    /*
28190b17f1bSmrg     *FIXME: Check $DISPLAY for legal values here
28290b17f1bSmrg     */
28390b17f1bSmrg
28490b17f1bSmrg    context->surface_type_id = surface_type_id;
28590b17f1bSmrg    context->width = (unsigned short)((width + 15) & ~15);
28690b17f1bSmrg    context->height = (unsigned short)((height + 15) & ~15);
28790b17f1bSmrg    context->flags = flags;
28890b17f1bSmrg    context->port = port;
28990b17f1bSmrg
29090b17f1bSmrg    /*
29190b17f1bSmrg     *  Width, Height, and flags are checked against surface_type_id
29290b17f1bSmrg     *  and port for validity inside the X server, no need to check
29390b17f1bSmrg     *  here.
29490b17f1bSmrg     */
29590b17f1bSmrg
29690b17f1bSmrg    /* Allocate private Context data */
29790b17f1bSmrg    context->privData = (void *)malloc(sizeof(ViaXvMCContext));
29890b17f1bSmrg    if (!context->privData) {
29990b17f1bSmrg	fprintf(stderr, "Unable to allocate resources for XvMC context.\n");
30090b17f1bSmrg	return BadAlloc;
30190b17f1bSmrg    }
30290b17f1bSmrg
30390b17f1bSmrg    pViaXvMC = (ViaXvMCContext *) context->privData;
30490b17f1bSmrg    pViaXvMC->resources = context_none;
30590b17f1bSmrg
30690b17f1bSmrg    /* Verify the XvMC extension exists */
30790b17f1bSmrg
30890b17f1bSmrg    XLockDisplay(display);
30990b17f1bSmrg    if (!XvMCQueryExtension(display, &event_base, &error_base)) {
31090b17f1bSmrg	fprintf(stderr, "XvMC Extension is not available!\n");
31190b17f1bSmrg	free(pViaXvMC);
31290b17f1bSmrg	XUnlockDisplay(display);
31390b17f1bSmrg	return BadAlloc;
31490b17f1bSmrg    }
31590b17f1bSmrg
31690b17f1bSmrg    /* Verify XvMC version */
31790b17f1bSmrg    ret = XvMCQueryVersion(display, &major, &minor);
31890b17f1bSmrg    if (ret) {
31990b17f1bSmrg	fprintf(stderr, "XvMCQuery Version Failed, unable to determine "
32090b17f1bSmrg	    "protocol version!\n");
32190b17f1bSmrg    }
32290b17f1bSmrg    XUnlockDisplay(display);
32390b17f1bSmrg
32490b17f1bSmrg    /* FIXME: Check Major and Minor here */
32590b17f1bSmrg
32690b17f1bSmrg    XLockDisplay(display);
32790b17f1bSmrg    if ((ret = _xvmc_create_context(display, context, &priv_count,
32890b17f1bSmrg		&priv_data))) {
32990b17f1bSmrg	XUnlockDisplay(display);
33090b17f1bSmrg	fprintf(stderr, "Unable to create XvMC Context!\n");
33190b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
33290b17f1bSmrg    }
33390b17f1bSmrg    XUnlockDisplay(display);
33490b17f1bSmrg
33590b17f1bSmrg    /*
33690b17f1bSmrg     * Check size and version of returned data.
33790b17f1bSmrg     */
33890b17f1bSmrg
33990b17f1bSmrg    tmpComm = (ViaXvMCCreateContextRec *) priv_data;
34090b17f1bSmrg    if (priv_count != (sizeof(ViaXvMCCreateContextRec) >> 2)) {
34190b17f1bSmrg	fprintf(stderr, "_xvmc_create_context() returned incorrect "
34290b17f1bSmrg	    "data size!\n");
34390b17f1bSmrg	fprintf(stderr, "\tExpected %d, got %d\n",
34490b17f1bSmrg	    ((int)(sizeof(ViaXvMCCreateContextRec) >> 2)), priv_count);
34590b17f1bSmrg	XFree(priv_data);
34690b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
34790b17f1bSmrg    }
34890b17f1bSmrg    pViaXvMC->resources = context_context;
34990b17f1bSmrg
35090b17f1bSmrg    if ((tmpComm->major != VIAXVMC_MAJOR) ||
35190b17f1bSmrg	(tmpComm->minor != VIAXVMC_MINOR)) {
35290b17f1bSmrg	fprintf(stderr, "Version mismatch between the X via driver\n"
35390b17f1bSmrg	    "and the XvMC library. Cannot continue!\n");
35490b17f1bSmrg	XFree(priv_data);
35590b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
35690b17f1bSmrg    }
35790b17f1bSmrg
35890b17f1bSmrg    pViaXvMC->ctxNo = tmpComm->ctxNo;
35990b17f1bSmrg    pViaXvMC->fbOffset = tmpComm->fbOffset;
36090b17f1bSmrg    pViaXvMC->fbSize = tmpComm->fbSize;
36190b17f1bSmrg    pViaXvMC->mmioOffset = tmpComm->mmioOffset;
36290b17f1bSmrg    pViaXvMC->mmioSize = tmpComm->mmioSize;
36390b17f1bSmrg    pViaXvMC->sAreaSize = tmpComm->sAreaSize;
36490b17f1bSmrg    pViaXvMC->sAreaPrivOffset = tmpComm->sAreaPrivOffset;
36590b17f1bSmrg    pViaXvMC->decoderOn = 0;
36690b17f1bSmrg    pViaXvMC->xvMCPort = tmpComm->xvmc_port;
36790b17f1bSmrg    pViaXvMC->useAGP = tmpComm->useAGP;
36890b17f1bSmrg    pViaXvMC->attrib = tmpComm->initAttrs;
36990b17f1bSmrg    pViaXvMC->screen = tmpComm->screen;
37090b17f1bSmrg    pViaXvMC->depth = tmpComm->depth;
37190b17f1bSmrg    pViaXvMC->stride = tmpComm->stride;
37290b17f1bSmrg    pViaXvMC->chipId = tmpComm->chipId;
37390b17f1bSmrg
37490b17f1bSmrg    /*
37590b17f1bSmrg     * Must free the private data we were passed from X
37690b17f1bSmrg     */
37790b17f1bSmrg
37890b17f1bSmrg    XFree(priv_data);
37990b17f1bSmrg    priv_data = NULL;
38090b17f1bSmrg
38190b17f1bSmrg    /*
38290b17f1bSmrg     * Check for direct rendering capable, establish DRI and DRM connections,
38390b17f1bSmrg     * map framebuffer, DRI shared area and read-only register areas.
38490b17f1bSmrg     * Initial checking for drm has already been done by the server.
38590b17f1bSmrg     * Only do this for the first context we create.
38690b17f1bSmrg     */
38790b17f1bSmrg
38890b17f1bSmrg    if (numContexts == 0) {
38990b17f1bSmrg	XLockDisplay(display);
39090b17f1bSmrg	ret =
39190b17f1bSmrg	    uniDRIQueryDirectRenderingCapable(display, pViaXvMC->screen,
39290b17f1bSmrg	    &isCapable);
39390b17f1bSmrg	if (!ret || !isCapable) {
39490b17f1bSmrg	    XUnlockDisplay(display);
39590b17f1bSmrg	    fprintf(stderr,
39690b17f1bSmrg		"Direct Rendering is not available on this system!\n");
39790b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
39890b17f1bSmrg	}
39990b17f1bSmrg
40090b17f1bSmrg	if (!uniDRIOpenConnection(display, pViaXvMC->screen,
40190b17f1bSmrg		&pViaXvMC->sAreaOffset, &curBusID)) {
40290b17f1bSmrg	    XUnlockDisplay(display);
40390b17f1bSmrg	    fprintf(stderr, "Could not open DRI connection to X server!\n");
40490b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
40590b17f1bSmrg	}
40690b17f1bSmrg	XUnlockDisplay(display);
40790b17f1bSmrg
40890b17f1bSmrg	strncpy(pViaXvMC->busIdString, curBusID, 20);
40990b17f1bSmrg	pViaXvMC->busIdString[20] = '\0';
41090b17f1bSmrg	XFree(curBusID);
41190b17f1bSmrg
41290b17f1bSmrg	pViaXvMC->resources = context_driConnection;
41390b17f1bSmrg
41490b17f1bSmrg	if ((pViaXvMC->fd = drmOpen("via", pViaXvMC->busIdString)) < 0) {
41590b17f1bSmrg	    fprintf(stderr, "DRM Device for via could not be opened.\n");
41690b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
41790b17f1bSmrg	}
41890b17f1bSmrg	globalFD = pViaXvMC->fd;
41990b17f1bSmrg	pViaXvMC->resources = context_fd;
42090b17f1bSmrg
42190b17f1bSmrg	if (NULL == (drmVer = drmGetVersion(pViaXvMC->fd))) {
42290b17f1bSmrg	    fprintf(stderr, "viaXvMC: Could not get drm version.");
42390b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
42490b17f1bSmrg	}
42590b17f1bSmrg	if ((drmVer->version_major < drmExpected.major) ||
42690b17f1bSmrg	    (drmVer->version_major > drmCompat.major) ||
42790b17f1bSmrg	    ((drmVer->version_major == drmExpected.major) &&
42890b17f1bSmrg		(drmVer->version_minor < drmExpected.minor))) {
42990b17f1bSmrg	    fprintf(stderr,
43090b17f1bSmrg		"viaXvMC: Kernel drm is not compatible with XvMC.\n");
43190b17f1bSmrg	    fprintf(stderr,
43290b17f1bSmrg		"viaXvMC: Kernel drm version: %d.%d.%d "
43390b17f1bSmrg		"and I can work with versions %d.%d.x - %d.x.x\n"
43490b17f1bSmrg		"Please update either this XvMC driver or your kernel DRM.\n",
43590b17f1bSmrg		drmVer->version_major, drmVer->version_minor,
43690b17f1bSmrg		drmVer->version_patchlevel, drmExpected.major,
43790b17f1bSmrg		drmExpected.minor, drmCompat.major);
43890b17f1bSmrg	    drmFreeVersion(drmVer);
43990b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
44090b17f1bSmrg	}
44190b17f1bSmrg	drmFreeVersion(drmVer);
44290b17f1bSmrg	drmGetMagic(pViaXvMC->fd, &magic);
44390b17f1bSmrg
44490b17f1bSmrg	XLockDisplay(display);
44590b17f1bSmrg	if (!uniDRIAuthConnection(display, pViaXvMC->screen, magic)) {
44690b17f1bSmrg	    XUnlockDisplay(display);
44790b17f1bSmrg	    fprintf(stderr,
44890b17f1bSmrg		"viaXvMC: X server did not allow DRI. Check permissions.\n");
44990b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
45090b17f1bSmrg	}
45190b17f1bSmrg	XUnlockDisplay(display);
45290b17f1bSmrg
45390b17f1bSmrg	/*
45490b17f1bSmrg	 * Map the register memory
45590b17f1bSmrg	 */
45690b17f1bSmrg
45790b17f1bSmrg	if (drmMap(pViaXvMC->fd, pViaXvMC->mmioOffset,
45890b17f1bSmrg		pViaXvMC->mmioSize, &mmioAddress) < 0) {
45990b17f1bSmrg	    fprintf(stderr,
46090b17f1bSmrg		"Unable to map the display chip mmio registers.\n");
46190b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
46290b17f1bSmrg	}
46390b17f1bSmrg	pViaXvMC->mmioAddress = mmioAddress;
46490b17f1bSmrg	pViaXvMC->resources = context_mmioMap;
46590b17f1bSmrg
46690b17f1bSmrg	/*
46790b17f1bSmrg	 * Map Framebuffer memory
46890b17f1bSmrg	 */
46990b17f1bSmrg
47090b17f1bSmrg	if (drmMap(pViaXvMC->fd, pViaXvMC->fbOffset,
47190b17f1bSmrg		pViaXvMC->fbSize, &fbAddress) < 0) {
47290b17f1bSmrg	    fprintf(stderr, "Unable to map XvMC Framebuffer.\n");
47390b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
47490b17f1bSmrg	}
47590b17f1bSmrg	pViaXvMC->fbAddress = fbAddress;
47690b17f1bSmrg	pViaXvMC->resources = context_fbMap;
47790b17f1bSmrg
47890b17f1bSmrg	/*
47990b17f1bSmrg	 * Map DRI Sarea.
48090b17f1bSmrg	 */
48190b17f1bSmrg
48290b17f1bSmrg	if (drmMap(pViaXvMC->fd, pViaXvMC->sAreaOffset,
48390b17f1bSmrg		pViaXvMC->sAreaSize, &sAreaAddress) < 0) {
48490b17f1bSmrg	    fprintf(stderr, "Unable to map DRI SAREA.\n");
48590b17f1bSmrg	    return releaseContextResources(display, context, 1, BadAlloc);
48690b17f1bSmrg	}
48790b17f1bSmrg    } else {
48890b17f1bSmrg	pViaXvMC->fd = globalFD;
48990b17f1bSmrg	pViaXvMC->mmioAddress = mmioAddress;
49090b17f1bSmrg	pViaXvMC->fbAddress = fbAddress;
49190b17f1bSmrg    }
49290b17f1bSmrg
49390b17f1bSmrg    pViaXvMC->sAreaAddress = sAreaAddress;
49490b17f1bSmrg    pViaXvMC->resources = context_sAreaMap;
49590b17f1bSmrg    numContexts++;
49690b17f1bSmrg
49790b17f1bSmrg    /*
49890b17f1bSmrg     * Find a matching visual. Important only for direct drawing to the visible
49990b17f1bSmrg     * frame-buffer.
50090b17f1bSmrg     */
50190b17f1bSmrg
50290b17f1bSmrg    XLockDisplay(display);
50390b17f1bSmrg    ret = XMatchVisualInfo(display, pViaXvMC->screen,
50490b17f1bSmrg	(pViaXvMC->depth == 32) ? 24 : pViaXvMC->depth, TrueColor,
50590b17f1bSmrg	&pViaXvMC->visualInfo);
50690b17f1bSmrg    XUnlockDisplay(display);
50790b17f1bSmrg    if (!ret) {
50890b17f1bSmrg	fprintf(stderr,
50990b17f1bSmrg	    "viaXvMC: Could not find a matching TrueColor visual.\n");
51090b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
51190b17f1bSmrg    }
51290b17f1bSmrg
51390b17f1bSmrg    if (!uniDRICreateContext(display, pViaXvMC->screen,
51490b17f1bSmrg	    pViaXvMC->visualInfo.visual, &pViaXvMC->id,
51590b17f1bSmrg	    &pViaXvMC->drmcontext)) {
51690b17f1bSmrg
51790b17f1bSmrg	fprintf(stderr, "viaXvMC: Could not create DRI context.\n");
51890b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
51990b17f1bSmrg    }
52090b17f1bSmrg
52190b17f1bSmrg    pViaXvMC->resources = context_drmContext;
52290b17f1bSmrg
52390b17f1bSmrg    for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
52490b17f1bSmrg	pViaXvMC->rendSurf[i] = 0;
52590b17f1bSmrg    }
52690b17f1bSmrg    pViaXvMC->lastSrfDisplaying = ~0;
52790b17f1bSmrg    setupAttribDesc(display, port, &pViaXvMC->attrib, pViaXvMC->attribDesc);
52890b17f1bSmrg
52990b17f1bSmrg    pViaXvMC->hwLock = (drmLockPtr) pViaXvMC->sAreaAddress;
53090b17f1bSmrg    defaultQMatrices(pViaXvMC);
53190b17f1bSmrg    pViaXvMC->chromaIntraLoaded = 1;
53290b17f1bSmrg    pViaXvMC->chromaNonIntraLoaded = 1;
53390b17f1bSmrg    pViaXvMC->yStride = (width + 31) & ~31;
53490b17f1bSmrg    pViaXvMC->haveDecoder = 0;
53590b17f1bSmrg    pViaXvMC->attribChanged = 1;
53690b17f1bSmrg    pViaXvMC->haveXv = 0;
53790b17f1bSmrg    pViaXvMC->port = context->port;
53890b17f1bSmrg    pthread_mutex_init(&pViaXvMC->ctxMutex, NULL);
53990b17f1bSmrg    pViaXvMC->resources = context_mutex;
54090b17f1bSmrg    pViaXvMC->timeStamp = 0;
54190b17f1bSmrg    setRegion(0, 0, -1, -1, pViaXvMC->sRegion);
54290b17f1bSmrg    setRegion(0, 0, -1, -1, pViaXvMC->dRegion);
54390b17f1bSmrg
54490b17f1bSmrg    if (NULL == (pViaXvMC->xl =
54590b17f1bSmrg	    initXvMCLowLevel(pViaXvMC->fd, &pViaXvMC->drmcontext,
54690b17f1bSmrg		pViaXvMC->hwLock, pViaXvMC->mmioAddress,
54790b17f1bSmrg		pViaXvMC->fbAddress, pViaXvMC->stride, pViaXvMC->depth,
54890b17f1bSmrg		context->width, context->height,
54990b17f1bSmrg		pViaXvMC->useAGP, pViaXvMC->chipId))) {
55090b17f1bSmrg
55190b17f1bSmrg	fprintf(stderr, "ViaXvMC: Could not allocate timestamp blit area.\n");
55290b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
55390b17f1bSmrg    }
55490b17f1bSmrg    pViaXvMC->resources = context_lowLevel;
55590b17f1bSmrg    setAGPSyncLowLevel(pViaXvMC->xl, 1, 0);
55690b17f1bSmrg
55790b17f1bSmrg    if (NULL == (pViaXvMC->drawHash = drmHashCreate())) {
55890b17f1bSmrg	fprintf(stderr, "ViaXvMC: Could not allocate drawable hash table.\n");
55990b17f1bSmrg	return releaseContextResources(display, context, 1, BadAlloc);
56090b17f1bSmrg    }
56190b17f1bSmrg    pViaXvMC->resources = context_drawHash;
56290b17f1bSmrg
56390b17f1bSmrg    if (numContexts == 1) {
56490b17f1bSmrg	hwlLock(pViaXvMC->xl, 1);
56590b17f1bSmrg	setLowLevelLocking(pViaXvMC->xl, 0);
56690b17f1bSmrg	viaVideoSubPictureOffLocked(pViaXvMC->xl);
56790b17f1bSmrg	flushXvMCLowLevel(pViaXvMC->xl);
56890b17f1bSmrg	setLowLevelLocking(pViaXvMC->xl, 1);
56990b17f1bSmrg	hwlUnlock(pViaXvMC->xl, 1);
57090b17f1bSmrg    }
57190b17f1bSmrg
57290b17f1bSmrg    return Success;
57390b17f1bSmrg}
57490b17f1bSmrg
57590b17f1bSmrg_X_EXPORT Status
57690b17f1bSmrgXvMCDestroyContext(Display * display, XvMCContext * context)
57790b17f1bSmrg{
57890b17f1bSmrg    ViaXvMCContext *pViaXvMC;
57990b17f1bSmrg
58090b17f1bSmrg    if (context == NULL) {
58190b17f1bSmrg	return (error_base + XvMCBadContext);
58290b17f1bSmrg    }
58390b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
58490b17f1bSmrg	return (error_base + XvMCBadContext);
58590b17f1bSmrg    }
58690b17f1bSmrg
58790b17f1bSmrg    /*
58890b17f1bSmrg     * Release decoder if we have it. In case of crash or termination
58990b17f1bSmrg     * before XvMCDestroyContext, the X server will take care of this.
59090b17f1bSmrg     */
59190b17f1bSmrg
59290b17f1bSmrg    releaseAttribDesc(pViaXvMC->attrib.numAttr, pViaXvMC->attribDesc);
59390b17f1bSmrg    releaseDecoder(pViaXvMC, 1);
59490b17f1bSmrg    return releaseContextResources(display, context, 1, Success);
59590b17f1bSmrg}
59690b17f1bSmrg
59790b17f1bSmrg_X_EXPORT Status
59890b17f1bSmrgXvMCCreateSurface(Display * display, XvMCContext * context,
59990b17f1bSmrg    XvMCSurface * surface)
60090b17f1bSmrg{
60190b17f1bSmrg    ViaXvMCContext *pViaXvMC;
60290b17f1bSmrg    ViaXvMCSurface *pViaSurface;
60390b17f1bSmrg    int priv_count;
60490b17f1bSmrg    unsigned *priv_data;
60590b17f1bSmrg    unsigned i;
60690b17f1bSmrg    Status ret;
60790b17f1bSmrg
60890b17f1bSmrg    if ((surface == NULL) || (context == NULL) || (display == NULL)) {
60990b17f1bSmrg	return BadValue;
61090b17f1bSmrg    }
61190b17f1bSmrg
61290b17f1bSmrg    pViaXvMC = (ViaXvMCContext *) context->privData;
61390b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
61490b17f1bSmrg
61590b17f1bSmrg    if (pViaXvMC == NULL) {
61690b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
61790b17f1bSmrg	return (error_base + XvMCBadContext);
61890b17f1bSmrg    }
61990b17f1bSmrg
62090b17f1bSmrg    pViaSurface = surface->privData =
62190b17f1bSmrg	(ViaXvMCSurface *) malloc(sizeof(ViaXvMCSurface));
62290b17f1bSmrg    if (!surface->privData) {
62390b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
62490b17f1bSmrg	return BadAlloc;
62590b17f1bSmrg    }
62690b17f1bSmrg    XLockDisplay(display);
62790b17f1bSmrg    if ((ret = _xvmc_create_surface(display, context, surface,
62890b17f1bSmrg		&priv_count, &priv_data))) {
62990b17f1bSmrg	XUnlockDisplay(display);
63090b17f1bSmrg	free(pViaSurface);
63190b17f1bSmrg	fprintf(stderr, "Unable to create XvMC Surface.\n");
63290b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
63390b17f1bSmrg	return ret;
63490b17f1bSmrg    }
63590b17f1bSmrg    XUnlockDisplay(display);
63690b17f1bSmrg
63790b17f1bSmrg    pViaSurface->srfNo = priv_data[0];
63890b17f1bSmrg
63990b17f1bSmrg    /*
64090b17f1bSmrg     * Store framebuffer offsets to the buffers allocated for this surface.
64190b17f1bSmrg     * For some chipset revisions, surfaces may be double-buffered.
64290b17f1bSmrg     */
64390b17f1bSmrg
64490b17f1bSmrg    pViaSurface->numBuffers = priv_data[1];
64590b17f1bSmrg    for (i = 0; i < pViaSurface->numBuffers; ++i) {
64690b17f1bSmrg	pViaSurface->offsets[i] = priv_data[i + 2];
64790b17f1bSmrg    }
64890b17f1bSmrg    pViaSurface->curBuf = 0;
64990b17f1bSmrg
65090b17f1bSmrg    /* Free data returned from xvmc_create_surface */
65190b17f1bSmrg
65290b17f1bSmrg    XFree(priv_data);
65390b17f1bSmrg
65490b17f1bSmrg    pViaSurface->width = context->width;
65590b17f1bSmrg    pViaSurface->height = context->height;
65690b17f1bSmrg    pViaSurface->yStride = pViaXvMC->yStride;
65790b17f1bSmrg    pViaSurface->privContext = pViaXvMC;
65890b17f1bSmrg    pViaSurface->privSubPic = NULL;
65990b17f1bSmrg    pViaSurface->needsSync = 0;
66090b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
66190b17f1bSmrg    return Success;
66290b17f1bSmrg}
66390b17f1bSmrg
66490b17f1bSmrg_X_EXPORT Status
66590b17f1bSmrgXvMCDestroySurface(Display * display, XvMCSurface * surface)
66690b17f1bSmrg{
66790b17f1bSmrg    ViaXvMCSurface *pViaSurface;
66890b17f1bSmrg
66990b17f1bSmrg    if ((display == NULL) || (surface == NULL)) {
67090b17f1bSmrg	return BadValue;
67190b17f1bSmrg    }
67290b17f1bSmrg    if (surface->privData == NULL) {
67390b17f1bSmrg	return (error_base + XvMCBadSurface);
67490b17f1bSmrg    }
67590b17f1bSmrg
67690b17f1bSmrg    pViaSurface = (ViaXvMCSurface *) surface->privData;
67790b17f1bSmrg
67890b17f1bSmrg    XLockDisplay(display);
67990b17f1bSmrg    _xvmc_destroy_surface(display, surface);
68090b17f1bSmrg    XUnlockDisplay(display);
68190b17f1bSmrg
68290b17f1bSmrg    free(pViaSurface);
68390b17f1bSmrg    surface->privData = NULL;
68490b17f1bSmrg    return Success;
68590b17f1bSmrg}
68690b17f1bSmrg
68790b17f1bSmrg_X_EXPORT Status
68890b17f1bSmrgXvMCPutSlice2(Display * display, XvMCContext * context, char *slice,
68990b17f1bSmrg    int nBytes, int sliceCode)
69090b17f1bSmrg{
69190b17f1bSmrg    ViaXvMCContext *pViaXvMC;
69290b17f1bSmrg    CARD32 sCode = 0x00010000 | (sliceCode & 0xFF) << 24;
69390b17f1bSmrg
69490b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
69590b17f1bSmrg	return BadValue;
69690b17f1bSmrg    }
69790b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
69890b17f1bSmrg	return (error_base + XvMCBadContext);
69990b17f1bSmrg    }
70090b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
70190b17f1bSmrg    if (!pViaXvMC->haveDecoder) {
70290b17f1bSmrg	fprintf(stderr, "XvMCPutSlice: This context does not own decoder!\n");
70390b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
70490b17f1bSmrg	return BadAlloc;
70590b17f1bSmrg    }
70690b17f1bSmrg
70790b17f1bSmrg    viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *) slice, nBytes, sCode);
70890b17f1bSmrg
70990b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
71090b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
71190b17f1bSmrg    return Success;
71290b17f1bSmrg}
71390b17f1bSmrg
71490b17f1bSmrg_X_EXPORT Status
71590b17f1bSmrgXvMCPutSlice(Display * display, XvMCContext * context, char *slice,
71690b17f1bSmrg    int nBytes)
71790b17f1bSmrg{
71890b17f1bSmrg    ViaXvMCContext *pViaXvMC;
71990b17f1bSmrg
72090b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
72190b17f1bSmrg	return BadValue;
72290b17f1bSmrg    }
72390b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
72490b17f1bSmrg	return (error_base + XvMCBadContext);
72590b17f1bSmrg    }
72690b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
72790b17f1bSmrg
72890b17f1bSmrg    if (!pViaXvMC->haveDecoder) {
72990b17f1bSmrg	fprintf(stderr, "XvMCPutSlice: This context does not own decoder!\n");
73090b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
73190b17f1bSmrg	return BadAlloc;
73290b17f1bSmrg    }
73390b17f1bSmrg
73490b17f1bSmrg    viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *) slice, nBytes, 0);
73590b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
73690b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
73790b17f1bSmrg    return Success;
73890b17f1bSmrg}
73990b17f1bSmrg
74090b17f1bSmrgstatic Status
74190b17f1bSmrgupdateXVOverlay(Display * display, ViaXvMCContext * pViaXvMC,
74290b17f1bSmrg    ViaXvMCSurface * pViaSurface, Drawable draw,
74390b17f1bSmrg    short srcx, short srcy, unsigned short srcw,
74490b17f1bSmrg    unsigned short srch, short destx, short desty,
74590b17f1bSmrg    unsigned short destw, unsigned short desth)
74690b17f1bSmrg{
74790b17f1bSmrg    ViaXvMCCommandBuffer buf;
74890b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
74990b17f1bSmrg    Status ret;
75090b17f1bSmrg
75190b17f1bSmrg    if (!pViaXvMC->haveXv) {
75290b17f1bSmrg	pViaXvMC->xvImage =
75390b17f1bSmrg	    XvCreateImage(display, pViaXvMC->port, FOURCC_XVMC,
75490b17f1bSmrg	    (char *)&buf, pViaSurface->width, pViaSurface->height);
75590b17f1bSmrg	pViaXvMC->gc = XCreateGC(display, draw, 0, 0);
75690b17f1bSmrg	pViaXvMC->haveXv = 1;
75790b17f1bSmrg    }
75890b17f1bSmrg    pViaXvMC->draw = draw;
75990b17f1bSmrg    pViaXvMC->xvImage->data = (char *)&buf;
76090b17f1bSmrg
76190b17f1bSmrg    buf.command = (pViaXvMC->attribChanged) ?
76290b17f1bSmrg	VIA_XVMC_COMMAND_FDISPLAY : VIA_XVMC_COMMAND_DISPLAY;
76390b17f1bSmrg    buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
76490b17f1bSmrg    buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
76590b17f1bSmrg    pViaSubPic = pViaSurface->privSubPic;
76690b17f1bSmrg    buf.subPicNo = ((NULL == pViaSubPic) ? 0 : pViaSubPic->srfNo)
76790b17f1bSmrg	| VIA_XVMC_VALID;
76890b17f1bSmrg    buf.attrib = pViaXvMC->attrib;
76990b17f1bSmrg
77090b17f1bSmrg    XLockDisplay(display);
77190b17f1bSmrg
77290b17f1bSmrg    if ((ret = XvPutImage(display, pViaXvMC->port, draw, pViaXvMC->gc,
77390b17f1bSmrg		pViaXvMC->xvImage, srcx, srcy, srcw, srch,
77490b17f1bSmrg		destx, desty, destw, desth))) {
77590b17f1bSmrg	XUnlockDisplay(display);
77690b17f1bSmrg	return ret;
77790b17f1bSmrg    }
77890b17f1bSmrg    XSync(display, 0);
77990b17f1bSmrg    XUnlockDisplay(display);
78090b17f1bSmrg    pViaXvMC->attribChanged = 0;
78190b17f1bSmrg    return Success;
78290b17f1bSmrg}
78390b17f1bSmrg
78490b17f1bSmrg_X_EXPORT Status
78590b17f1bSmrgXvMCPutSurface(Display * display, XvMCSurface * surface, Drawable draw,
78690b17f1bSmrg    short srcx, short srcy, unsigned short srcw,
78790b17f1bSmrg    unsigned short srch, short destx, short desty,
78890b17f1bSmrg    unsigned short destw, unsigned short desth, int flags)
78990b17f1bSmrg{
79090b17f1bSmrg    /*
79190b17f1bSmrg     * This function contains some hairy locking logic. What we really want to
79290b17f1bSmrg     * do is to flip the picture ASAP, to get a low latency and smooth playback.
79390b17f1bSmrg     * However, if somebody else used the overlay since we used it last or if it is
79490b17f1bSmrg     * our first time, we'll have to call X to update the overlay first. Otherwise
79590b17f1bSmrg     * we'll do the overlay update once we've flipped. Since we release the hardware
79690b17f1bSmrg     * lock when we call X, X needs to verify using the SAREA that nobody else flipped
79790b17f1bSmrg     * in a picture between the lock release and the X server control. Similarly
79890b17f1bSmrg     * when the overlay update returns, we have to make sure that we still own the
79990b17f1bSmrg     * overlay.
80090b17f1bSmrg     */
80190b17f1bSmrg
80290b17f1bSmrg    ViaXvMCSurface *pViaSurface;
80390b17f1bSmrg    ViaXvMCContext *pViaXvMC;
80490b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
80590b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
80690b17f1bSmrg    Status ret;
80790b17f1bSmrg    unsigned dispSurface, lastSurface;
80890b17f1bSmrg    int overlayUpdated;
80990b17f1bSmrg    drawableInfo *drawInfo;
81090b17f1bSmrg    XvMCRegion sReg, dReg;
81190b17f1bSmrg    Bool forceUpdate = FALSE;
81290b17f1bSmrg
81390b17f1bSmrg    if ((display == NULL) || (surface == NULL)) {
81490b17f1bSmrg	return BadValue;
81590b17f1bSmrg    }
81690b17f1bSmrg    if (NULL == (pViaSurface = surface->privData)) {
81790b17f1bSmrg	return (error_base + XvMCBadSurface);
81890b17f1bSmrg    }
81990b17f1bSmrg    if (NULL == (pViaXvMC = pViaSurface->privContext)) {
82090b17f1bSmrg	return (error_base + XvMCBadContext);
82190b17f1bSmrg    }
82290b17f1bSmrg
82390b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
82490b17f1bSmrg    pViaSubPic = pViaSurface->privSubPic;
82590b17f1bSmrg    sAPriv = SAREAPTR(pViaXvMC);
82690b17f1bSmrg
82790b17f1bSmrg    setRegion(srcx, srcy, srcw, srch, sReg);
82890b17f1bSmrg    setRegion(destx, desty, destw, desth, dReg);
82990b17f1bSmrg
83090b17f1bSmrg    if ((!regionEqual(sReg, pViaXvMC->sRegion)) ||
83190b17f1bSmrg	(!regionEqual(dReg, pViaXvMC->dRegion))) {
83290b17f1bSmrg
83390b17f1bSmrg	/*
83490b17f1bSmrg	 * Force update of the video overlay to match the new format.
83590b17f1bSmrg	 */
83690b17f1bSmrg
83790b17f1bSmrg	pViaXvMC->sRegion = sReg;
83890b17f1bSmrg	pViaXvMC->dRegion = dReg;
83990b17f1bSmrg	forceUpdate = TRUE;
84090b17f1bSmrg    }
84190b17f1bSmrg
84290b17f1bSmrg    hwlLock(pViaXvMC->xl, 1);
84390b17f1bSmrg
84490b17f1bSmrg    if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display,
84590b17f1bSmrg	    pViaXvMC->screen, draw, 0, pViaXvMC->fd, pViaXvMC->drmcontext,
84690b17f1bSmrg	    pViaXvMC->sAreaAddress, FALSE, &drawInfo, sizeof(*drawInfo))) {
84790b17f1bSmrg
84890b17f1bSmrg	hwlUnlock(pViaXvMC->xl, 1);
84990b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
85090b17f1bSmrg	return BadAccess;
85190b17f1bSmrg    }
85290b17f1bSmrg
85390b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 0);
85490b17f1bSmrg
85590b17f1bSmrg    /*
85690b17f1bSmrg     * Put a surface ID in the SAREA to "authenticate" to the
85790b17f1bSmrg     * X server.
85890b17f1bSmrg     */
85990b17f1bSmrg
86090b17f1bSmrg    dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
86190b17f1bSmrg    lastSurface = pViaXvMC->lastSrfDisplaying;
86290b17f1bSmrg    sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] =
86390b17f1bSmrg	pViaXvMC->lastSrfDisplaying = pViaSurface->srfNo | VIA_XVMC_VALID;
86490b17f1bSmrg    overlayUpdated = 0;
86590b17f1bSmrg
86690b17f1bSmrg    viaVideoSetSWFLipLocked(pViaXvMC->xl, yOffs(pViaSurface),
86790b17f1bSmrg	uOffs(pViaSurface), vOffs(pViaSurface), pViaSurface->yStride,
86890b17f1bSmrg	pViaSurface->yStride >> 1);
86990b17f1bSmrg
87090b17f1bSmrg    while ((lastSurface != dispSurface) || forceUpdate) {
87190b17f1bSmrg
87290b17f1bSmrg	forceUpdate = FALSE;
87390b17f1bSmrg	flushPCIXvMCLowLevel(pViaXvMC->xl);
87490b17f1bSmrg	setLowLevelLocking(pViaXvMC->xl, 1);
87590b17f1bSmrg	hwlUnlock(pViaXvMC->xl, 1);
87690b17f1bSmrg
87790b17f1bSmrg	/*
87890b17f1bSmrg	 * We weren't the last to display. Update the overlay before flipping.
87990b17f1bSmrg	 */
88090b17f1bSmrg
88190b17f1bSmrg	ret =
88290b17f1bSmrg	    updateXVOverlay(display, pViaXvMC, pViaSurface, draw, srcx, srcy,
88390b17f1bSmrg	    srcw, srch, destx, desty, destw, desth);
88490b17f1bSmrg	if (ret) {
88590b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
88690b17f1bSmrg	    return ret;
88790b17f1bSmrg	}
88890b17f1bSmrg
88990b17f1bSmrg	hwlLock(pViaXvMC->xl, 1);
89090b17f1bSmrg
89190b17f1bSmrg	if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display,
89290b17f1bSmrg		pViaXvMC->screen, draw, 0, pViaXvMC->fd, pViaXvMC->drmcontext,
89390b17f1bSmrg		pViaXvMC->sAreaAddress, FALSE, &drawInfo,
89490b17f1bSmrg		sizeof(*drawInfo))) {
89590b17f1bSmrg
89690b17f1bSmrg	    hwlUnlock(pViaXvMC->xl, 1);
89790b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
89890b17f1bSmrg	    return BadAccess;
89990b17f1bSmrg	}
90090b17f1bSmrg
90190b17f1bSmrg	setLowLevelLocking(pViaXvMC->xl, 0);
90290b17f1bSmrg	lastSurface = pViaSurface->srfNo | VIA_XVMC_VALID;
90390b17f1bSmrg	dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
90490b17f1bSmrg	overlayUpdated = 1;
90590b17f1bSmrg    }
90690b17f1bSmrg
90790b17f1bSmrg    /*
90890b17f1bSmrg     * Subpictures
90990b17f1bSmrg     */
91090b17f1bSmrg
91190b17f1bSmrg    if (NULL != pViaSubPic) {
91290b17f1bSmrg	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort]
91390b17f1bSmrg	    != (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
91490b17f1bSmrg	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] =
91590b17f1bSmrg		pViaSubPic->srfNo | VIA_XVMC_VALID;
91690b17f1bSmrg	    viaVideoSubPictureLocked(pViaXvMC->xl, pViaSubPic);
91790b17f1bSmrg	}
91890b17f1bSmrg    } else {
91990b17f1bSmrg	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] & VIA_XVMC_VALID) {
92090b17f1bSmrg	    viaVideoSubPictureOffLocked(pViaXvMC->xl);
92190b17f1bSmrg	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
92290b17f1bSmrg	}
92390b17f1bSmrg    }
92490b17f1bSmrg
92590b17f1bSmrg    /*
92690b17f1bSmrg     * Flip
92790b17f1bSmrg     */
92890b17f1bSmrg
92990b17f1bSmrg    viaVideoSWFlipLocked(pViaXvMC->xl, flags,
93090b17f1bSmrg	pViaSurface->progressiveSequence);
93190b17f1bSmrg    flushXvMCLowLevel(pViaXvMC->xl);
93290b17f1bSmrg
93390b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 1);
93490b17f1bSmrg    hwlUnlock(pViaXvMC->xl, 1);
93590b17f1bSmrg
93690b17f1bSmrg    if (overlayUpdated || !drawInfo->touched) {
93790b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
93890b17f1bSmrg	return Success;
93990b17f1bSmrg    }
94090b17f1bSmrg
94190b17f1bSmrg    /*
94290b17f1bSmrg     * Update overlay
94390b17f1bSmrg     */
94490b17f1bSmrg
94590b17f1bSmrg    ret =
94690b17f1bSmrg	updateXVOverlay(display, pViaXvMC, pViaSurface, draw, srcx, srcy,
94790b17f1bSmrg	srcw, srch, destx, desty, destw, desth);
94890b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
94990b17f1bSmrg    return ret;
95090b17f1bSmrg
95190b17f1bSmrg}
95290b17f1bSmrg
95390b17f1bSmrgvoid
95490b17f1bSmrgdebugControl(const XvMCMpegControl * control)
95590b17f1bSmrg{
95690b17f1bSmrg    printf("BVMV_range: %u\n", control->BVMV_range);
95790b17f1bSmrg    printf("BHMV_range: %u\n", control->BHMV_range);
95890b17f1bSmrg    printf("FVMV_range: %u\n", control->FVMV_range);
95990b17f1bSmrg    printf("FHMV_range: %u\n", control->FHMV_range);
96090b17f1bSmrg    printf("picture_structure: %u\n", control->picture_structure);
96190b17f1bSmrg    printf("intra_dc_precision: %u\n", control->intra_dc_precision);
96290b17f1bSmrg    printf("picture_coding_type: %u\n", control->picture_coding_type);
96390b17f1bSmrg    printf("mpeg_coding: %u\n", control->mpeg_coding);
96490b17f1bSmrg    printf("flags: 0x%x\n", control->flags);
96590b17f1bSmrg}
96690b17f1bSmrg
96790b17f1bSmrg_X_EXPORT Status
96890b17f1bSmrgXvMCBeginSurface(Display * display,
96990b17f1bSmrg    XvMCContext * context,
97090b17f1bSmrg    XvMCSurface * target_surface,
97190b17f1bSmrg    XvMCSurface * past_surface,
97290b17f1bSmrg    XvMCSurface * future_surface, const XvMCMpegControl * control)
97390b17f1bSmrg{
97490b17f1bSmrg    ViaXvMCSurface *targS, *futS, *pastS;
97590b17f1bSmrg    ViaXvMCContext *pViaXvMC;
97690b17f1bSmrg    int hadDecoderLast;
97790b17f1bSmrg    CARD32 timeStamp;
97890b17f1bSmrg
97990b17f1bSmrg    if ((display == NULL) || (context == NULL) || (target_surface == NULL)) {
98090b17f1bSmrg	return BadValue;
98190b17f1bSmrg    }
98290b17f1bSmrg
98390b17f1bSmrg    pViaXvMC = context->privData;
98490b17f1bSmrg
98590b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
98690b17f1bSmrg    if (grabDecoder(pViaXvMC, &hadDecoderLast)) {
98790b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
98890b17f1bSmrg	return BadAlloc;
98990b17f1bSmrg    }
99090b17f1bSmrg    pViaXvMC->haveDecoder = 1;
99190b17f1bSmrg
99290b17f1bSmrg    /*
99390b17f1bSmrg     * We need to wait for decoder idle at next flush, since hardware doesn't queue
99490b17f1bSmrg     * beginsurface requests until the decoder is idle. This is
99590b17f1bSmrg     * done by waiting on the last previous timestamp, or if there was another context
99690b17f1bSmrg     * having the decoder before us, by emitting a new one.
99790b17f1bSmrg     */
99890b17f1bSmrg
99990b17f1bSmrg    if (pViaXvMC->useAGP) {
100090b17f1bSmrg	if (!hadDecoderLast || pViaXvMC->timeStamp == 0) {
100190b17f1bSmrg	    timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
100290b17f1bSmrg	    if (flushXvMCLowLevel(pViaXvMC->xl)) {
100390b17f1bSmrg		releaseDecoder(pViaXvMC, 0);
100490b17f1bSmrg		ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
100590b17f1bSmrg		return BadAlloc;
100690b17f1bSmrg	    }
100790b17f1bSmrg	    pViaXvMC->timeStamp = timeStamp;
100890b17f1bSmrg	} else {
100990b17f1bSmrg	    timeStamp = pViaXvMC->timeStamp;
101090b17f1bSmrg	}
101190b17f1bSmrg	setAGPSyncLowLevel(pViaXvMC->xl, 1, timeStamp);
101290b17f1bSmrg    }
101390b17f1bSmrg
101490b17f1bSmrg    if (!hadDecoderLast || !pViaXvMC->decoderOn) {
101590b17f1bSmrg	pViaXvMC->intraLoaded = 0;
101690b17f1bSmrg	pViaXvMC->nonIntraLoaded = 0;
101790b17f1bSmrg    }
101890b17f1bSmrg
101990b17f1bSmrg    viaMpegReset(pViaXvMC->xl);
102090b17f1bSmrg
102190b17f1bSmrg    targS = (ViaXvMCSurface *) target_surface->privData;
102290b17f1bSmrg    futS = NULL;
102390b17f1bSmrg    pastS = NULL;
102490b17f1bSmrg
102590b17f1bSmrg    pViaXvMC->rendSurf[0] = targS->srfNo | VIA_XVMC_VALID;
102690b17f1bSmrg    if (future_surface) {
102790b17f1bSmrg	futS = (ViaXvMCSurface *) future_surface->privData;
102890b17f1bSmrg	futS->needsSync = 0;
102990b17f1bSmrg    }
103090b17f1bSmrg    if (past_surface) {
103190b17f1bSmrg	pastS = (ViaXvMCSurface *) past_surface->privData;
103290b17f1bSmrg	pastS->needsSync = 0;
103390b17f1bSmrg    }
103490b17f1bSmrg
103590b17f1bSmrg    targS->progressiveSequence = (control->flags & XVMC_PROGRESSIVE_SEQUENCE);
103690b17f1bSmrg    targS->topFieldFirst = (control->flags & XVMC_TOP_FIELD_FIRST);
103790b17f1bSmrg    targS->privSubPic = NULL;
103890b17f1bSmrg
103990b17f1bSmrg    viaMpegSetSurfaceStride(pViaXvMC->xl, pViaXvMC);
104090b17f1bSmrg
104190b17f1bSmrg    viaMpegSetFB(pViaXvMC->xl, 0, yOffs(targS), uOffs(targS), vOffs(targS));
104290b17f1bSmrg    if (past_surface) {
104390b17f1bSmrg	viaMpegSetFB(pViaXvMC->xl, 1, yOffs(pastS), uOffs(pastS),
104490b17f1bSmrg	    vOffs(pastS));
104590b17f1bSmrg    } else {
104690b17f1bSmrg	viaMpegSetFB(pViaXvMC->xl, 1, 0, 0, 0);
104790b17f1bSmrg    }
104890b17f1bSmrg
104990b17f1bSmrg    if (future_surface) {
105090b17f1bSmrg	viaMpegSetFB(pViaXvMC->xl, 2, yOffs(futS), uOffs(futS), vOffs(futS));
105190b17f1bSmrg    } else {
105290b17f1bSmrg	viaMpegSetFB(pViaXvMC->xl, 2, 0, 0, 0);
105390b17f1bSmrg    }
105490b17f1bSmrg
105590b17f1bSmrg    viaMpegBeginPicture(pViaXvMC->xl, pViaXvMC, context->width,
105690b17f1bSmrg	context->height, control);
105790b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
105890b17f1bSmrg    targS->needsSync = 1;
105990b17f1bSmrg    targS->syncMode = LL_MODE_DECODER_IDLE;
106090b17f1bSmrg    pViaXvMC->decoderOn = 1;
106190b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
106290b17f1bSmrg    return Success;
106390b17f1bSmrg}
106490b17f1bSmrg
106590b17f1bSmrg_X_EXPORT Status
106690b17f1bSmrgXvMCSyncSurface(Display * display, XvMCSurface * surface)
106790b17f1bSmrg{
106890b17f1bSmrg    ViaXvMCSurface *pViaSurface;
106990b17f1bSmrg    ViaXvMCContext *pViaXvMC;
107090b17f1bSmrg    unsigned i;
107190b17f1bSmrg
107290b17f1bSmrg    if ((display == NULL) || (surface == NULL)) {
107390b17f1bSmrg	return BadValue;
107490b17f1bSmrg    }
107590b17f1bSmrg    if (surface->privData == NULL) {
107690b17f1bSmrg	return (error_base + XvMCBadSurface);
107790b17f1bSmrg    }
107890b17f1bSmrg
107990b17f1bSmrg    pViaSurface = (ViaXvMCSurface *) surface->privData;
108090b17f1bSmrg    pViaXvMC = pViaSurface->privContext;
108190b17f1bSmrg
108290b17f1bSmrg    if (pViaXvMC == NULL) {
108390b17f1bSmrg	return (error_base + XvMCBadSurface);
108490b17f1bSmrg    }
108590b17f1bSmrg
108690b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
108790b17f1bSmrg
108890b17f1bSmrg    if (pViaSurface->needsSync) {
108990b17f1bSmrg	CARD32 timeStamp = pViaSurface->timeStamp;
109090b17f1bSmrg	int syncMode = pViaSurface->syncMode;
109190b17f1bSmrg
109290b17f1bSmrg	if (pViaXvMC->useAGP) {
109390b17f1bSmrg
109490b17f1bSmrg	    syncMode = (pViaSurface->syncMode == LL_MODE_2D ||
109590b17f1bSmrg		pViaSurface->timeStamp < pViaXvMC->timeStamp) ?
109690b17f1bSmrg		LL_MODE_2D : LL_MODE_DECODER_IDLE;
109790b17f1bSmrg	    if (pViaSurface->syncMode != LL_MODE_2D)
109890b17f1bSmrg		timeStamp = pViaXvMC->timeStamp;
109990b17f1bSmrg
110090b17f1bSmrg	} else if (syncMode != LL_MODE_2D &&
110190b17f1bSmrg	    pViaXvMC->rendSurf[0] != (pViaSurface->srfNo | VIA_XVMC_VALID)) {
110290b17f1bSmrg
110390b17f1bSmrg	    pViaSurface->needsSync = 0;
110490b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
110590b17f1bSmrg	    return Success;
110690b17f1bSmrg	}
110790b17f1bSmrg
110890b17f1bSmrg	if (syncXvMCLowLevel(pViaXvMC->xl, syncMode, 1,
110990b17f1bSmrg		pViaSurface->timeStamp)) {
111090b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
111190b17f1bSmrg	    return BadValue;
111290b17f1bSmrg	}
111390b17f1bSmrg	pViaSurface->needsSync = 0;
111490b17f1bSmrg    }
111590b17f1bSmrg
111690b17f1bSmrg    if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
111790b17f1bSmrg	pViaSurface->needsSync = 0;
111890b17f1bSmrg	for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
111990b17f1bSmrg	    pViaXvMC->rendSurf[i] = 0;
112090b17f1bSmrg	}
112190b17f1bSmrg    }
112290b17f1bSmrg
112390b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
112490b17f1bSmrg    return Success;
112590b17f1bSmrg}
112690b17f1bSmrg
112790b17f1bSmrg_X_EXPORT Status
112890b17f1bSmrgXvMCLoadQMatrix(Display * display, XvMCContext * context,
112990b17f1bSmrg    const XvMCQMatrix * qmx)
113090b17f1bSmrg{
113190b17f1bSmrg    ViaXvMCContext * pViaXvMC;
113290b17f1bSmrg
113390b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
113490b17f1bSmrg	return BadValue;
113590b17f1bSmrg    }
113690b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
113790b17f1bSmrg	return (error_base + XvMCBadContext);
113890b17f1bSmrg    }
113990b17f1bSmrg
114090b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
114190b17f1bSmrg    if (qmx->load_intra_quantiser_matrix) {
114290b17f1bSmrg	memcpy(pViaXvMC->intra_quantiser_matrix,
114390b17f1bSmrg	    qmx->intra_quantiser_matrix, sizeof(qmx->intra_quantiser_matrix));
114490b17f1bSmrg	pViaXvMC->intraLoaded = 0;
114590b17f1bSmrg    }
114690b17f1bSmrg
114790b17f1bSmrg    if (qmx->load_non_intra_quantiser_matrix) {
114890b17f1bSmrg	memcpy(pViaXvMC->non_intra_quantiser_matrix,
114990b17f1bSmrg	    qmx->non_intra_quantiser_matrix,
115090b17f1bSmrg	    sizeof(qmx->non_intra_quantiser_matrix));
115190b17f1bSmrg	pViaXvMC->nonIntraLoaded = 0;
115290b17f1bSmrg    }
115390b17f1bSmrg
115490b17f1bSmrg    if (qmx->load_chroma_intra_quantiser_matrix) {
115590b17f1bSmrg	memcpy(pViaXvMC->chroma_intra_quantiser_matrix,
115690b17f1bSmrg	    qmx->chroma_intra_quantiser_matrix,
115790b17f1bSmrg	    sizeof(qmx->chroma_intra_quantiser_matrix));
115890b17f1bSmrg	pViaXvMC->chromaIntraLoaded = 0;
115990b17f1bSmrg    }
116090b17f1bSmrg
116190b17f1bSmrg    if (qmx->load_chroma_non_intra_quantiser_matrix) {
116290b17f1bSmrg	memcpy(pViaXvMC->chroma_non_intra_quantiser_matrix,
116390b17f1bSmrg	    qmx->chroma_non_intra_quantiser_matrix,
116490b17f1bSmrg	    sizeof(qmx->chroma_non_intra_quantiser_matrix));
116590b17f1bSmrg	pViaXvMC->chromaNonIntraLoaded = 0;
116690b17f1bSmrg    }
116790b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
116890b17f1bSmrg
116990b17f1bSmrg    return Success;
117090b17f1bSmrg}
117190b17f1bSmrg
117290b17f1bSmrg/*
117390b17f1bSmrg * Below, we provide functions unusable for this implementation, but for
117490b17f1bSmrg * standard completeness.
117590b17f1bSmrg */
117690b17f1bSmrg
117790b17f1bSmrg_X_EXPORT Status XvMCRenderSurface
117890b17f1bSmrg    (Display * display,
117990b17f1bSmrg    XvMCContext * context,
118090b17f1bSmrg    unsigned int picture_structure,
118190b17f1bSmrg    XvMCSurface * target_surface,
118290b17f1bSmrg    XvMCSurface * past_surface,
118390b17f1bSmrg    XvMCSurface * future_surface,
118490b17f1bSmrg    unsigned int flags,
118590b17f1bSmrg    unsigned int num_macroblocks,
118690b17f1bSmrg    unsigned int first_macroblock,
118790b17f1bSmrg    XvMCMacroBlockArray * macroblock_array, XvMCBlockArray * blocks)
118890b17f1bSmrg{
118990b17f1bSmrg    return (error_base + XvMCBadContext);
119090b17f1bSmrg}
119190b17f1bSmrg
119290b17f1bSmrg_X_EXPORT Status XvMCCreateBlocks
119390b17f1bSmrg    (Display * display,
119490b17f1bSmrg    XvMCContext * context, unsigned int num_blocks, XvMCBlockArray * block)
119590b17f1bSmrg{
119690b17f1bSmrg    return (error_base + XvMCBadContext);
119790b17f1bSmrg}
119890b17f1bSmrg
119990b17f1bSmrg_X_EXPORT Status
120090b17f1bSmrgXvMCDestroyBlocks(Display * display, XvMCBlockArray * block)
120190b17f1bSmrg{
120290b17f1bSmrg    return Success;
120390b17f1bSmrg}
120490b17f1bSmrg
120590b17f1bSmrg_X_EXPORT Status XvMCCreateMacroBlocks
120690b17f1bSmrg    (Display * display,
120790b17f1bSmrg    XvMCContext * context,
120890b17f1bSmrg    unsigned int num_blocks, XvMCMacroBlockArray * blocks)
120990b17f1bSmrg{
121090b17f1bSmrg    return (error_base + XvMCBadContext);
121190b17f1bSmrg}
121290b17f1bSmrg
121390b17f1bSmrg_X_EXPORT Status
121490b17f1bSmrgXvMCDestroyMacroBlocks(Display * display, XvMCMacroBlockArray * block)
121590b17f1bSmrg{
121690b17f1bSmrg    return (error_base + XvMCBadContext);
121790b17f1bSmrg}
121890b17f1bSmrg
121990b17f1bSmrg_X_EXPORT Status
122090b17f1bSmrgXvMCCreateSubpicture(Display * display,
122190b17f1bSmrg    XvMCContext * context,
122290b17f1bSmrg    XvMCSubpicture * subpicture,
122390b17f1bSmrg    unsigned short width, unsigned short height, int xvimage_id)
122490b17f1bSmrg{
122590b17f1bSmrg    ViaXvMCContext *pViaXvMC;
122690b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
122790b17f1bSmrg    int priv_count;
122890b17f1bSmrg    unsigned *priv_data;
122990b17f1bSmrg    Status ret;
123090b17f1bSmrg
123190b17f1bSmrg    if ((subpicture == NULL) || (context == NULL) || (display == NULL)) {
123290b17f1bSmrg	return BadValue;
123390b17f1bSmrg    }
123490b17f1bSmrg
123590b17f1bSmrg    pViaXvMC = (ViaXvMCContext *) context->privData;
123690b17f1bSmrg    if (pViaXvMC == NULL) {
123790b17f1bSmrg	return (error_base + XvMCBadContext);
123890b17f1bSmrg    }
123990b17f1bSmrg
124090b17f1bSmrg    subpicture->privData = (ViaXvMCSubPicture *)
124190b17f1bSmrg	malloc(sizeof(ViaXvMCSubPicture));
124290b17f1bSmrg    if (!subpicture->privData) {
124390b17f1bSmrg	return BadAlloc;
124490b17f1bSmrg    }
124590b17f1bSmrg
124690b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
124790b17f1bSmrg    subpicture->width = context->width;
124890b17f1bSmrg    subpicture->height = context->height;
124990b17f1bSmrg    subpicture->xvimage_id = xvimage_id;
125090b17f1bSmrg    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
125190b17f1bSmrg
125290b17f1bSmrg    XLockDisplay(display);
125390b17f1bSmrg    if ((ret = _xvmc_create_subpicture(display, context, subpicture,
125490b17f1bSmrg		&priv_count, &priv_data))) {
125590b17f1bSmrg	XUnlockDisplay(display);
125690b17f1bSmrg	free(pViaSubPic);
125790b17f1bSmrg	fprintf(stderr, "Unable to create XvMC Subpicture.\n");
125890b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
125990b17f1bSmrg	return ret;
126090b17f1bSmrg    }
126190b17f1bSmrg    XUnlockDisplay(display);
126290b17f1bSmrg
126390b17f1bSmrg    subpicture->num_palette_entries = VIA_SUBPIC_PALETTE_SIZE;
126490b17f1bSmrg    subpicture->entry_bytes = 3;
126590b17f1bSmrg    strncpy(subpicture->component_order, "YUV", 4);
126690b17f1bSmrg    pViaSubPic->srfNo = priv_data[0];
126790b17f1bSmrg    pViaSubPic->offset = priv_data[1];
126890b17f1bSmrg    pViaSubPic->stride = (subpicture->width + 31) & ~31;
126990b17f1bSmrg    pViaSubPic->privContext = pViaXvMC;
127090b17f1bSmrg    pViaSubPic->ia44 = (xvimage_id == FOURCC_IA44);
127190b17f1bSmrg    pViaSubPic->needsSync = 0;
127290b17f1bSmrg
127390b17f1bSmrg    /* Free data returned from _xvmc_create_subpicture */
127490b17f1bSmrg
127590b17f1bSmrg    XFree(priv_data);
127690b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
127790b17f1bSmrg    return Success;
127890b17f1bSmrg}
127990b17f1bSmrg
128090b17f1bSmrg_X_EXPORT Status
128190b17f1bSmrgXvMCSetSubpicturePalette(Display * display, XvMCSubpicture * subpicture,
128290b17f1bSmrg    unsigned char *palette)
128390b17f1bSmrg{
128490b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
128590b17f1bSmrg    ViaXvMCContext *pViaXvMC;
128690b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
128790b17f1bSmrg    unsigned i;
128890b17f1bSmrg    CARD32 tmp;
128990b17f1bSmrg
129090b17f1bSmrg    if ((subpicture == NULL) || (display == NULL)) {
129190b17f1bSmrg	return BadValue;
129290b17f1bSmrg    }
129390b17f1bSmrg    if (subpicture->privData == NULL) {
129490b17f1bSmrg	return (error_base + XvMCBadSubpicture);
129590b17f1bSmrg    }
129690b17f1bSmrg    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
129790b17f1bSmrg    for (i = 0; i < VIA_SUBPIC_PALETTE_SIZE; ++i) {
129890b17f1bSmrg	tmp = *palette++ << 8;
129990b17f1bSmrg	tmp |= *palette++ << 16;
130090b17f1bSmrg	tmp |= *palette++ << 24;
130190b17f1bSmrg	tmp |= ((i & 0x0f) << 4) | 0x07;
130290b17f1bSmrg	pViaSubPic->palette[i] = tmp;
130390b17f1bSmrg    }
130490b17f1bSmrg
130590b17f1bSmrg    pViaXvMC = pViaSubPic->privContext;
130690b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
130790b17f1bSmrg    sAPriv = SAREAPTR(pViaXvMC);
130890b17f1bSmrg    hwlLock(pViaXvMC->xl, 1);
130990b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 0);
131090b17f1bSmrg
131190b17f1bSmrg    /*
131290b17f1bSmrg     * If the subpicture is displaying, Immeadiately update it with the
131390b17f1bSmrg     * new palette.
131490b17f1bSmrg     */
131590b17f1bSmrg
131690b17f1bSmrg    if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
131790b17f1bSmrg	(pViaSubPic->srfNo | VIA_XVMC_VALID)) {
131890b17f1bSmrg	viaVideoSubPictureLocked(pViaXvMC->xl, pViaSubPic);
131990b17f1bSmrg    }
132090b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
132190b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 1);
132290b17f1bSmrg    hwlUnlock(pViaXvMC->xl, 1);
132390b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
132490b17f1bSmrg    return Success;
132590b17f1bSmrg}
132690b17f1bSmrg
132790b17f1bSmrgstatic int
132890b17f1bSmrgfindOverlap(unsigned width, unsigned height,
132990b17f1bSmrg    short *dstX, short *dstY,
133090b17f1bSmrg    short *srcX, short *srcY, unsigned short *areaW, unsigned short *areaH)
133190b17f1bSmrg{
133290b17f1bSmrg    int w, h;
133390b17f1bSmrg    unsigned mWidth, mHeight;
133490b17f1bSmrg
133590b17f1bSmrg    w = *areaW;
133690b17f1bSmrg    h = *areaH;
133790b17f1bSmrg
133890b17f1bSmrg    if ((*dstX >= width) || (*dstY >= height))
133990b17f1bSmrg	return 1;
134090b17f1bSmrg    if (*dstX < 0) {
134190b17f1bSmrg	w += *dstX;
134290b17f1bSmrg	*srcX -= *dstX;
134390b17f1bSmrg	*dstX = 0;
134490b17f1bSmrg    }
134590b17f1bSmrg    if (*dstY < 0) {
134690b17f1bSmrg	h += *dstY;
134790b17f1bSmrg	*srcY -= *dstY;
134890b17f1bSmrg	*dstY = 0;
134990b17f1bSmrg    }
135090b17f1bSmrg    if ((w <= 0) || ((h <= 0)))
135190b17f1bSmrg	return 1;
135290b17f1bSmrg    mWidth = width - *dstX;
135390b17f1bSmrg    mHeight = height - *dstY;
135490b17f1bSmrg    *areaW = (w <= mWidth) ? w : mWidth;
135590b17f1bSmrg    *areaH = (h <= mHeight) ? h : mHeight;
135690b17f1bSmrg    return 0;
135790b17f1bSmrg}
135890b17f1bSmrg
135990b17f1bSmrg_X_EXPORT Status
136090b17f1bSmrgXvMCClearSubpicture(Display * display,
136190b17f1bSmrg    XvMCSubpicture * subpicture,
136290b17f1bSmrg    short x,
136390b17f1bSmrg    short y, unsigned short width, unsigned short height, unsigned int color)
136490b17f1bSmrg{
136590b17f1bSmrg
136690b17f1bSmrg    ViaXvMCContext *pViaXvMC;
136790b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
136890b17f1bSmrg    short dummyX, dummyY;
136990b17f1bSmrg    unsigned long bOffs;
137090b17f1bSmrg
137190b17f1bSmrg    if ((subpicture == NULL) || (display == NULL)) {
137290b17f1bSmrg	return BadValue;
137390b17f1bSmrg    }
137490b17f1bSmrg    if (subpicture->privData == NULL) {
137590b17f1bSmrg	return (error_base + XvMCBadSubpicture);
137690b17f1bSmrg    }
137790b17f1bSmrg    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
137890b17f1bSmrg    pViaXvMC = pViaSubPic->privContext;
137990b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
138090b17f1bSmrg
138190b17f1bSmrg    /* Clip clearing area so that it fits inside subpicture. */
138290b17f1bSmrg
138390b17f1bSmrg    if (findOverlap(subpicture->width, subpicture->height, &x, &y,
138490b17f1bSmrg	    &dummyX, &dummyY, &width, &height)) {
138590b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
138690b17f1bSmrg	return Success;
138790b17f1bSmrg    }
138890b17f1bSmrg
138990b17f1bSmrg    bOffs = pViaSubPic->offset + y * pViaSubPic->stride + x;
139090b17f1bSmrg    viaBlit(pViaXvMC->xl, 8, 0, pViaSubPic->stride, bOffs, pViaSubPic->stride,
139190b17f1bSmrg	width, height, 1, 1, VIABLIT_FILL, color);
139290b17f1bSmrg    pViaSubPic->needsSync = 1;
139390b17f1bSmrg    pViaSubPic->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
139490b17f1bSmrg    if (flushXvMCLowLevel(pViaXvMC->xl)) {
139590b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
139690b17f1bSmrg	return BadValue;
139790b17f1bSmrg    }
139890b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
139990b17f1bSmrg    return Success;
140090b17f1bSmrg}
140190b17f1bSmrg
140290b17f1bSmrg_X_EXPORT Status
140390b17f1bSmrgXvMCCompositeSubpicture(Display * display,
140490b17f1bSmrg    XvMCSubpicture * subpicture,
140590b17f1bSmrg    XvImage * image,
140690b17f1bSmrg    short srcx,
140790b17f1bSmrg    short srcy,
140890b17f1bSmrg    unsigned short width, unsigned short height, short dstx, short dsty)
140990b17f1bSmrg{
141090b17f1bSmrg
141190b17f1bSmrg    unsigned i;
141290b17f1bSmrg    ViaXvMCContext *pViaXvMC;
141390b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
141490b17f1bSmrg    CARD8 *dAddr, *sAddr;
141590b17f1bSmrg
141690b17f1bSmrg    if ((subpicture == NULL) || (display == NULL) || (image == NULL)) {
141790b17f1bSmrg	return BadValue;
141890b17f1bSmrg    }
141990b17f1bSmrg    if (NULL == (pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData)) {
142090b17f1bSmrg	return (error_base + XvMCBadSubpicture);
142190b17f1bSmrg    }
142290b17f1bSmrg
142390b17f1bSmrg    pViaXvMC = pViaSubPic->privContext;
142490b17f1bSmrg
142590b17f1bSmrg    if (image->id != subpicture->xvimage_id)
142690b17f1bSmrg	return BadMatch;
142790b17f1bSmrg
142890b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
142990b17f1bSmrg
143090b17f1bSmrg    /*
143190b17f1bSmrg     * Clip copy area so that it fits inside subpicture and image.
143290b17f1bSmrg     */
143390b17f1bSmrg
143490b17f1bSmrg    if (findOverlap(subpicture->width, subpicture->height,
143590b17f1bSmrg	    &dstx, &dsty, &srcx, &srcy, &width, &height)) {
143690b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
143790b17f1bSmrg	return Success;
143890b17f1bSmrg    }
143990b17f1bSmrg    if (findOverlap(image->width, image->height,
144090b17f1bSmrg	    &srcx, &srcy, &dstx, &dsty, &width, &height)) {
144190b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
144290b17f1bSmrg	return Success;
144390b17f1bSmrg    }
144490b17f1bSmrg
144590b17f1bSmrg    if (pViaSubPic->needsSync) {
144690b17f1bSmrg	if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D, 0,
144790b17f1bSmrg		pViaSubPic->timeStamp)) {
144890b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
144990b17f1bSmrg	    return BadValue;
145090b17f1bSmrg	}
145190b17f1bSmrg	pViaSubPic->needsSync = 0;
145290b17f1bSmrg    }
145390b17f1bSmrg
145490b17f1bSmrg    for (i = 0; i < height; ++i) {
145590b17f1bSmrg	dAddr = (((CARD8 *) pViaXvMC->fbAddress) +
145690b17f1bSmrg	    (pViaSubPic->offset + (dsty + i) * pViaSubPic->stride + dstx));
145790b17f1bSmrg	sAddr = (((CARD8 *) image->data) +
145890b17f1bSmrg	    (image->offsets[0] + (srcy + i) * image->pitches[0] + srcx));
145990b17f1bSmrg	memcpy(dAddr, sAddr, width);
146090b17f1bSmrg    }
146190b17f1bSmrg
146290b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
146390b17f1bSmrg    return Success;
146490b17f1bSmrg}
146590b17f1bSmrg
146690b17f1bSmrg_X_EXPORT Status
146790b17f1bSmrgXvMCBlendSubpicture(Display * display,
146890b17f1bSmrg    XvMCSurface * target_surface,
146990b17f1bSmrg    XvMCSubpicture * subpicture,
147090b17f1bSmrg    short subx,
147190b17f1bSmrg    short suby,
147290b17f1bSmrg    unsigned short subw,
147390b17f1bSmrg    unsigned short subh,
147490b17f1bSmrg    short surfx, short surfy, unsigned short surfw, unsigned short surfh)
147590b17f1bSmrg{
147690b17f1bSmrg    ViaXvMCSurface *pViaSurface;
147790b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
147890b17f1bSmrg
147990b17f1bSmrg    if ((display == NULL) || target_surface == NULL) {
148090b17f1bSmrg	return BadValue;
148190b17f1bSmrg    }
148290b17f1bSmrg
148390b17f1bSmrg    if (subx || suby || surfx || surfy || (subw != surfw) || (subh != surfh)) {
148490b17f1bSmrg	fprintf(stderr, "ViaXvMC: Only completely overlapping subpicture "
148590b17f1bSmrg	    "supported.\n");
148690b17f1bSmrg	return BadValue;
148790b17f1bSmrg    }
148890b17f1bSmrg
148990b17f1bSmrg    if (NULL == (pViaSurface = target_surface->privData)) {
149090b17f1bSmrg	return (error_base + XvMCBadSurface);
149190b17f1bSmrg    }
149290b17f1bSmrg
149390b17f1bSmrg    if (subpicture) {
149490b17f1bSmrg
149590b17f1bSmrg	if (NULL == (pViaSubPic = subpicture->privData)) {
149690b17f1bSmrg	    return (error_base + XvMCBadSubpicture);
149790b17f1bSmrg	}
149890b17f1bSmrg
149990b17f1bSmrg	pViaSurface->privSubPic = pViaSubPic;
150090b17f1bSmrg    } else {
150190b17f1bSmrg	pViaSurface->privSubPic = NULL;
150290b17f1bSmrg    }
150390b17f1bSmrg    return Success;
150490b17f1bSmrg}
150590b17f1bSmrg
150690b17f1bSmrg_X_EXPORT Status
150790b17f1bSmrgXvMCBlendSubpicture2(Display * display,
150890b17f1bSmrg    XvMCSurface * source_surface,
150990b17f1bSmrg    XvMCSurface * target_surface,
151090b17f1bSmrg    XvMCSubpicture * subpicture,
151190b17f1bSmrg    short subx,
151290b17f1bSmrg    short suby,
151390b17f1bSmrg    unsigned short subw,
151490b17f1bSmrg    unsigned short subh,
151590b17f1bSmrg    short surfx, short surfy, unsigned short surfw, unsigned short surfh)
151690b17f1bSmrg{
151790b17f1bSmrg    ViaXvMCSurface *pViaSurface, *pViaSSurface;
151890b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
151990b17f1bSmrg    ViaXvMCContext *pViaXvMC;
152090b17f1bSmrg
152190b17f1bSmrg    unsigned width, height;
152290b17f1bSmrg
152390b17f1bSmrg    if ((display == NULL) || target_surface == NULL || source_surface == NULL) {
152490b17f1bSmrg	return BadValue;
152590b17f1bSmrg    }
152690b17f1bSmrg
152790b17f1bSmrg    if (subx || suby || surfx || surfy || (subw != surfw) || (subh != surfh)) {
152890b17f1bSmrg	fprintf(stderr, "ViaXvMC: Only completely overlapping subpicture "
152990b17f1bSmrg	    "supported.\n");
153090b17f1bSmrg	return BadMatch;
153190b17f1bSmrg    }
153290b17f1bSmrg
153390b17f1bSmrg    if (NULL == (pViaSurface = target_surface->privData)) {
153490b17f1bSmrg	return (error_base + XvMCBadSurface);
153590b17f1bSmrg    }
153690b17f1bSmrg
153790b17f1bSmrg    if (NULL == (pViaSSurface = source_surface->privData)) {
153890b17f1bSmrg	return (error_base + XvMCBadSurface);
153990b17f1bSmrg    }
154090b17f1bSmrg    pViaXvMC = pViaSurface->privContext;
154190b17f1bSmrg    width = pViaSSurface->width;
154290b17f1bSmrg    height = pViaSSurface->height;
154390b17f1bSmrg    if (width != pViaSurface->width || height != pViaSSurface->height) {
154490b17f1bSmrg	return BadMatch;
154590b17f1bSmrg    }
154690b17f1bSmrg
154790b17f1bSmrg    if (XvMCSyncSurface(display, source_surface)) {
154890b17f1bSmrg	return BadValue;
154990b17f1bSmrg    }
155090b17f1bSmrg
155190b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
155290b17f1bSmrg    viaBlit(pViaXvMC->xl, 8, yOffs(pViaSSurface), pViaSSurface->yStride,
155390b17f1bSmrg	yOffs(pViaSurface), pViaSurface->yStride,
155490b17f1bSmrg	width, height, 1, 1, VIABLIT_COPY, 0);
155590b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
155690b17f1bSmrg    if (pViaXvMC->chipId != PCI_CHIP_VT3259) {
155790b17f1bSmrg
155890b17f1bSmrg	/*
155990b17f1bSmrg	 * YV12 Chroma blit.
156090b17f1bSmrg	 */
156190b17f1bSmrg
156290b17f1bSmrg	viaBlit(pViaXvMC->xl, 8, uOffs(pViaSSurface),
156390b17f1bSmrg	    pViaSSurface->yStride >> 1, uOffs(pViaSurface),
156490b17f1bSmrg	    pViaSurface->yStride >> 1, width >> 1, height >> 1, 1, 1,
156590b17f1bSmrg	    VIABLIT_COPY, 0);
156690b17f1bSmrg	flushPCIXvMCLowLevel(pViaXvMC->xl);
156790b17f1bSmrg	viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface),
156890b17f1bSmrg	    pViaSSurface->yStride >> 1, vOffs(pViaSurface),
156990b17f1bSmrg	    pViaSurface->yStride >> 1, width >> 1, height >> 1, 1, 1,
157090b17f1bSmrg	    VIABLIT_COPY, 0);
157190b17f1bSmrg    } else {
157290b17f1bSmrg
157390b17f1bSmrg	/*
157490b17f1bSmrg	 * NV12 Chroma blit.
157590b17f1bSmrg	 */
157690b17f1bSmrg
157790b17f1bSmrg	viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface), pViaSSurface->yStride,
157890b17f1bSmrg	    vOffs(pViaSurface), pViaSurface->yStride,
157990b17f1bSmrg	    width, height >> 1, 1, 1, VIABLIT_COPY, 0);
158090b17f1bSmrg    }
158190b17f1bSmrg    pViaSurface->needsSync = 1;
158290b17f1bSmrg    pViaSurface->syncMode = LL_MODE_2D;
158390b17f1bSmrg    pViaSurface->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
158490b17f1bSmrg    if (flushXvMCLowLevel(pViaXvMC->xl)) {
158590b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
158690b17f1bSmrg	return BadValue;
158790b17f1bSmrg    }
158890b17f1bSmrg    if (subpicture) {
158990b17f1bSmrg
159090b17f1bSmrg	if (NULL == (pViaSubPic = subpicture->privData)) {
159190b17f1bSmrg	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
159290b17f1bSmrg	    return (error_base + XvMCBadSubpicture);
159390b17f1bSmrg	}
159490b17f1bSmrg
159590b17f1bSmrg	pViaSurface->privSubPic = pViaSubPic;
159690b17f1bSmrg    } else {
159790b17f1bSmrg	pViaSurface->privSubPic = NULL;
159890b17f1bSmrg    }
159990b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
160090b17f1bSmrg    return Success;
160190b17f1bSmrg}
160290b17f1bSmrg
160390b17f1bSmrg_X_EXPORT Status
160490b17f1bSmrgXvMCSyncSubpicture(Display * display, XvMCSubpicture * subpicture)
160590b17f1bSmrg{
160690b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
160790b17f1bSmrg    ViaXvMCContext *pViaXvMC;
160890b17f1bSmrg    Status retVal = 0;
160990b17f1bSmrg
161090b17f1bSmrg    if ((display == NULL) || subpicture == NULL) {
161190b17f1bSmrg	return BadValue;
161290b17f1bSmrg    }
161390b17f1bSmrg    if (NULL == (pViaSubPic = subpicture->privData)) {
161490b17f1bSmrg	return (error_base + XvMCBadSubpicture);
161590b17f1bSmrg    }
161690b17f1bSmrg
161790b17f1bSmrg    pViaXvMC = pViaSubPic->privContext;
161890b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
161990b17f1bSmrg    if (pViaSubPic->needsSync) {
162090b17f1bSmrg	if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D,
162190b17f1bSmrg		0, pViaSubPic->timeStamp)) {
162290b17f1bSmrg	    retVal = BadValue;
162390b17f1bSmrg	}
162490b17f1bSmrg	pViaSubPic->needsSync = 0;
162590b17f1bSmrg    }
162690b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
162790b17f1bSmrg    return retVal;
162890b17f1bSmrg}
162990b17f1bSmrg
163090b17f1bSmrg_X_EXPORT Status
163190b17f1bSmrgXvMCFlushSubpicture(Display * display, XvMCSubpicture * subpicture)
163290b17f1bSmrg{
163390b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
163490b17f1bSmrg
163590b17f1bSmrg    if ((display == NULL) || subpicture == NULL) {
163690b17f1bSmrg	return BadValue;
163790b17f1bSmrg    }
163890b17f1bSmrg    if (NULL == (pViaSubPic = subpicture->privData)) {
163990b17f1bSmrg	return (error_base + XvMCBadSubpicture);
164090b17f1bSmrg    }
164190b17f1bSmrg
164290b17f1bSmrg    return Success;
164390b17f1bSmrg}
164490b17f1bSmrg
164590b17f1bSmrg_X_EXPORT Status
164690b17f1bSmrgXvMCDestroySubpicture(Display * display, XvMCSubpicture * subpicture)
164790b17f1bSmrg{
164890b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
164990b17f1bSmrg    ViaXvMCContext *pViaXvMC;
165090b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
165190b17f1bSmrg
165290b17f1bSmrg    if ((display == NULL) || subpicture == NULL) {
165390b17f1bSmrg	return BadValue;
165490b17f1bSmrg    }
165590b17f1bSmrg    if (NULL == (pViaSubPic = subpicture->privData)) {
165690b17f1bSmrg	return (error_base + XvMCBadSubpicture);
165790b17f1bSmrg    }
165890b17f1bSmrg    pViaXvMC = pViaSubPic->privContext;
165990b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
166090b17f1bSmrg
166190b17f1bSmrg    sAPriv = SAREAPTR(pViaXvMC);
166290b17f1bSmrg    hwlLock(pViaXvMC->xl, 1);
166390b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 0);
166490b17f1bSmrg    if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
166590b17f1bSmrg	(pViaSubPic->srfNo | VIA_XVMC_VALID)) {
166690b17f1bSmrg	viaVideoSubPictureOffLocked(pViaXvMC->xl);
166790b17f1bSmrg	sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] = 0;
166890b17f1bSmrg    }
166990b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
167090b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 1);
167190b17f1bSmrg    hwlUnlock(pViaXvMC->xl, 1);
167290b17f1bSmrg
167390b17f1bSmrg    XLockDisplay(display);
167490b17f1bSmrg    _xvmc_destroy_subpicture(display, subpicture);
167590b17f1bSmrg    XUnlockDisplay(display);
167690b17f1bSmrg
167790b17f1bSmrg    free(pViaSubPic);
167890b17f1bSmrg    subpicture->privData = NULL;
167990b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
168090b17f1bSmrg
168190b17f1bSmrg    return Success;
168290b17f1bSmrg}
168390b17f1bSmrg
168490b17f1bSmrg_X_EXPORT Status
168590b17f1bSmrgXvMCGetSubpictureStatus(Display * display, XvMCSubpicture * subpic, int *stat)
168690b17f1bSmrg{
168790b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
168890b17f1bSmrg    ViaXvMCContext *pViaXvMC;
168990b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
169090b17f1bSmrg
169190b17f1bSmrg    if ((display == NULL) || subpic == NULL) {
169290b17f1bSmrg	return BadValue;
169390b17f1bSmrg    }
169490b17f1bSmrg    if (NULL == (pViaSubPic = subpic->privData)) {
169590b17f1bSmrg	return (error_base + XvMCBadSubpicture);
169690b17f1bSmrg    }
169790b17f1bSmrg    if (stat) {
169890b17f1bSmrg	*stat = 0;
169990b17f1bSmrg	pViaXvMC = pViaSubPic->privContext;
170090b17f1bSmrg	sAPriv = SAREAPTR(pViaXvMC);
170190b17f1bSmrg	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
170290b17f1bSmrg	    (pViaSubPic->srfNo | VIA_XVMC_VALID))
170390b17f1bSmrg	    *stat |= XVMC_DISPLAYING;
170490b17f1bSmrg    }
170590b17f1bSmrg    return Success;
170690b17f1bSmrg}
170790b17f1bSmrg
170890b17f1bSmrg_X_EXPORT Status
170990b17f1bSmrgXvMCFlushSurface(Display * display, XvMCSurface * surface)
171090b17f1bSmrg{
171190b17f1bSmrg    ViaXvMCSurface *pViaSurface;
171290b17f1bSmrg    ViaXvMCContext *pViaXvMC;
171390b17f1bSmrg    Status ret;
171490b17f1bSmrg
171590b17f1bSmrg    if ((display == NULL) || surface == NULL) {
171690b17f1bSmrg	return BadValue;
171790b17f1bSmrg    }
171890b17f1bSmrg    if (NULL == (pViaSurface = surface->privData)) {
171990b17f1bSmrg	return (error_base + XvMCBadSurface);
172090b17f1bSmrg    }
172190b17f1bSmrg
172290b17f1bSmrg    pViaXvMC = pViaSurface->privContext;
172390b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
172490b17f1bSmrg    if (pViaSurface->needsSync)
172590b17f1bSmrg	pViaSurface->timeStamp = pViaXvMC->timeStamp =
172690b17f1bSmrg	    viaDMATimeStampLowLevel(pViaXvMC->xl);
172790b17f1bSmrg    ret = (flushXvMCLowLevel(pViaXvMC->xl)) ? BadValue : Success;
172890b17f1bSmrg    if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
172990b17f1bSmrg	hwlLock(pViaXvMC->xl, 0);
173090b17f1bSmrg	pViaXvMC->haveDecoder = 0;
173190b17f1bSmrg	releaseDecoder(pViaXvMC, 0);
173290b17f1bSmrg	hwlUnlock(pViaXvMC->xl, 0);
173390b17f1bSmrg    }
173490b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
173590b17f1bSmrg    return ret;
173690b17f1bSmrg}
173790b17f1bSmrg
173890b17f1bSmrg_X_EXPORT Status
173990b17f1bSmrgXvMCGetSurfaceStatus(Display * display, XvMCSurface * surface, int *stat)
174090b17f1bSmrg{
174190b17f1bSmrg    ViaXvMCSurface *pViaSurface;
174290b17f1bSmrg    ViaXvMCContext *pViaXvMC;
174390b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
174490b17f1bSmrg    unsigned i;
174590b17f1bSmrg    int ret = 0;
174690b17f1bSmrg
174790b17f1bSmrg    if ((display == NULL) || surface == NULL) {
174890b17f1bSmrg	return BadValue;
174990b17f1bSmrg    }
175090b17f1bSmrg    if (NULL == (pViaSurface = surface->privData)) {
175190b17f1bSmrg	return (error_base + XvMCBadSurface);
175290b17f1bSmrg    }
175390b17f1bSmrg    if (stat) {
175490b17f1bSmrg	*stat = 0;
175590b17f1bSmrg	pViaXvMC = pViaSurface->privContext;
175690b17f1bSmrg	ppthread_mutex_lock(&pViaXvMC->ctxMutex);
175790b17f1bSmrg	sAPriv = SAREAPTR(pViaXvMC);
175890b17f1bSmrg	if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort]
175990b17f1bSmrg	    == (pViaSurface->srfNo | VIA_XVMC_VALID))
176090b17f1bSmrg	    *stat |= XVMC_DISPLAYING;
176190b17f1bSmrg	for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
176290b17f1bSmrg	    if (pViaXvMC->rendSurf[i] ==
176390b17f1bSmrg		(pViaSurface->srfNo | VIA_XVMC_VALID)) {
176490b17f1bSmrg		*stat |= XVMC_RENDERING;
176590b17f1bSmrg		break;
176690b17f1bSmrg	    }
176790b17f1bSmrg	}
176890b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
176990b17f1bSmrg    }
177090b17f1bSmrg    return ret;
177190b17f1bSmrg}
177290b17f1bSmrg
177390b17f1bSmrg_X_EXPORT XvAttribute *
177490b17f1bSmrgXvMCQueryAttributes(Display * display, XvMCContext * context, int *number)
177590b17f1bSmrg{
177690b17f1bSmrg    ViaXvMCContext *pViaXvMC;
177790b17f1bSmrg    XvAttribute *ret;
177890b17f1bSmrg    unsigned long siz;
177990b17f1bSmrg
178090b17f1bSmrg    *number = 0;
178190b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
178290b17f1bSmrg	return NULL;
178390b17f1bSmrg    }
178490b17f1bSmrg
178590b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
178690b17f1bSmrg	return NULL;
178790b17f1bSmrg    }
178890b17f1bSmrg
178990b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
179090b17f1bSmrg    if (NULL != (ret = (XvAttribute *)
179190b17f1bSmrg	    malloc(siz = VIA_NUM_XVMC_ATTRIBUTES * sizeof(XvAttribute)))) {
179290b17f1bSmrg	memcpy(ret, pViaXvMC->attribDesc, siz);
179390b17f1bSmrg	*number = VIA_NUM_XVMC_ATTRIBUTES;
179490b17f1bSmrg    }
179590b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
179690b17f1bSmrg
179790b17f1bSmrg    return ret;
179890b17f1bSmrg}
179990b17f1bSmrg
180090b17f1bSmrg_X_EXPORT Status
180190b17f1bSmrgXvMCSetAttribute(Display * display,
180290b17f1bSmrg    XvMCContext * context, Atom attribute, int value)
180390b17f1bSmrg{
180490b17f1bSmrg    int found;
180590b17f1bSmrg    unsigned i;
180690b17f1bSmrg    ViaXvMCContext *pViaXvMC;
180790b17f1bSmrg    ViaXvMCCommandBuffer buf;
180890b17f1bSmrg
180990b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
181090b17f1bSmrg	return (error_base + XvMCBadContext);
181190b17f1bSmrg    }
181290b17f1bSmrg
181390b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
181490b17f1bSmrg	return (error_base + XvMCBadContext);
181590b17f1bSmrg    }
181690b17f1bSmrg
181790b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
181890b17f1bSmrg
181990b17f1bSmrg    found = 0;
182090b17f1bSmrg    for (i = 0; i < pViaXvMC->attrib.numAttr; ++i) {
182190b17f1bSmrg	if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
182290b17f1bSmrg	    if ((!(pViaXvMC->attribDesc[i].flags & XvSettable)) ||
182390b17f1bSmrg		value < pViaXvMC->attribDesc[i].min_value ||
182490b17f1bSmrg		value > pViaXvMC->attribDesc[i].max_value) {
182590b17f1bSmrg		ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
182690b17f1bSmrg		return BadValue;
182790b17f1bSmrg	    }
182890b17f1bSmrg	    pViaXvMC->attrib.attributes[i].value = value;
182990b17f1bSmrg	    found = 1;
183090b17f1bSmrg	    pViaXvMC->attribChanged = 1;
183190b17f1bSmrg	    break;
183290b17f1bSmrg	}
183390b17f1bSmrg    }
183490b17f1bSmrg    if (!found) {
183590b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
183690b17f1bSmrg	return BadMatch;
183790b17f1bSmrg    }
183890b17f1bSmrg    if (pViaXvMC->haveXv) {
183990b17f1bSmrg	buf.command = VIA_XVMC_COMMAND_ATTRIBUTES;
184090b17f1bSmrg	pViaXvMC->xvImage->data = (char *)&buf;
184190b17f1bSmrg	buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
184290b17f1bSmrg	buf.attrib = pViaXvMC->attrib;
184390b17f1bSmrg	XLockDisplay(display);
184490b17f1bSmrg	pViaXvMC->attribChanged =
184590b17f1bSmrg	    XvPutImage(display, pViaXvMC->port, pViaXvMC->draw,
184690b17f1bSmrg	    pViaXvMC->gc, pViaXvMC->xvImage, 0, 0, 1, 1, 0, 0, 1, 1);
184790b17f1bSmrg	XUnlockDisplay(display);
184890b17f1bSmrg    }
184990b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
185090b17f1bSmrg    return Success;
185190b17f1bSmrg}
185290b17f1bSmrg
185390b17f1bSmrg_X_EXPORT Status
185490b17f1bSmrgXvMCGetAttribute(Display * display,
185590b17f1bSmrg    XvMCContext * context, Atom attribute, int *value)
185690b17f1bSmrg{
185790b17f1bSmrg    int found;
185890b17f1bSmrg    unsigned i;
185990b17f1bSmrg    ViaXvMCContext *pViaXvMC;
186090b17f1bSmrg
186190b17f1bSmrg    if ((display == NULL) || (context == NULL)) {
186290b17f1bSmrg	return (error_base + XvMCBadContext);
186390b17f1bSmrg    }
186490b17f1bSmrg
186590b17f1bSmrg    if (NULL == (pViaXvMC = context->privData)) {
186690b17f1bSmrg	return (error_base + XvMCBadContext);
186790b17f1bSmrg    }
186890b17f1bSmrg
186990b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
187090b17f1bSmrg    found = 0;
187190b17f1bSmrg    for (i = 0; i < pViaXvMC->attrib.numAttr; ++i) {
187290b17f1bSmrg	if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
187390b17f1bSmrg	    if (pViaXvMC->attribDesc[i].flags & XvGettable) {
187490b17f1bSmrg		*value = pViaXvMC->attrib.attributes[i].value;
187590b17f1bSmrg		found = 1;
187690b17f1bSmrg		break;
187790b17f1bSmrg	    }
187890b17f1bSmrg	}
187990b17f1bSmrg    }
188090b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
188190b17f1bSmrg
188290b17f1bSmrg    if (!found)
188390b17f1bSmrg	return BadMatch;
188490b17f1bSmrg    return Success;
188590b17f1bSmrg}
188690b17f1bSmrg
188790b17f1bSmrg_X_EXPORT Status
188890b17f1bSmrgXvMCHideSurface(Display * display, XvMCSurface * surface)
188990b17f1bSmrg{
189090b17f1bSmrg
189190b17f1bSmrg    ViaXvMCSurface *pViaSurface;
189290b17f1bSmrg    ViaXvMCContext *pViaXvMC;
189390b17f1bSmrg    ViaXvMCSubPicture *pViaSubPic;
189490b17f1bSmrg    volatile ViaXvMCSAreaPriv *sAPriv;
189590b17f1bSmrg    ViaXvMCCommandBuffer buf;
189690b17f1bSmrg    Status ret;
189790b17f1bSmrg
189890b17f1bSmrg    if ((display == NULL) || (surface == NULL)) {
189990b17f1bSmrg	return BadValue;
190090b17f1bSmrg    }
190190b17f1bSmrg    if (NULL == (pViaSurface = surface->privData)) {
190290b17f1bSmrg	return (error_base + XvMCBadSurface);
190390b17f1bSmrg    }
190490b17f1bSmrg    if (NULL == (pViaXvMC = pViaSurface->privContext)) {
190590b17f1bSmrg	return (error_base + XvMCBadContext);
190690b17f1bSmrg    }
190790b17f1bSmrg
190890b17f1bSmrg    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
190990b17f1bSmrg    if (!pViaXvMC->haveXv) {
191090b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
191190b17f1bSmrg	return Success;
191290b17f1bSmrg    }
191390b17f1bSmrg
191490b17f1bSmrg    sAPriv = SAREAPTR(pViaXvMC);
191590b17f1bSmrg    hwlLock(pViaXvMC->xl, 1);
191690b17f1bSmrg
191790b17f1bSmrg    if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] !=
191890b17f1bSmrg	(pViaSurface->srfNo | VIA_XVMC_VALID)) {
191990b17f1bSmrg	hwlUnlock(pViaXvMC->xl, 1);
192090b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
192190b17f1bSmrg	return Success;
192290b17f1bSmrg    }
192390b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 0);
192490b17f1bSmrg    if (NULL != (pViaSubPic = pViaSurface->privSubPic)) {
192590b17f1bSmrg	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
192690b17f1bSmrg	    (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
192790b17f1bSmrg	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
192890b17f1bSmrg	    viaVideoSubPictureOffLocked(pViaXvMC->xl);
192990b17f1bSmrg	}
193090b17f1bSmrg    }
193190b17f1bSmrg    flushPCIXvMCLowLevel(pViaXvMC->xl);
193290b17f1bSmrg    setLowLevelLocking(pViaXvMC->xl, 1);
193390b17f1bSmrg    hwlUnlock(pViaXvMC->xl, 1);
193490b17f1bSmrg
193590b17f1bSmrg    buf.command = VIA_XVMC_COMMAND_UNDISPLAY;
193690b17f1bSmrg    buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
193790b17f1bSmrg    buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
193890b17f1bSmrg    pViaXvMC->xvImage->data = (char *)&buf;
193990b17f1bSmrg    if ((ret = XvPutImage(display, pViaXvMC->port, pViaXvMC->draw,
194090b17f1bSmrg		pViaXvMC->gc, pViaXvMC->xvImage, 0, 0, 1, 1, 0, 0, 1, 1))) {
194190b17f1bSmrg	fprintf(stderr, "XvMCPutSurface: Hiding overlay failed.\n");
194290b17f1bSmrg	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
194390b17f1bSmrg	return ret;
194490b17f1bSmrg    }
194590b17f1bSmrg    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
194690b17f1bSmrg    return Success;
194790b17f1bSmrg}
1948