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