1/*
2 * Copyright (c) 2004 The Unichrome Project. All rights reserved.
3 * Copyright (c) 2000 Intel Corporation. All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "xf86.h"
29#include "xf86_OSproc.h"
30
31#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
32#include "xf86Resources.h"
33#endif
34
35#include "compiler.h"
36#include "xf86Pci.h"
37#include "regionstr.h"
38
39#ifdef HAVE_DRI
40
41#include "via_drmclient.h"
42#include "via_drm.h"
43#include "via_dri.h"
44#include "via_driver.h"
45
46#include "xf86xv.h"
47#include "fourcc.h"
48
49#if defined(X_NEED_XVPRIV_H) || defined (_XF86_FOURCC_H_)
50#include "xf86xvpriv.h"
51#endif
52
53#include "xf86xvmc.h"
54#include <X11/extensions/Xv.h>
55#include <X11/extensions/XvMC.h>
56#include "dixstruct.h"
57#include "via_xvmc.h"
58#include "dristruct.h"
59#include "dri.h"
60#include "via_xvpriv.h"
61#include "via_xv.h"
62
63#define MAKE_ATOM(a) MakeAtom(a, strlen(a), TRUE)
64
65
66/*
67 * List of attributes for the XvMC extension to handle.
68 * As long as the attribute is supported by the Xv adaptor, it needs only
69 * to be added here to be supported also by XvMC.
70 * Currently, only colorkey seems to be supported by Xv for Putimage.
71 */
72static char *attrXvMC[VIA_NUM_XVMC_ATTRIBUTES] = { "XV_COLORKEY",
73    "XV_AUTOPAINT_COLORKEY",
74    "XV_BRIGHTNESS",
75    "XV_CONTRAST",
76    "XV_SATURATION",
77    "XV_HUE"
78};
79static Atom attrAtoms[VIA_NUM_XVMC_ATTRIBUTES];
80
81/*
82 * Xv Port private structure for XvMC.
83 */
84typedef struct
85{
86    unsigned ctxDisplaying;
87    int xvmc_port;
88    ViaXvMCAttrHolder xvAttr;
89    int newAttribute;
90
91    SetPortAttributeFuncPtr SetPortAttribute;
92    GetPortAttributeFuncPtr GetPortAttribute;
93    PutImageFuncPtr PutImage;
94} ViaXvMCXVPriv;
95
96/* Proposed XvMC VIA driver extension. */
97#define XVMC_VLD 0x0020000
98
99
100/* Function declarations. */
101static int ViaXvMCCreateContext(ScrnInfoPtr pScrn, XvMCContextPtr pContext,
102                                int *num_priv, INT32 ** priv);
103static void ViaXvMCDestroyContext(ScrnInfoPtr pScrn, XvMCContextPtr pContext);
104static int ViaXvMCCreateSurface(ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf,
105                                int *num_priv, INT32 ** priv);
106static void ViaXvMCDestroySurface(ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf);
107static int ViaXvMCCreateSubpicture(ScrnInfoPtr pScrn, XvMCSubpicturePtr pSurf,
108                                   int *num_priv, INT32 ** priv);
109static void ViaXvMCDestroySubpicture(ScrnInfoPtr pScrn,
110                                     XvMCSubpicturePtr pSubp);
111static int viaXvMCInterceptXvAttribute(ScrnInfoPtr pScrn, Atom attribute,
112                                       INT32 value, pointer data);
113static int viaXvMCInterceptPutImage(ScrnInfoPtr, short, short, short, short,
114                                    short, short, short, short, int,
115                                    unsigned char *, short, short, Bool,
116                                    RegionPtr, pointer, DrawablePtr);
117static int viaXvMCInterceptXvGetAttribute(ScrnInfoPtr pScrn, Atom attribute,
118                                          INT32 * value, pointer data);
119
120
121/*
122 * Initialize and clean up the screen private parts of XvMC.
123 */
124static void
125initViaXvMC(ViaXvMCPtr vXvMC)
126{
127    unsigned i;
128
129    for (i = 0; i < VIA_XVMC_MAX_CONTEXTS; ++i) {
130        vXvMC->contexts[i] = 0;
131        vXvMC->cPrivs[i] = 0;
132    }
133
134    for (i = 0; i < VIA_XVMC_MAX_SURFACES; ++i) {
135        vXvMC->surfaces[i] = 0;
136        vXvMC->sPrivs[i] = 0;
137    }
138}
139
140static void
141cleanupViaXvMC(ViaXvMCPtr vXvMC, XF86VideoAdaptorPtr * XvAdaptors,
142               int XvAdaptorCount)
143{
144    unsigned i;
145
146    for (i = 0; i < VIA_XVMC_MAX_CONTEXTS; ++i) {
147        vXvMC->contexts[i] = 0;
148        if (vXvMC->cPrivs[i]) {
149            free(vXvMC->cPrivs[i]);
150            vXvMC->cPrivs[i] = 0;
151        }
152    }
153
154    for (i = 0; i < VIA_XVMC_MAX_SURFACES; ++i) {
155        vXvMC->surfaces[i] = 0;
156        if (vXvMC->sPrivs[i]) {
157            free(vXvMC->sPrivs[i]);
158            vXvMC->sPrivs[i] = 0;
159        }
160    }
161}
162
163static unsigned
164stride(int w)
165{
166    return (w + 31) & ~31;
167}
168
169static unsigned long
170size_yuv420(int w, int h)
171{
172    unsigned yPitch = stride(w);
173
174    return h * (yPitch + (yPitch >> 1));
175}
176
177static unsigned long
178size_xx44(int w, int h)
179{
180    return h * stride(w);
181}
182
183
184static int yv12_subpicture_index_list[2] = {
185    FOURCC_IA44,
186    FOURCC_AI44
187};
188
189static XF86MCImageIDList yv12_subpicture_list = {
190    2,
191    yv12_subpicture_index_list
192};
193
194static XF86MCSurfaceInfoRec Via_YV12_mpg2_surface = {
195    FOURCC_YV12,
196    XVMC_CHROMA_FORMAT_420,
197    0,
198    1024,
199    1024,
200    1024,
201    1024,
202    XVMC_MPEG_2 | XVMC_VLD,
203    XVMC_OVERLAID_SURFACE | XVMC_BACKEND_SUBPICTURE,
204    &yv12_subpicture_list
205};
206
207static XF86MCSurfaceInfoRec Via_pga_mpg2_surface = {
208    FOURCC_YV12,
209    XVMC_CHROMA_FORMAT_420,
210    0,
211    2048,
212    2048,
213    2048,
214    2048,
215    XVMC_MPEG_2 | XVMC_VLD,
216    XVMC_OVERLAID_SURFACE | XVMC_BACKEND_SUBPICTURE,
217    &yv12_subpicture_list
218};
219
220static XF86MCSurfaceInfoRec Via_YV12_mpg1_surface = {
221    FOURCC_YV12,
222    XVMC_CHROMA_FORMAT_420,
223    0,
224    1024,
225    1024,
226    1024,
227    1024,
228    XVMC_MPEG_1 | XVMC_VLD,
229    XVMC_OVERLAID_SURFACE | XVMC_BACKEND_SUBPICTURE,
230    &yv12_subpicture_list
231};
232
233static XF86MCSurfaceInfoRec Via_pga_mpg1_surface = {
234    FOURCC_YV12,
235    XVMC_CHROMA_FORMAT_420,
236    0,
237    2048,
238    2048,
239    2048,
240    2048,
241    XVMC_MPEG_1 | XVMC_VLD,
242    XVMC_OVERLAID_SURFACE | XVMC_BACKEND_SUBPICTURE,
243    &yv12_subpicture_list
244};
245
246static XF86MCSurfaceInfoPtr ppSI[2] = {
247    (XF86MCSurfaceInfoPtr) & Via_YV12_mpg2_surface,
248    (XF86MCSurfaceInfoPtr) & Via_YV12_mpg1_surface
249};
250
251static XF86MCSurfaceInfoPtr ppSI_pga[2] = {
252    (XF86MCSurfaceInfoPtr) & Via_pga_mpg2_surface,
253    (XF86MCSurfaceInfoPtr) & Via_pga_mpg1_surface
254};
255
256/* List of supported subpicture types. */
257static XF86ImageRec ia44_subpicture = XVIMAGE_IA44;
258static XF86ImageRec ai44_subpicture = XVIMAGE_AI44;
259
260static XF86ImagePtr Via_subpicture_list[2] = {
261    (XF86ImagePtr) & ia44_subpicture,
262    (XF86ImagePtr) & ai44_subpicture
263};
264
265/*
266 * Filling in the device dependent adaptor record.
267 * This is named "VIA Video Overlay" because this code falls under the
268 * XV extension, the name must match or it won't be used.
269 *
270 * For surface and subpicture, see above.
271 * The function pointers point to functions below.
272 */
273static XF86MCAdaptorRec pAdapt = {
274    "XV_SWOV",            /* name */
275    2,                    /* num_surfaces */
276    ppSI,                 /* surfaces */
277    2,                    /* num_subpictures */
278    Via_subpicture_list,  /* subpictures */
279    (xf86XvMCCreateContextProcPtr) ViaXvMCCreateContext,
280    (xf86XvMCDestroyContextProcPtr) ViaXvMCDestroyContext,
281    (xf86XvMCCreateSurfaceProcPtr) ViaXvMCCreateSurface,
282    (xf86XvMCDestroySurfaceProcPtr) ViaXvMCDestroySurface,
283    (xf86XvMCCreateSubpictureProcPtr) ViaXvMCCreateSubpicture,
284    (xf86XvMCDestroySubpictureProcPtr) ViaXvMCDestroySubpicture
285};
286
287static XF86MCAdaptorRec pAdapt_pga = {
288    "XV_SWOV",            /* name */
289    2,                    /* num_surfaces */
290    ppSI_pga,             /* surfaces */
291    2,                    /* num_subpictures */
292    Via_subpicture_list,  /* subpictures */
293    (xf86XvMCCreateContextProcPtr) ViaXvMCCreateContext,
294    (xf86XvMCDestroyContextProcPtr) ViaXvMCDestroyContext,
295    (xf86XvMCCreateSurfaceProcPtr) ViaXvMCCreateSurface,
296    (xf86XvMCDestroySurfaceProcPtr) ViaXvMCDestroySurface,
297    (xf86XvMCCreateSubpictureProcPtr) ViaXvMCCreateSubpicture,
298    (xf86XvMCDestroySubpictureProcPtr) ViaXvMCDestroySubpicture
299};
300
301static XF86MCAdaptorPtr ppAdapt[1] = { (XF86MCAdaptorPtr) & pAdapt };
302static XF86MCAdaptorPtr ppAdapt_pga[1] = { (XF86MCAdaptorPtr) & pAdapt_pga };
303
304
305static void
306mpegDisable(VIAPtr pVia, CARD32 val)
307{
308    MPGOutD(0x0c, MPGInD(0x0c) & (val ^ 0xffffffff));
309}
310
311void
312ViaInitXVMC(ScreenPtr pScreen)
313{
314    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
315    VIAPtr pVia = VIAPTR(pScrn);
316    ViaXvMCPtr vXvMC = &(pVia->xvmc);
317    volatile ViaXvMCSAreaPriv *saPriv;
318
319    pVia->XvMCEnabled = 0;
320
321    if ((pVia->Chipset == VIA_KM400) ||
322        (pVia->Chipset == VIA_CX700) ||
323        (pVia->Chipset == VIA_K8M890) ||
324        (pVia->Chipset == VIA_P4M900) ||
325        (pVia->Chipset == VIA_VX800) ||
326        (pVia->Chipset == VIA_VX855) ||
327        (pVia->Chipset == VIA_VX900)) {
328        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
329                   "[XvMC] XvMC is not supported on this chipset.\n");
330        return;
331    }
332
333    if (!pVia->directRenderingType) {
334        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
335                   "[XvMC] Cannot use XvMC without DRI!\n");
336        return;
337    }
338
339    if (((pVia->drmVerMajor <= 2) && (pVia->drmVerMinor < 4))) {
340        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
341                   "[XvMC] Kernel drm is not compatible with XvMC.\n");
342        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
343                   "[XvMC] Kernel drm version is %d.%d.%d; "
344                   "at least version 2.4.0 is needed.\n",
345                   pVia->drmVerMajor, pVia->drmVerMinor, pVia->drmVerPL);
346        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
347                   "[XvMC] Please update. Disabling XvMC.\n");
348        return;
349    }
350
351    vXvMC->mmioBase = pVia->registerHandle;
352
353    if (drmAddMap(pVia->drmmode.fd,
354                  (drm_handle_t) pVia->FrameBufferBase,
355                  pVia->videoRambytes, DRM_FRAME_BUFFER, 0,
356                  &(vXvMC->fbBase)) < 0) {
357        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
358                   "[XvMC] drmAddMap(FB) failed. Disabling XvMC.\n");
359        return;
360    }
361
362    initViaXvMC(vXvMC);
363
364    if (!xf86XvMCScreenInit(pScreen, 1, ((pVia->Chipset == VIA_PM800)
365                                         ? ppAdapt_pga : ppAdapt))) {
366        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
367                   "[XvMC] XvMCScreenInit failed. Disabling XvMC.\n");
368        drmRmMap(pVia->drmmode.fd, vXvMC->fbBase);
369        return;
370    }
371#if (XvMCVersion > 1) || (XvMCRevision > 0)
372    {
373        DRIInfoPtr pDRIInfo = pVia->pDRIInfo;
374
375        if (pVia->ChipId != PCI_CHIP_VT3259 &&
376            pVia->ChipId != PCI_CHIP_VT3364) {
377            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
378                       "[XvMC] Registering chromeXvMC.\n");
379            xf86XvMCRegisterDRInfo(pScreen, "chromeXvMC", pDRIInfo->busIdString,
380                                   VIAXVMC_MAJOR, VIAXVMC_MINOR, VIAXVMC_PL);
381        } else {
382            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
383                       "[XvMC] Registering chromeXvMCPro.\n");
384            xf86XvMCRegisterDRInfo(pScreen, "chromeXvMCPro",
385                                   pDRIInfo->busIdString, VIAXVMC_MAJOR,
386                                   VIAXVMC_MINOR, VIAXVMC_PL);
387        }
388    }
389#endif
390
391    vXvMC->activePorts = 0;
392    saPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScreen);
393    saPriv->XvMCCtxNoGrabbed = ~0;
394
395    XVMCLOCKPTR(saPriv, UNICHROME_LOCK_DECODER1)->lock = 0;
396
397    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
398               "[XvMC] Initialized XvMC extension.\n");
399    pVia->XvMCEnabled = 1;
400}
401
402void
403ViaCleanupXVMC(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr * XvAdaptors,
404               int XvAdaptorCount)
405{
406    VIAPtr pVia = VIAPTR(pScrn);
407    ViaXvMCPtr vXvMC = &(pVia->xvmc);
408    int i, j;
409
410    if (pVia->XvMCEnabled) {
411        mpegDisable(pVia, 0);
412        drmRmMap(pVia->drmmode.fd, vXvMC->mmioBase);
413        cleanupViaXvMC(vXvMC, XvAdaptors, XvAdaptorCount);
414    }
415    for (i = 0; i < XvAdaptorCount; ++i) {
416        if (!XvAdaptors[i])
417            continue;
418
419        for (j = 0; j < XvAdaptors[i]->nPorts; ++j) {
420            viaPortPrivPtr pPriv = XvAdaptors[i]->pPortPrivates[j].ptr;
421
422            if (pPriv->xvmc_priv)
423                free(pPriv->xvmc_priv);
424        }
425    }
426    pVia->XvMCEnabled = 0;
427}
428
429static int
430ViaXvMCCreateContext(ScrnInfoPtr pScrn, XvMCContextPtr pContext,
431                     int *num_priv, INT32 ** priv)
432{
433    VIAPtr pVia = VIAPTR(pScrn);
434    ViaXvMCPtr vXvMC = &(pVia->xvmc);
435    DRIInfoPtr pDRIInfo = pVia->pDRIInfo;
436    VIADRIPtr pViaDRI = pDRIInfo->devPrivate;
437    ViaXvMCCreateContextRec *contextRec;
438    unsigned ctxNo;
439    ViaXvMCContextPriv *cPriv;
440    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) pContext->port_priv;
441    viaPortPrivPtr pPriv = (viaPortPrivPtr) portPriv->DevPriv.ptr;
442    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
443    volatile ViaXvMCSAreaPriv *sAPriv;
444
445    sAPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScrn->pScreen);
446
447    if (-1 == vx->xvmc_port) {
448        vx->xvmc_port = (vXvMC->activePorts++);
449        sAPriv->XvMCSubPicOn[vx->xvmc_port] = 0;
450        sAPriv->XvMCDisplaying[vx->xvmc_port] = 0;
451    }
452
453    if (vXvMC->nContexts >= VIA_XVMC_MAX_CONTEXTS) {
454        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
455                   "[XvMC] ViaXvMCCreateContext: Out of contexts.\n");
456        return BadAlloc;
457    }
458
459    *priv = calloc(1, sizeof(ViaXvMCCreateContextRec));
460    contextRec = (ViaXvMCCreateContextRec *) * priv;
461
462    if (!*priv) {
463        *num_priv = 0;
464        return BadAlloc;
465    }
466
467    *num_priv = sizeof(ViaXvMCCreateContextRec) >> 2;
468
469    for (ctxNo = 0; ctxNo < VIA_XVMC_MAX_CONTEXTS; ++ctxNo) {
470        if (0 == vXvMC->contexts[ctxNo])
471            break;
472    }
473
474    cPriv = (ViaXvMCContextPriv *) calloc(1, sizeof(ViaXvMCContextPriv));
475
476    if (!cPriv) {
477        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
478                   "[XvMC] ViaXvMCCreateContext: Unable to allocate memory!\n");
479        free(*priv);
480        *num_priv = 0;
481        return BadAlloc;
482    }
483
484    /* Export framebuffer and mmio to non-root clients. */
485    contextRec->ctxNo = ctxNo;
486    contextRec->xvmc_port = vx->xvmc_port;
487    contextRec->fbOffset = vXvMC->fbBase;
488    contextRec->fbSize = pVia->videoRambytes;
489    contextRec->mmioOffset = vXvMC->mmioBase;
490    contextRec->mmioSize = VIA_MMIO_REGSIZE;
491    contextRec->sAreaSize = pDRIInfo->SAREASize;
492    contextRec->sAreaPrivOffset = sizeof(XF86DRISAREARec);
493    contextRec->major = VIAXVMC_MAJOR;
494    contextRec->minor = VIAXVMC_MINOR;
495    contextRec->pl = VIAXVMC_PL;
496    contextRec->initAttrs = vx->xvAttr;
497    contextRec->useAGP = (pViaDRI->ringBufActive &&
498                          ((pVia->Chipset == VIA_CLE266) ||
499                           (pVia->Chipset == VIA_KM400) ||
500                           (pVia->Chipset == VIA_PM800) ||
501                           (pVia->Chipset == VIA_P4M900)));
502    contextRec->chipId = pVia->ChipId;
503    contextRec->screen = pScrn->scrnIndex;
504    contextRec->depth = pScrn->bitsPerPixel;
505    contextRec->stride = pVia->Bpp * pScrn->virtualX;
506
507    vXvMC->nContexts++;
508    vXvMC->contexts[ctxNo] = pContext->context_id;
509    vXvMC->cPrivs[ctxNo] = cPriv;
510
511    return Success;
512}
513
514static int
515ViaXvMCCreateSurface(ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf,
516                     int *num_priv, INT32 ** priv)
517{
518    VIAPtr pVia = VIAPTR(pScrn);
519    ViaXvMCPtr vXvMC = &(pVia->xvmc);
520    unsigned srfNo, numBuffers, i;
521    ViaXvMCSurfacePriv *sPriv;
522    XvMCContextPtr ctx;
523    unsigned bufSize, yBufSize;
524    void *buf;
525
526    if (VIA_XVMC_MAX_SURFACES == vXvMC->nSurfaces) {
527        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
528                   "[XvMC] ViaXvMCCreateSurface: Too many surfaces !\n");
529        return BadAlloc;
530    }
531
532    sPriv = (ViaXvMCSurfacePriv *) calloc(1, sizeof(ViaXvMCSurfacePriv));
533
534    if (!sPriv) {
535        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
536                   "[XvMC] ViaXvMCCreateSurface: Unable to allocate memory!\n");
537        *num_priv = 0;
538        return BadAlloc;
539    }
540
541    numBuffers = 1;
542
543    /*
544     * Some chips require more than one buffer per surface (and a special
545     * flipping procedure; See Ivor Hewitt's ddmpeg.c version 1.6). The client
546     * lib will detect the number of buffers allocated and determine the
547     * flipping method from that.
548     */
549#if 0  /* Not enabled yet. */
550    switch (pVia->ChipSet) {
551        case VIA_CLE266:
552            switch (pVia->ChipRev) {
553                case 0x10:  /* CLE266 C0 only? Or all C? */
554                    numBuffers = 2;
555                    break;
556                default:
557                    break;
558            }
559            break;
560        default:
561            break;
562    }
563#endif
564    *num_priv = numBuffers + 2;
565
566    *priv = (INT32 *) calloc(*num_priv, sizeof(INT32));
567
568    if (!*priv) {
569        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
570                   "[XvMC] ViaXvMCCreateSurface: Unable to allocate memory!\n");
571        *num_priv = 0;
572        free(sPriv);
573        return BadAlloc;
574    }
575
576    for (srfNo = 0; srfNo < VIA_XVMC_MAX_SURFACES; ++srfNo) {
577        if (0 == vXvMC->sPrivs[srfNo])
578            break;
579    }
580
581    (*priv)[0] = srfNo;
582
583    ctx = pSurf->context;
584    bufSize = size_yuv420(ctx->width, ctx->height);
585    sPriv->memory_ref = drm_bo_alloc(pScrn, numBuffers * bufSize,
586                                    32, TTM_PL_FLAG_VRAM);
587    if (!sPriv->memory_ref) {
588        free(*priv);
589        free(sPriv);
590        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] ViaXvMCCreateSurface: "
591                   "Unable to allocate frambuffer memory!\n");
592        return BadAlloc;
593    }
594    buf = drm_bo_map(pScrn, sPriv->memory_ref);
595
596    (*priv)[1] = numBuffers;
597    (*priv)[2] = sPriv->offsets[0] = sPriv->memory_ref->offset;
598    for (i = 1; i < numBuffers; ++i) {
599        (*priv)[i + 2] = sPriv->offsets[i] = sPriv->offsets[i - 1] + bufSize;
600    }
601
602    yBufSize = stride(ctx->width) * ctx->height;
603    for (i = 0; i < numBuffers; ++i) {
604        memset(buf, 0, yBufSize);
605        memset(buf + yBufSize, 0x80, yBufSize >> 1);
606        buf += bufSize;
607    }
608    drm_bo_unmap(pScrn, sPriv->memory_ref);
609
610    vXvMC->sPrivs[srfNo] = sPriv;
611    vXvMC->surfaces[srfNo] = pSurf->surface_id;
612    vXvMC->nSurfaces++;
613    return Success;
614}
615
616static int
617ViaXvMCCreateSubpicture(ScrnInfoPtr pScrn, XvMCSubpicturePtr pSubp,
618                        int *num_priv, INT32 ** priv)
619{
620    VIAPtr pVia = VIAPTR(pScrn);
621    ViaXvMCPtr vXvMC = &(pVia->xvmc);
622    unsigned srfNo;
623    ViaXvMCSurfacePriv *sPriv;
624    XvMCContextPtr ctx;
625    unsigned bufSize;
626
627    if (VIA_XVMC_MAX_SURFACES == vXvMC->nSurfaces) {
628        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
629                   "[XvMC] ViaXvMCCreateSubpicture: Too many surfaces !\n");
630        return BadAlloc;
631    }
632
633    sPriv = (ViaXvMCSurfacePriv *) calloc(1, sizeof(ViaXvMCSurfacePriv));
634
635    if (!sPriv) {
636        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] ViaXvMCCreateSubpicture:"
637                   " Unable to allocate memory!\n");
638        *num_priv = 0;
639        return BadAlloc;
640    }
641
642    *priv = (INT32 *) calloc(3, sizeof(INT32));
643
644    if (!*priv) {
645        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] ViaXvMCCreateSubpicture:"
646                   " Unable to allocate memory!\n");
647        *num_priv = 0;
648        free(sPriv);
649        return BadAlloc;
650    }
651
652    *num_priv = 2;
653
654    for (srfNo = 0; srfNo < VIA_XVMC_MAX_SURFACES; ++srfNo) {
655        if (0 == vXvMC->sPrivs[srfNo])
656            break;
657    }
658
659    (*priv)[0] = srfNo;
660
661    ctx = pSubp->context;
662    bufSize = size_xx44(ctx->width, ctx->height);
663    sPriv->memory_ref = drm_bo_alloc(pScrn, 1 * bufSize, 32, TTM_PL_FLAG_VRAM);
664    if (!sPriv->memory_ref) {
665        free(*priv);
666        free(sPriv);
667        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "[XvMC] ViaXvMCCreateSubpicture:"
668                   " Unable to allocate framebuffer memory!\n");
669        return BadAlloc;
670    }
671    (*priv)[1] = sPriv->offsets[0] = sPriv->memory_ref->offset;
672
673    vXvMC->sPrivs[srfNo] = sPriv;
674    vXvMC->surfaces[srfNo] = pSubp->subpicture_id;
675    vXvMC->nSurfaces++;
676
677    return Success;
678}
679
680static void
681ViaXvMCDestroyContext(ScrnInfoPtr pScrn, XvMCContextPtr pContext)
682{
683    VIAPtr pVia = VIAPTR(pScrn);
684    ViaXvMCPtr vXvMC = &(pVia->xvmc);
685    int i;
686    volatile ViaXvMCSAreaPriv *sAPriv;
687    viaPortPrivPtr pPriv;
688    XvPortRecPrivatePtr portPriv;
689    ViaXvMCXVPriv *vx;
690
691    for (i = 0; i < VIA_XVMC_MAX_CONTEXTS; i++) {
692        if (vXvMC->contexts[i] == pContext->context_id) {
693
694            sAPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScrn->pScreen);
695            portPriv = (XvPortRecPrivatePtr) pContext->port_priv;
696            pPriv = (viaPortPrivPtr) portPriv->DevPriv.ptr;
697            vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
698
699            if ((i | VIA_XVMC_VALID) == vx->ctxDisplaying) {
700                vx->ctxDisplaying = 0;
701            }
702
703            free(vXvMC->cPrivs[i]);
704            vXvMC->cPrivs[i] = 0;
705            vXvMC->nContexts--;
706            vXvMC->contexts[i] = 0;
707            return;
708        }
709    }
710    return;
711}
712
713static void
714ViaXvMCDestroySurface(ScrnInfoPtr pScrn, XvMCSurfacePtr pSurf)
715{
716    VIAPtr pVia = VIAPTR(pScrn);
717    ViaXvMCPtr vXvMC = &(pVia->xvmc);
718    int i;
719    volatile ViaXvMCSAreaPriv *sAPriv;
720    XvMCContextPtr pContext = pSurf->context;
721    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) pContext->port_priv;
722    viaPortPrivPtr pPriv = (viaPortPrivPtr) portPriv->DevPriv.ptr;
723    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
724
725    for (i = 0; i < VIA_XVMC_MAX_SURFACES; i++) {
726        if (vXvMC->surfaces[i] == pSurf->surface_id) {
727
728            sAPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScrn->pScreen);
729            {
730                DRM_CAS_RESULT(__ret);
731                DRM_CAS(&(sAPriv->XvMCDisplaying[vx->xvmc_port]),
732                        i | VIA_XVMC_VALID, 0, __ret);
733                if (!__ret)
734                    ViaOverlayHide(pScrn);
735            }
736            drm_bo_free(pScrn, vXvMC->sPrivs[i]->memory_ref);
737            free(vXvMC->sPrivs[i]);
738            vXvMC->nSurfaces--;
739            vXvMC->sPrivs[i] = 0;
740            vXvMC->surfaces[i] = 0;
741            return;
742        }
743    }
744    return;
745}
746
747static void
748ViaXvMCDestroySubpicture(ScrnInfoPtr pScrn, XvMCSubpicturePtr pSubp)
749{
750    VIAPtr pVia = VIAPTR(pScrn);
751    ViaXvMCPtr vXvMC = &(pVia->xvmc);
752    int i;
753    volatile ViaXvMCSAreaPriv *sAPriv;
754    XvMCContextPtr pContext = pSubp->context;
755    XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr) pContext->port_priv;
756    viaPortPrivPtr pPriv = (viaPortPrivPtr) portPriv->DevPriv.ptr;
757    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
758
759    for (i = 0; i < VIA_XVMC_MAX_SURFACES; i++) {
760        if (vXvMC->surfaces[i] == pSubp->subpicture_id) {
761
762            sAPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScrn->pScreen);
763
764            {
765                DRM_CAS_RESULT(__ret);
766
767                DRM_CAS(&(sAPriv->XvMCSubPicOn[vx->xvmc_port]),
768                        i | VIA_XVMC_VALID, 0, __ret);
769                if (!__ret) {
770                    /* Turn subpicture off. */
771                    while (VIAGETREG(V_COMPOSE_MODE) &
772                           (V1_COMMAND_FIRE | V3_COMMAND_FIRE)) ;
773                    VIASETREG(SUBP_CONTROL_STRIDE,
774                            VIAGETREG(SUBP_CONTROL_STRIDE) & ~SUBP_HQV_ENABLE);
775                }
776            }
777
778            drm_bo_free(pScrn, vXvMC->sPrivs[i]->memory_ref);
779            free(vXvMC->sPrivs[i]);
780            vXvMC->nSurfaces--;
781            vXvMC->sPrivs[i] = 0;
782            vXvMC->surfaces[i] = 0;
783
784            return;
785        }
786    }
787    return;
788}
789
790/*
791 * Tell XvMC clients that Xv is currently displaying;
792 * return 1 if another client was displaying before.
793 */
794static int
795viaXvMCSetDisplayLock(ScrnInfoPtr pScrn, ViaXvMCXVPriv * vx)
796{
797    VIAPtr pVia = VIAPTR(pScrn);
798    ViaXvMCSAreaPriv *sAPriv = (ViaXvMCSAreaPriv *)
799            DRIGetSAREAPrivate(pScrn->pScreen);
800
801    if (vx->xvmc_port > 0) {
802        if ((VIA_XVMC_MAX_SURFACES | VIA_XVMC_VALID) !=
803            sAPriv->XvMCDisplaying[vx->xvmc_port]) {
804            sAPriv->XvMCDisplaying[vx->xvmc_port] =
805                    (VIA_XVMC_MAX_SURFACES | VIA_XVMC_VALID);
806        }
807
808        if (sAPriv->XvMCSubPicOn[vx->xvmc_port] & VIA_XVMC_VALID) {
809            sAPriv->XvMCSubPicOn[vx->xvmc_port] = 0;
810            while (VIAGETREG(V_COMPOSE_MODE) &
811                   (V1_COMMAND_FIRE | V3_COMMAND_FIRE)) ;
812            VIASETREG(SUBP_CONTROL_STRIDE,
813                    VIAGETREG(SUBP_CONTROL_STRIDE) & ~SUBP_HQV_ENABLE);
814        }
815    }
816    return 0;
817}
818
819int
820viaXvMCInitXv(ScrnInfoPtr pScrn, XF86VideoAdaptorPtr XvAdapt)
821{
822    viaPortPrivPtr pPriv;
823    ViaXvMCXVPriv *vx;
824    unsigned i, j;
825
826    for (j = 0; j < XvAdapt->nPorts; ++j) {
827        pPriv = (viaPortPrivPtr) XvAdapt->pPortPrivates[j].ptr;
828
829        if (NULL == (pPriv->xvmc_priv = calloc(1, sizeof(ViaXvMCXVPriv))))
830            return BadAlloc;
831
832        for (i = 0; i < VIA_NUM_XVMC_ATTRIBUTES; ++i) {
833            attrAtoms[i] = MAKE_ATOM(attrXvMC[i]);
834        }
835
836        vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
837
838        vx->ctxDisplaying = 0;
839        vx->xvAttr.numAttr = VIA_NUM_XVMC_ATTRIBUTES;
840        vx->xvmc_port = -1;
841        vx->newAttribute = 1;
842
843        /* Set up wrappers. */
844        vx->GetPortAttribute = XvAdapt->GetPortAttribute;
845        vx->SetPortAttribute = XvAdapt->SetPortAttribute;
846        vx->PutImage = XvAdapt->PutImage;
847
848        XvAdapt->GetPortAttribute = viaXvMCInterceptXvGetAttribute;
849        XvAdapt->SetPortAttribute = viaXvMCInterceptXvAttribute;
850        XvAdapt->PutImage = viaXvMCInterceptPutImage;
851
852        for (i = 0; i < VIA_NUM_XVMC_ATTRIBUTES; ++i) {
853            vx->xvAttr.attributes[i].attribute = attrAtoms[i];
854            vx->xvAttr.attributes[i].value = 0;
855            vx->GetPortAttribute(pScrn, attrAtoms[i],
856                                 &(vx->xvAttr.attributes[i].value), pPriv);
857        }
858    }
859    return Success;
860}
861
862static int
863viaXvMCInterceptXvAttribute(ScrnInfoPtr pScrn, Atom attribute,
864                            INT32 value, pointer data)
865{
866    unsigned i;
867    viaPortPrivPtr pPriv = (viaPortPrivPtr) data;
868    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
869
870    if (VIAPTR(pScrn)->XvMCEnabled) {
871        for (i = 0; i < vx->xvAttr.numAttr; ++i) {
872            if (vx->xvAttr.attributes[i].attribute == attribute) {
873                vx->xvAttr.attributes[i].value = value;
874                if (vx->ctxDisplaying !=
875                    (VIA_XVMC_MAX_CONTEXTS | VIA_XVMC_VALID)) {
876                    vx->newAttribute = 1;
877                    return 0;
878                }
879            }
880        }
881    }
882
883    return vx->SetPortAttribute(pScrn, attribute, value, data);
884}
885
886static int
887viaXvMCInterceptXvGetAttribute(ScrnInfoPtr pScrn, Atom attribute,
888                               INT32 * value, pointer data)
889{
890    unsigned i;
891    viaPortPrivPtr pPriv = (viaPortPrivPtr) data;
892    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
893
894    if (VIAPTR(pScrn)->XvMCEnabled) {
895        for (i = 0; i < vx->xvAttr.numAttr; ++i) {
896            if (vx->xvAttr.attributes[i].attribute == attribute) {
897                *value = vx->xvAttr.attributes[i].value;
898                return Success;
899            }
900        }
901    }
902
903    return vx->GetPortAttribute(pScrn, attribute, value, data);
904}
905
906static int
907viaXvMCDisplayAttributes(ScrnInfoPtr pScrn,
908                         const ViaXvMCAttrHolder * ah, viaPortPrivPtr pPriv)
909{
910    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
911    unsigned i;
912    int ret;
913
914    for (i = 0; i < ah->numAttr; ++i) {
915        ret = vx->SetPortAttribute(pScrn, ah->attributes[i].attribute,
916                                   ah->attributes[i].value, pPriv);
917        if (ret)
918            return ret;
919    }
920    return Success;
921}
922
923static int
924viaXvMCInterceptPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
925                         short drw_x, short drw_y, short src_w,
926                         short src_h, short drw_w, short drw_h,
927                         int id, unsigned char *buf, short width,
928                         short height, Bool sync, RegionPtr clipBoxes,
929                         pointer data, DrawablePtr pDraw)
930{
931    viaPortPrivPtr pPriv = (viaPortPrivPtr) data;
932    ViaXvMCXVPriv *vx = (ViaXvMCXVPriv *) pPriv->xvmc_priv;
933
934    if (VIAPTR(pScrn)->XvMCEnabled) {
935        if (FOURCC_XVMC == id) {
936            volatile ViaXvMCSAreaPriv *sAPriv;
937            ViaXvMCCommandBuffer *vXvMCData = (ViaXvMCCommandBuffer *) buf;
938
939            sAPriv = (ViaXvMCSAreaPriv *) DRIGetSAREAPrivate(pScrn->pScreen);
940
941            switch (vXvMCData->command) {
942            case VIA_XVMC_COMMAND_ATTRIBUTES:
943                if ((vXvMCData->ctxNo | VIA_XVMC_VALID) != vx->ctxDisplaying)
944                    return 1;
945                viaXvMCDisplayAttributes(pScrn, &vXvMCData->attrib, pPriv);
946                return 0;
947            case VIA_XVMC_COMMAND_FDISPLAY:
948                if (sAPriv->XvMCDisplaying[vx->xvmc_port] != vXvMCData->srfNo)
949                    return 1;
950                viaXvMCDisplayAttributes(pScrn, &vXvMCData->attrib, pPriv);
951                vx->ctxDisplaying = vXvMCData->ctxNo;
952                break;
953            case VIA_XVMC_COMMAND_DISPLAY:
954                if ((vXvMCData->ctxNo | VIA_XVMC_VALID) != vx->ctxDisplaying) {
955                    viaXvMCDisplayAttributes(pScrn, &vXvMCData->attrib, pPriv);
956                }
957                if (sAPriv->XvMCDisplaying[vx->xvmc_port] != vXvMCData->srfNo)
958                    return 1;
959                vx->ctxDisplaying = vXvMCData->ctxNo;
960                break;
961            case VIA_XVMC_COMMAND_UNDISPLAY:
962                {
963                    DRM_CAS_RESULT(__ret);
964                    DRM_CAS(&(sAPriv->XvMCDisplaying[vx->xvmc_port]),
965                        vXvMCData->srfNo, 0, __ret);
966                    if (!__ret)
967                        ViaOverlayHide(pScrn);
968                }
969                return Success;
970            default:
971                break;
972            }
973        } else {
974            if ((VIA_XVMC_MAX_CONTEXTS | VIA_XVMC_VALID) != vx->ctxDisplaying) {
975                viaXvMCDisplayAttributes(pScrn, &vx->xvAttr, pPriv);
976                vx->ctxDisplaying = VIA_XVMC_MAX_CONTEXTS | VIA_XVMC_VALID;
977            } else if (vx->newAttribute) {
978                vx->newAttribute = 0;
979                viaXvMCDisplayAttributes(pScrn, &vx->xvAttr, pPriv);
980            }
981            viaXvMCSetDisplayLock(pScrn, vx);
982        }
983    }
984    return vx->PutImage(pScrn, src_x, src_y, drw_x, drw_y, src_w, src_h,
985                        drw_w, drw_h, id, buf, width, height, sync, clipBoxes,
986                        data, pDraw);
987}
988
989unsigned long
990viaXvMCPutImageSize(ScrnInfoPtr pScrn)
991{
992    if (VIAPTR(pScrn)->XvMCEnabled)
993        return sizeof(ViaXvMCCommandBuffer);
994    return 0;
995}
996
997#endif /* HAVE_DRI */
998