1/**********************************************************************
2Copyright 2002 by Shigehiro Nomura.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, distribute, and sell this software and
7its documentation for any purpose is hereby granted without fee,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Shigehiro Nomura not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.  Shigehiro Nomura
13and its suppliers make no representations about the suitability of this
14software for any purpose.  It is provided "as is" without express or
15implied warranty.
16
17SHIGEHIRO NOMURA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19EVENT SHALL SHIGEHIRO NOMURA AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24**********************************************************************/
25
26/*
27 * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "neo.h"
35#include "neo_video.h"
36
37#define nElems(x)		(sizeof(x) / sizeof(x[0]))
38#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
39
40#include "dixstruct.h"
41
42static XF86VideoAdaptorPtr NEOSetupVideo(ScreenPtr);
43
44static int NEOPutVideo(ScrnInfoPtr, short, short, short, short,
45		       short, short, short, short, RegionPtr, pointer,
46		       DrawablePtr);
47
48static void NEOStopVideo(ScrnInfoPtr, pointer, Bool);
49static int NEOSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
50static int NEOGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
51static void NEOQueryBestSize(ScrnInfoPtr, Bool, short, short, short,
52			     short, unsigned int *, unsigned int *, pointer);
53static int NEOPutImage(ScrnInfoPtr, short, short, short, short, short, short,
54		       short, short, int, unsigned char *, short, short, Bool,
55		       RegionPtr, pointer, DrawablePtr);
56static int NEOQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
57				   unsigned short *, int *, int *);
58
59static void NEODisplayVideo(ScrnInfoPtr, int, int, short, short, int, int,
60			    int, int, int, BoxPtr, short, short, short, short);
61
62static void NEOInitOffscreenImages(ScreenPtr);
63static FBLinearPtr NEOAllocateMemory(ScrnInfoPtr, FBLinearPtr, int);
64
65static int NEOAllocSurface(ScrnInfoPtr, int, unsigned short, unsigned short,
66			   XF86SurfacePtr);
67static int NEOFreeSurface(XF86SurfacePtr);
68static int NEODisplaySurface(XF86SurfacePtr, short, short, short, short,
69			     short, short, short, short, RegionPtr clipBoxes);
70static int NEOStopSurface(XF86SurfacePtr);
71static int NEOGetSurfaceAttribute(ScrnInfoPtr, Atom, INT32 *);
72static int NEOSetSurfaceAttribute(ScrnInfoPtr, Atom, INT32);
73
74static Atom xvColorKey, xvBrightness, xvInterlace;
75
76void
77NEOInitVideo(ScreenPtr pScreen)
78{
79    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
80    NEOPtr nPtr = NEOPTR(pScrn);
81    XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
82    XF86VideoAdaptorPtr newAdaptor = NULL;
83    int numAdaptors;
84
85    numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
86
87    if (nPtr->NeoChipset > NM2070
88	&& nPtr->NeoMMIOBase2 != NULL){
89	nPtr->video = TRUE;
90	newAdaptor = NEOSetupVideo(pScreen);
91	NEOInitOffscreenImages(pScreen);
92    } else
93	nPtr->video = FALSE;
94
95    if (newAdaptor){
96	if (!numAdaptors){
97	    numAdaptors = 1;
98	    overlayAdaptors = &newAdaptor;
99	} else {
100	    newAdaptors = malloc((numAdaptors + 1)
101				 * sizeof(XF86VideoAdaptorPtr*));
102	    if (newAdaptors){
103		memcpy(newAdaptors, overlayAdaptors,
104		       numAdaptors * sizeof(XF86VideoAdaptorPtr));
105		newAdaptors[numAdaptors++] = newAdaptor;
106		overlayAdaptors = newAdaptors;
107	    }
108	}
109    }
110
111    if (numAdaptors)
112	xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors);
113
114    if (newAdaptors)
115	free(newAdaptors);
116}
117
118static XF86VideoEncodingRec NEOVideoEncodings[] =
119{
120    {
121	NEO_VIDEO_VIDEO,
122	"XV_VIDEO",
123	1024, 1024,
124	{1, 1}
125    },
126    {
127	NEO_VIDEO_IMAGE,
128	"XV_IMAGE",
129	1024, 1024,
130	{1, 1}
131    }
132};
133
134static XF86VideoFormatRec NEOVideoFormats[] =
135{
136    {  8, PseudoColor },
137    { 15, TrueColor },
138    { 16, TrueColor },
139    { 24, TrueColor },
140};
141
142static XF86AttributeRec NEOVideoAttributes[] =
143{
144    {
145	XvSettable | XvGettable,
146	0x000000, 0xFFFFFF,
147	"XV_COLORKEY"
148    },
149    {
150	XvSettable | XvGettable,
151	-128, 127,
152	"XV_BRIGHTNESS"
153    },
154    {
155	XvSettable | XvGettable,
156	0,2,
157	"XV_INTERLACE"
158    },
159};
160
161static XF86ImageRec NEOVideoImages[] =
162{
163    XVIMAGE_YUY2,
164    XVIMAGE_YV12,
165    XVIMAGE_I420,
166    {
167	FOURCC_RV15,
168	XvRGB,
169	LSBFirst,
170	{ 'R', 'V' ,'1', '5',
171	  0x00,'5',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
172	16,
173	XvPacked,
174	1,
175	15, 0x001F, 0x03E0, 0x7C00,
176	0, 0, 0,
177	0, 0, 0,
178	0, 0, 0,
179	{ 'R', 'V', 'B' },
180	XvTopToBottom
181    },
182    {
183	FOURCC_RV16,
184	XvRGB,
185	LSBFirst,
186	{ 'R', 'V' ,'1', '6',
187	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
188	16,
189	XvPacked,
190	1,
191	16, 0xF800, 0x07E0, 0x001F,
192	0, 0, 0,
193	0, 0, 0,
194	0, 0, 0,
195	{ 'R', 'V', 'B' },
196	XvTopToBottom
197    }
198};
199
200static XF86VideoAdaptorPtr
201NEOSetupVideo(ScreenPtr pScreen)
202{
203    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
204    NEOPtr nPtr = NEOPTR(pScrn);
205    NEOPortPtr pPriv;
206    XF86VideoAdaptorPtr overlayAdaptor;
207    int i;
208
209#ifdef DEBUG
210    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetupVideo\n");
211#endif
212    if ((overlayAdaptor = calloc(1, sizeof(XF86VideoAdaptorRec) +
213			      sizeof(DevUnion) +
214			      sizeof(NEOPortRec))) == NULL){
215	return (NULL);
216    }
217
218    overlayAdaptor->type = XvInputMask | XvImageMask | XvWindowMask
219	| XvOutputMask | XvVideoMask;
220    overlayAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
221    overlayAdaptor->name = "NeoMagic Video Engine";
222    overlayAdaptor->nEncodings = nElems(NEOVideoEncodings);
223    overlayAdaptor->pEncodings = NEOVideoEncodings;
224    for (i = 0; i < nElems(NEOVideoEncodings); i++){
225	NEOVideoEncodings[i].width = 1024;
226	NEOVideoEncodings[i].height = 1024;
227    }
228    overlayAdaptor->nFormats = nElems(NEOVideoFormats);
229    overlayAdaptor->pFormats = NEOVideoFormats;
230    overlayAdaptor->nPorts = 1;
231    overlayAdaptor->pPortPrivates = (DevUnion*) &overlayAdaptor[1];
232    overlayAdaptor->pPortPrivates[0].ptr =
233	(pointer) &overlayAdaptor->pPortPrivates[1];
234    overlayAdaptor->nAttributes = nElems(NEOVideoAttributes);
235    overlayAdaptor->pAttributes = NEOVideoAttributes;
236    overlayAdaptor->nImages = nElems(NEOVideoImages);
237    overlayAdaptor->pImages = NEOVideoImages;
238
239    overlayAdaptor->PutVideo = NEOPutVideo;
240    overlayAdaptor->PutStill = NULL;
241    overlayAdaptor->GetVideo = NULL;
242    overlayAdaptor->GetStill = NULL;
243
244    overlayAdaptor->StopVideo = NEOStopVideo;
245    overlayAdaptor->SetPortAttribute = NEOSetPortAttribute;
246    overlayAdaptor->GetPortAttribute = NEOGetPortAttribute;
247    overlayAdaptor->QueryBestSize = NEOQueryBestSize;
248    overlayAdaptor->PutImage = NEOPutImage;
249    overlayAdaptor->QueryImageAttributes = NEOQueryImageAttributes;
250
251    pPriv = (NEOPortPtr)overlayAdaptor->pPortPrivates[0].ptr;
252    pPriv->colorKey = nPtr->videoKey;
253    pPriv->interlace = nPtr->interlace;
254    pPriv->videoStatus = 0;
255    pPriv->brightness = 0;
256    REGION_NULL(pScreen, &pPriv->clip);
257    nPtr->overlayAdaptor = overlayAdaptor;
258
259    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
260    xvColorKey = MAKE_ATOM("XV_COLORKEY");
261    xvInterlace = MAKE_ATOM("XV_INTERLACE");
262
263    NEOResetVideo(pScrn);
264
265    return (overlayAdaptor);
266}
267
268void
269NEOResetVideo(ScrnInfoPtr pScrn)
270{
271    NEOPtr nPtr = NEOPTR(pScrn);
272    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
273    int r, g, b;
274    VGA_HWP(pScrn);
275
276#ifdef DEBUG
277    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOResetVideo\n");
278#endif
279    switch (pScrn->depth){
280    case 8:
281	OUTGR(0xc6, pPriv->colorKey & 0);
282	OUTGR(0xc5, pPriv->colorKey & 0xff);
283	OUTGR(0xc7, pPriv->colorKey & 0);
284	break;
285    default:
286	r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
287	g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
288	b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
289	OUTGR(0xc5, r);
290	OUTGR(0xc6, g);
291	OUTGR(0xc7, b);
292	break;
293    }
294    OUTGR(0xc4, pPriv->brightness);
295}
296
297static int
298NEOPutVideo(ScrnInfoPtr pScrn,
299	     short src_x, short src_y, short drw_x, short drw_y,
300	     short src_w, short src_h, short drw_w, short drw_h,
301	     RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
302{
303    NEOPortPtr pPriv = (NEOPortPtr)data;
304    NEOPtr nPtr = NEOPTR(pScrn);
305    CARD32 src_pitch, offset;
306    int xscale, yscale;
307    BoxRec dstBox;
308    INT32 x1, y1, x2, y2;
309    int size, bpp;
310    unsigned char capctrl;
311    VGA_HWP(pScrn);
312
313#ifdef DEBUG
314    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: src: %d %d %d %d\n",
315	       src_x, src_y, src_w, src_h);
316    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: drw: %d %d %d %d\n",
317	       drw_x, drw_y, drw_w, drw_h);
318#endif
319    if (src_w > 720)
320	src_w = 720;
321    if (src_h > 576)
322        src_h = 576;
323    if (pPriv->interlace != 2)
324	src_h /= 2;
325    x1 = src_x;
326    y1 = src_y;
327    x2 = src_x + src_w;
328    y2 = src_y + src_h;
329
330    dstBox.x1 = drw_x;
331    dstBox.y1 = drw_y;
332    dstBox.x2 = drw_x + drw_w;
333    dstBox.y2 = drw_y + drw_h;
334
335    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
336			       clipBoxes, src_w, src_h)){
337	return(Success);
338    }
339#ifdef DEBUG
340    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: %d %d %d %d\n",
341	       x1, y1, x2, y2);
342#endif
343
344    dstBox.x1 -= pScrn->frameX0;
345    dstBox.y1 -= pScrn->frameY0;
346    dstBox.x2 -= pScrn->frameX0;
347    dstBox.y2 -= pScrn->frameY0;
348#ifdef DEBUG
349    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: dstBox %d %d %d %d\n",
350	       dstBox.x1, dstBox.y1, dstBox.x2, dstBox.y2);
351#endif
352
353    bpp = (pScrn->bitsPerPixel + 1) >> 3;
354    src_pitch = (src_w + 7) & ~7;
355
356    xscale = 0x1000;
357    if (src_w <= drw_w){
358	xscale = (src_w * 0x1000 / drw_w) & 0xffff;
359    }
360
361    yscale = 0x1000;
362    if (src_h <= drw_h){
363 	yscale = (src_h * 0x1000 / drw_h) & 0xffff;
364    }
365
366    size = src_h * src_pitch * 2;
367
368    if (size > nPtr->overlay){
369	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
370	    == NULL){
371	    return (BadAlloc);
372	}
373    } else {
374	pPriv->linear = NULL;
375    }
376
377    if (pPriv->linear == NULL){
378	offset = nPtr->overlay_offset;
379    } else {
380	offset = pPriv->linear->offset * bpp;
381    }
382
383#ifdef DEBUG
384    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: offset=0x%x\n", offset);
385#endif
386     WAIT_ENGINE_IDLE();
387     memset(nPtr->NeoFbBase + offset, 0, size);
388
389    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
390	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
391	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
392    }
393
394    x1 >>= 16;
395    y1 >>= 16;
396    x2 >>= 16;
397    y2 >>= 16;
398
399    switch (nPtr->NeoChipset) {
400    default:
401    case NM2090:
402    case NM2093:
403    case NM2097:
404    case NM2160:
405	offset/=2;
406	OUTGR(0xbc, 0x4f);
407 	break;
408    case NM2200:
409    case NM2230:
410    case NM2360:
411    case NM2380:
412	OUTGR(0xbc, 0x2e);
413 	break;
414    }
415
416
417    OUTGR(0xb1, (((dstBox.x2-1) >> 4) & 0xf0) | ((dstBox.x1 >> 8) & 0x0f));
418    OUTGR(0xb2, dstBox.x1);
419    OUTGR(0xb3, dstBox.x2 - 1);
420    OUTGR(0xb4, (((dstBox.y2 - 1) >> 4) & 0xf0) | ((dstBox.y1 >> 8) & 0x0f));
421    OUTGR(0xb5, dstBox.y1);
422    OUTGR(0xb6, dstBox.y2 - 1);
423    OUTGR(0xb7, offset >> 16);
424    OUTGR(0xb8, offset >> 8);
425    OUTGR(0xb9, offset );
426    OUTGR(0xba, src_pitch >> 8);
427    OUTGR(0xbb, src_pitch);
428
429    OUTGR(0xc0, xscale >> 8);
430    OUTGR(0xc1, xscale);
431    OUTGR(0xc2, yscale >> 8);
432    OUTGR(0xc3, yscale);
433    OUTGR(0xbf, 0x02);
434
435    OUTGR(0x0a, 0x21);
436
437    OUTSR(0x0c, offset );
438    OUTSR(0x0d, offset >> 8);
439    OUTSR(0x0e, offset >> 16);
440    OUTSR(0x1a, src_pitch);
441    OUTSR(0x1b, src_pitch>>8);
442
443    OUTSR(0x17, 0 + x1);
444    OUTSR(0x18, 0 + x2 -1);
445    OUTSR(0x19, (((0 + x2 - 1) >> 4) & 0xf0) | (((0 + x1) >> 8) & 0x0f));
446
447    OUTSR(0x14, 14 + y1);
448    OUTSR(0x15, 14 + y2 - 2);
449    OUTSR(0x16, (((14 + y2 - 1) >> 4) & 0xf0) | (((14 + y1) >> 8) & 0x0f));
450
451    OUTSR(0x1c, 0xfb);
452    OUTSR(0x1d, 0x00);
453    OUTSR(0x1e, 0xe2);
454    OUTSR(0x1f, 0x02);
455
456    OUTSR(0x09, 0x11);
457    OUTSR(0x0a, 0x00);
458
459    capctrl = 0x21;
460    switch (pPriv->interlace){
461    case 0: /* Combine 2 fields */
462	break;
463    case 1: /* one field only */
464	capctrl |= 0x80;
465	break;
466    case 2: /* Interlaced fields */
467	capctrl |= 0x40;
468	break;
469    }
470    OUTSR(0x08, capctrl);
471
472#if 0
473    OUTGR(0x0a, 0x01);
474#endif
475    OUTGR(0xb0, 0x03);
476
477    pPriv->videoStatus = CLIENT_VIDEO_ON;
478    return (Success);
479}
480
481static void
482NEOStopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
483{
484    NEOPortPtr pPriv = (NEOPortPtr)data;
485    NEOPtr nPtr = NEOPTR(pScrn);
486    VGA_HWP(pScrn);
487
488#ifdef DEBUG
489    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo\n");
490#endif
491    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
492
493    if (exit){
494	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
495#ifdef DEBUG
496            xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo: stop capture\n");
497#endif
498	    OUTGR(0xb0, 0x02);
499	    OUTGR(0x0a, 0x21);
500	    OUTSR(0x08, 0xa0);
501#if 0
502	    OUTGR(0x0a, 0x01);
503#endif
504	}
505	if (pPriv->linear != NULL){
506	    xf86FreeOffscreenLinear(pPriv->linear);
507	    pPriv->linear = NULL;
508	}
509	pPriv->videoStatus = 0;
510    } else {
511	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
512	    OUTGR(0xb0, 0x02);
513	    OUTGR(0x0a, 0x21);
514	    OUTSR(0x08, 0xa0);
515#if 0
516	    OUTGR(0x0a, 0x01);
517#endif
518	    pPriv->videoStatus |= OFF_TIMER;
519	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
520	}
521    }
522}
523
524static int
525NEOSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value,
526		    pointer data)
527{
528    NEOPortPtr pPriv = (NEOPortPtr)data;
529    NEOPtr nPtr = NEOPTR(pScrn);
530    VGA_HWP(pScrn);
531
532#ifdef DEBUG
533    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetPortAttribute\n");
534#endif
535    if (attribute == xvColorKey){
536	int r, g, b;
537
538	pPriv->colorKey = value;
539	switch (pScrn->depth){
540	case 8:
541	    OUTGR(0xc6, pPriv->colorKey & 0xff);
542	    OUTGR(0xc5, 0x00);
543	    OUTGR(0xc7, 0x00);
544	    break;
545	default:
546	    r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
547	    g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
548	    b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
549	    OUTGR(0xc5, r);
550	    OUTGR(0xc6, g);
551	    OUTGR(0xc7, b);
552	}
553    } else if (attribute == xvBrightness){
554	if ((value < -128) || (value > 127)){
555	    return (BadValue);
556	}
557	pPriv->brightness = value;
558	OUTGR(0xc4, value);
559    } else if (attribute == xvInterlace){
560	if (value < 0  ||  value > 2){
561	    return (BadValue);
562	}
563	pPriv->interlace = value;
564    } else {
565	return (BadMatch);
566    }
567    return (Success);
568}
569
570static int
571NEOGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value,
572		    pointer data)
573{
574    NEOPortPtr pPriv = (NEOPortPtr)data;
575
576#ifdef DEBUG
577    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetPortAttribute\n");
578#endif
579    if (attribute == xvColorKey){
580	*value = pPriv->colorKey;
581    } else if (attribute == xvBrightness){
582	*value = pPriv->brightness;
583    } else if (attribute == xvInterlace){
584	*value = pPriv->interlace;
585    } else {
586	return (BadMatch);
587    }
588    return (Success);
589}
590
591static void
592NEOQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
593		 short vid_w, short vid_h, short drw_w, short drw_h,
594		 unsigned int *p_w, unsigned int *p_h,
595		 pointer data)
596{
597#ifdef DEBUG
598    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryBestSize\n");
599#endif
600    *p_w = min(drw_w, 1024);
601    *p_h = min(drw_h, 1024);
602}
603
604static int
605NEOPutImage(ScrnInfoPtr pScrn,
606	    short src_x, short src_y, short drw_x, short drw_y,
607	    short src_w, short src_h, short drw_w, short drw_h,
608	    int id, unsigned char *buf, short width, short height,
609	    Bool sync, RegionPtr clipBoxes, pointer data,
610	    DrawablePtr pDraw)
611{
612    NEOPtr nPtr = NEOPTR(pScrn);
613    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
614    INT32 x1, y1, x2, y2;
615    int bpp;
616    int srcPitch, srcPitch2 = 0, dstPitch, size;
617    BoxRec dstBox;
618    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
619    int left, top, nPixels, nLines;
620    unsigned char *dstStart;
621
622#ifdef DEBUG
623    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutImage\n");
624#endif
625
626    x1 = src_x;
627    y1 = src_y;
628    x2 = src_x + src_w;
629    y2 = src_y + src_h;
630
631    dstBox.x1 = drw_x;
632    dstBox.y1 = drw_y;
633    dstBox.x2 = drw_x + drw_w;
634    dstBox.y2 = drw_y + drw_h;
635
636    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
637			       clipBoxes, width, height)){
638	return (Success);
639    }
640
641    dstBox.x1 -= pScrn->frameX0;
642    dstBox.y1 -= pScrn->frameY0;
643    dstBox.x2 -= pScrn->frameX0;
644    dstBox.y2 -= pScrn->frameY0;
645
646    bpp = ((pScrn->bitsPerPixel + 1) >> 3);
647
648    switch (id){
649    case FOURCC_YV12:
650	srcPitch  = (width + 3) & ~3;
651	offset2   = srcPitch * height;
652	srcPitch2 = ((width >> 1) + 3) & ~3;
653	offset3   = offset2 + (srcPitch2 * (height >> 1));
654  	dstPitch  = ((width << 1) + 15) & ~15;
655	break;
656    case FOURCC_I420:
657	srcPitch  = (width + 3) & ~3;
658	offset3   = srcPitch * height;
659	srcPitch2 = ((width >> 1) + 3) & ~3;
660	offset2   = offset3 + (srcPitch2 * (height >> 1));
661  	dstPitch  = ((width << 1) + 15) & ~15;
662	break;
663    case FOURCC_YUY2:
664    case FOURCC_RV15:
665    case FOURCC_RV16:
666    default:
667	srcPitch = width << 1;
668  	dstPitch = (srcPitch + 15) & ~15;
669	break;
670    }
671
672    size = dstPitch * height;
673    if (size > nPtr->overlay){
674	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
675	    == NULL){
676	    return (BadAlloc);
677	}
678    } else {
679	pPriv->linear = NULL;
680    }
681
682    top = y1 >> 16;
683    left = (x1 >> 16) & ~1;
684    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
685    left <<= 1;
686
687    if (pPriv->linear == NULL){
688	offset = nPtr->overlay_offset;
689    } else {
690	offset =  pPriv->linear->offset * bpp;
691    }
692
693#ifdef DEBUG
694    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"offset=%x\n", offset);
695#endif
696
697    dstStart = (unsigned char *)(nPtr->NeoFbBase + offset + left);
698
699    switch (id){
700    case FOURCC_YV12:
701    case FOURCC_I420:
702	top &= ~1;
703	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
704	offset2 += tmp;
705	offset3 += tmp;
706	nLines = ((((y2 + 0xFFFF) >> 16) + 1) & ~1) - top;
707	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
708				buf + offset2, buf + offset3,
709				dstStart, srcPitch, srcPitch2,
710				dstPitch, nLines, nPixels);
711	break;
712    default:
713	buf += (top * srcPitch) + left;
714	nLines = ((y2 + 0xFFFF) >> 16) - top;
715	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch,
716			 nLines, nPixels << 1);
717    }
718
719    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
720	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
721        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
722    }
723	NEODisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1,
724			x2, y2,	&dstBox, src_w, src_h, drw_w, drw_h);
725
726    pPriv->videoStatus = CLIENT_VIDEO_ON;
727    return (Success);
728
729}
730
731static int
732NEOQueryImageAttributes(ScrnInfoPtr pScrn, int id,
733			unsigned short *width, unsigned short *height,
734			int *pitches, int *offsets)
735{
736    int size, tmp;
737
738#ifdef DEBUG
739    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryImageAttributes\n");
740#endif
741    if (*width > 1024){
742	*width = 1024;
743    }
744    if (*height > 1024){
745	*height = 1024;
746    }
747
748    *width = (*width + 1) & ~1;
749    if (offsets != NULL){
750	offsets[0] = 0;
751    }
752
753    switch (id){
754    case FOURCC_YV12:
755    case FOURCC_I420:
756	*height = (*height + 1) & ~1;
757	size = (*width + 3) & ~3;
758	if (pitches != NULL){
759	    pitches[0] = size;
760	}
761	size *= *height;
762	if (offsets != NULL){
763	    offsets[1] = size;
764	}
765	tmp = ((*width >> 1) + 3) & ~3;
766	if (pitches != NULL){
767	    pitches[1] = pitches[2] = tmp;
768	}
769	tmp *= (*height >> 1);
770	size += tmp;
771	if (offsets != NULL){
772	    offsets[2] = size;
773	}
774	size += tmp;
775	break;
776    case FOURCC_YUY2:
777    case FOURCC_RV15:
778    case FOURCC_RV16:
779    default:
780	size = *width * 2;
781	if (pitches != NULL){
782	    pitches[0] = size;
783	}
784	size *= *height;
785	break;
786    }
787    return (size);
788}
789
790static void
791NEODisplayVideo(ScrnInfoPtr pScrn, int id, int offset,
792		 short width, short height, int pitch,
793		 int x1, int y1, int x2, int y2, BoxPtr dstBox,
794		 short src_w, short src_h, short drw_w, short drw_h)
795{
796    NEOPtr nPtr = NEOPTR(pScrn);
797    int hstretch, vstretch, fmt;
798    VGA_HWP(pScrn);
799#ifdef DEBUG
800    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo\n");
801    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo src_w=%d, src_h=%d, pitch=%d, drw_w=%d, drw_h=%d\n", src_w, src_h, pitch, drw_w, drw_h);
802#endif
803#define WIDTH_THRESHOLD 160
804    if (dstBox->x2 >= pScrn->virtualX) {
805	/*
806	 * This is a hack to work around a problem when video is moved
807	 * across the right border.
808	 */
809	int diff_s = (width - ((x2 - x1) >> 16)) & ~1;
810	int diff_d = (drw_w - dstBox->x2 + dstBox->x1) & ~1;
811
812	offset -= 2 * ((diff_s > diff_d) ? diff_d : diff_s);
813	dstBox->x1 -= diff_d;
814    } else if (dstBox->x2 - dstBox->x1 < WIDTH_THRESHOLD) {
815	/*
816	 * When the video window is less than about 160 pixel wide
817	 * it will be distoreted. We attempt to fix it by actually
818	 * making it wider and relying on the color key to prevent
819	 * it from appearing outside of the video.
820	 */
821	int pre, post;
822	int scale = 1;
823
824	if (dstBox->x1 < WIDTH_THRESHOLD) {
825	    pre = dstBox->x1;
826	    post = 160 - pre;
827	} else {
828	    pre = 160;
829	    post = 0;
830	}
831	offset -= 2 * scale * pre;
832	dstBox->x1 -= pre;
833	dstBox->x2 += post;
834    }
835    if (nPtr->videoHZoom != 1.0) {
836	if ((dstBox->x2 += 5) > pScrn->virtualX)
837	    dstBox->x2 = pScrn->virtualX;
838	if (dstBox->x1 > 0) dstBox->x1 += 2;
839    }
840
841    fmt = 0x00;
842    switch (id){
843    case FOURCC_YV12:
844    case FOURCC_I420:
845    case FOURCC_YUY2:
846	fmt = 0x00;
847	break;
848    case FOURCC_RV15:
849    case FOURCC_RV16:
850	fmt = 0x20;
851	break;
852    }
853
854    offset += (x1 >> 15) & ~0x03;
855
856    switch (nPtr->NeoChipset) {
857    default:
858    case NM2090:
859    case NM2093:
860    case NM2097:
861    case NM2160:
862        offset/=2;
863	pitch/=2;
864        OUTGR(0xbc, 0x4f);
865	break;
866    case NM2200:
867    case NM2230:
868    case NM2360:
869    case NM2380:
870        OUTGR(0xbc, 0x2e);
871	break;
872    }
873
874    /* factor 4 for granularity */
875    hstretch = (double)0x1000 * 4 / (int)(nPtr->videoHZoom * 4);
876    if (drw_w > src_w)
877	hstretch = (((int)src_w) * hstretch) / (int) drw_w;
878
879    vstretch = (double)0x1000 / nPtr->videoVZoom;
880    if (drw_h > src_h)
881	vstretch = (((int)src_h) * vstretch )/ (int) drw_h;
882
883    OUTGR(0xb1, (((dstBox->x2 - 1) >> 4) & 0xf0) | ((dstBox->x1 >> 8) & 0x0f));
884    OUTGR(0xb2, dstBox->x1);
885    OUTGR(0xb3, dstBox->x2 - 1);
886    OUTGR(0xb4, (((dstBox->y2 - 1) >> 4) & 0xf0) | ((dstBox->y1 >> 8) & 0x0f));
887    OUTGR(0xb5, dstBox->y1);
888    OUTGR(0xb6, dstBox->y2 - 1);
889    OUTGR(0xb7, offset >> 16);
890    OUTGR(0xb8, offset >> 8);
891    OUTGR(0xb9, offset );
892    OUTGR(0xba, pitch >> 8);
893    OUTGR(0xbb, pitch);
894
895    OUTGR(0xbd, 0x02);
896    OUTGR(0xbe, 0x00);
897    OUTGR(0xbf, 0x02);
898
899    OUTGR(0xc0, hstretch >> 8);
900    OUTGR(0xc1, hstretch);
901    OUTGR(0xc2, vstretch >> 8);
902    OUTGR(0xc3, vstretch);
903
904    OUTGR(0xb0, fmt | 0x03);
905
906    OUTGR(0x0a, 0x21);
907    OUTSR(0x08, 0xa0);
908    OUTGR(0x0a, 0x01);
909}
910
911static void
912NEOInitOffscreenImages(ScreenPtr pScreen)
913{
914    XF86OffscreenImagePtr offscreenImages;
915
916#ifdef DEBUG
917    xf86DrvMsg(xf86ScreenToScrn(pScreen)->scrnIndex,X_INFO,"NEOInitOffscreenImages\n");
918#endif
919    if ((offscreenImages = malloc(sizeof(XF86OffscreenImageRec))) == NULL){
920	return;
921    }
922
923    offscreenImages->image = NEOVideoImages;
924    offscreenImages->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
925    offscreenImages->alloc_surface = NEOAllocSurface;
926    offscreenImages->free_surface = NEOFreeSurface;
927    offscreenImages->display = NEODisplaySurface;
928    offscreenImages->stop = NEOStopSurface;
929    offscreenImages->getAttribute = NEOGetSurfaceAttribute;
930    offscreenImages->setAttribute = NEOSetSurfaceAttribute;
931    offscreenImages->max_width = 1024;
932    offscreenImages->max_height = 1024;
933    offscreenImages->num_attributes = nElems(NEOVideoAttributes);
934    offscreenImages->attributes = NEOVideoAttributes;
935
936    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
937}
938
939static FBLinearPtr
940NEOAllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
941{
942    ScreenPtr pScreen;
943    FBLinearPtr new_linear;
944    int bytespp = pScrn->bitsPerPixel >> 3;
945
946    /* convert size in bytes into number of pixels */
947    size = (size + bytespp - 1) / bytespp;
948#ifdef DEBUG
949    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
950	       "NEOAllocateMemory: linear=%x, size=%d\n", linear, size);
951#endif
952    if (linear){
953#ifdef DEBUG
954        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
955		   "NEOAllocateMemory: linear->size=%d\n", linear->size);
956#endif
957	if (linear->size >= size){
958	    return (linear);
959	}
960
961	if (xf86ResizeOffscreenLinear(linear, size)){
962	    return (linear);
963	}
964
965	xf86FreeOffscreenLinear(linear);
966    }
967
968
969    pScreen = xf86ScrnToScreen(pScrn);
970    if ((new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL,
971						  NULL, NULL)) == NULL){
972	int max_size;
973
974	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
975					PRIORITY_EXTREME);
976#ifdef DEBUG
977        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
978		   "NEOAllocateMemory: max_size=%d\n", max_size);
979#endif
980	if (max_size < size){
981	    return (NULL);
982	}
983
984	xf86PurgeUnlockedOffscreenAreas(pScreen);
985	new_linear = xf86AllocateOffscreenLinear(pScreen,
986						 size, 16, NULL, NULL, NULL);
987    }
988
989    return (new_linear);
990}
991
992static int
993NEOAllocSurface(ScrnInfoPtr pScrn, int id,
994		unsigned short width, unsigned short height,
995		XF86SurfacePtr surface)
996{
997    int pitch, size;
998    NEOOffscreenPtr pPriv;
999    FBLinearPtr linear;
1000
1001#ifdef DEBUG
1002    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOAllocSurface\n");
1003#endif
1004    if (width > 1024  || height > 1024){
1005	return (BadAlloc);
1006    }
1007
1008    width = (width + 1) & ~1;
1009    pitch = ((width << 1) + 15) & ~15;
1010    size = pitch * height;
1011
1012    if ((linear = NEOAllocateMemory(pScrn, NULL, size)) == NULL){
1013	return (BadAlloc);
1014    }
1015
1016    surface->width = width;
1017    surface->height = height;
1018    if ((surface->pitches = malloc(sizeof(int))) == NULL){
1019	xf86FreeOffscreenLinear(linear);
1020	return (BadAlloc);
1021    }
1022    if ((surface->offsets = malloc(sizeof(int))) == NULL){
1023	free(surface->pitches);
1024	xf86FreeOffscreenLinear(linear);
1025	return (BadAlloc);
1026    }
1027
1028    if ((pPriv = malloc(sizeof(NEOOffscreenRec))) == NULL){
1029	free(surface->pitches);
1030	free(surface->offsets);
1031	xf86FreeOffscreenLinear(linear);
1032	return (BadAlloc);
1033    }
1034
1035    pPriv->linear = linear;
1036    pPriv->isOn = FALSE;
1037
1038    surface->pScrn = pScrn;
1039    surface->id = id;
1040    surface->pitches[0] = pitch;
1041    surface->offsets[0] = linear->offset << 1;
1042    surface->devPrivate.ptr = (pointer)pPriv;
1043    return (Success);
1044}
1045
1046static int
1047NEOFreeSurface(XF86SurfacePtr surface)
1048{
1049    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1050
1051#ifdef DEBUG
1052    xf86DrvMsg(0,X_INFO,"NEOFreeSurface\n");
1053#endif
1054    if (pPriv->isOn)
1055	NEOStopSurface(surface);
1056
1057    xf86FreeOffscreenLinear(pPriv->linear);
1058    free(surface->pitches);
1059    free(surface->offsets);
1060    free(surface->devPrivate.ptr);
1061    return (Success);
1062}
1063
1064static int
1065NEODisplaySurface(XF86SurfacePtr surface,
1066		  short src_x, short src_y, short drw_x, short drw_y,
1067		  short src_w, short src_h, short drw_w, short drw_h,
1068		  RegionPtr clipBoxes)
1069{
1070    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1071    NEOPtr nPtr = NEOPTR(surface->pScrn);
1072    NEOPortPtr portPriv = nPtr->overlayAdaptor->pPortPrivates[0].ptr;
1073    INT32 x1, y1, x2, y2;
1074    BoxRec dstBox;
1075
1076#ifdef DEBUG
1077    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEODisplaySurface\n");
1078#endif
1079    x1 = src_x;
1080    x2 = src_x + src_w;
1081    y1 = src_y;
1082    y2 = src_y + src_h;
1083
1084    dstBox.x1 = drw_x;
1085    dstBox.x2 = drw_x + drw_w;
1086    dstBox.y1 = drw_y;
1087    dstBox.y2 = drw_y + drw_h;
1088    if (!xf86XVClipVideoHelper( &dstBox, &x1, &x2, &y1, &y2,
1089			       clipBoxes, surface->width, surface->height)){
1090	return (Success);
1091    }
1092
1093    dstBox.x1 -= surface->pScrn->frameX0;
1094    dstBox.y1 -= surface->pScrn->frameY0;
1095    dstBox.x2 -= surface->pScrn->frameX0;
1096    dstBox.y2 -= surface->pScrn->frameY0;
1097
1098    xf86XVFillKeyHelper(surface->pScrn->pScreen, portPriv->colorKey,
1099			clipBoxes);
1100    NEOResetVideo(surface->pScrn);
1101    NEODisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
1102		    surface->width, surface->height, surface->pitches[0],
1103		    x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1104
1105    pPriv->isOn = TRUE;
1106    if (portPriv->videoStatus & CLIENT_VIDEO_ON){
1107	REGION_EMPTY(surface->pScrn->pScreen, &portPriv->clip);
1108	UpdateCurrentTime();
1109	portPriv->videoStatus = FREE_TIMER;
1110	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1111    }
1112    return (Success);
1113}
1114
1115static int
1116NEOStopSurface(XF86SurfacePtr surface)
1117{
1118    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1119
1120#ifdef DEBUG
1121    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEOStopSurface\n");
1122#endif
1123    if (pPriv->isOn){
1124	NEOPtr nPtr = NEOPTR(surface->pScrn);
1125	VGA_HWP(surface->pScrn);
1126	OUTGR(0xb0, 0x02);
1127	pPriv->isOn = FALSE;
1128    }
1129    return (Success);
1130}
1131
1132static int
1133NEOGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value)
1134{
1135    NEOPtr nPtr = NEOPTR(pScrn);
1136
1137#ifdef DEBUG
1138    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetSurfaceAttribute\n");
1139#endif
1140    return (NEOGetPortAttribute(pScrn,
1141            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1142}
1143
1144static int
1145NEOSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value)
1146{
1147    NEOPtr nPtr = NEOPTR(pScrn);
1148
1149#ifdef DEBUG
1150    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetSurfaceAttribute\n");
1151#endif
1152    return (NEOSetPortAttribute(pScrn,
1153            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1154}
1155