atimach64xv.c revision 0b0ce0bf
1/*
2 * Copyright 2003 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as-is" without express or implied warranty.
13 *
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include <string.h>
28
29#include "ati.h"
30#include "atichip.h"
31#include "atimach64accel.h"
32#include "atimach64io.h"
33#include "atixv.h"
34#include "atimach64version.h"
35
36#include <X11/extensions/Xv.h>
37#include "fourcc.h"
38#include "xf86xv.h"
39
40#define MAKE_ATOM(string) MakeAtom(string, strlen(string), TRUE)
41#define MaxScale          (CARD32)(CARD16)(-1)
42
43static unsigned long ATIMach64XVAtomGeneration = (unsigned long)(-1);
44
45static XF86VideoEncodingRec ATIMach64VideoEncoding[] =
46{
47    { 0, "XV_IMAGE", 720, 2048, {1, 1} }
48};
49#define nATIMach64VideoEncoding NumberOf(ATIMach64VideoEncoding)
50
51static XF86VideoFormatRec ATIMach64VideoFormat[] =
52{
53    { 8, TrueColor},
54    { 8, DirectColor},
55    { 8, PseudoColor},
56    { 8, GrayScale},
57    { 8, StaticGray},
58    { 8, StaticColor},
59    {15, TrueColor},
60    {16, TrueColor},
61    {24, TrueColor},
62    {15, DirectColor},
63    {16, DirectColor},
64    {24, DirectColor}
65};
66#define nATIMach64VideoFormat NumberOf(ATIMach64VideoFormat)
67
68static XF86AttributeRec ATIMach64Attribute[] =
69{
70    /* These are only supported on the Rage Pro and later ... */
71    {
72        XvSettable | XvGettable,
73        -1000, 1000,
74        "XV_SATURATION"
75    },
76    {
77        XvSettable | XvGettable,
78        -1000, 1000,
79        "XV_BRIGHTNESS"
80    },
81    {
82        XvSettable | XvGettable,
83        -1000, 1000,
84        "XV_COLOUR"
85    },
86    {
87        XvSettable | XvGettable,
88        -1000, 1000,
89        "XV_COLOR"
90    },
91
92    /* Local attributes, odds and ends for compatibility, etc... */
93    {
94        XvSettable | XvGettable,
95        0, 1,
96        "XV_AUTOPAINT_COLOURKEY"
97    },
98    {
99        XvSettable | XvGettable,
100        0, 1,
101        "XV_AUTOPAINT_COLORKEY"
102    },
103    {
104        XvSettable | XvGettable,
105        0, (1 << 24) - 1,
106        "XV_COLOURKEY"
107    },
108    {
109        XvSettable | XvGettable,
110        0, (1 << 24) - 1,
111        "XV_COLORKEY"
112    },
113    {
114        XvSettable | XvGettable,
115        0, (1 << 24) - 1,
116        "XV_COLOURKEY_MASK"
117    },
118    {
119        XvSettable | XvGettable,
120        0, (1 << 24) - 1,
121        "XV_COLORKEY_MASK"
122    },
123    {
124        XvSettable,
125        0, 0,
126        "XV_SET_DEFAULTS"
127    },
128    {   /* Keep last */
129        XvSettable | XvGettable,
130        0, 1,
131        "XV_DOUBLE_BUFFER"
132    }
133};
134#define nATIMach64Attribute NumberOf(ATIMach64Attribute)
135
136static XF86ImageRec ATIMach64Image[] =
137{
138    XVIMAGE_YUY2,
139    XVIMAGE_UYVY,
140    XVIMAGE_YV12,
141    XVIMAGE_I420
142};
143#define nATIMach64Image NumberOf(ATIMach64Image)
144
145/* A local XVideo adaptor attribute record */
146typedef struct _ATIMach64Attribute
147{
148    Atom  AttributeID;
149    INT32 MaxValue;             /* ... for the hardware */
150    void  (*SetAttribute) (ATIPtr, INT32);
151    INT32 (*GetAttribute) (ATIPtr);
152} ATIMach64AttributeRec, *ATIMach64AttributePtr;
153
154/* Functions to get/set XVideo adaptor attributes */
155
156static void
157ATIMach64SetSaturationAttribute
158(
159    ATIPtr pATI,
160    INT32  Value
161)
162{
163    /* Set the register */
164    pATI->NewHW.scaler_colour_cntl &=
165        ~(SCALE_SATURATION_U | SCALE_SATURATION_V);
166    pATI->NewHW.scaler_colour_cntl |= SetBits(Value, SCALE_SATURATION_U) |
167        SetBits(Value, SCALE_SATURATION_V);
168    outf(SCALER_COLOUR_CNTL, pATI->NewHW.scaler_colour_cntl);
169}
170
171static INT32
172ATIMach64GetSaturationAttribute
173(
174    ATIPtr pATI
175)
176{
177    return (INT32)GetBits(pATI->NewHW.scaler_colour_cntl, SCALE_SATURATION_U);
178}
179
180static void
181ATIMach64SetBrightnessAttribute
182(
183    ATIPtr pATI,
184    INT32  Value
185)
186{
187    /* Set the register */
188    pATI->NewHW.scaler_colour_cntl &= ~SCALE_BRIGHTNESS;
189    pATI->NewHW.scaler_colour_cntl |= SetBits(Value, SCALE_BRIGHTNESS);
190    outf(SCALER_COLOUR_CNTL, pATI->NewHW.scaler_colour_cntl);
191}
192
193static INT32
194ATIMach64GetBrightnessAttribute
195(
196    ATIPtr pATI
197)
198{
199    return (INT32)GetBits(pATI->NewHW.scaler_colour_cntl, SCALE_BRIGHTNESS);
200}
201
202static void
203ATIMach64SetDoubleBufferAttribute
204(
205    ATIPtr pATI,
206    INT32  Value
207)
208{
209    pATI->DoubleBuffer = Value;
210}
211
212static INT32
213ATIMach64GetDoubleBufferAttribute
214(
215    ATIPtr pATI
216)
217{
218    return (int)pATI->DoubleBuffer;
219}
220
221static void
222ATIMach64SetAutoPaintAttribute
223(
224    ATIPtr pATI,
225    INT32  Value
226)
227{
228    pATI->AutoPaint = Value;
229}
230
231static INT32
232ATIMach64GetAutoPaintAttribute
233(
234    ATIPtr pATI
235)
236{
237    return (int)pATI->AutoPaint;
238}
239
240static void
241ATIMach64SetColourKeyAttribute
242(
243    ATIPtr pATI,
244    INT32  Value
245)
246{
247    pATI->NewHW.overlay_graphics_key_clr =
248        (CARD32)(Value & ((1 << pATI->depth) - 1));
249    outf(OVERLAY_GRAPHICS_KEY_CLR, pATI->NewHW.overlay_graphics_key_clr);
250}
251
252static INT32
253ATIMach64GetColourKeyAttribute
254(
255    ATIPtr pATI
256)
257{
258    return (INT32)pATI->NewHW.overlay_graphics_key_clr;
259}
260
261static void
262ATIMach64SetColourKeyMaskAttribute
263(
264    ATIPtr pATI,
265    INT32  Value
266)
267{
268    pATI->NewHW.overlay_graphics_key_msk =
269        (CARD32)(Value & ((1 << pATI->depth) - 1));
270    outf(OVERLAY_GRAPHICS_KEY_MSK, pATI->NewHW.overlay_graphics_key_msk);
271}
272
273static INT32
274ATIMach64GetColourKeyMaskAttribute
275(
276    ATIPtr pATI
277)
278{
279    return (INT32)pATI->NewHW.overlay_graphics_key_msk;
280}
281
282/*
283 * ATIMach64SetDefaultAttributes --
284 *
285 * This function calls other functions to set default values for the various
286 * attributes of an XVideo port.
287 */
288static void
289ATIMach64SetDefaultAttributes
290(
291    ATIPtr pATI,
292    INT32  Value
293)
294{
295    ATIMach64SetAutoPaintAttribute(pATI, TRUE);
296    ATIMach64SetDoubleBufferAttribute(pATI, FALSE);
297    ATIMach64SetColourKeyMaskAttribute(pATI, (1 << pATI->depth) - 1);
298    ATIMach64SetColourKeyAttribute(pATI, (3 << ((2 * pATI->depth) / 3)) |
299                                         (2 << ((1 * pATI->depth) / 3)) |
300                                         (1 << ((0 * pATI->depth) / 3)));
301
302    if (pATI->Chip < ATI_CHIP_264GTPRO)
303        return;
304
305    ATIMach64SetBrightnessAttribute(pATI, 32);
306    ATIMach64SetSaturationAttribute(pATI, 16);
307}
308
309/*
310 * There is a one-to-one correspondence between elements of the following array
311 * and those of ATIMach64Attribute.
312 */
313static ATIMach64AttributeRec ATIMach64AttributeInfo[nATIMach64Attribute] =
314{
315    {   /* SATURATION */
316        0, 23,
317        ATIMach64SetSaturationAttribute,
318        ATIMach64GetSaturationAttribute
319    },
320    {   /* BRIGHTNESS */
321        0, 63,
322        ATIMach64SetBrightnessAttribute,
323        ATIMach64GetBrightnessAttribute
324    },
325    {   /* COLOUR */
326        0, 23,
327        ATIMach64SetSaturationAttribute,
328        ATIMach64GetSaturationAttribute
329    },
330    {   /* COLOR */
331        0, 23,
332        ATIMach64SetSaturationAttribute,
333        ATIMach64GetSaturationAttribute
334    },
335    {   /* AUTOPAINT_COLOURKEY */
336        0, 1,
337        ATIMach64SetAutoPaintAttribute,
338        ATIMach64GetAutoPaintAttribute
339    },
340    {   /* AUTOPAINT_COLORKEY */
341        0, 1,
342        ATIMach64SetAutoPaintAttribute,
343        ATIMach64GetAutoPaintAttribute
344    },
345    {   /* COLOURKEY */
346        0, (1 << 24) - 1,
347        ATIMach64SetColourKeyAttribute,
348        ATIMach64GetColourKeyAttribute
349    },
350    {   /* COLORKEY */
351        0, (1 << 24) - 1,
352        ATIMach64SetColourKeyAttribute,
353        ATIMach64GetColourKeyAttribute
354    },
355    {   /* COLOURKEY_MASK */
356        0, (1 << 24) - 1,
357        ATIMach64SetColourKeyMaskAttribute,
358        ATIMach64GetColourKeyMaskAttribute
359    },
360    {   /* COLORKEY_MASK */
361        0, (1 << 24) - 1,
362        ATIMach64SetColourKeyMaskAttribute,
363        ATIMach64GetColourKeyMaskAttribute
364    },
365    {   /* SET_DEFAULTS */
366        0, 0,
367        ATIMach64SetDefaultAttributes,
368        NULL
369    },
370    {   /* DOUBLE_BUFFER */
371        0, 1,
372        ATIMach64SetDoubleBufferAttribute,
373        ATIMach64GetDoubleBufferAttribute
374    }
375};
376
377/*
378 * ATIMach64FindAttribute --
379 *
380 * This function is called to locate an Xv attribute's table entry.
381 */
382static int
383ATIMach64FindPortAttribute
384(
385    ATIPtr pATI,
386    Atom   AttributeID
387)
388{
389    int iAttribute;
390
391    if (pATI->Chip < ATI_CHIP_264GTPRO)
392        iAttribute = 4;
393    else
394        iAttribute = 0;
395
396    for (;  iAttribute < nATIMach64Attribute;  iAttribute++)
397        if (AttributeID == ATIMach64AttributeInfo[iAttribute].AttributeID)
398            return iAttribute;
399
400    return -1;
401}
402
403/*
404 * ATIMach64SetPortAttribute --
405 *
406 * This function sets the value of a particular port's attribute.
407 */
408static int
409ATIMach64SetPortAttribute
410(
411    ScrnInfoPtr pScreenInfo,
412    Atom        AttributeID,
413    INT32       Value,
414    pointer     pATI
415)
416{
417    INT32 Range;
418    int   iAttribute;
419
420    if (((iAttribute = ATIMach64FindPortAttribute(pATI, AttributeID)) < 0) ||
421        !ATIMach64AttributeInfo[iAttribute].SetAttribute)
422        return BadMatch;
423
424    Range = ATIMach64Attribute[iAttribute].max_value -
425        ATIMach64Attribute[iAttribute].min_value;
426
427    if (Range >= 0)
428    {
429        /* Limit and scale the value */
430        Value -= ATIMach64Attribute[iAttribute].min_value;
431
432        if (Value < 0)
433            Value = 0;
434        else if (Value > Range)
435            Value = Range;
436
437        if (Range != ATIMach64AttributeInfo[iAttribute].MaxValue)
438        {
439            if (ATIMach64AttributeInfo[iAttribute].MaxValue > 0)
440                Value *= ATIMach64AttributeInfo[iAttribute].MaxValue;
441            if (Range > 0)
442                Value /= Range;
443        }
444    }
445
446    (*ATIMach64AttributeInfo[iAttribute].SetAttribute)(pATI, Value);
447
448    return Success;
449}
450
451/*
452 * ATIMach64SetPortAttribute --
453 *
454 * This function retrieves the value of a particular port's attribute.
455 */
456static int
457ATIMach64GetPortAttribute
458(
459    ScrnInfoPtr pScreenInfo,
460    Atom        AttributeID,
461    INT32       *Value,
462    pointer     pATI
463)
464{
465    INT32 Range;
466    int   iAttribute;
467
468    if (!Value ||
469        ((iAttribute = ATIMach64FindPortAttribute(pATI, AttributeID)) < 0) ||
470        !ATIMach64AttributeInfo[iAttribute].GetAttribute)
471        return BadMatch;
472
473    *Value = (*ATIMach64AttributeInfo[iAttribute].GetAttribute)(pATI);
474
475    Range = ATIMach64Attribute[iAttribute].max_value -
476        ATIMach64Attribute[iAttribute].min_value;
477
478    if (Range >= 0)
479    {
480        if (Range != ATIMach64AttributeInfo[iAttribute].MaxValue)
481        {
482            /* (Un-)scale the value */
483            if (Range > 0)
484                *Value *= Range;
485            if (ATIMach64AttributeInfo[iAttribute].MaxValue > 0)
486                *Value /= ATIMach64AttributeInfo[iAttribute].MaxValue;
487        }
488
489        *Value += ATIMach64Attribute[iAttribute].min_value;
490    }
491
492    return Success;
493}
494
495static pointer
496ATIMach64XVMemAlloc
497(
498    ScreenPtr pScreen,
499    pointer   pVideo,
500    int       size,
501    int       *offset,
502    ATIPtr    pATI
503);
504
505static void
506ATIMach64XVMemFree
507(
508    ScreenPtr pScreen,
509    pointer   pVideo,
510    ATIPtr    pATI
511);
512
513#ifdef USE_XAA
514/*
515 * ATIMach64RemoveLinearCallback --
516 *
517 * This is called by the framebuffer manager to release the offscreen XVideo
518 * buffer after the video has been temporarily disabled due to its window being
519 * iconified or completely occluded.
520 */
521static void
522ATIMach64RemoveLinearCallback
523(
524    FBLinearPtr pLinear
525)
526{
527    ATIPtr pATI = ATIPTR(xf86ScreenToScrn(pLinear->pScreen));
528
529    pATI->pXVBuffer = NULL;
530    outf(OVERLAY_SCALE_CNTL, SCALE_EN);
531}
532#endif /* USE_XAA */
533
534/*
535 * ATIMach64StopVideo --
536 *
537 * This is called to stop displaying a video.  Note that, to prevent jittering
538 * this doesn't actually turn off the overlay unless 'Cleanup' is TRUE, i.e.
539 * when the video is to be actually stopped rather than temporarily disabled.
540 */
541static void
542ATIMach64StopVideo
543(
544    ScrnInfoPtr pScreenInfo,
545    pointer     Data,
546    Bool        Cleanup
547)
548{
549    ScreenPtr pScreen = pScreenInfo->pScreen;
550    ATIPtr    pATI    = Data;
551
552    if (pATI->ActiveSurface)
553        return;
554
555    REGION_EMPTY(pScreen, &pATI->VideoClip);
556
557#ifdef USE_XAA
558    if (!pATI->useEXA && !Cleanup)
559    {
560        /*
561         * Free offscreen buffer if/when its allocation is needed by XAA's
562         * pixmap cache.
563         */
564        FBLinearPtr linear = (FBLinearPtr)pATI->pXVBuffer;
565        if (linear)
566            linear->RemoveLinearCallback =
567                ATIMach64RemoveLinearCallback;
568        return;
569    }
570#endif /* USE_XAA */
571
572    ATIMach64XVMemFree(pScreen, pATI->pXVBuffer, pATI);
573    pATI->pXVBuffer = NULL;
574    outf(OVERLAY_SCALE_CNTL, SCALE_EN);
575}
576
577/*
578 * ATIMach64QueryBestSize --
579 *
580 * Quoting XVideo docs:
581 *
582 * This function provides the client with a way to query what the destination
583 * dimensions would end up being if they were to request that an area
584 * VideoWidth by VideoHeight from the video stream be scaled to rectangle of
585 * DrawableWidth by DrawableHeight on the screen.  Since it is not expected
586 * that all hardware will be able to get the target dimensions exactly, it is
587 * important that the driver provide this function.
588 */
589static void
590ATIMach64QueryBestSize
591(
592    ScrnInfoPtr  pScreenInfo,
593    Bool         Motion,
594    short        VideoWidth,
595    short        VideoHeight,
596    short        DrawableWidth,
597    short        DrawableHeight,
598    unsigned int *Width,
599    unsigned int *Height,
600    pointer      pATI
601)
602{
603    *Width  = DrawableWidth;
604    *Height = DrawableHeight;
605}
606
607/*
608 * ATIMach64QueryImageAttributes --
609 *
610 * Quoting XVideo docs:
611 *
612 * This function is called to let the driver specify how data for a particular
613 * image of size Width by Height should be stored.  Sometimes only the size and
614 * corrected width and height are needed.  In that case pitches and offsets are
615 * NULL.  The size of the memory required for the image is returned by this
616 * function.  The width and height of the requested image can be altered by the
617 * driver to reflect format limitations (such as component sampling periods
618 * that are larger than one).  If pPitch and pOffset are not NULL, these will
619 * be arrays with as many elements in them as there are planes in the image
620 * format.  The driver should specify the pitch (in bytes) of each scanline in
621 * the particular plane as well as the offset to that plane (in bytes) from the
622 * beginning of the image.
623 */
624static int
625ATIMach64QueryImageAttributes
626(
627    ScrnInfoPtr    pScreenInfo,
628    int            ImageID,
629    unsigned short *Width,
630    unsigned short *Height,
631    int            *pPitch,
632    int            *pOffset
633)
634{
635    int Size, tmp;
636
637    if (!Width || !Height)
638        return 0;
639
640    if (*Width > 2048)
641        *Width = 2048;
642    else
643        *Width = (*Width + 1) & ~1;
644
645    if (*Height > 2048)
646        *Height = 2048;
647
648    if (pOffset)
649        pOffset[0] = 0;
650
651    switch (ImageID)
652    {
653        case FOURCC_YV12:
654        case FOURCC_I420:
655            *Height = (*Height + 1) & ~1;
656            Size = (*Width + 3) & ~3;
657            if (pPitch)
658                pPitch[0] = Size;
659            Size *= *Height;
660            if (pOffset)
661                pOffset[1] = Size;
662            tmp = ((*Width >> 1) + 3) & ~3;
663            if (pPitch)
664                pPitch[1] = pPitch[2] = tmp;
665            tmp *= (*Height >> 1);
666            Size += tmp;
667            if (pOffset)
668                pOffset[2] = Size;
669            Size += tmp;
670            break;
671
672        case FOURCC_UYVY:
673        case FOURCC_YUY2:
674            Size = *Width << 1;
675            if (pPitch)
676                pPitch[0] = Size;
677            Size *= *Height;
678            break;
679
680        default:
681            Size = 0;
682            break;
683    }
684
685    return Size;
686}
687
688/*
689 * ATIMach64ScaleVideo --
690 *
691 * This function is called to calculate overlay scaling factors.
692 */
693static void
694ATIMach64ScaleVideo
695(
696    ATIPtr         pATI,
697    DisplayModePtr pMode,
698    int            SrcW,
699    int            SrcH,
700    int            DstW,
701    int            DstH,
702    CARD32         *pHScale,
703    CARD32         *pVScale
704)
705{
706    int Shift;
707
708    *pHScale = ATIDivide(SrcW, DstW,
709        GetBits(pATI->NewHW.pll_vclk_cntl, PLL_ECP_DIV) + 12, 0);
710
711    Shift = 12;
712    if (pMode->Flags & V_INTERLACE)
713        Shift++;
714
715    if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
716    {
717        if (pMode->VDisplay < pATI->LCDVertical)
718        {
719            SrcH *= pMode->VDisplay;
720            DstH *= pATI->LCDVertical;
721        }
722    }
723    else
724    {
725        if (pMode->Flags & V_DBLSCAN)
726            Shift--;
727        if (pMode->VScan > 1)
728            DstH *= pMode->VScan;
729    }
730
731    *pVScale = ATIDivide(SrcH, DstH, Shift, 0);
732}
733
734/*
735 * ATIMach64ClipVideo --
736 *
737 * Clip the video (both source and destination) and make various other
738 * adjustments.
739 */
740static Bool
741ATIMach64ClipVideo
742(
743    ScrnInfoPtr pScreenInfo,
744    ATIPtr      pATI,
745    int         ImageID,
746    short       SrcX,
747    short       SrcY,
748    short       SrcW,
749    short       SrcH,
750    short       DstX,
751    short       DstY,
752    short       *DstW,
753    short       *DstH,
754    short       Width,
755    short       Height,
756    RegionPtr   pClip,
757    BoxPtr      pDstBox,
758    INT32       *SrcX1,
759    INT32       *SrcX2,
760    INT32       *SrcY1,
761    INT32       *SrcY2,
762    int         *SrcLeft,
763    int         *SrcTop
764)
765{
766    CARD32 HScale, VScale;
767
768    /* Check hardware limits */
769    if ((Height <= 0) || (Height > 2048) || (Width <= 0) || (Width > 768) ||
770        ((Width > 384) && (pATI->Chip < ATI_CHIP_264VTB)) ||
771        ((Width > 720) && (pATI->Chip < ATI_CHIP_264GTPRO ||
772                           pATI->Chip > ATI_CHIP_264LTPRO)))
773        return FALSE;
774
775    ATIMach64ScaleVideo(pATI, pScreenInfo->currentMode,
776        SrcW, SrcH, *DstW, *DstH, &HScale, &VScale);
777    if (!HScale || !VScale)
778        return FALSE;
779    if (HScale > MaxScale)
780        *DstW = (*DstW * HScale) / MaxScale;
781    if (VScale > MaxScale)
782        *DstH = (*DstH * HScale) / MaxScale;
783
784    /* Clip both the source and the destination */
785    *SrcX1 = SrcX;
786    *SrcX2 = SrcX + SrcW;
787    *SrcY1 = SrcY;
788    *SrcY2 = SrcY + SrcH;
789
790    pDstBox->x1 = DstX;
791    pDstBox->x2 = DstX + *DstW;
792    pDstBox->y1 = DstY;
793    pDstBox->y2 = DstY + *DstH;
794
795    if (!xf86XVClipVideoHelper(pDstBox, SrcX1, SrcX2, SrcY1, SrcY2,
796                               pClip, Width, Height))
797        return FALSE;
798
799    /*
800     * Reset overlay scaler origin.  This prevents jittering during
801     * viewport panning or while the video is being moved or gradually
802     * obscured/unobscured.
803     */
804    pDstBox->x1 = DstX;
805    pDstBox->y1 = DstY;
806
807    /* Translate to the current viewport */
808    pDstBox->x1 -= pScreenInfo->frameX0;
809    pDstBox->x2 -= pScreenInfo->frameX0;
810    pDstBox->y1 -= pScreenInfo->frameY0;
811    pDstBox->y2 -= pScreenInfo->frameY0;
812
813    *SrcLeft = *SrcTop = 0;
814
815    /*
816     * If the overlay scaler origin ends up outside the current viewport, move
817     * it to the viewport's top left corner.  This unavoidably causes a slight
818     * jittering in the image (even with double-buffering).
819     */
820    if (pDstBox->x1 < 0)
821    {
822        *SrcLeft = ((-pDstBox->x1 * SrcW) / *DstW) & ~1;
823        pDstBox->x1 = 0;
824    }
825
826    if (pDstBox->y1 < 0)
827    {
828        *SrcTop = (-pDstBox->y1 * SrcH) / *DstH;
829        pDstBox->y1 = 0;
830
831        switch (ImageID)
832        {
833            case FOURCC_YV12:
834            case FOURCC_I420:
835                *SrcTop = (*SrcTop + 1) & ~1;
836                break;
837
838            default:
839                break;
840        }
841    }
842
843    return TRUE;
844}
845
846#ifdef ATIMove32
847
848/* A faster intercept */
849#undef  xf86XVCopyPacked
850#define xf86XVCopyPacked ATIMach64XVCopyPacked
851
852static void
853ATIMach64XVCopyPacked
854(
855    const CARD8 *pSrc,
856    CARD8       *pDst,
857    int         SrcPitch,
858    int         DstPitch,
859    int         Height,
860    int         Width
861)
862{
863    Width >>= 1;
864    while (--Height >= 0)
865    {
866        ATIMove32(pDst, pSrc, Width);
867        pSrc += SrcPitch;
868        pDst += DstPitch;
869    }
870}
871
872#endif
873
874/*
875 * ATIMach64DisplayVideo --
876 *
877 * This function programmes Mach64 registers needed to display a video.
878 */
879static void
880ATIMach64DisplayVideo
881(
882    ScrnInfoPtr pScreenInfo,
883    ATIPtr      pATI,
884    BoxPtr      pDstBox,
885    int         ImageID,
886    int         Offset,
887    int         Pitch,
888    short       SrcW,
889    short       SrcH,
890    short       DstW,
891    short       DstH,
892    short       Width,
893    short       Height
894)
895{
896    DisplayModePtr pMode = pScreenInfo->currentMode;
897    CARD32         HScale, VScale;
898
899    if (pMode->VScan > 1)
900    {
901        pDstBox->y1 *= pMode->VScan;
902        pDstBox->y2 *= pMode->VScan;
903    }
904    if (pMode->Flags & V_DBLSCAN)
905    {
906        pDstBox->y1 <<= 1;
907        pDstBox->y2 <<= 1;
908    }
909
910    /* Recalculate overlay scale factors */
911    ATIMach64ScaleVideo(pATI, pMode, SrcW, SrcH, DstW, DstH, &HScale, &VScale);
912
913    pATI->NewHW.video_format &= ~SCALER_IN;
914    if (ImageID == FOURCC_UYVY)
915        pATI->NewHW.video_format |= SCALER_IN_YVYU422;
916    else
917        pATI->NewHW.video_format |= SCALER_IN_VYUY422;
918
919    ATIMach64WaitForFIFO(pATI, 8);
920    outq(OVERLAY_Y_X_START, OVERLAY_Y_X_END, OVERLAY_LOCK_START |
921        SetWord(pDstBox->x1, 1) | SetWord(pDstBox->y1, 0),
922        SetWord(pDstBox->x2 - 1, 1) | SetWord(pDstBox->y2 - 1, 0));
923    outf(OVERLAY_SCALE_INC, SetWord(HScale, 1) | SetWord(VScale, 0));
924    outf(SCALER_HEIGHT_WIDTH, SetWord(Width, 1) | SetWord(Height, 0));
925    outf(VIDEO_FORMAT, pATI->NewHW.video_format);
926
927    if (pATI->Chip < ATI_CHIP_264VTB)
928    {
929        outf(BUF0_OFFSET, Offset);
930        outf(BUF0_PITCH, Pitch);
931    }
932    else
933    {
934        outf(SCALER_BUF0_OFFSET, Offset);
935        outf(SCALER_BUF_PITCH, Pitch);
936    }
937
938    outf(OVERLAY_SCALE_CNTL, SCALE_PIX_EXPAND | OVERLAY_EN | SCALE_EN);
939}
940
941/*
942 * ATIMach64PutImage --
943 *
944 * This function is called to put a video image on the screen.
945 */
946static int
947ATIMach64PutImage
948(
949    ScrnInfoPtr   pScreenInfo,
950    short         SrcX,
951    short         SrcY,
952    short         DstX,
953    short         DstY,
954    short         SrcW,
955    short         SrcH,
956    short         DstW,
957    short         DstH,
958    int           ImageID,
959    unsigned char *Buffer,
960    short         Width,
961    short         Height,
962    Bool          Synchronise,
963    RegionPtr     pClip,
964    pointer       Data,
965    DrawablePtr   pDraw
966)
967{
968    ATIPtr    pATI    = Data;
969    ScreenPtr pScreen;
970    INT32     SrcX1, SrcX2, SrcY1, SrcY2;
971    BoxRec    DstBox;
972    int       SrcPitch, SrcPitchUV, DstPitch, DstSize;
973    int       SrcTop, SrcLeft, DstWidth, DstHeight;
974    int       Top, Bottom, Left, Right, nLine, nPixel, Offset;
975    int       OffsetV, OffsetU;
976    int       XVOffset;
977    int       tmp;
978    CARD8     *pDst;
979
980    if (pATI->ActiveSurface)
981        return Success;
982
983    if (DstH < 16)
984	return Success;
985
986    if (!ATIMach64ClipVideo(pScreenInfo, pATI, ImageID,
987                            SrcX, SrcY, SrcW, SrcH,
988                            DstX, DstY, &DstW, &DstH,
989                            Width, Height, pClip, &DstBox,
990                            &SrcX1, &SrcX2, &SrcY1, &SrcY2,
991                            &SrcLeft, &SrcTop))
992        return Success;
993
994    pScreen = pScreenInfo->pScreen;
995
996    DstWidth = Width - SrcLeft;
997    DstHeight = Height - SrcTop;
998
999    /*
1000     * Allocate an offscreen buffer for the entire source, even though only a
1001     * subset of the source will be copied into it.
1002     */
1003    DstPitch = /* bytes */
1004        (DstWidth + DstWidth + 15) & ~15;
1005    DstSize =  /* bytes */
1006        (DstPitch * DstHeight);
1007
1008    pATI->pXVBuffer = ATIMach64XVMemAlloc(pScreen, pATI->pXVBuffer,
1009        (pATI->DoubleBuffer + 1) * DstSize, &XVOffset, pATI);
1010
1011    if (!pATI->pXVBuffer)
1012    {
1013        if (!pATI->DoubleBuffer)
1014            return BadAlloc;
1015
1016        pATI->pXVBuffer =
1017            ATIMach64XVMemAlloc(pScreen, pATI->pXVBuffer, DstSize, &XVOffset, pATI);
1018
1019        if (!pATI->pXVBuffer)
1020            return BadAlloc;
1021
1022        xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING,
1023            "Video image double-buffering downgraded to single-buffering\n due"
1024            " to insufficient video memory.\n");
1025        pATI->DoubleBuffer = pATI->CurrentBuffer = 0;
1026    }
1027    else
1028    {
1029        /* Possibly switch buffers */
1030        pATI->CurrentBuffer = pATI->DoubleBuffer - pATI->CurrentBuffer;
1031    }
1032
1033    /* Synchronise video memory accesses */
1034    ATIMach64Sync(pScreenInfo);
1035
1036    Offset = XVOffset + pATI->CurrentBuffer * DstSize;
1037    pDst = pATI->pMemoryLE;
1038    pDst += Offset;
1039
1040    switch (ImageID)
1041    {
1042        case FOURCC_YV12:
1043        case FOURCC_I420:
1044            Left = (SrcX1 >> 16) & ~1;
1045            Right = ((SrcX2 + 0x1FFFF) >> 16) & ~1;
1046            Top = (SrcY1 >> 16) & ~1;
1047            Bottom = ((SrcY2 + 0x1FFFF) >> 16) & ~1;
1048
1049            if ((Right < Width) && ((SrcX1 & 0x1FFFF) <= (SrcX2 & 0x1FFFF)))
1050                Right += 2;
1051            if ((Bottom < Height) && ((SrcY1 & 0x1FFFF) <= (SrcY2 & 0x1FFFF)))
1052                Bottom += 2;
1053
1054            nPixel = Right - Left;
1055            nLine = Bottom - Top;
1056
1057            SrcPitch = (Width + 3) & ~3;
1058            OffsetV = SrcPitch * Height;
1059            SrcPitchUV = ((Width >> 1) + 3) & ~3;
1060            OffsetU = ((Height >> 1) * SrcPitchUV) + OffsetV;
1061
1062            tmp = ((Top >> 1) * SrcPitchUV) + (Left >> 1);
1063            OffsetV += tmp;
1064            OffsetU += tmp;
1065
1066            if (ImageID == FOURCC_I420)
1067            {
1068                tmp = OffsetV;
1069                OffsetV = OffsetU;
1070                OffsetU = tmp;
1071            }
1072
1073            pDst += ((Top - SrcTop) * DstPitch) + ((Left - SrcLeft) << 1);
1074
1075            xf86XVCopyYUV12ToPacked(Buffer + (Top * SrcPitch) + Left,
1076                Buffer + OffsetV, Buffer + OffsetU, pDst, SrcPitch, SrcPitchUV,
1077                DstPitch, nLine, nPixel);
1078            break;
1079
1080        case FOURCC_UYVY:
1081        case FOURCC_YUY2:
1082        default:
1083            Left = (SrcX1 >> 16) & ~1;
1084            Right = ((SrcX2 + 0x1FFFF) >> 16) & ~1;
1085            Top = SrcY1 >> 16;
1086            Bottom = (SrcY2 + 0x0FFFF) >> 16;
1087
1088            if ((Right < Width) && ((SrcX1 & 0x1FFFF) <= (SrcX2 & 0x1FFFF)))
1089                Right += 2;
1090            if ((Bottom < Height) && ((SrcY1 & 0x0FFFF) <= (SrcY2 & 0x0FFFF)))
1091                Bottom++;
1092
1093            nPixel = Right - Left;
1094            nLine = Bottom - Top;
1095
1096            SrcPitch = Width << 1;
1097            Buffer += (Top * SrcPitch) + (Left << 1);
1098            pDst += ((Top - SrcTop) * DstPitch) + ((Left - SrcLeft) << 1);
1099
1100            xf86XVCopyPacked(Buffer, pDst, SrcPitch, DstPitch, nLine, nPixel);
1101            break;
1102    }
1103
1104    if (!REGION_EQUAL(pScreen, &pATI->VideoClip, pClip))
1105    {
1106        REGION_COPY(pScreen, &pATI->VideoClip, pClip);
1107        if (pATI->AutoPaint)
1108            xf86XVFillKeyHelper(pScreen, pATI->NewHW.overlay_graphics_key_clr,
1109                pClip);
1110    }
1111
1112    ATIMach64DisplayVideo(pScreenInfo, pATI, &DstBox, ImageID,
1113        Offset, DstPitch / 2, SrcW, SrcH, DstW, DstH, DstWidth, DstHeight);
1114
1115    return Success;
1116}
1117
1118/*
1119 * ATIMach64AllocateSurface --
1120 *
1121 * This function allocates an offscreen buffer (called a "surface") for use by
1122 * an external driver such as 'v4l'.
1123 */
1124static int
1125ATIMach64AllocateSurface
1126(
1127    ScrnInfoPtr    pScreenInfo,
1128    int            ImageID,
1129    unsigned short Width,
1130    unsigned short Height,
1131    XF86SurfacePtr pSurface
1132)
1133{
1134    ScreenPtr pScreen;
1135    ATIPtr    pATI = ATIPTR(pScreenInfo);
1136    int       XVOffset;
1137
1138    if (pATI->ActiveSurface)
1139        return BadAlloc;
1140
1141    if ((Height <= 0) || (Height > 2048) || (Width <= 0) || (Width > 768) ||
1142        ((Width > 384) && (pATI->Chip < ATI_CHIP_264VTB)) ||
1143        ((Width > 720) && (pATI->Chip < ATI_CHIP_264GTPRO ||
1144                           pATI->Chip > ATI_CHIP_264LTPRO)))
1145        return BadValue;
1146
1147    Width = (Width + 1) & ~1;
1148    pATI->SurfacePitch = ((Width << 1) + 15) & ~15;
1149
1150    pScreen = pScreenInfo->pScreen;
1151
1152    pATI->pXVBuffer = ATIMach64XVMemAlloc(pScreen, pATI->pXVBuffer,
1153        Height * pATI->SurfacePitch, &XVOffset, pATI);
1154    if (!pATI->pXVBuffer)
1155        return BadAlloc;
1156
1157    pATI->SurfaceOffset = XVOffset;
1158
1159    pSurface->pScrn = pScreenInfo;
1160    pSurface->id = ImageID;
1161    pSurface->width = Width;
1162    pSurface->height = Height;
1163    pSurface->pitches = &pATI->SurfacePitch;
1164    pSurface->offsets = &pATI->SurfaceOffset;
1165    pSurface->devPrivate.ptr = pATI;
1166
1167    /* Stop the video */
1168    outf(OVERLAY_SCALE_CNTL, SCALE_EN);
1169    REGION_EMPTY(pScreen, &pATI->VideoClip);
1170    pATI->ActiveSurface = TRUE;
1171
1172    return Success;
1173}
1174
1175/*
1176 * ATIMach64FreeSurface --
1177 *
1178 * This function called to free a surface's offscreen buffer.
1179 */
1180static int
1181ATIMach64FreeSurface
1182(
1183    XF86SurfacePtr pSurface
1184)
1185{
1186    ATIPtr pATI = pSurface->devPrivate.ptr;
1187
1188    if (!pATI->ActiveSurface)
1189        return Success;
1190
1191    outf(OVERLAY_SCALE_CNTL, SCALE_EN);
1192    ATIMach64XVMemFree(pSurface->pScrn->pScreen, pATI->pXVBuffer, pATI);
1193    pATI->pXVBuffer = NULL;
1194    pATI->ActiveSurface = FALSE;
1195
1196    return Success;
1197}
1198
1199/*
1200 * ATIMach64DisplaySurface --
1201 *
1202 * This function is called to display a video surface.
1203 */
1204static int
1205ATIMach64DisplaySurface
1206(
1207    XF86SurfacePtr pSurface,
1208    short          SrcX,
1209    short          SrcY,
1210    short          DstX,
1211    short          DstY,
1212    short          SrcW,
1213    short          SrcH,
1214    short          DstW,
1215    short          DstH,
1216    RegionPtr      pClip
1217)
1218{
1219    ATIPtr      pATI = pSurface->devPrivate.ptr;
1220    ScrnInfoPtr pScreenInfo;
1221    int         ImageID;
1222    short       Width, Height;
1223    BoxRec      DstBox;
1224    INT32       SrcX1, SrcX2, SrcY1, SrcY2;
1225    int         SrcLeft, SrcTop, SrcPitch, Offset;
1226
1227    if (!pATI->ActiveSurface)
1228        return Success;
1229
1230    pScreenInfo = pSurface->pScrn;
1231    ImageID = pSurface->id;
1232    Width = pSurface->width;
1233    Height = pSurface->height;
1234
1235    if (!ATIMach64ClipVideo(pScreenInfo, pATI, ImageID,
1236                            SrcX, SrcY, SrcW, SrcH,
1237                            DstX, DstY, &DstW, &DstH,
1238                            Width, Height, pClip, &DstBox,
1239                            &SrcX1, &SrcX2, &SrcY1, &SrcY2,
1240                            &SrcLeft, &SrcTop))
1241        return Success;
1242
1243    xf86XVFillKeyHelper(pScreenInfo->pScreen,
1244        pATI->NewHW.overlay_graphics_key_clr, pClip);
1245
1246    SrcPitch = pSurface->pitches[0];
1247    Offset = pSurface->offsets[0] + (SrcTop * SrcPitch) + (SrcLeft << 1);
1248    ATIMach64DisplayVideo(pScreenInfo, pATI, &DstBox, ImageID,
1249        Offset, SrcPitch, SrcW, SrcH, DstW, DstH, Width, Height);
1250
1251    return Success;
1252}
1253
1254/*
1255 * ATIMach64StopSurface --
1256 *
1257 * This function is called to stop the overlaid display of a video surface.
1258 */
1259static int
1260ATIMach64StopSurface
1261(
1262    XF86SurfacePtr pSurface
1263)
1264{
1265    ATIPtr pATI = pSurface->devPrivate.ptr;
1266
1267    if (pATI->ActiveSurface)
1268        outf(OVERLAY_SCALE_CNTL, SCALE_EN);
1269
1270    return Success;
1271}
1272
1273/*
1274 * ATIMach64GetSurfaceAttribute --
1275 *
1276 * Retrieve the value of an XVideo attribute.
1277 */
1278static int
1279ATIMach64GetSurfaceAttribute
1280(
1281    ScrnInfoPtr pScreenInfo,
1282    Atom        AttributeID,
1283    INT32       *Value
1284)
1285{
1286    return ATIMach64GetPortAttribute(pScreenInfo, AttributeID, Value,
1287                                     ATIPTR(pScreenInfo));
1288}
1289
1290/*
1291 * ATIMach64SetSurfaceAttribute
1292 *
1293 * Set the value of an XVideo attribute.
1294 */
1295static int
1296ATIMach64SetSurfaceAttribute
1297(
1298    ScrnInfoPtr pScreenInfo,
1299    Atom        AttributeID,
1300    INT32       Value
1301)
1302{
1303    return ATIMach64SetPortAttribute(pScreenInfo, AttributeID, Value,
1304                                     ATIPTR(pScreenInfo));
1305}
1306
1307/* XVideo surface registration data */
1308static XF86OffscreenImageRec ATIMach64Surface[] =
1309{
1310    {
1311        &ATIMach64Image[0],             /* YUY2 */
1312        VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1313        ATIMach64AllocateSurface,
1314        ATIMach64FreeSurface,
1315        ATIMach64DisplaySurface,
1316        ATIMach64StopSurface,
1317        ATIMach64GetSurfaceAttribute,
1318        ATIMach64SetSurfaceAttribute,
1319        720, 2048,
1320        nATIMach64Attribute - 1,        /* No double-buffering */
1321        ATIMach64Attribute
1322    },
1323    {
1324        &ATIMach64Image[1],             /* UYVY */
1325        VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1326        ATIMach64AllocateSurface,
1327        ATIMach64FreeSurface,
1328        ATIMach64DisplaySurface,
1329        ATIMach64StopSurface,
1330        ATIMach64GetSurfaceAttribute,
1331        ATIMach64SetSurfaceAttribute,
1332        720, 2048,
1333        nATIMach64Attribute - 1,        /* No double-buffering */
1334        ATIMach64Attribute
1335    }
1336};
1337#define nATIMach64Surface NumberOf(ATIMach64Surface)
1338
1339/*
1340 * ATIMach64XVInitialiseAdaptor --
1341 *
1342 * This function is called to make a Mach64's hardware overlay support
1343 * available as an XVideo adaptor.
1344 */
1345static int
1346ATIMach64XVInitialiseAdaptor
1347(
1348    ScrnInfoPtr         pScreenInfo,
1349    XF86VideoAdaptorPtr **pppAdaptor
1350)
1351{
1352    ScreenPtr           pScreen    = xf86ScrnToScreen(pScreenInfo);
1353    ATIPtr              pATI       = ATIPTR(pScreenInfo);
1354    XF86VideoAdaptorPtr *ppAdaptor = NULL;
1355    XF86VideoAdaptorPtr pAdaptor;
1356    int                 Index;
1357
1358    XF86VideoEncodingPtr  enc = &(ATIMach64VideoEncoding[0]);
1359    XF86OffscreenImagePtr surf0 = &(ATIMach64Surface[0]);
1360    XF86OffscreenImagePtr surf1 = &(ATIMach64Surface[1]);
1361
1362    if (xf86NameCmp(pScreenInfo->driverName, MACH64_DRIVER_NAME) != 0)
1363	return 0;
1364
1365    if (pppAdaptor)
1366        *pppAdaptor = NULL;
1367
1368    if (!pATI->Block1Base)
1369        return 0;
1370
1371    if (!(pAdaptor = xf86XVAllocateVideoAdaptorRec(pScreenInfo)))
1372        return 0;
1373
1374    ppAdaptor = xnfalloc(sizeof(pAdaptor));
1375    ppAdaptor[0] = pAdaptor;
1376
1377    pAdaptor->nPorts = 1;
1378    pAdaptor->pPortPrivates = pATI->XVPortPrivate;
1379    pATI->XVPortPrivate[0].ptr = pATI;
1380
1381    pAdaptor->type = XvInputMask | XvImageMask | XvWindowMask;
1382    pAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
1383    pAdaptor->name = "ATI Mach64 Back-end Overlay Scaler";
1384
1385    if (pATI->Chip < ATI_CHIP_264VTB)
1386    {
1387        enc->width = 384;
1388    }
1389    else if (pATI->Chip < ATI_CHIP_264GTPRO ||
1390             pATI->Chip > ATI_CHIP_264LTPRO)
1391    {
1392        enc->width = 720; /* default */
1393    }
1394    else
1395    {
1396        enc->width = 768;
1397    }
1398    pAdaptor->nEncodings = nATIMach64VideoEncoding;
1399    pAdaptor->pEncodings = ATIMach64VideoEncoding;
1400
1401    pAdaptor->nFormats = nATIMach64VideoFormat;
1402    pAdaptor->pFormats = ATIMach64VideoFormat;
1403
1404    pAdaptor->nAttributes = nATIMach64Attribute;
1405    pAdaptor->pAttributes = ATIMach64Attribute;
1406
1407    if (pATI->Chip < ATI_CHIP_264GTPRO)
1408    {
1409        /* Older controllers don't have brightness or saturation controls */
1410        pAdaptor->nAttributes -= 4;
1411        pAdaptor->pAttributes += 4;
1412    }
1413
1414    pAdaptor->nImages = nATIMach64Image;
1415    pAdaptor->pImages = ATIMach64Image;
1416
1417    pAdaptor->StopVideo            = ATIMach64StopVideo;
1418    pAdaptor->SetPortAttribute     = ATIMach64SetPortAttribute;
1419    pAdaptor->GetPortAttribute     = ATIMach64GetPortAttribute;
1420    pAdaptor->QueryBestSize        = ATIMach64QueryBestSize;
1421    pAdaptor->PutImage             = ATIMach64PutImage;
1422    pAdaptor->QueryImageAttributes = ATIMach64QueryImageAttributes;
1423
1424    REGION_NULL(pScreen, &pATI->VideoClip);
1425    pATI->ActiveSurface = FALSE;
1426
1427    if (ATIMach64XVAtomGeneration != serverGeneration)
1428    {
1429        /* Refresh static data */
1430        ATIMach64XVAtomGeneration = serverGeneration;
1431
1432        Index = nATIMach64Attribute - pAdaptor->nAttributes;
1433        for (;  Index < nATIMach64Attribute;  Index++)
1434            ATIMach64AttributeInfo[Index].AttributeID =
1435                MAKE_ATOM(ATIMach64Attribute[Index].name);
1436    }
1437
1438    ATIMach64SetDefaultAttributes(pATI, 0);
1439
1440    if (pATI->Chip < ATI_CHIP_264VTB)
1441    {
1442        surf0->max_width = 384;
1443        surf1->max_width = 384;
1444    }
1445    else if (pATI->Chip < ATI_CHIP_264GTPRO ||
1446             pATI->Chip > ATI_CHIP_264LTPRO)
1447    {
1448        surf0->max_width = 720; /* default */
1449        surf1->max_width = 720;
1450    }
1451    else
1452    {
1453        surf0->max_width = 768;
1454        surf1->max_width = 768;
1455    }
1456
1457    if (pATI->Chip < ATI_CHIP_264GTPRO)
1458    {
1459        /* No saturation nor brightness */
1460        surf0->num_attributes -= 4;
1461        surf1->num_attributes -= 4;
1462        surf0->attributes += 4;
1463        surf1->attributes += 4;
1464    }
1465    xf86XVRegisterOffscreenImages(pScreen, ATIMach64Surface, nATIMach64Surface);
1466
1467    if (pppAdaptor)
1468        *pppAdaptor = ppAdaptor;
1469    else {
1470        free(ppAdaptor[0]);
1471        free(ppAdaptor);
1472    }
1473
1474    return 1;
1475}
1476
1477/*
1478 * ATIXVPreInit --
1479 *
1480 * This function is called by ATIPreInit() to set up the environment required
1481 * to support the XVideo extension.
1482 */
1483void
1484ATIXVPreInit
1485(
1486    ATIPtr      pATI
1487)
1488{
1489    (void)xf86XVRegisterGenericAdaptorDriver(ATIMach64XVInitialiseAdaptor);
1490}
1491
1492/*
1493 * ATIXVFreeAdaptorInfo --
1494 *
1495 * Free XVideo adaptor information.
1496 */
1497static void
1498ATIXVFreeAdaptorInfo
1499(
1500    XF86VideoAdaptorPtr *ppAdaptor,
1501    int                 nAdaptor
1502)
1503{
1504    if (!ppAdaptor)
1505        return;
1506
1507    while (nAdaptor > 0)
1508        free(ppAdaptor[--nAdaptor]);
1509
1510    free(ppAdaptor);
1511}
1512
1513/*
1514 * ATIInitializeXVideo --
1515 *
1516 * This function is called to initialise XVideo extension support on a screen.
1517 */
1518Bool
1519ATIInitializeXVideo
1520(
1521    ScreenPtr   pScreen,
1522    ScrnInfoPtr pScreenInfo,
1523    ATIPtr      pATI
1524)
1525{
1526    XF86VideoAdaptorPtr *ppAdaptor;
1527    int                 nAdaptor;
1528    Bool                result;
1529
1530    pScreenInfo->memPhysBase = pATI->LinearBase;
1531    pScreenInfo->fbOffset = 0;
1532
1533    nAdaptor = xf86XVListGenericAdaptors(pScreenInfo, &ppAdaptor);
1534    result = xf86XVScreenInit(pScreen, ppAdaptor, nAdaptor);
1535
1536    ATIXVFreeAdaptorInfo(ppAdaptor, nAdaptor);
1537
1538    return result;
1539}
1540
1541/*
1542 * ATIMach64CloseXVideo --
1543 *
1544 * This function is called during screen termination to clean up after
1545 * initialisation of Mach64 XVideo support.
1546 */
1547void
1548ATICloseXVideo
1549(
1550    ScreenPtr   pScreen,
1551    ScrnInfoPtr pScreenInfo,
1552    ATIPtr      pATI
1553)
1554{
1555    if (!pATI->Block1Base)
1556        return;
1557
1558    ATIMach64StopVideo(pScreenInfo, pATI, TRUE);
1559
1560    REGION_UNINIT(pScreen, &pATI->VideoClip);
1561}
1562
1563/* Functions for offscreen memory management */
1564
1565#ifdef USE_XAA
1566static FBLinearPtr
1567ATIResizeOffscreenLinear
1568(
1569    ScreenPtr   pScreen,
1570    FBLinearPtr pLinear,
1571    int         Size
1572)
1573{
1574    if (Size <= 0)
1575    {
1576        xf86FreeOffscreenLinear(pLinear);
1577        return NULL;
1578    }
1579
1580    if (pLinear)
1581    {
1582        if ((pLinear->size >= Size) ||
1583            xf86ResizeOffscreenLinear(pLinear, Size))
1584        {
1585            pLinear->MoveLinearCallback = NULL;
1586            pLinear->RemoveLinearCallback = NULL;
1587            return pLinear;
1588        }
1589
1590        xf86FreeOffscreenLinear(pLinear);
1591    }
1592
1593    pLinear = xf86AllocateOffscreenLinear(pScreen, Size, 16, NULL, NULL, NULL);
1594
1595    if (!pLinear)
1596    {
1597        int maxSize;
1598
1599        xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16,
1600            PRIORITY_EXTREME);
1601
1602        if (maxSize < Size)
1603            return NULL;
1604
1605        xf86PurgeUnlockedOffscreenAreas(pScreen);
1606        pLinear =
1607            xf86AllocateOffscreenLinear(pScreen, Size, 16, NULL, NULL, NULL);
1608    }
1609
1610    return pLinear;
1611}
1612#endif /* USE_XAA */
1613
1614static pointer
1615ATIMach64XVMemAlloc
1616(
1617    ScreenPtr pScreen,
1618    pointer   pVideo,
1619    int       size,
1620    int       *offset,
1621    ATIPtr    pATI
1622)
1623{
1624#ifdef USE_EXA
1625    if (pATI->useEXA) {
1626        ExaOffscreenArea *area = (ExaOffscreenArea *)pVideo;
1627
1628        if (area != NULL) {
1629            if (area->size >= size) {
1630                *offset = area->offset;
1631                return area;
1632            }
1633
1634            exaOffscreenFree(pScreen, area);
1635        }
1636
1637        area = exaOffscreenAlloc(pScreen, size, 64, TRUE, NULL, NULL);
1638        if (area != NULL) {
1639            *offset = area->offset;
1640            return area;
1641        }
1642    }
1643#endif /* USE_EXA */
1644
1645#ifdef USE_XAA
1646    if (!pATI->useEXA) {
1647        FBLinearPtr linear = (FBLinearPtr)pVideo;
1648        int cpp = pATI->AdjustDepth;
1649
1650        /* XAA allocates in units of pixels at the screen bpp, so adjust size
1651         * appropriately.
1652         */
1653        size = (size + cpp - 1) / cpp;
1654
1655        linear = ATIResizeOffscreenLinear(pScreen, linear, size);
1656        if (linear != NULL) {
1657            *offset = linear->offset * cpp;
1658            return linear;
1659        }
1660    }
1661#endif /* USE_XAA */
1662
1663    *offset = 0;
1664    return NULL;
1665}
1666
1667static void
1668ATIMach64XVMemFree
1669(
1670    ScreenPtr pScreen,
1671    pointer   pVideo,
1672    ATIPtr    pATI
1673)
1674{
1675#ifdef USE_EXA
1676    if (pATI->useEXA) {
1677        ExaOffscreenArea *area = (ExaOffscreenArea *)pVideo;
1678
1679        if (area != NULL)
1680            exaOffscreenFree(pScreen, area);
1681    }
1682#endif /* USE_EXA */
1683
1684#ifdef USE_XAA
1685    if (!pATI->useEXA) {
1686        FBLinearPtr linear = (FBLinearPtr)pVideo;
1687
1688        if (linear != NULL)
1689            ATIResizeOffscreenLinear(pScreen, linear, 0);
1690    }
1691#endif /* USE_XAA */
1692}
1693
1694