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