ct_video.c revision c06b6b69
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/chips/ct_video.c,v 1.16tsi Exp $ */
2
3#ifdef HAVE_CONFIG_H
4#include "config.h"
5#endif
6
7#include "xf86.h"
8#include "xf86_OSproc.h"
9#include "xf86Resources.h"
10#include "compiler.h"
11#include "xf86PciInfo.h"
12#include "xf86Pci.h"
13#include "xf86fbman.h"
14#include "regionstr.h"
15
16#include "ct_driver.h"
17#include <X11/extensions/Xv.h>
18#include "xaa.h"
19#include "xaalocal.h"
20#include "dixstruct.h"
21#include "fourcc.h"
22
23#define OFF_DELAY 	200  /* milliseconds */
24#define FREE_DELAY 	60000
25
26#define OFF_TIMER 	0x01
27#define FREE_TIMER	0x02
28#define CLIENT_VIDEO_ON	0x04
29
30#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
31
32static XF86VideoAdaptorPtr CHIPSSetupImageVideo(ScreenPtr);
33static void CHIPSInitOffscreenImages(ScreenPtr);
34static void CHIPSStopVideo(ScrnInfoPtr, pointer, Bool);
35static int CHIPSSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
36static int CHIPSGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
37static void CHIPSQueryBestSize(ScrnInfoPtr, Bool,
38	short, short, short, short, unsigned int *, unsigned int *, pointer);
39static int CHIPSPutImage( ScrnInfoPtr,
40	short, short, short, short, short, short, short, short,
41	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
42	DrawablePtr);
43static int CHIPSQueryImageAttributes(ScrnInfoPtr,
44	int, unsigned short *, unsigned short *,  int *, int *);
45static void CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
46
47
48#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
49
50static Atom xvColorKey;
51
52void
53CHIPSInitVideo(ScreenPtr pScreen)
54{
55    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
56    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
57    XF86VideoAdaptorPtr newAdaptor = NULL;
58    CHIPSPtr cPtr = CHIPSPTR(pScrn);
59    int num_adaptors;
60
61    if (!(cPtr->Flags & ChipsOverlay8plus16) &&
62       (cPtr->Flags & ChipsVideoSupport)) {
63	newAdaptor = CHIPSSetupImageVideo(pScreen);
64	CHIPSInitOffscreenImages(pScreen);
65    }
66
67    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
68
69    if(newAdaptor) {
70	if(!num_adaptors) {
71	    num_adaptors = 1;
72	    adaptors = &newAdaptor;
73	} else {
74	    newAdaptors =  /* need to free this someplace */
75		xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
76	    if(newAdaptors) {
77		memcpy(newAdaptors, adaptors, num_adaptors *
78					sizeof(XF86VideoAdaptorPtr));
79		newAdaptors[num_adaptors] = newAdaptor;
80		adaptors = newAdaptors;
81		num_adaptors++;
82	    }
83	}
84    }
85
86    if(num_adaptors)
87        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
88
89    if(newAdaptors)
90	xfree(newAdaptors);
91}
92
93/* client libraries expect an encoding */
94static
95XF86VideoEncodingRec DummyEncoding[1] =
96{
97 {
98   0,
99   "XV_IMAGE",
100   1024, 1024,
101   {1, 1}
102 }
103};
104
105#define NUM_FORMATS 4
106
107static XF86VideoFormatRec Formats[NUM_FORMATS] =
108{
109  {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
110};
111
112#define NUM_ATTRIBUTES 1
113
114static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
115{
116   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}
117};
118
119#define NUM_IMAGES 4
120
121static XF86ImageRec Images[NUM_IMAGES] =
122{
123   {
124	0x35315652,
125        XvRGB,
126	LSBFirst,
127	{'R','V','1','5',
128	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
129	16,
130	XvPacked,
131	1,
132	15, 0x7C00, 0x03E0, 0x001F,
133	0, 0, 0,
134	0, 0, 0,
135	0, 0, 0,
136	{'R','V','B',0,
137	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
138	XvTopToBottom
139   },
140   {
141	0x36315652,
142        XvRGB,
143	LSBFirst,
144	{'R','V','1','6',
145	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
146	16,
147	XvPacked,
148	1,
149	16, 0xF800, 0x07E0, 0x001F,
150	0, 0, 0,
151	0, 0, 0,
152	0, 0, 0,
153	{'R','V','B',0,
154	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
155	XvTopToBottom
156   },
157   XVIMAGE_YV12,
158   XVIMAGE_YUY2
159};
160
161typedef struct {
162   FBLinearPtr	linear;
163   RegionRec	clip;
164   CARD32	colorKey;
165   CARD32	videoStatus;
166   Time		offTime;
167   Time		freeTime;
168   Bool         doubleBuffer;
169   Bool         manualDoubleBuffer;
170   int          currentBuffer;
171} CHIPSPortPrivRec, *CHIPSPortPrivPtr;
172
173
174#define GET_PORT_PRIVATE(pScrn) \
175   (CHIPSPortPrivPtr)((CHIPSPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
176
177void
178CHIPSResetVideo(ScrnInfoPtr pScrn)
179{
180    CHIPSPtr cPtr = CHIPSPTR(pScrn);
181    CHIPSPortPrivPtr pPriv = cPtr->adaptor->pPortPrivates[0].ptr;
182    unsigned char mr3c;
183    int red, green, blue;
184
185    if (cPtr->Flags & ChipsAccelSupport)
186	CHIPSHiQVSync(pScrn);
187
188    mr3c = cPtr->readMR(cPtr, 0x3C);
189    cPtr->writeMR(cPtr, 0x3C, (mr3c | 0x6));
190    switch (pScrn->depth) {
191    case 8:
192	cPtr->writeMR(cPtr, 0x3D, 0x00);
193	cPtr->writeMR(cPtr, 0x3E, 0x00);
194	cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF));
195	cPtr->writeMR(cPtr, 0x40, 0xFF);
196	cPtr->writeMR(cPtr, 0x41, 0xFF);
197	cPtr->writeMR(cPtr, 0x42, 0x00);
198	break;
199    default:
200	red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
201	green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
202	blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
203	switch (pScrn->depth) {
204	case 15:
205	    cPtr->writeMR(cPtr, 0x3D, (red << 3));
206	    cPtr->writeMR(cPtr, 0x3E, (green << 3));
207	    cPtr->writeMR(cPtr, 0x3F, (blue << 3));
208	    cPtr->writeMR(cPtr, 0x40, 0x07);
209	    cPtr->writeMR(cPtr, 0x41, 0x07);
210	    cPtr->writeMR(cPtr, 0x42, 0x07);
211	    break;
212	case 16:
213	    cPtr->writeMR(cPtr, 0x3D, (red << 3));
214	    cPtr->writeMR(cPtr, 0x3E, (green << 2));
215	    cPtr->writeMR(cPtr, 0x3F, (blue << 3));
216	    cPtr->writeMR(cPtr, 0x40, 0x07);
217	    cPtr->writeMR(cPtr, 0x41, 0x03);
218	    cPtr->writeMR(cPtr, 0x42, 0x07);
219	    break;
220	case 24:
221	    cPtr->writeMR(cPtr, 0x3D, red);
222	    cPtr->writeMR(cPtr, 0x3E, green);
223	    cPtr->writeMR(cPtr, 0x3F, blue);
224	    cPtr->writeMR(cPtr, 0x40, 0x00);
225	    cPtr->writeMR(cPtr, 0x41, 0x00);
226	    cPtr->writeMR(cPtr, 0x42, 0x00);
227	    break;
228	}
229    }
230}
231
232
233static XF86VideoAdaptorPtr
234CHIPSSetupImageVideo(ScreenPtr pScreen)
235{
236    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
237    CHIPSPtr cPtr = CHIPSPTR(pScrn);
238    XF86VideoAdaptorPtr adapt;
239    CHIPSPortPrivPtr pPriv;
240
241    if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
242			    sizeof(CHIPSPortPrivRec) +
243			    sizeof(DevUnion))))
244	return NULL;
245
246    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
247    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
248    adapt->name = "Chips and Technologies Backend Scaler";
249    adapt->nEncodings = 1;
250    adapt->pEncodings = DummyEncoding;
251    adapt->nFormats = NUM_FORMATS;
252    adapt->pFormats = Formats;
253    adapt->nPorts = 1;
254    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
255    pPriv = (CHIPSPortPrivPtr)(&adapt->pPortPrivates[1]);
256    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
257    adapt->pAttributes = Attributes;
258    adapt->nImages = NUM_IMAGES;
259    adapt->nAttributes = NUM_ATTRIBUTES;
260    adapt->pImages = Images;
261    adapt->PutVideo = NULL;
262    adapt->PutStill = NULL;
263    adapt->GetVideo = NULL;
264    adapt->GetStill = NULL;
265    adapt->StopVideo = CHIPSStopVideo;
266    adapt->SetPortAttribute = CHIPSSetPortAttribute;
267    adapt->GetPortAttribute = CHIPSGetPortAttribute;
268    adapt->QueryBestSize = CHIPSQueryBestSize;
269    adapt->PutImage = CHIPSPutImage;
270    adapt->QueryImageAttributes = CHIPSQueryImageAttributes;
271
272    pPriv->colorKey = cPtr->videoKey;
273    pPriv->videoStatus = 0;
274    pPriv->manualDoubleBuffer = FALSE;
275    pPriv->currentBuffer	= 0;
276
277    /* gotta uninit this someplace */
278    REGION_NULL(pScreen, &pPriv->clip);
279
280    cPtr->adaptor = adapt;
281
282    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
283
284    CHIPSResetVideo(pScrn);
285
286    return adapt;
287}
288
289
290static void
291CHIPSStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shadow)
292{
293  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
294  CHIPSPtr cPtr = CHIPSPTR(pScrn);
295  unsigned char mr3c, tmp;
296
297  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
298  if (cPtr->Flags & ChipsAccelSupport)
299      CHIPSHiQVSync(pScrn);
300  if(shadow) {
301     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
302	mr3c = cPtr->readMR(cPtr, 0x3C);
303	cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
304	tmp = cPtr->readXR(cPtr, 0xD0);
305	cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf));
306     }
307     if(pPriv->linear) {
308	xf86FreeOffscreenLinear(pPriv->linear);
309	pPriv->linear = NULL;
310     }
311     pPriv->videoStatus = 0;
312  } else {
313     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
314	pPriv->videoStatus |= OFF_TIMER;
315	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
316	cPtr->VideoTimerCallback = CHIPSVideoTimerCallback;
317     }
318  }
319}
320
321static int
322CHIPSSetPortAttribute(
323  ScrnInfoPtr pScrn,
324  Atom attribute,
325  INT32 value,
326  pointer data
327){
328  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
329  CHIPSPtr cPtr = CHIPSPTR(pScrn);
330
331  if (cPtr->Flags & ChipsAccelSupport)
332      CHIPSHiQVSync(pScrn);
333  if(attribute == xvColorKey) {
334	int red, green, blue;
335	pPriv->colorKey = value;
336	switch (pScrn->depth) {
337	case 8:
338	    cPtr->writeMR(cPtr, 0x3D, 0x00);
339	    cPtr->writeMR(cPtr, 0x3E, 0x00);
340	    cPtr->writeMR(cPtr, 0x3F, (pPriv->colorKey & 0xFF));
341	    break;
342	default:
343	    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
344	    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
345	    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
346	    switch (pScrn->depth) {
347	    case 15:
348		cPtr->writeMR(cPtr, 0x3D, (red << 3));
349		cPtr->writeMR(cPtr, 0x3E, (green << 3));
350		cPtr->writeMR(cPtr, 0x3F, (blue << 3));
351		break;
352	    case 16:
353		cPtr->writeMR(cPtr, 0x3D, (red << 3));
354		cPtr->writeMR(cPtr, 0x3E, (green << 2));
355		cPtr->writeMR(cPtr, 0x3F, (blue << 3));
356		break;
357	    case 24:
358		cPtr->writeMR(cPtr, 0x3D, red);
359		cPtr->writeMR(cPtr, 0x3E, green);
360		cPtr->writeMR(cPtr, 0x3F, blue);
361		break;
362	    }
363	}
364	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
365  } else return BadMatch;
366
367  return Success;
368}
369
370static int
371CHIPSGetPortAttribute(
372  ScrnInfoPtr pScrn,
373  Atom attribute,
374  INT32 *value,
375  pointer data
376){
377  CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
378
379  if(attribute == xvColorKey) {
380	*value = pPriv->colorKey;
381  } else return BadMatch;
382
383  return Success;
384}
385
386static void
387CHIPSQueryBestSize(
388  ScrnInfoPtr pScrn,
389  Bool motion,
390  short vid_w, short vid_h,
391  short drw_w, short drw_h,
392  unsigned int *p_w, unsigned int *p_h,
393  pointer data
394){
395  *p_w = drw_w;
396  *p_h = drw_h;
397
398  if(*p_w > 16384) *p_w = 16384;
399}
400
401
402static void
403CHIPSCopyData(
404  unsigned char *src,
405  unsigned char *dst,
406  int srcPitch,
407  int dstPitch,
408  int h,
409  int w
410){
411    w <<= 1;
412    while(h--) {
413	memcpy(dst, src, w);
414	src += srcPitch;
415	dst += dstPitch;
416    }
417}
418
419static void
420CHIPSCopyMungedData(
421   unsigned char *src1,
422   unsigned char *src2,
423   unsigned char *src3,
424   unsigned char *dst1,
425   int srcPitch,
426   int srcPitch2,
427   int dstPitch,
428   int h,
429   int w
430){
431   CARD32 *dst = (CARD32*)dst1;
432   int i, j;
433
434   dstPitch >>= 2;
435   w >>= 1;
436
437   for(j = 0; j < h; j++) {
438	for(i = 0; i < w; i++) {
439	    dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
440		     (src3[i] << 8) | (src2[i] << 24);
441	}
442	dst += dstPitch;
443	src1 += srcPitch;
444	if(j & 1) {
445	    src2 += srcPitch2;
446	    src3 += srcPitch2;
447	}
448   }
449}
450
451static FBLinearPtr
452CHIPSAllocateMemory(
453   ScrnInfoPtr pScrn,
454   FBLinearPtr linear,
455   int size
456){
457   ScreenPtr pScreen;
458   FBLinearPtr new_linear;
459
460   if(linear) {
461	if(linear->size >= size)
462	   return linear;
463
464        if(xf86ResizeOffscreenLinear(linear, size))
465	   return linear;
466
467	xf86FreeOffscreenLinear(linear);
468   }
469
470   pScreen = screenInfo.screens[pScrn->scrnIndex];
471
472   new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
473   						NULL, NULL, NULL);
474
475   if(!new_linear) {
476	int max_size;
477
478	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8,
479						PRIORITY_EXTREME);
480
481	if(max_size < size)
482	   return NULL;
483
484	xf86PurgeUnlockedOffscreenAreas(pScreen);
485	new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8,
486						NULL, NULL, NULL);
487   }
488
489   return new_linear;
490}
491
492static int
493CHIPSSetCurrentPlaybackBuffer(CHIPSPtr cPtr, int n)
494{
495
496    CARD8 mr20;
497    mr20 = cPtr->readMR(cPtr, 0x20);
498    mr20 &= ~0x1B;
499    if (!n) mr20 |= 0x10;
500    cPtr->writeMR(cPtr, 0x22, mr20);
501    return n;
502}
503
504static int
505CHIPSWaitGetNextFrame(CHIPSPtr cPtr)
506{
507    volatile CARD8 mr20;
508    volatile CARD8 mr21;
509
510    mr20 = cPtr->readMR(cPtr, 0x20);
511    while (1) {
512      mr21 = cPtr->readMR(cPtr, 0x21);
513      if (!(mr20 & (1 << 5)) || !(mr21 & 1))
514	break;
515    }
516    mr20 &= ~0x4;
517    mr20 = cPtr->readMR(cPtr, 0x20);
518    return (mr21 & 2)? 0 : 1;
519}
520
521static void
522CHIPSDisplayVideo(
523    ScrnInfoPtr pScrn,
524    int id,
525    int offset,
526    short width, short height,
527    int pitch,
528    int x1, int y1, int x2, int y2,
529    BoxPtr dstBox,
530    short src_w, short src_h,
531    short drw_w, short drw_h,
532    Bool triggerBufSwitch
533){
534    CHIPSPtr cPtr = CHIPSPTR(pScrn);
535    CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
536    DisplayModePtr mode = pScrn->currentMode;
537    unsigned char tmp, m1f, m1e;
538    int buffer = pPriv->currentBuffer;
539    Bool dblscan = (pScrn->currentMode->Flags & V_DBLSCAN) == V_DBLSCAN;
540    int val;
541
542    if (cPtr->Flags & ChipsAccelSupport)
543	CHIPSHiQVSync(pScrn);
544
545    tmp = cPtr->readXR(cPtr, 0xD0);
546    cPtr->writeXR(cPtr, 0xD0, (tmp | 0x10));
547
548    m1e = cPtr->readMR(cPtr, 0x1E);
549    m1e &= 0xE0;		/* Set Zoom and Direction */
550    if ((!(cPtr->PanelType & ChipsLCD)) && (mode->Flags & V_INTERLACE))
551	m1e |= 0x10;
552
553    m1f = cPtr->readMR(cPtr, 0x1F);
554    m1f = (m1f & 0x14); /* Mask reserved bits, unset interpolation */
555    switch(id) {
556    case 0x35315652:		/* RGB15 */
557	m1f |= 0x09;
558	break;
559    case 0x36315652:		/* RGB16 */
560	m1f |= 0x08;
561	break;
562    case FOURCC_YV12:		/* YV12 */
563      /* m1f |= 0x03 */
564	m1f |= 0x00;
565	break;
566    case FOURCC_YUY2:		/* YUY2 */
567    default:
568	m1f |= 0x00;		/* Do nothing here */
569	break;
570    }
571
572    offset += (x1 >> 15) & ~0x01;
573    /* Setup Pointer 1 */
574    if (!buffer || pPriv->manualDoubleBuffer || !pPriv->doubleBuffer) {
575        cPtr->writeMR(cPtr, 0x22, (offset & 0xF8));
576	cPtr->writeMR(cPtr, 0x23, ((offset >> 8) & 0xFF));
577	cPtr->writeMR(cPtr, 0x24, ((offset >> 16) & 0xFF));
578    }
579
580    /* Setup Pointer 2 */
581    if ((buffer && !pPriv->manualDoubleBuffer) || !pPriv->doubleBuffer) {
582        cPtr->writeMR(cPtr, 0x25, (offset & 0xF8));
583	cPtr->writeMR(cPtr, 0x26, ((offset >> 8) & 0xFF));
584	cPtr->writeMR(cPtr, 0x27, ((offset >> 16) & 0xFF));
585    }
586
587    tmp = cPtr->readMR(cPtr, 0x04);
588    if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch)
589      tmp |= 0x18;
590    cPtr->writeMR(cPtr, 0x04, tmp);
591
592    tmp = cPtr->readMR(cPtr, 0x20);
593    tmp &= 0xC3;
594
595    if (pPriv->doubleBuffer && !pPriv->manualDoubleBuffer && triggerBufSwitch)
596	tmp |= ((1 << 2  | 1 << 5) | ((buffer) ? (1 << 4) : 0));
597    cPtr->writeMR(cPtr, 0x20, tmp);
598
599    cPtr->writeMR(cPtr, 0x28, ((width >> 2) - 1)); /* Width */
600    cPtr->writeMR(cPtr, 0x34, ((width >> 2) - 1));
601
602    /* Left Edge of Overlay */
603    cPtr->writeMR(cPtr, 0x2A, ((cPtr->OverlaySkewX + dstBox->x1) & 0xFF));
604    tmp = cPtr->readMR(cPtr, 0x2B);
605    tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x1) >> 8) & 0x07);
606    cPtr->writeMR(cPtr, 0x2B, tmp);
607    /* Right Edge of Overlay */
608    cPtr->writeMR(cPtr, 0x2C, ((cPtr->OverlaySkewX + dstBox->x2 -1)
609				& 0xFF));
610    tmp = cPtr->readMR(cPtr, 0x2D);
611    tmp = (tmp & 0xF8) + (((cPtr->OverlaySkewX + dstBox->x2 - 1) >> 8) & 0x07);
612    cPtr->writeMR(cPtr, 0x2D, tmp);
613    /* Top Edge of Overlay */
614    val = cPtr->OverlaySkewY + (dstBox->y1 << (dblscan ? 1 : 0));
615    cPtr->writeMR(cPtr, 0x2E, ((val) & 0xFF));
616    tmp = cPtr->readMR(cPtr, 0x2F);
617    tmp = (tmp & 0xF8) + (((val) >> 8) & 0x07);
618    cPtr->writeMR(cPtr, 0x2F, tmp);
619    /* Bottom Edge of Overlay*/
620    val = cPtr->OverlaySkewY + (dstBox->y2 << (dblscan ? 1 : 0));
621    cPtr->writeMR(cPtr, 0x30, ((val - 1) & 0xFF));
622    tmp = cPtr->readMR(cPtr, 0x31);
623    tmp = (tmp & 0xF8) + (((val - 1) >> 8) & 0x07);
624    cPtr->writeMR(cPtr, 0x31, tmp);
625
626    /* Horizontal Zoom */
627    if (drw_w > src_w) {
628        m1f = m1f | 0x20; /* set H-interpolation */
629	m1e = m1e | 0x04;
630	tmp = cPtr->VideoZoomMax * src_w / drw_w;
631	cPtr->writeMR(cPtr, 0x32, tmp);
632    }
633
634    /* Vertical Zoom */
635    if (drw_h > src_h || dblscan) {
636        m1f = m1f | 0x80; /* set V-interpolation */
637	m1e = m1e | 0x08;
638	if (dblscan)
639	    tmp = cPtr->VideoZoomMax >> 1;
640	if (drw_h > src_h)
641	    tmp = tmp * src_h / drw_h;
642	cPtr->writeMR(cPtr, 0x33, tmp);
643    }
644    cPtr->writeMR(cPtr, 0x1F, m1f);
645    cPtr->writeMR(cPtr, 0x1E, m1e);
646
647    tmp = cPtr->readMR(cPtr, 0x3C);
648    cPtr->writeMR(cPtr, 0x3C, (tmp | 0x7));
649    if (cPtr->Flags & ChipsAccelSupport)
650	CHIPSHiQVSync(pScrn);
651}
652
653static int
654CHIPSPutImage(
655  ScrnInfoPtr pScrn,
656  short src_x, short src_y,
657  short drw_x, short drw_y,
658  short src_w, short src_h,
659  short drw_w, short drw_h,
660  int id, unsigned char* buf,
661  short width, short height,
662  Bool sync,
663  RegionPtr clipBoxes, pointer data,
664  DrawablePtr pDraw
665){
666   CHIPSPortPrivPtr pPriv = (CHIPSPortPrivPtr)data;
667   CHIPSPtr cPtr = CHIPSPTR(pScrn);
668   INT32 x1, x2, y1, y2;
669   unsigned char *dst_start;
670   int new_size, offset, offset2 = 0, offset3 = 0;
671   int srcPitch, srcPitch2 = 0, dstPitch;
672   int top, left, npixels, nlines, bpp;
673   BoxRec dstBox;
674   CARD32 tmp;
675
676   if(drw_w > 16384) drw_w = 16384;
677
678   /* Clip */
679   x1 = src_x;
680   x2 = src_x + src_w;
681   y1 = src_y;
682   y2 = src_y + src_h;
683
684   dstBox.x1 = drw_x;
685   dstBox.x2 = drw_x + drw_w;
686   dstBox.y1 = drw_y;
687   dstBox.y2 = drw_y + drw_h;
688
689   if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
690			      clipBoxes, width, height))
691	return Success;
692
693   dstBox.x1 -= pScrn->frameX0 & cPtr->viewportMask;
694   dstBox.x2 -= pScrn->frameX0 & cPtr->viewportMask;
695   dstBox.y1 -= pScrn->frameY0;
696   dstBox.y2 -= pScrn->frameY0;
697
698   bpp = pScrn->bitsPerPixel >> 3;
699
700   dstPitch = ((width << 1) + 15) & ~15;
701   new_size = ((dstPitch * height) + bpp - 1) / bpp;
702
703   pPriv->doubleBuffer = (pScrn->currentMode->Flags & V_DBLSCAN) != V_DBLSCAN;
704
705   if (pPriv->doubleBuffer)
706       new_size <<= 1;
707
708   switch(id) {
709   case FOURCC_YV12:		/* YV12 */
710	srcPitch = (width + 3) & ~3;
711	offset2 = srcPitch * height;
712	srcPitch2 = ((width >> 1) + 3) & ~3;
713	offset3 = (srcPitch2 * (height >> 1)) + offset2;
714	break;
715   default:			/* RGB15, RGB16, YUY2 */
716	srcPitch = (width << 1);
717	break;
718   }
719
720   if(!(pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear, new_size))) {
721       if (pPriv->doubleBuffer
722	   && (pPriv->linear = CHIPSAllocateMemory(pScrn, pPriv->linear,
723					      new_size >> 1))) {
724         new_size >>= 1;
725	 pPriv->doubleBuffer = FALSE;
726   } else
727	return BadAlloc;
728   }
729
730   /* copy data */
731   top = y1 >> 16;
732   left = (x1 >> 16) & ~1;
733   npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
734   left <<= 1;
735
736   offset = pPriv->linear->offset * bpp;
737   if (!pPriv->manualDoubleBuffer)
738     pPriv->currentBuffer = CHIPSWaitGetNextFrame(cPtr);
739   if(pPriv->doubleBuffer && pPriv->currentBuffer)
740	offset += (new_size * bpp) >> 1;
741
742   dst_start = cPtr->FbBase + offset + left + (top * dstPitch);
743
744   switch(id) {
745   case FOURCC_YV12:		/* YV12 */
746        top &= ~1;
747	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
748	offset2 += tmp;
749	offset3 += tmp;
750	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
751	CHIPSCopyMungedData(buf + (top * srcPitch) + (left >> 1),
752			  buf + offset2, buf + offset3, dst_start,
753			  srcPitch, srcPitch2, dstPitch, nlines, npixels);
754	break;
755   default:			/* RGB15, RGB16, YUY2 */
756	buf += (top * srcPitch) + left;
757	nlines = ((y2 + 0xffff) >> 16) - top;
758	CHIPSCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
759	break;
760   }
761
762   /* update cliplist */
763   if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
764	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
765        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
766   }
767
768   offset += top * dstPitch;
769   CHIPSDisplayVideo(pScrn, id, offset, width, height, dstPitch,
770	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, TRUE);
771
772   pPriv->videoStatus = CLIENT_VIDEO_ON;
773
774   if (pPriv->manualDoubleBuffer)
775     pPriv->currentBuffer ^= 1;
776
777   return Success;
778}
779
780static int
781CHIPSQueryImageAttributes(
782  ScrnInfoPtr pScrn,
783  int id,
784  unsigned short *w, unsigned short *h,
785  int *pitches, int *offsets
786){
787    int size, tmp;
788
789    if(*w > 1024) *w = 1024;
790    if(*h > 1024) *h = 1024;
791
792    *w = (*w + 1) & ~1;
793    if(offsets) offsets[0] = 0;
794
795    switch(id) {
796    case FOURCC_YV12:		/* YV12 */
797	*h = (*h + 1) & ~1;
798	size = (*w + 3) & ~3;
799	if(pitches) pitches[0] = size;
800	size *= *h;
801	if(offsets) offsets[1] = size;
802	tmp = ((*w >> 1) + 3) & ~3;
803	if(pitches) pitches[1] = pitches[2] = tmp;
804	tmp *= (*h >> 1);
805	size += tmp;
806	if(offsets) offsets[2] = size;
807	size += tmp;
808	break;
809    default:			/* RGB15, RGB16, YUY2 */
810	size = *w << 1;
811	if(pitches) pitches[0] = size;
812	size *= *h;
813	break;
814    }
815
816    return size;
817}
818
819
820static void
821CHIPSVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
822{
823    CHIPSPtr    cPtr = CHIPSPTR(pScrn);
824    CHIPSPortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
825    unsigned char mr3c;
826
827    if(pPriv->videoStatus & TIMER_MASK) {
828	if(pPriv->videoStatus & OFF_TIMER) {
829	    if(pPriv->offTime < time) {
830		if (cPtr->Flags & ChipsAccelSupport)
831		    CHIPSHiQVSync(pScrn);
832		mr3c = cPtr->readMR(cPtr, 0x3C);
833		cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
834		pPriv->videoStatus = FREE_TIMER;
835		pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
836	    }
837	} else {  /* FREE_TIMER */
838	    if(pPriv->freeTime < time) {
839		if(pPriv->linear) {
840		   xf86FreeOffscreenLinear(pPriv->linear);
841		   pPriv->linear = NULL;
842		}
843		pPriv->videoStatus = 0;
844	        cPtr->VideoTimerCallback = NULL;
845	    }
846        }
847    } else  /* shouldn't get here */
848	cPtr->VideoTimerCallback = NULL;
849}
850
851
852/****************** Offscreen stuff ***************/
853
854typedef struct {
855  FBLinearPtr linear;
856  Bool isOn;
857} OffscreenPrivRec, * OffscreenPrivPtr;
858
859static int
860CHIPSAllocateSurface(
861    ScrnInfoPtr pScrn,
862    int id,
863    unsigned short w,
864    unsigned short h,
865    XF86SurfacePtr surface
866){
867    FBLinearPtr linear;
868    int pitch, size, bpp;
869    OffscreenPrivPtr pPriv;
870
871    if((w > 1024) || (h > 1024))
872	return BadAlloc;
873
874    w = (w + 1) & ~1;
875    pitch = ((w << 1) + 15) & ~15;
876    bpp = pScrn->bitsPerPixel >> 3;
877    size = ((pitch * h) + bpp - 1) / bpp;
878
879    if(!(linear = CHIPSAllocateMemory(pScrn, NULL, size)))
880	return BadAlloc;
881
882    surface->width = w;
883    surface->height = h;
884
885    if(!(surface->pitches = xalloc(sizeof(int)))) {
886	xf86FreeOffscreenLinear(linear);
887	return BadAlloc;
888    }
889    if(!(surface->offsets = xalloc(sizeof(int)))) {
890	xfree(surface->pitches);
891	xf86FreeOffscreenLinear(linear);
892	return BadAlloc;
893    }
894    if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
895	xfree(surface->pitches);
896	xfree(surface->offsets);
897	xf86FreeOffscreenLinear(linear);
898	return BadAlloc;
899    }
900
901    pPriv->linear = linear;
902    pPriv->isOn = FALSE;
903
904    surface->pScrn = pScrn;
905    surface->id = id;
906    surface->pitches[0] = pitch;
907    surface->offsets[0] = linear->offset * bpp;
908    surface->devPrivate.ptr = (pointer)pPriv;
909
910    return Success;
911}
912
913static int
914CHIPSStopSurface(
915    XF86SurfacePtr surface
916){
917    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
918
919    if(pPriv->isOn) {
920	CHIPSPtr cPtr = CHIPSPTR(surface->pScrn);
921	unsigned char mr3c, tmp;
922	tmp = cPtr->readXR(cPtr, 0xD0);
923	cPtr->writeXR(cPtr, 0xD0, (tmp & 0xf));
924	mr3c = cPtr->readMR(cPtr, 0x3C);
925	cPtr->writeMR(cPtr, 0x3C, (mr3c & 0xFE));
926	pPriv->isOn = FALSE;
927    }
928
929    return Success;
930}
931
932
933static int
934CHIPSFreeSurface(
935    XF86SurfacePtr surface
936){
937    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
938
939    if(pPriv->isOn)
940	CHIPSStopSurface(surface);
941    xf86FreeOffscreenLinear(pPriv->linear);
942    xfree(surface->pitches);
943    xfree(surface->offsets);
944    xfree(surface->devPrivate.ptr);
945
946    return Success;
947}
948
949static int
950CHIPSGetSurfaceAttribute(
951    ScrnInfoPtr pScrn,
952    Atom attribute,
953    INT32 *value
954){
955    return CHIPSGetPortAttribute(pScrn, attribute, value,
956			(pointer)(GET_PORT_PRIVATE(pScrn)));
957}
958
959static int
960CHIPSSetSurfaceAttribute(
961    ScrnInfoPtr pScrn,
962    Atom attribute,
963    INT32 value
964){
965    return CHIPSSetPortAttribute(pScrn, attribute, value,
966			(pointer)(GET_PORT_PRIVATE(pScrn)));
967}
968
969
970static int
971CHIPSDisplaySurface(
972    XF86SurfacePtr surface,
973    short src_x, short src_y,
974    short drw_x, short drw_y,
975    short src_w, short src_h,
976    short drw_w, short drw_h,
977    RegionPtr clipBoxes
978){
979    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
980    ScrnInfoPtr pScrn = surface->pScrn;
981    CHIPSPtr cPtr = CHIPSPTR(pScrn);
982    CHIPSPortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
983    INT32 x1, y1, x2, y2;
984    BoxRec dstBox;
985
986    x1 = src_x;
987    x2 = src_x + src_w;
988    y1 = src_y;
989    y2 = src_y + src_h;
990
991    dstBox.x1 = drw_x;
992    dstBox.x2 = drw_x + drw_w;
993    dstBox.y1 = drw_y;
994    dstBox.y2 = drw_y + drw_h;
995
996    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
997			      surface->width, surface->height))
998	return Success;
999
1000    dstBox.x1 -= pScrn->frameX0;
1001    dstBox.x2 -= pScrn->frameX0;
1002    dstBox.y1 -= pScrn->frameY0;
1003    dstBox.y2 -= pScrn->frameY0;
1004
1005    if (portPriv->doubleBuffer)
1006      portPriv->currentBuffer = CHIPSSetCurrentPlaybackBuffer(cPtr,0);
1007    else
1008      portPriv->currentBuffer = 0;
1009
1010    CHIPSDisplayVideo(pScrn, surface->id, surface->offsets[0],
1011	     surface->width, surface->height, surface->pitches[0],
1012	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h, FALSE);
1013    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
1014
1015    pPriv->isOn = TRUE;
1016    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
1017	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
1018	UpdateCurrentTime();
1019	portPriv->videoStatus = FREE_TIMER;
1020	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1021	cPtr->VideoTimerCallback = CHIPSVideoTimerCallback;
1022    }
1023
1024    return Success;
1025}
1026
1027
1028static void
1029CHIPSInitOffscreenImages(ScreenPtr pScreen)
1030{
1031    XF86OffscreenImagePtr offscreenImages;
1032
1033    /* need to free this someplace */
1034    if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
1035	return;
1036
1037    offscreenImages[0].image = &Images[0];
1038    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1039			       VIDEO_CLIP_TO_VIEWPORT;
1040    offscreenImages[0].alloc_surface = CHIPSAllocateSurface;
1041    offscreenImages[0].free_surface = CHIPSFreeSurface;
1042    offscreenImages[0].display = CHIPSDisplaySurface;
1043    offscreenImages[0].stop = CHIPSStopSurface;
1044    offscreenImages[0].setAttribute = CHIPSSetSurfaceAttribute;
1045    offscreenImages[0].getAttribute = CHIPSGetSurfaceAttribute;
1046    offscreenImages[0].max_width = 1024;
1047    offscreenImages[0].max_height = 1024;
1048    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
1049    offscreenImages[0].attributes = Attributes;
1050
1051    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
1052}
1053