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