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