savage_video.c revision ab47cfaa
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                                                + 2 * srcPitch * 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    for (i=0;i<srcPitch * h;i++) {
1193        dstCopy[i] = srcY[i];
1194    }
1195
1196    /* copy V planar */
1197    dstCopy = dstCopy + srcPitch * h;
1198    for (i=0;i<srcPitch2 * (h>>1);i++) {
1199        dstCopy[i] = srcV[i];
1200    }
1201
1202    /* copy U planar */
1203    dstCopy = dstCopy + srcPitch2 * (h>>1);
1204    for (i=0;i<srcPitch2 * (h>>1);i++) {
1205        dstCopy[i] = srcU[i];
1206    }
1207
1208    /*
1209     * Transfer pixel data from one memory location to another location
1210     * and reformat the data during the transfer
1211     * a. program BCI51 to specify the source information
1212     * b. program BCI52 to specify the destination information
1213     * c. program BCI53 to specify the source dimensions
1214     * d. program BCI54 to specify the destination dimensions
1215     * e. (if the data is in YCbCr420 format)program BCI55,BCI56,BCI57 to
1216     *    locations of the Y,Cb,and Cr data
1217     * f. program BCI50(command=011) to specify the formatting options and
1218     *    kick off the transfer
1219     * this command can be used for color space conversion(YCbCr to RGB)
1220     * or for oversampling, but not for both simultaneously. it can also be
1221     * used to do mastered image transfer when the source is tiled
1222     */
1223
1224    w = (w+0xf)&0xff0;
1225    psav->WaitQueue(psav,11);
1226    BCI_SEND(0x96070051);
1227    BCI_SEND(offsetY);
1228
1229    BCI_SEND(dstOffset);
1230
1231    BCI_SEND(((h-1)<<16)|((w-1)>>3));
1232
1233    BCI_SEND(dstPitch >> 3);
1234
1235
1236    BCI_SEND(offsetU);
1237    BCI_SEND(offsetV);
1238
1239    BCI_SEND((srcPitch2 << 16)| srcPitch2);
1240
1241    BCI_SEND(0x96010050);
1242    BCI_SEND(0x00200003 | srcPitch);
1243    BCI_SEND(0xC0170000);
1244}
1245
1246static void
1247SavageCopyData(
1248  unsigned char *src,
1249  unsigned char *dst,
1250  int srcPitch,
1251  int dstPitch,
1252  int h,
1253  int w
1254){
1255    w <<= 1;
1256    while(h--) {
1257	memcpy(dst, src, w);
1258	src += srcPitch;
1259	dst += dstPitch;
1260    }
1261}
1262
1263static void
1264SavageCopyPlanarData(
1265   unsigned char *src1, /* Y */
1266   unsigned char *src2, /* V */
1267   unsigned char *src3, /* U */
1268   unsigned char *dst1,
1269   int srcPitch,
1270   int srcPitch2,
1271   int dstPitch,
1272   int h,
1273   int w
1274){
1275   CARD32 *dst = (CARD32*)dst1;
1276   int i, j;
1277
1278   dstPitch >>= 2;
1279   w >>= 1;
1280
1281   for(j = 0; j < h; j++) {
1282	for(i = 0; i < w; i++) {
1283/* Shouldn't this be 'if LITTLEENDIAN'? */
1284#if 1
1285	    dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
1286		     (src3[i] << 8) | (src2[i] << 24);
1287#else
1288	    dst[i] = (src1[i << 1] << 24) | (src1[(i << 1) + 1] << 8) |
1289		     (src3[i] << 0) | (src2[i] << 16);
1290#endif
1291	}
1292	dst += dstPitch;
1293	src1 += srcPitch;
1294	if(j & 1) {
1295	    src2 += srcPitch2;
1296	    src3 += srcPitch2;
1297	}
1298   }
1299}
1300
1301static void
1302SavageVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
1303{
1304    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1305    SavagePtr psav = SAVPTR(pScrn);
1306    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1307
1308    if (pPriv->video_memory == area)
1309        pPriv->video_memory = NULL;
1310}
1311
1312static CARD32
1313SavageAllocateMemory(
1314    ScrnInfoPtr pScrn,
1315    void **mem_struct,
1316    int size
1317){
1318    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
1319    SavagePtr psav = SAVPTR(pScrn);
1320    int offset = 0;
1321
1322    if (psav->useEXA) {
1323	ExaOffscreenArea *area = *mem_struct;
1324
1325	if (area != NULL) {
1326	    if (area->size >= size)
1327		return area->offset;
1328
1329	    exaOffscreenFree(pScrn->pScreen, area);
1330	}
1331
1332	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, SavageVideoSave,
1333				 NULL);
1334	*mem_struct = area;
1335	if (area == NULL)
1336	    return 0;
1337	offset = area->offset;
1338    }
1339
1340    if (!psav->useEXA) {
1341	FBLinearPtr linear = *mem_struct;
1342	int cpp = pScrn->bitsPerPixel / 8;
1343
1344	/* XAA allocates in units of pixels at the screen bpp, so adjust size
1345	 * appropriately.
1346	 */
1347	size = (size + cpp - 1) / cpp;
1348
1349	if (linear) {
1350	    if(linear->size >= size)
1351		return linear->offset * cpp;
1352
1353	    if(xf86ResizeOffscreenLinear(linear, size))
1354		return linear->offset * cpp;
1355
1356	    xf86FreeOffscreenLinear(linear);
1357	}
1358
1359	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1360						NULL, NULL, NULL);
1361	*mem_struct = linear;
1362
1363	if (!linear) {
1364	    int max_size;
1365
1366	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
1367					    PRIORITY_EXTREME);
1368
1369	    if(max_size < size)
1370		return 0;
1371
1372	    xf86PurgeUnlockedOffscreenAreas(pScreen);
1373	    linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1374						     NULL, NULL, NULL);
1375	    *mem_struct = linear;
1376	    if (!linear)
1377		return 0;
1378	}
1379	offset = linear->offset * cpp;
1380    }
1381
1382    return offset;
1383}
1384
1385static void
1386SavageFreeMemory(
1387   ScrnInfoPtr pScrn,
1388   void *mem_struct
1389){
1390    SavagePtr psav = SAVPTR(pScrn);
1391
1392    if (psav->useEXA) {
1393	ExaOffscreenArea *area = mem_struct;
1394
1395	if (area != NULL)
1396	    exaOffscreenFree(pScrn->pScreen, area);
1397    }
1398    if (!psav->useEXA) {
1399	FBLinearPtr linear = mem_struct;
1400
1401	if (linear != NULL)
1402	    xf86FreeOffscreenLinear(linear);
1403    }
1404}
1405
1406static void
1407SavageSetBlend(ScrnInfoPtr pScrn, int id)
1408{
1409    SavagePtr psav = SAVPTR(pScrn);
1410
1411    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
1412    {
1413	psav->blendBase = GetBlendForFourCC( id );
1414	xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1415	if (psav->IsSecondary) {
1416	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1417	} else if (psav->IsPrimary) {
1418	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1419	} else {
1420	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1421#if 0
1422	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1423#endif
1424	}
1425    } else if (psav->Chipset == S3_SAVAGE2000) {
1426      psav->blendBase = GetBlendForFourCC2000( id );
1427      xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1428      if (id != FOURCC_YV12)
1429	OUTREG( BLEND_CONTROL,
1430		((psav->blendBase << 24) | (8 << 2) /*| 0x20000000*/));
1431      else
1432	OUTREG( BLEND_CONTROL,
1433		((psav->blendBase << 24) | (8 << 2) /*| 0x10000000*/));
1434    }
1435
1436    psav->videoFourCC = id;
1437}
1438
1439static void
1440SavageDisplayVideoOld(
1441    ScrnInfoPtr pScrn,
1442    int id,
1443    int offset,
1444    short width, short height,
1445    int pitch,
1446    int x1, int y1, int x2, int y2,
1447    BoxPtr dstBox,
1448    short src_w, short src_h,
1449    short drw_w, short drw_h
1450){
1451    SavagePtr psav = SAVPTR(pScrn);
1452    vgaHWPtr hwp = VGAHWPTR(pScrn);
1453    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1454    /*DisplayModePtr mode = pScrn->currentMode;*/
1455    int vgaCRIndex, vgaCRReg, vgaIOBase;
1456    CARD32 ssControl;
1457    int scalratio;
1458
1459
1460    vgaIOBase = hwp->IOBase;
1461    vgaCRIndex = vgaIOBase + 4;
1462    vgaCRReg = vgaIOBase + 5;
1463#if 0
1464    if ( psav->videoFourCC != id ) {
1465	SavageSetBlend(pScrn,id);
1466	SavageResetVideo(pScrn);
1467    }
1468#endif
1469    if( psav->videoFourCC != id )
1470      SavageStreamsOff(pScrn);
1471
1472    if( !psav->videoFlags & VF_STREAMS_ON )
1473      {
1474        SavageSetBlend(pScrn,id);
1475	SavageStreamsOn(pScrn);
1476	SavageResetVideo(pScrn);
1477      }
1478
1479    if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)
1480        && psav->FPExpansion) {
1481        drw_w = (((float)(drw_w * psav->XExp1)/(float)psav->XExp2)+1);
1482        drw_h = (float)(drw_h * psav->YExp1)/(float)psav->YExp2+1;
1483        dstBox->x1 = (float)(dstBox->x1 * psav->XExp1)/(float)psav->XExp2;
1484        dstBox->y1 = (float)(dstBox->y1 * psav->YExp1)/(float)psav->YExp2;
1485
1486        dstBox->x1 += psav->displayXoffset;
1487        dstBox->y1 += psav->displayYoffset;
1488    }
1489
1490    /*
1491     * Process horizontal scaling
1492     *  upscaling and downscaling smaller than 2:1 controled by MM8198
1493     *  MM8190 controls downscaling mode larger than 2:1
1494     */
1495    scalratio = 0;
1496    ssControl = 0;
1497
1498    if (src_w >= (drw_w * 2)) {
1499        if (src_w < (drw_w * 4)) {
1500            scalratio = HSCALING(2,1);
1501        } else if (src_w < (drw_w * 8)) {
1502            ssControl |= HDSCALE_4;
1503        } else if (src_w < (drw_w * 16)) {
1504            ssControl |= HDSCALE_8;
1505        } else if (src_w < (drw_w * 32)) {
1506            ssControl |= HDSCALE_16;
1507        }  else if (src_w < (drw_w * 64)) {
1508            ssControl |= HDSCALE_32;
1509        } else
1510            ssControl |= HDSCALE_64;
1511    } else
1512        scalratio = HSCALING(src_w,drw_w);
1513
1514    ssControl |= src_w;
1515    /*ssControl |= (1 << 24);*/
1516    ssControl |= (GetBlendForFourCC(psav->videoFourCC) << 24);
1517    /* Wait for VBLANK. */
1518    VerticalRetraceWait();
1519    OUTREG(SSTREAM_CONTROL_REG, ssControl);
1520    if (scalratio)
1521        OUTREG(SSTREAM_STRETCH_REG,scalratio);
1522
1523    /* Calculate vertical scale factor. */
1524    OUTREG(SSTREAM_VINITIAL_REG, 0 );
1525    /*OUTREG(SSTREAM_VSCALE_REG, (src_h << 15) / drw_h );*/
1526    OUTREG(SSTREAM_VSCALE_REG, VSCALING(src_h,drw_h));
1527
1528    /* Set surface location and stride. */
1529    OUTREG(SSTREAM_FBADDR0_REG, (offset + (x1>>15)) & (0x1ffffff & ~BASE_PAD) );
1530    OUTREG(SSTREAM_FBADDR1_REG, 0);
1531    OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
1532
1533    OUTREG(SSTREAM_WINDOW_START_REG, OS_XY(dstBox->x1, dstBox->y1) );
1534    OUTREG(SSTREAM_WINDOW_SIZE_REG, OS_WH(dstBox->x2-dstBox->x1,
1535                                          dstBox->y2-dstBox->y1));
1536
1537    /*
1538     * MM81E8:Secondary Stream Source Line Count
1539     *   bit_0~10: # of lines in the source image (before scaling)
1540     *   bit_15 = 1: Enable vertical interpolation
1541     *            0: Line duplicaion
1542     */
1543    /*
1544     * Vertical Interpolation is very bandwidth intensive.  Some savages can't
1545     * seem to handle it.  Default is line doubling.  --AGD
1546     */
1547    if (pPriv->interpolation) {
1548        if (src_w * 16 <= 0x3300) {
1549            OUTREG(SSTREAM_LINES_REG, 0x8000 | src_h );
1550	    OUTREG(FIFO_CONTROL, (INREG(FIFO_CONTROL) + 1));
1551        } else {
1552            OUTREG(SSTREAM_LINES_REG, src_h );
1553        }
1554    } else {
1555        OUTREG(SSTREAM_LINES_REG, src_h );
1556    }
1557
1558#if 0
1559    /* Set color key on primary. */
1560
1561    SavageSetColorKey( pScrn );
1562#endif
1563
1564    /* Set FIFO L2 on second stream. */
1565
1566    if( pPriv->lastKnownPitch != pitch )
1567    {
1568	unsigned char cr92;
1569
1570	pPriv->lastKnownPitch = pitch;
1571
1572	pitch = (pitch + 7) / 8;
1573	VGAOUT8(vgaCRIndex, 0x92);
1574	cr92 = VGAIN8(vgaCRReg);
1575	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1576	VGAOUT8(vgaCRIndex, 0x93);
1577	if (psav->bTiled && (( drw_h > src_h) || (drw_w > src_w)))
1578	    VGAOUT8(vgaCRReg, pitch | 0xf);
1579	else
1580	    VGAOUT8(vgaCRReg, pitch);
1581    }
1582}
1583
1584static void
1585SavageDisplayVideoNew(
1586    ScrnInfoPtr pScrn,
1587    int id,
1588    int offset,
1589    short width, short height,
1590    int pitch,
1591    int x1, int y1, int x2, int y2,
1592    BoxPtr dstBox,
1593    short src_w, short src_h,
1594    short drw_w, short drw_h
1595){
1596    SavagePtr psav = SAVPTR(pScrn);
1597    vgaHWPtr hwp = VGAHWPTR(pScrn);
1598    /*DisplayModePtr mode = pScrn->currentMode;*/
1599    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1600    int vgaCRIndex, vgaCRReg, vgaIOBase;
1601
1602
1603    vgaIOBase = hwp->IOBase;
1604    vgaCRIndex = vgaIOBase + 4;
1605    vgaCRReg = vgaIOBase + 5;
1606#if 0
1607    if ( psav->videoFourCC != id ) {
1608	SavageSetBlend(pScrn,id);
1609	SavageResetVideo(pScrn);
1610    }
1611#endif
1612    if( psav->videoFourCC != id )
1613      SavageStreamsOff(pScrn);
1614
1615    if( !psav->videoFlags & VF_STREAMS_ON )
1616      {
1617	SavageSetBlend(pScrn,id);
1618	SavageStreamsOn(pScrn);
1619	SavageResetVideo(pScrn);
1620      }
1621
1622    /* Calculate horizontal and vertical scale factors. */
1623
1624    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
1625	    (psav->DisplayType == MT_LCD) &&
1626	    !psav->CrtOnly &&
1627	    !psav->TvOn)
1628    {
1629	drw_w = (drw_w * psav->XExp1)/psav->XExp2 + 1;
1630	drw_h = (drw_h * psav->YExp1)/psav->YExp2 + 1;
1631	dstBox->x1 = (dstBox->x1 * psav->XExp1)/psav->XExp2;
1632	dstBox->y1 = (dstBox->y1 * psav->YExp1)/psav->YExp2;
1633	dstBox->x1 += psav->displayXoffset;
1634	dstBox->y1 += psav->displayYoffset;
1635    }
1636
1637	if (psav->IsSecondary) {
1638	    OUTREG(SEC_STREAM2_HSCALING,
1639	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1640	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1641	    OUTREG(SEC_STREAM2_VSCALING,
1642	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1643	} else if (psav->IsPrimary) {
1644	    OUTREG(SEC_STREAM_HSCALING,
1645	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1646	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1647	    OUTREG(SEC_STREAM_VSCALING,
1648	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1649	} else {
1650	    OUTREG(SEC_STREAM_HSCALING,
1651	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1652	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1653	    OUTREG(SEC_STREAM_VSCALING,
1654	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1655#if 0
1656	    OUTREG(SEC_STREAM2_HSCALING,
1657	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1658	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1659	    OUTREG(SEC_STREAM2_VSCALING,
1660	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1661#endif
1662	}
1663
1664    /*
1665     * Set surface location and stride.  We use x1>>15 because all surfaces
1666     * are 2 bytes/pixel.
1667     */
1668
1669    if (psav->IsSecondary) {
1670        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1671	   & (0x7ffffff & ~BASE_PAD));
1672        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1673        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1674        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1675	   | (dstBox->x2-dstBox->x1) );
1676    } else if (psav->IsPrimary) {
1677        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1678	   & (0x7ffffff & ~BASE_PAD));
1679        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1680        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1681        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1682	   | (dstBox->x2-dstBox->x1) );
1683    } else {
1684        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1685	   & (0x7ffffff & ~BASE_PAD));
1686        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1687        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1688        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1689	   | (dstBox->x2-dstBox->x1) );
1690#if 0
1691        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1692	   & (0x7ffffff & ~BASE_PAD));
1693        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1694        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1695        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1696	   | (dstBox->x2-dstBox->x1) );
1697#endif
1698    }
1699
1700#if 0
1701    /* Set color key on primary. */
1702
1703    SavageSetColorKey( pScrn );
1704#endif
1705
1706    /* Set FIFO L2 on second stream. */
1707    /* Is CR92 shadowed for crtc2? -- AGD */
1708    if( pPriv->lastKnownPitch != pitch )
1709    {
1710	unsigned char cr92;
1711
1712	pPriv->lastKnownPitch = pitch;
1713	pitch = (pitch + 7) / 8 - 4;
1714	VGAOUT8(vgaCRIndex, 0x92);
1715	cr92 = VGAIN8(vgaCRReg);
1716	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1717	VGAOUT8(vgaCRIndex, 0x93);
1718	VGAOUT8(vgaCRReg, pitch);
1719    }
1720}
1721
1722static void
1723SavageDisplayVideo2000(
1724    ScrnInfoPtr pScrn,
1725    int id,
1726    int offset,
1727    short width, short height,
1728    int pitch,
1729    int x1, int y1, int x2, int y2,
1730    BoxPtr dstBox,
1731    short src_w, short src_h,
1732    short drw_w, short drw_h
1733){
1734    SavagePtr psav = SAVPTR(pScrn);
1735    vgaHWPtr hwp = VGAHWPTR(pScrn);
1736    /*DisplayModePtr mode = pScrn->currentMode;*/
1737    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1738    int vgaCRIndex, vgaCRReg, vgaIOBase;
1739    CARD32 addr0, addr1, addr2;
1740
1741    vgaIOBase = hwp->IOBase;
1742    vgaCRIndex = vgaIOBase + 4;
1743    vgaCRReg = vgaIOBase + 5;
1744
1745
1746    if( psav->videoFourCC != id )
1747        SavageStreamsOff(pScrn);
1748
1749    if( !psav->videoFlags & VF_STREAMS_ON )
1750    {
1751        SavageSetBlend(pScrn,id);
1752        SavageStreamsOn(pScrn);
1753        SavageResetVideo(pScrn);
1754    }
1755
1756    if (src_w > drw_w)
1757        OUTREG(SEC_STREAM_SRC_START_2000, 0);
1758    else
1759        OUTREG(SEC_STREAM_SRC_START_2000, SRCSTART(x1, y1));
1760
1761    /*OUTREG(SEC_STREAM_SRC_SIZE_2000, SRCSIZE(src_w, src_h));*/
1762    OUTREG(SEC_STREAM_SRC_SIZE_2000,
1763	   SRCSIZE((dstBox->x2-dstBox->x1), (dstBox->y2-dstBox->y1)));
1764    /*
1765        buffersize = (src_w * src_h * 2) / 4096;
1766	  OUTREG(SEC_STREAM_BUFFERSIZE_2000, (buffersize & 0xffffff) << 12);
1767    */
1768
1769    /*SavageResetVideo(pScrn);*/
1770
1771    if( src_w > drw_w )
1772	OUTREG(SEC_STREAM_HSCALE_NORMALIZE, HSCALING_NORMALIZE(drw_w,src_w));
1773    else
1774        OUTREG(SEC_STREAM_HSCALE_NORMALIZE, (2048 << 16));
1775
1776    /* Calculate horizontal and vertical scale factors. */
1777    if ((src_w > drw_w) || (src_h > drw_h))
1778        OUTREG(SEC_STREAM_HSCALING, (HSCALING_2000(src_w,drw_w)) | 0x01000000);
1779    else
1780        OUTREG(SEC_STREAM_HSCALING, HSCALING_2000(src_w,drw_w));
1781
1782    OUTREG(SEC_STREAM_VSCALING, VSCALING_2000(src_h,drw_h));
1783
1784    /*
1785     * Set surface location and stride.  We use x1>>15 because all surfaces
1786     * are 2 bytes/pixel.
1787     */
1788
1789    addr0 = offset + (x1>>15); /* Y in YCbCr420 */
1790    addr1 = addr0 + (width * height); /* Cb in in YCbCr420 */
1791    addr2 = addr1 + ((width * height) / 4); /* Cr in in YCbCr420 */
1792    OUTREG(SEC_STREAM_FBUF_ADDR0, (addr0) & (0x3fffff & ~BASE_PAD));
1793#if 0
1794    OUTREG(SEC_STREAM_FBUF_ADDR1, (addr1) & (0x3fffff & ~BASE_PAD));
1795    OUTREG(SEC_STREAM_FBUF_ADDR2, (addr2) & (0x3fffff & ~BASE_PAD));
1796#endif
1797
1798    OUTREG(SEC_STREAM_WINDOW_START, XY_2000(dstBox->x1,dstBox->y1));
1799    OUTREG(SEC_STREAM_WINDOW_SZ,
1800	   WH_2000((dstBox->x2-dstBox->x1),(dstBox->y2-dstBox->y1)));
1801
1802    /*pitch = width * 2;*/
1803    OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff);
1804#if 0
1805    /* Y stride + CbCr stride in YCbCr420 */
1806    OUTREG(SEC_STREAM_STRIDE, (pitch & 0xfff) + ((pitch & 0xfff) << 15));
1807#endif
1808
1809#if 0
1810    /* Set color key on primary. */
1811
1812    SavageSetColorKey2000( pScrn );
1813#endif
1814
1815#if 0
1816    /* Set FIFO L2 on second stream. */
1817    if( pPriv->lastKnownPitch != pitch )
1818    {
1819	unsigned char cr92;
1820
1821	pPriv->lastKnownPitch = pitch;
1822	pitch = (pitch + 7) / 8 - 4;
1823	VGAOUT8(vgaCRIndex, 0x92);
1824	cr92 = VGAIN8(vgaCRReg);
1825	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1826	VGAOUT8(vgaCRIndex, 0x93);
1827	VGAOUT8(vgaCRReg, pitch);
1828    }
1829#endif
1830}
1831
1832static int
1833SavagePutImage(
1834    ScrnInfoPtr pScrn,
1835    short src_x, short src_y,
1836    short drw_x, short drw_y,
1837    short src_w, short src_h,
1838    short drw_w, short drw_h,
1839    int id, unsigned char* buf,
1840    short width, short height,
1841    Bool sync,
1842    RegionPtr clipBoxes, pointer data,
1843    DrawablePtr pDraw
1844){
1845    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1846    SavagePtr psav = SAVPTR(pScrn);
1847    ScreenPtr pScreen = pScrn->pScreen;
1848    INT32 x1, x2, y1, y2;
1849    unsigned char *dst_start;
1850    int pitch, new_size, offset, offsetV=0, offsetU=0;
1851    int srcPitch, srcPitch2=0, dstPitch;
1852    int top, left, npixels, nlines;
1853    BoxRec dstBox;
1854    CARD32 tmp;
1855/*    xf86ErrorFVerb(XVTRACE,"SavagePutImage\n"); */
1856    if(drw_w > 16384) drw_w = 16384;
1857
1858    /* Clip */
1859    x1 = src_x;
1860    x2 = src_x + src_w;
1861    y1 = src_y;
1862    y2 = src_y + src_h;
1863
1864    dstBox.x1 = drw_x;
1865    dstBox.x2 = drw_x + drw_w;
1866    dstBox.y1 = drw_y;
1867    dstBox.y2 = drw_y + drw_h;
1868
1869    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
1870		REGION_EXTENTS(pScreen, clipBoxes), width, height);
1871
1872    drw_w = dstBox.x2 - dstBox.x1;
1873    drw_h = dstBox.y2 - dstBox.y1;
1874    src_w = ( x2 - x1 ) >> 16;
1875    src_h = ( y2 - y1 ) >> 16;
1876
1877    if((x1 >= x2) || (y1 >= y2))
1878	return Success;
1879
1880    dstBox.x1 -= pScrn->frameX0;
1881    dstBox.x2 -= pScrn->frameX0;
1882    dstBox.y1 -= pScrn->frameY0;
1883    dstBox.y2 -= pScrn->frameY0;
1884
1885    pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
1886
1887    dstPitch = ((width << 1) + 15) & ~15;
1888    /*new_h = ((dstPitch * height) + pitch - 1) / pitch;*/
1889    new_size = dstPitch * height;
1890
1891    switch(id) {
1892    case FOURCC_Y211:		/* Y211 */
1893        srcPitch = width;
1894	break;
1895    case FOURCC_YV12:		/* YV12 */
1896	srcPitch = (width + 3) & ~3;
1897	offsetV = srcPitch * height;
1898	srcPitch2 = ((width >> 1) + 3) & ~3;
1899	offsetU = (srcPitch2 * (height >> 1)) + offsetV;
1900	break;
1901    case FOURCC_I420:
1902	srcPitch = (width + 3) & ~3;
1903	offsetU = srcPitch * height;
1904	srcPitch2 = ((width >> 1) + 3) & ~3;
1905	offsetV = (srcPitch2 * (height >> 1)) + offsetU;
1906	break;
1907    case FOURCC_RV15:		/* RGB15 */
1908    case FOURCC_RV16:		/* RGB16 */
1909    case FOURCC_YUY2:		/* YUY2 */
1910    default:
1911	srcPitch = (width << 1);
1912	break;
1913    }
1914
1915/*    if(!(pPriv->area = SavageAllocateMemory(pScrn, pPriv->area, new_h)))
1916	return BadAlloc;*/
1917    pPriv->video_offset = SavageAllocateMemory(pScrn, &pPriv->video_memory,
1918					      new_size);
1919    if (pPriv->video_offset == 0)
1920        return BadAlloc;
1921
1922    /* copy data */
1923    top = y1 >> 16;
1924    left = (x1 >> 16) & ~1;
1925    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
1926    left <<= 1;
1927
1928    offset = (pPriv->video_offset) + (top * dstPitch);
1929    /*offset = pPriv->area->box.y1 * psav->lDelta;*/
1930    dst_start = (psav->FBBase + ((offset + left) & ~BASE_PAD));
1931
1932    switch(id) {
1933    case FOURCC_YV12:		/* YV12 */
1934    case FOURCC_I420:
1935	top &= ~1;
1936	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
1937	offsetU += tmp;
1938	offsetV += tmp;
1939	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
1940        if (S3_SAVAGE4_SERIES(psav->Chipset) && psav->BCIforXv) {
1941            SavageCopyPlanarDataBCI(
1942                pScrn,
1943	    	buf + (top * srcPitch) + (left >> 1),
1944	    	buf + offsetV,
1945	    	buf + offsetU,
1946	    	dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
1947        } else {
1948	    SavageCopyPlanarData(
1949	    	buf + (top * srcPitch) + (left >> 1),
1950	    	buf + offsetV,
1951	    	buf + offsetU,
1952	    	dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
1953        }
1954	break;
1955    case FOURCC_Y211:		/* Y211 */
1956    case FOURCC_RV15:		/* RGB15 */
1957    case FOURCC_RV16:		/* RGB16 */
1958    case FOURCC_YUY2:		/* YUY2 */
1959    default:
1960	buf += (top * srcPitch) + left;
1961	nlines = ((y2 + 0xffff) >> 16) - top;
1962	SavageCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1963	break;
1964    }
1965
1966    /* We need to enable the video before we draw the chroma color.
1967       Otherwise, we get blue flashes. */
1968
1969    SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
1970	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
1971
1972    /* update cliplist */
1973    if(!REGION_EQUAL(pScreen, &pPriv->clip, clipBoxes)) {
1974	REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
1975	/* draw these */
1976	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1977
1978    }
1979
1980    pPriv->videoStatus = CLIENT_VIDEO_ON;
1981
1982    return Success;
1983}
1984
1985static int
1986SavageQueryImageAttributes(
1987  ScrnInfoPtr pScrn,
1988  int id,
1989  unsigned short *w, unsigned short *h,
1990  int *pitches, int *offsets
1991){
1992    int size, tmp;
1993
1994    if(*w > 1024) *w = 1024;
1995    if(*h > 1024) *h = 1024;
1996
1997    *w = (*w + 1) & ~1;
1998    if(offsets) offsets[0] = 0;
1999
2000    switch(id) {
2001    case FOURCC_IA44:
2002        if (pitches) pitches[0]=*w;
2003        size=(*w)*(*h);
2004        break;
2005    case FOURCC_Y211:
2006	size = *w << 2;
2007	if(pitches) pitches[0] = size;
2008	size *= *h;
2009	break;
2010    case FOURCC_YV12:
2011    case FOURCC_I420:
2012	*h = (*h + 1) & ~1;
2013	size = (*w + 3) & ~3;
2014	if(pitches) pitches[0] = size;
2015	size *= *h;
2016	if(offsets) offsets[1] = size;
2017	tmp = ((*w >> 1) + 3) & ~3;
2018	if(pitches) pitches[1] = pitches[2] = tmp;
2019	tmp *= (*h >> 1);
2020	size += tmp;
2021	if(offsets) offsets[2] = size;
2022	size += tmp;
2023	break;
2024    case FOURCC_RV15:		/* RGB15 */
2025    case FOURCC_RV16:		/* RGB16 */
2026    case FOURCC_YUY2:
2027    default:
2028	size = *w << 1;
2029	if(pitches) pitches[0] = size;
2030	size *= *h;
2031	break;
2032    }
2033
2034    return size;
2035}
2036
2037/****************** Offscreen stuff ***************/
2038
2039typedef struct {
2040  void *surface_memory;
2041  Bool isOn;
2042} OffscreenPrivRec, * OffscreenPrivPtr;
2043
2044static int
2045SavageAllocateSurface(
2046    ScrnInfoPtr pScrn,
2047    int id,
2048    unsigned short w,
2049    unsigned short h,
2050    XF86SurfacePtr surface
2051){
2052    int offset, size;
2053    int pitch, fbpitch, numlines;
2054    void *surface_memory = NULL;
2055    OffscreenPrivPtr pPriv;
2056
2057    if((w > 1024) || (h > 1024))
2058	return BadAlloc;
2059
2060    w = (w + 1) & ~1;
2061    pitch = ((w << 1) + 15) & ~15;
2062    fbpitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
2063    numlines = ((pitch * h) + fbpitch - 1) / fbpitch;
2064    size = pitch * h;
2065
2066    offset = SavageAllocateMemory(pScrn, &surface_memory, size);
2067    if (offset == 0)
2068	return BadAlloc;
2069
2070    surface->width = w;
2071    surface->height = h;
2072
2073    if(!(surface->pitches = xalloc(sizeof(int)))) {
2074	SavageFreeMemory(pScrn, surface_memory);
2075	return BadAlloc;
2076    }
2077    if(!(surface->offsets = xalloc(sizeof(int)))) {
2078	xfree(surface->pitches);
2079	SavageFreeMemory(pScrn, surface_memory);
2080	return BadAlloc;
2081    }
2082    if(!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
2083	xfree(surface->pitches);
2084	xfree(surface->offsets);
2085	SavageFreeMemory(pScrn, surface_memory);
2086	return BadAlloc;
2087    }
2088
2089    pPriv->surface_memory = surface_memory;
2090    pPriv->isOn = FALSE;
2091
2092    surface->pScrn = pScrn;
2093    surface->id = id;
2094    surface->pitches[0] = pitch;
2095    surface->offsets[0] = offset; /*area->box.y1 * fbpitch;*/
2096    surface->devPrivate.ptr = (pointer)pPriv;
2097
2098    return Success;
2099}
2100
2101static int
2102SavageStopSurface(
2103    XF86SurfacePtr surface
2104){
2105    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2106    xf86ErrorFVerb(XVTRACE,"SavageStopSurface\n");
2107
2108    if(pPriv->isOn) {
2109	/*SavagePtr psav = SAVPTR(surface->pScrn);*/
2110	/*SavageClipVWindow(surface->pScrn);*/
2111	SavageStreamsOff( surface->pScrn );
2112	pPriv->isOn = FALSE;
2113    }
2114
2115    return Success;
2116}
2117
2118
2119static int
2120SavageFreeSurface(
2121    XF86SurfacePtr surface
2122){
2123    ScrnInfoPtr pScrn = surface->pScrn;
2124    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2125
2126    if(pPriv->isOn)
2127	SavageStopSurface(surface);
2128    SavageFreeMemory(pScrn, pPriv->surface_memory);
2129    xfree(surface->pitches);
2130    xfree(surface->offsets);
2131    xfree(surface->devPrivate.ptr);
2132
2133    return Success;
2134}
2135
2136static int
2137SavageGetSurfaceAttribute(
2138    ScrnInfoPtr pScrn,
2139    Atom attribute,
2140    INT32 *value
2141){
2142    return SavageGetPortAttribute(pScrn, attribute, value,
2143			(pointer)(GET_PORT_PRIVATE(pScrn)));
2144}
2145
2146static int
2147SavageSetSurfaceAttribute(
2148    ScrnInfoPtr pScrn,
2149    Atom attribute,
2150    INT32 value
2151){
2152    return SavageSetPortAttribute(pScrn, attribute, value,
2153			(pointer)(GET_PORT_PRIVATE(pScrn)));
2154}
2155
2156
2157static int
2158SavageDisplaySurface(
2159    XF86SurfacePtr surface,
2160    short src_x, short src_y,
2161    short drw_x, short drw_y,
2162    short src_w, short src_h,
2163    short drw_w, short drw_h,
2164    RegionPtr clipBoxes
2165){
2166    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2167    ScrnInfoPtr pScrn = surface->pScrn;
2168    ScreenPtr pScreen = pScrn->pScreen;
2169    SavagePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
2170    INT32 x1, y1, x2, y2;
2171    BoxRec dstBox;
2172    xf86ErrorFVerb(XVTRACE,"SavageDisplaySurface\n");
2173
2174    x1 = src_x;
2175    x2 = src_x + src_w;
2176    y1 = src_y;
2177    y2 = src_y + src_h;
2178
2179    dstBox.x1 = drw_x;
2180    dstBox.x2 = drw_x + drw_w;
2181    dstBox.y1 = drw_y;
2182    dstBox.y2 = drw_y + drw_h;
2183
2184    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
2185                	REGION_EXTENTS(pScreen, clipBoxes),
2186			surface->width, surface->height);
2187
2188    if((x1 >= x2) || (y1 >= y2))
2189	return Success;
2190
2191    dstBox.x1 -= pScrn->frameX0;
2192    dstBox.x2 -= pScrn->frameX0;
2193    dstBox.y1 -= pScrn->frameY0;
2194    dstBox.y2 -= pScrn->frameY0;
2195
2196    SavageDisplayVideo(pScrn, surface->id, surface->offsets[0],
2197	     surface->width, surface->height, surface->pitches[0],
2198	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
2199
2200    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
2201
2202    pPriv->isOn = TRUE;
2203#if 0
2204    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
2205	REGION_EMPTY(pScreen, &portPriv->clip);
2206	UpdateCurrentTime();
2207	portPriv->videoStatus = FREE_TIMER;
2208	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
2209    }
2210#endif
2211
2212    return Success;
2213}
2214
2215
2216static void
2217SavageInitOffscreenImages(ScreenPtr pScreen)
2218{
2219    XF86OffscreenImagePtr offscreenImages;
2220    SavagePtr psav = SAVPTR(xf86Screens[pScreen->myNum]);
2221
2222    /* need to free this someplace */
2223    if (!psav->offscreenImages) {
2224	if(!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
2225	    return;
2226	psav->offscreenImages = offscreenImages;
2227    } else {
2228	offscreenImages = psav->offscreenImages;
2229    }
2230
2231    offscreenImages[0].image = &Images[0];
2232    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
2233			       VIDEO_CLIP_TO_VIEWPORT;
2234    offscreenImages[0].alloc_surface = SavageAllocateSurface;
2235    offscreenImages[0].free_surface = SavageFreeSurface;
2236    offscreenImages[0].display = SavageDisplaySurface;
2237    offscreenImages[0].stop = SavageStopSurface;
2238    offscreenImages[0].setAttribute = SavageSetSurfaceAttribute;
2239    offscreenImages[0].getAttribute = SavageGetSurfaceAttribute;
2240    offscreenImages[0].max_width = 1024;
2241    offscreenImages[0].max_height = 1024;
2242    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
2243    offscreenImages[0].attributes = Attributes;
2244
2245    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2246}
2247
2248