neo_video.c revision 692f60a7
1692f60a7Smrg/**********************************************************************
2692f60a7SmrgCopyright 2002 by Shigehiro Nomura.
3692f60a7Smrg
4692f60a7Smrg                        All Rights Reserved
5692f60a7Smrg
6692f60a7SmrgPermission to use, copy, modify, distribute, and sell this software and
7692f60a7Smrgits documentation for any purpose is hereby granted without fee,
8692f60a7Smrgprovided that the above copyright notice appear in all copies and that
9692f60a7Smrgboth that copyright notice and this permission notice appear in
10692f60a7Smrgsupporting documentation, and that the name of Shigehiro Nomura not be
11692f60a7Smrgused in advertising or publicity pertaining to distribution of the
12692f60a7Smrgsoftware without specific, written prior permission.  Shigehiro Nomura
13692f60a7Smrgand its suppliers make no representations about the suitability of this
14692f60a7Smrgsoftware for any purpose.  It is provided "as is" without express or
15692f60a7Smrgimplied warranty.
16692f60a7Smrg
17692f60a7SmrgSHIGEHIRO NOMURA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18692f60a7SmrgINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19692f60a7SmrgEVENT SHALL SHIGEHIRO NOMURA AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20692f60a7SmrgSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21692f60a7SmrgRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22692f60a7SmrgCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23692f60a7SmrgCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24692f60a7Smrg**********************************************************************/
25692f60a7Smrg
26692f60a7Smrg/*
27692f60a7Smrg * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
28692f60a7Smrg */
29692f60a7Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_video.c,v 1.6tsi Exp $ */
30692f60a7Smrg
31692f60a7Smrg#ifdef HAVE_CONFIG_H
32692f60a7Smrg#include "config.h"
33692f60a7Smrg#endif
34692f60a7Smrg
35692f60a7Smrg#include "neo.h"
36692f60a7Smrg#include "neo_video.h"
37692f60a7Smrg
38692f60a7Smrg#define nElems(x)		(sizeof(x) / sizeof(x[0]))
39692f60a7Smrg#define MAKE_ATOM(a)	MakeAtom(a, sizeof(a) - 1, TRUE)
40692f60a7Smrg
41692f60a7Smrg#include "dixstruct.h"
42692f60a7Smrg#include "xaa.h"
43692f60a7Smrg#include "xaalocal.h"
44692f60a7Smrg
45692f60a7Smrgstatic XF86VideoAdaptorPtr NEOSetupVideo(ScreenPtr);
46692f60a7Smrg
47692f60a7Smrgstatic int NEOPutVideo(ScrnInfoPtr, short, short, short, short,
48692f60a7Smrg		       short, short, short, short, RegionPtr, pointer,
49692f60a7Smrg		       DrawablePtr);
50692f60a7Smrg
51692f60a7Smrgstatic void NEOStopVideo(ScrnInfoPtr, pointer, Bool);
52692f60a7Smrgstatic int NEOSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
53692f60a7Smrgstatic int NEOGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
54692f60a7Smrgstatic void NEOQueryBestSize(ScrnInfoPtr, Bool, short, short, short,
55692f60a7Smrg			     short, unsigned int *, unsigned int *, pointer);
56692f60a7Smrgstatic int NEOPutImage(ScrnInfoPtr, short, short, short, short, short, short,
57692f60a7Smrg		       short, short, int, unsigned char *, short, short, Bool,
58692f60a7Smrg		       RegionPtr, pointer, DrawablePtr);
59692f60a7Smrgstatic int NEOQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
60692f60a7Smrg				   unsigned short *, int *, int *);
61692f60a7Smrg
62692f60a7Smrgstatic void NEODisplayVideo(ScrnInfoPtr, int, int, short, short, int, int,
63692f60a7Smrg			    int, int, int, BoxPtr, short, short, short, short);
64692f60a7Smrg
65692f60a7Smrgstatic void NEOInitOffscreenImages(ScreenPtr);
66692f60a7Smrgstatic FBLinearPtr NEOAllocateMemory(ScrnInfoPtr, FBLinearPtr, int);
67692f60a7Smrg
68692f60a7Smrgstatic int NEOAllocSurface(ScrnInfoPtr, int, unsigned short, unsigned short,
69692f60a7Smrg			   XF86SurfacePtr);
70692f60a7Smrgstatic int NEOFreeSurface(XF86SurfacePtr);
71692f60a7Smrgstatic int NEODisplaySurface(XF86SurfacePtr, short, short, short, short,
72692f60a7Smrg			     short, short, short, short, RegionPtr clipBoxes);
73692f60a7Smrgstatic int NEOStopSurface(XF86SurfacePtr);
74692f60a7Smrgstatic int NEOGetSurfaceAttribute(ScrnInfoPtr, Atom, INT32 *);
75692f60a7Smrgstatic int NEOSetSurfaceAttribute(ScrnInfoPtr, Atom, INT32);
76692f60a7Smrg
77692f60a7Smrgstatic Atom xvColorKey, xvBrightness, xvInterlace;
78692f60a7Smrg
79692f60a7Smrgvoid
80692f60a7SmrgNEOInitVideo(ScreenPtr pScreen)
81692f60a7Smrg{
82692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
83692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
84692f60a7Smrg    XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
85692f60a7Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
86692f60a7Smrg    int numAdaptors;
87692f60a7Smrg
88692f60a7Smrg    numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
89692f60a7Smrg
90692f60a7Smrg    if (nPtr->NeoChipset > NM2070
91692f60a7Smrg	&& !nPtr->noLinear
92692f60a7Smrg	&& nPtr->NeoMMIOBase2 != NULL){
93692f60a7Smrg	nPtr->video = TRUE;
94692f60a7Smrg	newAdaptor = NEOSetupVideo(pScreen);
95692f60a7Smrg	NEOInitOffscreenImages(pScreen);
96692f60a7Smrg    } else
97692f60a7Smrg	nPtr->video = FALSE;
98692f60a7Smrg
99692f60a7Smrg    if (newAdaptor){
100692f60a7Smrg	if (!numAdaptors){
101692f60a7Smrg	    numAdaptors = 1;
102692f60a7Smrg	    overlayAdaptors = &newAdaptor;
103692f60a7Smrg	} else {
104692f60a7Smrg	    newAdaptors = xalloc((numAdaptors + 1)
105692f60a7Smrg				 * sizeof(XF86VideoAdaptorPtr*));
106692f60a7Smrg	    if (newAdaptors){
107692f60a7Smrg		memcpy(newAdaptors, overlayAdaptors,
108692f60a7Smrg		       numAdaptors * sizeof(XF86VideoAdaptorPtr));
109692f60a7Smrg		newAdaptors[numAdaptors++] = newAdaptor;
110692f60a7Smrg		overlayAdaptors = newAdaptors;
111692f60a7Smrg	    }
112692f60a7Smrg	}
113692f60a7Smrg    }
114692f60a7Smrg
115692f60a7Smrg    if (numAdaptors)
116692f60a7Smrg	xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors);
117692f60a7Smrg
118692f60a7Smrg    if (newAdaptors)
119692f60a7Smrg	xfree(newAdaptors);
120692f60a7Smrg}
121692f60a7Smrg
122692f60a7Smrgstatic XF86VideoEncodingRec NEOVideoEncodings[] =
123692f60a7Smrg{
124692f60a7Smrg    {
125692f60a7Smrg	NEO_VIDEO_VIDEO,
126692f60a7Smrg	"XV_VIDEO",
127692f60a7Smrg	1024, 1024,
128692f60a7Smrg	{1, 1}
129692f60a7Smrg    },
130692f60a7Smrg    {
131692f60a7Smrg	NEO_VIDEO_IMAGE,
132692f60a7Smrg	"XV_IMAGE",
133692f60a7Smrg	1024, 1024,
134692f60a7Smrg	{1, 1}
135692f60a7Smrg    }
136692f60a7Smrg};
137692f60a7Smrg
138692f60a7Smrgstatic XF86VideoFormatRec NEOVideoFormats[] =
139692f60a7Smrg{
140692f60a7Smrg    {  8, PseudoColor },
141692f60a7Smrg    { 15, TrueColor },
142692f60a7Smrg    { 16, TrueColor },
143692f60a7Smrg    { 24, TrueColor },
144692f60a7Smrg};
145692f60a7Smrg
146692f60a7Smrgstatic XF86AttributeRec NEOVideoAttributes[] =
147692f60a7Smrg{
148692f60a7Smrg    {
149692f60a7Smrg	XvSettable | XvGettable,
150692f60a7Smrg	0x000000, 0xFFFFFF,
151692f60a7Smrg	"XV_COLORKEY"
152692f60a7Smrg    },
153692f60a7Smrg    {
154692f60a7Smrg	XvSettable | XvGettable,
155692f60a7Smrg	-128, 127,
156692f60a7Smrg	"XV_BRIGHTNESS"
157692f60a7Smrg    },
158692f60a7Smrg    {
159692f60a7Smrg	XvSettable | XvGettable,
160692f60a7Smrg	0,2,
161692f60a7Smrg	"XV_INTERLACE"
162692f60a7Smrg    },
163692f60a7Smrg};
164692f60a7Smrg
165692f60a7Smrgstatic XF86ImageRec NEOVideoImages[] =
166692f60a7Smrg{
167692f60a7Smrg    XVIMAGE_YUY2,
168692f60a7Smrg    XVIMAGE_YV12,
169692f60a7Smrg    XVIMAGE_I420,
170692f60a7Smrg    {
171692f60a7Smrg	FOURCC_RV15,
172692f60a7Smrg	XvRGB,
173692f60a7Smrg	LSBFirst,
174692f60a7Smrg	{ 'R', 'V' ,'1', '5',
175692f60a7Smrg	  0x00,'5',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
176692f60a7Smrg	16,
177692f60a7Smrg	XvPacked,
178692f60a7Smrg	1,
179692f60a7Smrg	15, 0x001F, 0x03E0, 0x7C00,
180692f60a7Smrg	0, 0, 0,
181692f60a7Smrg	0, 0, 0,
182692f60a7Smrg	0, 0, 0,
183692f60a7Smrg	{ 'R', 'V', 'B' },
184692f60a7Smrg	XvTopToBottom
185692f60a7Smrg    },
186692f60a7Smrg    {
187692f60a7Smrg	FOURCC_RV16,
188692f60a7Smrg	XvRGB,
189692f60a7Smrg	LSBFirst,
190692f60a7Smrg	{ 'R', 'V' ,'1', '6',
191692f60a7Smrg	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
192692f60a7Smrg	16,
193692f60a7Smrg	XvPacked,
194692f60a7Smrg	1,
195692f60a7Smrg	16, 0xF800, 0x07E0, 0x001F,
196692f60a7Smrg	0, 0, 0,
197692f60a7Smrg	0, 0, 0,
198692f60a7Smrg	0, 0, 0,
199692f60a7Smrg	{ 'R', 'V', 'B' },
200692f60a7Smrg	XvTopToBottom
201692f60a7Smrg    }
202692f60a7Smrg};
203692f60a7Smrg
204692f60a7Smrgstatic XF86VideoAdaptorPtr
205692f60a7SmrgNEOSetupVideo(ScreenPtr pScreen)
206692f60a7Smrg{
207692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
208692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
209692f60a7Smrg    NEOPortPtr pPriv;
210692f60a7Smrg    XF86VideoAdaptorPtr overlayAdaptor;
211692f60a7Smrg    int i;
212692f60a7Smrg
213692f60a7Smrg#ifdef DEBUG
214692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetupVideo\n");
215692f60a7Smrg#endif
216692f60a7Smrg    if ((overlayAdaptor = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
217692f60a7Smrg			      sizeof(DevUnion) +
218692f60a7Smrg			      sizeof(NEOPortRec))) == NULL){
219692f60a7Smrg	return (NULL);
220692f60a7Smrg    }
221692f60a7Smrg
222692f60a7Smrg    overlayAdaptor->type = XvInputMask | XvImageMask | XvWindowMask
223692f60a7Smrg	| XvOutputMask | XvVideoMask;
224692f60a7Smrg    overlayAdaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
225692f60a7Smrg    overlayAdaptor->name = "NeoMagic Video Engine";
226692f60a7Smrg    overlayAdaptor->nEncodings = nElems(NEOVideoEncodings);
227692f60a7Smrg    overlayAdaptor->pEncodings = NEOVideoEncodings;
228692f60a7Smrg    for (i = 0; i < nElems(NEOVideoEncodings); i++){
229692f60a7Smrg	NEOVideoEncodings[i].width = 1024;
230692f60a7Smrg	NEOVideoEncodings[i].height = 1024;
231692f60a7Smrg    }
232692f60a7Smrg    overlayAdaptor->nFormats = nElems(NEOVideoFormats);
233692f60a7Smrg    overlayAdaptor->pFormats = NEOVideoFormats;
234692f60a7Smrg    overlayAdaptor->nPorts = 1;
235692f60a7Smrg    overlayAdaptor->pPortPrivates = (DevUnion*) &overlayAdaptor[1];
236692f60a7Smrg    overlayAdaptor->pPortPrivates[0].ptr =
237692f60a7Smrg	(pointer) &overlayAdaptor->pPortPrivates[1];
238692f60a7Smrg    overlayAdaptor->nAttributes = nElems(NEOVideoAttributes);
239692f60a7Smrg    overlayAdaptor->pAttributes = NEOVideoAttributes;
240692f60a7Smrg    overlayAdaptor->nImages = nElems(NEOVideoImages);
241692f60a7Smrg    overlayAdaptor->pImages = NEOVideoImages;
242692f60a7Smrg
243692f60a7Smrg    overlayAdaptor->PutVideo = NEOPutVideo;
244692f60a7Smrg    overlayAdaptor->PutStill = NULL;
245692f60a7Smrg    overlayAdaptor->GetVideo = NULL;
246692f60a7Smrg    overlayAdaptor->GetStill = NULL;
247692f60a7Smrg
248692f60a7Smrg    overlayAdaptor->StopVideo = NEOStopVideo;
249692f60a7Smrg    overlayAdaptor->SetPortAttribute = NEOSetPortAttribute;
250692f60a7Smrg    overlayAdaptor->GetPortAttribute = NEOGetPortAttribute;
251692f60a7Smrg    overlayAdaptor->QueryBestSize = NEOQueryBestSize;
252692f60a7Smrg    overlayAdaptor->PutImage = NEOPutImage;
253692f60a7Smrg    overlayAdaptor->QueryImageAttributes = NEOQueryImageAttributes;
254692f60a7Smrg
255692f60a7Smrg    pPriv = (NEOPortPtr)overlayAdaptor->pPortPrivates[0].ptr;
256692f60a7Smrg    pPriv->colorKey = nPtr->videoKey;
257692f60a7Smrg    pPriv->interlace = nPtr->interlace;
258692f60a7Smrg    pPriv->videoStatus = 0;
259692f60a7Smrg    pPriv->brightness = 0;
260692f60a7Smrg    REGION_NULL(pScreen, &pPriv->clip);
261692f60a7Smrg    nPtr->overlayAdaptor = overlayAdaptor;
262692f60a7Smrg
263692f60a7Smrg    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
264692f60a7Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
265692f60a7Smrg    xvInterlace = MAKE_ATOM("XV_INTERLACE");
266692f60a7Smrg
267692f60a7Smrg    NEOResetVideo(pScrn);
268692f60a7Smrg
269692f60a7Smrg    return (overlayAdaptor);
270692f60a7Smrg}
271692f60a7Smrg
272692f60a7Smrgvoid
273692f60a7SmrgNEOResetVideo(ScrnInfoPtr pScrn)
274692f60a7Smrg{
275692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
276692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
277692f60a7Smrg    int r, g, b;
278692f60a7Smrg    VGA_HWP(pScrn);
279692f60a7Smrg
280692f60a7Smrg#ifdef DEBUG
281692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOResetVideo\n");
282692f60a7Smrg#endif
283692f60a7Smrg    switch (pScrn->depth){
284692f60a7Smrg    case 8:
285692f60a7Smrg	OUTGR(0xc6, pPriv->colorKey & 0);
286692f60a7Smrg	OUTGR(0xc5, pPriv->colorKey & 0xff);
287692f60a7Smrg	OUTGR(0xc7, pPriv->colorKey & 0);
288692f60a7Smrg	break;
289692f60a7Smrg    default:
290692f60a7Smrg	r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
291692f60a7Smrg	g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
292692f60a7Smrg	b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
293692f60a7Smrg	OUTGR(0xc5, r);
294692f60a7Smrg	OUTGR(0xc6, g);
295692f60a7Smrg	OUTGR(0xc7, b);
296692f60a7Smrg	break;
297692f60a7Smrg    }
298692f60a7Smrg    OUTGR(0xc4, pPriv->brightness);
299692f60a7Smrg}
300692f60a7Smrg
301692f60a7Smrgstatic int
302692f60a7SmrgNEOPutVideo(ScrnInfoPtr pScrn,
303692f60a7Smrg	     short src_x, short src_y, short drw_x, short drw_y,
304692f60a7Smrg	     short src_w, short src_h, short drw_w, short drw_h,
305692f60a7Smrg	     RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
306692f60a7Smrg{
307692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
308692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
309692f60a7Smrg    CARD32 src_pitch, offset;
310692f60a7Smrg    int xscale, yscale;
311692f60a7Smrg    BoxRec dstBox;
312692f60a7Smrg    INT32 x1, y1, x2, y2;
313692f60a7Smrg    int size, bpp;
314692f60a7Smrg    unsigned char capctrl;
315692f60a7Smrg    VGA_HWP(pScrn);
316692f60a7Smrg
317692f60a7Smrg#ifdef DEBUG
318692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: src: %d %d %d %d\n",
319692f60a7Smrg	       src_x, src_y, src_w, src_h);
320692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: drw: %d %d %d %d\n",
321692f60a7Smrg	       drw_x, drw_y, drw_w, drw_h);
322692f60a7Smrg#endif
323692f60a7Smrg    if (src_w > 720)
324692f60a7Smrg	src_w = 720;
325692f60a7Smrg    if (src_h > 576)
326692f60a7Smrg        src_h = 576;
327692f60a7Smrg    if (pPriv->interlace != 2)
328692f60a7Smrg	src_h /= 2;
329692f60a7Smrg    x1 = src_x;
330692f60a7Smrg    y1 = src_y;
331692f60a7Smrg    x2 = src_x + src_w;
332692f60a7Smrg    y2 = src_y + src_h;
333692f60a7Smrg
334692f60a7Smrg    dstBox.x1 = drw_x;
335692f60a7Smrg    dstBox.y1 = drw_y;
336692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
337692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
338692f60a7Smrg
339692f60a7Smrg    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
340692f60a7Smrg			       clipBoxes, src_w, src_h)){
341692f60a7Smrg	return(Success);
342692f60a7Smrg    }
343692f60a7Smrg#ifdef DEBUG
344692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: %d %d %d %d\n",
345692f60a7Smrg	       x1, y1, x2, y2);
346692f60a7Smrg#endif
347692f60a7Smrg
348692f60a7Smrg    dstBox.x1 -= pScrn->frameX0;
349692f60a7Smrg    dstBox.y1 -= pScrn->frameY0;
350692f60a7Smrg    dstBox.x2 -= pScrn->frameX0;
351692f60a7Smrg    dstBox.y2 -= pScrn->frameY0;
352692f60a7Smrg#ifdef DEBUG
353692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: dstBox %d %d %d %d\n",
354692f60a7Smrg	       dstBox.x1, dstBox.y1, dstBox.x2, dstBox.y2);
355692f60a7Smrg#endif
356692f60a7Smrg
357692f60a7Smrg    bpp = (pScrn->bitsPerPixel + 1) >> 3;
358692f60a7Smrg    src_pitch = (src_w + 7) & ~7;
359692f60a7Smrg
360692f60a7Smrg    xscale = 0x1000;
361692f60a7Smrg    if (src_w <= drw_w){
362692f60a7Smrg	xscale = (src_w * 0x1000 / drw_w) & 0xffff;
363692f60a7Smrg    }
364692f60a7Smrg
365692f60a7Smrg    yscale = 0x1000;
366692f60a7Smrg    if (src_h <= drw_h){
367692f60a7Smrg 	yscale = (src_h * 0x1000 / drw_h) & 0xffff;
368692f60a7Smrg    }
369692f60a7Smrg
370692f60a7Smrg    size = src_h * src_pitch * 2;
371692f60a7Smrg
372692f60a7Smrg    if (size > nPtr->overlay){
373692f60a7Smrg	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
374692f60a7Smrg	    == NULL){
375692f60a7Smrg	    return (BadAlloc);
376692f60a7Smrg	}
377692f60a7Smrg    } else {
378692f60a7Smrg	pPriv->linear = NULL;
379692f60a7Smrg    }
380692f60a7Smrg
381692f60a7Smrg    if (pPriv->linear == NULL){
382692f60a7Smrg	offset = nPtr->overlay_offset;
383692f60a7Smrg    } else {
384692f60a7Smrg	offset = pPriv->linear->offset * bpp;
385692f60a7Smrg    }
386692f60a7Smrg
387692f60a7Smrg#ifdef DEBUG
388692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutVideo: offset=0x%x\n", offset);
389692f60a7Smrg#endif
390692f60a7Smrg     WAIT_ENGINE_IDLE();
391692f60a7Smrg     memset(nPtr->NeoFbBase + offset, 0, size);
392692f60a7Smrg
393692f60a7Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
394692f60a7Smrg	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
395692f60a7Smrg	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
396692f60a7Smrg    }
397692f60a7Smrg
398692f60a7Smrg    x1 >>= 16;
399692f60a7Smrg    y1 >>= 16;
400692f60a7Smrg    x2 >>= 16;
401692f60a7Smrg    y2 >>= 16;
402692f60a7Smrg
403692f60a7Smrg    switch (nPtr->NeoChipset) {
404692f60a7Smrg    default:
405692f60a7Smrg    case NM2090:
406692f60a7Smrg    case NM2093:
407692f60a7Smrg    case NM2097:
408692f60a7Smrg    case NM2160:
409692f60a7Smrg	offset/=2;
410692f60a7Smrg	OUTGR(0xbc, 0x4f);
411692f60a7Smrg 	break;
412692f60a7Smrg    case NM2200:
413692f60a7Smrg    case NM2230:
414692f60a7Smrg    case NM2360:
415692f60a7Smrg    case NM2380:
416692f60a7Smrg	OUTGR(0xbc, 0x2e);
417692f60a7Smrg 	break;
418692f60a7Smrg    }
419692f60a7Smrg
420692f60a7Smrg
421692f60a7Smrg    OUTGR(0xb1, (((dstBox.x2-1) >> 4) & 0xf0) | ((dstBox.x1 >> 8) & 0x0f));
422692f60a7Smrg    OUTGR(0xb2, dstBox.x1);
423692f60a7Smrg    OUTGR(0xb3, dstBox.x2 - 1);
424692f60a7Smrg    OUTGR(0xb4, (((dstBox.y2 - 1) >> 4) & 0xf0) | ((dstBox.y1 >> 8) & 0x0f));
425692f60a7Smrg    OUTGR(0xb5, dstBox.y1);
426692f60a7Smrg    OUTGR(0xb6, dstBox.y2 - 1);
427692f60a7Smrg    OUTGR(0xb7, offset >> 16);
428692f60a7Smrg    OUTGR(0xb8, offset >> 8);
429692f60a7Smrg    OUTGR(0xb9, offset );
430692f60a7Smrg    OUTGR(0xba, src_pitch >> 8);
431692f60a7Smrg    OUTGR(0xbb, src_pitch);
432692f60a7Smrg
433692f60a7Smrg    OUTGR(0xc0, xscale >> 8);
434692f60a7Smrg    OUTGR(0xc1, xscale);
435692f60a7Smrg    OUTGR(0xc2, yscale >> 8);
436692f60a7Smrg    OUTGR(0xc3, yscale);
437692f60a7Smrg    OUTGR(0xbf, 0x02);
438692f60a7Smrg
439692f60a7Smrg    OUTGR(0x0a, 0x21);
440692f60a7Smrg
441692f60a7Smrg    OUTSR(0x0c, offset );
442692f60a7Smrg    OUTSR(0x0d, offset >> 8);
443692f60a7Smrg    OUTSR(0x0e, offset >> 16);
444692f60a7Smrg    OUTSR(0x1a, src_pitch);
445692f60a7Smrg    OUTSR(0x1b, src_pitch>>8);
446692f60a7Smrg
447692f60a7Smrg    OUTSR(0x17, 0 + x1);
448692f60a7Smrg    OUTSR(0x18, 0 + x2 -1);
449692f60a7Smrg    OUTSR(0x19, (((0 + x2 - 1) >> 4) & 0xf0) | (((0 + x1) >> 8) & 0x0f));
450692f60a7Smrg
451692f60a7Smrg    OUTSR(0x14, 14 + y1);
452692f60a7Smrg    OUTSR(0x15, 14 + y2 - 2);
453692f60a7Smrg    OUTSR(0x16, (((14 + y2 - 1) >> 4) & 0xf0) | (((14 + y1) >> 8) & 0x0f));
454692f60a7Smrg
455692f60a7Smrg    OUTSR(0x1c, 0xfb);
456692f60a7Smrg    OUTSR(0x1d, 0x00);
457692f60a7Smrg    OUTSR(0x1e, 0xe2);
458692f60a7Smrg    OUTSR(0x1f, 0x02);
459692f60a7Smrg
460692f60a7Smrg    OUTSR(0x09, 0x11);
461692f60a7Smrg    OUTSR(0x0a, 0x00);
462692f60a7Smrg
463692f60a7Smrg    capctrl = 0x21;
464692f60a7Smrg    switch (pPriv->interlace){
465692f60a7Smrg    case 0: /* Combine 2 fields */
466692f60a7Smrg	break;
467692f60a7Smrg    case 1: /* one field only */
468692f60a7Smrg	capctrl |= 0x80;
469692f60a7Smrg	break;
470692f60a7Smrg    case 2: /* Interlaced fields */
471692f60a7Smrg	capctrl |= 0x40;
472692f60a7Smrg	break;
473692f60a7Smrg    }
474692f60a7Smrg    OUTSR(0x08, capctrl);
475692f60a7Smrg
476692f60a7Smrg#if 0
477692f60a7Smrg    OUTGR(0x0a, 0x01);
478692f60a7Smrg#endif
479692f60a7Smrg    OUTGR(0xb0, 0x03);
480692f60a7Smrg
481692f60a7Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
482692f60a7Smrg    return (Success);
483692f60a7Smrg}
484692f60a7Smrg
485692f60a7Smrgstatic void
486692f60a7SmrgNEOStopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
487692f60a7Smrg{
488692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
489692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
490692f60a7Smrg    VGA_HWP(pScrn);
491692f60a7Smrg
492692f60a7Smrg#ifdef DEBUG
493692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo\n");
494692f60a7Smrg#endif
495692f60a7Smrg    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
496692f60a7Smrg
497692f60a7Smrg    if (exit){
498692f60a7Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
499692f60a7Smrg#ifdef DEBUG
500692f60a7Smrg            xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOStopVideo: stop capture\n");
501692f60a7Smrg#endif
502692f60a7Smrg	    OUTGR(0xb0, 0x02);
503692f60a7Smrg	    OUTGR(0x0a, 0x21);
504692f60a7Smrg	    OUTSR(0x08, 0xa0);
505692f60a7Smrg#if 0
506692f60a7Smrg	    OUTGR(0x0a, 0x01);
507692f60a7Smrg#endif
508692f60a7Smrg	}
509692f60a7Smrg	if (pPriv->linear != NULL){
510692f60a7Smrg	    xf86FreeOffscreenLinear(pPriv->linear);
511692f60a7Smrg	    pPriv->linear = NULL;
512692f60a7Smrg	}
513692f60a7Smrg	pPriv->videoStatus = 0;
514692f60a7Smrg    } else {
515692f60a7Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON){
516692f60a7Smrg	    OUTGR(0xb0, 0x02);
517692f60a7Smrg	    OUTGR(0x0a, 0x21);
518692f60a7Smrg	    OUTSR(0x08, 0xa0);
519692f60a7Smrg#if 0
520692f60a7Smrg	    OUTGR(0x0a, 0x01);
521692f60a7Smrg#endif
522692f60a7Smrg	    pPriv->videoStatus |= OFF_TIMER;
523692f60a7Smrg	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
524692f60a7Smrg	}
525692f60a7Smrg    }
526692f60a7Smrg}
527692f60a7Smrg
528692f60a7Smrgstatic int
529692f60a7SmrgNEOSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value,
530692f60a7Smrg		    pointer data)
531692f60a7Smrg{
532692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
533692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
534692f60a7Smrg    VGA_HWP(pScrn);
535692f60a7Smrg
536692f60a7Smrg#ifdef DEBUG
537692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetPortAttribute\n");
538692f60a7Smrg#endif
539692f60a7Smrg    if (attribute == xvColorKey){
540692f60a7Smrg	int r, g, b;
541692f60a7Smrg
542692f60a7Smrg	pPriv->colorKey = value;
543692f60a7Smrg	switch (pScrn->depth){
544692f60a7Smrg	case 8:
545692f60a7Smrg	    OUTGR(0xc6, pPriv->colorKey & 0xff);
546692f60a7Smrg	    OUTGR(0xc5, 0x00);
547692f60a7Smrg	    OUTGR(0xc7, 0x00);
548692f60a7Smrg	    break;
549692f60a7Smrg	default:
550692f60a7Smrg	    r = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
551692f60a7Smrg	    g = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
552692f60a7Smrg	    b = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
553692f60a7Smrg	    OUTGR(0xc5, r);
554692f60a7Smrg	    OUTGR(0xc6, g);
555692f60a7Smrg	    OUTGR(0xc7, b);
556692f60a7Smrg	}
557692f60a7Smrg    } else if (attribute == xvBrightness){
558692f60a7Smrg	if ((value < -128) || (value > 127)){
559692f60a7Smrg	    return (BadValue);
560692f60a7Smrg	}
561692f60a7Smrg	pPriv->brightness = value;
562692f60a7Smrg	OUTGR(0xc4, value);
563692f60a7Smrg    } else if (attribute == xvInterlace){
564692f60a7Smrg	if (value < 0  ||  value > 2){
565692f60a7Smrg	    return (BadValue);
566692f60a7Smrg	}
567692f60a7Smrg	pPriv->interlace = value;
568692f60a7Smrg    } else {
569692f60a7Smrg	return (BadMatch);
570692f60a7Smrg    }
571692f60a7Smrg    return (Success);
572692f60a7Smrg}
573692f60a7Smrg
574692f60a7Smrgstatic int
575692f60a7SmrgNEOGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value,
576692f60a7Smrg		    pointer data)
577692f60a7Smrg{
578692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)data;
579692f60a7Smrg
580692f60a7Smrg#ifdef DEBUG
581692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetPortAttribute\n");
582692f60a7Smrg#endif
583692f60a7Smrg    if (attribute == xvColorKey){
584692f60a7Smrg	*value = pPriv->colorKey;
585692f60a7Smrg    } else if (attribute == xvBrightness){
586692f60a7Smrg	*value = pPriv->brightness;
587692f60a7Smrg    } else if (attribute == xvInterlace){
588692f60a7Smrg	*value = pPriv->interlace;
589692f60a7Smrg    } else {
590692f60a7Smrg	return (BadMatch);
591692f60a7Smrg    }
592692f60a7Smrg    return (Success);
593692f60a7Smrg}
594692f60a7Smrg
595692f60a7Smrgstatic void
596692f60a7SmrgNEOQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
597692f60a7Smrg		 short vid_w, short vid_h, short drw_w, short drw_h,
598692f60a7Smrg		 unsigned int *p_w, unsigned int *p_h,
599692f60a7Smrg		 pointer data)
600692f60a7Smrg{
601692f60a7Smrg#ifdef DEBUG
602692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryBestSize\n");
603692f60a7Smrg#endif
604692f60a7Smrg    *p_w = min(drw_w, 1024);
605692f60a7Smrg    *p_h = min(drw_h, 1024);
606692f60a7Smrg}
607692f60a7Smrg
608692f60a7Smrgstatic int
609692f60a7SmrgNEOPutImage(ScrnInfoPtr pScrn,
610692f60a7Smrg	    short src_x, short src_y, short drw_x, short drw_y,
611692f60a7Smrg	    short src_w, short src_h, short drw_w, short drw_h,
612692f60a7Smrg	    int id, unsigned char *buf, short width, short height,
613692f60a7Smrg	    Bool sync, RegionPtr clipBoxes, pointer data,
614692f60a7Smrg	    DrawablePtr pDraw)
615692f60a7Smrg{
616692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
617692f60a7Smrg    NEOPortPtr pPriv = (NEOPortPtr)nPtr->overlayAdaptor->pPortPrivates[0].ptr;
618692f60a7Smrg    INT32 x1, y1, x2, y2;
619692f60a7Smrg    int bpp;
620692f60a7Smrg    int srcPitch, srcPitch2 = 0, dstPitch, size;
621692f60a7Smrg    BoxRec dstBox;
622692f60a7Smrg    CARD32 offset, offset2 = 0, offset3 = 0, tmp;
623692f60a7Smrg    int left, top, nPixels, nLines;
624692f60a7Smrg    unsigned char *dstStart;
625692f60a7Smrg
626692f60a7Smrg#ifdef DEBUG
627692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOPutImage\n");
628692f60a7Smrg#endif
629692f60a7Smrg
630692f60a7Smrg    x1 = src_x;
631692f60a7Smrg    y1 = src_y;
632692f60a7Smrg    x2 = src_x + src_w;
633692f60a7Smrg    y2 = src_y + src_h;
634692f60a7Smrg
635692f60a7Smrg    dstBox.x1 = drw_x;
636692f60a7Smrg    dstBox.y1 = drw_y;
637692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
638692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
639692f60a7Smrg
640692f60a7Smrg    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
641692f60a7Smrg			       clipBoxes, width, height)){
642692f60a7Smrg	return (Success);
643692f60a7Smrg    }
644692f60a7Smrg
645692f60a7Smrg    dstBox.x1 -= pScrn->frameX0;
646692f60a7Smrg    dstBox.y1 -= pScrn->frameY0;
647692f60a7Smrg    dstBox.x2 -= pScrn->frameX0;
648692f60a7Smrg    dstBox.y2 -= pScrn->frameY0;
649692f60a7Smrg
650692f60a7Smrg    bpp = ((pScrn->bitsPerPixel + 1) >> 3);
651692f60a7Smrg
652692f60a7Smrg    switch (id){
653692f60a7Smrg    case FOURCC_YV12:
654692f60a7Smrg	srcPitch  = (width + 3) & ~3;
655692f60a7Smrg	offset2   = srcPitch * height;
656692f60a7Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
657692f60a7Smrg	offset3   = offset2 + (srcPitch2 * (height >> 1));
658692f60a7Smrg  	dstPitch  = ((width << 1) + 15) & ~15;
659692f60a7Smrg	break;
660692f60a7Smrg    case FOURCC_I420:
661692f60a7Smrg	srcPitch  = (width + 3) & ~3;
662692f60a7Smrg	offset3   = srcPitch * height;
663692f60a7Smrg	srcPitch2 = ((width >> 1) + 3) & ~3;
664692f60a7Smrg	offset2   = offset3 + (srcPitch2 * (height >> 1));
665692f60a7Smrg  	dstPitch  = ((width << 1) + 15) & ~15;
666692f60a7Smrg	break;
667692f60a7Smrg    case FOURCC_YUY2:
668692f60a7Smrg    case FOURCC_RV15:
669692f60a7Smrg    case FOURCC_RV16:
670692f60a7Smrg    default:
671692f60a7Smrg	srcPitch = width << 1;
672692f60a7Smrg  	dstPitch = (srcPitch + 15) & ~15;
673692f60a7Smrg	break;
674692f60a7Smrg    }
675692f60a7Smrg
676692f60a7Smrg    size = dstPitch * height;
677692f60a7Smrg    if (size > nPtr->overlay){
678692f60a7Smrg	if ((pPriv->linear = NEOAllocateMemory(pScrn, pPriv->linear, size))
679692f60a7Smrg	    == NULL){
680692f60a7Smrg	    return (BadAlloc);
681692f60a7Smrg	}
682692f60a7Smrg    } else {
683692f60a7Smrg	pPriv->linear = NULL;
684692f60a7Smrg    }
685692f60a7Smrg
686692f60a7Smrg    top = y1 >> 16;
687692f60a7Smrg    left = (x1 >> 16) & ~1;
688692f60a7Smrg    nPixels = ((((x2 + 0xFFFF) >> 16) + 1) & ~1) - left;
689692f60a7Smrg    left <<= 1;
690692f60a7Smrg
691692f60a7Smrg    if (pPriv->linear == NULL){
692692f60a7Smrg	offset = nPtr->overlay_offset;
693692f60a7Smrg    } else {
694692f60a7Smrg	offset =  pPriv->linear->offset * bpp;
695692f60a7Smrg    }
696692f60a7Smrg
697692f60a7Smrg#ifdef DEBUG
698692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"offset=%x\n", offset);
699692f60a7Smrg#endif
700692f60a7Smrg
701692f60a7Smrg    dstStart = (unsigned char *)(nPtr->NeoFbBase + offset + left);
702692f60a7Smrg
703692f60a7Smrg    switch (id){
704692f60a7Smrg    case FOURCC_YV12:
705692f60a7Smrg    case FOURCC_I420:
706692f60a7Smrg	top &= ~1;
707692f60a7Smrg	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
708692f60a7Smrg	offset2 += tmp;
709692f60a7Smrg	offset3 += tmp;
710692f60a7Smrg	nLines = ((((y2 + 0xFFFF) >> 16) + 1) & ~1) - top;
711692f60a7Smrg	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
712692f60a7Smrg				buf + offset2, buf + offset3,
713692f60a7Smrg				dstStart, srcPitch, srcPitch2,
714692f60a7Smrg				dstPitch, nLines, nPixels);
715692f60a7Smrg	break;
716692f60a7Smrg    default:
717692f60a7Smrg	buf += (top * srcPitch) + left;
718692f60a7Smrg	nLines = ((y2 + 0xFFFF) >> 16) - top;
719692f60a7Smrg	xf86XVCopyPacked(buf, dstStart, srcPitch, dstPitch,
720692f60a7Smrg			 nLines, nPixels << 1);
721692f60a7Smrg    }
722692f60a7Smrg
723692f60a7Smrg    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)){
724692f60a7Smrg	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
725692f60a7Smrg        xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
726692f60a7Smrg    }
727692f60a7Smrg	NEODisplayVideo(pScrn, id, offset, width, height, dstPitch, x1, y1,
728692f60a7Smrg			x2, y2,	&dstBox, src_w, src_h, drw_w, drw_h);
729692f60a7Smrg
730692f60a7Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
731692f60a7Smrg    return (Success);
732692f60a7Smrg
733692f60a7Smrg}
734692f60a7Smrg
735692f60a7Smrgstatic int
736692f60a7SmrgNEOQueryImageAttributes(ScrnInfoPtr pScrn, int id,
737692f60a7Smrg			unsigned short *width, unsigned short *height,
738692f60a7Smrg			int *pitches, int *offsets)
739692f60a7Smrg{
740692f60a7Smrg    int size, tmp;
741692f60a7Smrg
742692f60a7Smrg#ifdef DEBUG
743692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOQueryImageAttributes\n");
744692f60a7Smrg#endif
745692f60a7Smrg    if (*width > 1024){
746692f60a7Smrg	*width = 1024;
747692f60a7Smrg    }
748692f60a7Smrg    if (*height > 1024){
749692f60a7Smrg	*height = 1024;
750692f60a7Smrg    }
751692f60a7Smrg
752692f60a7Smrg    *width = (*width + 1) & ~1;
753692f60a7Smrg    if (offsets != NULL){
754692f60a7Smrg	offsets[0] = 0;
755692f60a7Smrg    }
756692f60a7Smrg
757692f60a7Smrg    switch (id){
758692f60a7Smrg    case FOURCC_YV12:
759692f60a7Smrg    case FOURCC_I420:
760692f60a7Smrg	*height = (*height + 1) & ~1;
761692f60a7Smrg	size = (*width + 3) & ~3;
762692f60a7Smrg	if (pitches != NULL){
763692f60a7Smrg	    pitches[0] = size;
764692f60a7Smrg	}
765692f60a7Smrg	size *= *height;
766692f60a7Smrg	if (offsets != NULL){
767692f60a7Smrg	    offsets[1] = size;
768692f60a7Smrg	}
769692f60a7Smrg	tmp = ((*width >> 1) + 3) & ~3;
770692f60a7Smrg	if (pitches != NULL){
771692f60a7Smrg	    pitches[1] = pitches[2] = tmp;
772692f60a7Smrg	}
773692f60a7Smrg	tmp *= (*height >> 1);
774692f60a7Smrg	size += tmp;
775692f60a7Smrg	if (offsets != NULL){
776692f60a7Smrg	    offsets[2] = size;
777692f60a7Smrg	}
778692f60a7Smrg	size += tmp;
779692f60a7Smrg	break;
780692f60a7Smrg    case FOURCC_YUY2:
781692f60a7Smrg    case FOURCC_RV15:
782692f60a7Smrg    case FOURCC_RV16:
783692f60a7Smrg    default:
784692f60a7Smrg	size = *width * 2;
785692f60a7Smrg	if (pitches != NULL){
786692f60a7Smrg	    pitches[0] = size;
787692f60a7Smrg	}
788692f60a7Smrg	size *= *height;
789692f60a7Smrg	break;
790692f60a7Smrg    }
791692f60a7Smrg    return (size);
792692f60a7Smrg}
793692f60a7Smrg
794692f60a7Smrgstatic void
795692f60a7SmrgNEODisplayVideo(ScrnInfoPtr pScrn, int id, int offset,
796692f60a7Smrg		 short width, short height, int pitch,
797692f60a7Smrg		 int x1, int y1, int x2, int y2, BoxPtr dstBox,
798692f60a7Smrg		 short src_w, short src_h, short drw_w, short drw_h)
799692f60a7Smrg{
800692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
801692f60a7Smrg    int hstretch, vstretch, fmt;
802692f60a7Smrg    VGA_HWP(pScrn);
803692f60a7Smrg#ifdef DEBUG
804692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEODisplayVideo\n");
805692f60a7Smrg    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);
806692f60a7Smrg#endif
807692f60a7Smrg#define WIDTH_THRESHOLD 160
808692f60a7Smrg    if (dstBox->x2 >= pScrn->virtualX) {
809692f60a7Smrg	/*
810692f60a7Smrg	 * This is a hack to work around a problem when video is moved
811692f60a7Smrg	 * accross the right border.
812692f60a7Smrg	 */
813692f60a7Smrg	int diff_s = (width - ((x2 - x1) >> 16)) & ~1;
814692f60a7Smrg	int diff_d = (drw_w - dstBox->x2 + dstBox->x1) & ~1;
815692f60a7Smrg
816692f60a7Smrg	offset -= 2 * ((diff_s > diff_d) ? diff_d : diff_s);
817692f60a7Smrg	dstBox->x1 -= diff_d;
818692f60a7Smrg    } else if (dstBox->x2 - dstBox->x1 < WIDTH_THRESHOLD) {
819692f60a7Smrg	/*
820692f60a7Smrg	 * When the video window is less than about 160 pixel wide
821692f60a7Smrg	 * it will be distoreted. We attempt to fix it by actually
822692f60a7Smrg	 * making it wider and relying on the color key to prevent
823692f60a7Smrg	 * it from appearing outside of the video.
824692f60a7Smrg	 */
825692f60a7Smrg	int pre, post;
826692f60a7Smrg	int scale = 1;
827692f60a7Smrg
828692f60a7Smrg	if (dstBox->x1 < WIDTH_THRESHOLD) {
829692f60a7Smrg	    pre = dstBox->x1;
830692f60a7Smrg	    post = 160 - pre;
831692f60a7Smrg	} else {
832692f60a7Smrg	    pre = 160;
833692f60a7Smrg	    post = 0;
834692f60a7Smrg	}
835692f60a7Smrg	offset -= 2 * scale * pre;
836692f60a7Smrg	dstBox->x1 -= pre;
837692f60a7Smrg	dstBox->x2 += post;
838692f60a7Smrg    }
839692f60a7Smrg    if (nPtr->videoHZoom != 1.0) {
840692f60a7Smrg	if ((dstBox->x2 += 5) > pScrn->virtualX)
841692f60a7Smrg	    dstBox->x2 = pScrn->virtualX;
842692f60a7Smrg	if (dstBox->x1 > 0) dstBox->x1 += 2;
843692f60a7Smrg    }
844692f60a7Smrg
845692f60a7Smrg    fmt = 0x00;
846692f60a7Smrg    switch (id){
847692f60a7Smrg    case FOURCC_YV12:
848692f60a7Smrg    case FOURCC_I420:
849692f60a7Smrg    case FOURCC_YUY2:
850692f60a7Smrg	fmt = 0x00;
851692f60a7Smrg	break;
852692f60a7Smrg    case FOURCC_RV15:
853692f60a7Smrg    case FOURCC_RV16:
854692f60a7Smrg	fmt = 0x20;
855692f60a7Smrg	break;
856692f60a7Smrg    }
857692f60a7Smrg
858692f60a7Smrg    offset += (x1 >> 15) & ~0x03;
859692f60a7Smrg
860692f60a7Smrg    switch (nPtr->NeoChipset) {
861692f60a7Smrg    default:
862692f60a7Smrg    case NM2090:
863692f60a7Smrg    case NM2093:
864692f60a7Smrg    case NM2097:
865692f60a7Smrg    case NM2160:
866692f60a7Smrg        offset/=2;
867692f60a7Smrg	pitch/=2;
868692f60a7Smrg        OUTGR(0xbc, 0x4f);
869692f60a7Smrg	break;
870692f60a7Smrg    case NM2200:
871692f60a7Smrg    case NM2230:
872692f60a7Smrg    case NM2360:
873692f60a7Smrg    case NM2380:
874692f60a7Smrg        OUTGR(0xbc, 0x2e);
875692f60a7Smrg	break;
876692f60a7Smrg    }
877692f60a7Smrg
878692f60a7Smrg    /* factor 4 for granularity */
879692f60a7Smrg    hstretch = (double)0x1000 * 4 / (int)(nPtr->videoHZoom * 4);
880692f60a7Smrg    if (drw_w > src_w)
881692f60a7Smrg	hstretch = (((int)src_w) * hstretch) / (int) drw_w;
882692f60a7Smrg
883692f60a7Smrg    vstretch = (double)0x1000 / nPtr->videoVZoom;
884692f60a7Smrg    if (drw_h > src_h)
885692f60a7Smrg	vstretch = (((int)src_h) * vstretch )/ (int) drw_h;
886692f60a7Smrg
887692f60a7Smrg    OUTGR(0xb1, (((dstBox->x2 - 1) >> 4) & 0xf0) | ((dstBox->x1 >> 8) & 0x0f));
888692f60a7Smrg    OUTGR(0xb2, dstBox->x1);
889692f60a7Smrg    OUTGR(0xb3, dstBox->x2 - 1);
890692f60a7Smrg    OUTGR(0xb4, (((dstBox->y2 - 1) >> 4) & 0xf0) | ((dstBox->y1 >> 8) & 0x0f));
891692f60a7Smrg    OUTGR(0xb5, dstBox->y1);
892692f60a7Smrg    OUTGR(0xb6, dstBox->y2 - 1);
893692f60a7Smrg    OUTGR(0xb7, offset >> 16);
894692f60a7Smrg    OUTGR(0xb8, offset >> 8);
895692f60a7Smrg    OUTGR(0xb9, offset );
896692f60a7Smrg    OUTGR(0xba, pitch >> 8);
897692f60a7Smrg    OUTGR(0xbb, pitch);
898692f60a7Smrg
899692f60a7Smrg    OUTGR(0xbd, 0x02);
900692f60a7Smrg    OUTGR(0xbe, 0x00);
901692f60a7Smrg    OUTGR(0xbf, 0x02);
902692f60a7Smrg
903692f60a7Smrg    OUTGR(0xc0, hstretch >> 8);
904692f60a7Smrg    OUTGR(0xc1, hstretch);
905692f60a7Smrg    OUTGR(0xc2, vstretch >> 8);
906692f60a7Smrg    OUTGR(0xc3, vstretch);
907692f60a7Smrg
908692f60a7Smrg    OUTGR(0xb0, fmt | 0x03);
909692f60a7Smrg
910692f60a7Smrg    OUTGR(0x0a, 0x21);
911692f60a7Smrg    OUTSR(0x08, 0xa0);
912692f60a7Smrg    OUTGR(0x0a, 0x01);
913692f60a7Smrg}
914692f60a7Smrg
915692f60a7Smrgstatic void
916692f60a7SmrgNEOInitOffscreenImages(ScreenPtr pScreen)
917692f60a7Smrg{
918692f60a7Smrg    XF86OffscreenImagePtr offscreenImages;
919692f60a7Smrg
920692f60a7Smrg#ifdef DEBUG
921692f60a7Smrg    xf86DrvMsg(xf86Screens[pScreen->myNum]->scrnIndex,X_INFO,"NEOInitOffscreenImages\n");
922692f60a7Smrg#endif
923692f60a7Smrg    if ((offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))) == NULL){
924692f60a7Smrg	return;
925692f60a7Smrg    }
926692f60a7Smrg
927692f60a7Smrg    offscreenImages->image = NEOVideoImages;
928692f60a7Smrg    offscreenImages->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
929692f60a7Smrg    offscreenImages->alloc_surface = NEOAllocSurface;
930692f60a7Smrg    offscreenImages->free_surface = NEOFreeSurface;
931692f60a7Smrg    offscreenImages->display = NEODisplaySurface;
932692f60a7Smrg    offscreenImages->stop = NEOStopSurface;
933692f60a7Smrg    offscreenImages->getAttribute = NEOGetSurfaceAttribute;
934692f60a7Smrg    offscreenImages->setAttribute = NEOSetSurfaceAttribute;
935692f60a7Smrg    offscreenImages->max_width = 1024;
936692f60a7Smrg    offscreenImages->max_height = 1024;
937692f60a7Smrg    offscreenImages->num_attributes = nElems(NEOVideoAttributes);
938692f60a7Smrg    offscreenImages->attributes = NEOVideoAttributes;
939692f60a7Smrg
940692f60a7Smrg    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
941692f60a7Smrg}
942692f60a7Smrg
943692f60a7Smrgstatic FBLinearPtr
944692f60a7SmrgNEOAllocateMemory(ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
945692f60a7Smrg{
946692f60a7Smrg    ScreenPtr pScreen;
947692f60a7Smrg    FBLinearPtr new_linear;
948692f60a7Smrg    int bytespp = pScrn->bitsPerPixel >> 3;
949692f60a7Smrg
950692f60a7Smrg    /* convert size in bytes into number of pixels */
951692f60a7Smrg    size = (size + bytespp - 1) / bytespp;
952692f60a7Smrg#ifdef DEBUG
953692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
954692f60a7Smrg	       "NEOAllocateMemory: linear=%x, size=%d\n", linear, size);
955692f60a7Smrg#endif
956692f60a7Smrg    if (linear){
957692f60a7Smrg#ifdef DEBUG
958692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
959692f60a7Smrg		   "NEOAllocateMemory: linear->size=%d\n", linear->size);
960692f60a7Smrg#endif
961692f60a7Smrg	if (linear->size >= size){
962692f60a7Smrg	    return (linear);
963692f60a7Smrg	}
964692f60a7Smrg
965692f60a7Smrg	if (xf86ResizeOffscreenLinear(linear, size)){
966692f60a7Smrg	    return (linear);
967692f60a7Smrg	}
968692f60a7Smrg
969692f60a7Smrg	xf86FreeOffscreenLinear(linear);
970692f60a7Smrg    }
971692f60a7Smrg
972692f60a7Smrg
973692f60a7Smrg    pScreen = screenInfo.screens[pScrn->scrnIndex];
974692f60a7Smrg    if ((new_linear = xf86AllocateOffscreenLinear(pScreen, size, 16, NULL,
975692f60a7Smrg						  NULL, NULL)) == NULL){
976692f60a7Smrg	int max_size;
977692f60a7Smrg
978692f60a7Smrg	xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
979692f60a7Smrg					PRIORITY_EXTREME);
980692f60a7Smrg#ifdef DEBUG
981692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
982692f60a7Smrg		   "NEOAllocateMemory: max_size=%d\n", max_size);
983692f60a7Smrg#endif
984692f60a7Smrg	if (max_size < size){
985692f60a7Smrg	    return (NULL);
986692f60a7Smrg	}
987692f60a7Smrg
988692f60a7Smrg	xf86PurgeUnlockedOffscreenAreas(pScreen);
989692f60a7Smrg	new_linear = xf86AllocateOffscreenLinear(pScreen,
990692f60a7Smrg						 size, 16, NULL, NULL, NULL);
991692f60a7Smrg    }
992692f60a7Smrg
993692f60a7Smrg    return (new_linear);
994692f60a7Smrg}
995692f60a7Smrg
996692f60a7Smrgstatic int
997692f60a7SmrgNEOAllocSurface(ScrnInfoPtr pScrn, int id,
998692f60a7Smrg		unsigned short width, unsigned short height,
999692f60a7Smrg		XF86SurfacePtr surface)
1000692f60a7Smrg{
1001692f60a7Smrg    int pitch, size;
1002692f60a7Smrg    NEOOffscreenPtr pPriv;
1003692f60a7Smrg    FBLinearPtr linear;
1004692f60a7Smrg
1005692f60a7Smrg#ifdef DEBUG
1006692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOAllocSurface\n");
1007692f60a7Smrg#endif
1008692f60a7Smrg    if (width > 1024  || height > 1024){
1009692f60a7Smrg	return (BadAlloc);
1010692f60a7Smrg    }
1011692f60a7Smrg
1012692f60a7Smrg    width = (width + 1) & ~1;
1013692f60a7Smrg    pitch = ((width << 1) + 15) & ~15;
1014692f60a7Smrg    size = pitch * height;
1015692f60a7Smrg
1016692f60a7Smrg    if ((linear = NEOAllocateMemory(pScrn, NULL, size)) == NULL){
1017692f60a7Smrg	return (BadAlloc);
1018692f60a7Smrg    }
1019692f60a7Smrg
1020692f60a7Smrg    surface->width = width;
1021692f60a7Smrg    surface->height = height;
1022692f60a7Smrg    if ((surface->pitches = xalloc(sizeof(int))) == NULL){
1023692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1024692f60a7Smrg	return (BadAlloc);
1025692f60a7Smrg    }
1026692f60a7Smrg    if ((surface->offsets = xalloc(sizeof(int))) == NULL){
1027692f60a7Smrg	xfree(surface->pitches);
1028692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1029692f60a7Smrg	return (BadAlloc);
1030692f60a7Smrg    }
1031692f60a7Smrg
1032692f60a7Smrg    if ((pPriv = xalloc(sizeof(NEOOffscreenRec))) == NULL){
1033692f60a7Smrg	xfree(surface->pitches);
1034692f60a7Smrg	xfree(surface->offsets);
1035692f60a7Smrg	xf86FreeOffscreenLinear(linear);
1036692f60a7Smrg	return (BadAlloc);
1037692f60a7Smrg    }
1038692f60a7Smrg
1039692f60a7Smrg    pPriv->linear = linear;
1040692f60a7Smrg    pPriv->isOn = FALSE;
1041692f60a7Smrg
1042692f60a7Smrg    surface->pScrn = pScrn;
1043692f60a7Smrg    surface->id = id;
1044692f60a7Smrg    surface->pitches[0] = pitch;
1045692f60a7Smrg    surface->offsets[0] = linear->offset << 1;
1046692f60a7Smrg    surface->devPrivate.ptr = (pointer)pPriv;
1047692f60a7Smrg    return (Success);
1048692f60a7Smrg}
1049692f60a7Smrg
1050692f60a7Smrgstatic int
1051692f60a7SmrgNEOFreeSurface(XF86SurfacePtr surface)
1052692f60a7Smrg{
1053692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1054692f60a7Smrg
1055692f60a7Smrg#ifdef DEBUG
1056692f60a7Smrg    xf86DrvMsg(0,X_INFO,"NEOFreeSurface\n");
1057692f60a7Smrg#endif
1058692f60a7Smrg    if (pPriv->isOn)
1059692f60a7Smrg	NEOStopSurface(surface);
1060692f60a7Smrg
1061692f60a7Smrg    xf86FreeOffscreenLinear(pPriv->linear);
1062692f60a7Smrg    xfree(surface->pitches);
1063692f60a7Smrg    xfree(surface->offsets);
1064692f60a7Smrg    xfree(surface->devPrivate.ptr);
1065692f60a7Smrg    return (Success);
1066692f60a7Smrg}
1067692f60a7Smrg
1068692f60a7Smrgstatic int
1069692f60a7SmrgNEODisplaySurface(XF86SurfacePtr surface,
1070692f60a7Smrg		  short src_x, short src_y, short drw_x, short drw_y,
1071692f60a7Smrg		  short src_w, short src_h, short drw_w, short drw_h,
1072692f60a7Smrg		  RegionPtr clipBoxes)
1073692f60a7Smrg{
1074692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1075692f60a7Smrg    NEOPtr nPtr = NEOPTR(surface->pScrn);
1076692f60a7Smrg    NEOPortPtr portPriv = nPtr->overlayAdaptor->pPortPrivates[0].ptr;
1077692f60a7Smrg    INT32 x1, y1, x2, y2;
1078692f60a7Smrg    BoxRec dstBox;
1079692f60a7Smrg
1080692f60a7Smrg#ifdef DEBUG
1081692f60a7Smrg    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEODisplaySurface\n");
1082692f60a7Smrg#endif
1083692f60a7Smrg    x1 = src_x;
1084692f60a7Smrg    x2 = src_x + src_w;
1085692f60a7Smrg    y1 = src_y;
1086692f60a7Smrg    y2 = src_y + src_h;
1087692f60a7Smrg
1088692f60a7Smrg    dstBox.x1 = drw_x;
1089692f60a7Smrg    dstBox.x2 = drw_x + drw_w;
1090692f60a7Smrg    dstBox.y1 = drw_y;
1091692f60a7Smrg    dstBox.y2 = drw_y + drw_h;
1092692f60a7Smrg    if (!xf86XVClipVideoHelper( &dstBox, &x1, &x2, &y1, &y2,
1093692f60a7Smrg			       clipBoxes, surface->width, surface->height)){
1094692f60a7Smrg	return (Success);
1095692f60a7Smrg    }
1096692f60a7Smrg
1097692f60a7Smrg    dstBox.x1 -= surface->pScrn->frameX0;
1098692f60a7Smrg    dstBox.y1 -= surface->pScrn->frameY0;
1099692f60a7Smrg    dstBox.x2 -= surface->pScrn->frameX0;
1100692f60a7Smrg    dstBox.y2 -= surface->pScrn->frameY0;
1101692f60a7Smrg
1102692f60a7Smrg    xf86XVFillKeyHelper(surface->pScrn->pScreen, portPriv->colorKey,
1103692f60a7Smrg			clipBoxes);
1104692f60a7Smrg    NEOResetVideo(surface->pScrn);
1105692f60a7Smrg    NEODisplayVideo(surface->pScrn, surface->id, surface->offsets[0],
1106692f60a7Smrg		    surface->width, surface->height, surface->pitches[0],
1107692f60a7Smrg		    x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1108692f60a7Smrg
1109692f60a7Smrg    pPriv->isOn = TRUE;
1110692f60a7Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON){
1111692f60a7Smrg	REGION_EMPTY(surface->pScrn->pScreen, &portPriv->clip);
1112692f60a7Smrg	UpdateCurrentTime();
1113692f60a7Smrg	portPriv->videoStatus = FREE_TIMER;
1114692f60a7Smrg	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1115692f60a7Smrg    }
1116692f60a7Smrg    return (Success);
1117692f60a7Smrg}
1118692f60a7Smrg
1119692f60a7Smrgstatic int
1120692f60a7SmrgNEOStopSurface(XF86SurfacePtr surface)
1121692f60a7Smrg{
1122692f60a7Smrg    NEOOffscreenPtr pPriv = (NEOOffscreenPtr)surface->devPrivate.ptr;
1123692f60a7Smrg
1124692f60a7Smrg#ifdef DEBUG
1125692f60a7Smrg    xf86DrvMsg(surface->pScrn->scrnIndex,X_INFO,"NEOStopSurface\n");
1126692f60a7Smrg#endif
1127692f60a7Smrg    if (pPriv->isOn){
1128692f60a7Smrg	NEOPtr nPtr = NEOPTR(surface->pScrn);
1129692f60a7Smrg	VGA_HWP(surface->pScrn);
1130692f60a7Smrg	OUTGR(0xb0, 0x02);
1131692f60a7Smrg	pPriv->isOn = FALSE;
1132692f60a7Smrg    }
1133692f60a7Smrg    return (Success);
1134692f60a7Smrg}
1135692f60a7Smrg
1136692f60a7Smrgstatic int
1137692f60a7SmrgNEOGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 *value)
1138692f60a7Smrg{
1139692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1140692f60a7Smrg
1141692f60a7Smrg#ifdef DEBUG
1142692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOGetSurfaceAttribute\n");
1143692f60a7Smrg#endif
1144692f60a7Smrg    return (NEOGetPortAttribute(pScrn,
1145692f60a7Smrg            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1146692f60a7Smrg}
1147692f60a7Smrg
1148692f60a7Smrgstatic int
1149692f60a7SmrgNEOSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attr, INT32 value)
1150692f60a7Smrg{
1151692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1152692f60a7Smrg
1153692f60a7Smrg#ifdef DEBUG
1154692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"NEOSetSurfaceAttribute\n");
1155692f60a7Smrg#endif
1156692f60a7Smrg    return (NEOSetPortAttribute(pScrn,
1157692f60a7Smrg            attr, value, (pointer)nPtr->overlayAdaptor->pPortPrivates[0].ptr));
1158692f60a7Smrg}
1159