gx_video.c revision 04007eba
1/* Copyright (c) 2003-2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPDIs2IED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26/*
27 * File Contents:   This file consists of main Xfree video supported routines.
28 *
29 * Project:         Geode Xfree Frame buffer device driver.
30 * */
31
32/*
33 * Fixes & Extensions to support Y800 greyscale modes
34 * Alan Hourihane <alanh@fairlite.demon.co.uk>
35
36 * code to allocate offscreen memory from EXA - is borrowed from Radeon
37 */
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <stdlib.h>
44#include <string.h>
45
46#include "xf86.h"
47#include "xf86_OSproc.h"
48#include "compiler.h"
49#include "xf86PciInfo.h"
50#include "xf86Pci.h"
51#include "xf86fbman.h"
52#include "regionstr.h"
53
54#include "geode.h"
55#include "xf86xv.h"
56#include <X11/extensions/Xv.h>
57#ifdef HAVE_XAA_H
58#include "xaa.h"
59#include "xaalocal.h"
60#endif
61#include "dixstruct.h"
62#include "fourcc.h"
63#include "geode_fourcc.h"
64
65#define OFF_DELAY 		200     /* milliseconds */
66#define FREE_DELAY 		60000
67
68#define OFF_TIMER 		0x01
69#define FREE_TIMER		0x02
70#define CLIENT_VIDEO_ON	0x04
71
72#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
73#define XV_PROFILE 		0
74#define REINIT  		1
75
76#ifndef XvExtension
77#error "It didn't work!"
78void
79GXInitVideo(ScreenPtr pScrn)
80{
81}
82
83void
84GXResetVideo(ScrnInfoPtr pScrni)
85{
86}
87
88void
89GXSetVideoPosition()
90{
91}
92#else
93
94#define DBUF 1
95void GXResetVideo(ScrnInfoPtr pScrni);
96static XF86VideoAdaptorPtr GXSetupImageVideo(ScreenPtr);
97static void GXInitOffscreenImages(ScreenPtr);
98static void GXStopVideo(ScrnInfoPtr, pointer, Bool);
99static int GXSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
100static int GXGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
101static void GXQueryBestSize(ScrnInfoPtr, Bool,
102                            short, short, short, short, unsigned int *,
103                            unsigned int *, pointer);
104static int GXPutImage(ScrnInfoPtr, short, short, short, short, short, short,
105                      short, short, int, unsigned char *, short, short, Bool,
106                      RegionPtr, pointer, DrawablePtr pDraw);
107
108static void GXBlockHandler(BLOCKHANDLER_ARGS_DECL);
109void GXSetVideoPosition(int x, int y, int width, int height,
110                        short src_w, short src_h, short drw_w,
111                        short drw_h, int id, int offset, ScrnInfoPtr pScrni);
112
113extern void GXAccelSync(ScrnInfoPtr pScrni);
114
115int DeltaX, DeltaY;
116
117unsigned long graphics_lut[256];
118static int lutflag = 0;
119
120#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
121
122static Atom xvColorKey, xvColorKeyMode, xvFilter
123#if DBUF
124, xvDoubleBuffer
125#endif
126;
127
128#define PALETTE_ADDRESS   0x038
129#define PALETTE_DATA      0x040
130#define DISPLAY_CONFIG    0x008
131#define MISC              0x050
132
133static void
134get_gamma_ram(unsigned long *lut)
135{
136
137    int i;
138
139    gfx_write_vid32(PALETTE_ADDRESS, 0);
140
141    for (i = 0; i < 256; i++)
142        lut[i] = gfx_read_vid32(PALETTE_DATA);
143}
144
145/*----------------------------------------------------------------------------
146 * GXInitVideo
147 *
148 * Description	:This is the initialization routine.It creates a new video
149 * 				adapter and calls GXSetupImageVideo to initialize the adaptor
150 * 				by filling XF86VideoAdaptorREc.Then it lists the existing
151 * 				adaptors and adds the new one to it. Finally the list of
152 * 				XF86VideoAdaptorPtr pointers are passed to the
153 * 				xf86XVScreenInit().
154 *
155 * Parameters.
156 *		pScrn	:Screen handler pointer having screen information.
157 *
158 * Returns		:none
159 *
160 * Comments		:none
161 *----------------------------------------------------------------------------
162 */
163void
164GXInitVideo(ScreenPtr pScrn)
165{
166    GeodeRec *pGeode;
167    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
168
169    pGeode = GEODEPTR(pScrni);
170
171    if (!pGeode->NoAccel) {
172        XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
173        XF86VideoAdaptorPtr newAdaptor = NULL;
174
175        int num_adaptors;
176
177        newAdaptor = GXSetupImageVideo(pScrn);
178        GXInitOffscreenImages(pScrn);
179
180        num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
181
182        if (newAdaptor) {
183            if (!num_adaptors) {
184                num_adaptors = 1;
185                adaptors = &newAdaptor;
186            }
187            else {
188                newAdaptors =   /* need to free this someplace */
189                    malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
190                if (newAdaptors) {
191                    memcpy(newAdaptors, adaptors, num_adaptors *
192                           sizeof(XF86VideoAdaptorPtr));
193                    newAdaptors[num_adaptors] = newAdaptor;
194                    adaptors = newAdaptors;
195                    num_adaptors++;
196                }
197            }
198        }
199
200        if (num_adaptors)
201            xf86XVScreenInit(pScrn, adaptors, num_adaptors);
202
203        if (newAdaptors)
204            free(newAdaptors);
205    }
206}
207
208/* client libraries expect an encoding */
209static XF86VideoEncodingRec DummyEncoding[1] = {
210    {
211     0,
212     "XV_IMAGE",
213     1024, 1024,
214     {1, 1}
215     }
216};
217
218#define NUM_FORMATS 4
219
220static XF86VideoFormatRec Formats[NUM_FORMATS] = {
221    {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
222};
223
224#if DBUF
225#define NUM_ATTRIBUTES 4
226#else
227#define NUM_ATTRIBUTES 3
228#endif
229
230static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
231#if DBUF
232    {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
233#endif
234    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
235    {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
236    {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
237};
238
239#define NUM_IMAGES 8
240
241static XF86ImageRec Images[NUM_IMAGES] = {
242    XVIMAGE_UYVY,
243    XVIMAGE_YUY2,
244    XVIMAGE_Y2YU,
245    XVIMAGE_YVYU,
246    XVIMAGE_Y800,
247    XVIMAGE_I420,
248    XVIMAGE_YV12,
249    XVIMAGE_RGB565
250};
251
252typedef struct {
253    void *area;
254    int offset;
255    RegionRec clip;
256    CARD32 filter;
257    CARD32 colorKey;
258    CARD32 colorKeyMode;
259    CARD32 videoStatus;
260    Time offTime;
261    Time freeTime;
262#if DBUF
263    Bool doubleBuffer;
264    int currentBuffer;
265#endif
266} GeodePortPrivRec, *GeodePortPrivPtr;
267
268#define GET_PORT_PRIVATE(pScrni) \
269   (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr)
270
271/*----------------------------------------------------------------------------
272 * GXSetColorKey
273 *
274 * Description	:This function reads the color key for the pallete and
275 *				  sets the video color key register.
276 *
277 * Parameters.
278 * ScreenInfoPtr
279 *		pScrni	:Screen  pointer having screen information.
280 *		pPriv	:Video port private data
281 *
282 * Returns		:none
283 *
284 * Comments		:none
285 *
286 *----------------------------------------------------------------------------
287 */
288static INT32
289GXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv)
290{
291    int red, green, blue;
292    unsigned long key;
293
294    switch (pScrni->depth) {
295    case 8:
296        GFX(get_display_palette_entry(pPriv->colorKey & 0xFF, &key));
297        red = ((key >> 16) & 0xFF);
298        green = ((key >> 8) & 0xFF);
299        blue = (key & 0xFF);
300        break;
301    case 16:
302        red = (pPriv->colorKey & pScrni->mask.red) >>
303            pScrni->offset.red << (8 - pScrni->weight.red);
304        green = (pPriv->colorKey & pScrni->mask.green) >>
305            pScrni->offset.green << (8 - pScrni->weight.green);
306        blue = (pPriv->colorKey & pScrni->mask.blue) >>
307            pScrni->offset.blue << (8 - pScrni->weight.blue);
308        break;
309    default:
310        /* for > 16 bpp we send in the mask in xf86SetWeight. This
311         * function is providing the offset by 1 more. So we take
312         * this as a special case and subtract 1 for > 16
313         */
314        red = (pPriv->colorKey & pScrni->mask.red) >>
315            (pScrni->offset.red - 1) << (8 - pScrni->weight.red);
316        green = (pPriv->colorKey & pScrni->mask.green) >>
317            (pScrni->offset.green - 1) << (8 - pScrni->weight.green);
318        blue = (pPriv->colorKey & pScrni->mask.blue) >>
319            (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue);
320        break;
321    }
322
323    GFX(set_video_color_key((blue | (green << 8) | (red << 16)), 0xFFFFFF,
324                            (pPriv->colorKeyMode == 0)));
325    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
326    return 0;
327}
328
329/*----------------------------------------------------------------------------
330 * GXResetVideo
331 *
332 * Description	: This function resets the video
333 *
334 * Parameters.
335 *		pScrni	:Screen  pointer having screen information.
336 *
337 * Returns		:None
338 *
339 * Comments		:none
340 *
341 *----------------------------------------------------------------------------
342 */
343void
344GXResetVideo(ScrnInfoPtr pScrni)
345{
346    GeodeRec *pGeode = GEODEPTR(pScrni);
347
348    if (!pGeode->NoAccel) {
349        GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
350
351        GXAccelSync(pScrni);
352        GXSetColorkey(pScrni, pPriv);
353        GFX(set_video_filter(pPriv->filter, pPriv->filter));
354    }
355}
356
357/*----------------------------------------------------------------------------
358 * GXSetupImageVideo
359 *
360 * Description	: This function allocates space for a Videoadaptor and
361 * 				initializes the XF86VideoAdaptorPtr record.
362 *
363 * Parameters.
364 *		pScrn	:Screen handler pointer having screen information.
365 *
366 * Returns		:pointer to the initialized video adaptor record.
367 *
368 * Comments		:none
369 *----------------------------------------------------------------------------
370 */
371static XF86VideoAdaptorPtr
372GXSetupImageVideo(ScreenPtr pScrn)
373{
374    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
375    GeodeRec *pGeode = GEODEPTR(pScrni);
376    XF86VideoAdaptorPtr adapt;
377    GeodePortPrivRec *pPriv;
378
379    if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
380                         sizeof(GeodePortPrivRec) + sizeof(DevUnion))))
381        return NULL;
382
383    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
384    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
385    adapt->name = "Advanced Micro Devices";
386    adapt->nEncodings = 1;
387    adapt->pEncodings = DummyEncoding;
388    adapt->nFormats = NUM_FORMATS;
389    adapt->pFormats = Formats;
390    adapt->nPorts = 1;
391    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
392    pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
393    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
394    adapt->pAttributes = Attributes;
395    adapt->nImages = NUM_IMAGES;
396    adapt->nAttributes = NUM_ATTRIBUTES;
397    adapt->pImages = Images;
398    adapt->PutVideo = NULL;
399    adapt->PutStill = NULL;
400    adapt->GetVideo = NULL;
401    adapt->GetStill = NULL;
402    adapt->StopVideo = GXStopVideo;
403    adapt->SetPortAttribute = GXSetPortAttribute;
404    adapt->GetPortAttribute = GXGetPortAttribute;
405    adapt->QueryBestSize = GXQueryBestSize;
406    adapt->PutImage = GXPutImage;
407    adapt->QueryImageAttributes = GeodeQueryImageAttributes;
408
409    pPriv->filter = 0;
410    pPriv->colorKey = 0;
411    pPriv->colorKeyMode = 0;
412    pPriv->videoStatus = 0;
413#if DBUF
414    pPriv->doubleBuffer = TRUE;
415    pPriv->currentBuffer = 0;   /* init to first buffer */
416#endif
417
418    /* gotta uninit this someplace */
419#if defined(REGION_NULL)
420    REGION_NULL(pScrn, &pPriv->clip);
421#else
422    REGION_INIT(pScrn, &pPriv->clip, NullBox, 0);
423#endif
424
425    pGeode->adaptor = adapt;
426
427    pGeode->BlockHandler = pScrn->BlockHandler;
428    pScrn->BlockHandler = GXBlockHandler;
429
430    xvColorKey = MAKE_ATOM("XV_COLORKEY");
431    xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
432    xvFilter = MAKE_ATOM("XV_FILTER");
433#if DBUF
434    xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
435#endif
436
437    GXResetVideo(pScrni);
438
439    return adapt;
440}
441
442/*----------------------------------------------------------------------------
443 * GXStopVideo
444 *
445 * Description	:This function is used to stop input and output video
446 *
447 * Parameters.
448 *		pScrni	:Screen handler pointer having screen information.
449 *		data	:Pointer to the video port's private data
450 *		exit	:Flag indicating whether the offscreen areas used for
451 *				video to be deallocated or not.
452 *
453 * Returns		:none
454 *
455 * Comments		:none
456 *----------------------------------------------------------------------------
457 */
458static void
459GXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
460{
461    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
462    GeodeRec *pGeode = GEODEPTR(pScrni);
463
464    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
465
466    GXAccelSync(pScrni);
467    if (exit) {
468        if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
469            GFX(set_video_enable(0));
470
471            /* If we have saved graphics LUT data - restore it */
472            /* Otherwise, turn bypass on */
473
474            if (lutflag)
475                GFX(set_graphics_palette(graphics_lut));
476            else
477                GFX(set_video_palette_bypass(1));
478
479            lutflag = 0;
480        }
481
482        if (pPriv->area) {
483#ifdef XF86EXA
484            if (pGeode->useEXA)
485                exaOffscreenFree(pScrni->pScreen, pPriv->area);
486#endif
487
488            if (!pGeode->useEXA)
489                xf86FreeOffscreenArea(pPriv->area);
490
491            pPriv->area = NULL;
492        }
493
494        pPriv->videoStatus = 0;
495        pGeode->OverlayON = FALSE;
496    }
497    else {
498        if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
499            pPriv->videoStatus |= OFF_TIMER;
500            pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
501        }
502    }
503}
504
505/*----------------------------------------------------------------------------
506 * GXSetPortAttribute
507 *
508 * Description		:This function is used to set the attributes of a port
509 * 					like colorkeymode, double buffer support and filter.
510 *
511 * Parameters.
512 *		pScrni		:Screen handler pointer having screen information.
513 *		data		:Pointer to the video port's private data
514 *		attribute	:The port attribute to be set
515 *		value		:Value of the attribute to be set.
516 *
517 * Returns			:Sucess if the attribute is supported, else BadMatch
518 *
519 * Comments			:none
520 *----------------------------------------------------------------------------
521 */
522static int
523GXSetPortAttribute(ScrnInfoPtr pScrni,
524                   Atom attribute, INT32 value, pointer data)
525{
526    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
527
528    GXAccelSync(pScrni);
529    if (attribute == xvColorKey) {
530        pPriv->colorKey = value;
531        GXSetColorkey(pScrni, pPriv);
532    }
533#if DBUF
534    else if (attribute == xvDoubleBuffer) {
535        if ((value < 0) || (value > 1))
536            return BadValue;
537        pPriv->doubleBuffer = value;
538    }
539#endif
540    else if (attribute == xvColorKeyMode) {
541        pPriv->colorKeyMode = value;
542        GXSetColorkey(pScrni, pPriv);
543    }
544    else if (attribute == xvFilter) {
545        if ((value < 0) || (value > 1))
546            return BadValue;
547        pPriv->filter = value;
548    }
549    else
550        return BadMatch;
551
552    return Success;
553}
554
555/*----------------------------------------------------------------------------
556 * GXGetPortAttribute
557 *
558 * Description		:This function is used to get the attributes of a port
559 * 					like hue, saturation,brightness or contrast.
560 *
561 * Parameters.
562 *		pScrni		:Screen handler pointer having screen information.
563 *		data		:Pointer to the video port's private data
564 *		attribute	:The port attribute to be read
565 *		value		:Pointer to the value of the attribute to be read.
566 *
567 * Returns			:Sucess if the attribute is supported, else BadMatch
568 *
569 * Comments			:none
570 *----------------------------------------------------------------------------
571 */
572static int
573GXGetPortAttribute(ScrnInfoPtr pScrni,
574                   Atom attribute, INT32 *value, pointer data)
575{
576    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
577
578    if (attribute == xvColorKey) {
579        *value = pPriv->colorKey;
580    }
581#if DBUF
582    else if (attribute == xvDoubleBuffer) {
583        *value = (pPriv->doubleBuffer) ? 1 : 0;
584    }
585#endif
586    else if (attribute == xvColorKeyMode) {
587        *value = pPriv->colorKeyMode;
588    }
589    else if (attribute == xvFilter) {
590        *value = pPriv->filter;
591    }
592    else
593        return BadMatch;
594
595    return Success;
596}
597
598/*----------------------------------------------------------------------------
599 * GXQueryBestSize
600 *
601 * Description		:This function provides a way to query what the
602 * 					destination dimensions would end up being if they were to
603 * 					request that an area vid_w by vid_h from the video stream
604 * 					be scaled to rectangle of drw_w by drw_h on the screen.
605 *
606 * Parameters.
607 *		pScrni		:Screen handler pointer having screen information.
608 *		data		:Pointer to the video port's private data
609 *      vid_w,vid_h	:Width and height of the video data.
610 *		drw_w,drw_h :Width and height of the scaled rectangle.
611 *		p_w,p_h		:Width and height of the destination rectangle.
612 *
613 * Returns			:None
614 *
615 * Comments			:None
616 *----------------------------------------------------------------------------
617 */
618static void
619GXQueryBestSize(ScrnInfoPtr pScrni,
620                Bool motion,
621                short vid_w, short vid_h,
622                short drw_w, short drw_h,
623                unsigned int *p_w, unsigned int *p_h, pointer data)
624{
625    *p_w = drw_w;
626    *p_h = drw_h;
627
628    if (*p_w > 16384)
629        *p_w = 16384;
630}
631
632/*----------------------------------------------------------------------------
633 * GXCopyData420
634 *
635 * Description		: Copies data from src to destination
636 *
637 * Parameters.
638 *		src			: pointer to the source data
639 *		dst			: pointer to destination data
640 *		srcPitch	: pitch of the srcdata
641 *		dstPitch	: pitch of the destination data
642 *		h & w		: height and width of source data
643 *
644 * Returns			:None
645 *
646 * Comments			:None
647 *----------------------------------------------------------------------------
648 */
649static void
650GXCopyData420(unsigned char *src, unsigned char *dst,
651              int srcPitch, int dstPitch, int h, int w)
652{
653    while (h--) {
654        memcpy(dst, src, w);
655        src += srcPitch;
656        dst += dstPitch;
657    }
658}
659
660/*----------------------------------------------------------------------------
661 * GXCopyData422
662 *
663 * Description		: Copies data from src to destination
664 *
665 * Parameters.
666 *		src			: pointer to the source data
667 *		dst			: pointer to destination data
668 *		srcPitch	: pitch of the srcdata
669 *		dstPitch	: pitch of the destination data
670 *		h & w		: height and width of source data
671 *
672 * Returns			:None
673 *
674 * Comments			:None
675 *----------------------------------------------------------------------------
676 */
677static void
678GXCopyData422(unsigned char *src, unsigned char *dst,
679              int srcPitch, int dstPitch, int h, int w)
680{
681    w <<= 1;
682    while (h--) {
683        memcpy(dst, src, w);
684        src += srcPitch;
685        dst += dstPitch;
686    }
687}
688
689#ifdef XF86EXA
690static void
691GXVideoSave(ScreenPtr pScreen, ExaOffscreenArea * area)
692{
693    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
694    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
695
696    if (area == pPriv->area)
697        pPriv->area = NULL;
698}
699#endif
700
701static int
702GXAllocateMemory(ScrnInfoPtr pScrni, void **memp, int numlines)
703{
704    ScreenPtr pScrn = xf86ScrnToScreen(pScrni);
705    GeodeRec *pGeode = GEODEPTR(pScrni);
706
707    //long displayWidth = pGeode->Pitch / ((pScrni->bitsPerPixel + 7) / 8);
708    int size = numlines * pGeode->displayWidth;
709
710#if XF86EXA
711    if (pGeode->useEXA) {
712        ExaOffscreenArea *area = *memp;
713
714        if (area != NULL) {
715            if (area->size >= size)
716                return area->offset;
717
718            exaOffscreenFree(pScrni->pScreen, area);
719        }
720
721        area = exaOffscreenAlloc(pScrni->pScreen, size, 16,
722                                 TRUE, GXVideoSave, NULL);
723        *memp = area;
724
725        return area == NULL ? 0 : area->offset;
726    }
727#endif
728
729    if (!pGeode->useEXA) {
730        FBAreaPtr area = *memp;
731        FBAreaPtr new_area;
732
733        if (area) {
734            if ((area->box.y2 - area->box.y1) >= numlines)
735                return (area->box.y1 * pGeode->Pitch);
736
737            if (xf86ResizeOffscreenArea(area, pGeode->displayWidth, numlines))
738                return (area->box.y1 * pGeode->Pitch);
739
740            xf86FreeOffscreenArea(area);
741        }
742
743        new_area = xf86AllocateOffscreenArea(pScrn, pGeode->displayWidth,
744                                             numlines, 0, NULL, NULL, NULL);
745
746        if (!new_area) {
747            int max_w, max_h;
748
749            xf86QueryLargestOffscreenArea(pScrn, &max_w, &max_h, 0,
750                                          FAVOR_WIDTH_THEN_AREA,
751                                          PRIORITY_EXTREME);
752
753            if ((max_w < pGeode->displayWidth) || (max_h < numlines)) {
754                xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
755                           "No room - how sad %x, %x, %x, %x\n", max_w,
756                           pGeode->displayWidth, max_h, numlines);
757                return 0;
758            }
759
760            xf86PurgeUnlockedOffscreenAreas(pScrn);
761            new_area = xf86AllocateOffscreenArea(pScrn, pGeode->displayWidth,
762                                                 numlines, 0, NULL, NULL, NULL);
763        }
764
765        return (new_area->box.y1 * pGeode->Pitch);
766    }
767
768    return 0;
769}
770
771static BoxRec dstBox;
772static int srcPitch = 0, srcPitch2 = 0, dstPitch = 0, dstPitch2 = 0;
773static INT32 Bx1, Bx2, By1, By2;
774static int top, left, npixels, nlines;
775static int offset, s1offset = 0, s2offset = 0, s3offset = 0;
776static unsigned char *dst_start;
777static int d2offset = 0, d3offset = 0;
778
779#if 0
780static Bool
781RegionsIntersect(BoxPtr pRcl1, BoxPtr pRcl2, BoxPtr pRclResult)
782{
783    pRclResult->x1 = max(pRcl1->x1, pRcl2->x1);
784    pRclResult->x2 = min(pRcl1->x2, pRcl2->x2);
785
786    if (pRclResult->x1 <= pRclResult->x2) {
787        pRclResult->y1 = max(pRcl1->y1, pRcl2->y1);
788        pRclResult->y2 = min(pRcl1->y2, pRcl2->y2);
789
790        if (pRclResult->y1 <= pRclResult->y2) {
791            return (TRUE);
792        }
793    }
794
795    return (FALSE);
796}
797#endif
798
799void
800GXSetVideoPosition(int x, int y, int width, int height,
801                   short src_w, short src_h, short drw_w, short drw_h,
802                   int id, int offset, ScrnInfoPtr pScrni)
803{
804    GeodeRec *pGeode = GEODEPTR(pScrni);
805    long ystart, xend, yend;
806    unsigned long lines = 0;
807    unsigned long y_extra, uv_extra = 0;
808    unsigned long startAddress;
809
810#if 0
811    BoxRec ovly, display, result;
812#endif
813
814    xend = x + drw_w;
815    yend = y + drw_h;
816
817    /* Take care of panning when panel is present */
818
819    startAddress = gfx_get_display_offset();
820    DeltaY = startAddress / pGeode->Pitch;
821    DeltaX = startAddress & (pGeode->Pitch - 1);
822    DeltaX /= (pScrni->bitsPerPixel >> 3);
823
824#if 0
825    /* Thhis code is pretty dang broken - comment it out for now */
826
827    if (pGeode->Panel) {
828        ovly.x1 = x;
829        ovly.x2 = x + pGeode->video_dstw;
830        ovly.y1 = y;
831        ovly.y2 = y + pGeode->video_dsth;
832
833        display.x1 = DeltaX;
834        display.x2 = DeltaX + pGeode->FPBX;
835        display.y1 = DeltaY;
836        display.y2 = DeltaY + pGeode->FPBY;
837        x = xend = 0;
838        if (RegionsIntersect(&display, &ovly, &result)) {
839            x = ovly.x1 - DeltaX;
840            xend = ovly.x2 - DeltaX;
841            y = ovly.y1 - DeltaY;
842            yend = ovly.y2 - DeltaY;
843        }
844    }
845#endif
846
847    /*  TOP CLIPPING */
848
849    if (y < 0) {
850        if (src_h < drw_h)
851            lines = (-y) * src_h / drw_h;
852        else
853            lines = (-y);
854        ystart = 0;
855        drw_h += y;
856        y_extra = lines * dstPitch;
857        uv_extra = (lines >> 1) * (dstPitch2);
858    }
859    else {
860        ystart = y;
861        lines = 0;
862        y_extra = 0;
863    }
864
865    GFX(set_video_window(x, ystart, xend - x, yend - ystart));
866
867    if ((id == FOURCC_Y800) || (id == FOURCC_I420) || (id == FOURCC_YV12)) {
868        GFX(set_video_yuv_offsets(offset + y_extra,
869                                  offset + d3offset + uv_extra,
870                                  offset + d2offset + uv_extra));
871    }
872    else {
873        GFX(set_video_offset(offset + y_extra));
874    }
875}
876
877/*----------------------------------------------------------------------------
878 * GXDisplayVideo
879 *
880 * Description	:This function sets up the video registers for playing video
881 * 				It sets up the video format,width, height & position of the
882 *		  		video window ,video offsets( y,u,v) and video pitches(y,u,v)
883 *
884 * Parameters
885 *
886 * Returns		:None
887 *
888 * Comments		:None
889 *----------------------------------------------------------------------------
890 */
891
892static void
893GXDisplayVideo(ScrnInfoPtr pScrni,
894               int id,
895               int offset,
896               short width, short height,
897               int pitch,
898               int x1, int y1, int x2, int y2,
899               BoxPtr dstBox, short src_w, short src_h, short drw_w,
900               short drw_h)
901{
902    GeodeRec *pGeode = GEODEPTR(pScrni);
903    unsigned long dcfg, misc;
904
905    GXAccelSync(pScrni);
906
907    /* If the gamma LUT is already loaded with graphics data, then save it
908     * off
909     */
910
911    if (id != FOURCC_RGB565) {
912        dcfg = gfx_read_vid32(DISPLAY_CONFIG);
913        misc = gfx_read_vid32(MISC);
914
915        lutflag = (!(misc & 1) && (dcfg & (1 << 21)));
916
917        if (lutflag)
918            get_gamma_ram(graphics_lut);
919
920        /* Set the video gamma ram */
921        GFX(set_video_palette(NULL));
922    }
923
924    GFX(set_video_enable(1));
925
926    switch (id) {
927    case FOURCC_UYVY:          /* UYVY */
928        GFX(set_video_format(VIDEO_FORMAT_UYVY));
929        GFX(set_video_size(width, height));
930        break;
931    case FOURCC_Y800:          /* Y800 - greyscale - we munge it! */
932    case FOURCC_YV12:          /* YV12 */
933    case FOURCC_I420:          /* I420 */
934        GFX(set_video_format(VIDEO_FORMAT_Y0Y1Y2Y3));
935        GFX(set_video_size(width, height));
936        GFX(set_video_yuv_pitch(dstPitch, dstPitch2));
937        break;
938    case FOURCC_YUY2:          /* YUY2 */
939        GFX(set_video_format(VIDEO_FORMAT_YUYV));
940        GFX(set_video_size(width, height));
941        break;
942    case FOURCC_Y2YU:          /* Y2YU */
943        GFX(set_video_format(VIDEO_FORMAT_Y2YU));
944        GFX(set_video_size(width, height));
945        break;
946    case FOURCC_YVYU:          /* YVYU */
947        GFX(set_video_format(VIDEO_FORMAT_YVYU));
948        GFX(set_video_size(width, height));
949        break;
950    case FOURCC_RGB565:
951        GFX(set_video_format(VIDEO_FORMAT_RGB));
952        GFX(set_video_size(width, height));
953        break;
954
955    }
956
957    if (pGeode->Panel) {
958        pGeode->video_x = dstBox->x1;
959        pGeode->video_y = dstBox->y1;
960        pGeode->video_w = width;
961        pGeode->video_h = height;
962        pGeode->video_srcw = src_w;
963        pGeode->video_srch = src_h;
964        pGeode->video_dstw = drw_w;
965        pGeode->video_dsth = drw_h;
966        pGeode->video_offset = offset;
967        pGeode->video_id = id;
968        pGeode->video_scrnptr = pScrni;
969    }
970
971    if ((drw_w >= src_w) && (drw_h >= src_h))
972        GFX(set_video_scale(width, height, drw_w, drw_h));
973    else if (drw_w < src_w)
974        GFX(set_video_scale(drw_w, height, drw_w, drw_h));
975    else if (drw_h < src_h)
976        GFX(set_video_scale(width, drw_h, drw_w, drw_h));
977
978    GXSetVideoPosition(dstBox->x1, dstBox->y1, width, height, src_w,
979                       src_h, drw_w, drw_h, id, offset, pScrni);
980}
981
982/* Used by LX as well */
983
984Bool
985RegionsEqual(RegionPtr A, RegionPtr B)
986{
987    int *dataA, *dataB;
988    int num;
989
990    num = REGION_NUM_RECTS(A);
991    if (num != REGION_NUM_RECTS(B)) {
992        return FALSE;
993    }
994
995    if ((A->extents.x1 != B->extents.x1) ||
996        (A->extents.x2 != B->extents.x2) ||
997        (A->extents.y1 != B->extents.y1) || (A->extents.y2 != B->extents.y2))
998        return FALSE;
999
1000    dataA = (int *) REGION_RECTS(A);
1001    dataB = (int *) REGION_RECTS(B);
1002
1003    while (num--) {
1004        if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1]))
1005            return FALSE;
1006
1007        dataA += 2;
1008        dataB += 2;
1009    }
1010
1011    return TRUE;
1012}
1013
1014/*----------------------------------------------------------------------------
1015 * GXPutImage	:This function writes a single frame of video into a
1016 * 				drawable. The position and size of the source rectangle is
1017 * 				specified by src_x,src_y, src_w and src_h. This data is
1018 * 				stored in a system memory buffer at buf. The position and
1019 * 				size of the destination rectangle is specified by drw_x,
1020 * 				drw_y,drw_w,drw_h.The data is in the format indicated by the
1021 * 				image descriptor and represents a source of size width by
1022 * 				height.  If sync is TRUE the driver should not return from
1023 * 				this function until it is through reading the data from buf.
1024 * 				Returning when sync is TRUE indicates that it is safe for the
1025 * 				data at buf to be replaced,freed, or modified.
1026 *
1027 * Parameters.
1028 *
1029 * Returns		:None
1030 *
1031 * Comments		:None
1032 *----------------------------------------------------------------------------
1033 */
1034
1035static int
1036GXPutImage(ScrnInfoPtr pScrni,
1037           short src_x, short src_y,
1038           short drw_x, short drw_y,
1039           short src_w, short src_h,
1040           short drw_w, short drw_h,
1041           int id, unsigned char *buf,
1042           short width, short height, Bool sync, RegionPtr clipBoxes,
1043           pointer data, DrawablePtr pDraw)
1044{
1045    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
1046    GeodeRec *pGeode = GEODEPTR(pScrni);
1047    int new_h;
1048
1049#if REINIT
1050    BOOL ReInitVideo = FALSE;
1051    static BOOL DoReinitAgain = 0;
1052#endif
1053
1054#if XV_PROFILE
1055    long oldtime, newtime;
1056
1057    UpdateCurrentTime();
1058    oldtime = currentTime.milliseconds;
1059#endif
1060
1061#if REINIT
1062/* update cliplist */
1063    if (!RegionsEqual(&pPriv->clip, clipBoxes)) {
1064        ReInitVideo = TRUE;
1065    }
1066
1067    if (DoReinitAgain)
1068        ReInitVideo = TRUE;
1069
1070    if (ReInitVideo) {
1071        DEBUGMSG(1, (0, X_NONE, "Regional Not Equal - Init\n"));
1072#endif
1073        DoReinitAgain = ~DoReinitAgain;
1074        if (drw_w > 16384)
1075            drw_w = 16384;
1076
1077        /* Clip */
1078        Bx1 = src_x;
1079        Bx2 = src_x + src_w;
1080        By1 = src_y;
1081        By2 = src_y + src_h;
1082
1083        if ((Bx1 >= Bx2) || (By1 >= By2))
1084            return Success;
1085
1086        dstBox.x1 = drw_x;
1087        dstBox.x2 = drw_x + drw_w;
1088        dstBox.y1 = drw_y;
1089        dstBox.y2 = drw_y + drw_h;
1090
1091        dstBox.x1 -= pScrni->frameX0;
1092        dstBox.x2 -= pScrni->frameX0;
1093        dstBox.y1 -= pScrni->frameY0;
1094        dstBox.y2 -= pScrni->frameY0;
1095
1096        switch (id) {
1097        case FOURCC_YV12:
1098        case FOURCC_I420:
1099            srcPitch = (width + 3) & ~3;        /* of luma */
1100            dstPitch = (width + 31) & ~31;
1101
1102            s2offset = srcPitch * height;
1103            d2offset = dstPitch * height;
1104
1105            srcPitch2 = ((width >> 1) + 3) & ~3;
1106            dstPitch2 = ((width >> 1) + 15) & ~15;
1107
1108            s3offset = (srcPitch2 * (height >> 1)) + s2offset;
1109            d3offset = (dstPitch2 * (height >> 1)) + d2offset;
1110
1111            new_h = dstPitch * height;  /* Y */
1112            new_h += (dstPitch2 * height);      /* U+V */
1113            new_h += pGeode->Pitch - 1;
1114            new_h /= pGeode->Pitch;
1115            break;
1116        case FOURCC_UYVY:
1117        case FOURCC_YUY2:
1118        case FOURCC_Y800:
1119        case FOURCC_RGB565:
1120        default:
1121            dstPitch = ((width << 1) + 3) & ~3;
1122            srcPitch = (width << 1);
1123            new_h = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
1124            break;
1125        }
1126#if DBUF
1127        if (pPriv->doubleBuffer)
1128            new_h <<= 1;
1129#endif
1130
1131        if (!(pPriv->offset = GXAllocateMemory(pScrni, &pPriv->area, new_h))) {
1132            xf86DrvMsg(pScrni->scrnIndex, X_ERROR,
1133                       "Could not allocate area of size %d\n", new_h);
1134            return BadAlloc;
1135        }
1136
1137        /* copy data */
1138        top = By1;
1139        left = Bx1 & ~1;
1140        npixels = ((Bx2 + 1) & ~1) - left;
1141
1142        switch (id) {
1143        case FOURCC_YV12:
1144        case FOURCC_I420:
1145        {
1146            int tmp;
1147
1148            top &= ~1;
1149
1150            offset = pPriv->offset + (top * dstPitch);
1151
1152#if DBUF
1153            if (pPriv->doubleBuffer && pPriv->currentBuffer)
1154                offset += (new_h >> 1) * pGeode->Pitch;
1155#endif
1156            dst_start = pGeode->FBBase + offset + left;
1157            tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1158            s2offset += tmp;
1159            s3offset += tmp;
1160            if (id == FOURCC_I420) {
1161                tmp = s2offset;
1162                s2offset = s3offset;
1163                s3offset = tmp;
1164            }
1165            nlines = ((By2 + 1) & ~1) - top;
1166        }
1167            break;
1168        case FOURCC_UYVY:
1169        case FOURCC_YUY2:
1170        case FOURCC_Y800:
1171        case FOURCC_RGB565:
1172        default:
1173            left <<= 1;
1174            buf += (top * srcPitch) + left;
1175            nlines = By2 - top;
1176            offset = (pPriv->offset) + (top * dstPitch);
1177
1178#if DBUF
1179            if (pPriv->doubleBuffer && pPriv->currentBuffer)
1180                offset += (new_h >> 1) * pGeode->Pitch;
1181#endif
1182            dst_start = pGeode->FBBase + offset + left;
1183            break;
1184        }
1185        s1offset = (top * srcPitch) + left;
1186#if REINIT
1187        /* update cliplist */
1188        REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
1189
1190        if (pPriv->colorKeyMode == 0) {
1191            xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
1192        }
1193
1194        GXDisplayVideo(pScrni, id, offset, width, height, dstPitch,
1195                       Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w, drw_h);
1196    }
1197#endif
1198    switch (id) {
1199    case FOURCC_Y800:
1200        /* This is shared between LX and GX, so it lives in amd_common.c */
1201        GeodeCopyGreyscale(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1202        break;
1203    case FOURCC_YV12:
1204    case FOURCC_I420:
1205        GXCopyData420(buf + s1offset, dst_start, srcPitch, dstPitch, nlines,
1206                      npixels);
1207        GXCopyData420(buf + s2offset, dst_start + d2offset, srcPitch2,
1208                      dstPitch2, nlines >> 1, npixels >> 1);
1209        GXCopyData420(buf + s3offset, dst_start + d3offset, srcPitch2,
1210                      dstPitch2, nlines >> 1, npixels >> 1);
1211        break;
1212    case FOURCC_UYVY:
1213    case FOURCC_YUY2:
1214    case FOURCC_RGB565:
1215    default:
1216        GXCopyData422(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1217        break;
1218    }
1219#if !REINIT
1220    /* update cliplist */
1221    REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
1222    if (pPriv->colorKeyMode == 0) {
1223        /* draw these */
1224        XAAFillSolidRects(pScrni, pPriv->colorKey, GXcopy, ~0,
1225                          REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes));
1226    }
1227
1228    GXDisplayVideo(pScrni, id, offset, width, height, dstPitch,
1229                   Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w, drw_h);
1230#endif
1231
1232#if XV_PROFILE
1233    UpdateCurrentTime();
1234    newtime = currentTime.milliseconds;
1235    DEBUGMSG(1, (0, X_NONE, "PI %d\n", newtime - oldtime));
1236#endif
1237
1238#if DBUF
1239    pPriv->currentBuffer ^= 1;
1240#endif
1241
1242    pPriv->videoStatus = CLIENT_VIDEO_ON;
1243    pGeode->OverlayON = TRUE;
1244    return Success;
1245}
1246
1247/*----------------------------------------------------------------------------
1248 * GXQueryImageAttributes
1249 *
1250 * Description	:This function is called to let the driver specify how data
1251 *				 for a particular image of size width by height should be
1252 *				 stored.
1253 *
1254 * Parameters.
1255 *		pScrni	:Screen handler pointer having screen information.
1256 *		id		:Id for the video format
1257 *		width	:width  of the image (can be modified by the driver)
1258 *		height	:height of the image (can be modified by the driver)
1259 * Returns		: Size of the memory required for storing this image
1260 *
1261 * Comments		:None
1262 *
1263 *----------------------------------------------------------------------------
1264 */
1265
1266int
1267GeodeQueryImageAttributes(ScrnInfoPtr pScrni,
1268                          int id, unsigned short *w, unsigned short *h,
1269                          int *pitches, int *offsets)
1270{
1271    int size;
1272    int tmp;
1273
1274    DEBUGMSG(0, (0, X_NONE, "QueryImageAttributes %X\n", id));
1275
1276    if (*w > 1024)
1277        *w = 1024;
1278    if (*h > 1024)
1279        *h = 1024;
1280
1281    *w = (*w + 1) & ~1;
1282    if (offsets)
1283        offsets[0] = 0;
1284
1285    switch (id) {
1286    case FOURCC_YV12:
1287    case FOURCC_I420:
1288        *h = (*h + 1) & ~1;
1289        size = (*w + 3) & ~3;
1290        if (pitches)
1291            pitches[0] = size;
1292
1293        size *= *h;
1294        if (offsets)
1295            offsets[1] = size;
1296
1297        tmp = ((*w >> 1) + 3) & ~3;
1298        if (pitches)
1299            pitches[1] = pitches[2] = tmp;
1300
1301        tmp *= (*h >> 1);
1302        size += tmp;
1303        if (offsets)
1304            offsets[2] = size;
1305
1306        size += tmp;
1307        break;
1308    case FOURCC_UYVY:
1309    case FOURCC_YUY2:
1310    case FOURCC_Y800:
1311    default:
1312        size = *w << 1;
1313        if (pitches)
1314            pitches[0] = size;
1315
1316        size *= *h;
1317        break;
1318    }
1319    return size;
1320}
1321
1322static void
1323GXBlockHandler(BLOCKHANDLER_ARGS_DECL)
1324{
1325    SCREEN_PTR(arg);
1326    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
1327    GeodeRec *pGeode = GEODEPTR(pScrni);
1328    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
1329
1330    pScrn->BlockHandler = pGeode->BlockHandler;
1331    (*pScrn->BlockHandler) (BLOCKHANDLER_ARGS);
1332    pScrn->BlockHandler = GXBlockHandler;
1333
1334    if (pPriv->videoStatus & TIMER_MASK) {
1335        GXAccelSync(pScrni);
1336        UpdateCurrentTime();
1337        if (pPriv->videoStatus & OFF_TIMER) {
1338            if (pPriv->offTime < currentTime.milliseconds) {
1339                GFX(set_video_enable(0));
1340
1341                /* If we have saved graphics LUT data - restore it */
1342                /* Otherwise, turn bypass on */
1343
1344                if (lutflag)
1345                    GFX(set_graphics_palette(graphics_lut));
1346                else
1347                    GFX(set_video_palette_bypass(1));
1348
1349                lutflag = 0;
1350
1351                pPriv->videoStatus = FREE_TIMER;
1352                pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1353            }
1354        }
1355        else {                  /* FREE_TIMER */
1356            if (pPriv->freeTime < currentTime.milliseconds) {
1357
1358                if (pPriv->area) {
1359#ifdef XF86EXA
1360                    if (pGeode->useEXA)
1361                        exaOffscreenFree(pScrn, pPriv->area);
1362#endif
1363                    if (!pGeode->useEXA)
1364                        xf86FreeOffscreenArea(pPriv->area);
1365
1366                    pPriv->area = NULL;
1367                }
1368
1369                pPriv->videoStatus = 0;
1370            }
1371        }
1372    }
1373}
1374
1375/****************** Offscreen stuff ***************/
1376
1377typedef struct {
1378    void *area;
1379    int offset;
1380    Bool isOn;
1381} OffscreenPrivRec, *OffscreenPrivPtr;
1382
1383/*----------------------------------------------------------------------------
1384 * GXAllocateSurface
1385 *
1386 * Description	:This function allocates an area of w by h in the offscreen
1387 *
1388 * Parameters.
1389 *		pScrni	:Screen handler pointer having screen information.
1390 *
1391 * Returns		:None
1392 *
1393 * Comments		:None
1394 *----------------------------------------------------------------------------
1395 */
1396static int
1397GXAllocateSurface(ScrnInfoPtr pScrni,
1398                  int id, unsigned short w, unsigned short h,
1399                  XF86SurfacePtr surface)
1400{
1401    void *area = NULL;
1402    int pitch, fbpitch, numlines;
1403    OffscreenPrivRec *pPriv;
1404
1405    if ((w > 1024) || (h > 1024))
1406        return BadAlloc;
1407
1408    w = (w + 1) & ~1;
1409    pitch = ((w << 1) + 15) & ~15;
1410    fbpitch = pScrni->bitsPerPixel * pScrni->displayWidth >> 3;
1411    numlines = ((pitch * h) + fbpitch - 1) / fbpitch;
1412
1413    if (!(offset = GXAllocateMemory(pScrni, &area, numlines)))
1414        return BadAlloc;
1415
1416    surface->width = w;
1417    surface->height = h;
1418
1419    if (!(surface->pitches = malloc(sizeof(int))))
1420        return BadAlloc;
1421
1422    if (!(surface->offsets = malloc(sizeof(int)))) {
1423        free(surface->pitches);
1424        return BadAlloc;
1425    }
1426
1427    if (!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
1428        free(surface->pitches);
1429        free(surface->offsets);
1430        return BadAlloc;
1431    }
1432
1433    pPriv->area = area;
1434    pPriv->offset = offset;
1435
1436    pPriv->isOn = FALSE;
1437
1438    surface->pScrn = pScrni;
1439    surface->id = id;
1440    surface->pitches[0] = pitch;
1441    surface->offsets[0] = offset;
1442    surface->devPrivate.ptr = (pointer) pPriv;
1443
1444    return Success;
1445}
1446
1447static int
1448GXStopSurface(XF86SurfacePtr surface)
1449{
1450    OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr;
1451
1452    if (pPriv->isOn) {
1453        pPriv->isOn = FALSE;
1454    }
1455
1456    return Success;
1457}
1458
1459static int
1460GXFreeSurface(XF86SurfacePtr surface)
1461{
1462    OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr;
1463
1464    if (pPriv->isOn)
1465        GXStopSurface(surface);
1466
1467    xf86FreeOffscreenArea(pPriv->area);
1468    free(surface->pitches);
1469    free(surface->offsets);
1470    free(surface->devPrivate.ptr);
1471
1472    return Success;
1473}
1474
1475static int
1476GXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value)
1477{
1478    return GXGetPortAttribute(pScrni, attribute, value,
1479                              (pointer) (GET_PORT_PRIVATE(pScrni)));
1480}
1481
1482static int
1483GXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
1484{
1485    return GXSetPortAttribute(pScrni, attribute, value,
1486                              (pointer) (GET_PORT_PRIVATE(pScrni)));
1487}
1488
1489static int
1490GXDisplaySurface(XF86SurfacePtr surface,
1491                 short src_x, short src_y,
1492                 short drw_x, short drw_y,
1493                 short src_w, short src_h, short drw_w, short drw_h,
1494                 RegionPtr clipBoxes)
1495{
1496    OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr;
1497    ScrnInfoPtr pScrni = surface->pScrn;
1498    GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
1499    INT32 x1, y1, x2, y2;
1500    BoxRec dstBox;
1501
1502    DEBUGMSG(0, (0, X_NONE, "DisplaySuface\n"));
1503    x1 = src_x;
1504    x2 = src_x + src_w;
1505    y1 = src_y;
1506    y2 = src_y + src_h;
1507
1508    dstBox.x1 = drw_x;
1509    dstBox.x2 = drw_x + drw_w;
1510    dstBox.y1 = drw_y;
1511    dstBox.y2 = drw_y + drw_h;
1512
1513    if ((x1 >= x2) || (y1 >= y2))
1514        return Success;
1515
1516    dstBox.x1 -= pScrni->frameX0;
1517    dstBox.x2 -= pScrni->frameX0;
1518    dstBox.y1 -= pScrni->frameY0;
1519    dstBox.y2 -= pScrni->frameY0;
1520
1521    xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
1522
1523    GXDisplayVideo(pScrni, surface->id, surface->offsets[0],
1524                   surface->width, surface->height, surface->pitches[0],
1525                   x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1526
1527    pPriv->isOn = TRUE;
1528    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
1529        REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
1530        UpdateCurrentTime();
1531        portPriv->videoStatus = FREE_TIMER;
1532        portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1533    }
1534
1535    return Success;
1536}
1537
1538/*----------------------------------------------------------------------------
1539 * GXInitOffscreenImages
1540 *
1541 * Description	:This function sets up the offscreen memory management. It
1542 * 				fills in the XF86OffscreenImagePtr structure with functions to
1543 * 				handle offscreen memory operations.
1544 *
1545 * Parameters.
1546 *		pScrn	:Screen handler pointer having screen information.
1547 *
1548 * Returns		: None
1549 *
1550 * Comments		:None
1551 *----------------------------------------------------------------------------
1552 */
1553static void
1554GXInitOffscreenImages(ScreenPtr pScrn)
1555{
1556    XF86OffscreenImagePtr offscreenImages;
1557
1558    /* need to free this someplace */
1559    if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
1560        return;
1561
1562    offscreenImages[0].image = &Images[0];
1563    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
1564    offscreenImages[0].alloc_surface = GXAllocateSurface;
1565    offscreenImages[0].free_surface = GXFreeSurface;
1566    offscreenImages[0].display = GXDisplaySurface;
1567    offscreenImages[0].stop = GXStopSurface;
1568    offscreenImages[0].setAttribute = GXSetSurfaceAttribute;
1569    offscreenImages[0].getAttribute = GXGetSurfaceAttribute;
1570    offscreenImages[0].max_width = 1024;
1571    offscreenImages[0].max_height = 1024;
1572    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
1573    offscreenImages[0].attributes = Attributes;
1574
1575    xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
1576}
1577
1578#endif                          /* !XvExtension */
1579