savage_video.c revision 8697ee19
1/*
2 * Copyright (C) 1994-2000 The XFree86 Project, Inc.  All Rights Reserved.
3 * Copyright (c) 2003-2006, X.Org Foundation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 * COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Except as contained in this notice, the name of the copyright holder(s)
24 * and author(s) shall not be used in advertising or otherwise to promote
25 * the sale, use or other dealings in this Software without prior written
26 * authorization from the copyright holder(s) and author(s).
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <X11/extensions/Xv.h>
34#include "dix.h"
35#include "dixstruct.h"
36#include "fourcc.h"
37
38#include "savage_driver.h"
39#include "savage_streams.h"
40#include "savage_regs.h"
41#include "savage_bci.h"
42
43#define OFF_DELAY 	200  /* milliseconds */
44#define FREE_DELAY 	60000
45
46#define OFF_TIMER 	0x01
47#define FREE_TIMER	0x02
48#define CLIENT_VIDEO_ON	0x04
49
50#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
51
52void savageOUTREG( SavagePtr psav, unsigned long offset, unsigned long value );
53
54static XF86VideoAdaptorPtr SavageSetupImageVideo(ScreenPtr);
55static void SavageInitOffscreenImages(ScreenPtr);
56static void SavageStopVideo(ScrnInfoPtr, pointer, Bool);
57static int SavageSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer);
58static int SavageGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
59static void SavageQueryBestSize(ScrnInfoPtr, Bool,
60	short, short, short, short, unsigned int *, unsigned int *, pointer);
61static int SavagePutImage( ScrnInfoPtr,
62	short, short, short, short, short, short, short, short,
63	int, unsigned char*, short, short, Bool, RegionPtr, pointer,
64	DrawablePtr);
65static int SavageQueryImageAttributes(ScrnInfoPtr,
66	int, unsigned short *, unsigned short *,  int *, int *);
67static void SavageFreeMemory(ScrnInfoPtr pScrn, void *mem_struct);
68
69void SavageResetVideo(ScrnInfoPtr pScrn);
70
71static void SavageSetColorKeyOld(ScrnInfoPtr pScrn);
72static void SavageSetColorKeyNew(ScrnInfoPtr pScrn);
73static void SavageSetColorKey2000(ScrnInfoPtr pScrn);
74static void (*SavageSetColorKey)(ScrnInfoPtr pScrn) = NULL;
75
76static void SavageSetColorOld(ScrnInfoPtr pScrn );
77static void SavageSetColorNew(ScrnInfoPtr pScrn );
78static void SavageSetColor2000(ScrnInfoPtr pScrn );
79static void (*SavageSetColor)(ScrnInfoPtr pScrn ) = NULL;
80
81static void (*SavageInitStreams)(ScrnInfoPtr pScrn) = NULL;
82
83static void SavageDisplayVideoOld(
84    ScrnInfoPtr pScrn, int id, int offset,
85    short width, short height, int pitch,
86    int x1, int y1, int x2, int y2,
87    BoxPtr dstBox,
88    short src_w, short src_h,
89    short drw_w, short drw_h
90);
91static void SavageDisplayVideoNew(
92    ScrnInfoPtr pScrn, int id, int offset,
93    short width, short height, int pitch,
94    int x1, int y1, int x2, int y2,
95    BoxPtr dstBox,
96    short src_w, short src_h,
97    short drw_w, short drw_h
98);
99static void SavageDisplayVideo2000(
100    ScrnInfoPtr pScrn, int id, int offset,
101    short width, short height, int pitch,
102    int x1, int y1, int x2, int y2,
103    BoxPtr dstBox,
104    short src_w, short src_h,
105    short drw_w, short drw_h
106);
107static void (*SavageDisplayVideo)(
108    ScrnInfoPtr pScrn, int id, int offset,
109    short width, short height, int pitch,
110    int x1, int y1, int x2, int y2,
111    BoxPtr dstBox,
112    short src_w, short src_h,
113    short drw_w, short drw_h
114) = NULL;
115
116/*static void SavageBlockHandler(int, pointer, pointer, pointer);*/
117
118#define XVTRACE	4
119
120#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
121
122static Atom xvColorKey, xvBrightness, xvContrast, xvSaturation, xvHue, xvInterpolation;
123
124/* client libraries expect an encoding */
125static XF86VideoEncodingRec DummyEncoding[1] =
126{
127 {
128   0,
129   "XV_IMAGE",
130   1024, 1024,
131   {1, 1}
132 }
133};
134
135#define NUM_FORMATS 5
136
137static XF86VideoFormatRec Formats[NUM_FORMATS] =
138{
139  {8, PseudoColor},  {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
140};
141
142#define NUM_ATTRIBUTES 6
143
144static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
145{
146   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
147   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
148   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
149   {XvSettable | XvGettable, 0, 255, "XV_SATURATION"},
150   {XvSettable | XvGettable, -180, 180, "XV_HUE"},
151   {XvSettable | XvGettable, 0, 1, "XV_VERTICAL_INTERPOLATION"}
152};
153
154#define FOURCC_RV16	0x36315652
155#define FOURCC_RV15	0x35315652
156#define FOURCC_Y211	0x31313259
157
158/*
159 * For completeness sake, here is a cracking of the fourcc's I support.
160 *
161 * YUY2, packed 4:2:2, byte order: Y0 U0 Y1 V0  Y2 U2 Y3 V2
162 * Y211, packed 2:1:1, byte order: Y0 U0 Y2 V0  Y4 U2 Y6 V2
163 * YV12, planar 4:1:1, Y plane HxW, V plane H/2xW/2, U plane H/2xW/2
164 * I420, planar 4:1:1, Y plane HxW, U plane H/2xW/2, V plane H/2xW/2
165 * (I420 is also known as IYUV)
166 */
167
168
169static XF86ImageRec Images[] =
170{
171   XVIMAGE_YUY2,
172   XVIMAGE_YV12,
173   XVIMAGE_I420,
174   {
175	FOURCC_RV15,
176        XvRGB,
177	LSBFirst,
178	{'R','V','1','5',
179	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
180	16,
181	XvPacked,
182	1,
183	15, 0x001F, 0x03E0, 0x7C00,
184	0, 0, 0,
185	0, 0, 0,
186	0, 0, 0,
187	{'R','V','B',0,
188	  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},
189	XvTopToBottom
190   },
191   {
192	FOURCC_RV16,
193        XvRGB,
194	LSBFirst,
195	{'R','V','1','6',
196	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
197	16,
198	XvPacked,
199	1,
200	16, 0x001F, 0x07E0, 0xF800,
201	0, 0, 0,
202	0, 0, 0,
203	0, 0, 0,
204	{'R','V','B',0,
205	  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},
206	XvTopToBottom
207   },
208   {
209	FOURCC_Y211,
210	XvYUV,
211	LSBFirst,
212	{'Y','2','1','1',
213	  0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71},
214	6,
215	XvPacked,
216	3,
217	0, 0, 0, 0 ,
218	8, 8, 8,
219	2, 4, 4,
220	1, 1, 1,
221	{'Y','U','Y','V',
222	  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},
223	XvTopToBottom
224   }
225};
226
227#define NUM_IMAGES (sizeof(Images)/sizeof(Images[0]))
228
229typedef struct {
230   int		brightness;	/* -128 .. 127 */
231   CARD32	contrast;	/* 0 .. 255 */
232   CARD32	saturation;	/* 0 .. 255 */
233   int		hue;		/* -128 .. 127 */
234   Bool		interpolation; /* on/off */
235
236   /*FBAreaPtr	area;*/
237   RegionRec	clip;
238   CARD32	colorKey;
239   CARD32	videoStatus;
240   Time		offTime;
241   Time		freeTime;
242   int		lastKnownPitch;
243
244   int          size;
245   void         *video_memory;
246   int          video_offset;
247
248} SavagePortPrivRec, *SavagePortPrivPtr;
249
250
251#define GET_PORT_PRIVATE(pScrn) \
252   (SavagePortPrivPtr)((SAVPTR(pScrn))->adaptor->pPortPrivates[0].ptr)
253
254static
255unsigned int GetBlendForFourCC( int id )
256{
257    switch( id ) {
258	case FOURCC_YUY2:
259        case FOURCC_YV12: /* shouldn't this be 4? */
260        case FOURCC_I420: /* shouldn't this be 4? */
261	    return 1;
262	case FOURCC_Y211:
263	    return 4;
264	case FOURCC_RV15:
265	    return 3;
266	case FOURCC_RV16:
267	    return 5;
268        default:
269	    return 0;
270    }
271}
272
273static
274unsigned int GetBlendForFourCC2000( int id )
275{
276  switch( id ) {
277  case FOURCC_YUY2:
278    return 1;
279  case FOURCC_I420:
280    return 1; /* was 4 */
281  case FOURCC_YV12:
282    return 1; /* was 4 */
283  case FOURCC_Y211:
284    return 4;
285  case FOURCC_RV15:
286    return 3;
287  case FOURCC_RV16:
288    return 5;
289  default:
290    return 0;
291  }
292}
293
294
295void savageOUTREG( SavagePtr psav, unsigned long offset, unsigned long value )
296{
297    ErrorF( "MMIO %08lx, was %08lx, want %08lx,",
298	offset, (CARD32)MMIO_IN32( psav->MapBase, offset ), value );
299    MMIO_OUT32( psav->MapBase, offset, value );
300    ErrorF( " now %08lx\n", (CARD32)MMIO_IN32( psav->MapBase, offset ) );
301}
302
303#if 0
304static void
305SavageClipVWindow(ScrnInfoPtr pScrn)
306{
307    SavagePtr psav = SAVPTR(pScrn);
308
309    if( (psav->Chipset == S3_SAVAGE_MX)  ||
310	(psav->Chipset == S3_SUPERSAVAGE) ) {
311	if (psav->IsSecondary) {
312	    OUTREG(SEC_STREAM2_WINDOW_SZ, 0);
313	} else if (psav->IsPrimary) {
314	    OUTREG(SEC_STREAM_WINDOW_SZ, 0);
315	} else {
316	    OUTREG(SEC_STREAM_WINDOW_SZ, 0);
317#if 0
318	    OUTREG(SEC_STREAM2_WINDOW_SZ, 0);
319#endif
320  	}
321    } else if (psav->Chipset == S3_SAVAGE2000) {
322        OUTREG(SEC_STREAM_WINDOW_SZ, 0);
323    } else {
324	OUTREG( SSTREAM_WINDOW_SIZE_REG, 1);
325	OUTREG( SSTREAM_WINDOW_START_REG, 0x03ff03ff);
326    }
327}
328#endif
329
330void SavageInitVideo(ScreenPtr pScreen)
331{
332    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
333    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
334    XF86VideoAdaptorPtr newAdaptor = NULL;
335    SavagePtr psav = SAVPTR(pScrn);
336    int num_adaptors;
337
338    xf86ErrorFVerb(XVTRACE,"SavageInitVideo\n");
339    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset))
340    {
341	newAdaptor = SavageSetupImageVideo(pScreen);
342	SavageInitOffscreenImages(pScreen);
343
344	SavageInitStreams = SavageInitStreamsNew;
345	SavageSetColor = SavageSetColorNew;
346	SavageSetColorKey = SavageSetColorKeyNew;
347	SavageDisplayVideo = SavageDisplayVideoNew;
348    }
349    else if (psav->Chipset == S3_SAVAGE2000)
350    {
351        newAdaptor = SavageSetupImageVideo(pScreen);
352        SavageInitOffscreenImages(pScreen);
353
354	SavageInitStreams = SavageInitStreams2000;
355        SavageSetColor = SavageSetColor2000;
356        SavageSetColorKey = SavageSetColorKey2000;
357        SavageDisplayVideo = SavageDisplayVideo2000;
358    }
359    else
360    {
361	newAdaptor = SavageSetupImageVideo(pScreen);
362	SavageInitOffscreenImages(pScreen);
363
364	SavageInitStreams = SavageInitStreamsOld;
365	SavageSetColor = SavageSetColorOld;
366	SavageSetColorKey = SavageSetColorKeyOld;
367	SavageDisplayVideo = SavageDisplayVideoOld;
368    }
369
370    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
371
372    if(newAdaptor) {
373        if(!num_adaptors) {
374            num_adaptors = 1;
375            adaptors = &newAdaptor;
376        } else {
377            newAdaptors =  /* need to free this someplace */
378        	xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
379            if(newAdaptors) {
380        	memcpy(newAdaptors, adaptors, num_adaptors *
381        				sizeof(XF86VideoAdaptorPtr));
382        	newAdaptors[num_adaptors] = newAdaptor;
383        	adaptors = newAdaptors;
384        	num_adaptors++;
385            }
386        }
387    }
388
389    if(num_adaptors)
390        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
391
392    if(newAdaptors)
393	xfree(newAdaptors);
394
395    if( newAdaptor )
396    {
397	psav->videoFourCC = 0;
398    }
399}
400
401
402void SavageSetColorKeyOld(ScrnInfoPtr pScrn)
403{
404    SavagePtr psav = SAVPTR(pScrn);
405    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
406    int red, green, blue;
407
408    /* Here, we reset the colorkey and all the controls. */
409
410    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
411    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
412    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
413
414    if( !pPriv->colorKey ) {
415	OUTREG( COL_CHROMA_KEY_CONTROL_REG, 0 );
416	OUTREG( CHROMA_KEY_UPPER_BOUND_REG, 0 );
417	OUTREG( BLEND_CONTROL_REG, 0 );
418    }
419    else {
420	switch (pScrn->depth) {
421	case 8:
422	    OUTREG( COL_CHROMA_KEY_CONTROL_REG,
423		0x37000000 | (pPriv->colorKey & 0xFF) );
424	    OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
425		0x00000000 | (pPriv->colorKey & 0xFF) );
426	    break;
427	case 15:
428	    OUTREG( COL_CHROMA_KEY_CONTROL_REG,
429		0x05000000 | (red<<19) | (green<<11) | (blue<<3) );
430	    OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
431		0x00000000 | (red<<19) | (green<<11) | (blue<<3) );
432	    break;
433	case 16:
434	    OUTREG( COL_CHROMA_KEY_CONTROL_REG,
435		0x16000000 | (red<<19) | (green<<10) | (blue<<3) );
436	    OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
437		0x00020002 | (red<<19) | (green<<10) | (blue<<3) );
438	    break;
439	case 24:
440	    OUTREG( COL_CHROMA_KEY_CONTROL_REG,
441		0x17000000 | (red<<16) | (green<<8) | (blue) );
442	    OUTREG( CHROMA_KEY_UPPER_BOUND_REG,
443		0x00000000 | (red<<16) | (green<<8) | (blue) );
444	    break;
445	}
446
447	/* We use destination colorkey */
448	OUTREG( BLEND_CONTROL_REG, 0x05000000 );
449    }
450}
451
452void SavageSetColorKeyNew(ScrnInfoPtr pScrn)
453{
454    SavagePtr psav = SAVPTR(pScrn);
455    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
456    int red, green, blue;
457
458    /* Here, we reset the colorkey and all the controls. */
459
460    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
461    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
462    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
463
464    if( !pPriv->colorKey ) {
465	if (psav->IsSecondary) {
466	    OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
467	    OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
468	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
469	} else if (psav->IsPrimary) {
470	    OUTREG( SEC_STREAM_CKEY_LOW, 0 );
471	    OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
472	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
473	} else {
474	    OUTREG( SEC_STREAM_CKEY_LOW, 0 );
475	    OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
476	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
477#if 0
478	    sleep(1);
479	    OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
480	    OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
481	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
482#endif
483	}
484    }
485    else {
486	switch (pScrn->depth) {
487	case 8:
488	    if (psav->IsSecondary) {
489	    	OUTREG( SEC_STREAM2_CKEY_LOW,
490		    0x47000000 | (pPriv->colorKey & 0xFF) );
491	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
492		    0x47000000 | (pPriv->colorKey & 0xFF) );
493	    } else if (psav->IsPrimary) {
494	    	OUTREG( SEC_STREAM_CKEY_LOW,
495		    0x47000000 | (pPriv->colorKey & 0xFF) );
496	    	OUTREG( SEC_STREAM_CKEY_UPPER,
497		    0x47000000 | (pPriv->colorKey & 0xFF) );
498	    } else {
499	    	OUTREG( SEC_STREAM_CKEY_LOW,
500		    0x47000000 | (pPriv->colorKey & 0xFF) );
501	    	OUTREG( SEC_STREAM_CKEY_UPPER,
502		    0x47000000 | (pPriv->colorKey & 0xFF) );
503#if 0
504	    	OUTREG( SEC_STREAM2_CKEY_LOW,
505		    0x47000000 | (pPriv->colorKey & 0xFF) );
506	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
507		    0x47000000 | (pPriv->colorKey & 0xFF) );
508#endif
509	    }
510	    break;
511	case 15:
512	    if (psav->IsSecondary) {
513	    	OUTREG( SEC_STREAM2_CKEY_LOW,
514		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
515	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
516		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
517	    } else if (psav->IsPrimary) {
518	    	OUTREG( SEC_STREAM_CKEY_LOW,
519		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
520	    	OUTREG( SEC_STREAM_CKEY_UPPER,
521		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
522	    } else {
523	    	OUTREG( SEC_STREAM_CKEY_LOW,
524		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
525	    	OUTREG( SEC_STREAM_CKEY_UPPER,
526		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
527#if 0
528	    	OUTREG( SEC_STREAM2_CKEY_LOW,
529		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
530	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
531		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
532#endif
533	    }
534	    break;
535	case 16:
536	    if (psav->IsSecondary) {
537	    	OUTREG( SEC_STREAM2_CKEY_LOW,
538		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
539	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
540		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
541	    } else if (psav->IsPrimary) {
542	    	OUTREG( SEC_STREAM_CKEY_LOW,
543		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
544	    	OUTREG( SEC_STREAM_CKEY_UPPER,
545		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
546	    } else {
547	    	OUTREG( SEC_STREAM_CKEY_LOW,
548		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
549	    	OUTREG( SEC_STREAM_CKEY_UPPER,
550		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
551#if 0
552	    	OUTREG( SEC_STREAM2_CKEY_LOW,
553		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
554	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
555		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
556#endif
557	    }
558	    break;
559	case 24:
560	    if (psav->IsSecondary) {
561	        OUTREG( SEC_STREAM2_CKEY_LOW,
562		    0x47000000 | (red<<16) | (green<<8) | (blue) );
563	        OUTREG( SEC_STREAM2_CKEY_UPPER,
564		    0x47000000 | (red<<16) | (green<<8) | (blue) );
565	    } else if (psav->IsPrimary) {
566	        OUTREG( SEC_STREAM_CKEY_LOW,
567		    0x47000000 | (red<<16) | (green<<8) | (blue) );
568	        OUTREG( SEC_STREAM_CKEY_UPPER,
569		    0x47000000 | (red<<16) | (green<<8) | (blue) );
570	    } else {
571	        OUTREG( SEC_STREAM_CKEY_LOW,
572		    0x47000000 | (red<<16) | (green<<8) | (blue) );
573	        OUTREG( SEC_STREAM_CKEY_UPPER,
574		    0x47000000 | (red<<16) | (green<<8) | (blue) );
575#if 0
576	        OUTREG( SEC_STREAM2_CKEY_LOW,
577		    0x47000000 | (red<<16) | (green<<8) | (blue) );
578	        OUTREG( SEC_STREAM2_CKEY_UPPER,
579		    0x47000000 | (red<<16) | (green<<8) | (blue) );
580#endif
581	    }
582	    break;
583	}
584
585	/* We assume destination colorkey */
586	if (psav->IsSecondary) {
587	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
588	} else if (psav->IsPrimary) {
589	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
590	} else {
591	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
592#if 0
593	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
594#endif
595	}
596    }
597}
598
599void SavageSetColorKey2000(ScrnInfoPtr pScrn)
600{
601    SavagePtr psav = SAVPTR(pScrn);
602    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
603    int red, green, blue;
604
605    /* Here, we reset the colorkey and all the controls. */
606
607    red = (pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red;
608    green = (pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green;
609    blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
610
611    if( !pPriv->colorKey ) {
612        OUTREG( SEC_STREAM_CKEY_LOW, 0);
613	OUTREG( SEC_STREAM_CKEY_UPPER, 0);
614        OUTREG( BLEND_CONTROL, (8 << 2));
615    }
616    else {
617	switch (pScrn->depth) {
618	case 8:
619	    OUTREG( SEC_STREAM_CKEY_LOW,
620		0x47000000 | (pPriv->colorKey & 0xFF) );
621	    OUTREG( SEC_STREAM_CKEY_UPPER,
622		  (pPriv->colorKey & 0xFF) );
623	    break;
624	case 15:
625	    OUTREG( SEC_STREAM_CKEY_LOW,
626		0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
627	    OUTREG( SEC_STREAM_CKEY_UPPER,
628		  (red<<19) | (green<<11) | (blue<<3) );
629	    break;
630	case 16:
631	    OUTREG( SEC_STREAM_CKEY_LOW,
632		0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
633	    OUTREG( SEC_STREAM_CKEY_UPPER,
634		  (red<<19) | (green<<10) | (blue<<3) );
635	    break;
636	case 24:
637	    OUTREG( SEC_STREAM_CKEY_LOW,
638		0x47000000 | (red<<16) | (green<<8) | (blue) );
639	    OUTREG( SEC_STREAM_CKEY_UPPER,
640		  (red<<16) | (green<<8) | (blue) );
641	    break;
642	}
643
644	/* We assume destination colorkey */
645	OUTREG( BLEND_CONTROL, INREG(BLEND_CONTROL) | (8 << 2));
646    }
647}
648
649void SavageSetColorOld( ScrnInfoPtr pScrn )
650{
651    SavagePtr psav = SAVPTR(pScrn);
652    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
653
654    xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
655	pPriv->brightness, (int)pPriv->contrast, (int)pPriv->saturation, pPriv->hue );
656
657    if(
658	(psav->videoFourCC == FOURCC_RV15) ||
659	(psav->videoFourCC == FOURCC_RV16)
660    )
661    {
662	OUTREG( COLOR_ADJUSTMENT_REG, 0 );
663    }
664    else
665    {
666        /* Change 0..255 into 0..15 */
667	long sat = pPriv->saturation * 16 / 256;
668	double hue = pPriv->hue * 0.017453292;
669	unsigned long hs1 = ((long)(sat * cos(hue))) & 0x1f;
670	unsigned long hs2 = ((long)(sat * sin(hue))) & 0x1f;
671
672	OUTREG( COLOR_ADJUSTMENT_REG,
673	    0x80008000 |
674	    (pPriv->brightness + 128) |
675	    ((pPriv->contrast & 0xf8) << (12-7)) |
676	    (hs1 << 16) |
677	    (hs2 << 24)
678	);
679
680    }
681}
682
683void SavageSetColorNew( ScrnInfoPtr pScrn )
684{
685    SavagePtr psav = SAVPTR(pScrn);
686    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
687
688    /* Brightness/contrast/saturation/hue computations. */
689
690    double k, dk1, dk2, dk3, dk4, dk5, dk6, dk7, dkb;
691    int k1, k2, k3, k4, k5, k6, k7, kb;
692    double s = pPriv->saturation / 128.0;
693    double h = pPriv->hue * 0.017453292;
694    unsigned long assembly1, assembly2, assembly3;
695
696    xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
697	pPriv->brightness, (int)pPriv->contrast, (int)pPriv->saturation, pPriv->hue );
698
699    if( psav->videoFourCC == FOURCC_Y211 )
700	k = 1.0;	/* YUV */
701    else
702	k = 1.14;	/* YCrCb */
703
704    /*
705     * The S3 documentation must be wrong for k4 and k5.  Their default
706     * values, which they hardcode in their Windows driver, have the
707     * opposite sign from the results in the register spec.
708     */
709
710    dk1 = k * pPriv->contrast;
711    dk2 = 64.0 * 1.371 * k * s * cos(h);
712    dk3 = -64.0 * 1.371 * k * s * sin(h);
713    dk4 = -128.0 * k * s * (0.698 * cos(h) - 0.336 * sin(h));
714    dk5 = -128.0 * k * s * (0.698 * sin(h) + 0.336 * cos(h));
715    dk6 = 64.0 * 1.732 * k * s * sin(h);	/* == k3 / 1.26331, right? */
716    dk7 = 64.0 * 1.732 * k * s * cos(h);	/* == k2 / -1.26331, right? */
717    dkb = 128.0 * pPriv->brightness + 64.0;
718    if( psav->videoFourCC != FOURCC_Y211 )
719	dkb -= dk1 * 14.0;
720
721    k1 = (int)(dk1+0.5) & 0x1ff;
722    k2 = (int)(dk2+0.5) & 0x1ff;
723    k3 = (int)(dk3+0.5) & 0x1ff;
724    assembly1 = (k3<<18) | (k2<<9) | k1;
725    xf86ErrorFVerb(XVTRACE+1, "CC1 = %08lx  ", assembly1 );
726
727    k4 = (int)(dk4+0.5) & 0x1ff;
728    k5 = (int)(dk5+0.5) & 0x1ff;
729    k6 = (int)(dk6+0.5) & 0x1ff;
730    assembly2 = (k6<<18) | (k5<<9) | k4;
731    xf86ErrorFVerb(XVTRACE+1, "CC2 = %08lx  ", assembly2 );
732
733    k7 = (int)(dk7+0.5) & 0x1ff;
734    kb = (int)(dkb+0.5) & 0xffff;
735    assembly3 = (kb<<9) | k7;
736    xf86ErrorFVerb(XVTRACE+1, "CC3 = %08lx\n", assembly3 );
737
738    if (psav->IsSecondary) {
739	OUTREG( SEC_STREAM2_COLOR_CONVERT1, assembly1 );
740	OUTREG( SEC_STREAM2_COLOR_CONVERT2, assembly2 );
741	OUTREG( SEC_STREAM2_COLOR_CONVERT3, assembly3 );
742    } else if (psav->IsPrimary) {
743	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly1 );
744	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly2 );
745	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly3 );
746    } else {
747	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly1 );
748	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly2 );
749	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly3 );
750#if 0
751	sleep(1);
752	OUTREG( SEC_STREAM2_COLOR_CONVERT1, assembly1 );
753	OUTREG( SEC_STREAM2_COLOR_CONVERT2, assembly2 );
754	OUTREG( SEC_STREAM2_COLOR_CONVERT3, assembly3 );
755#endif
756    }
757}
758
759void SavageSetColor2000( ScrnInfoPtr pScrn )
760{
761    SavagePtr psav = SAVPTR(pScrn);
762    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
763
764    /* Brightness/contrast/saturation/hue computations. */
765
766    double k, yb, dk1, dk2, dk3, dk4, dk5, dk6, dk7, dkb;
767    int k1, k2, k3, k4, k5, k6, k7, kb;
768    double s = pPriv->saturation / 10000.0;
769    double h = pPriv->hue * 0.017453292;
770    unsigned long assembly1, assembly2, assembly3, assembly4;
771    unsigned long brightness = pPriv->brightness;
772
773    xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
774		 pPriv->brightness, (int)pPriv->contrast, (int)pPriv->saturation, pPriv->hue );
775
776    if( psav->videoFourCC == FOURCC_Y211 ) {
777      k = 1.0;/* YUV */
778      yb = 0.0;
779    } else {
780      k = 1.1;/* YCrCb */
781      yb = 14.0;
782    }
783
784    dk1 = 128 * k * (pPriv->contrast / 10000.0);
785    if (dk1 < 0)
786      dk1 -= 0.5;
787    else
788      dk1 += 0.5;
789    dk2 = 64.0 * 1.371 * k * s * cos(h);
790    if (dk2 < 0)
791      dk2 -= 0.5;
792    else
793      dk2 += 0.5;
794    dk3 = -64.0 * 1.371 * k * s * sin(h);
795    if (dk3 < 0)
796      dk3 -= 0.5;
797    else
798      dk3 += 0.5;
799    dk4 = -128.0 * k * s * (0.698 * cos(h) + 0.336 * sin(h));
800    if (dk4 < 0)
801      dk4 -= 0.5;
802    else
803      dk4 += 0.5;
804    dk5 = 128.0 * k * s * (0.698 * sin(h) - 0.336 * cos(h));
805    if (dk5 < 0)
806      dk5 -= 0.5;
807    else
808      dk5 += 0.5;
809    dk6 = 64.0 * 1.732 * k * s * sin(h);
810    if (dk6 < 0)
811      dk6 -= 0.5;
812    else
813      dk6 += 0.5;
814    dk7 = 64.0 * 1.732 * k * s * cos(h);
815    if (dk7 < 0)
816      dk7 -= 0.5;
817    else
818      dk7 += 0.5;
819
820    if (pPriv->brightness <= 0)
821        brightness = pPriv->brightness * 200 / 750 - 200;
822    else
823        brightness = (pPriv->brightness - 750) * 200 / (10000 - 750);
824    dkb = 128 * (brightness - (k * pPriv->contrast * yb / 10000.0) + 0.5);
825    if (dkb < 0)
826      dkb -= 0.5;
827    else
828      dkb += 0.5;
829
830    k1 = (int)(dk1 /*+0.5*/) & 0x1ff;
831    k2 = (int)(dk2 /*+0.5*/) & 0x1ff;
832    assembly1 = (k2<<16) | k1;
833
834    k3 = (int)(dk3 /*+0.5*/) & 0x1ff;
835    k4 = (int)(dk4 /*+0.5*/) & 0x1ff;
836    assembly2 = (k4<<16) | k3;
837
838    k5 = (int)(dk5 /*+0.5*/) & 0x1ff;
839    k6 = (int)(dk6 /*+0.5*/) & 0x1ff;
840    assembly3 = (k6<<16) | k5;
841
842    k7 = (int)(dk7 /*+0.5*/) & 0x1ff;
843    kb = (int)(dkb /*+0.5*/) & 0xffff;
844    assembly4 = (kb<<16) | k7;
845
846#if 0
847    assembly1 = 0x640092;
848    assembly2 = 0x19a0000;
849    assembly3 = 0x001cf;
850    assembly4 = 0xf8ca007e;
851#endif
852
853    OUTREG( SEC_STREAM_COLOR_CONVERT0_2000, assembly1 );
854    OUTREG( SEC_STREAM_COLOR_CONVERT1_2000, assembly2 );
855    OUTREG( SEC_STREAM_COLOR_CONVERT2_2000, assembly3 );
856    OUTREG( SEC_STREAM_COLOR_CONVERT3_2000, assembly4 );
857
858}
859
860void SavageResetVideo(ScrnInfoPtr pScrn)
861{
862    xf86ErrorFVerb(XVTRACE,"SavageResetVideo\n");
863    SavageSetColor( pScrn );
864    SavageSetColorKey( pScrn );
865}
866
867
868static XF86VideoAdaptorPtr
869SavageSetupImageVideo(ScreenPtr pScreen)
870{
871    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
872    SavagePtr psav = SAVPTR(pScrn);
873    XF86VideoAdaptorPtr adapt;
874    SavagePortPrivPtr pPriv;
875
876    xf86ErrorFVerb(XVTRACE,"SavageSetupImageVideo\n");
877
878    if(!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
879			    sizeof(SavagePortPrivRec) +
880			    sizeof(DevUnion))))
881	return NULL;
882
883    adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
884    adapt->flags	= VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
885    adapt->name			= "Savage Streams Engine";
886    adapt->nEncodings 		= 1;
887    adapt->pEncodings 		= DummyEncoding;
888    adapt->nFormats 		= NUM_FORMATS;
889    adapt->pFormats 		= Formats;
890    adapt->nPorts 		= 1;
891    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
892    pPriv = (SavagePortPrivPtr)(&adapt->pPortPrivates[1]);
893    adapt->pPortPrivates[0].ptr	= (pointer)(pPriv);
894    adapt->pAttributes		= Attributes;
895    adapt->nImages		= NUM_IMAGES;
896    adapt->nAttributes		= NUM_ATTRIBUTES;
897    adapt->pImages		= Images;
898    adapt->PutVideo		= NULL;
899    adapt->PutStill		= NULL;
900    adapt->GetVideo		= NULL;
901    adapt->GetStill		= NULL;
902    adapt->StopVideo		= SavageStopVideo;
903    adapt->SetPortAttribute	= SavageSetPortAttribute;
904    adapt->GetPortAttribute	= SavageGetPortAttribute;
905    adapt->QueryBestSize	= SavageQueryBestSize;
906    adapt->PutImage		= SavagePutImage;
907    adapt->QueryImageAttributes	= SavageQueryImageAttributes;
908
909    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
910    xvContrast   = MAKE_ATOM("XV_CONTRAST");
911    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
912    xvHue        = MAKE_ATOM("XV_HUE");
913    xvSaturation = MAKE_ATOM("XV_SATURATION");
914    /* interpolation option only available on "old" streams */
915    xvInterpolation = MAKE_ATOM("XV_VERTICAL_INTERPOLATION");
916
917    pPriv->colorKey =
918      (1 << pScrn->offset.red) |
919      (1 << pScrn->offset.green) |
920      (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
921    pPriv->videoStatus = 0;
922    pPriv->brightness = 0;
923    pPriv->contrast = 128;
924    pPriv->saturation = 128;
925#if 0
926    /*
927     * The S3 driver has these values for some of the chips.  I have yet
928     * to find any Savage where these make sense.
929     */
930    pPriv->brightness = 64;
931    pPriv->contrast = 16;
932    pPriv->saturation = 128;
933#endif
934    pPriv->hue = 0;
935    pPriv->lastKnownPitch = 0;
936
937    pPriv->interpolation = FALSE;
938
939    /* gotta uninit this someplace */
940    REGION_NULL(pScreen, &pPriv->clip);
941
942    psav->adaptor = adapt;
943
944    #if 0
945    psav->BlockHandler = pScreen->BlockHandler;
946    pScreen->BlockHandler = SavageBlockHandler;
947    #endif
948
949    return adapt;
950}
951
952
953/* SavageClipVideo -
954
955   Takes the dst box in standard X BoxRec form (top and left
956   edges inclusive, bottom and right exclusive).  The new dst
957   box is returned.  The source boundaries are given (x1, y1
958   inclusive, x2, y2 exclusive) and returned are the new source
959   boundaries in 16.16 fixed point.
960*/
961
962static void
963SavageClipVideo(
964  BoxPtr dst,
965  INT32 *x1,
966  INT32 *x2,
967  INT32 *y1,
968  INT32 *y2,
969  BoxPtr extents,            /* extents of the clip region */
970  INT32 width,
971  INT32 height
972){
973    INT32 vscale, hscale, delta;
974    int diff;
975
976    hscale = ((*x2 - *x1) << 16) / (dst->x2 - dst->x1);
977    vscale = ((*y2 - *y1) << 16) / (dst->y2 - dst->y1);
978
979    *x1 <<= 16; *x2 <<= 16;
980    *y1 <<= 16; *y2 <<= 16;
981
982    diff = extents->x1 - dst->x1;
983    if(diff > 0) {
984	dst->x1 = extents->x1;
985	*x1 += diff * hscale;
986    }
987    diff = dst->x2 - extents->x2;
988    if(diff > 0) {
989	dst->x2 = extents->x2;
990	*x2 -= diff * hscale;
991    }
992    diff = extents->y1 - dst->y1;
993    if(diff > 0) {
994	dst->y1 = extents->y1;
995	*y1 += diff * vscale;
996    }
997    diff = dst->y2 - extents->y2;
998    if(diff > 0) {
999	dst->y2 = extents->y2;
1000	*y2 -= diff * vscale;
1001    }
1002
1003    if(*x1 < 0) {
1004	diff =  (- *x1 + hscale - 1)/ hscale;
1005	dst->x1 += diff;
1006	*x1 += diff * hscale;
1007    }
1008    delta = *x2 - (width << 16);
1009    if(delta > 0) {
1010	diff = (delta + hscale - 1)/ hscale;
1011	dst->x2 -= diff;
1012	*x2 -= diff * hscale;
1013    }
1014    if(*y1 < 0) {
1015	diff =  (- *y1 + vscale - 1)/ vscale;
1016	dst->y1 += diff;
1017	*y1 += diff * vscale;
1018    }
1019    delta = *y2 - (height << 16);
1020    if(delta > 0) {
1021	diff = (delta + vscale - 1)/ vscale;
1022	dst->y2 -= diff;
1023	*y2 -= diff * vscale;
1024    }
1025}
1026
1027static void
1028SavageStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
1029{
1030    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1031    /*SavagePtr psav = SAVPTR(pScrn); */
1032
1033    xf86ErrorFVerb(XVTRACE,"SavageStopVideo\n");
1034
1035    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1036
1037    if(shutdown) {
1038      /*SavageClipVWindow(pScrn);*/
1039 	SavageStreamsOff( pScrn );
1040        if (pPriv->video_memory != NULL) {
1041	    SavageFreeMemory(pScrn, pPriv->video_memory);
1042	    pPriv->video_memory = NULL;
1043        }
1044	pPriv->videoStatus = 0;
1045    } else {
1046	if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1047	    pPriv->videoStatus |= OFF_TIMER;
1048	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
1049	}
1050    }
1051}
1052
1053
1054static int
1055SavageSetPortAttribute(
1056    ScrnInfoPtr pScrn,
1057    Atom attribute,
1058    INT32 value,
1059    pointer data
1060){
1061    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1062    SavagePtr psav = SAVPTR(pScrn);
1063
1064    if(attribute == xvColorKey) {
1065	pPriv->colorKey = value;
1066	if( psav->videoFlags & VF_STREAMS_ON)
1067	    SavageSetColorKey( pScrn );
1068	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1069    }
1070    else if( attribute == xvBrightness) {
1071	if((value < -128) || (value > 127))
1072	    return BadValue;
1073	pPriv->brightness = value;
1074	if( psav->videoFlags & VF_STREAMS_ON)
1075	    SavageSetColor( pScrn );
1076    }
1077    else if( attribute == xvContrast) {
1078	if((value < 0) || (value > 255))
1079	    return BadValue;
1080	pPriv->contrast = value;
1081	if( psav->videoFlags & VF_STREAMS_ON)
1082	    SavageSetColor( pScrn );
1083    }
1084    else if( attribute == xvSaturation) {
1085	if((value < 0) || (value > 255))
1086	    return BadValue;
1087	pPriv->saturation = value;
1088	if( psav->videoFlags & VF_STREAMS_ON)
1089	    SavageSetColor( pScrn );
1090    }
1091    else if( attribute == xvHue) {
1092	if((value < -180) || (value > 180))
1093	    return BadValue;
1094	pPriv->hue = value;
1095	if( psav->videoFlags & VF_STREAMS_ON)
1096	    SavageSetColor( pScrn );
1097    }
1098    else if( attribute == xvInterpolation) {
1099        if((value < 0) || (value > 1))
1100            return BadValue;
1101        if (value == 1)
1102            pPriv->interpolation = TRUE;
1103	else
1104	    pPriv->interpolation = FALSE;
1105    }
1106    else
1107	return BadMatch;
1108
1109    return Success;
1110}
1111
1112
1113static int
1114SavageGetPortAttribute(
1115  ScrnInfoPtr pScrn,
1116  Atom attribute,
1117  INT32 *value,
1118  pointer data
1119){
1120    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1121
1122    if(attribute == xvColorKey) {
1123	*value = pPriv->colorKey;
1124    }
1125    else if( attribute == xvBrightness ) {
1126	*value = pPriv->brightness;
1127    }
1128    else if( attribute == xvContrast ) {
1129	*value = pPriv->contrast;
1130    }
1131    else if( attribute == xvHue ) {
1132	*value = pPriv->hue;
1133    }
1134    else if( attribute == xvSaturation ) {
1135	*value = pPriv->saturation;
1136    }
1137    else if( attribute == xvInterpolation ) {
1138        *value = pPriv->interpolation;
1139    }
1140    else return BadMatch;
1141
1142    return Success;
1143}
1144
1145static void
1146SavageQueryBestSize(
1147  ScrnInfoPtr pScrn,
1148  Bool motion,
1149  short vid_w, short vid_h,
1150  short drw_w, short drw_h,
1151  unsigned int *p_w, unsigned int *p_h,
1152  pointer data
1153){
1154    /* What are the real limits for the Savage? */
1155
1156    *p_w = drw_w;
1157    *p_h = drw_h;
1158
1159    if(*p_w > 16384) *p_w = 16384;
1160}
1161
1162/* SavageCopyPlanarDataBCI() causes artifacts on the screen when used on savage4.
1163 * It's probably something with the BCI.  Maybe we need a waitforidle() or
1164 * something...
1165 */
1166static void
1167SavageCopyPlanarDataBCI(
1168    ScrnInfoPtr pScrn,
1169    unsigned char *srcY, /* Y */
1170    unsigned char *srcV, /* V */
1171    unsigned char *srcU, /* U */
1172    unsigned char *dst,
1173    int srcPitch, int srcPitch2,
1174    int dstPitch,
1175    int h,int w)
1176{
1177    SavagePtr psav = SAVPTR(pScrn);
1178    /* half of the dest buffer for copying the YVU data to it ??? */
1179    unsigned char *dstCopy = (unsigned char *)(((unsigned long)dst
1180                                                + dstPitch * h
1181                                                + 0x0f) & ~0x0f);
1182    /* for pixel transfer */
1183    unsigned long offsetY = (unsigned long)dstCopy - (unsigned long)psav->FBBase;
1184    unsigned long offsetV = offsetY +  srcPitch * h;
1185    unsigned long offsetU = offsetV +  srcPitch2 * (h>>1);
1186    unsigned long dstOffset  = (unsigned long)dst - (unsigned long)psav->FBBase;
1187    int i;
1188
1189    BCI_GET_PTR;
1190
1191    /* copy Y planar */
1192    memcpy(dstCopy, srcY, srcPitch * h);
1193
1194    /* copy V planar */
1195    dstCopy = dstCopy + srcPitch * h;
1196    memcpy(dstCopy, srcV, srcPitch2 * (h>>1));
1197
1198    /* copy U planar */
1199    dstCopy = dstCopy + srcPitch2 * (h>>1);
1200    memcpy(dstCopy, srcU, srcPitch2 * (h>>1));
1201
1202    /*
1203     * Transfer pixel data from one memory location to another location
1204     * and reformat the data during the transfer
1205     * a. program BCI51 to specify the source information
1206     * b. program BCI52 to specify the destination information
1207     * c. program BCI53 to specify the source dimensions
1208     * d. program BCI54 to specify the destination dimensions
1209     * e. (if the data is in YCbCr420 format)program BCI55,BCI56,BCI57 to
1210     *    locations of the Y,Cb,and Cr data
1211     * f. program BCI50(command=011) to specify the formatting options and
1212     *    kick off the transfer
1213     * this command can be used for color space conversion(YCbCr to RGB)
1214     * or for oversampling, but not for both simultaneously. it can also be
1215     * used to do mastered image transfer when the source is tiled
1216     */
1217
1218    w = (w+0xf)&0xff0;
1219    psav->WaitQueue(psav,11);
1220    BCI_SEND(0x96070051);
1221    BCI_SEND(offsetY);
1222
1223    BCI_SEND(dstOffset);
1224
1225    BCI_SEND(((h-1)<<16)|((w-1)>>3));
1226
1227    BCI_SEND(dstPitch >> 3);
1228
1229
1230    BCI_SEND(offsetU);
1231    BCI_SEND(offsetV);
1232
1233    BCI_SEND((srcPitch2 << 16)| srcPitch2);
1234
1235    BCI_SEND(0x96010050);
1236    BCI_SEND(0x00200003 | srcPitch);
1237    BCI_SEND(0xC0170000);
1238}
1239
1240static void
1241SavageCopyData(
1242  unsigned char *src,
1243  unsigned char *dst,
1244  int srcPitch,
1245  int dstPitch,
1246  int h,
1247  int w
1248){
1249    w <<= 1;
1250    if (w == srcPitch && w == dstPitch) {
1251        memcpy(dst, src, w * h);
1252    } else
1253    while(h--) {
1254	memcpy(dst, src, w);
1255	src += srcPitch;
1256	dst += dstPitch;
1257    }
1258}
1259
1260static void
1261SavageCopyPlanarData(
1262   unsigned char *src1, /* Y */
1263   unsigned char *src2, /* V */
1264   unsigned char *src3, /* U */
1265   unsigned char *dst1,
1266   int srcPitch,
1267   int srcPitch2,
1268   int dstPitch,
1269   int h,
1270   int w
1271){
1272   CARD32 *dst = (CARD32*)dst1;
1273   int i, j;
1274
1275   dstPitch >>= 2;
1276   w >>= 1;
1277
1278   for(j = 0; j < h; j++) {
1279	for(i = 0; i < w; i++) {
1280/* Shouldn't this be 'if LITTLEENDIAN'? */
1281#if 1
1282	    dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
1283		     (src3[i] << 8) | (src2[i] << 24);
1284#else
1285	    dst[i] = (src1[i << 1] << 24) | (src1[(i << 1) + 1] << 8) |
1286		     (src3[i] << 0) | (src2[i] << 16);
1287#endif
1288	}
1289	dst += dstPitch;
1290	src1 += srcPitch;
1291	if(j & 1) {
1292	    src2 += srcPitch2;
1293	    src3 += srcPitch2;
1294	}
1295   }
1296}
1297
1298static void
1299SavageVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
1300{
1301    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1302    SavagePtr psav = SAVPTR(pScrn);
1303    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1304
1305    if (pPriv->video_memory == area)
1306        pPriv->video_memory = NULL;
1307}
1308
1309static CARD32
1310SavageAllocateMemory(
1311    ScrnInfoPtr pScrn,
1312    void **mem_struct,
1313    int size
1314){
1315    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
1316    SavagePtr psav = SAVPTR(pScrn);
1317    int offset = 0;
1318
1319    if (psav->useEXA) {
1320	ExaOffscreenArea *area = *mem_struct;
1321
1322	if (area != NULL) {
1323	    if (area->size >= size)
1324		return area->offset;
1325
1326	    exaOffscreenFree(pScrn->pScreen, area);
1327	}
1328
1329	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, SavageVideoSave,
1330				 NULL);
1331	*mem_struct = area;
1332	if (area == NULL)
1333	    return 0;
1334	offset = area->offset;
1335    }
1336
1337    if (!psav->useEXA) {
1338	FBLinearPtr linear = *mem_struct;
1339	int cpp = pScrn->bitsPerPixel / 8;
1340
1341	/* XAA allocates in units of pixels at the screen bpp, so adjust size
1342	 * appropriately.
1343	 */
1344	size = (size + cpp - 1) / cpp;
1345
1346	if (linear) {
1347	    if(linear->size >= size)
1348		return linear->offset * cpp;
1349
1350	    if(xf86ResizeOffscreenLinear(linear, size))
1351		return linear->offset * cpp;
1352
1353	    xf86FreeOffscreenLinear(linear);
1354	}
1355
1356	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1357						NULL, NULL, NULL);
1358	*mem_struct = linear;
1359
1360	if (!linear) {
1361	    int max_size;
1362
1363	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
1364					    PRIORITY_EXTREME);
1365
1366	    if(max_size < size)
1367		return 0;
1368
1369	    xf86PurgeUnlockedOffscreenAreas(pScreen);
1370	    linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1371						     NULL, NULL, NULL);
1372	    *mem_struct = linear;
1373	    if (!linear)
1374		return 0;
1375	}
1376	offset = linear->offset * cpp;
1377    }
1378
1379    return offset;
1380}
1381
1382static void
1383SavageFreeMemory(
1384   ScrnInfoPtr pScrn,
1385   void *mem_struct
1386){
1387    SavagePtr psav = SAVPTR(pScrn);
1388
1389    if (psav->useEXA) {
1390	ExaOffscreenArea *area = mem_struct;
1391
1392	if (area != NULL)
1393	    exaOffscreenFree(pScrn->pScreen, area);
1394    }
1395    if (!psav->useEXA) {
1396	FBLinearPtr linear = mem_struct;
1397
1398	if (linear != NULL)
1399	    xf86FreeOffscreenLinear(linear);
1400    }
1401}
1402
1403static void
1404SavageSetBlend(ScrnInfoPtr pScrn, int id)
1405{
1406    SavagePtr psav = SAVPTR(pScrn);
1407
1408    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
1409    {
1410	psav->blendBase = GetBlendForFourCC( id );
1411	xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1412	if (psav->IsSecondary) {
1413	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1414	} else if (psav->IsPrimary) {
1415	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1416	} else {
1417	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1418#if 0
1419	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1420#endif
1421	}
1422    } else if (psav->Chipset == S3_SAVAGE2000) {
1423      psav->blendBase = GetBlendForFourCC2000( id );
1424      xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1425      if (id != FOURCC_YV12)
1426	OUTREG( BLEND_CONTROL,
1427		((psav->blendBase << 24) | (8 << 2) /*| 0x20000000*/));
1428      else
1429	OUTREG( BLEND_CONTROL,
1430		((psav->blendBase << 24) | (8 << 2) /*| 0x10000000*/));
1431    }
1432
1433    psav->videoFourCC = id;
1434}
1435
1436static void
1437SavageDisplayVideoOld(
1438    ScrnInfoPtr pScrn,
1439    int id,
1440    int offset,
1441    short width, short height,
1442    int pitch,
1443    int x1, int y1, int x2, int y2,
1444    BoxPtr dstBox,
1445    short src_w, short src_h,
1446    short drw_w, short drw_h
1447){
1448    SavagePtr psav = SAVPTR(pScrn);
1449    vgaHWPtr hwp = VGAHWPTR(pScrn);
1450    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1451    /*DisplayModePtr mode = pScrn->currentMode;*/
1452    int vgaCRIndex, vgaCRReg, vgaIOBase;
1453    CARD32 ssControl;
1454    int scalratio;
1455
1456
1457    vgaIOBase = hwp->IOBase;
1458    vgaCRIndex = vgaIOBase + 4;
1459    vgaCRReg = vgaIOBase + 5;
1460#if 0
1461    if ( psav->videoFourCC != id ) {
1462	SavageSetBlend(pScrn,id);
1463	SavageResetVideo(pScrn);
1464    }
1465#endif
1466    if( psav->videoFourCC != id )
1467      SavageStreamsOff(pScrn);
1468
1469    if( !(psav->videoFlags & VF_STREAMS_ON) )
1470      {
1471        SavageSetBlend(pScrn,id);
1472	SavageStreamsOn(pScrn);
1473	SavageResetVideo(pScrn);
1474	pPriv->lastKnownPitch = 0;
1475      }
1476
1477    if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)
1478        && psav->FPExpansion) {
1479        drw_w = (((float)(drw_w * psav->XExp1)/(float)psav->XExp2)+1);
1480        drw_h = (float)(drw_h * psav->YExp1)/(float)psav->YExp2+1;
1481        dstBox->x1 = (float)(dstBox->x1 * psav->XExp1)/(float)psav->XExp2;
1482        dstBox->y1 = (float)(dstBox->y1 * psav->YExp1)/(float)psav->YExp2;
1483
1484        dstBox->x1 += psav->displayXoffset;
1485        dstBox->y1 += psav->displayYoffset;
1486    }
1487
1488    /*
1489     * Process horizontal scaling
1490     *  upscaling and downscaling smaller than 2:1 controled by MM8198
1491     *  MM8190 controls downscaling mode larger than 2:1
1492     *  Together MM8190 and MM8198 can set arbitrary downscale up to 64:1
1493     */
1494    scalratio = 0;
1495    ssControl = 0;
1496
1497    if (src_w >= (drw_w * 2)) {
1498        if (src_w < (drw_w * 4)) {
1499            ssControl |= HDSCALE_4;
1500            scalratio = HSCALING(src_w,(drw_w*4));
1501        } else if (src_w < (drw_w * 8)) {
1502            ssControl |= HDSCALE_8;
1503            scalratio = HSCALING(src_w,(drw_w*8));
1504        } else if (src_w < (drw_w * 16)) {
1505            ssControl |= HDSCALE_16;
1506            scalratio = HSCALING(src_w,(drw_w*16));
1507        } else if (src_w < (drw_w * 32)) {
1508            ssControl |= HDSCALE_32;
1509            scalratio = HSCALING(src_w,(drw_w*32));
1510        } else if (src_w < (drw_w * 64)) {
1511            ssControl |= HDSCALE_64;
1512            scalratio = HSCALING(src_w,(drw_w*64));
1513        } else {
1514            /* Request beyond maximum downscale! */
1515            ssControl |= HDSCALE_64;
1516            scalratio = HSCALING(2,1);
1517        }
1518    } else
1519        scalratio = HSCALING(src_w,drw_w);
1520
1521    ssControl |= src_w;
1522    /*ssControl |= (1 << 24);*/
1523    ssControl |= (GetBlendForFourCC(psav->videoFourCC) << 24);
1524#if 0
1525    /* Wait for VBLANK. */
1526    VerticalRetraceWait();
1527#endif
1528    OUTREG(SSTREAM_CONTROL_REG, ssControl);
1529    if (scalratio)
1530        OUTREG(SSTREAM_STRETCH_REG,scalratio);
1531
1532    /* Calculate vertical scale factor. */
1533    OUTREG(SSTREAM_VINITIAL_REG, 0 );
1534    /*OUTREG(SSTREAM_VSCALE_REG, (src_h << 15) / drw_h );*/
1535    OUTREG(SSTREAM_VSCALE_REG, VSCALING(src_h,drw_h));
1536
1537    /* Set surface location and stride. */
1538    OUTREG(SSTREAM_FBADDR0_REG, (offset + (x1>>15)) & (0x1ffffff & ~BASE_PAD) );
1539    OUTREG(SSTREAM_FBADDR1_REG, 0);
1540    OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
1541
1542    OUTREG(SSTREAM_WINDOW_START_REG, OS_XY(dstBox->x1, dstBox->y1) );
1543    OUTREG(SSTREAM_WINDOW_SIZE_REG, OS_WH(dstBox->x2-dstBox->x1,
1544                                          dstBox->y2-dstBox->y1));
1545
1546    /*
1547     * MM81E8:Secondary Stream Source Line Count
1548     *   bit_0~10: # of lines in the source image (before scaling)
1549     *   bit_15 = 1: Enable vertical interpolation
1550     *            0: Line duplicaion
1551     */
1552    /*
1553     * Vertical Interpolation is very bandwidth intensive.  Some savages can't
1554     * seem to handle it.  Default is line doubling.  --AGD
1555     */
1556    if (pPriv->interpolation) {
1557        if (src_w * 16 <= 0x3300) {
1558            OUTREG(SSTREAM_LINES_REG, 0x8000 | src_h );
1559	    OUTREG(FIFO_CONTROL, (INREG(FIFO_CONTROL) + 1));
1560        } else {
1561            OUTREG(SSTREAM_LINES_REG, src_h );
1562        }
1563    } else {
1564        OUTREG(SSTREAM_LINES_REG, src_h );
1565    }
1566
1567#if 0
1568    /* Set color key on primary. */
1569
1570    SavageSetColorKey( pScrn );
1571#endif
1572
1573    /* Set FIFO L2 on second stream. */
1574
1575    if( pPriv->lastKnownPitch != pitch )
1576    {
1577	unsigned char cr92;
1578
1579	pPriv->lastKnownPitch = pitch;
1580
1581	pitch = (pitch + 7) / 8;
1582	VGAOUT8(vgaCRIndex, 0x92);
1583	cr92 = VGAIN8(vgaCRReg);
1584	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1585	VGAOUT8(vgaCRIndex, 0x93);
1586	if (psav->bTiled && (( drw_h > src_h) || (drw_w > src_w)))
1587	    VGAOUT8(vgaCRReg, pitch | 0xf);
1588	else
1589	    VGAOUT8(vgaCRReg, pitch);
1590    }
1591}
1592
1593static void
1594SavageDisplayVideoNew(
1595    ScrnInfoPtr pScrn,
1596    int id,
1597    int offset,
1598    short width, short height,
1599    int pitch,
1600    int x1, int y1, int x2, int y2,
1601    BoxPtr dstBox,
1602    short src_w, short src_h,
1603    short drw_w, short drw_h
1604){
1605    SavagePtr psav = SAVPTR(pScrn);
1606    vgaHWPtr hwp = VGAHWPTR(pScrn);
1607    /*DisplayModePtr mode = pScrn->currentMode;*/
1608    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1609    int vgaCRIndex, vgaCRReg, vgaIOBase;
1610
1611
1612    vgaIOBase = hwp->IOBase;
1613    vgaCRIndex = vgaIOBase + 4;
1614    vgaCRReg = vgaIOBase + 5;
1615#if 0
1616    if ( psav->videoFourCC != id ) {
1617	SavageSetBlend(pScrn,id);
1618	SavageResetVideo(pScrn);
1619    }
1620#endif
1621    if( psav->videoFourCC != id )
1622      SavageStreamsOff(pScrn);
1623
1624    if( !(psav->videoFlags & VF_STREAMS_ON) )
1625      {
1626	SavageSetBlend(pScrn,id);
1627	SavageStreamsOn(pScrn);
1628	SavageResetVideo(pScrn);
1629	pPriv->lastKnownPitch = 0;
1630      }
1631
1632    /* Calculate horizontal and vertical scale factors. */
1633
1634    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
1635	    (psav->DisplayType == MT_LCD) &&
1636	    !psav->CrtOnly &&
1637	    !psav->TvOn)
1638    {
1639	drw_w = (drw_w * psav->XExp1)/psav->XExp2 + 1;
1640	drw_h = (drw_h * psav->YExp1)/psav->YExp2 + 1;
1641	dstBox->x1 = (dstBox->x1 * psav->XExp1)/psav->XExp2;
1642	dstBox->y1 = (dstBox->y1 * psav->YExp1)/psav->YExp2;
1643	dstBox->x1 += psav->displayXoffset;
1644	dstBox->y1 += psav->displayYoffset;
1645    }
1646
1647	if (psav->IsSecondary) {
1648	    OUTREG(SEC_STREAM2_HSCALING,
1649	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1650	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1651	    OUTREG(SEC_STREAM2_VSCALING,
1652	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1653	} else if (psav->IsPrimary) {
1654	    OUTREG(SEC_STREAM_HSCALING,
1655	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1656	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1657	    OUTREG(SEC_STREAM_VSCALING,
1658	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1659	} else {
1660	    OUTREG(SEC_STREAM_HSCALING,
1661	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1662	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1663	    OUTREG(SEC_STREAM_VSCALING,
1664	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1665#if 0
1666	    OUTREG(SEC_STREAM2_HSCALING,
1667	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1668	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1669	    OUTREG(SEC_STREAM2_VSCALING,
1670	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1671#endif
1672	}
1673
1674    /*
1675     * Set surface location and stride.  We use x1>>15 because all surfaces
1676     * are 2 bytes/pixel.
1677     */
1678
1679    if (psav->IsSecondary) {
1680        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1681	   & (0x7ffffff & ~BASE_PAD));
1682        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1683        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1684        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1685	   | (dstBox->x2-dstBox->x1) );
1686    } else if (psav->IsPrimary) {
1687        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1688	   & (0x7ffffff & ~BASE_PAD));
1689        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1690        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1691        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1692	   | (dstBox->x2-dstBox->x1) );
1693    } else {
1694        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1695	   & (0x7ffffff & ~BASE_PAD));
1696        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1697        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1698        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1699	   | (dstBox->x2-dstBox->x1) );
1700#if 0
1701        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1702	   & (0x7ffffff & ~BASE_PAD));
1703        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1704        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1705        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1706	   | (dstBox->x2-dstBox->x1) );
1707#endif
1708    }
1709
1710#if 0
1711    /* Set color key on primary. */
1712
1713    SavageSetColorKey( pScrn );
1714#endif
1715
1716    /* Set FIFO L2 on second stream. */
1717    /* Is CR92 shadowed for crtc2? -- AGD */
1718    if( pPriv->lastKnownPitch != pitch )
1719    {
1720	unsigned char cr92;
1721
1722	pPriv->lastKnownPitch = pitch;
1723	pitch = (pitch + 7) / 8 - 4;
1724	VGAOUT8(vgaCRIndex, 0x92);
1725	cr92 = VGAIN8(vgaCRReg);
1726	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1727	VGAOUT8(vgaCRIndex, 0x93);
1728	VGAOUT8(vgaCRReg, pitch);
1729    }
1730}
1731
1732static void
1733SavageDisplayVideo2000(
1734    ScrnInfoPtr pScrn,
1735    int id,
1736    int offset,
1737    short width, short height,
1738    int pitch,
1739    int x1, int y1, int x2, int y2,
1740    BoxPtr dstBox,
1741    short src_w, short src_h,
1742    short drw_w, short drw_h
1743){
1744    SavagePtr psav = SAVPTR(pScrn);
1745    vgaHWPtr hwp = VGAHWPTR(pScrn);
1746    /*DisplayModePtr mode = pScrn->currentMode;*/
1747    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1748    int vgaCRIndex, vgaCRReg, vgaIOBase;
1749    CARD32 addr0, addr1, addr2;
1750
1751    vgaIOBase = hwp->IOBase;
1752    vgaCRIndex = vgaIOBase + 4;
1753    vgaCRReg = vgaIOBase + 5;
1754
1755
1756    if( psav->videoFourCC != id )
1757        SavageStreamsOff(pScrn);
1758
1759    if( !(psav->videoFlags & VF_STREAMS_ON) )
1760    {
1761        SavageSetBlend(pScrn,id);
1762        SavageStreamsOn(pScrn);
1763        SavageResetVideo(pScrn);
1764        pPriv->lastKnownPitch = 0;
1765    }
1766
1767    if (src_w > drw_w)
1768        OUTREG(SEC_STREAM_SRC_START_2000, 0);
1769    else
1770        OUTREG(SEC_STREAM_SRC_START_2000, SRCSTART(x1, y1));
1771
1772    /*OUTREG(SEC_STREAM_SRC_SIZE_2000, SRCSIZE(src_w, src_h));*/
1773    OUTREG(SEC_STREAM_SRC_SIZE_2000,
1774	   SRCSIZE((dstBox->x2-dstBox->x1), (dstBox->y2-dstBox->y1)));
1775    /*
1776        buffersize = (src_w * src_h * 2) / 4096;
1777	  OUTREG(SEC_STREAM_BUFFERSIZE_2000, (buffersize & 0xffffff) << 12);
1778    */
1779
1780    /*SavageResetVideo(pScrn);*/
1781
1782    if( src_w > drw_w )
1783	OUTREG(SEC_STREAM_HSCALE_NORMALIZE, HSCALING_NORMALIZE(drw_w,src_w));
1784    else
1785        OUTREG(SEC_STREAM_HSCALE_NORMALIZE, (2048 << 16));
1786
1787    /* Calculate horizontal and vertical scale factors. */
1788    if ((src_w > drw_w) || (src_h > drw_h))
1789        OUTREG(SEC_STREAM_HSCALING, (HSCALING_2000(src_w,drw_w)) | 0x01000000);
1790    else
1791        OUTREG(SEC_STREAM_HSCALING, HSCALING_2000(src_w,drw_w));
1792
1793    OUTREG(SEC_STREAM_VSCALING, VSCALING_2000(src_h,drw_h));
1794
1795    /*
1796     * Set surface location and stride.  We use x1>>15 because all surfaces
1797     * are 2 bytes/pixel.
1798     */
1799
1800    addr0 = offset + (x1>>15); /* Y in YCbCr420 */
1801    addr1 = addr0 + (width * height); /* Cb in in YCbCr420 */
1802    addr2 = addr1 + ((width * height) / 4); /* Cr in in YCbCr420 */
1803    OUTREG(SEC_STREAM_FBUF_ADDR0, (addr0) & (0x3fffff & ~BASE_PAD));
1804#if 0
1805    OUTREG(SEC_STREAM_FBUF_ADDR1, (addr1) & (0x3fffff & ~BASE_PAD));
1806    OUTREG(SEC_STREAM_FBUF_ADDR2, (addr2) & (0x3fffff & ~BASE_PAD));
1807#endif
1808
1809    OUTREG(SEC_STREAM_WINDOW_START, XY_2000(dstBox->x1,dstBox->y1));
1810    OUTREG(SEC_STREAM_WINDOW_SZ,
1811	   WH_2000((dstBox->x2-dstBox->x1),(dstBox->y2-dstBox->y1)));
1812
1813    /*pitch = width * 2;*/
1814    OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff);
1815#if 0
1816    /* Y stride + CbCr stride in YCbCr420 */
1817    OUTREG(SEC_STREAM_STRIDE, (pitch & 0xfff) + ((pitch & 0xfff) << 15));
1818#endif
1819
1820#if 0
1821    /* Set color key on primary. */
1822
1823    SavageSetColorKey2000( pScrn );
1824#endif
1825
1826#if 0
1827    /* Set FIFO L2 on second stream. */
1828    if( pPriv->lastKnownPitch != pitch )
1829    {
1830	unsigned char cr92;
1831
1832	pPriv->lastKnownPitch = pitch;
1833	pitch = (pitch + 7) / 8 - 4;
1834	VGAOUT8(vgaCRIndex, 0x92);
1835	cr92 = VGAIN8(vgaCRReg);
1836	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1837	VGAOUT8(vgaCRIndex, 0x93);
1838	VGAOUT8(vgaCRReg, pitch);
1839    }
1840#endif
1841}
1842
1843static int
1844SavagePutImage(
1845    ScrnInfoPtr pScrn,
1846    short src_x, short src_y,
1847    short drw_x, short drw_y,
1848    short src_w, short src_h,
1849    short drw_w, short drw_h,
1850    int id, unsigned char* buf,
1851    short width, short height,
1852    Bool sync,
1853    RegionPtr clipBoxes, pointer data,
1854    DrawablePtr pDraw
1855){
1856    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1857    SavagePtr psav = SAVPTR(pScrn);
1858    ScreenPtr pScreen = pScrn->pScreen;
1859    INT32 x1, x2, y1, y2;
1860    unsigned char *dst_start;
1861    int pitch, new_size, offset, offsetV=0, offsetU=0;
1862    int srcPitch, srcPitch2=0, dstPitch;
1863    int top, left, npixels, nlines;
1864    BoxRec dstBox;
1865    CARD32 tmp;
1866/*    xf86ErrorFVerb(XVTRACE,"SavagePutImage\n"); */
1867    if(drw_w > 16384) drw_w = 16384;
1868
1869    /* Clip */
1870    x1 = src_x;
1871    x2 = src_x + src_w;
1872    y1 = src_y;
1873    y2 = src_y + src_h;
1874
1875    dstBox.x1 = drw_x;
1876    dstBox.x2 = drw_x + drw_w;
1877    dstBox.y1 = drw_y;
1878    dstBox.y2 = drw_y + drw_h;
1879
1880    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
1881		REGION_EXTENTS(pScreen, clipBoxes), width, height);
1882
1883    drw_w = dstBox.x2 - dstBox.x1;
1884    drw_h = dstBox.y2 - dstBox.y1;
1885    src_w = ( x2 - x1 ) >> 16;
1886    src_h = ( y2 - y1 ) >> 16;
1887
1888    if((x1 >= x2) || (y1 >= y2))
1889	return Success;
1890
1891    dstBox.x1 -= pScrn->frameX0;
1892    dstBox.x2 -= pScrn->frameX0;
1893    dstBox.y1 -= pScrn->frameY0;
1894    dstBox.y2 -= pScrn->frameY0;
1895
1896    pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
1897
1898    dstPitch = ((width << 1) + 15) & ~15;
1899    /*new_h = ((dstPitch * height) + pitch - 1) / pitch;*/
1900    new_size = dstPitch * height;
1901
1902    switch(id) {
1903    case FOURCC_Y211:		/* Y211 */
1904        srcPitch = width;
1905	break;
1906    case FOURCC_YV12:		/* YV12 */
1907	srcPitch = (width + 3) & ~3;
1908	offsetV = srcPitch * height;
1909	srcPitch2 = ((width >> 1) + 3) & ~3;
1910	offsetU = (srcPitch2 * (height >> 1)) + offsetV;
1911	break;
1912    case FOURCC_I420:
1913	srcPitch = (width + 3) & ~3;
1914	offsetU = srcPitch * height;
1915	srcPitch2 = ((width >> 1) + 3) & ~3;
1916	offsetV = (srcPitch2 * (height >> 1)) + offsetU;
1917	break;
1918    case FOURCC_RV15:		/* RGB15 */
1919    case FOURCC_RV16:		/* RGB16 */
1920    case FOURCC_YUY2:		/* YUY2 */
1921    default:
1922	srcPitch = (width << 1);
1923	break;
1924    }
1925
1926    if (srcPitch2 != 0 && S3_SAVAGE4_SERIES(psav->Chipset) && psav->BCIforXv) {
1927        new_size = ((new_size + 0xF) & ~0xF) + srcPitch * height + srcPitch2 * height;
1928    }
1929
1930/*    if(!(pPriv->area = SavageAllocateMemory(pScrn, pPriv->area, new_h)))
1931	return BadAlloc;*/
1932    pPriv->video_offset = SavageAllocateMemory(pScrn, &pPriv->video_memory,
1933					      new_size);
1934    if (pPriv->video_offset == 0)
1935        return BadAlloc;
1936
1937    /* copy data */
1938    top = y1 >> 16;
1939    left = (x1 >> 16) & ~1;
1940    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
1941    left <<= 1;
1942
1943    offset = (pPriv->video_offset) + (top * dstPitch);
1944    /*offset = pPriv->area->box.y1 * psav->lDelta;*/
1945    dst_start = (psav->FBBase + ((offset + left) & ~BASE_PAD));
1946
1947    switch(id) {
1948    case FOURCC_YV12:		/* YV12 */
1949    case FOURCC_I420:
1950	top &= ~1;
1951	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
1952	offsetU += tmp;
1953	offsetV += tmp;
1954	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
1955        if (S3_SAVAGE4_SERIES(psav->Chipset) && psav->BCIforXv && (npixels & 0xF) == 0) {
1956            SavageCopyPlanarDataBCI(
1957                pScrn,
1958	    	buf + (top * srcPitch) + (left >> 1),
1959	    	buf + offsetV,
1960	    	buf + offsetU,
1961	    	dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
1962        } else {
1963	    SavageCopyPlanarData(
1964	    	buf + (top * srcPitch) + (left >> 1),
1965	    	buf + offsetV,
1966	    	buf + offsetU,
1967	    	dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
1968        }
1969	break;
1970    case FOURCC_Y211:		/* Y211 */
1971    case FOURCC_RV15:		/* RGB15 */
1972    case FOURCC_RV16:		/* RGB16 */
1973    case FOURCC_YUY2:		/* YUY2 */
1974    default:
1975	buf += (top * srcPitch) + left;
1976	nlines = ((y2 + 0xffff) >> 16) - top;
1977	SavageCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1978	break;
1979    }
1980
1981    /* We need to enable the video before we draw the chroma color.
1982       Otherwise, we get blue flashes. */
1983
1984    SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
1985	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1986
1987    /* update cliplist */
1988    if(!REGION_EQUAL(pScreen, &pPriv->clip, clipBoxes)) {
1989	REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
1990	/* draw these */
1991	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1992
1993    }
1994
1995    pPriv->videoStatus = CLIENT_VIDEO_ON;
1996
1997    return Success;
1998}
1999
2000static int
2001SavageQueryImageAttributes(
2002  ScrnInfoPtr pScrn,
2003  int id,
2004  unsigned short *w, unsigned short *h,
2005  int *pitches, int *offsets
2006){
2007    int size, tmp;
2008
2009    if(*w > 1024) *w = 1024;
2010    if(*h > 1024) *h = 1024;
2011
2012    *w = (*w + 1) & ~1;
2013    if(offsets) offsets[0] = 0;
2014
2015    switch(id) {
2016    case FOURCC_IA44:
2017        if (pitches) pitches[0]=*w;
2018        size=(*w)*(*h);
2019        break;
2020    case FOURCC_Y211:
2021	size = *w << 2;
2022	if(pitches) pitches[0] = size;
2023	size *= *h;
2024	break;
2025    case FOURCC_YV12:
2026    case FOURCC_I420:
2027	*h = (*h + 1) & ~1;
2028	size = (*w + 3) & ~3;
2029	if(pitches) pitches[0] = size;
2030	size *= *h;
2031	if(offsets) offsets[1] = size;
2032	tmp = ((*w >> 1) + 3) & ~3;
2033	if(pitches) pitches[1] = pitches[2] = tmp;
2034	tmp *= (*h >> 1);
2035	size += tmp;
2036	if(offsets) offsets[2] = size;
2037	size += tmp;
2038	break;
2039    case FOURCC_RV15:		/* RGB15 */
2040    case FOURCC_RV16:		/* RGB16 */
2041    case FOURCC_YUY2:
2042    default:
2043	size = *w << 1;
2044	if(pitches) pitches[0] = size;
2045	size *= *h;
2046	break;
2047    }
2048
2049    return size;
2050}
2051
2052/****************** Offscreen stuff ***************/
2053
2054typedef struct {
2055  void *surface_memory;
2056  Bool isOn;
2057} OffscreenPrivRec, * OffscreenPrivPtr;
2058
2059static int
2060SavageAllocateSurface(
2061    ScrnInfoPtr pScrn,
2062    int id,
2063    unsigned short w,
2064    unsigned short h,
2065    XF86SurfacePtr surface
2066){
2067    int offset, size;
2068    int pitch, fbpitch, numlines;
2069    void *surface_memory = NULL;
2070    OffscreenPrivPtr pPriv;
2071
2072    if((w > 1024) || (h > 1024))
2073	return BadAlloc;
2074
2075    w = (w + 1) & ~1;
2076    pitch = ((w << 1) + 15) & ~15;
2077    fbpitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
2078    numlines = ((pitch * h) + fbpitch - 1) / fbpitch;
2079    size = pitch * h;
2080
2081    offset = SavageAllocateMemory(pScrn, &surface_memory, size);
2082    if (offset == 0)
2083	return BadAlloc;
2084
2085    surface->width = w;
2086    surface->height = h;
2087
2088    if(!(surface->pitches = xalloc(sizeof(int)))) {
2089	SavageFreeMemory(pScrn, surface_memory);
2090	return BadAlloc;
2091    }
2092    if(!(surface->offsets = xalloc(sizeof(int)))) {
2093	xfree(surface->pitches);
2094	SavageFreeMemory(pScrn, surface_memory);
2095	return BadAlloc;
2096    }
2097    if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
2098	xfree(surface->pitches);
2099	xfree(surface->offsets);
2100	SavageFreeMemory(pScrn, surface_memory);
2101	return BadAlloc;
2102    }
2103
2104    pPriv->surface_memory = surface_memory;
2105    pPriv->isOn = FALSE;
2106
2107    surface->pScrn = pScrn;
2108    surface->id = id;
2109    surface->pitches[0] = pitch;
2110    surface->offsets[0] = offset; /*area->box.y1 * fbpitch;*/
2111    surface->devPrivate.ptr = (pointer)pPriv;
2112
2113    return Success;
2114}
2115
2116static int
2117SavageStopSurface(
2118    XF86SurfacePtr surface
2119){
2120    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2121    xf86ErrorFVerb(XVTRACE,"SavageStopSurface\n");
2122
2123    if(pPriv->isOn) {
2124	/*SavagePtr psav = SAVPTR(surface->pScrn);*/
2125	/*SavageClipVWindow(surface->pScrn);*/
2126	SavageStreamsOff( surface->pScrn );
2127	pPriv->isOn = FALSE;
2128    }
2129
2130    return Success;
2131}
2132
2133
2134static int
2135SavageFreeSurface(
2136    XF86SurfacePtr surface
2137){
2138    ScrnInfoPtr pScrn = surface->pScrn;
2139    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2140
2141    if(pPriv->isOn)
2142	SavageStopSurface(surface);
2143    SavageFreeMemory(pScrn, pPriv->surface_memory);
2144    xfree(surface->pitches);
2145    xfree(surface->offsets);
2146    xfree(surface->devPrivate.ptr);
2147
2148    return Success;
2149}
2150
2151static int
2152SavageGetSurfaceAttribute(
2153    ScrnInfoPtr pScrn,
2154    Atom attribute,
2155    INT32 *value
2156){
2157    return SavageGetPortAttribute(pScrn, attribute, value,
2158			(pointer)(GET_PORT_PRIVATE(pScrn)));
2159}
2160
2161static int
2162SavageSetSurfaceAttribute(
2163    ScrnInfoPtr pScrn,
2164    Atom attribute,
2165    INT32 value
2166){
2167    return SavageSetPortAttribute(pScrn, attribute, value,
2168			(pointer)(GET_PORT_PRIVATE(pScrn)));
2169}
2170
2171
2172static int
2173SavageDisplaySurface(
2174    XF86SurfacePtr surface,
2175    short src_x, short src_y,
2176    short drw_x, short drw_y,
2177    short src_w, short src_h,
2178    short drw_w, short drw_h,
2179    RegionPtr clipBoxes
2180){
2181    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2182    ScrnInfoPtr pScrn = surface->pScrn;
2183    ScreenPtr pScreen = pScrn->pScreen;
2184    SavagePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
2185    INT32 x1, y1, x2, y2;
2186    BoxRec dstBox;
2187    xf86ErrorFVerb(XVTRACE,"SavageDisplaySurface\n");
2188
2189    x1 = src_x;
2190    x2 = src_x + src_w;
2191    y1 = src_y;
2192    y2 = src_y + src_h;
2193
2194    dstBox.x1 = drw_x;
2195    dstBox.x2 = drw_x + drw_w;
2196    dstBox.y1 = drw_y;
2197    dstBox.y2 = drw_y + drw_h;
2198
2199    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
2200                	REGION_EXTENTS(pScreen, clipBoxes),
2201			surface->width, surface->height);
2202
2203    if((x1 >= x2) || (y1 >= y2))
2204	return Success;
2205
2206    dstBox.x1 -= pScrn->frameX0;
2207    dstBox.x2 -= pScrn->frameX0;
2208    dstBox.y1 -= pScrn->frameY0;
2209    dstBox.y2 -= pScrn->frameY0;
2210
2211    SavageDisplayVideo(pScrn, surface->id, surface->offsets[0],
2212	     surface->width, surface->height, surface->pitches[0],
2213	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
2214
2215    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
2216
2217    pPriv->isOn = TRUE;
2218#if 0
2219    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
2220	REGION_EMPTY(pScreen, &portPriv->clip);
2221	UpdateCurrentTime();
2222	portPriv->videoStatus = FREE_TIMER;
2223	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
2224    }
2225#endif
2226
2227    return Success;
2228}
2229
2230
2231static void
2232SavageInitOffscreenImages(ScreenPtr pScreen)
2233{
2234    XF86OffscreenImagePtr offscreenImages;
2235    SavagePtr psav = SAVPTR(xf86Screens[pScreen->myNum]);
2236
2237    /* need to free this someplace */
2238    if (!psav->offscreenImages) {
2239	if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
2240	    return;
2241	psav->offscreenImages = offscreenImages;
2242    } else {
2243	offscreenImages = psav->offscreenImages;
2244    }
2245
2246    offscreenImages[0].image = &Images[0];
2247    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
2248			       VIDEO_CLIP_TO_VIEWPORT;
2249    offscreenImages[0].alloc_surface = SavageAllocateSurface;
2250    offscreenImages[0].free_surface = SavageFreeSurface;
2251    offscreenImages[0].display = SavageDisplaySurface;
2252    offscreenImages[0].stop = SavageStopSurface;
2253    offscreenImages[0].setAttribute = SavageSetSurfaceAttribute;
2254    offscreenImages[0].getAttribute = SavageGetSurfaceAttribute;
2255    offscreenImages[0].max_width = 1024;
2256    offscreenImages[0].max_height = 1024;
2257    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
2258    offscreenImages[0].attributes = Attributes;
2259
2260    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2261}
2262
2263