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