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