1/***************************************************************************
2
3Copyright 2000 Intel Corporation.  All Rights Reserved.
4
5Permission is hereby granted, free of charge, to any person obtaining a
6copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sub license, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice (including the
14next paragraph) shall be included in all copies or substantial portions
15of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25**************************************************************************/
26
27/*
28 * i810_video.c: i810 Xv driver. Based on the mga Xv driver by Mark Vojkovich.
29 *
30 * Authors:
31 * 	Jonathan Bian <jonathan.bian@intel.com>
32 *      Offscreen Images:
33 *        Matt Sottek <matthew.j.sottek@intel.com>
34 */
35
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40#include <string.h>
41
42#include "xorg-server.h"
43#include "xf86.h"
44#include "xf86_OSproc.h"
45#include "compiler.h"
46#include "xf86Pci.h"
47#include "xf86fbman.h"
48#include "regionstr.h"
49
50#include "i810.h"
51#include "xf86xv.h"
52#include <X11/extensions/Xv.h>
53#include "dixstruct.h"
54#include "fourcc.h"
55
56#define OFF_DELAY 	250  /* milliseconds */
57#define FREE_DELAY 	15000
58
59#define OFF_TIMER 	0x01
60#define FREE_TIMER	0x02
61#define CLIENT_VIDEO_ON	0x04
62
63#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
64
65static void I810InitOffscreenImages(ScreenPtr);
66
67static XF86VideoAdaptorPtr I810SetupImageVideo(ScreenPtr);
68static void I810StopVideo(ScrnInfoPtr, pointer, Bool);
69static int I810SetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
70static int I810GetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
71static void I810QueryBestSize(ScrnInfoPtr, Bool,
72	short, short, short, short, unsigned int *, unsigned int *, pointer);
73static int I810PutImage( ScrnInfoPtr,
74	short, short, short, short, short, short, short, short,
75	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
76	DrawablePtr);
77static int I810QueryImageAttributes(ScrnInfoPtr,
78	int, unsigned short *, unsigned short *,  int *, int *);
79
80static void I810BlockHandler(BLOCKHANDLER_ARGS_DECL);
81
82#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
83
84static Atom xvBrightness, xvContrast, xvColorKey;
85
86#define IMAGE_MAX_WIDTH		1440
87#define IMAGE_FAST_WIDTH	720
88#define IMAGE_MAX_HEIGHT	1080
89#define Y_BUF_SIZE		(IMAGE_MAX_WIDTH * IMAGE_MAX_HEIGHT)
90
91#define OVERLAY_UPDATE(p)	OUTREG(0x30000, p | 0x80000000);
92
93/*
94 * OV0CMD - Overlay Command Register
95 */
96#define	VERTICAL_CHROMINANCE_FILTER 	0x70000000
97#define VC_SCALING_OFF		0x00000000
98#define VC_LINE_REPLICATION	0x10000000
99#define VC_UP_INTERPOLATION	0x20000000
100#define VC_PIXEL_DROPPING	0x50000000
101#define VC_DOWN_INTERPOLATION	0x60000000
102#define VERTICAL_LUMINANCE_FILTER	0x0E000000
103#define VL_SCALING_OFF		0x00000000
104#define VL_LINE_REPLICATION	0x02000000
105#define VL_UP_INTERPOLATION	0x04000000
106#define VL_PIXEL_DROPPING	0x0A000000
107#define VL_DOWN_INTERPOLATION	0x0C000000
108#define	HORIZONTAL_CHROMINANCE_FILTER 	0x01C00000
109#define HC_SCALING_OFF		0x00000000
110#define HC_LINE_REPLICATION	0x00400000
111#define HC_UP_INTERPOLATION	0x00800000
112#define HC_PIXEL_DROPPING	0x01400000
113#define HC_DOWN_INTERPOLATION	0x01800000
114#define HORIZONTAL_LUMINANCE_FILTER	0x00380000
115#define HL_SCALING_OFF		0x00000000
116#define HL_LINE_REPLICATION	0x00080000
117#define HL_UP_INTERPOLATION	0x00100000
118#define HL_PIXEL_DROPPING	0x00280000
119#define HL_DOWN_INTERPOLATION	0x00300000
120
121#define Y_ADJUST		0x00010000
122#define OV_BYTE_ORDER		0x0000C000
123#define UV_SWAP			0x00004000
124#define Y_SWAP			0x00008000
125#define Y_AND_UV_SWAP		0x0000C000
126#define SOURCE_FORMAT		0x00003C00
127#define	RGB_555			0x00000800
128#define	RGB_565			0x00000C00
129#define	YUV_422			0x00002000
130#define	YUV_411			0x00002400
131#define	YUV_420			0x00003000
132#define	YUV_410			0x00003800
133#define BUFFER_AND_FIELD	0x00000006
134#define	BUFFER0_FIELD0		0x00000000
135#define	BUFFER1_FIELD0		0x00000004
136#define OVERLAY_ENABLE		0x00000001
137
138#define UV_VERT_BUF1 		0x02
139#define UV_VERT_BUF0 		0x04
140
141/*
142 * DOV0STA - Display/Overlay 0 Status Register
143 */
144#define	DOV0STA 	0x30008
145
146#define MINUV_SCALE	0x1
147
148#define RGB16ToColorKey(c) \
149	(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
150
151#define RGB15ToColorKey(c) \
152        (((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
153
154void I810InitVideo(ScreenPtr screen)
155{
156    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
157    XF86VideoAdaptorPtr *adaptors = NULL;
158    int num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
159
160    if (pScrn->bitsPerPixel != 8) {
161	XF86VideoAdaptorPtr newAdaptor;
162
163	newAdaptor = I810SetupImageVideo(screen);
164	I810InitOffscreenImages(screen);
165
166	if (newAdaptor) {
167	    XF86VideoAdaptorPtr *newAdaptors;
168
169	    newAdaptors =
170		realloc(adaptors,
171			(num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr));
172	    if (newAdaptors != NULL) {
173		newAdaptors[num_adaptors++] = newAdaptor;
174		adaptors = newAdaptors;
175	    }
176	}
177    }
178
179    if (num_adaptors)
180	xf86XVScreenInit(screen, adaptors, num_adaptors);
181
182    free(adaptors);
183}
184
185/* *INDENT-OFF* */
186/* client libraries expect an encoding */
187static XF86VideoEncodingRec DummyEncoding[1] =
188{
189 {
190   0,
191   "XV_IMAGE",
192   IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
193   {1, 1}
194 }
195};
196
197#define NUM_FORMATS 3
198
199static XF86VideoFormatRec Formats[NUM_FORMATS] =
200{
201  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
202};
203
204#define NUM_ATTRIBUTES 3
205
206static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
207{
208   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
209   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
210   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
211};
212
213#define NUM_IMAGES 6
214
215#define I810_RV15 0x35315652
216#define I810_RV16 0x36315652
217
218static XF86ImageRec Images[NUM_IMAGES] =
219{
220   {
221	I810_RV15,
222        XvRGB,
223	LSBFirst,
224	{'R','V','1','5',
225	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
226	16,
227	XvPacked,
228	1,
229	15, 0x7C00, 0x03E0, 0x001F,
230	0, 0, 0,
231	0, 0, 0,
232	0, 0, 0,
233	{'R','V','B',0,
234	  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},
235	XvTopToBottom
236   },
237   {
238	I810_RV16,
239        XvRGB,
240	LSBFirst,
241	{'R','V','1','6',
242	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
243	16,
244	XvPacked,
245	1,
246	16, 0xF800, 0x07E0, 0x001F,
247	0, 0, 0,
248	0, 0, 0,
249	0, 0, 0,
250	{'R','V','B',0,
251	  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},
252	XvTopToBottom
253   },
254	XVIMAGE_YUY2,
255	XVIMAGE_YV12,
256	XVIMAGE_I420,
257	XVIMAGE_UYVY
258};
259/* *INDENT-ON* */
260
261typedef struct {
262    uint32_t OBUF_0Y;
263    uint32_t OBUF_1Y;
264    uint32_t OBUF_0U;
265    uint32_t OBUF_0V;
266    uint32_t OBUF_1U;
267    uint32_t OBUF_1V;
268    uint32_t OV0STRIDE;
269    uint32_t YRGB_VPH;
270    uint32_t UV_VPH;
271    uint32_t HORZ_PH;
272    uint32_t INIT_PH;
273    uint32_t DWINPOS;
274    uint32_t DWINSZ;
275    uint32_t SWID;
276    uint32_t SWIDQW;
277    uint32_t SHEIGHT;
278    uint32_t YRGBSCALE;
279    uint32_t UVSCALE;
280    uint32_t OV0CLRC0;
281    uint32_t OV0CLRC1;
282    uint32_t DCLRKV;
283    uint32_t DCLRKM;
284    uint32_t SCLRKVH;
285    uint32_t SCLRKVL;
286    uint32_t SCLRKM;
287    uint32_t OV0CONF;
288    uint32_t OV0CMD;
289} I810OverlayRegRec, *I810OverlayRegPtr;
290
291typedef struct {
292	uint32_t     YBuf0offset;
293	uint32_t     UBuf0offset;
294	uint32_t     VBuf0offset;
295
296	uint32_t     YBuf1offset;
297	uint32_t     UBuf1offset;
298	uint32_t     VBuf1offset;
299
300	unsigned char currentBuf;
301
302	int          brightness;
303	int          contrast;
304
305	RegionRec    clip;
306	uint32_t     colorKey;
307
308	uint32_t     videoStatus;
309	Time         offTime;
310	Time         freeTime;
311	FBLinearPtr  linear;
312} I810PortPrivRec, *I810PortPrivPtr;
313
314#define GET_PORT_PRIVATE(pScrn) \
315   (I810PortPrivPtr)((I810PTR(pScrn))->adaptor->pPortPrivates[0].ptr)
316
317static void I810ResetVideo(ScrnInfoPtr pScrn)
318{
319    I810Ptr pI810 = I810PTR(pScrn);
320    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
321    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
322
323    /*
324     * Default to maximum image size in YV12
325     */
326
327    overlay->YRGB_VPH = 0;
328    overlay->UV_VPH = 0;
329    overlay->HORZ_PH = 0;
330    overlay->INIT_PH = 0;
331    overlay->DWINPOS = 0;
332    overlay->DWINSZ = (IMAGE_MAX_HEIGHT << 16) | IMAGE_MAX_WIDTH;
333    overlay->SWID =  IMAGE_MAX_WIDTH | (IMAGE_MAX_WIDTH << 15);
334    overlay->SWIDQW = (IMAGE_MAX_WIDTH >> 3) | (IMAGE_MAX_WIDTH << 12);
335    overlay->SHEIGHT = IMAGE_MAX_HEIGHT | (IMAGE_MAX_HEIGHT << 15);
336    overlay->YRGBSCALE = 0x80004000; /* scale factor 1 */
337    overlay->UVSCALE = 0x80004000; /* scale factor 1 */
338    overlay->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */
339    overlay->OV0CLRC1 = 0x80; /* saturation: bypass */
340
341    /*
342     * Enable destination color keying
343     */
344    switch(pScrn->depth) {
345    case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
346             overlay->DCLRKM = 0x80070307;
347             break;
348    case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
349             overlay->DCLRKM = 0x80070707;
350             break;
351    default: overlay->DCLRKV = pPriv->colorKey;
352             overlay->DCLRKM = 0x80000000;
353             break;
354    }
355
356    overlay->SCLRKVH = 0;
357    overlay->SCLRKVL = 0;
358    overlay->SCLRKM = 0; /* source color key disable */
359    overlay->OV0CONF = 0; /* two 720 pixel line buffers */
360
361    overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST |
362		      YUV_420;
363
364    OVERLAY_UPDATE(pI810->OverlayPhysical);
365}
366
367
368static XF86VideoAdaptorPtr
369I810SetupImageVideo(ScreenPtr screen)
370{
371    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
372    I810Ptr pI810 = I810PTR(pScrn);
373    XF86VideoAdaptorPtr adapt;
374    I810PortPrivPtr pPriv;
375
376    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
377			    sizeof(I810PortPrivRec) +
378			    sizeof(DevUnion))))
379	return NULL;
380
381    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
382    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
383    adapt->name = "I810 Video Overlay";
384    adapt->nEncodings = 1;
385    adapt->pEncodings = DummyEncoding;
386    adapt->nFormats = NUM_FORMATS;
387    adapt->pFormats = Formats;
388    adapt->nPorts = 1;
389    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
390
391    pPriv = (I810PortPrivPtr)(&adapt->pPortPrivates[1]);
392
393    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
394    adapt->pAttributes = Attributes;
395    adapt->nImages = NUM_IMAGES;
396    adapt->nAttributes = NUM_ATTRIBUTES;
397    adapt->pImages = Images;
398    adapt->PutVideo = NULL;
399    adapt->PutStill = NULL;
400    adapt->GetVideo = NULL;
401    adapt->GetStill = NULL;
402    adapt->StopVideo = I810StopVideo;
403    adapt->SetPortAttribute = I810SetPortAttribute;
404    adapt->GetPortAttribute = I810GetPortAttribute;
405    adapt->QueryBestSize = I810QueryBestSize;
406    adapt->PutImage = I810PutImage;
407    adapt->QueryImageAttributes = I810QueryImageAttributes;
408
409    pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1);
410    pPriv->videoStatus = 0;
411    pPriv->brightness = 0;
412    pPriv->contrast = 64;
413    pPriv->linear = NULL;
414    pPriv->currentBuf = 0;
415
416    /* gotta uninit this someplace */
417    REGION_NULL(screen, &pPriv->clip);
418
419    pI810->adaptor = adapt;
420
421    pI810->BlockHandler = screen->BlockHandler;
422    screen->BlockHandler = I810BlockHandler;
423
424    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
425    xvContrast   = MAKE_ATOM("XV_CONTRAST");
426    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
427
428    I810ResetVideo(pScrn);
429
430    return adapt;
431}
432
433
434/* I810ClipVideo -
435
436   Takes the dst box in standard X BoxRec form (top and left
437   edges inclusive, bottom and right exclusive).  The new dst
438   box is returned.  The source boundaries are given (x1, y1
439   inclusive, x2, y2 exclusive) and returned are the new source
440   boundaries in 16.16 fixed point.
441*/
442
443static void
444I810ClipVideo(
445  BoxPtr dst,
446  INT32 *x1,
447  INT32 *x2,
448  INT32 *y1,
449  INT32 *y2,
450  BoxPtr extents,            /* extents of the clip region */
451  INT32 width,
452  INT32 height
453){
454    INT32 vscale, hscale, delta;
455    int diff;
456
457    hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
458    vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
459
460    *x1 <<= 16; *x2 <<= 16;
461    *y1 <<= 16; *y2 <<= 16;
462
463    diff = extents->x1 - dst->x1;
464    if(diff > 0) {
465	dst->x1 = extents->x1;
466	*x1 += diff * hscale;
467    }
468    diff = dst->x2 - extents->x2;
469    if(diff > 0) {
470	dst->x2 = extents->x2;
471	*x2 -= diff * hscale;
472    }
473    diff = extents->y1 - dst->y1;
474    if(diff > 0) {
475	dst->y1 = extents->y1;
476	*y1 += diff * vscale;
477    }
478    diff = dst->y2 - extents->y2;
479    if(diff > 0) {
480	dst->y2 = extents->y2;
481	*y2 -= diff * vscale;
482    }
483
484    if(*x1 < 0) {
485	diff =  (- *x1 + hscale - 1)/ hscale;
486	dst->x1 += diff;
487	*x1 += diff * hscale;
488    }
489    delta = *x2 - (width << 16);
490    if(delta > 0) {
491	diff = (delta + hscale - 1)/ hscale;
492	dst->x2 -= diff;
493	*x2 -= diff * hscale;
494    }
495    if(*y1 < 0) {
496	diff =  (- *y1 + vscale - 1)/ vscale;
497	dst->y1 += diff;
498	*y1 += diff * vscale;
499    }
500    delta = *y2 - (height << 16);
501    if(delta > 0) {
502	diff = (delta + vscale - 1)/ vscale;
503	dst->y2 -= diff;
504	*y2 -= diff * vscale;
505    }
506}
507
508static void
509I810StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
510{
511  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
512  I810Ptr pI810 = I810PTR(pScrn);
513
514  I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
515
516  REGION_EMPTY(pScrn->screen, &pPriv->clip);
517
518  if(shutdown) {
519     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
520	overlay->OV0CMD &= 0xFFFFFFFE;
521	OVERLAY_UPDATE(pI810->OverlayPhysical);
522     }
523     if(pPriv->linear) {
524	xf86FreeOffscreenLinear(pPriv->linear);
525	pPriv->linear = NULL;
526     }
527     pPriv->videoStatus = 0;
528  } else {
529     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
530	pPriv->videoStatus |= OFF_TIMER;
531	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
532     }
533  }
534
535}
536
537static int
538I810SetPortAttribute(
539  ScrnInfoPtr pScrn,
540  Atom attribute,
541  INT32 value,
542  pointer data
543){
544  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
545  I810Ptr pI810 = I810PTR(pScrn);
546  I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
547
548  if(attribute == xvBrightness) {
549	if((value < -128) || (value > 127))
550	   return BadValue;
551	pPriv->brightness = value;
552	overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
553	OVERLAY_UPDATE(pI810->OverlayPhysical);
554  } else
555  if(attribute == xvContrast) {
556	if((value < 0) || (value > 255))
557	   return BadValue;
558	pPriv->contrast = value;
559	overlay->OV0CLRC0 = (pPriv->contrast << 8) | (pPriv->brightness & 0xff);
560	OVERLAY_UPDATE(pI810->OverlayPhysical);
561  } else
562  if(attribute == xvColorKey) {
563	pPriv->colorKey = value;
564	switch(pScrn->depth) {
565	case 16: overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
566	         break;
567	case 15: overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
568                 break;
569	default: overlay->DCLRKV = pPriv->colorKey;
570                 break;
571	}
572	OVERLAY_UPDATE(pI810->OverlayPhysical);
573	REGION_EMPTY(pScrn->screen, &pPriv->clip);
574  } else return BadMatch;
575
576  return Success;
577}
578
579static int
580I810GetPortAttribute(
581  ScrnInfoPtr pScrn,
582  Atom attribute,
583  INT32 *value,
584  pointer data
585){
586  I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
587
588  if(attribute == xvBrightness) {
589	*value = pPriv->brightness;
590  } else
591  if(attribute == xvContrast) {
592	*value = pPriv->contrast;
593  } else
594  if(attribute == xvColorKey) {
595	*value = pPriv->colorKey;
596  } else return BadMatch;
597
598  return Success;
599}
600
601static void
602I810QueryBestSize(
603  ScrnInfoPtr pScrn,
604  Bool motion,
605  short vid_w, short vid_h,
606  short drw_w, short drw_h,
607  unsigned int *p_w, unsigned int *p_h,
608  pointer data
609){
610   if(vid_w > (drw_w << 1)) drw_w = vid_w >> 1;
611   if(vid_h > (drw_h << 1)) drw_h = vid_h >> 1;
612
613  *p_w = drw_w;
614  *p_h = drw_h;
615}
616
617
618static void
619I810CopyPackedData(
620   ScrnInfoPtr pScrn,
621   unsigned char *buf,
622   int srcPitch,
623   int dstPitch,
624   int top,
625   int left,
626   int h,
627   int w
628   )
629{
630    I810Ptr pI810 = I810PTR(pScrn);
631    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
632    unsigned char *src, *dst;
633
634    src = buf + (top*srcPitch) + (left<<1);
635
636    if (pPriv->currentBuf == 0)
637	dst = pI810->FbBase + pPriv->YBuf0offset;
638    else
639	dst = pI810->FbBase + pPriv->YBuf1offset;
640
641    w <<= 1;
642    while(h--) {
643	memcpy(dst, src, w);
644	src += srcPitch;
645	dst += dstPitch;
646    }
647}
648
649static void
650I810CopyPlanarData(
651   ScrnInfoPtr pScrn,
652   unsigned char *buf,
653   int srcPitch,
654   int dstPitch,  /* of chroma */
655   int srcH,
656   int top,
657   int left,
658   int h,
659   int w,
660   int id
661   )
662{
663    I810Ptr pI810 = I810PTR(pScrn);
664    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
665    int i;
666    unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3;
667
668    /* Copy Y data */
669    src1 = buf + (top*srcPitch) + left;
670    if (pPriv->currentBuf == 0)
671	dst1 = pI810->FbBase + pPriv->YBuf0offset;
672    else
673	dst1 = pI810->FbBase + pPriv->YBuf1offset;
674
675    for (i = 0; i < h; i++) {
676	memcpy(dst1, src1, w);
677	src1 += srcPitch;
678	dst1 += dstPitch << 1;
679    }
680
681    /* Copy V data for YV12, or U data for I420 */
682    src2 = buf + (srcH*srcPitch) + ((top*srcPitch)>>2) + (left>>1);
683    if (pPriv->currentBuf == 0) {
684	if (id == FOURCC_I420)
685	    dst2 = pI810->FbBase + pPriv->UBuf0offset;
686	else
687	    dst2 = pI810->FbBase + pPriv->VBuf0offset;
688    } else {
689	if (id == FOURCC_I420)
690	    dst2 = pI810->FbBase + pPriv->UBuf1offset;
691	else
692	    dst2 = pI810->FbBase + pPriv->VBuf1offset;
693    }
694
695    for (i = 0; i < h/2; i++) {
696	memcpy(dst2, src2, w/2);
697	src2 += srcPitch>>1;
698	dst2 += dstPitch;
699    }
700
701    /* Copy U data for YV12, or V data for I420 */
702    src3 = buf + (srcH*srcPitch) + ((srcH*srcPitch)>>2) + ((top*srcPitch)>>2) + (left>>1);
703    if (pPriv->currentBuf == 0) {
704	if (id == FOURCC_I420)
705	    dst3 = pI810->FbBase + pPriv->VBuf0offset;
706	else
707	    dst3 = pI810->FbBase + pPriv->UBuf0offset;
708    } else {
709	if (id == FOURCC_I420)
710	    dst3 = pI810->FbBase + pPriv->VBuf1offset;
711	else
712	    dst3 = pI810->FbBase + pPriv->UBuf1offset;
713    }
714
715    for (i = 0; i < h/2; i++) {
716	memcpy(dst3, src3, w/2);
717	src3 += srcPitch>>1;
718	dst3 += dstPitch;
719    }
720}
721
722static void
723I810DisplayVideo(
724    ScrnInfoPtr pScrn,
725    int id,
726    short width, short height,
727    int dstPitch,  /* of chroma for 4:2:0 */
728    int x1, int y1, int x2, int y2,
729    BoxPtr dstBox,
730    short src_w, short src_h,
731    short drw_w, short drw_h
732){
733    I810Ptr pI810 = I810PTR(pScrn);
734    I810PortPrivPtr pPriv = pI810->adaptor->pPortPrivates[0].ptr;
735    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
736    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
737    int xscaleIntUV = 0, xscaleFractUV = 0, yscaleIntUV = 0, yscaleFractUV = 0;
738    unsigned int swidth;
739
740    switch(id) {
741    case FOURCC_YV12:
742    case FOURCC_I420:
743	swidth = ALIGN(width, 8);
744	overlay->SWID = (swidth << 15) | swidth;
745	overlay->SWIDQW = (swidth << 12) | (swidth >> 3);
746	break;
747    case FOURCC_UYVY:
748    case FOURCC_YUY2:
749    default:
750	swidth = ALIGN(width, 4) << 1;
751	overlay->SWID = swidth;
752	overlay->SWIDQW = swidth >> 3;
753	break;
754    }
755
756    /* wide video formats (>720 pixels) are special */
757    if( swidth > IMAGE_FAST_WIDTH ) {
758	overlay->OV0CONF = 1; /* one 1440 pixel line buffer */
759    } else {
760	overlay->OV0CONF = 0; /* two 720 pixel line buffers */
761    }
762
763    overlay->SHEIGHT = height | (height << 15);
764    overlay->DWINPOS = (dstBox->y1 << 16) | (dstBox->x1);
765    overlay->DWINSZ = ((dstBox->y2 - dstBox->y1) << 16) |
766	              (dstBox->x2 - dstBox->x1);
767
768    /* buffer locations */
769    overlay->OBUF_0Y = pPriv->YBuf0offset;
770    overlay->OBUF_1Y = pPriv->YBuf1offset;
771    overlay->OBUF_0U = pPriv->UBuf0offset;
772    overlay->OBUF_0V = pPriv->VBuf0offset;
773    overlay->OBUF_1U = pPriv->UBuf1offset;
774    overlay->OBUF_1V = pPriv->VBuf1offset;
775
776    /*
777     * Calculate horizontal and vertical scaling factors, default to 1:1
778     */
779    overlay->YRGBSCALE = 0x80004000;
780    overlay->UVSCALE = 0x80004000;
781
782    /*
783     * Initially, YCbCr and Overlay Enable and
784     * vertical chrominance up interpolation and horozontal chrominance
785     * up interpolation
786     */
787    overlay->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST |
788	              OVERLAY_ENABLE;
789
790    if ((drw_w != src_w) || (drw_h != src_h))
791    {
792	xscaleInt = (src_w / drw_w) & 0x3;
793	xscaleFract = (src_w << 12) / drw_w;
794	yscaleInt = (src_h / drw_h) & 0x3;
795	yscaleFract = (src_h << 12) / drw_h;
796
797	overlay->YRGBSCALE = (xscaleInt << 15) |
798	                     ((xscaleFract & 0xFFF) << 3) |
799	                     (yscaleInt) |
800			     ((yscaleFract & 0xFFF) << 20);
801
802	if (drw_w > src_w)
803	{
804	    /* horizontal up-scaling */
805	    overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER;
806	    overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER;
807	    overlay->OV0CMD |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION);
808	}
809
810	if (drw_h > src_h)
811	{
812	    /* vertical up-scaling */
813	    overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER;
814	    overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER;
815	    overlay->OV0CMD |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION);
816	}
817
818	if (drw_w < src_w)
819	{
820	    /* horizontal down-scaling */
821	    overlay->OV0CMD &= ~HORIZONTAL_CHROMINANCE_FILTER;
822	    overlay->OV0CMD &= ~HORIZONTAL_LUMINANCE_FILTER;
823	    overlay->OV0CMD |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION);
824	}
825
826	if (drw_h < src_h)
827	{
828	    /* vertical down-scaling */
829	    overlay->OV0CMD &= ~VERTICAL_CHROMINANCE_FILTER;
830	    overlay->OV0CMD &= ~VERTICAL_LUMINANCE_FILTER;
831	    overlay->OV0CMD |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION);
832	}
833
834	/* now calculate the UV scaling factor */
835
836	if (xscaleFract)
837	{
838	    xscaleFractUV = xscaleFract >> MINUV_SCALE;
839	    overlay->OV0CMD &= ~HC_DOWN_INTERPOLATION;
840	    overlay->OV0CMD |= HC_UP_INTERPOLATION;
841	}
842
843	if (xscaleInt)
844	{
845	    xscaleIntUV = xscaleInt >> MINUV_SCALE;
846	    if (xscaleIntUV)
847	    {
848		overlay->OV0CMD &= ~HC_UP_INTERPOLATION;
849	    }
850	}
851
852	if (yscaleFract)
853	{
854	    yscaleFractUV = yscaleFract >> MINUV_SCALE;
855	    overlay->OV0CMD &= ~VC_DOWN_INTERPOLATION;
856	    overlay->OV0CMD |= VC_UP_INTERPOLATION;
857	}
858
859	if (yscaleInt)
860	{
861	    yscaleIntUV = yscaleInt >> MINUV_SCALE;
862	    if (yscaleIntUV)
863	    {
864		overlay->OV0CMD &= ~VC_UP_INTERPOLATION;
865		overlay->OV0CMD |= VC_DOWN_INTERPOLATION;
866	    }
867	}
868
869	overlay->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) |
870	                   ((yscaleFractUV & 0xFFF) << 20);
871    }
872
873    switch(id) {
874    case FOURCC_YV12:
875    case FOURCC_I420:
876	/* set UV vertical phase to -0.25 */
877	overlay->UV_VPH = 0x30003000;
878	overlay->INIT_PH = UV_VERT_BUF0 | UV_VERT_BUF1;
879	overlay->OV0STRIDE = (dstPitch << 1) | (dstPitch << 16);
880	overlay->OV0CMD &= ~SOURCE_FORMAT;
881	overlay->OV0CMD |= YUV_420;
882	break;
883    case I810_RV15:
884    case I810_RV16:
885	overlay->UV_VPH = 0;
886	overlay->INIT_PH = 0;
887	overlay->OV0STRIDE = dstPitch;
888	overlay->OV0CMD &= ~SOURCE_FORMAT;
889	overlay->OV0CMD |= (id==I810_RV15 ? RGB_555 : RGB_565);
890	overlay->OV0CMD &= ~OV_BYTE_ORDER;
891	break;
892    case FOURCC_UYVY:
893    case FOURCC_YUY2:
894    default:
895	overlay->UV_VPH = 0;
896	overlay->INIT_PH = 0;
897	overlay->OV0STRIDE = dstPitch;
898	overlay->OV0CMD &= ~SOURCE_FORMAT;
899	overlay->OV0CMD |= YUV_422;
900	overlay->OV0CMD &= ~OV_BYTE_ORDER;
901	if (id == FOURCC_UYVY)
902	    overlay->OV0CMD |= Y_SWAP;
903	break;
904    }
905
906    overlay->OV0CMD &= ~BUFFER_AND_FIELD;
907    if (pPriv->currentBuf == 0)
908	overlay->OV0CMD |= BUFFER0_FIELD0;
909    else
910	overlay->OV0CMD |= BUFFER1_FIELD0;
911
912    OVERLAY_UPDATE(pI810->OverlayPhysical);
913
914}
915
916static FBLinearPtr
917I810AllocateMemory(
918  ScrnInfoPtr pScrn,
919  FBLinearPtr linear,
920  int size
921){
922   ScreenPtr screen;
923   FBLinearPtr new_linear;
924
925   if(linear) {
926	if(linear->size >= size)
927	   return linear;
928
929	if(xf86ResizeOffscreenLinear(linear, size))
930	   return linear;
931
932	xf86FreeOffscreenLinear(linear);
933   }
934
935   screen = xf86ScrnToScreen(pScrn);
936
937   new_linear = xf86AllocateOffscreenLinear(screen, size, 4,
938                                            NULL, NULL, NULL);
939
940   if(!new_linear) {
941        int max_size;
942
943        xf86QueryLargestOffscreenLinear(screen, &max_size, 4,
944				       PRIORITY_EXTREME);
945
946        if(max_size < size) return NULL;
947
948        xf86PurgeUnlockedOffscreenAreas(screen);
949        new_linear = xf86AllocateOffscreenLinear(screen, size, 4,
950                                                 NULL, NULL, NULL);
951   }
952
953   return new_linear;
954}
955
956static int
957I810PutImage(
958  ScrnInfoPtr pScrn,
959  short src_x, short src_y,
960  short drw_x, short drw_y,
961  short src_w, short src_h,
962  short drw_w, short drw_h,
963  int id, unsigned char* buf,
964  short width, short height,
965  Bool sync,
966  RegionPtr clipBoxes, pointer data,
967  DrawablePtr pDraw
968){
969    I810Ptr pI810 = I810PTR(pScrn);
970    I810PortPrivPtr pPriv = (I810PortPrivPtr)data;
971    INT32 x1, x2, y1, y2;
972    int srcPitch, dstPitch;
973    int top, left, npixels, nlines, size, loops;
974    BoxRec dstBox;
975
976
977    /* Clip */
978    x1 = src_x;
979    x2 = src_x + src_w;
980    y1 = src_y;
981    y2 = src_y + src_h;
982
983    dstBox.x1 = drw_x;
984    dstBox.x2 = drw_x + drw_w;
985    dstBox.y1 = drw_y;
986    dstBox.y2 = drw_y + drw_h;
987
988    I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
989		  REGION_EXTENTS(pScrn->screen, clipBoxes), width, height);
990
991    if((x1 >= x2) || (y1 >= y2))
992       return Success;
993    /*
994     * Fix for 4 pixel granularity of AdjustFrame
995     * unless boarder is clipped  by frame
996     */
997    dstBox.x1 -= (pScrn->frameX0 &
998		  ((dstBox.x1 == pScrn->frameX0) ? ~0x0UL : ~0x3UL));
999    dstBox.x2 -= (pScrn->frameX0 & ~0x3);
1000    dstBox.y1 -= pScrn->frameY0;
1001    dstBox.y2 -= pScrn->frameY0;
1002
1003    switch(id) {
1004    case FOURCC_YV12:
1005    case FOURCC_I420:
1006	 srcPitch = ALIGN(width, 4);
1007	 dstPitch = ALIGN((width >> 1), 8);  /* of chroma */
1008	 size =  dstPitch * height * 3;
1009	 break;
1010    case FOURCC_UYVY:
1011    case FOURCC_YUY2:
1012    default:
1013	 srcPitch = (width << 1);
1014	 dstPitch = ALIGN(srcPitch, 8);
1015	 size = dstPitch * height;
1016	 break;
1017    }
1018
1019    if(!(pPriv->linear = I810AllocateMemory(pScrn, pPriv->linear,
1020		(pScrn->bitsPerPixel == 16) ? size : (size >> 1))))
1021	return BadAlloc;
1022
1023    /* fixup pointers */
1024    pPriv->YBuf0offset = pPriv->linear->offset * pI810->cpp;
1025    pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height);
1026    pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height >> 1);
1027
1028    pPriv->YBuf1offset = (pPriv->linear->offset * pI810->cpp) + size;
1029    pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height);
1030    pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height >> 1);
1031
1032
1033    /* Make sure this buffer isn't in use */
1034    loops = 0;
1035    while (loops < 1000000) {
1036          if(((INREG(DOV0STA)&0x00100000)>>20) == pPriv->currentBuf) {
1037            break;
1038          }
1039          loops++;
1040    }
1041    if(loops >= 1000000) {
1042      pPriv->currentBuf = !pPriv->currentBuf;
1043    }
1044
1045
1046    /* buffer swap */
1047    if (pPriv->currentBuf == 0)
1048        pPriv->currentBuf = 1;
1049    else
1050        pPriv->currentBuf = 0;
1051
1052    /* copy data */
1053    top = y1 >> 16;
1054    left = (x1 >> 16) & ~1;
1055    npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - left;
1056
1057    switch(id) {
1058    case FOURCC_YV12:
1059    case FOURCC_I420:
1060	top &= ~1;
1061	nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - top;
1062	I810CopyPlanarData(pScrn, buf, srcPitch, dstPitch,  height, top, left,
1063                           nlines, npixels, id);
1064	break;
1065    case FOURCC_UYVY:
1066    case FOURCC_YUY2:
1067    default:
1068	nlines = ((y2 + 0xffff) >> 16) - top;
1069	I810CopyPackedData(pScrn, buf, srcPitch, dstPitch, top, left, nlines,
1070                                                              npixels);
1071        break;
1072    }
1073
1074    /* update cliplist */
1075    if(!REGION_EQUAL(pScrn->screen, &pPriv->clip, clipBoxes)) {
1076	REGION_COPY(pScrn->screen, &pPriv->clip, clipBoxes);
1077	/* draw these */
1078	xf86XVFillKeyHelperDrawable(pDraw, pPriv->colorKey, clipBoxes);
1079    }
1080
1081    I810DisplayVideo(pScrn, id, width, height, dstPitch,
1082	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1083
1084    pPriv->videoStatus = CLIENT_VIDEO_ON;
1085
1086    return Success;
1087}
1088
1089
1090static int
1091I810QueryImageAttributes(
1092  ScrnInfoPtr pScrn,
1093  int id,
1094  unsigned short *w, unsigned short *h,
1095  int *pitches, int *offsets
1096){
1097    int size, tmp;
1098
1099    if(*w > IMAGE_MAX_WIDTH) *w = IMAGE_MAX_WIDTH;
1100    if(*h > IMAGE_MAX_HEIGHT) *h = IMAGE_MAX_HEIGHT;
1101
1102    *w = (*w + 1) & ~1;
1103    if(offsets) offsets[0] = 0;
1104
1105    switch(id) {
1106      /* IA44 is for XvMC only */
1107    case FOURCC_IA44:
1108    case FOURCC_AI44:
1109	if(pitches) pitches[0] = *w;
1110	size = *w * *h;
1111	break;
1112    case FOURCC_YV12:
1113    case FOURCC_I420:
1114	*h = (*h + 1) & ~1;
1115	size = (*w + 3) & ~3;
1116	if(pitches) pitches[0] = size;
1117	size *= *h;
1118	if(offsets) offsets[1] = size;
1119	tmp = ((*w >> 1) + 3) & ~3;
1120	if(pitches) pitches[1] = pitches[2] = tmp;
1121	tmp *= (*h >> 1);
1122	size += tmp;
1123	if(offsets) offsets[2] = size;
1124	size += tmp;
1125	break;
1126    case FOURCC_UYVY:
1127    case FOURCC_YUY2:
1128    default:
1129	size = *w << 1;
1130	if(pitches) pitches[0] = size;
1131	size *= *h;
1132	break;
1133    }
1134
1135    return size;
1136}
1137
1138static void
1139I810BlockHandler (BLOCKHANDLER_ARGS_DECL)
1140{
1141    SCREEN_PTR(arg);
1142    ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
1143    I810Ptr      pI810 = I810PTR(pScrn);
1144    I810PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
1145    I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
1146
1147    screen->BlockHandler = pI810->BlockHandler;
1148
1149    (*screen->BlockHandler) (BLOCKHANDLER_ARGS);
1150
1151    screen->BlockHandler = I810BlockHandler;
1152
1153    if(pPriv->videoStatus & TIMER_MASK) {
1154	UpdateCurrentTime();
1155	if(pPriv->videoStatus & OFF_TIMER) {
1156	    if(pPriv->offTime < currentTime.milliseconds) {
1157		/* Turn off the overlay */
1158		overlay->OV0CMD &= 0xFFFFFFFE;
1159		OVERLAY_UPDATE(pI810->OverlayPhysical);
1160
1161		pPriv->videoStatus = FREE_TIMER;
1162		pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1163	    }
1164	} else {  /* FREE_TIMER */
1165	    if(pPriv->freeTime < currentTime.milliseconds) {
1166		if(pPriv->linear) {
1167		   xf86FreeOffscreenLinear(pPriv->linear);
1168		   pPriv->linear = NULL;
1169		}
1170		pPriv->videoStatus = 0;
1171	    }
1172        }
1173    }
1174}
1175
1176
1177/***************************************************************************
1178 * Offscreen Images
1179 ***************************************************************************/
1180
1181typedef struct {
1182  FBLinearPtr linear;
1183  Bool isOn;
1184} OffscreenPrivRec, * OffscreenPrivPtr;
1185
1186static int
1187I810AllocateSurface(
1188    ScrnInfoPtr pScrn,
1189    int id,
1190    unsigned short w,
1191    unsigned short h,
1192    XF86SurfacePtr surface
1193){
1194    FBLinearPtr linear;
1195    int pitch, size, bpp;
1196    OffscreenPrivPtr pPriv;
1197    I810Ptr pI810 = I810PTR(pScrn);
1198
1199    if((w > 1024) || (h > 1024))
1200	return BadAlloc;
1201
1202    w = ALIGN(w, 2);
1203    pitch = ALIGN((w << 1), 16);
1204    bpp = pScrn->bitsPerPixel >> 3;
1205    size = ((pitch * h) + bpp - 1) / bpp;
1206
1207    if(!(linear = I810AllocateMemory(pScrn, NULL, size)))
1208	return BadAlloc;
1209
1210    surface->width = w;
1211    surface->height = h;
1212
1213    if(!(surface->pitches = malloc(sizeof(int)))) {
1214	xf86FreeOffscreenLinear(linear);
1215	return BadAlloc;
1216    }
1217    if(!(surface->offsets = malloc(sizeof(int)))) {
1218	free(surface->pitches);
1219	xf86FreeOffscreenLinear(linear);
1220	return BadAlloc;
1221    }
1222    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
1223	free(surface->pitches);
1224	free(surface->offsets);
1225	xf86FreeOffscreenLinear(linear);
1226	return BadAlloc;
1227    }
1228
1229    pPriv->linear = linear;
1230    pPriv->isOn = FALSE;
1231
1232    surface->pScrn = pScrn;
1233    surface->id = id;
1234    surface->pitches[0] = pitch;
1235    surface->offsets[0] = linear->offset * bpp;
1236    surface->devPrivate.ptr = (pointer)pPriv;
1237
1238    memset(pI810->FbBase + surface->offsets[0],0,size);
1239
1240    return Success;
1241}
1242
1243static int
1244I810StopSurface(
1245    XF86SurfacePtr surface
1246){
1247    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1248
1249    if(pPriv->isOn) {
1250      I810Ptr pI810 = I810PTR(surface->pScrn);
1251
1252      I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
1253
1254      overlay->OV0CMD &= 0xFFFFFFFE;
1255      OVERLAY_UPDATE(pI810->OverlayPhysical);
1256
1257      pPriv->isOn = FALSE;
1258    }
1259
1260    return Success;
1261}
1262
1263
1264static int
1265I810FreeSurface(
1266    XF86SurfacePtr surface
1267){
1268    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1269
1270    if(pPriv->isOn) {
1271	I810StopSurface(surface);
1272    }
1273    xf86FreeOffscreenLinear(pPriv->linear);
1274    free(surface->pitches);
1275    free(surface->offsets);
1276    free(surface->devPrivate.ptr);
1277
1278    return Success;
1279}
1280
1281static int
1282I810GetSurfaceAttribute(
1283    ScrnInfoPtr pScrn,
1284    Atom attribute,
1285    INT32 *value
1286){
1287    return I810GetPortAttribute(pScrn, attribute, value, GET_PORT_PRIVATE(pScrn));
1288}
1289
1290static int
1291I810SetSurfaceAttribute(
1292    ScrnInfoPtr pScrn,
1293    Atom attribute,
1294    INT32 value
1295){
1296    return I810SetPortAttribute(pScrn, attribute, value, GET_PORT_PRIVATE(pScrn));
1297}
1298
1299
1300static int
1301I810DisplaySurface(
1302    XF86SurfacePtr surface,
1303    short src_x, short src_y,
1304    short drw_x, short drw_y,
1305    short src_w, short src_h,
1306    short drw_w, short drw_h,
1307    RegionPtr clipBoxes
1308){
1309    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1310    ScrnInfoPtr pScrn = surface->pScrn;
1311    I810Ptr      pI810 = I810PTR(pScrn);
1312    I810PortPrivPtr pI810Priv =  GET_PORT_PRIVATE(pScrn);
1313
1314    INT32 x1, y1, x2, y2;
1315    INT32 loops = 0;
1316    BoxRec dstBox;
1317
1318    x1 = src_x;
1319    x2 = src_x + src_w;
1320    y1 = src_y;
1321    y2 = src_y + src_h;
1322
1323    dstBox.x1 = drw_x;
1324    dstBox.x2 = drw_x + drw_w;
1325    dstBox.y1 = drw_y;
1326    dstBox.y2 = drw_y + drw_h;
1327
1328    I810ClipVideo(&dstBox, &x1, &x2, &y1, &y2,
1329		  REGION_EXTENTS(screenInfo.screens[0], clipBoxes),
1330		  surface->width, surface->height);
1331
1332    /*
1333     * Fix for 4 pixel granularity of AdjustFrame
1334     * unless boarder is clipped  by frame
1335     */
1336    dstBox.x1 -= (pScrn->frameX0 &
1337		  ((dstBox.x1 == pScrn->frameX0) ? ~0x0UL : ~0x3UL));
1338    dstBox.x2 -= (pScrn->frameX0 & ~0x3);
1339    dstBox.y1 -= pScrn->frameY0;
1340    dstBox.y2 -= pScrn->frameY0;
1341
1342    /* fixup pointers */
1343    pI810Priv->YBuf0offset = surface->offsets[0];
1344    pI810Priv->YBuf1offset = pI810Priv->YBuf0offset;
1345
1346   /* wait for the last rendered buffer to be flipped in */
1347    while (((INREG(DOV0STA)&0x00100000)>>20) != pI810Priv->currentBuf) {
1348      if(loops == 200000) {
1349	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Overlay Lockup\n");
1350	break;
1351      }
1352      loops++;
1353    }
1354
1355    /* buffer swap */
1356    if (pI810Priv->currentBuf == 0)
1357      pI810Priv->currentBuf = 1;
1358    else
1359      pI810Priv->currentBuf = 0;
1360
1361    I810ResetVideo(pScrn);
1362
1363    I810DisplayVideo(pScrn, surface->id, surface->width, surface->height,
1364		     surface->pitches[0], x1, y1, x2, y2, &dstBox,
1365		     src_w, src_h, drw_w, drw_h);
1366
1367    xf86XVFillKeyHelper(pScrn->pScreen, pI810Priv->colorKey, clipBoxes);
1368
1369    pPriv->isOn = TRUE;
1370    /* we've prempted the XvImage stream so set its free timer */
1371    if(pI810Priv->videoStatus & CLIENT_VIDEO_ON) {
1372      REGION_EMPTY(pScrn->screen, & pI810Priv->clip);
1373      UpdateCurrentTime();
1374      pI810Priv->videoStatus = FREE_TIMER;
1375      pI810Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
1376      pScrn->pScreen->BlockHandler = I810BlockHandler;
1377    }
1378
1379    return Success;
1380}
1381
1382
1383static void
1384I810InitOffscreenImages(ScreenPtr screen)
1385{
1386    XF86OffscreenImagePtr offscreenImages;
1387
1388    /* need to free this someplace */
1389    if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec)))) {
1390      return;
1391    }
1392
1393    offscreenImages[0].image = &Images[0];
1394    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1395			       VIDEO_CLIP_TO_VIEWPORT;
1396    offscreenImages[0].alloc_surface = I810AllocateSurface;
1397    offscreenImages[0].free_surface = I810FreeSurface;
1398    offscreenImages[0].display = I810DisplaySurface;
1399    offscreenImages[0].stop = I810StopSurface;
1400    offscreenImages[0].setAttribute = I810SetSurfaceAttribute;
1401    offscreenImages[0].getAttribute = I810GetSurfaceAttribute;
1402    offscreenImages[0].max_width = 1024;
1403    offscreenImages[0].max_height = 1024;
1404    offscreenImages[0].num_attributes = 1;
1405    offscreenImages[0].attributes = Attributes;
1406
1407    if (!xf86XVRegisterOffscreenImages(screen, offscreenImages, 1))
1408	    free(offscreenImages);
1409}
1410
1411