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