viaXvMC.c revision 90b17f1b
1/*****************************************************************************
2 * VIA Unichrome XvMC extension client lib.
3 *
4 * Copyright (c) 2004-2005 Thomas Hellstr�m. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25/*
26 *Author: Thomas Hellstr�m, 2004.
27 *Bugfixes by among others Pascal Brisset and Terry Barnaby.
28 *DRI protocol support by Thomas Hellstr�m, 2005.
29 */
30
31#undef WAITPAUSE
32
33#include "viaXvMCPriv.h"
34#include "viaLowLevel.h"
35#include <stdio.h>
36#include <sys/ioctl.h>
37#include <sys/time.h>
38#include <time.h>
39#include <fourcc.h>
40#include <X11/extensions/Xv.h>
41#include <xf86drm.h>
42#include <pthread.h>
43#include "vldXvMC.h"
44#include "xf86dri.h"
45#include "driDrawable.h"
46
47#define SAREAPTR(ctx) ((ViaXvMCSAreaPriv *)			\
48		       (((CARD8 *)(ctx)->sAreaAddress) +	\
49			(ctx)->sAreaPrivOffset))
50
51typedef struct
52{
53    int major;
54    int minor;
55    int patchlevel;
56} ViaDRMVersion;
57
58static int error_base;
59static int event_base;
60static unsigned numContexts = 0;
61static int globalFD;
62static drmAddress sAreaAddress;
63static drmAddress fbAddress;
64static drmAddress mmioAddress;
65static const ViaDRMVersion drmExpected = { 2, 0, 0 };
66static const ViaDRMVersion drmCompat = { 2, 0, 0 };
67
68#define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X')
69
70#define ppthread_mutex_lock(arg)		\
71  {						\
72    pthread_mutex_lock(arg);			\
73  }						\
74
75#define ppthread_mutex_unlock(arg)		\
76  {						\
77    pthread_mutex_unlock(arg);			\
78  }						\
79
80static unsigned
81yOffs(ViaXvMCSurface * srf)
82{
83    return srf->offsets[0];
84}
85
86static unsigned
87vOffs(ViaXvMCSurface * srf)
88{
89    return srf->offsets[0] + srf->yStride * srf->height;
90}
91
92static unsigned
93uOffs(ViaXvMCSurface * srf)
94{
95    return srf->offsets[0] + (srf->yStride * srf->height) +
96	(srf->yStride >> 1) * (srf->height >> 1);
97}
98
99static void
100defaultQMatrices(ViaXvMCContext * ctx)
101{
102    int i;
103
104    static const char intra[64] = {
105	8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37,
106	19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40,
107	22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58,
108	26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83
109    };
110
111    for (i = 0; i < 64; ++i) {
112	ctx->intra_quantiser_matrix[i] = intra[i];
113	ctx->non_intra_quantiser_matrix[i] = 16;
114    }
115    ctx->intraLoaded = 0;
116    ctx->nonIntraLoaded = 0;
117}
118
119static void
120releaseDecoder(ViaXvMCContext * ctx, int clearCtx)
121{
122    volatile ViaXvMCSAreaPriv *sAPriv;
123
124    sAPriv = SAREAPTR(ctx);
125    UNICHROME_UNLOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv,
126	ctx->drmcontext);
127}
128
129static int
130grabDecoder(ViaXvMCContext * ctx, int *hadLastLock)
131{
132    volatile ViaXvMCSAreaPriv *sAPriv = SAREAPTR(ctx);
133    int retFtx, lc;
134
135    /*
136     * Try to grab the decoder. If it is not available we will sleep until
137     * it becomes available or for a maximum of 20 ms.
138     * Then try to grab it again, unless a timeout occured. If the decoder is
139     * available, the lock should be reasonably fast.
140     */
141
142    if (ctx->haveDecoder) {
143	flushXvMCLowLevel(ctx->xl);    /* Ignore errors here. */
144
145	/*fprintf(stderr,"ViaXvMC: ERROR: Trying to re-lock decoder.\n"); */
146	*hadLastLock = 1;
147	return 0;
148    }
149    UNICHROME_LOCK(ctx->fd, UNICHROME_LOCK_DECODER1, sAPriv, ctx->drmcontext,
150	lc, retFtx);
151    *hadLastLock = (ctx->drmcontext == lc);
152
153    return retFtx;
154}
155
156static void
157setupAttribDesc(Display * display, XvPortID port,
158    const ViaXvMCAttrHolder * attrib, XvAttribute attribDesc[])
159{
160    XvAttribute *XvAttribs, *curAD;
161    int num;
162    unsigned i, j;
163
164    XLockDisplay(display);
165    XvAttribs = XvQueryPortAttributes(display, port, &num);
166    for (i = 0; i < attrib->numAttr; ++i) {
167	curAD = attribDesc + i;
168	curAD->flags = 0;
169	curAD->min_value = 0;
170	curAD->max_value = 0;
171	curAD->name = NULL;
172	for (j = 0; j < num; ++j) {
173	    if (attrib->attributes[i].attribute ==
174		XInternAtom(display, XvAttribs[j].name, TRUE)) {
175		*curAD = XvAttribs[j];
176		curAD->name = strdup(XvAttribs[j].name);
177		break;
178	    }
179	}
180    }
181    if (XvAttribs)
182	XFree(XvAttribs);
183    XUnlockDisplay(display);
184
185}
186
187static void
188releaseAttribDesc(int numAttr, XvAttribute attribDesc[])
189{
190    int i;
191
192    for (i = 0; i < numAttr; ++i) {
193	if (attribDesc[i].name)
194	    free(attribDesc[i].name);
195    }
196}
197
198static Status
199releaseContextResources(Display * display, XvMCContext * context,
200    int freePrivate, Status errType)
201{
202    ViaXvMCContext *pViaXvMC = (ViaXvMCContext *) context->privData;
203
204    switch (pViaXvMC->resources) {
205    case context_drawHash:
206	driDestroyHashContents(pViaXvMC->drawHash);
207	drmHashDestroy(pViaXvMC->drawHash);
208    case context_lowLevel:
209	closeXvMCLowLevel(pViaXvMC->xl);
210    case context_mutex:
211	pthread_mutex_destroy(&pViaXvMC->ctxMutex);
212    case context_drmContext:
213	XLockDisplay(display);
214	uniDRIDestroyContext(display, pViaXvMC->screen, pViaXvMC->id);
215	XUnlockDisplay(display);
216    case context_sAreaMap:
217	numContexts--;
218	if (numContexts == 0)
219	    drmUnmap(pViaXvMC->sAreaAddress, pViaXvMC->sAreaSize);
220    case context_fbMap:
221	if (numContexts == 0)
222	    drmUnmap(pViaXvMC->fbAddress, pViaXvMC->fbSize);
223    case context_mmioMap:
224	if (numContexts == 0)
225	    drmUnmap(pViaXvMC->mmioAddress, pViaXvMC->mmioSize);
226    case context_fd:
227	if (numContexts == 0) {
228	    if (pViaXvMC->fd >= 0)
229		drmClose(pViaXvMC->fd);
230	}
231	pViaXvMC->fd = -1;
232    case context_driConnection:
233	if (numContexts == 0) {
234	    XLockDisplay(display);
235	    uniDRICloseConnection(display, pViaXvMC->screen);
236	    XUnlockDisplay(display);
237	}
238    case context_context:
239	XLockDisplay(display);
240	_xvmc_destroy_context(display, context);
241	XUnlockDisplay(display);
242	if (!freePrivate)
243	    break;
244    default:
245	free(pViaXvMC);
246	context->privData = NULL;
247    }
248    return errType;
249}
250
251_X_EXPORT Status
252XvMCCreateContext(Display * display, XvPortID port,
253    int surface_type_id, int width, int height, int flags,
254    XvMCContext * context)
255{
256    ViaXvMCContext *pViaXvMC;
257    int priv_count;
258    uint *priv_data;
259    uint magic;
260    unsigned i;
261    Status ret;
262    int major, minor;
263    ViaXvMCCreateContextRec *tmpComm;
264    drmVersionPtr drmVer;
265    char *curBusID;
266    int isCapable;
267
268    /*
269     * Verify Obvious things first
270     */
271
272    if (context == NULL) {
273	return XvMCBadContext;
274    }
275
276    if (!(flags & XVMC_DIRECT)) {
277	fprintf(stderr, "Indirect Rendering not supported! Using Direct.\n");
278    }
279
280    /*
281     *FIXME: Check $DISPLAY for legal values here
282     */
283
284    context->surface_type_id = surface_type_id;
285    context->width = (unsigned short)((width + 15) & ~15);
286    context->height = (unsigned short)((height + 15) & ~15);
287    context->flags = flags;
288    context->port = port;
289
290    /*
291     *  Width, Height, and flags are checked against surface_type_id
292     *  and port for validity inside the X server, no need to check
293     *  here.
294     */
295
296    /* Allocate private Context data */
297    context->privData = (void *)malloc(sizeof(ViaXvMCContext));
298    if (!context->privData) {
299	fprintf(stderr, "Unable to allocate resources for XvMC context.\n");
300	return BadAlloc;
301    }
302
303    pViaXvMC = (ViaXvMCContext *) context->privData;
304    pViaXvMC->resources = context_none;
305
306    /* Verify the XvMC extension exists */
307
308    XLockDisplay(display);
309    if (!XvMCQueryExtension(display, &event_base, &error_base)) {
310	fprintf(stderr, "XvMC Extension is not available!\n");
311	free(pViaXvMC);
312	XUnlockDisplay(display);
313	return BadAlloc;
314    }
315
316    /* Verify XvMC version */
317    ret = XvMCQueryVersion(display, &major, &minor);
318    if (ret) {
319	fprintf(stderr, "XvMCQuery Version Failed, unable to determine "
320	    "protocol version!\n");
321    }
322    XUnlockDisplay(display);
323
324    /* FIXME: Check Major and Minor here */
325
326    XLockDisplay(display);
327    if ((ret = _xvmc_create_context(display, context, &priv_count,
328		&priv_data))) {
329	XUnlockDisplay(display);
330	fprintf(stderr, "Unable to create XvMC Context!\n");
331	return releaseContextResources(display, context, 1, BadAlloc);
332    }
333    XUnlockDisplay(display);
334
335    /*
336     * Check size and version of returned data.
337     */
338
339    tmpComm = (ViaXvMCCreateContextRec *) priv_data;
340    if (priv_count != (sizeof(ViaXvMCCreateContextRec) >> 2)) {
341	fprintf(stderr, "_xvmc_create_context() returned incorrect "
342	    "data size!\n");
343	fprintf(stderr, "\tExpected %d, got %d\n",
344	    ((int)(sizeof(ViaXvMCCreateContextRec) >> 2)), priv_count);
345	XFree(priv_data);
346	return releaseContextResources(display, context, 1, BadAlloc);
347    }
348    pViaXvMC->resources = context_context;
349
350    if ((tmpComm->major != VIAXVMC_MAJOR) ||
351	(tmpComm->minor != VIAXVMC_MINOR)) {
352	fprintf(stderr, "Version mismatch between the X via driver\n"
353	    "and the XvMC library. Cannot continue!\n");
354	XFree(priv_data);
355	return releaseContextResources(display, context, 1, BadAlloc);
356    }
357
358    pViaXvMC->ctxNo = tmpComm->ctxNo;
359    pViaXvMC->fbOffset = tmpComm->fbOffset;
360    pViaXvMC->fbSize = tmpComm->fbSize;
361    pViaXvMC->mmioOffset = tmpComm->mmioOffset;
362    pViaXvMC->mmioSize = tmpComm->mmioSize;
363    pViaXvMC->sAreaSize = tmpComm->sAreaSize;
364    pViaXvMC->sAreaPrivOffset = tmpComm->sAreaPrivOffset;
365    pViaXvMC->decoderOn = 0;
366    pViaXvMC->xvMCPort = tmpComm->xvmc_port;
367    pViaXvMC->useAGP = tmpComm->useAGP;
368    pViaXvMC->attrib = tmpComm->initAttrs;
369    pViaXvMC->screen = tmpComm->screen;
370    pViaXvMC->depth = tmpComm->depth;
371    pViaXvMC->stride = tmpComm->stride;
372    pViaXvMC->chipId = tmpComm->chipId;
373
374    /*
375     * Must free the private data we were passed from X
376     */
377
378    XFree(priv_data);
379    priv_data = NULL;
380
381    /*
382     * Check for direct rendering capable, establish DRI and DRM connections,
383     * map framebuffer, DRI shared area and read-only register areas.
384     * Initial checking for drm has already been done by the server.
385     * Only do this for the first context we create.
386     */
387
388    if (numContexts == 0) {
389	XLockDisplay(display);
390	ret =
391	    uniDRIQueryDirectRenderingCapable(display, pViaXvMC->screen,
392	    &isCapable);
393	if (!ret || !isCapable) {
394	    XUnlockDisplay(display);
395	    fprintf(stderr,
396		"Direct Rendering is not available on this system!\n");
397	    return releaseContextResources(display, context, 1, BadAlloc);
398	}
399
400	if (!uniDRIOpenConnection(display, pViaXvMC->screen,
401		&pViaXvMC->sAreaOffset, &curBusID)) {
402	    XUnlockDisplay(display);
403	    fprintf(stderr, "Could not open DRI connection to X server!\n");
404	    return releaseContextResources(display, context, 1, BadAlloc);
405	}
406	XUnlockDisplay(display);
407
408	strncpy(pViaXvMC->busIdString, curBusID, 20);
409	pViaXvMC->busIdString[20] = '\0';
410	XFree(curBusID);
411
412	pViaXvMC->resources = context_driConnection;
413
414	if ((pViaXvMC->fd = drmOpen("via", pViaXvMC->busIdString)) < 0) {
415	    fprintf(stderr, "DRM Device for via could not be opened.\n");
416	    return releaseContextResources(display, context, 1, BadAlloc);
417	}
418	globalFD = pViaXvMC->fd;
419	pViaXvMC->resources = context_fd;
420
421	if (NULL == (drmVer = drmGetVersion(pViaXvMC->fd))) {
422	    fprintf(stderr, "viaXvMC: Could not get drm version.");
423	    return releaseContextResources(display, context, 1, BadAlloc);
424	}
425	if ((drmVer->version_major < drmExpected.major) ||
426	    (drmVer->version_major > drmCompat.major) ||
427	    ((drmVer->version_major == drmExpected.major) &&
428		(drmVer->version_minor < drmExpected.minor))) {
429	    fprintf(stderr,
430		"viaXvMC: Kernel drm is not compatible with XvMC.\n");
431	    fprintf(stderr,
432		"viaXvMC: Kernel drm version: %d.%d.%d "
433		"and I can work with versions %d.%d.x - %d.x.x\n"
434		"Please update either this XvMC driver or your kernel DRM.\n",
435		drmVer->version_major, drmVer->version_minor,
436		drmVer->version_patchlevel, drmExpected.major,
437		drmExpected.minor, drmCompat.major);
438	    drmFreeVersion(drmVer);
439	    return releaseContextResources(display, context, 1, BadAlloc);
440	}
441	drmFreeVersion(drmVer);
442	drmGetMagic(pViaXvMC->fd, &magic);
443
444	XLockDisplay(display);
445	if (!uniDRIAuthConnection(display, pViaXvMC->screen, magic)) {
446	    XUnlockDisplay(display);
447	    fprintf(stderr,
448		"viaXvMC: X server did not allow DRI. Check permissions.\n");
449	    return releaseContextResources(display, context, 1, BadAlloc);
450	}
451	XUnlockDisplay(display);
452
453	/*
454	 * Map the register memory
455	 */
456
457	if (drmMap(pViaXvMC->fd, pViaXvMC->mmioOffset,
458		pViaXvMC->mmioSize, &mmioAddress) < 0) {
459	    fprintf(stderr,
460		"Unable to map the display chip mmio registers.\n");
461	    return releaseContextResources(display, context, 1, BadAlloc);
462	}
463	pViaXvMC->mmioAddress = mmioAddress;
464	pViaXvMC->resources = context_mmioMap;
465
466	/*
467	 * Map Framebuffer memory
468	 */
469
470	if (drmMap(pViaXvMC->fd, pViaXvMC->fbOffset,
471		pViaXvMC->fbSize, &fbAddress) < 0) {
472	    fprintf(stderr, "Unable to map XvMC Framebuffer.\n");
473	    return releaseContextResources(display, context, 1, BadAlloc);
474	}
475	pViaXvMC->fbAddress = fbAddress;
476	pViaXvMC->resources = context_fbMap;
477
478	/*
479	 * Map DRI Sarea.
480	 */
481
482	if (drmMap(pViaXvMC->fd, pViaXvMC->sAreaOffset,
483		pViaXvMC->sAreaSize, &sAreaAddress) < 0) {
484	    fprintf(stderr, "Unable to map DRI SAREA.\n");
485	    return releaseContextResources(display, context, 1, BadAlloc);
486	}
487    } else {
488	pViaXvMC->fd = globalFD;
489	pViaXvMC->mmioAddress = mmioAddress;
490	pViaXvMC->fbAddress = fbAddress;
491    }
492
493    pViaXvMC->sAreaAddress = sAreaAddress;
494    pViaXvMC->resources = context_sAreaMap;
495    numContexts++;
496
497    /*
498     * Find a matching visual. Important only for direct drawing to the visible
499     * frame-buffer.
500     */
501
502    XLockDisplay(display);
503    ret = XMatchVisualInfo(display, pViaXvMC->screen,
504	(pViaXvMC->depth == 32) ? 24 : pViaXvMC->depth, TrueColor,
505	&pViaXvMC->visualInfo);
506    XUnlockDisplay(display);
507    if (!ret) {
508	fprintf(stderr,
509	    "viaXvMC: Could not find a matching TrueColor visual.\n");
510	return releaseContextResources(display, context, 1, BadAlloc);
511    }
512
513    if (!uniDRICreateContext(display, pViaXvMC->screen,
514	    pViaXvMC->visualInfo.visual, &pViaXvMC->id,
515	    &pViaXvMC->drmcontext)) {
516
517	fprintf(stderr, "viaXvMC: Could not create DRI context.\n");
518	return releaseContextResources(display, context, 1, BadAlloc);
519    }
520
521    pViaXvMC->resources = context_drmContext;
522
523    for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
524	pViaXvMC->rendSurf[i] = 0;
525    }
526    pViaXvMC->lastSrfDisplaying = ~0;
527    setupAttribDesc(display, port, &pViaXvMC->attrib, pViaXvMC->attribDesc);
528
529    pViaXvMC->hwLock = (drmLockPtr) pViaXvMC->sAreaAddress;
530    defaultQMatrices(pViaXvMC);
531    pViaXvMC->chromaIntraLoaded = 1;
532    pViaXvMC->chromaNonIntraLoaded = 1;
533    pViaXvMC->yStride = (width + 31) & ~31;
534    pViaXvMC->haveDecoder = 0;
535    pViaXvMC->attribChanged = 1;
536    pViaXvMC->haveXv = 0;
537    pViaXvMC->port = context->port;
538    pthread_mutex_init(&pViaXvMC->ctxMutex, NULL);
539    pViaXvMC->resources = context_mutex;
540    pViaXvMC->timeStamp = 0;
541    setRegion(0, 0, -1, -1, pViaXvMC->sRegion);
542    setRegion(0, 0, -1, -1, pViaXvMC->dRegion);
543
544    if (NULL == (pViaXvMC->xl =
545	    initXvMCLowLevel(pViaXvMC->fd, &pViaXvMC->drmcontext,
546		pViaXvMC->hwLock, pViaXvMC->mmioAddress,
547		pViaXvMC->fbAddress, pViaXvMC->stride, pViaXvMC->depth,
548		context->width, context->height,
549		pViaXvMC->useAGP, pViaXvMC->chipId))) {
550
551	fprintf(stderr, "ViaXvMC: Could not allocate timestamp blit area.\n");
552	return releaseContextResources(display, context, 1, BadAlloc);
553    }
554    pViaXvMC->resources = context_lowLevel;
555    setAGPSyncLowLevel(pViaXvMC->xl, 1, 0);
556
557    if (NULL == (pViaXvMC->drawHash = drmHashCreate())) {
558	fprintf(stderr, "ViaXvMC: Could not allocate drawable hash table.\n");
559	return releaseContextResources(display, context, 1, BadAlloc);
560    }
561    pViaXvMC->resources = context_drawHash;
562
563    if (numContexts == 1) {
564	hwlLock(pViaXvMC->xl, 1);
565	setLowLevelLocking(pViaXvMC->xl, 0);
566	viaVideoSubPictureOffLocked(pViaXvMC->xl);
567	flushXvMCLowLevel(pViaXvMC->xl);
568	setLowLevelLocking(pViaXvMC->xl, 1);
569	hwlUnlock(pViaXvMC->xl, 1);
570    }
571
572    return Success;
573}
574
575_X_EXPORT Status
576XvMCDestroyContext(Display * display, XvMCContext * context)
577{
578    ViaXvMCContext *pViaXvMC;
579
580    if (context == NULL) {
581	return (error_base + XvMCBadContext);
582    }
583    if (NULL == (pViaXvMC = context->privData)) {
584	return (error_base + XvMCBadContext);
585    }
586
587    /*
588     * Release decoder if we have it. In case of crash or termination
589     * before XvMCDestroyContext, the X server will take care of this.
590     */
591
592    releaseAttribDesc(pViaXvMC->attrib.numAttr, pViaXvMC->attribDesc);
593    releaseDecoder(pViaXvMC, 1);
594    return releaseContextResources(display, context, 1, Success);
595}
596
597_X_EXPORT Status
598XvMCCreateSurface(Display * display, XvMCContext * context,
599    XvMCSurface * surface)
600{
601    ViaXvMCContext *pViaXvMC;
602    ViaXvMCSurface *pViaSurface;
603    int priv_count;
604    unsigned *priv_data;
605    unsigned i;
606    Status ret;
607
608    if ((surface == NULL) || (context == NULL) || (display == NULL)) {
609	return BadValue;
610    }
611
612    pViaXvMC = (ViaXvMCContext *) context->privData;
613    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
614
615    if (pViaXvMC == NULL) {
616	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
617	return (error_base + XvMCBadContext);
618    }
619
620    pViaSurface = surface->privData =
621	(ViaXvMCSurface *) malloc(sizeof(ViaXvMCSurface));
622    if (!surface->privData) {
623	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
624	return BadAlloc;
625    }
626    XLockDisplay(display);
627    if ((ret = _xvmc_create_surface(display, context, surface,
628		&priv_count, &priv_data))) {
629	XUnlockDisplay(display);
630	free(pViaSurface);
631	fprintf(stderr, "Unable to create XvMC Surface.\n");
632	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
633	return ret;
634    }
635    XUnlockDisplay(display);
636
637    pViaSurface->srfNo = priv_data[0];
638
639    /*
640     * Store framebuffer offsets to the buffers allocated for this surface.
641     * For some chipset revisions, surfaces may be double-buffered.
642     */
643
644    pViaSurface->numBuffers = priv_data[1];
645    for (i = 0; i < pViaSurface->numBuffers; ++i) {
646	pViaSurface->offsets[i] = priv_data[i + 2];
647    }
648    pViaSurface->curBuf = 0;
649
650    /* Free data returned from xvmc_create_surface */
651
652    XFree(priv_data);
653
654    pViaSurface->width = context->width;
655    pViaSurface->height = context->height;
656    pViaSurface->yStride = pViaXvMC->yStride;
657    pViaSurface->privContext = pViaXvMC;
658    pViaSurface->privSubPic = NULL;
659    pViaSurface->needsSync = 0;
660    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
661    return Success;
662}
663
664_X_EXPORT Status
665XvMCDestroySurface(Display * display, XvMCSurface * surface)
666{
667    ViaXvMCSurface *pViaSurface;
668
669    if ((display == NULL) || (surface == NULL)) {
670	return BadValue;
671    }
672    if (surface->privData == NULL) {
673	return (error_base + XvMCBadSurface);
674    }
675
676    pViaSurface = (ViaXvMCSurface *) surface->privData;
677
678    XLockDisplay(display);
679    _xvmc_destroy_surface(display, surface);
680    XUnlockDisplay(display);
681
682    free(pViaSurface);
683    surface->privData = NULL;
684    return Success;
685}
686
687_X_EXPORT Status
688XvMCPutSlice2(Display * display, XvMCContext * context, char *slice,
689    int nBytes, int sliceCode)
690{
691    ViaXvMCContext *pViaXvMC;
692    CARD32 sCode = 0x00010000 | (sliceCode & 0xFF) << 24;
693
694    if ((display == NULL) || (context == NULL)) {
695	return BadValue;
696    }
697    if (NULL == (pViaXvMC = context->privData)) {
698	return (error_base + XvMCBadContext);
699    }
700    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
701    if (!pViaXvMC->haveDecoder) {
702	fprintf(stderr, "XvMCPutSlice: This context does not own decoder!\n");
703	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
704	return BadAlloc;
705    }
706
707    viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *) slice, nBytes, sCode);
708
709    flushPCIXvMCLowLevel(pViaXvMC->xl);
710    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
711    return Success;
712}
713
714_X_EXPORT Status
715XvMCPutSlice(Display * display, XvMCContext * context, char *slice,
716    int nBytes)
717{
718    ViaXvMCContext *pViaXvMC;
719
720    if ((display == NULL) || (context == NULL)) {
721	return BadValue;
722    }
723    if (NULL == (pViaXvMC = context->privData)) {
724	return (error_base + XvMCBadContext);
725    }
726    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
727
728    if (!pViaXvMC->haveDecoder) {
729	fprintf(stderr, "XvMCPutSlice: This context does not own decoder!\n");
730	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
731	return BadAlloc;
732    }
733
734    viaMpegWriteSlice(pViaXvMC->xl, (CARD8 *) slice, nBytes, 0);
735    flushPCIXvMCLowLevel(pViaXvMC->xl);
736    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
737    return Success;
738}
739
740static Status
741updateXVOverlay(Display * display, ViaXvMCContext * pViaXvMC,
742    ViaXvMCSurface * pViaSurface, Drawable draw,
743    short srcx, short srcy, unsigned short srcw,
744    unsigned short srch, short destx, short desty,
745    unsigned short destw, unsigned short desth)
746{
747    ViaXvMCCommandBuffer buf;
748    ViaXvMCSubPicture *pViaSubPic;
749    Status ret;
750
751    if (!pViaXvMC->haveXv) {
752	pViaXvMC->xvImage =
753	    XvCreateImage(display, pViaXvMC->port, FOURCC_XVMC,
754	    (char *)&buf, pViaSurface->width, pViaSurface->height);
755	pViaXvMC->gc = XCreateGC(display, draw, 0, 0);
756	pViaXvMC->haveXv = 1;
757    }
758    pViaXvMC->draw = draw;
759    pViaXvMC->xvImage->data = (char *)&buf;
760
761    buf.command = (pViaXvMC->attribChanged) ?
762	VIA_XVMC_COMMAND_FDISPLAY : VIA_XVMC_COMMAND_DISPLAY;
763    buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
764    buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
765    pViaSubPic = pViaSurface->privSubPic;
766    buf.subPicNo = ((NULL == pViaSubPic) ? 0 : pViaSubPic->srfNo)
767	| VIA_XVMC_VALID;
768    buf.attrib = pViaXvMC->attrib;
769
770    XLockDisplay(display);
771
772    if ((ret = XvPutImage(display, pViaXvMC->port, draw, pViaXvMC->gc,
773		pViaXvMC->xvImage, srcx, srcy, srcw, srch,
774		destx, desty, destw, desth))) {
775	XUnlockDisplay(display);
776	return ret;
777    }
778    XSync(display, 0);
779    XUnlockDisplay(display);
780    pViaXvMC->attribChanged = 0;
781    return Success;
782}
783
784_X_EXPORT Status
785XvMCPutSurface(Display * display, XvMCSurface * surface, Drawable draw,
786    short srcx, short srcy, unsigned short srcw,
787    unsigned short srch, short destx, short desty,
788    unsigned short destw, unsigned short desth, int flags)
789{
790    /*
791     * This function contains some hairy locking logic. What we really want to
792     * do is to flip the picture ASAP, to get a low latency and smooth playback.
793     * However, if somebody else used the overlay since we used it last or if it is
794     * our first time, we'll have to call X to update the overlay first. Otherwise
795     * we'll do the overlay update once we've flipped. Since we release the hardware
796     * lock when we call X, X needs to verify using the SAREA that nobody else flipped
797     * in a picture between the lock release and the X server control. Similarly
798     * when the overlay update returns, we have to make sure that we still own the
799     * overlay.
800     */
801
802    ViaXvMCSurface *pViaSurface;
803    ViaXvMCContext *pViaXvMC;
804    ViaXvMCSubPicture *pViaSubPic;
805    volatile ViaXvMCSAreaPriv *sAPriv;
806    Status ret;
807    unsigned dispSurface, lastSurface;
808    int overlayUpdated;
809    drawableInfo *drawInfo;
810    XvMCRegion sReg, dReg;
811    Bool forceUpdate = FALSE;
812
813    if ((display == NULL) || (surface == NULL)) {
814	return BadValue;
815    }
816    if (NULL == (pViaSurface = surface->privData)) {
817	return (error_base + XvMCBadSurface);
818    }
819    if (NULL == (pViaXvMC = pViaSurface->privContext)) {
820	return (error_base + XvMCBadContext);
821    }
822
823    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
824    pViaSubPic = pViaSurface->privSubPic;
825    sAPriv = SAREAPTR(pViaXvMC);
826
827    setRegion(srcx, srcy, srcw, srch, sReg);
828    setRegion(destx, desty, destw, desth, dReg);
829
830    if ((!regionEqual(sReg, pViaXvMC->sRegion)) ||
831	(!regionEqual(dReg, pViaXvMC->dRegion))) {
832
833	/*
834	 * Force update of the video overlay to match the new format.
835	 */
836
837	pViaXvMC->sRegion = sReg;
838	pViaXvMC->dRegion = dReg;
839	forceUpdate = TRUE;
840    }
841
842    hwlLock(pViaXvMC->xl, 1);
843
844    if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display,
845	    pViaXvMC->screen, draw, 0, pViaXvMC->fd, pViaXvMC->drmcontext,
846	    pViaXvMC->sAreaAddress, FALSE, &drawInfo, sizeof(*drawInfo))) {
847
848	hwlUnlock(pViaXvMC->xl, 1);
849	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
850	return BadAccess;
851    }
852
853    setLowLevelLocking(pViaXvMC->xl, 0);
854
855    /*
856     * Put a surface ID in the SAREA to "authenticate" to the
857     * X server.
858     */
859
860    dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
861    lastSurface = pViaXvMC->lastSrfDisplaying;
862    sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] =
863	pViaXvMC->lastSrfDisplaying = pViaSurface->srfNo | VIA_XVMC_VALID;
864    overlayUpdated = 0;
865
866    viaVideoSetSWFLipLocked(pViaXvMC->xl, yOffs(pViaSurface),
867	uOffs(pViaSurface), vOffs(pViaSurface), pViaSurface->yStride,
868	pViaSurface->yStride >> 1);
869
870    while ((lastSurface != dispSurface) || forceUpdate) {
871
872	forceUpdate = FALSE;
873	flushPCIXvMCLowLevel(pViaXvMC->xl);
874	setLowLevelLocking(pViaXvMC->xl, 1);
875	hwlUnlock(pViaXvMC->xl, 1);
876
877	/*
878	 * We weren't the last to display. Update the overlay before flipping.
879	 */
880
881	ret =
882	    updateXVOverlay(display, pViaXvMC, pViaSurface, draw, srcx, srcy,
883	    srcw, srch, destx, desty, destw, desth);
884	if (ret) {
885	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
886	    return ret;
887	}
888
889	hwlLock(pViaXvMC->xl, 1);
890
891	if (getDRIDrawableInfoLocked(pViaXvMC->drawHash, display,
892		pViaXvMC->screen, draw, 0, pViaXvMC->fd, pViaXvMC->drmcontext,
893		pViaXvMC->sAreaAddress, FALSE, &drawInfo,
894		sizeof(*drawInfo))) {
895
896	    hwlUnlock(pViaXvMC->xl, 1);
897	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
898	    return BadAccess;
899	}
900
901	setLowLevelLocking(pViaXvMC->xl, 0);
902	lastSurface = pViaSurface->srfNo | VIA_XVMC_VALID;
903	dispSurface = sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort];
904	overlayUpdated = 1;
905    }
906
907    /*
908     * Subpictures
909     */
910
911    if (NULL != pViaSubPic) {
912	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort]
913	    != (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
914	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] =
915		pViaSubPic->srfNo | VIA_XVMC_VALID;
916	    viaVideoSubPictureLocked(pViaXvMC->xl, pViaSubPic);
917	}
918    } else {
919	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] & VIA_XVMC_VALID) {
920	    viaVideoSubPictureOffLocked(pViaXvMC->xl);
921	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
922	}
923    }
924
925    /*
926     * Flip
927     */
928
929    viaVideoSWFlipLocked(pViaXvMC->xl, flags,
930	pViaSurface->progressiveSequence);
931    flushXvMCLowLevel(pViaXvMC->xl);
932
933    setLowLevelLocking(pViaXvMC->xl, 1);
934    hwlUnlock(pViaXvMC->xl, 1);
935
936    if (overlayUpdated || !drawInfo->touched) {
937	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
938	return Success;
939    }
940
941    /*
942     * Update overlay
943     */
944
945    ret =
946	updateXVOverlay(display, pViaXvMC, pViaSurface, draw, srcx, srcy,
947	srcw, srch, destx, desty, destw, desth);
948    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
949    return ret;
950
951}
952
953void
954debugControl(const XvMCMpegControl * control)
955{
956    printf("BVMV_range: %u\n", control->BVMV_range);
957    printf("BHMV_range: %u\n", control->BHMV_range);
958    printf("FVMV_range: %u\n", control->FVMV_range);
959    printf("FHMV_range: %u\n", control->FHMV_range);
960    printf("picture_structure: %u\n", control->picture_structure);
961    printf("intra_dc_precision: %u\n", control->intra_dc_precision);
962    printf("picture_coding_type: %u\n", control->picture_coding_type);
963    printf("mpeg_coding: %u\n", control->mpeg_coding);
964    printf("flags: 0x%x\n", control->flags);
965}
966
967_X_EXPORT Status
968XvMCBeginSurface(Display * display,
969    XvMCContext * context,
970    XvMCSurface * target_surface,
971    XvMCSurface * past_surface,
972    XvMCSurface * future_surface, const XvMCMpegControl * control)
973{
974    ViaXvMCSurface *targS, *futS, *pastS;
975    ViaXvMCContext *pViaXvMC;
976    int hadDecoderLast;
977    CARD32 timeStamp;
978
979    if ((display == NULL) || (context == NULL) || (target_surface == NULL)) {
980	return BadValue;
981    }
982
983    pViaXvMC = context->privData;
984
985    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
986    if (grabDecoder(pViaXvMC, &hadDecoderLast)) {
987	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
988	return BadAlloc;
989    }
990    pViaXvMC->haveDecoder = 1;
991
992    /*
993     * We need to wait for decoder idle at next flush, since hardware doesn't queue
994     * beginsurface requests until the decoder is idle. This is
995     * done by waiting on the last previous timestamp, or if there was another context
996     * having the decoder before us, by emitting a new one.
997     */
998
999    if (pViaXvMC->useAGP) {
1000	if (!hadDecoderLast || pViaXvMC->timeStamp == 0) {
1001	    timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
1002	    if (flushXvMCLowLevel(pViaXvMC->xl)) {
1003		releaseDecoder(pViaXvMC, 0);
1004		ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1005		return BadAlloc;
1006	    }
1007	    pViaXvMC->timeStamp = timeStamp;
1008	} else {
1009	    timeStamp = pViaXvMC->timeStamp;
1010	}
1011	setAGPSyncLowLevel(pViaXvMC->xl, 1, timeStamp);
1012    }
1013
1014    if (!hadDecoderLast || !pViaXvMC->decoderOn) {
1015	pViaXvMC->intraLoaded = 0;
1016	pViaXvMC->nonIntraLoaded = 0;
1017    }
1018
1019    viaMpegReset(pViaXvMC->xl);
1020
1021    targS = (ViaXvMCSurface *) target_surface->privData;
1022    futS = NULL;
1023    pastS = NULL;
1024
1025    pViaXvMC->rendSurf[0] = targS->srfNo | VIA_XVMC_VALID;
1026    if (future_surface) {
1027	futS = (ViaXvMCSurface *) future_surface->privData;
1028	futS->needsSync = 0;
1029    }
1030    if (past_surface) {
1031	pastS = (ViaXvMCSurface *) past_surface->privData;
1032	pastS->needsSync = 0;
1033    }
1034
1035    targS->progressiveSequence = (control->flags & XVMC_PROGRESSIVE_SEQUENCE);
1036    targS->topFieldFirst = (control->flags & XVMC_TOP_FIELD_FIRST);
1037    targS->privSubPic = NULL;
1038
1039    viaMpegSetSurfaceStride(pViaXvMC->xl, pViaXvMC);
1040
1041    viaMpegSetFB(pViaXvMC->xl, 0, yOffs(targS), uOffs(targS), vOffs(targS));
1042    if (past_surface) {
1043	viaMpegSetFB(pViaXvMC->xl, 1, yOffs(pastS), uOffs(pastS),
1044	    vOffs(pastS));
1045    } else {
1046	viaMpegSetFB(pViaXvMC->xl, 1, 0, 0, 0);
1047    }
1048
1049    if (future_surface) {
1050	viaMpegSetFB(pViaXvMC->xl, 2, yOffs(futS), uOffs(futS), vOffs(futS));
1051    } else {
1052	viaMpegSetFB(pViaXvMC->xl, 2, 0, 0, 0);
1053    }
1054
1055    viaMpegBeginPicture(pViaXvMC->xl, pViaXvMC, context->width,
1056	context->height, control);
1057    flushPCIXvMCLowLevel(pViaXvMC->xl);
1058    targS->needsSync = 1;
1059    targS->syncMode = LL_MODE_DECODER_IDLE;
1060    pViaXvMC->decoderOn = 1;
1061    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1062    return Success;
1063}
1064
1065_X_EXPORT Status
1066XvMCSyncSurface(Display * display, XvMCSurface * surface)
1067{
1068    ViaXvMCSurface *pViaSurface;
1069    ViaXvMCContext *pViaXvMC;
1070    unsigned i;
1071
1072    if ((display == NULL) || (surface == NULL)) {
1073	return BadValue;
1074    }
1075    if (surface->privData == NULL) {
1076	return (error_base + XvMCBadSurface);
1077    }
1078
1079    pViaSurface = (ViaXvMCSurface *) surface->privData;
1080    pViaXvMC = pViaSurface->privContext;
1081
1082    if (pViaXvMC == NULL) {
1083	return (error_base + XvMCBadSurface);
1084    }
1085
1086    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1087
1088    if (pViaSurface->needsSync) {
1089	CARD32 timeStamp = pViaSurface->timeStamp;
1090	int syncMode = pViaSurface->syncMode;
1091
1092	if (pViaXvMC->useAGP) {
1093
1094	    syncMode = (pViaSurface->syncMode == LL_MODE_2D ||
1095		pViaSurface->timeStamp < pViaXvMC->timeStamp) ?
1096		LL_MODE_2D : LL_MODE_DECODER_IDLE;
1097	    if (pViaSurface->syncMode != LL_MODE_2D)
1098		timeStamp = pViaXvMC->timeStamp;
1099
1100	} else if (syncMode != LL_MODE_2D &&
1101	    pViaXvMC->rendSurf[0] != (pViaSurface->srfNo | VIA_XVMC_VALID)) {
1102
1103	    pViaSurface->needsSync = 0;
1104	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1105	    return Success;
1106	}
1107
1108	if (syncXvMCLowLevel(pViaXvMC->xl, syncMode, 1,
1109		pViaSurface->timeStamp)) {
1110	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1111	    return BadValue;
1112	}
1113	pViaSurface->needsSync = 0;
1114    }
1115
1116    if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
1117	pViaSurface->needsSync = 0;
1118	for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
1119	    pViaXvMC->rendSurf[i] = 0;
1120	}
1121    }
1122
1123    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1124    return Success;
1125}
1126
1127_X_EXPORT Status
1128XvMCLoadQMatrix(Display * display, XvMCContext * context,
1129    const XvMCQMatrix * qmx)
1130{
1131    ViaXvMCContext * pViaXvMC;
1132
1133    if ((display == NULL) || (context == NULL)) {
1134	return BadValue;
1135    }
1136    if (NULL == (pViaXvMC = context->privData)) {
1137	return (error_base + XvMCBadContext);
1138    }
1139
1140    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1141    if (qmx->load_intra_quantiser_matrix) {
1142	memcpy(pViaXvMC->intra_quantiser_matrix,
1143	    qmx->intra_quantiser_matrix, sizeof(qmx->intra_quantiser_matrix));
1144	pViaXvMC->intraLoaded = 0;
1145    }
1146
1147    if (qmx->load_non_intra_quantiser_matrix) {
1148	memcpy(pViaXvMC->non_intra_quantiser_matrix,
1149	    qmx->non_intra_quantiser_matrix,
1150	    sizeof(qmx->non_intra_quantiser_matrix));
1151	pViaXvMC->nonIntraLoaded = 0;
1152    }
1153
1154    if (qmx->load_chroma_intra_quantiser_matrix) {
1155	memcpy(pViaXvMC->chroma_intra_quantiser_matrix,
1156	    qmx->chroma_intra_quantiser_matrix,
1157	    sizeof(qmx->chroma_intra_quantiser_matrix));
1158	pViaXvMC->chromaIntraLoaded = 0;
1159    }
1160
1161    if (qmx->load_chroma_non_intra_quantiser_matrix) {
1162	memcpy(pViaXvMC->chroma_non_intra_quantiser_matrix,
1163	    qmx->chroma_non_intra_quantiser_matrix,
1164	    sizeof(qmx->chroma_non_intra_quantiser_matrix));
1165	pViaXvMC->chromaNonIntraLoaded = 0;
1166    }
1167    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1168
1169    return Success;
1170}
1171
1172/*
1173 * Below, we provide functions unusable for this implementation, but for
1174 * standard completeness.
1175 */
1176
1177_X_EXPORT Status XvMCRenderSurface
1178    (Display * display,
1179    XvMCContext * context,
1180    unsigned int picture_structure,
1181    XvMCSurface * target_surface,
1182    XvMCSurface * past_surface,
1183    XvMCSurface * future_surface,
1184    unsigned int flags,
1185    unsigned int num_macroblocks,
1186    unsigned int first_macroblock,
1187    XvMCMacroBlockArray * macroblock_array, XvMCBlockArray * blocks)
1188{
1189    return (error_base + XvMCBadContext);
1190}
1191
1192_X_EXPORT Status XvMCCreateBlocks
1193    (Display * display,
1194    XvMCContext * context, unsigned int num_blocks, XvMCBlockArray * block)
1195{
1196    return (error_base + XvMCBadContext);
1197}
1198
1199_X_EXPORT Status
1200XvMCDestroyBlocks(Display * display, XvMCBlockArray * block)
1201{
1202    return Success;
1203}
1204
1205_X_EXPORT Status XvMCCreateMacroBlocks
1206    (Display * display,
1207    XvMCContext * context,
1208    unsigned int num_blocks, XvMCMacroBlockArray * blocks)
1209{
1210    return (error_base + XvMCBadContext);
1211}
1212
1213_X_EXPORT Status
1214XvMCDestroyMacroBlocks(Display * display, XvMCMacroBlockArray * block)
1215{
1216    return (error_base + XvMCBadContext);
1217}
1218
1219_X_EXPORT Status
1220XvMCCreateSubpicture(Display * display,
1221    XvMCContext * context,
1222    XvMCSubpicture * subpicture,
1223    unsigned short width, unsigned short height, int xvimage_id)
1224{
1225    ViaXvMCContext *pViaXvMC;
1226    ViaXvMCSubPicture *pViaSubPic;
1227    int priv_count;
1228    unsigned *priv_data;
1229    Status ret;
1230
1231    if ((subpicture == NULL) || (context == NULL) || (display == NULL)) {
1232	return BadValue;
1233    }
1234
1235    pViaXvMC = (ViaXvMCContext *) context->privData;
1236    if (pViaXvMC == NULL) {
1237	return (error_base + XvMCBadContext);
1238    }
1239
1240    subpicture->privData = (ViaXvMCSubPicture *)
1241	malloc(sizeof(ViaXvMCSubPicture));
1242    if (!subpicture->privData) {
1243	return BadAlloc;
1244    }
1245
1246    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1247    subpicture->width = context->width;
1248    subpicture->height = context->height;
1249    subpicture->xvimage_id = xvimage_id;
1250    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
1251
1252    XLockDisplay(display);
1253    if ((ret = _xvmc_create_subpicture(display, context, subpicture,
1254		&priv_count, &priv_data))) {
1255	XUnlockDisplay(display);
1256	free(pViaSubPic);
1257	fprintf(stderr, "Unable to create XvMC Subpicture.\n");
1258	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1259	return ret;
1260    }
1261    XUnlockDisplay(display);
1262
1263    subpicture->num_palette_entries = VIA_SUBPIC_PALETTE_SIZE;
1264    subpicture->entry_bytes = 3;
1265    strncpy(subpicture->component_order, "YUV", 4);
1266    pViaSubPic->srfNo = priv_data[0];
1267    pViaSubPic->offset = priv_data[1];
1268    pViaSubPic->stride = (subpicture->width + 31) & ~31;
1269    pViaSubPic->privContext = pViaXvMC;
1270    pViaSubPic->ia44 = (xvimage_id == FOURCC_IA44);
1271    pViaSubPic->needsSync = 0;
1272
1273    /* Free data returned from _xvmc_create_subpicture */
1274
1275    XFree(priv_data);
1276    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1277    return Success;
1278}
1279
1280_X_EXPORT Status
1281XvMCSetSubpicturePalette(Display * display, XvMCSubpicture * subpicture,
1282    unsigned char *palette)
1283{
1284    ViaXvMCSubPicture *pViaSubPic;
1285    ViaXvMCContext *pViaXvMC;
1286    volatile ViaXvMCSAreaPriv *sAPriv;
1287    unsigned i;
1288    CARD32 tmp;
1289
1290    if ((subpicture == NULL) || (display == NULL)) {
1291	return BadValue;
1292    }
1293    if (subpicture->privData == NULL) {
1294	return (error_base + XvMCBadSubpicture);
1295    }
1296    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
1297    for (i = 0; i < VIA_SUBPIC_PALETTE_SIZE; ++i) {
1298	tmp = *palette++ << 8;
1299	tmp |= *palette++ << 16;
1300	tmp |= *palette++ << 24;
1301	tmp |= ((i & 0x0f) << 4) | 0x07;
1302	pViaSubPic->palette[i] = tmp;
1303    }
1304
1305    pViaXvMC = pViaSubPic->privContext;
1306    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1307    sAPriv = SAREAPTR(pViaXvMC);
1308    hwlLock(pViaXvMC->xl, 1);
1309    setLowLevelLocking(pViaXvMC->xl, 0);
1310
1311    /*
1312     * If the subpicture is displaying, Immeadiately update it with the
1313     * new palette.
1314     */
1315
1316    if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
1317	(pViaSubPic->srfNo | VIA_XVMC_VALID)) {
1318	viaVideoSubPictureLocked(pViaXvMC->xl, pViaSubPic);
1319    }
1320    flushPCIXvMCLowLevel(pViaXvMC->xl);
1321    setLowLevelLocking(pViaXvMC->xl, 1);
1322    hwlUnlock(pViaXvMC->xl, 1);
1323    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1324    return Success;
1325}
1326
1327static int
1328findOverlap(unsigned width, unsigned height,
1329    short *dstX, short *dstY,
1330    short *srcX, short *srcY, unsigned short *areaW, unsigned short *areaH)
1331{
1332    int w, h;
1333    unsigned mWidth, mHeight;
1334
1335    w = *areaW;
1336    h = *areaH;
1337
1338    if ((*dstX >= width) || (*dstY >= height))
1339	return 1;
1340    if (*dstX < 0) {
1341	w += *dstX;
1342	*srcX -= *dstX;
1343	*dstX = 0;
1344    }
1345    if (*dstY < 0) {
1346	h += *dstY;
1347	*srcY -= *dstY;
1348	*dstY = 0;
1349    }
1350    if ((w <= 0) || ((h <= 0)))
1351	return 1;
1352    mWidth = width - *dstX;
1353    mHeight = height - *dstY;
1354    *areaW = (w <= mWidth) ? w : mWidth;
1355    *areaH = (h <= mHeight) ? h : mHeight;
1356    return 0;
1357}
1358
1359_X_EXPORT Status
1360XvMCClearSubpicture(Display * display,
1361    XvMCSubpicture * subpicture,
1362    short x,
1363    short y, unsigned short width, unsigned short height, unsigned int color)
1364{
1365
1366    ViaXvMCContext *pViaXvMC;
1367    ViaXvMCSubPicture *pViaSubPic;
1368    short dummyX, dummyY;
1369    unsigned long bOffs;
1370
1371    if ((subpicture == NULL) || (display == NULL)) {
1372	return BadValue;
1373    }
1374    if (subpicture->privData == NULL) {
1375	return (error_base + XvMCBadSubpicture);
1376    }
1377    pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData;
1378    pViaXvMC = pViaSubPic->privContext;
1379    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1380
1381    /* Clip clearing area so that it fits inside subpicture. */
1382
1383    if (findOverlap(subpicture->width, subpicture->height, &x, &y,
1384	    &dummyX, &dummyY, &width, &height)) {
1385	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1386	return Success;
1387    }
1388
1389    bOffs = pViaSubPic->offset + y * pViaSubPic->stride + x;
1390    viaBlit(pViaXvMC->xl, 8, 0, pViaSubPic->stride, bOffs, pViaSubPic->stride,
1391	width, height, 1, 1, VIABLIT_FILL, color);
1392    pViaSubPic->needsSync = 1;
1393    pViaSubPic->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
1394    if (flushXvMCLowLevel(pViaXvMC->xl)) {
1395	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1396	return BadValue;
1397    }
1398    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1399    return Success;
1400}
1401
1402_X_EXPORT Status
1403XvMCCompositeSubpicture(Display * display,
1404    XvMCSubpicture * subpicture,
1405    XvImage * image,
1406    short srcx,
1407    short srcy,
1408    unsigned short width, unsigned short height, short dstx, short dsty)
1409{
1410
1411    unsigned i;
1412    ViaXvMCContext *pViaXvMC;
1413    ViaXvMCSubPicture *pViaSubPic;
1414    CARD8 *dAddr, *sAddr;
1415
1416    if ((subpicture == NULL) || (display == NULL) || (image == NULL)) {
1417	return BadValue;
1418    }
1419    if (NULL == (pViaSubPic = (ViaXvMCSubPicture *) subpicture->privData)) {
1420	return (error_base + XvMCBadSubpicture);
1421    }
1422
1423    pViaXvMC = pViaSubPic->privContext;
1424
1425    if (image->id != subpicture->xvimage_id)
1426	return BadMatch;
1427
1428    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1429
1430    /*
1431     * Clip copy area so that it fits inside subpicture and image.
1432     */
1433
1434    if (findOverlap(subpicture->width, subpicture->height,
1435	    &dstx, &dsty, &srcx, &srcy, &width, &height)) {
1436	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1437	return Success;
1438    }
1439    if (findOverlap(image->width, image->height,
1440	    &srcx, &srcy, &dstx, &dsty, &width, &height)) {
1441	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1442	return Success;
1443    }
1444
1445    if (pViaSubPic->needsSync) {
1446	if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D, 0,
1447		pViaSubPic->timeStamp)) {
1448	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1449	    return BadValue;
1450	}
1451	pViaSubPic->needsSync = 0;
1452    }
1453
1454    for (i = 0; i < height; ++i) {
1455	dAddr = (((CARD8 *) pViaXvMC->fbAddress) +
1456	    (pViaSubPic->offset + (dsty + i) * pViaSubPic->stride + dstx));
1457	sAddr = (((CARD8 *) image->data) +
1458	    (image->offsets[0] + (srcy + i) * image->pitches[0] + srcx));
1459	memcpy(dAddr, sAddr, width);
1460    }
1461
1462    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1463    return Success;
1464}
1465
1466_X_EXPORT Status
1467XvMCBlendSubpicture(Display * display,
1468    XvMCSurface * target_surface,
1469    XvMCSubpicture * subpicture,
1470    short subx,
1471    short suby,
1472    unsigned short subw,
1473    unsigned short subh,
1474    short surfx, short surfy, unsigned short surfw, unsigned short surfh)
1475{
1476    ViaXvMCSurface *pViaSurface;
1477    ViaXvMCSubPicture *pViaSubPic;
1478
1479    if ((display == NULL) || target_surface == NULL) {
1480	return BadValue;
1481    }
1482
1483    if (subx || suby || surfx || surfy || (subw != surfw) || (subh != surfh)) {
1484	fprintf(stderr, "ViaXvMC: Only completely overlapping subpicture "
1485	    "supported.\n");
1486	return BadValue;
1487    }
1488
1489    if (NULL == (pViaSurface = target_surface->privData)) {
1490	return (error_base + XvMCBadSurface);
1491    }
1492
1493    if (subpicture) {
1494
1495	if (NULL == (pViaSubPic = subpicture->privData)) {
1496	    return (error_base + XvMCBadSubpicture);
1497	}
1498
1499	pViaSurface->privSubPic = pViaSubPic;
1500    } else {
1501	pViaSurface->privSubPic = NULL;
1502    }
1503    return Success;
1504}
1505
1506_X_EXPORT Status
1507XvMCBlendSubpicture2(Display * display,
1508    XvMCSurface * source_surface,
1509    XvMCSurface * target_surface,
1510    XvMCSubpicture * subpicture,
1511    short subx,
1512    short suby,
1513    unsigned short subw,
1514    unsigned short subh,
1515    short surfx, short surfy, unsigned short surfw, unsigned short surfh)
1516{
1517    ViaXvMCSurface *pViaSurface, *pViaSSurface;
1518    ViaXvMCSubPicture *pViaSubPic;
1519    ViaXvMCContext *pViaXvMC;
1520
1521    unsigned width, height;
1522
1523    if ((display == NULL) || target_surface == NULL || source_surface == NULL) {
1524	return BadValue;
1525    }
1526
1527    if (subx || suby || surfx || surfy || (subw != surfw) || (subh != surfh)) {
1528	fprintf(stderr, "ViaXvMC: Only completely overlapping subpicture "
1529	    "supported.\n");
1530	return BadMatch;
1531    }
1532
1533    if (NULL == (pViaSurface = target_surface->privData)) {
1534	return (error_base + XvMCBadSurface);
1535    }
1536
1537    if (NULL == (pViaSSurface = source_surface->privData)) {
1538	return (error_base + XvMCBadSurface);
1539    }
1540    pViaXvMC = pViaSurface->privContext;
1541    width = pViaSSurface->width;
1542    height = pViaSSurface->height;
1543    if (width != pViaSurface->width || height != pViaSSurface->height) {
1544	return BadMatch;
1545    }
1546
1547    if (XvMCSyncSurface(display, source_surface)) {
1548	return BadValue;
1549    }
1550
1551    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1552    viaBlit(pViaXvMC->xl, 8, yOffs(pViaSSurface), pViaSSurface->yStride,
1553	yOffs(pViaSurface), pViaSurface->yStride,
1554	width, height, 1, 1, VIABLIT_COPY, 0);
1555    flushPCIXvMCLowLevel(pViaXvMC->xl);
1556    if (pViaXvMC->chipId != PCI_CHIP_VT3259) {
1557
1558	/*
1559	 * YV12 Chroma blit.
1560	 */
1561
1562	viaBlit(pViaXvMC->xl, 8, uOffs(pViaSSurface),
1563	    pViaSSurface->yStride >> 1, uOffs(pViaSurface),
1564	    pViaSurface->yStride >> 1, width >> 1, height >> 1, 1, 1,
1565	    VIABLIT_COPY, 0);
1566	flushPCIXvMCLowLevel(pViaXvMC->xl);
1567	viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface),
1568	    pViaSSurface->yStride >> 1, vOffs(pViaSurface),
1569	    pViaSurface->yStride >> 1, width >> 1, height >> 1, 1, 1,
1570	    VIABLIT_COPY, 0);
1571    } else {
1572
1573	/*
1574	 * NV12 Chroma blit.
1575	 */
1576
1577	viaBlit(pViaXvMC->xl, 8, vOffs(pViaSSurface), pViaSSurface->yStride,
1578	    vOffs(pViaSurface), pViaSurface->yStride,
1579	    width, height >> 1, 1, 1, VIABLIT_COPY, 0);
1580    }
1581    pViaSurface->needsSync = 1;
1582    pViaSurface->syncMode = LL_MODE_2D;
1583    pViaSurface->timeStamp = viaDMATimeStampLowLevel(pViaXvMC->xl);
1584    if (flushXvMCLowLevel(pViaXvMC->xl)) {
1585	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1586	return BadValue;
1587    }
1588    if (subpicture) {
1589
1590	if (NULL == (pViaSubPic = subpicture->privData)) {
1591	    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1592	    return (error_base + XvMCBadSubpicture);
1593	}
1594
1595	pViaSurface->privSubPic = pViaSubPic;
1596    } else {
1597	pViaSurface->privSubPic = NULL;
1598    }
1599    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1600    return Success;
1601}
1602
1603_X_EXPORT Status
1604XvMCSyncSubpicture(Display * display, XvMCSubpicture * subpicture)
1605{
1606    ViaXvMCSubPicture *pViaSubPic;
1607    ViaXvMCContext *pViaXvMC;
1608    Status retVal = 0;
1609
1610    if ((display == NULL) || subpicture == NULL) {
1611	return BadValue;
1612    }
1613    if (NULL == (pViaSubPic = subpicture->privData)) {
1614	return (error_base + XvMCBadSubpicture);
1615    }
1616
1617    pViaXvMC = pViaSubPic->privContext;
1618    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1619    if (pViaSubPic->needsSync) {
1620	if (syncXvMCLowLevel(pViaXvMC->xl, LL_MODE_2D,
1621		0, pViaSubPic->timeStamp)) {
1622	    retVal = BadValue;
1623	}
1624	pViaSubPic->needsSync = 0;
1625    }
1626    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1627    return retVal;
1628}
1629
1630_X_EXPORT Status
1631XvMCFlushSubpicture(Display * display, XvMCSubpicture * subpicture)
1632{
1633    ViaXvMCSubPicture *pViaSubPic;
1634
1635    if ((display == NULL) || subpicture == NULL) {
1636	return BadValue;
1637    }
1638    if (NULL == (pViaSubPic = subpicture->privData)) {
1639	return (error_base + XvMCBadSubpicture);
1640    }
1641
1642    return Success;
1643}
1644
1645_X_EXPORT Status
1646XvMCDestroySubpicture(Display * display, XvMCSubpicture * subpicture)
1647{
1648    ViaXvMCSubPicture *pViaSubPic;
1649    ViaXvMCContext *pViaXvMC;
1650    volatile ViaXvMCSAreaPriv *sAPriv;
1651
1652    if ((display == NULL) || subpicture == NULL) {
1653	return BadValue;
1654    }
1655    if (NULL == (pViaSubPic = subpicture->privData)) {
1656	return (error_base + XvMCBadSubpicture);
1657    }
1658    pViaXvMC = pViaSubPic->privContext;
1659    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1660
1661    sAPriv = SAREAPTR(pViaXvMC);
1662    hwlLock(pViaXvMC->xl, 1);
1663    setLowLevelLocking(pViaXvMC->xl, 0);
1664    if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
1665	(pViaSubPic->srfNo | VIA_XVMC_VALID)) {
1666	viaVideoSubPictureOffLocked(pViaXvMC->xl);
1667	sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] = 0;
1668    }
1669    flushPCIXvMCLowLevel(pViaXvMC->xl);
1670    setLowLevelLocking(pViaXvMC->xl, 1);
1671    hwlUnlock(pViaXvMC->xl, 1);
1672
1673    XLockDisplay(display);
1674    _xvmc_destroy_subpicture(display, subpicture);
1675    XUnlockDisplay(display);
1676
1677    free(pViaSubPic);
1678    subpicture->privData = NULL;
1679    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1680
1681    return Success;
1682}
1683
1684_X_EXPORT Status
1685XvMCGetSubpictureStatus(Display * display, XvMCSubpicture * subpic, int *stat)
1686{
1687    ViaXvMCSubPicture *pViaSubPic;
1688    ViaXvMCContext *pViaXvMC;
1689    volatile ViaXvMCSAreaPriv *sAPriv;
1690
1691    if ((display == NULL) || subpic == NULL) {
1692	return BadValue;
1693    }
1694    if (NULL == (pViaSubPic = subpic->privData)) {
1695	return (error_base + XvMCBadSubpicture);
1696    }
1697    if (stat) {
1698	*stat = 0;
1699	pViaXvMC = pViaSubPic->privContext;
1700	sAPriv = SAREAPTR(pViaXvMC);
1701	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
1702	    (pViaSubPic->srfNo | VIA_XVMC_VALID))
1703	    *stat |= XVMC_DISPLAYING;
1704    }
1705    return Success;
1706}
1707
1708_X_EXPORT Status
1709XvMCFlushSurface(Display * display, XvMCSurface * surface)
1710{
1711    ViaXvMCSurface *pViaSurface;
1712    ViaXvMCContext *pViaXvMC;
1713    Status ret;
1714
1715    if ((display == NULL) || surface == NULL) {
1716	return BadValue;
1717    }
1718    if (NULL == (pViaSurface = surface->privData)) {
1719	return (error_base + XvMCBadSurface);
1720    }
1721
1722    pViaXvMC = pViaSurface->privContext;
1723    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1724    if (pViaSurface->needsSync)
1725	pViaSurface->timeStamp = pViaXvMC->timeStamp =
1726	    viaDMATimeStampLowLevel(pViaXvMC->xl);
1727    ret = (flushXvMCLowLevel(pViaXvMC->xl)) ? BadValue : Success;
1728    if (pViaXvMC->rendSurf[0] == (pViaSurface->srfNo | VIA_XVMC_VALID)) {
1729	hwlLock(pViaXvMC->xl, 0);
1730	pViaXvMC->haveDecoder = 0;
1731	releaseDecoder(pViaXvMC, 0);
1732	hwlUnlock(pViaXvMC->xl, 0);
1733    }
1734    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1735    return ret;
1736}
1737
1738_X_EXPORT Status
1739XvMCGetSurfaceStatus(Display * display, XvMCSurface * surface, int *stat)
1740{
1741    ViaXvMCSurface *pViaSurface;
1742    ViaXvMCContext *pViaXvMC;
1743    volatile ViaXvMCSAreaPriv *sAPriv;
1744    unsigned i;
1745    int ret = 0;
1746
1747    if ((display == NULL) || surface == NULL) {
1748	return BadValue;
1749    }
1750    if (NULL == (pViaSurface = surface->privData)) {
1751	return (error_base + XvMCBadSurface);
1752    }
1753    if (stat) {
1754	*stat = 0;
1755	pViaXvMC = pViaSurface->privContext;
1756	ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1757	sAPriv = SAREAPTR(pViaXvMC);
1758	if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort]
1759	    == (pViaSurface->srfNo | VIA_XVMC_VALID))
1760	    *stat |= XVMC_DISPLAYING;
1761	for (i = 0; i < VIA_MAX_RENDSURF; ++i) {
1762	    if (pViaXvMC->rendSurf[i] ==
1763		(pViaSurface->srfNo | VIA_XVMC_VALID)) {
1764		*stat |= XVMC_RENDERING;
1765		break;
1766	    }
1767	}
1768	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1769    }
1770    return ret;
1771}
1772
1773_X_EXPORT XvAttribute *
1774XvMCQueryAttributes(Display * display, XvMCContext * context, int *number)
1775{
1776    ViaXvMCContext *pViaXvMC;
1777    XvAttribute *ret;
1778    unsigned long siz;
1779
1780    *number = 0;
1781    if ((display == NULL) || (context == NULL)) {
1782	return NULL;
1783    }
1784
1785    if (NULL == (pViaXvMC = context->privData)) {
1786	return NULL;
1787    }
1788
1789    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1790    if (NULL != (ret = (XvAttribute *)
1791	    malloc(siz = VIA_NUM_XVMC_ATTRIBUTES * sizeof(XvAttribute)))) {
1792	memcpy(ret, pViaXvMC->attribDesc, siz);
1793	*number = VIA_NUM_XVMC_ATTRIBUTES;
1794    }
1795    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1796
1797    return ret;
1798}
1799
1800_X_EXPORT Status
1801XvMCSetAttribute(Display * display,
1802    XvMCContext * context, Atom attribute, int value)
1803{
1804    int found;
1805    unsigned i;
1806    ViaXvMCContext *pViaXvMC;
1807    ViaXvMCCommandBuffer buf;
1808
1809    if ((display == NULL) || (context == NULL)) {
1810	return (error_base + XvMCBadContext);
1811    }
1812
1813    if (NULL == (pViaXvMC = context->privData)) {
1814	return (error_base + XvMCBadContext);
1815    }
1816
1817    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1818
1819    found = 0;
1820    for (i = 0; i < pViaXvMC->attrib.numAttr; ++i) {
1821	if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
1822	    if ((!(pViaXvMC->attribDesc[i].flags & XvSettable)) ||
1823		value < pViaXvMC->attribDesc[i].min_value ||
1824		value > pViaXvMC->attribDesc[i].max_value) {
1825		ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1826		return BadValue;
1827	    }
1828	    pViaXvMC->attrib.attributes[i].value = value;
1829	    found = 1;
1830	    pViaXvMC->attribChanged = 1;
1831	    break;
1832	}
1833    }
1834    if (!found) {
1835	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1836	return BadMatch;
1837    }
1838    if (pViaXvMC->haveXv) {
1839	buf.command = VIA_XVMC_COMMAND_ATTRIBUTES;
1840	pViaXvMC->xvImage->data = (char *)&buf;
1841	buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
1842	buf.attrib = pViaXvMC->attrib;
1843	XLockDisplay(display);
1844	pViaXvMC->attribChanged =
1845	    XvPutImage(display, pViaXvMC->port, pViaXvMC->draw,
1846	    pViaXvMC->gc, pViaXvMC->xvImage, 0, 0, 1, 1, 0, 0, 1, 1);
1847	XUnlockDisplay(display);
1848    }
1849    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1850    return Success;
1851}
1852
1853_X_EXPORT Status
1854XvMCGetAttribute(Display * display,
1855    XvMCContext * context, Atom attribute, int *value)
1856{
1857    int found;
1858    unsigned i;
1859    ViaXvMCContext *pViaXvMC;
1860
1861    if ((display == NULL) || (context == NULL)) {
1862	return (error_base + XvMCBadContext);
1863    }
1864
1865    if (NULL == (pViaXvMC = context->privData)) {
1866	return (error_base + XvMCBadContext);
1867    }
1868
1869    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1870    found = 0;
1871    for (i = 0; i < pViaXvMC->attrib.numAttr; ++i) {
1872	if (attribute == pViaXvMC->attrib.attributes[i].attribute) {
1873	    if (pViaXvMC->attribDesc[i].flags & XvGettable) {
1874		*value = pViaXvMC->attrib.attributes[i].value;
1875		found = 1;
1876		break;
1877	    }
1878	}
1879    }
1880    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1881
1882    if (!found)
1883	return BadMatch;
1884    return Success;
1885}
1886
1887_X_EXPORT Status
1888XvMCHideSurface(Display * display, XvMCSurface * surface)
1889{
1890
1891    ViaXvMCSurface *pViaSurface;
1892    ViaXvMCContext *pViaXvMC;
1893    ViaXvMCSubPicture *pViaSubPic;
1894    volatile ViaXvMCSAreaPriv *sAPriv;
1895    ViaXvMCCommandBuffer buf;
1896    Status ret;
1897
1898    if ((display == NULL) || (surface == NULL)) {
1899	return BadValue;
1900    }
1901    if (NULL == (pViaSurface = surface->privData)) {
1902	return (error_base + XvMCBadSurface);
1903    }
1904    if (NULL == (pViaXvMC = pViaSurface->privContext)) {
1905	return (error_base + XvMCBadContext);
1906    }
1907
1908    ppthread_mutex_lock(&pViaXvMC->ctxMutex);
1909    if (!pViaXvMC->haveXv) {
1910	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1911	return Success;
1912    }
1913
1914    sAPriv = SAREAPTR(pViaXvMC);
1915    hwlLock(pViaXvMC->xl, 1);
1916
1917    if (sAPriv->XvMCDisplaying[pViaXvMC->xvMCPort] !=
1918	(pViaSurface->srfNo | VIA_XVMC_VALID)) {
1919	hwlUnlock(pViaXvMC->xl, 1);
1920	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1921	return Success;
1922    }
1923    setLowLevelLocking(pViaXvMC->xl, 0);
1924    if (NULL != (pViaSubPic = pViaSurface->privSubPic)) {
1925	if (sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] ==
1926	    (pViaSubPic->srfNo | VIA_XVMC_VALID)) {
1927	    sAPriv->XvMCSubPicOn[pViaXvMC->xvMCPort] &= ~VIA_XVMC_VALID;
1928	    viaVideoSubPictureOffLocked(pViaXvMC->xl);
1929	}
1930    }
1931    flushPCIXvMCLowLevel(pViaXvMC->xl);
1932    setLowLevelLocking(pViaXvMC->xl, 1);
1933    hwlUnlock(pViaXvMC->xl, 1);
1934
1935    buf.command = VIA_XVMC_COMMAND_UNDISPLAY;
1936    buf.ctxNo = pViaXvMC->ctxNo | VIA_XVMC_VALID;
1937    buf.srfNo = pViaSurface->srfNo | VIA_XVMC_VALID;
1938    pViaXvMC->xvImage->data = (char *)&buf;
1939    if ((ret = XvPutImage(display, pViaXvMC->port, pViaXvMC->draw,
1940		pViaXvMC->gc, pViaXvMC->xvImage, 0, 0, 1, 1, 0, 0, 1, 1))) {
1941	fprintf(stderr, "XvMCPutSurface: Hiding overlay failed.\n");
1942	ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1943	return ret;
1944    }
1945    ppthread_mutex_unlock(&pViaXvMC->ctxMutex);
1946    return Success;
1947}
1948