pm3_video.c revision c35d236e
1/*
2 * Copyright 2001 by Alan Hourihane, Sychdyn, North Wales.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Alan Hourihane not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Alan Hourihane makes no representations
11 * about the suitability of this software for any purpose.  It is provided
12 * "as is" without express or implied warranty.
13 *
14 * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Authors: Alan Hourihane, alanh@fairlite.demon.co.uk
23 *          Sven Luther <luther@dpt-info.u-strasbg.fr>
24 */
25/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/glint/pm3_video.c,v 1.14tsi Exp $ */
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "xf86.h"
32#include "xf86_OSproc.h"
33#include "xf86Resources.h"
34#include "compiler.h"
35#include "xf86PciInfo.h"
36#include "xf86Pci.h"
37#include "xf86fbman.h"
38#include "regionstr.h"
39
40#include "glint.h"
41#include "glint_regs.h"
42#include "pm3_regs.h"
43#include <X11/extensions/Xv.h>
44#include "xaa.h"
45#include "xaalocal.h"
46#include "dixstruct.h"
47#include "fourcc.h"
48
49#define OFF_DELAY 	200  /* milliseconds */
50#define FREE_DELAY 	60000
51
52#define OFF_TIMER 	0x01
53#define FREE_TIMER	0x02
54#define CLIENT_VIDEO_ON	0x04
55
56#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
57
58static XF86VideoAdaptorPtr Permedia3SetupImageVideo(ScreenPtr);
59static void Permedia3InitOffscreenImages(ScreenPtr);
60static void Permedia3StopVideo(ScrnInfoPtr, pointer, Bool);
61static int Permedia3SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
62static int Permedia3GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
63static void Permedia3QueryBestSize(ScrnInfoPtr, Bool,
64	short, short, short, short, unsigned int *, unsigned int *, pointer);
65static int Permedia3PutImage( ScrnInfoPtr,
66	short, short, short, short, short, short, short, short,
67	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
68	DrawablePtr);
69static int Permedia3QueryImageAttributes(ScrnInfoPtr,
70	int, unsigned short *, unsigned short *,  int *, int *);
71static void Permedia3VideoTimerCallback(ScrnInfoPtr pScrn, Time time);
72
73#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
74
75static Atom xvColorKey, xvDoubleBuffer, xvAutopaintColorKey, xvFilter;
76
77void Permedia3InitVideo(ScreenPtr pScreen)
78{
79    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
80    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
81    XF86VideoAdaptorPtr newAdaptor = NULL;
82    GLINTPtr pGlint = GLINTPTR(pScrn);
83    int num_adaptors;
84
85    /* Because of bugs in the PM3 when uploading images via the
86     * bypass to the framebuffer, we always have to use the accelerator.
87     */
88    if (pGlint->NoAccel)
89	return;
90
91    newAdaptor = Permedia3SetupImageVideo(pScreen);
92    Permedia3InitOffscreenImages(pScreen);
93
94    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
95
96    if(newAdaptor) {
97	if(!num_adaptors) {
98	    num_adaptors = 1;
99	    adaptors = &newAdaptor;
100	} else {
101	    newAdaptors =  /* need to free this someplace */
102		xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
103	    if(newAdaptors) {
104		memcpy(newAdaptors, adaptors, num_adaptors *
105					sizeof(XF86VideoAdaptorPtr));
106		newAdaptors[num_adaptors] = newAdaptor;
107		adaptors = newAdaptors;
108		num_adaptors++;
109	    }
110	}
111    }
112
113    if(num_adaptors)
114        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
115
116    if(newAdaptors)
117	xfree(newAdaptors);
118}
119
120/* client libraries expect an encoding */
121static XF86VideoEncodingRec DummyEncoding[1] =
122{
123 {
124   0,
125   "XV_IMAGE",
126   2047, 2047,
127   {1, 1}
128 }
129};
130
131#define NUM_FORMATS 4
132
133static XF86VideoFormatRec Formats[NUM_FORMATS] =
134{
135  {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
136};
137
138#define NUM_ATTRIBUTES 4
139
140static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
141{
142   {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
143   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
144   {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
145   {XvSettable | XvGettable, 0, 2, "XV_FILTER"},
146};
147
148/*
149 *  FOURCC from http://www.webartz.com/fourcc
150 *  Generic GUID for legacy FOURCC XXXXXXXX-0000-0010-8000-00AA00389B71
151 */
152#define LE4CC(a,b,c,d) (((CARD32)(a)&0xFF)|(((CARD32)(b)&0xFF)<<8)|(((CARD32)(c)&0xFF)<<16)|(((CARD32)(d)&0xFF)<<24))
153#define GUID4CC(a,b,c,d) { a,b,c,d,0,0,0,0x10,0x80,0,0,0xAA,0,0x38,0x9B,0x71 }
154
155#define NoOrder LSBFirst
156
157#define NUM_IMAGES 15
158
159static XF86ImageRec Images[NUM_IMAGES] =
160{
161    /* Planar YVU 4:2:0 (emulated) */
162    { LE4CC('Y','V','1','2'), XvYUV, NoOrder, GUID4CC('Y','V','1','2'),
163      12, XvPlanar, 3, 0, 0, 0, 0,
164      8, 8, 8,  1, 2, 2,  1, 2, 2, "YVU", XvTopToBottom },
165
166    /* Packed YUYV 4:2:2 */
167    { LE4CC('Y','U','Y','2'), XvYUV, NoOrder, GUID4CC('Y','U','Y','2'),
168      16, XvPacked, 1, 0, 0, 0, 0,
169      8, 8, 8,  1, 2, 2,  1, 1, 1, "YUYV", XvTopToBottom },
170
171    /* Packed UYVY 4:2:2 */
172    { LE4CC('U','Y','V','Y'), XvYUV, NoOrder, GUID4CC('U','Y','V','Y'),
173      16, XvPacked, 1, 0, 0, 0, 0,
174      8, 8, 8,  1, 2, 2,  1, 1, 1, "UYVY", XvTopToBottom },
175
176    /* Packed YUVA 4:4:4 */
177    { LE4CC('Y','U','V','A') /* XXX not registered */, XvYUV, LSBFirst, { 0 },
178      32, XvPacked, 1, 0, 0, 0, 0,
179      8, 8, 8,  1, 1, 1,  1, 1, 1, "YUVA", XvTopToBottom },
180
181    /* Packed VUYA 4:4:4 */
182    { LE4CC('V','U','Y','A') /* XXX not registered */, XvYUV, LSBFirst, { 0 },
183      32, XvPacked, 1, 0, 0, 0, 0,
184      8, 8, 8,  1, 1, 1,  1, 1, 1, "VUYA", XvTopToBottom },
185
186    /* RGBA 8:8:8:8 */
187    { 0x41, XvRGB, LSBFirst, { 0 },
188      32, XvPacked, 1, 24, 0x0000FF, 0x00FF00, 0xFF0000,
189      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
190
191    /* RGB 5:6:5 */
192    { 0x42, XvRGB, LSBFirst, { 0 },
193      16, XvPacked, 1, 16, 0x001F, 0x07E0, 0xF800,
194      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGB", XvTopToBottom },
195
196    /* RGBA 5:5:5:1 */
197    { 0x43, XvRGB, LSBFirst, { 0 },
198      16, XvPacked, 1, 15, 0x001F, 0x03E0, 0x7C00,
199      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
200
201    /* RGBA 4:4:4:4 */
202    { 0x44, XvRGB, LSBFirst, { 0 },
203      16, XvPacked, 1, 12, 0x000F, 0x00F0, 0x0F00,
204      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGBA", XvTopToBottom },
205
206    /* RGB 3:3:2 */
207    { 0x46, XvRGB, NoOrder, { 0 },
208      8, XvPacked, 1, 8, 0x07, 0x38, 0xC0,
209      0, 0, 0,  0, 0, 0,  0, 0, 0, "RGB", XvTopToBottom },
210
211    /* BGRA 8:8:8:8 */
212    { 0x47, XvRGB, LSBFirst, { 0 },
213      32, XvPacked, 1, 24, 0xFF0000, 0x00FF00, 0x0000FF,
214      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
215
216    /* BGR 5:6:5 */
217    { 0x48, XvRGB, LSBFirst, { 0 },
218      16, XvPacked, 1, 16, 0xF800, 0x07E0, 0x001F,
219      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGR", XvTopToBottom },
220
221    /* BGRA 5:5:5:1 */
222    { 0x49, XvRGB, LSBFirst, { 0 },
223      16, XvPacked, 1, 15, 0x7C00, 0x03E0, 0x001F,
224      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
225
226    /* BGRA 4:4:4:4 */
227    { 0x4A, XvRGB, LSBFirst, { 0 },
228      16, XvPacked, 1, 12, 0x0F00, 0x00F0, 0x000F,
229      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGRA", XvTopToBottom },
230
231    /* BGR 2:3:3 */
232    { 0x4C, XvRGB, NoOrder, { 0 },
233      8, XvPacked, 1, 8, 0xC0, 0x38, 0x07,
234      0, 0, 0,  0, 0, 0,  0, 0, 0, "BGR", XvTopToBottom },
235};
236
237#define MAX_BUFFERS 2
238
239typedef struct {
240   FBAreaPtr	area[MAX_BUFFERS];
241   RegionRec	clip;
242   CARD32	colorKey;
243   CARD32	videoStatus;
244   Time		offTime;
245   Time		freeTime;
246   int		Video_Shift;
247   int		Format;
248   Bool		ramdacOn;
249   Bool		doubleBuffer;
250   Bool		autopaintColorKey;
251   int		Filter;
252   int		sx, sy;
253   int		offset[MAX_BUFFERS];
254   int		buffer;
255} GLINTPortPrivRec, *GLINTPortPrivPtr;
256
257#define GET_PORT_PRIVATE(pScrn) \
258   (GLINTPortPrivPtr)((GLINTPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
259
260#define	RAMDAC_WRITE(data,index)				\
261do{                                                             \
262	GLINT_WRITE_REG(((index)>>8)&0xff, PM3RD_IndexHigh);	\
263 	GLINT_WRITE_REG((index)&0xff, PM3RD_IndexLow);		\
264	GLINT_WRITE_REG(data, PM3RD_IndexedData);		\
265}while(0)
266
267void Permedia3ResetVideo(ScrnInfoPtr pScrn)
268{
269    GLINTPtr pGlint = GLINTPTR(pScrn);
270    GLINTPortPrivPtr pPriv = pGlint->adaptor->pPortPrivates[0].ptr;
271
272    GLINT_WAIT(15);
273    GLINT_WRITE_REG(0xfff0|(0xffff<<16), PM3VideoOverlayFifoControl);
274    GLINT_WRITE_REG(PM3VideoOverlayMode_DISABLE, PM3VideoOverlayMode);
275    pPriv->ramdacOn = FALSE;
276    RAMDAC_WRITE(PM3RD_VideoOverlayControl_DISABLE, PM3RD_VideoOverlayControl);
277    RAMDAC_WRITE((pPriv->colorKey&0xff0000)>>16, PM3RD_VideoOverlayKeyR);
278    RAMDAC_WRITE((pPriv->colorKey&0x00ff00)>>8, PM3RD_VideoOverlayKeyG);
279    RAMDAC_WRITE(pPriv->colorKey&0x0000ff, PM3RD_VideoOverlayKeyB);
280    GLINT_WRITE_REG(PM3VideoOverlayUpdate_ENABLE, PM3VideoOverlayUpdate);
281}
282
283
284static XF86VideoAdaptorPtr
285Permedia3SetupImageVideo(ScreenPtr pScreen)
286{
287    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
288    GLINTPtr pGlint = GLINTPTR(pScrn);
289    XF86VideoAdaptorPtr adapt;
290    GLINTPortPrivPtr pPriv;
291
292    if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
293			    sizeof(GLINTPortPrivRec) +
294			    sizeof(DevUnion))))
295	return NULL;
296
297    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
298    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
299    adapt->name = "Permedia3 Backend Scaler";
300    adapt->nEncodings = 1;
301    adapt->pEncodings = DummyEncoding;
302    adapt->nFormats = NUM_FORMATS;
303    adapt->pFormats = Formats;
304    adapt->nPorts = 1;
305    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
306    pPriv = (GLINTPortPrivPtr)(&adapt->pPortPrivates[1]);
307    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
308    adapt->pAttributes = Attributes;
309    adapt->nImages = NUM_IMAGES;
310    adapt->nAttributes = NUM_ATTRIBUTES;
311    adapt->pImages = Images;
312    adapt->PutVideo = NULL;
313    adapt->PutStill = NULL;
314    adapt->GetVideo = NULL;
315    adapt->GetStill = NULL;
316    adapt->StopVideo = Permedia3StopVideo;
317    adapt->SetPortAttribute = Permedia3SetPortAttribute;
318    adapt->GetPortAttribute = Permedia3GetPortAttribute;
319    adapt->QueryBestSize = Permedia3QueryBestSize;
320    adapt->PutImage = Permedia3PutImage;
321    adapt->QueryImageAttributes = Permedia3QueryImageAttributes;
322
323    /* FIXME : depth 15 and 16 doesn't work here */
324    pPriv->colorKey = pGlint->videoKey;
325    pPriv->videoStatus = 0;
326    pPriv->buffer = 0; /* double buffer (or maybe triple later) */
327    pPriv->doubleBuffer = TRUE;
328    pPriv->autopaintColorKey = TRUE;
329    pPriv->Filter = PM3VideoOverlayMode_FILTER_FULL;
330
331    /* gotta uninit this someplace */
332    REGION_NULL(pScreen, &pPriv->clip);
333
334    pGlint->adaptor = adapt;
335
336    xvDoubleBuffer      = MAKE_ATOM("XV_DOUBLE_BUFFER");
337    xvColorKey          = MAKE_ATOM("XV_COLORKEY");
338    xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
339    xvFilter		= MAKE_ATOM("XV_FILTER");
340
341    Permedia3ResetVideo(pScrn);
342
343    return adapt;
344}
345
346
347static void
348Permedia3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
349{
350  GLINTPtr pGlint = GLINTPTR(pScrn);
351  GLINTPortPrivPtr pPriv = (GLINTPortPrivPtr)data;
352  int i;
353
354  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
355
356  if(shutdown) {
357     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
358    	pPriv->ramdacOn = FALSE;
359	GLINT_WAIT(4);
360        RAMDAC_WRITE(PM3RD_VideoOverlayControl_DISABLE,
361		PM3RD_VideoOverlayControl);
362	GLINT_WRITE_REG(PM3VideoOverlayMode_DISABLE,
363		PM3VideoOverlayMode);
364     }
365     for (i = 0; i < (pPriv->doubleBuffer ? 2 : 1); i++) {
366        if(pPriv->area[i]) {
367	   xf86FreeOffscreenArea(pPriv->area[i]);
368	   pPriv->area[i] = NULL;
369        }
370     }
371     pPriv->videoStatus = 0;
372  } else {
373     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
374	pPriv->videoStatus |= OFF_TIMER;
375	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
376     }
377  }
378}
379
380static int
381Permedia3SetPortAttribute(
382  ScrnInfoPtr pScrn,
383  Atom attribute,
384  INT32 value,
385  pointer data
386){
387    GLINTPortPrivPtr pPriv = (GLINTPortPrivPtr)data;
388    GLINTPtr pGlint = GLINTPTR(pScrn);
389
390    if (attribute == xvDoubleBuffer)
391    {
392        if ((value < 0) || (value > 1))
393            return BadValue;
394        pPriv->doubleBuffer = value;
395    }
396    else if (attribute == xvColorKey)
397    {
398        pPriv->colorKey = value;
399	GLINT_WAIT(9);
400    	RAMDAC_WRITE((value & 0xff0000)>>16, PM3RD_VideoOverlayKeyR);
401    	RAMDAC_WRITE((value & 0x00ff00)>>8, PM3RD_VideoOverlayKeyG);
402    	RAMDAC_WRITE((value & 0x0000ff), PM3RD_VideoOverlayKeyB);
403	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
404    }
405    else if (attribute == xvAutopaintColorKey)
406    {
407        if ((value < 0) || (value > 1))
408            return BadValue;
409        pPriv->autopaintColorKey = value;
410    }
411    else if (attribute == xvFilter)
412    {
413        if ((value < 0) || (value > 2))
414            return BadValue;
415	switch (value) {
416	    case 0:
417    		pPriv->Filter = PM3VideoOverlayMode_FILTER_OFF;
418		break;
419	    case 1:
420    		pPriv->Filter = PM3VideoOverlayMode_FILTER_FULL;
421		break;
422	    case 2:
423    		pPriv->Filter = PM3VideoOverlayMode_FILTER_PARTIAL;
424		break;
425	}
426    }
427    else
428        return BadMatch;
429
430  return Success;
431}
432
433static int
434Permedia3GetPortAttribute(
435  ScrnInfoPtr pScrn,
436  Atom attribute,
437  INT32 *value,
438  pointer data
439){
440    GLINTPortPrivPtr pPriv = (GLINTPortPrivPtr)data;
441
442    if (attribute == xvDoubleBuffer)
443        *value = (pPriv->doubleBuffer) ? 1 : 0;
444    else if (attribute == xvColorKey)
445        *value = pPriv->colorKey;
446    else if (attribute == xvAutopaintColorKey)
447        *value = (pPriv->autopaintColorKey) ? 1 : 0;
448    else if (attribute == xvFilter)
449        *value = pPriv->Filter >> 14;
450    else
451        return BadMatch;
452
453    return Success;
454}
455
456static void
457Permedia3QueryBestSize(
458  ScrnInfoPtr pScrn,
459  Bool motion,
460  short vid_w, short vid_h,
461  short drw_w, short drw_h,
462  unsigned int *p_w, unsigned int *p_h,
463  pointer data
464){
465    if(vid_w > (drw_w << 3))
466	drw_w = vid_w >> 3;
467    if(vid_h > (drw_h << 3))
468	drw_h = vid_h >> 3;
469
470    *p_w = drw_w;
471    *p_h = drw_h;
472}
473
474static void
475HWCopySetup(ScrnInfoPtr pScrn, int x, int y, int w, int h)
476{
477    GLINTPtr pGlint = GLINTPTR(pScrn);
478
479    GLINT_WAIT(4);
480    GLINT_WRITE_REG(0xffffffff, FBHardwareWriteMask);
481    GLINT_WRITE_REG(
482	PM3Config2D_ForegroundROPEnable |
483	PM3Config2D_ForegroundROP(GXcopy) |
484	PM3Config2D_FBWriteEnable,
485	PM3Config2D);
486    GLINT_WRITE_REG(
487	PM3RectanglePosition_XOffset(x) |
488	PM3RectanglePosition_YOffset(y),
489	PM3RectanglePosition);
490    GLINT_WRITE_REG(
491	PM3Render2D_SpanOperation |
492	PM3Render2D_XPositive |
493	PM3Render2D_YPositive |
494	PM3Render2D_Operation_SyncOnHostData |
495	PM3Render2D_Width(w) | PM3Render2D_Height(h),
496	PM3Render2D);
497}
498
499static void
500HWCopyYV12(ScrnInfoPtr pScrn, CARD8 *Y, int w, int h)
501{
502    GLINTPtr pGlint = GLINTPTR(pScrn);
503    int size = w * h;
504    CARD8 *V = Y + size;
505    CARD8 *U = V + (size >> 2);
506    CARD32 *dst;
507    int pass2 = 0;
508    int dwords, i, x = 0;
509
510    dwords = size >> 1;
511
512    w >>= 1;
513
514    while (dwords >= pGlint->FIFOSize) {
515	dst = (CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4);
516	GLINT_WAIT(pGlint->FIFOSize);
517	/* (0x15 << 4) | 0x05 is the TAG for FBSourceData */
518	GLINT_WRITE_REG(((pGlint->FIFOSize - 2) << 16) | (0x15 << 4) |
519	    0x05, OutputFIFO);
520	for (i = pGlint->FIFOSize - 1; i; i--, Y += 2, x++) {
521	    if (x == w) {
522		x = 0;
523		if (pass2 == 0)
524		    pass2 = 1;
525		else
526		if (pass2 == 1) {
527		    pass2 = 0;
528		    U += w;
529		    V += w;
530		}
531	    }
532	    *dst++ = Y[0] + (U[x] << 8) + (Y[1] << 16) + (V[x] << 24);
533	}
534	dwords -= pGlint->FIFOSize - 1;
535    }
536    if (dwords) {
537	dst = (CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4);
538	GLINT_WAIT(dwords + 1);
539	/* (0x15 << 4) | 0x05 is the TAG for FBSourceData */
540	GLINT_WRITE_REG(((dwords - 1) << 16) | (0x15 << 4) |
541	    0x05, OutputFIFO);
542	for (i = dwords; i; i--, Y += 2, x++) {
543	    if (x == w) {
544		x = 0;
545		if (pass2 == 0)
546		    pass2 = 1;
547		else
548		if (pass2 == 1) {
549		    pass2 = 0;
550		    U += w;
551		    V += w;
552		}
553	    }
554	    *dst++ = Y[0] + (U[x] << 8) + (Y[1] << 16) + (V[x] << 24);
555	}
556    }
557}
558
559static void
560HWCopyFlat(ScrnInfoPtr pScrn, CARD8 *src, int w, int h)
561{
562    GLINTPtr pGlint = GLINTPTR(pScrn);
563    GLINTPortPrivPtr pPriv = pGlint->adaptor->pPortPrivates[0].ptr;
564    int pitch = pScrn->displayWidth;
565    CARD8 *tmp_src;
566    int dwords;
567
568    if (w == pitch) {
569    	dwords = (w * h) >> (2 - pPriv->Video_Shift);
570    	while(dwords >= pGlint->FIFOSize) {
571	    GLINT_WAIT(pGlint->FIFOSize);
572            GLINT_WRITE_REG(((pGlint->FIFOSize - 2) << 16) | (0x15 << 4) |
573			0x05, OutputFIFO);
574	    GLINT_MoveDWORDS(
575		(CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4),
576	 	(CARD32*)src, pGlint->FIFOSize - 1);
577	    dwords -= (pGlint->FIFOSize - 1);
578	    src += (pGlint->FIFOSize << 2) - 4;
579    	}
580    	if(dwords) {
581	    GLINT_WAIT(dwords + 1);
582            GLINT_WRITE_REG(((dwords - 1) << 16)|(0x15 << 4) |0x05, OutputFIFO);
583	    GLINT_MoveDWORDS(
584		(CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4),
585	 	(CARD32*)src, dwords);
586    	}
587    } else {
588  	while (h--) {
589    	    tmp_src = src;
590    	    dwords = w >> (2 - pPriv->Video_Shift);
591    	    while(dwords >= pGlint->FIFOSize) {
592		GLINT_WAIT(pGlint->FIFOSize);
593        	GLINT_WRITE_REG(((pGlint->FIFOSize - 2) << 16) | (0x15 << 4) |
594			0x05, OutputFIFO);
595		GLINT_MoveDWORDS(
596			(CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4),
597	 		(CARD32*)src, pGlint->FIFOSize - 1);
598		dwords -= (pGlint->FIFOSize - 1);
599		src += (pGlint->FIFOSize << 2) - 4;
600    	    }
601    	    if(dwords) {
602		GLINT_WAIT(dwords + 1);
603        	GLINT_WRITE_REG(((dwords-1)<<16)|(0x15<<4) | 0x05, OutputFIFO);
604		GLINT_MoveDWORDS(
605			(CARD32*)((char*)pGlint->IOBase + OutputFIFO + 4),
606	 		(CARD32*)src, dwords);
607    	    }
608    	    src = tmp_src + (w << pPriv->Video_Shift);
609  	}
610    }
611}
612
613static FBAreaPtr
614Permedia3AllocateMemory(ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height)
615{
616  ScreenPtr pScreen;
617  FBAreaPtr new_area;
618
619  if (area) {
620    if ((area->box.x2 - area->box.x1 >= width) &&
621        (area->box.y2 - area->box.y1 >= height))
622      return area;
623
624    if (xf86ResizeOffscreenArea(area, width, height))
625      return area;
626
627    xf86FreeOffscreenArea(area);
628  }
629
630  pScreen = screenInfo.screens[pScrn->scrnIndex];
631
632  new_area = xf86AllocateOffscreenArea(pScreen, width, height, pScrn->bitsPerPixel / 8, NULL, NULL, NULL);
633
634  if (!new_area) {
635    int max_width, max_height;
636
637    xf86QueryLargestOffscreenArea(pScreen, &max_width, &max_height, pScrn->bitsPerPixel / 8, 0, PRIORITY_EXTREME);
638
639    if (max_width < width || max_height < height)
640      return NULL;
641
642    xf86PurgeUnlockedOffscreenAreas(pScreen);
643    new_area = xf86AllocateOffscreenArea(pScreen, width, height, pScrn->bitsPerPixel / 8, NULL, NULL, NULL);
644  }
645
646  return new_area;
647}
648
649#define FORMAT_RGB8888	PM3VideoOverlayMode_COLORFORMAT_RGB8888
650#define FORMAT_RGB4444	PM3VideoOverlayMode_COLORFORMAT_RGB4444
651#define FORMAT_RGB5551	PM3VideoOverlayMode_COLORFORMAT_RGB5551
652#define FORMAT_RGB565	PM3VideoOverlayMode_COLORFORMAT_RGB565
653#define FORMAT_RGB332	PM3VideoOverlayMode_COLORFORMAT_RGB332
654#define FORMAT_BGR8888	PM3VideoOverlayMode_COLORFORMAT_BGR8888
655#define FORMAT_BGR4444	PM3VideoOverlayMode_COLORFORMAT_BGR4444
656#define FORMAT_BGR5551	PM3VideoOverlayMode_COLORFORMAT_BGR5551
657#define FORMAT_BGR565	PM3VideoOverlayMode_COLORFORMAT_BGR565
658#define FORMAT_BGR332	PM3VideoOverlayMode_COLORFORMAT_BGR332
659#define FORMAT_CI8	PM3VideoOverlayMode_COLORFORMAT_CI8
660#define FORMAT_VUY444	PM3VideoOverlayMode_COLORFORMAT_VUY444
661#define FORMAT_YUV444	PM3VideoOverlayMode_COLORFORMAT_YUV444
662#define FORMAT_VUY422	PM3VideoOverlayMode_COLORFORMAT_VUY422
663#define FORMAT_YUV422	PM3VideoOverlayMode_COLORFORMAT_YUV422
664
665/* Notice, have to check that we dont overflow the deltas here ... */
666static void
667compute_scale_factor(
668    short* src_w, short* dst_w,
669    unsigned int* shrink_delta, unsigned int* zoom_delta)
670{
671    /* NOTE: If we don't return reasonable values here then the video
672     * unit can potential shut off and won't display an image until re-enabled.
673     * Seems as though the zoom_delta is o.k, and I've not had the problem.
674     * The 'shrink_delta' is prone to this the most - FIXME ! */
675
676    if (*src_w >= *dst_w) {
677	*src_w &= ~0x3;
678	*dst_w &= ~0x3;
679	*shrink_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0ffffff0;
680	*zoom_delta = 1<<16;
681	if ( ((*shrink_delta * *dst_w) >> 16) & 0x03 )
682	    *shrink_delta += 0x10;
683    } else {
684	*src_w &= ~0x3;
685	*dst_w &= ~0x3;
686	*zoom_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0001fff0;
687	*shrink_delta = 1<<16;
688	if ( ((*zoom_delta * *dst_w) >> 16) & 0x03 )
689	    *zoom_delta += 0x10;
690    }
691}
692
693static void
694Permedia3DisplayVideo(
695    ScrnInfoPtr pScrn,
696    int id,
697    int offset,
698    short width, short height,
699    int x1, int y1, int x2, int y2,
700    BoxPtr dstBox,
701    short src_w, short src_h,
702    short drw_w, short drw_h
703){
704    GLINTPtr pGlint = GLINTPTR(pScrn);
705    GLINTPortPrivPtr portPriv = pGlint->adaptor->pPortPrivates[0].ptr;
706    unsigned int shrink, zoom;
707    unsigned int newx2;
708
709    /* Let's overlay only to visible parts of the screen */
710    if (dstBox->x1 == 0) {
711	x1 = drw_w - dstBox->x2;
712	drw_w = dstBox->x2;
713    }
714    if (dstBox->x2 == pScrn->frameX1) {
715	x2 = drw_w - (dstBox->x2 - dstBox->x1);
716	drw_w = (dstBox->x2 - dstBox->x1);
717    }
718
719    /* Avoid divide by zero in compute_scale_factor. */
720    if (drw_w < 8)
721	return;
722
723    /* Let's adjust the width of source and dest to be compliant with
724     * the Permedia3 overlay unit requirement, and compute the X deltas. */
725    newx2 = drw_w;
726    compute_scale_factor(&src_w, &drw_w, &shrink, &zoom);
727    dstBox->x2 -= (newx2 - drw_w);
728
729    /* We do a long wait here - for everything that needs to be written */
730    GLINT_WAIT(39);
731    GLINT_WRITE_REG(offset>>portPriv->Video_Shift,
732	portPriv->buffer ? PM3VideoOverlayBase1 : PM3VideoOverlayBase0);
733    /* Let's set the source pitch. */
734    GLINT_WRITE_REG(PM3VideoOverlayStride_STRIDE(pScrn->displayWidth<<
735	(pScrn->bitsPerPixel>>4) >>portPriv->Video_Shift),
736	PM3VideoOverlayStride);
737    /* Let's set the position and size of the visible part of the source. */
738    GLINT_WRITE_REG(PM3VideoOverlayWidth_WIDTH(src_w),
739	PM3VideoOverlayWidth);
740    GLINT_WRITE_REG(PM3VideoOverlayHeight_HEIGHT(src_h),
741	PM3VideoOverlayHeight);
742    GLINT_WRITE_REG(
743	PM3VideoOverlayOrigin_XORIGIN(x1) |
744	PM3VideoOverlayOrigin_YORIGIN(y1),
745	PM3VideoOverlayOrigin);
746    /* Scale the source to the destinationsize */
747    if (src_h == drw_h) {
748	GLINT_WRITE_REG(
749	    PM3VideoOverlayYDelta_NONE,
750	    PM3VideoOverlayYDelta);
751    } else {
752	GLINT_WRITE_REG(
753	    PM3VideoOverlayYDelta_DELTA(src_h,drw_h),
754	    PM3VideoOverlayYDelta);
755    }
756    if (src_w == drw_w) {
757    	GLINT_WRITE_REG(1<<16, PM3VideoOverlayShrinkXDelta);
758    	GLINT_WRITE_REG(1<<16, PM3VideoOverlayZoomXDelta);
759    } else {
760    	GLINT_WRITE_REG(shrink, PM3VideoOverlayShrinkXDelta);
761    	GLINT_WRITE_REG(zoom, PM3VideoOverlayZoomXDelta);
762    }
763    GLINT_WRITE_REG(portPriv->buffer, PM3VideoOverlayIndex);
764
765    /* Now set the ramdac video overlay region and mode */
766    RAMDAC_WRITE((dstBox->x1&0xff), PM3RD_VideoOverlayXStartLow);
767    RAMDAC_WRITE((dstBox->x1&0xf00)>>8, PM3RD_VideoOverlayXStartHigh);
768    RAMDAC_WRITE((dstBox->x2&0xff), PM3RD_VideoOverlayXEndLow);
769    RAMDAC_WRITE((dstBox->x2&0xf00)>>8,PM3RD_VideoOverlayXEndHigh);
770    RAMDAC_WRITE((dstBox->y1&0xff), PM3RD_VideoOverlayYStartLow);
771    RAMDAC_WRITE((dstBox->y1&0xf00)>>8, PM3RD_VideoOverlayYStartHigh);
772    RAMDAC_WRITE((dstBox->y2&0xff), PM3RD_VideoOverlayYEndLow);
773    RAMDAC_WRITE((dstBox->y2&0xf00)>>8,PM3RD_VideoOverlayYEndHigh);
774
775    GLINT_WRITE_REG(portPriv->Video_Shift << 5 |
776	portPriv->Format |
777	portPriv->Filter |
778	PM3VideoOverlayMode_BUFFERSYNC_MANUAL |
779	PM3VideoOverlayMode_FLIP_VIDEO |
780	PM3VideoOverlayMode_ENABLE,
781	PM3VideoOverlayMode);
782
783    if (!portPriv->ramdacOn) {
784    	RAMDAC_WRITE(PM3RD_VideoOverlayControl_ENABLE |
785		PM3RD_VideoOverlayControl_KEY_COLOR |
786		PM3RD_VideoOverlayControl_MODE_MAINKEY |
787		PM3RD_VideoOverlayControl_DIRECTCOLOR_ENABLED,
788		PM3RD_VideoOverlayControl);
789	portPriv->ramdacOn = TRUE;
790    }
791    GLINT_WRITE_REG(PM3VideoOverlayUpdate_ENABLE,
792	PM3VideoOverlayUpdate);
793}
794
795static int
796Permedia3PutImage(
797  ScrnInfoPtr pScrn,
798  short src_x, short src_y,
799  short drw_x, short drw_y,
800  short src_w, short src_h,
801  short drw_w, short drw_h,
802  int id, unsigned char* buf,
803  short width, short height,
804  Bool sync,
805  RegionPtr clipBoxes, pointer data,
806  DrawablePtr pDraw
807){
808#if 0
809   GLINTPtr pGlint = GLINTPTR(pScrn);
810#endif
811   GLINTPortPrivPtr pPriv = (GLINTPortPrivPtr)data;
812   INT32 x1, x2, y1, y2;
813   int pitch;
814   int i;
815   int w_bpp, bpp;
816   Bool copy_flat = TRUE;
817   BoxRec dstBox;
818
819   /* Let's find the image format and Video_Shift values */
820   switch (id) {
821	case LE4CC('Y','V','1','2'):
822	    pPriv->Format = FORMAT_YUV422;
823	    pPriv->Video_Shift = 1;
824	    copy_flat = FALSE;
825	    break;
826	case LE4CC('Y','U','Y','2'):
827	    pPriv->Format = FORMAT_YUV422;
828	    pPriv->Video_Shift = 1;
829	    break;
830	case LE4CC('U','Y','V','Y'):
831	    pPriv->Format = FORMAT_VUY422;
832	    pPriv->Video_Shift = 1;
833	    break;
834	case LE4CC('Y','U','V','A'):
835	    pPriv->Format = FORMAT_YUV444;
836	    pPriv->Video_Shift = 2;
837	    break;
838	case LE4CC('V','U','Y','A'):
839	    pPriv->Format = FORMAT_VUY444;
840	    pPriv->Video_Shift = 2;
841	    break;
842	case 0x41: /* RGBA 8:8:8:8 */
843	    pPriv->Format = FORMAT_RGB8888;
844	    pPriv->Video_Shift = 2;
845	    break;
846	case 0x42: /* RGB 5:6:5 */
847	    pPriv->Format = FORMAT_RGB565;
848	    pPriv->Video_Shift = 1;
849	    break;
850	case 0x43: /* RGB 1:5:5:5 */
851	    pPriv->Format = FORMAT_RGB5551;
852	    pPriv->Video_Shift = 1;
853	    break;
854	case 0x44: /* RGB 4:4:4:4 */
855	    pPriv->Format = FORMAT_RGB4444;
856	    pPriv->Video_Shift = 1;
857	    break;
858	case 0x46: /* RGB 2:3:3 */
859	    pPriv->Format = FORMAT_RGB332;
860	    pPriv->Video_Shift = 0;
861	    break;
862	case 0x47: /* BGRA 8:8:8:8 */
863	    pPriv->Format = FORMAT_BGR8888;
864	    pPriv->Video_Shift = 2;
865	    break;
866	case 0x48: /* BGR 5:6:5 */
867	    pPriv->Format = FORMAT_BGR565;
868	    pPriv->Video_Shift = 1;
869	    break;
870	case 0x49: /* BGR 1:5:5:5 */
871	    pPriv->Format = FORMAT_BGR5551;
872	    pPriv->Video_Shift = 1;
873	    break;
874	case 0x4A: /* BGR 4:4:4:4 */
875	    pPriv->Format = FORMAT_BGR4444;
876	    pPriv->Video_Shift = 1;
877	    break;
878	case 0x4C: /* BGR 2:3:3 */
879	    pPriv->Format = FORMAT_BGR332;
880	    pPriv->Video_Shift = 0;
881	    break;
882	default:
883	    return XvBadAlloc;
884    }
885
886    /* Clip */
887    x1 = src_x;
888    x2 = src_x + src_w;
889    y1 = src_y;
890    y2 = src_y + src_h;
891
892    dstBox.x1 = drw_x;
893    dstBox.x2 = drw_x + drw_w;
894    dstBox.y1 = drw_y;
895    dstBox.y2 = drw_y + drw_h;
896
897    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
898                              width, height))
899    	return Success;
900
901    dstBox.x1 -= pScrn->frameX0;
902    dstBox.x2 -= pScrn->frameX0;
903    dstBox.y1 -= pScrn->frameY0;
904    dstBox.y2 -= pScrn->frameY0;
905
906    bpp = pScrn->bitsPerPixel >> 3;
907    pitch = bpp * pScrn->displayWidth;
908
909    w_bpp = (width << pPriv->Video_Shift) >> (pScrn->bitsPerPixel >> 4);
910
911    for (i = 0; i < (pPriv->doubleBuffer ? 2 : 1); i++) {
912      if (!(pPriv->area[i] =
913		Permedia3AllocateMemory(pScrn,pPriv->area[i],w_bpp,src_h)))
914        return BadAlloc;
915
916      pPriv->offset[i] = (pPriv->area[i]->box.x1 * bpp) +
917					(pPriv->area[i]->box.y1 * pitch);
918    }
919
920    HWCopySetup(pScrn, pPriv->area[pPriv->buffer]->box.x1,
921		       pPriv->area[pPriv->buffer]->box.y1, w_bpp, height);
922
923    if (copy_flat)
924	HWCopyFlat(pScrn, buf, width, height);
925    else
926	HWCopyYV12(pScrn, buf, width, height);
927
928    /* paint the color key */
929    if(pPriv->autopaintColorKey &&
930       !REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
931    	/* update cliplist */
932        REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
933#if 0
934	GLINT_WAIT(1);
935    	GLINT_WRITE_REG(PM3VideoOverlayMode_DISABLE,
936						PM3VideoOverlayMode);
937	pPriv->ramdacOn = FALSE;
938#endif
939        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
940    }
941
942    Permedia3Sync(pScrn);
943
944    Permedia3DisplayVideo(pScrn, id, pPriv->offset[pPriv->buffer], width,height,
945	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
946
947    /* Switch buffer on next run - double buffer */
948    if (pPriv->doubleBuffer) {
949    	if (!pPriv->buffer)
950	    pPriv->buffer = 1;
951    	else
952	    pPriv->buffer = 0;
953    }
954
955    pPriv->videoStatus = CLIENT_VIDEO_ON;
956
957    return Success;
958}
959
960static int
961Permedia3QueryImageAttributes(
962  ScrnInfoPtr pScrn,
963  int id,
964  unsigned short *w, unsigned short *h,
965  int *pitches, int *offsets
966){
967    int size, tmp;
968
969    if(*w > 2047) *w = 2047;
970    if(*h > 2047) *h = 2047;
971
972    *w = (*w + 1) & ~1;
973    if(offsets) offsets[0] = 0;
974
975    switch(id) {
976    case FOURCC_YV12:		/* YV12 */
977	*h = (*h + 1) & ~1;
978	size = (*w + 3) & ~3;
979	if(pitches) pitches[0] = size;
980	size *= *h;
981	if(offsets) offsets[1] = size;
982	tmp = ((*w >> 1) + 3) & ~3;
983	if(pitches) pitches[1] = pitches[2] = tmp;
984	tmp *= (*h >> 1);
985	size += tmp;
986	if(offsets) offsets[2] = size;
987	size += tmp;
988	break;
989    default:			/* RGB15, RGB16, YUY2 */
990	size = *w << 1;
991	if(pitches) pitches[0] = size;
992	size *= *h;
993	break;
994    }
995
996    return size;
997}
998
999/****************** Offscreen stuff ***************/
1000
1001typedef struct {
1002  FBAreaPtr area;
1003  Bool isOn;
1004  int Video_Shift;
1005  int Format;
1006  Bool ramdacOn;
1007} OffscreenPrivRec, * OffscreenPrivPtr;
1008
1009static int
1010Permedia3AllocateSurface(
1011    ScrnInfoPtr pScrn,
1012    int id,
1013    unsigned short w,
1014    unsigned short h,
1015    XF86SurfacePtr surface
1016){
1017    FBAreaPtr area;
1018    int fbpitch, bpp;
1019    OffscreenPrivPtr pPriv;
1020
1021    if((w > 2047) || (h > 2047))
1022	return BadAlloc;
1023
1024    w = (w + 1) & ~1;
1025    bpp = pScrn->bitsPerPixel >> 3;
1026    fbpitch = bpp * pScrn->displayWidth;
1027
1028    if(!(area = Permedia3AllocateMemory(pScrn, NULL, w, h)))
1029	return BadAlloc;
1030
1031    surface->width = w;
1032    surface->height = h;
1033
1034    if(!(surface->offsets = xalloc(sizeof(int)))) {
1035	xf86FreeOffscreenArea(area);
1036	return BadAlloc;
1037    }
1038    if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
1039	xfree(surface->offsets);
1040	xf86FreeOffscreenArea(area);
1041	return BadAlloc;
1042    }
1043
1044    pPriv->area = area;
1045    pPriv->isOn = FALSE;
1046
1047    surface->pScrn = pScrn;
1048    surface->id = id;
1049    surface->offsets[0] = (area->box.x1 * bpp) + (area->box.y1 * fbpitch);
1050    surface->devPrivate.ptr = (pointer)pPriv;
1051
1052    return Success;
1053}
1054
1055static int
1056Permedia3StopSurface(
1057    XF86SurfacePtr surface
1058){
1059    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1060
1061    if(pPriv->isOn) {
1062	GLINTPtr pGlint = GLINTPTR(surface->pScrn);
1063    	pPriv->ramdacOn = FALSE;
1064	GLINT_WAIT(4);
1065        RAMDAC_WRITE(PM3RD_VideoOverlayControl_DISABLE,
1066		PM3RD_VideoOverlayControl);
1067	GLINT_WRITE_REG(PM3VideoOverlayMode_DISABLE,
1068		PM3VideoOverlayMode);
1069	pPriv->isOn = FALSE;
1070    }
1071
1072    return Success;
1073}
1074
1075static int
1076Permedia3FreeSurface(
1077    XF86SurfacePtr surface
1078){
1079    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1080
1081    if(pPriv->isOn)
1082	Permedia3StopSurface(surface);
1083    xf86FreeOffscreenArea(pPriv->area);
1084    xfree(surface->pitches);
1085    xfree(surface->offsets);
1086    xfree(surface->devPrivate.ptr);
1087
1088    return Success;
1089}
1090
1091static int
1092Permedia3GetSurfaceAttribute(
1093    ScrnInfoPtr pScrn,
1094    Atom attribute,
1095    INT32 *value
1096){
1097    return Permedia3GetPortAttribute(pScrn, attribute, value,
1098			(pointer)(GET_PORT_PRIVATE(pScrn)));
1099}
1100
1101static int
1102Permedia3SetSurfaceAttribute(
1103    ScrnInfoPtr pScrn,
1104    Atom attribute,
1105    INT32 value
1106){
1107    return Permedia3SetPortAttribute(pScrn, attribute, value,
1108			(pointer)(GET_PORT_PRIVATE(pScrn)));
1109}
1110
1111static int
1112Permedia3DisplaySurface(
1113    XF86SurfacePtr surface,
1114    short src_x, short src_y,
1115    short drw_x, short drw_y,
1116    short src_w, short src_h,
1117    short drw_w, short drw_h,
1118    RegionPtr clipBoxes
1119){
1120    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1121    ScrnInfoPtr pScrn = surface->pScrn;
1122    GLINTPtr pGlint = GLINTPTR(pScrn);
1123    GLINTPortPrivPtr portPriv = pGlint->adaptor->pPortPrivates[0].ptr;
1124    INT32 x1, y1, x2, y2;
1125    BoxRec dstBox;
1126
1127    x1 = src_x;
1128    x2 = src_x + src_w;
1129    y1 = src_y;
1130    y2 = src_y + src_h;
1131
1132    dstBox.x1 = drw_x;
1133    dstBox.x2 = drw_x + drw_w;
1134    dstBox.y1 = drw_y;
1135    dstBox.y2 = drw_y + drw_h;
1136
1137    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1138		    surface->width, surface->height))
1139    {
1140        return Success;
1141    }
1142
1143    dstBox.x1 -= pScrn->frameX0;
1144    dstBox.x2 -= pScrn->frameX0;
1145    dstBox.y1 -= pScrn->frameY0;
1146    dstBox.y2 -= pScrn->frameY0;
1147
1148   /* Let's find the image format and Video_Shift values */
1149   switch (surface->id) {
1150	case LE4CC('Y','V','1','2'):
1151	    pPriv->Format = FORMAT_YUV422;
1152	    pPriv->Video_Shift = 1;
1153	    break;
1154	case LE4CC('Y','U','Y','2'):
1155	    pPriv->Format = FORMAT_YUV422;
1156	    pPriv->Video_Shift = 1;
1157	    break;
1158	case LE4CC('U','Y','V','Y'):
1159	    pPriv->Format = FORMAT_VUY422;
1160	    pPriv->Video_Shift = 1;
1161	    break;
1162	case LE4CC('Y','U','V','A'):
1163	    pPriv->Format = FORMAT_YUV444;
1164	    pPriv->Video_Shift = 2;
1165	    break;
1166	case LE4CC('V','U','Y','A'):
1167	    pPriv->Format = FORMAT_VUY444;
1168	    pPriv->Video_Shift = 2;
1169	    break;
1170	case 0x41: /* RGBA 8:8:8:8 */
1171	    pPriv->Format = FORMAT_RGB8888;
1172	    pPriv->Video_Shift = 2;
1173	    break;
1174	case 0x42: /* RGB 5:6:5 */
1175	    pPriv->Format = FORMAT_RGB565;
1176	    pPriv->Video_Shift = 1;
1177	    break;
1178	case 0x43: /* RGB 1:5:5:5 */
1179	    pPriv->Format = FORMAT_RGB5551;
1180	    pPriv->Video_Shift = 1;
1181	    break;
1182	case 0x44: /* RGB 4:4:4:4 */
1183	    pPriv->Format = FORMAT_RGB4444;
1184	    pPriv->Video_Shift = 1;
1185	    break;
1186	case 0x46: /* RGB 2:3:3 */
1187	    pPriv->Format = FORMAT_RGB332;
1188	    pPriv->Video_Shift = 0;
1189	    break;
1190	case 0x47: /* BGRA 8:8:8:8 */
1191	    pPriv->Format = FORMAT_BGR8888;
1192	    pPriv->Video_Shift = 2;
1193	    break;
1194	case 0x48: /* BGR 5:6:5 */
1195	    pPriv->Format = FORMAT_BGR565;
1196	    pPriv->Video_Shift = 1;
1197	    break;
1198	case 0x49: /* BGR 1:5:5:5 */
1199	    pPriv->Format = FORMAT_BGR5551;
1200	    pPriv->Video_Shift = 1;
1201	    break;
1202	case 0x4A: /* BGR 4:4:4:4 */
1203	    pPriv->Format = FORMAT_BGR4444;
1204	    pPriv->Video_Shift = 1;
1205	    break;
1206	case 0x4C: /* BGR 2:3:3 */
1207	    pPriv->Format = FORMAT_BGR332;
1208	    pPriv->Video_Shift = 0;
1209	    break;
1210	default:
1211	    return XvBadAlloc;
1212    }
1213
1214    Permedia3DisplayVideo(pScrn, surface->id, surface->offsets[0],
1215	     surface->width, surface->height,
1216	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1217
1218    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
1219
1220    pPriv->isOn = TRUE;
1221    /* we've prempted the XvImage stream so set its free timer */
1222    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
1223	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
1224	UpdateCurrentTime();
1225	portPriv->videoStatus = FREE_TIMER;
1226	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1227	pGlint->VideoTimerCallback = Permedia3VideoTimerCallback;
1228    }
1229
1230    return Success;
1231}
1232
1233static void
1234Permedia3InitOffscreenImages(ScreenPtr pScreen)
1235{
1236    XF86OffscreenImagePtr offscreenImages;
1237
1238    /* need to free this someplace */
1239    if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
1240	return;
1241
1242    offscreenImages[0].image = &Images[0];
1243    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1244			       VIDEO_CLIP_TO_VIEWPORT;
1245    offscreenImages[0].alloc_surface = Permedia3AllocateSurface;
1246    offscreenImages[0].free_surface = Permedia3FreeSurface;
1247    offscreenImages[0].display = Permedia3DisplaySurface;
1248    offscreenImages[0].stop = Permedia3StopSurface;
1249    offscreenImages[0].setAttribute = Permedia3SetSurfaceAttribute;
1250    offscreenImages[0].getAttribute = Permedia3GetSurfaceAttribute;
1251    offscreenImages[0].max_width = 2047;
1252    offscreenImages[0].max_height = 2047;
1253    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
1254    offscreenImages[0].attributes = Attributes;
1255
1256    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
1257}
1258
1259static void
1260Permedia3VideoTimerCallback(ScrnInfoPtr pScrn, Time time)
1261{
1262    GLINTPtr pGlint = GLINTPTR(pScrn);
1263    GLINTPortPrivPtr pPriv = pGlint->adaptor->pPortPrivates[0].ptr;
1264    int i;
1265
1266    if(pPriv->videoStatus & TIMER_MASK) {
1267	if(pPriv->videoStatus & OFF_TIMER) {
1268	    if(pPriv->offTime < time) {
1269		pPriv->ramdacOn = FALSE;
1270		GLINT_WAIT(4);
1271        	RAMDAC_WRITE(PM3RD_VideoOverlayControl_DISABLE,
1272					PM3RD_VideoOverlayControl);
1273		GLINT_WRITE_REG(PM3VideoOverlayMode_DISABLE,
1274					PM3VideoOverlayMode);
1275		pPriv->videoStatus = FREE_TIMER;
1276		pPriv->freeTime = time + FREE_DELAY;
1277	    }
1278	} else {  /* FREE_TIMER */
1279	    if(pPriv->freeTime < time) {
1280		for (i = 0; i < (pPriv->doubleBuffer ? 2 : 1); i++) {
1281		   if(pPriv->area[i]) {
1282		      xf86FreeOffscreenArea(pPriv->area[i]);
1283		      pPriv->area[i] = NULL;
1284		   }
1285		}
1286		pPriv->videoStatus = 0;
1287	        pGlint->VideoTimerCallback = NULL;
1288	    }
1289        }
1290    } else  /* shouldn't get here */
1291	pGlint->VideoTimerCallback = NULL;
1292}
1293