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