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, (unsigned long)MMIO_IN32( psav->MapBase, offset ), value );
308    MMIO_OUT32( psav->MapBase, offset, value );
309    ErrorF( " now %08lx\n", (unsigned long)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#ifdef SAVAGEDRI
1041    SavagePtr psav = SAVPTR(pScrn);
1042#endif
1043
1044    xf86ErrorFVerb(XVTRACE,"SavageStopVideo\n");
1045
1046    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1047
1048    if(shutdown) {
1049      /*SavageClipVWindow(pScrn);*/
1050 	SavageStreamsOff( pScrn );
1051
1052#ifdef SAVAGEDRI
1053	if (pPriv->agpBufferMap != NULL) {
1054	    SAVAGEDRIServerPrivatePtr pSAVAGEDRIServer = psav->DRIServerInfo;
1055
1056            /* agpXVideo is reused to implement UploadToScreen in EXA */
1057            if (!psav->useEXA) {
1058	        drmUnmap(pPriv->agpBufferMap, pSAVAGEDRIServer->agpXVideo.size);
1059	        pSAVAGEDRIServer->agpXVideo.map = NULL;
1060            }
1061	    pPriv->agpBufferMap = NULL;
1062	    pPriv->agpBufferOffset = 0;
1063	}
1064	pPriv->tried_agp = FALSE;
1065#endif
1066
1067        if (pPriv->video_memory != NULL) {
1068	    SavageFreeMemory(pScrn, pPriv->video_memory);
1069	    pPriv->video_memory = NULL;
1070        }
1071        if (pPriv->video_planarmem != NULL) {
1072	    SavageFreeMemory(pScrn, pPriv->video_planarmem);
1073	    pPriv->video_planarmem = NULL;
1074        }
1075	pPriv->videoStatus = 0;
1076    } else {
1077	if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
1078	    pPriv->videoStatus |= OFF_TIMER;
1079	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
1080	}
1081    }
1082}
1083
1084
1085static int
1086SavageSetPortAttribute(
1087    ScrnInfoPtr pScrn,
1088    Atom attribute,
1089    INT32 value,
1090    pointer data
1091){
1092    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1093    SavagePtr psav = SAVPTR(pScrn);
1094
1095    if(attribute == xvColorKey) {
1096	pPriv->colorKey = value;
1097	if( psav->videoFlags & VF_STREAMS_ON)
1098	    SavageSetColorKey( pScrn );
1099	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1100    }
1101    else if( attribute == xvBrightness) {
1102	if((value < -128) || (value > 127))
1103	    return BadValue;
1104	pPriv->brightness = value;
1105	if( psav->videoFlags & VF_STREAMS_ON)
1106	    SavageSetColor( pScrn );
1107    }
1108    else if( attribute == xvContrast) {
1109	if((value < 0) || (value > 255))
1110	    return BadValue;
1111	pPriv->contrast = value;
1112	if( psav->videoFlags & VF_STREAMS_ON)
1113	    SavageSetColor( pScrn );
1114    }
1115    else if( attribute == xvSaturation) {
1116	if((value < 0) || (value > 255))
1117	    return BadValue;
1118	pPriv->saturation = value;
1119	if( psav->videoFlags & VF_STREAMS_ON)
1120	    SavageSetColor( pScrn );
1121    }
1122    else if( attribute == xvHue) {
1123	if((value < -180) || (value > 180))
1124	    return BadValue;
1125	pPriv->hue = value;
1126	if( psav->videoFlags & VF_STREAMS_ON)
1127	    SavageSetColor( pScrn );
1128    }
1129    else if( attribute == xvInterpolation) {
1130        if((value < 0) || (value > 1))
1131            return BadValue;
1132        if (value == 1)
1133            pPriv->interpolation = TRUE;
1134	else
1135	    pPriv->interpolation = FALSE;
1136    }
1137    else
1138	return BadMatch;
1139
1140    return Success;
1141}
1142
1143
1144static int
1145SavageGetPortAttribute(
1146  ScrnInfoPtr pScrn,
1147  Atom attribute,
1148  INT32 *value,
1149  pointer data
1150){
1151    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1152
1153    if(attribute == xvColorKey) {
1154	*value = pPriv->colorKey;
1155    }
1156    else if( attribute == xvBrightness ) {
1157	*value = pPriv->brightness;
1158    }
1159    else if( attribute == xvContrast ) {
1160	*value = pPriv->contrast;
1161    }
1162    else if( attribute == xvHue ) {
1163	*value = pPriv->hue;
1164    }
1165    else if( attribute == xvSaturation ) {
1166	*value = pPriv->saturation;
1167    }
1168    else if( attribute == xvInterpolation ) {
1169        *value = pPriv->interpolation;
1170    }
1171    else return BadMatch;
1172
1173    return Success;
1174}
1175
1176static void
1177SavageQueryBestSize(
1178  ScrnInfoPtr pScrn,
1179  Bool motion,
1180  short vid_w, short vid_h,
1181  short drw_w, short drw_h,
1182  unsigned int *p_w, unsigned int *p_h,
1183  pointer data
1184){
1185    /* What are the real limits for the Savage? */
1186
1187    *p_w = drw_w;
1188    *p_h = drw_h;
1189
1190    if(*p_w > 16384) *p_w = 16384;
1191}
1192
1193/* SavageCopyPlanarDataBCI() causes artifacts on the screen when used on savage4.
1194 * It's probably something with the BCI.  Maybe we need a waitforidle() or
1195 * something...
1196 */
1197static void
1198SavageCopyPlanarDataBCI(
1199    ScrnInfoPtr pScrn,
1200    unsigned char *srcY, /* Y */
1201    unsigned char *srcV, /* V */
1202    unsigned char *srcU, /* U */
1203    unsigned char *dst,
1204    unsigned char * planarPtr,
1205    unsigned long planarOffset,
1206    int srcPitch, int srcPitch2,
1207    int dstPitch,
1208    int h,int w,
1209    Bool isAGP)
1210{
1211    SavagePtr psav = SAVPTR(pScrn);
1212
1213    /* for pixel transfer */
1214    unsigned long offsetY = planarOffset;
1215    unsigned long offsetV = offsetY +  srcPitch * h;
1216    unsigned long offsetU = offsetV +  srcPitch2 * (h>>1);
1217    unsigned long dstOffset  = (unsigned long)dst - (unsigned long)psav->FBBase;
1218    unsigned char memType;
1219
1220    BCI_GET_PTR;
1221
1222    /* copy Y planar */
1223    memcpy(planarPtr, srcY, srcPitch * h);
1224
1225    /* copy V planar */
1226    planarPtr = planarPtr + srcPitch * h;
1227    memcpy(planarPtr, srcV, srcPitch2 * (h>>1));
1228
1229    /* copy U planar */
1230    planarPtr = planarPtr + srcPitch2 * (h>>1);
1231    memcpy(planarPtr, srcU, srcPitch2 * (h>>1));
1232
1233    memType = isAGP ? 3 : 0;
1234
1235    /*
1236     * Transfer pixel data from one memory location to another location
1237     * and reformat the data during the transfer
1238     * a. program BCI51 to specify the source information
1239     * b. program BCI52 to specify the destination information
1240     * c. program BCI53 to specify the source dimensions
1241     * d. program BCI54 to specify the destination dimensions
1242     * e. (if the data is in YCbCr420 format)program BCI55,BCI56,BCI57 to
1243     *    locations of the Y,Cb,and Cr data
1244     * f. program BCI50(command=011) to specify the formatting options and
1245     *    kick off the transfer
1246     * this command can be used for color space conversion(YCbCr to RGB)
1247     * or for oversampling, but not for both simultaneously. it can also be
1248     * used to do mastered image transfer when the source is tiled
1249     */
1250
1251    w = (w+0xf)&0xff0;
1252    psav->WaitQueue(psav,11);
1253    BCI_SEND(BCI_SET_REGISTER | BCI_SET_REGISTER_COUNT(7) | 0x51);
1254    BCI_SEND(offsetY | memType);
1255    BCI_SEND(dstOffset);
1256    BCI_SEND(((h-1)<<16)|((w-1)>>3));
1257    BCI_SEND(dstPitch >> 3);
1258    BCI_SEND(offsetU | memType);
1259    BCI_SEND(offsetV | memType);
1260    BCI_SEND((srcPitch2 << 16)| srcPitch2);
1261
1262    BCI_SEND(BCI_SET_REGISTER | BCI_SET_REGISTER_COUNT(1) | 0x50);
1263    BCI_SEND(0x00200003 | srcPitch);
1264
1265    BCI_SEND(0xC0170000);
1266}
1267
1268static void
1269SavageCopyData(
1270  unsigned char *src,
1271  unsigned char *dst,
1272  int srcPitch,
1273  int dstPitch,
1274  int h,
1275  int w
1276){
1277    w <<= 1;
1278    if (w == srcPitch && w == dstPitch) {
1279        memcpy(dst, src, w * h);
1280    } else
1281    while(h--) {
1282	memcpy(dst, src, w);
1283	src += srcPitch;
1284	dst += dstPitch;
1285    }
1286}
1287
1288static void
1289SavageCopyPlanarData(
1290   unsigned char *src1, /* Y */
1291   unsigned char *src2, /* V */
1292   unsigned char *src3, /* U */
1293   unsigned char *dst1,
1294   int srcPitch,
1295   int srcPitch2,
1296   int dstPitch,
1297   int h,
1298   int w
1299){
1300   CARD32 *dst = (CARD32*)dst1;
1301   int i, j;
1302
1303   dstPitch >>= 2;
1304   w >>= 1;
1305
1306   for(j = 0; j < h; j++) {
1307	for(i = 0; i < w; i++) {
1308/* Shouldn't this be 'if LITTLEENDIAN'? */
1309#if 1
1310	    dst[i] = src1[i << 1] | (src1[(i << 1) + 1] << 16) |
1311		     (src3[i] << 8) | (src2[i] << 24);
1312#else
1313	    dst[i] = (src1[i << 1] << 24) | (src1[(i << 1) + 1] << 8) |
1314		     (src3[i] << 0) | (src2[i] << 16);
1315#endif
1316	}
1317	dst += dstPitch;
1318	src1 += srcPitch;
1319	if(j & 1) {
1320	    src2 += srcPitch2;
1321	    src3 += srcPitch2;
1322	}
1323   }
1324}
1325
1326static void
1327SavageVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
1328{
1329    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1330    SavagePtr psav = SAVPTR(pScrn);
1331    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1332
1333    if (pPriv->video_memory == area)
1334        pPriv->video_memory = NULL;
1335    if (pPriv->video_planarmem == area)
1336        pPriv->video_planarmem = NULL;
1337}
1338
1339static CARD32
1340SavageAllocateMemory(
1341    ScrnInfoPtr pScrn,
1342    void **mem_struct,
1343    int size
1344){
1345    ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1346    SavagePtr psav = SAVPTR(pScrn);
1347    int offset = 0;
1348
1349    if (psav->useEXA) {
1350	ExaOffscreenArea *area = *mem_struct;
1351
1352	if (area != NULL) {
1353	    if (area->size >= size)
1354		return area->offset;
1355
1356	    exaOffscreenFree(pScrn->pScreen, area);
1357	}
1358
1359	area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, SavageVideoSave,
1360				 NULL);
1361	*mem_struct = area;
1362	if (area == NULL)
1363	    return 0;
1364	offset = area->offset;
1365    }
1366
1367    if (!psav->useEXA) {
1368	FBLinearPtr linear = *mem_struct;
1369	int cpp = pScrn->bitsPerPixel / 8;
1370
1371	/* XAA allocates in units of pixels at the screen bpp, so adjust size
1372	 * appropriately.
1373	 */
1374	size = (size + cpp - 1) / cpp;
1375
1376	if (linear) {
1377	    if(linear->size >= size)
1378		return linear->offset * cpp;
1379
1380	    if(xf86ResizeOffscreenLinear(linear, size))
1381		return linear->offset * cpp;
1382
1383	    xf86FreeOffscreenLinear(linear);
1384	}
1385
1386	linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1387						NULL, NULL, NULL);
1388	*mem_struct = linear;
1389
1390	if (!linear) {
1391	    int max_size;
1392
1393	    xf86QueryLargestOffscreenLinear(pScreen, &max_size, 16,
1394					    PRIORITY_EXTREME);
1395
1396	    if(max_size < size)
1397		return 0;
1398
1399	    xf86PurgeUnlockedOffscreenAreas(pScreen);
1400	    linear = xf86AllocateOffscreenLinear(pScreen, size, 16,
1401						     NULL, NULL, NULL);
1402	    *mem_struct = linear;
1403	    if (!linear)
1404		return 0;
1405	}
1406	offset = linear->offset * cpp;
1407    }
1408
1409    return offset;
1410}
1411
1412static void
1413SavageFreeMemory(
1414   ScrnInfoPtr pScrn,
1415   void *mem_struct
1416){
1417    SavagePtr psav = SAVPTR(pScrn);
1418
1419    if (psav->useEXA) {
1420	ExaOffscreenArea *area = mem_struct;
1421
1422	if (area != NULL)
1423	    exaOffscreenFree(pScrn->pScreen, area);
1424    }
1425    if (!psav->useEXA) {
1426	FBLinearPtr linear = mem_struct;
1427
1428	if (linear != NULL)
1429	    xf86FreeOffscreenLinear(linear);
1430    }
1431}
1432
1433static void
1434SavageSetBlend(ScrnInfoPtr pScrn, int id)
1435{
1436    SavagePtr psav = SAVPTR(pScrn);
1437
1438    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
1439    {
1440	psav->blendBase = GetBlendForFourCC( id );
1441	xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1442	if (psav->IsSecondary) {
1443	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1444	} else if (psav->IsPrimary) {
1445	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1446	} else {
1447	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
1448#if 0
1449	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
1450#endif
1451	}
1452    } else if (psav->Chipset == S3_SAVAGE2000) {
1453      psav->blendBase = GetBlendForFourCC2000( id );
1454      xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
1455      if (id != FOURCC_YV12)
1456	OUTREG( BLEND_CONTROL,
1457		((psav->blendBase << 24) | (8 << 2) /*| 0x20000000*/));
1458      else
1459	OUTREG( BLEND_CONTROL,
1460		((psav->blendBase << 24) | (8 << 2) /*| 0x10000000*/));
1461    }
1462
1463    psav->videoFourCC = id;
1464}
1465
1466static void
1467SavageDisplayVideoOld(
1468    ScrnInfoPtr pScrn,
1469    int id,
1470    int offset,
1471    short width, short height,
1472    int pitch,
1473    int x1, int y1, int x2, int y2,
1474    BoxPtr dstBox,
1475    short src_w, short src_h,
1476    short drw_w, short drw_h
1477){
1478    SavagePtr psav = SAVPTR(pScrn);
1479    vgaHWPtr hwp = VGAHWPTR(pScrn);
1480    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1481    /*DisplayModePtr mode = pScrn->currentMode;*/
1482    int vgaCRIndex, vgaCRReg, vgaIOBase;
1483    CARD32 ssControl;
1484    int scalratio;
1485
1486
1487    vgaIOBase = hwp->IOBase;
1488    vgaCRIndex = vgaIOBase + 4;
1489    vgaCRReg = vgaIOBase + 5;
1490#if 0
1491    if ( psav->videoFourCC != id ) {
1492	SavageSetBlend(pScrn,id);
1493	SavageResetVideo(pScrn);
1494    }
1495#endif
1496    if( psav->videoFourCC != id )
1497      SavageStreamsOff(pScrn);
1498
1499    if( !(psav->videoFlags & VF_STREAMS_ON) )
1500      {
1501        SavageSetBlend(pScrn,id);
1502	SavageStreamsOn(pScrn);
1503	SavageResetVideo(pScrn);
1504	pPriv->lastKnownPitch = 0;
1505      }
1506
1507    if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)
1508	&& psav->FPExpansion) {
1509	drw_w = (drw_w * psav->XExp1) / psav->XExp2 + 1;
1510	drw_h = (drw_h * psav->YExp1) / psav->YExp2 + 1;
1511	dstBox->x1 = (dstBox->x1 * psav->XExp1) / psav->XExp2;
1512	dstBox->y1 = (dstBox->y1 * psav->YExp1) / psav->YExp2;
1513	dstBox->x2 = (dstBox->x2 * psav->XExp1) / psav->XExp2;
1514	dstBox->y2 = (dstBox->y2 * psav->YExp1) / psav->YExp2;
1515	dstBox->x1 += psav->displayXoffset;
1516	dstBox->y1 += psav->displayYoffset;
1517	dstBox->x2 += psav->displayXoffset;
1518	dstBox->y2 += psav->displayYoffset;
1519    }
1520
1521    /*
1522     * Process horizontal scaling
1523     *  upscaling and downscaling smaller than 2:1 controlled by MM8198
1524     *  MM8190 controls downscaling mode larger than 2:1
1525     *  Together MM8190 and MM8198 can set arbitrary downscale up to 64:1
1526     */
1527    scalratio = 0;
1528    ssControl = 0;
1529
1530    if (src_w >= (drw_w * 2)) {
1531        if (src_w < (drw_w * 4)) {
1532            ssControl |= HDSCALE_4;
1533            scalratio = HSCALING(src_w,(drw_w*4));
1534        } else if (src_w < (drw_w * 8)) {
1535            ssControl |= HDSCALE_8;
1536            scalratio = HSCALING(src_w,(drw_w*8));
1537        } else if (src_w < (drw_w * 16)) {
1538            ssControl |= HDSCALE_16;
1539            scalratio = HSCALING(src_w,(drw_w*16));
1540        } else if (src_w < (drw_w * 32)) {
1541            ssControl |= HDSCALE_32;
1542            scalratio = HSCALING(src_w,(drw_w*32));
1543        } else if (src_w < (drw_w * 64)) {
1544            ssControl |= HDSCALE_64;
1545            scalratio = HSCALING(src_w,(drw_w*64));
1546        } else {
1547            /* Request beyond maximum downscale! */
1548            ssControl |= HDSCALE_64;
1549            scalratio = HSCALING(2,1);
1550        }
1551    } else
1552        scalratio = HSCALING(src_w,drw_w);
1553
1554    ssControl |= src_w;
1555    /*ssControl |= (1 << 24);*/
1556    ssControl |= (GetBlendForFourCC(psav->videoFourCC) << 24);
1557#if 0
1558    /* Wait for VBLANK. */
1559    VerticalRetraceWait();
1560#endif
1561    OUTREG(SSTREAM_CONTROL_REG, ssControl);
1562    if (scalratio)
1563        OUTREG(SSTREAM_STRETCH_REG,scalratio);
1564
1565    /* Calculate vertical scale factor. */
1566    OUTREG(SSTREAM_VINITIAL_REG, 0 );
1567    /*OUTREG(SSTREAM_VSCALE_REG, (src_h << 15) / drw_h );*/
1568    OUTREG(SSTREAM_VSCALE_REG, VSCALING(src_h,drw_h));
1569
1570    /* Set surface location and stride. */
1571    OUTREG(SSTREAM_FBADDR0_REG, (offset + (x1>>15)) & (0x1ffffff & ~BASE_PAD) );
1572    OUTREG(SSTREAM_FBADDR1_REG, 0);
1573    OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
1574
1575    OUTREG(SSTREAM_WINDOW_START_REG, OS_XY(dstBox->x1, dstBox->y1) );
1576    OUTREG(SSTREAM_WINDOW_SIZE_REG, OS_WH(dstBox->x2-dstBox->x1,
1577                                          dstBox->y2-dstBox->y1));
1578
1579    /*
1580     * MM81E8:Secondary Stream Source Line Count
1581     *   bit_0~10: # of lines in the source image (before scaling)
1582     *   bit_15 = 1: Enable vertical interpolation
1583     *            0: Line duplicaion
1584     */
1585    /*
1586     * Vertical Interpolation is very bandwidth intensive.  Some savages can't
1587     * seem to handle it.  Default is line doubling.  --AGD
1588     */
1589    if (pPriv->interpolation) {
1590        if (src_w * 16 <= 0x3300) {
1591            OUTREG(SSTREAM_LINES_REG, 0x8000 | src_h );
1592	    OUTREG(FIFO_CONTROL, (INREG(FIFO_CONTROL) + 1));
1593        } else {
1594            OUTREG(SSTREAM_LINES_REG, src_h );
1595        }
1596    } else {
1597        OUTREG(SSTREAM_LINES_REG, src_h );
1598    }
1599
1600#if 0
1601    /* Set color key on primary. */
1602
1603    SavageSetColorKey( pScrn );
1604#endif
1605
1606    /* Set FIFO L2 on second stream. */
1607
1608    if( pPriv->lastKnownPitch != pitch )
1609    {
1610	unsigned char cr92;
1611
1612	pPriv->lastKnownPitch = pitch;
1613
1614	pitch = (pitch + 7) / 8;
1615	VGAOUT8(vgaCRIndex, 0x92);
1616	cr92 = VGAIN8(vgaCRReg);
1617	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1618	VGAOUT8(vgaCRIndex, 0x93);
1619	if (psav->bTiled && (( drw_h > src_h) || (drw_w > src_w)))
1620	    VGAOUT8(vgaCRReg, pitch | 0xf);
1621	else
1622	    VGAOUT8(vgaCRReg, pitch);
1623    }
1624}
1625
1626static void
1627SavageDisplayVideoNew(
1628    ScrnInfoPtr pScrn,
1629    int id,
1630    int offset,
1631    short width, short height,
1632    int pitch,
1633    int x1, int y1, int x2, int y2,
1634    BoxPtr dstBox,
1635    short src_w, short src_h,
1636    short drw_w, short drw_h
1637){
1638    SavagePtr psav = SAVPTR(pScrn);
1639    vgaHWPtr hwp = VGAHWPTR(pScrn);
1640    /*DisplayModePtr mode = pScrn->currentMode;*/
1641    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1642    int vgaCRIndex, vgaCRReg, vgaIOBase;
1643
1644
1645    vgaIOBase = hwp->IOBase;
1646    vgaCRIndex = vgaIOBase + 4;
1647    vgaCRReg = vgaIOBase + 5;
1648#if 0
1649    if ( psav->videoFourCC != id ) {
1650	SavageSetBlend(pScrn,id);
1651	SavageResetVideo(pScrn);
1652    }
1653#endif
1654    if( psav->videoFourCC != id )
1655      SavageStreamsOff(pScrn);
1656
1657    if( !(psav->videoFlags & VF_STREAMS_ON) )
1658      {
1659	SavageSetBlend(pScrn,id);
1660	SavageStreamsOn(pScrn);
1661	SavageResetVideo(pScrn);
1662	pPriv->lastKnownPitch = 0;
1663      }
1664
1665    /* Calculate horizontal and vertical scale factors. */
1666
1667    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
1668	    (psav->DisplayType == MT_LCD) &&
1669	    !psav->CrtOnly &&
1670	    !psav->TvOn)
1671    {
1672	drw_w = (drw_w * psav->XExp1) / psav->XExp2 + 1;
1673	drw_h = (drw_h * psav->YExp1) / psav->YExp2 + 1;
1674	dstBox->x1 = (dstBox->x1 * psav->XExp1) / psav->XExp2;
1675	dstBox->y1 = (dstBox->y1 * psav->YExp1) / psav->YExp2;
1676	dstBox->x2 = (dstBox->x2 * psav->XExp1) / psav->XExp2;
1677	dstBox->y2 = (dstBox->y2 * psav->YExp1) / psav->YExp2;
1678	dstBox->x1 += psav->displayXoffset;
1679	dstBox->y1 += psav->displayYoffset;
1680	dstBox->x2 += psav->displayXoffset;
1681	dstBox->y2 += psav->displayYoffset;
1682    }
1683
1684	if (psav->IsSecondary) {
1685	    OUTREG(SEC_STREAM2_HSCALING,
1686	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1687	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1688	    OUTREG(SEC_STREAM2_VSCALING,
1689	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1690	} else if (psav->IsPrimary) {
1691	    OUTREG(SEC_STREAM_HSCALING,
1692	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1693	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1694	    OUTREG(SEC_STREAM_VSCALING,
1695	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1696	} else {
1697	    OUTREG(SEC_STREAM_HSCALING,
1698	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1699	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1700	    OUTREG(SEC_STREAM_VSCALING,
1701	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1702#if 0
1703	    OUTREG(SEC_STREAM2_HSCALING,
1704	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
1705	    /* BUGBUG need to add 00040000 if src stride > 2048 */
1706	    OUTREG(SEC_STREAM2_VSCALING,
1707	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
1708#endif
1709	}
1710
1711    /*
1712     * Set surface location and stride.  We use x1>>15 because all surfaces
1713     * are 2 bytes/pixel.
1714     */
1715
1716    if (psav->IsSecondary) {
1717        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1718	   & (0x7ffffff & ~BASE_PAD));
1719        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1720        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1721        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1722	   | (dstBox->y2 - dstBox->y1) );
1723    } else if (psav->IsPrimary) {
1724        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1725	   & (0x7ffffff & ~BASE_PAD));
1726        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1727        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1728        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1729	   | (dstBox->y2 - dstBox->y1) );
1730    } else {
1731        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15))
1732	   & (0x7ffffff & ~BASE_PAD));
1733        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
1734        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1735        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1736	   | (dstBox->y2 - dstBox->y1) );
1737#if 0
1738        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15))
1739	   & (0x7ffffff & ~BASE_PAD));
1740        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
1741        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
1742        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16)
1743	   | (dstBox->y2 - dstBox->y1) );
1744#endif
1745    }
1746
1747#if 0
1748    /* Set color key on primary. */
1749
1750    SavageSetColorKey( pScrn );
1751#endif
1752
1753    /* Set FIFO L2 on second stream. */
1754    /* Is CR92 shadowed for crtc2? -- AGD */
1755    if( pPriv->lastKnownPitch != pitch )
1756    {
1757	unsigned char cr92;
1758
1759	pPriv->lastKnownPitch = pitch;
1760	pitch = (pitch + 7) / 8 - 4;
1761	VGAOUT8(vgaCRIndex, 0x92);
1762	cr92 = VGAIN8(vgaCRReg);
1763	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1764	VGAOUT8(vgaCRIndex, 0x93);
1765	VGAOUT8(vgaCRReg, pitch);
1766    }
1767}
1768
1769static void
1770SavageDisplayVideo2000(
1771    ScrnInfoPtr pScrn,
1772    int id,
1773    int offset,
1774    short width, short height,
1775    int pitch,
1776    int x1, int y1, int x2, int y2,
1777    BoxPtr dstBox,
1778    short src_w, short src_h,
1779    short drw_w, short drw_h
1780){
1781    SavagePtr psav = SAVPTR(pScrn);
1782#if 0
1783    vgaHWPtr hwp = VGAHWPTR(pScrn);
1784#endif
1785    /*DisplayModePtr mode = pScrn->currentMode;*/
1786    SavagePortPrivPtr pPriv = psav->adaptor->pPortPrivates[0].ptr;
1787#if 0
1788    int vgaCRIndex, vgaCRReg, vgaIOBase;
1789#endif
1790    CARD32 addr0;
1791#if 0
1792    CARD32 addr1, addr2;
1793#endif
1794
1795#if 0
1796    vgaIOBase = hwp->IOBase;
1797    vgaCRIndex = vgaIOBase + 4;
1798    vgaCRReg = vgaIOBase + 5;
1799#endif
1800
1801
1802    if( psav->videoFourCC != id )
1803        SavageStreamsOff(pScrn);
1804
1805    if( !(psav->videoFlags & VF_STREAMS_ON) )
1806    {
1807        SavageSetBlend(pScrn,id);
1808        SavageStreamsOn(pScrn);
1809        SavageResetVideo(pScrn);
1810        pPriv->lastKnownPitch = 0;
1811    }
1812
1813    if (src_w > drw_w)
1814        OUTREG(SEC_STREAM_SRC_START_2000, 0);
1815    else
1816        OUTREG(SEC_STREAM_SRC_START_2000, SRCSTART(x1, y1));
1817
1818    /*OUTREG(SEC_STREAM_SRC_SIZE_2000, SRCSIZE(src_w, src_h));*/
1819    OUTREG(SEC_STREAM_SRC_SIZE_2000,
1820	   SRCSIZE((dstBox->x2-dstBox->x1), (dstBox->y2-dstBox->y1)));
1821    /*
1822        buffersize = (src_w * src_h * 2) / 4096;
1823	  OUTREG(SEC_STREAM_BUFFERSIZE_2000, (buffersize & 0xffffff) << 12);
1824    */
1825
1826    /*SavageResetVideo(pScrn);*/
1827
1828    if( src_w > drw_w )
1829	OUTREG(SEC_STREAM_HSCALE_NORMALIZE, HSCALING_NORMALIZE(drw_w,src_w));
1830    else
1831        OUTREG(SEC_STREAM_HSCALE_NORMALIZE, (2048 << 16));
1832
1833    /* Calculate horizontal and vertical scale factors. */
1834    if ((src_w > drw_w) || (src_h > drw_h))
1835        OUTREG(SEC_STREAM_HSCALING, (HSCALING_2000(src_w,drw_w)) | 0x01000000);
1836    else
1837        OUTREG(SEC_STREAM_HSCALING, HSCALING_2000(src_w,drw_w));
1838
1839    OUTREG(SEC_STREAM_VSCALING, VSCALING_2000(src_h,drw_h));
1840
1841    /*
1842     * Set surface location and stride.  We use x1>>15 because all surfaces
1843     * are 2 bytes/pixel.
1844     */
1845
1846    addr0 = offset + (x1>>15); /* Y in YCbCr420 */
1847#if 0
1848    addr1 = addr0 + (width * height); /* Cb in in YCbCr420 */
1849    addr2 = addr1 + ((width * height) / 4); /* Cr in in YCbCr420 */
1850#endif
1851    OUTREG(SEC_STREAM_FBUF_ADDR0, (addr0) & (0x3fffff & ~BASE_PAD));
1852#if 0
1853    OUTREG(SEC_STREAM_FBUF_ADDR1, (addr1) & (0x3fffff & ~BASE_PAD));
1854    OUTREG(SEC_STREAM_FBUF_ADDR2, (addr2) & (0x3fffff & ~BASE_PAD));
1855#endif
1856
1857    OUTREG(SEC_STREAM_WINDOW_START, XY_2000(dstBox->x1,dstBox->y1));
1858    OUTREG(SEC_STREAM_WINDOW_SZ,
1859	   WH_2000((dstBox->x2-dstBox->x1),(dstBox->y2-dstBox->y1)));
1860
1861    /*pitch = width * 2;*/
1862    OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff);
1863#if 0
1864    /* Y stride + CbCr stride in YCbCr420 */
1865    OUTREG(SEC_STREAM_STRIDE, (pitch & 0xfff) + ((pitch & 0xfff) << 15));
1866#endif
1867
1868#if 0
1869    /* Set color key on primary. */
1870
1871    SavageSetColorKey2000( pScrn );
1872#endif
1873
1874#if 0
1875    /* Set FIFO L2 on second stream. */
1876    if( pPriv->lastKnownPitch != pitch )
1877    {
1878	unsigned char cr92;
1879
1880	pPriv->lastKnownPitch = pitch;
1881	pitch = (pitch + 7) / 8 - 4;
1882	VGAOUT8(vgaCRIndex, 0x92);
1883	cr92 = VGAIN8(vgaCRReg);
1884	VGAOUT8(vgaCRReg, (cr92 & 0x40) | (pitch >> 8) | 0x80);
1885	VGAOUT8(vgaCRIndex, 0x93);
1886	VGAOUT8(vgaCRReg, pitch);
1887    }
1888#endif
1889}
1890
1891static void
1892SavageFillKeyHelper(DrawablePtr pDraw, uint32_t colorKey, RegionPtr clipBoxes)
1893{
1894#if HAVE_XV_DRAWABLE_HELPER
1895    xf86XVFillKeyHelperDrawable(pDraw, colorKey, clipBoxes);
1896#else
1897    xf86XVFillKeyHelper(pDraw->pScreen, colorKey, clipBoxes);
1898#endif
1899}
1900
1901static int
1902SavagePutImage(
1903    ScrnInfoPtr pScrn,
1904    short src_x, short src_y,
1905    short drw_x, short drw_y,
1906    short src_w, short src_h,
1907    short drw_w, short drw_h,
1908    int id, unsigned char* buf,
1909    short width, short height,
1910    Bool sync,
1911    RegionPtr clipBoxes, pointer data,
1912    DrawablePtr pDraw
1913){
1914    SavagePortPrivPtr pPriv = (SavagePortPrivPtr)data;
1915    SavagePtr psav = SAVPTR(pScrn);
1916#ifdef SAVAGEDRI
1917    ScreenPtr pScreen = pScrn->pScreen;
1918#endif
1919    INT32 x1, x2, y1, y2;
1920    unsigned char *dst_start;
1921    int new_size, offset, offsetV=0, offsetU=0;
1922    int srcPitch, srcPitch2=0, dstPitch;
1923    int planarFrameSize;
1924    int top, left, npixels, nlines;
1925    BoxRec dstBox;
1926    CARD32 tmp;
1927/*    xf86ErrorFVerb(XVTRACE,"SavagePutImage\n"); */
1928    if(drw_w > 16384) drw_w = 16384;
1929
1930    /* Clip */
1931    x1 = src_x;
1932    x2 = src_x + src_w;
1933    y1 = src_y;
1934    y2 = src_y + src_h;
1935
1936    dstBox.x1 = drw_x;
1937    dstBox.x2 = drw_x + drw_w;
1938    dstBox.y1 = drw_y;
1939    dstBox.y2 = drw_y + drw_h;
1940
1941    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
1942		REGION_EXTENTS(pScreen, clipBoxes), width, height);
1943
1944    drw_w = dstBox.x2 - dstBox.x1;
1945    drw_h = dstBox.y2 - dstBox.y1;
1946    src_w = ( x2 - x1 ) >> 16;
1947    src_h = ( y2 - y1 ) >> 16;
1948
1949    if((x1 >= x2) || (y1 >= y2))
1950	return Success;
1951
1952    dstBox.x1 -= pScrn->frameX0;
1953    dstBox.x2 -= pScrn->frameX0;
1954    dstBox.y1 -= pScrn->frameY0;
1955    dstBox.y2 -= pScrn->frameY0;
1956
1957    /* All formats directly displayable by Savage are packed and 2 bytes per pixel */
1958    dstPitch = ((width << 1) + 15) & ~15;
1959    new_size = dstPitch * height;
1960
1961    switch(id) {
1962    case FOURCC_Y211:		/* Y211 */
1963        srcPitch = width;
1964	break;
1965    case FOURCC_YV12:		/* YV12 */
1966	srcPitch = (width + 3) & ~3;
1967	offsetV = srcPitch * height;
1968	srcPitch2 = ((width >> 1) + 3) & ~3;
1969	offsetU = (srcPitch2 * (height >> 1)) + offsetV;
1970	break;
1971    case FOURCC_I420:
1972	srcPitch = (width + 3) & ~3;
1973	offsetU = srcPitch * height;
1974	srcPitch2 = ((width >> 1) + 3) & ~3;
1975	offsetV = (srcPitch2 * (height >> 1)) + offsetU;
1976	break;
1977    case FOURCC_RV15:		/* RGB15 */
1978    case FOURCC_RV16:		/* RGB16 */
1979    case FOURCC_YUY2:		/* YUY2 */
1980    default:
1981	srcPitch = (width << 1);
1982	break;
1983    }
1984
1985    /* Calculate required memory for all planar frames */
1986    planarFrameSize = 0;
1987    if (srcPitch2 != 0 && S3_SAVAGE4_SERIES(psav->Chipset) && psav->BCIforXv) {
1988        new_size = ((new_size + 0xF) & ~0xF);
1989        planarFrameSize = srcPitch * height + srcPitch2 * height;
1990    }
1991
1992    /* Check whether AGP buffers can be allocated. If not, fall back to ordinary
1993       upload to framebuffer (slower) */
1994#ifdef SAVAGEDRI
1995    if (!pPriv->tried_agp && !psav->IsPCI && psav->drmFD > 0 && psav->DRIServerInfo != NULL) {
1996	SAVAGEDRIServerPrivatePtr pSAVAGEDRIServer = psav->DRIServerInfo;
1997
1998	pPriv->tried_agp = TRUE;
1999	if (pSAVAGEDRIServer->agpXVideo.size >= max(new_size, planarFrameSize)) {
2000	    if (pSAVAGEDRIServer->agpXVideo.map == NULL &&
2001	        drmMap( psav->drmFD,
2002		pSAVAGEDRIServer->agpXVideo.handle,
2003		pSAVAGEDRIServer->agpXVideo.size,
2004		&pSAVAGEDRIServer->agpXVideo.map ) < 0 ) {
2005
2006		xf86DrvMsg( pScreen->myNum, X_ERROR, "[agp] XVideo: Could not map agpXVideo \n" );
2007		pPriv->agpBufferOffset = 0;
2008		pPriv->agpBufferMap = NULL;
2009	    } else {
2010		pPriv->agpBufferMap = pSAVAGEDRIServer->agpXVideo.map;
2011		pPriv->agpBufferOffset = pSAVAGEDRIServer->agpXVideo.offset;
2012		pPriv->agpBase = drmAgpBase(psav->drmFD);
2013#if 0
2014		xf86DrvMsg( pScreen->myNum, X_INFO,
2015		       "[agp] agpXVideo mapped at 0x%08lx aperture=0x%08x offset=0x%08lx\n",
2016		       (unsigned long)pPriv->agpBufferMap, pPriv->agpBase, pPriv->agpBufferOffset);
2017#endif
2018	    }
2019	} else {
2020	    /* This situation is expected if AGPforXv is disabled, otherwise report. */
2021	    if (pSAVAGEDRIServer->agpXVideo.size > 0) {
2022		xf86DrvMsg( pScreen->myNum, X_ERROR,
2023		    "[agp] XVideo: not enough space in buffer (got %ld bytes, required %d bytes).\n",
2024	    	    (long int)pSAVAGEDRIServer->agpXVideo.size, max(new_size, planarFrameSize));
2025	    }
2026	    pPriv->agpBufferMap = NULL;
2027	    pPriv->agpBufferOffset = 0;
2028	}
2029    }
2030#endif /* SAVAGEDRI */
2031
2032
2033    /* Buffer for final packed frame */
2034    pPriv->video_offset = SavageAllocateMemory(
2035	pScrn, &pPriv->video_memory,
2036	new_size);
2037    if (pPriv->video_offset == 0)
2038        return BadAlloc;
2039
2040    /* Packed format cases */
2041    if (planarFrameSize == 0) {
2042	pPriv->video_planarbuf = 0;
2043
2044    /* Planar format cases */
2045    } else {
2046	/* Hardware-assisted planar conversion only works on 16-byte aligned addresses */
2047	pPriv->video_planarbuf = SavageAllocateMemory(
2048	    pScrn, &pPriv->video_planarmem,
2049	    ((planarFrameSize + 0xF) & ~0xF));
2050	if (pPriv->video_planarbuf != 0) {
2051	    /* TODO: stop any pending conversions when buffers change... */
2052	    pPriv->video_planarbuf = ((pPriv->video_planarbuf + 0xF) & ~0xF);
2053	} else {
2054	    /* Fallback using software conversion */
2055	}
2056    }
2057
2058    /* copy data */
2059    top = y1 >> 16;
2060    left = (x1 >> 16) & ~1;
2061    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
2062    left <<= 1;
2063
2064    offset = (pPriv->video_offset) + (top * dstPitch);
2065    dst_start = (psav->FBBase + ((offset + left) & ~BASE_PAD));
2066
2067    switch(id) {
2068    case FOURCC_YV12:		/* YV12 */
2069    case FOURCC_I420:
2070	top &= ~1;
2071	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
2072	offsetU += tmp;
2073	offsetV += tmp;
2074	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
2075        if (S3_SAVAGE4_SERIES(psav->Chipset) && psav->BCIforXv && (npixels & 0xF) == 0 && pPriv->video_planarbuf != 0) {
2076#ifdef SAVAGEDRI
2077            if (pPriv->agpBufferMap != NULL) {
2078		/* Using copy to AGP memory */
2079		SavageCopyPlanarDataBCI(
2080		    pScrn,
2081		    buf + (top * srcPitch) + (left >> 1),
2082		    buf + offsetV,
2083		    buf + offsetU,
2084		    dst_start,
2085		    pPriv->agpBufferMap,
2086		    pPriv->agpBase + pPriv->agpBufferOffset,
2087		    srcPitch, srcPitch2, dstPitch, nlines, npixels, TRUE);
2088            } else
2089#endif /* SAVAGEDRI */
2090            {
2091		/* Using ordinary copy to framebuffer */
2092		SavageCopyPlanarDataBCI(
2093		    pScrn,
2094		    buf + (top * srcPitch) + (left >> 1),
2095		    buf + offsetV,
2096		    buf + offsetU,
2097		    dst_start,
2098		    (unsigned char *)psav->FBBase + pPriv->video_planarbuf,
2099		    pPriv->video_planarbuf,
2100		    srcPitch, srcPitch2, dstPitch, nlines, npixels, FALSE);
2101	    }
2102        } else {
2103	    SavageCopyPlanarData(
2104	    	buf + (top * srcPitch) + (left >> 1),
2105	    	buf + offsetV,
2106	    	buf + offsetU,
2107	    	dst_start, srcPitch, srcPitch2, dstPitch, nlines, npixels);
2108        }
2109	break;
2110    case FOURCC_Y211:		/* Y211 */
2111    case FOURCC_RV15:		/* RGB15 */
2112    case FOURCC_RV16:		/* RGB16 */
2113    case FOURCC_YUY2:		/* YUY2 */
2114    default:
2115	buf += (top * srcPitch) + left;
2116	nlines = ((y2 + 0xffff) >> 16) - top;
2117	SavageCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
2118	break;
2119    }
2120
2121    /* We need to enable the video before we draw the chroma color.
2122       Otherwise, we get blue flashes. */
2123
2124    SavageDisplayVideo(pScrn, id, offset, width, height, dstPitch,
2125	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
2126
2127    /* update cliplist */
2128    if(!REGION_EQUAL(pScreen, &pPriv->clip, clipBoxes)) {
2129	REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
2130	/* draw these */
2131	SavageFillKeyHelper(pDraw, pPriv->colorKey, clipBoxes);
2132
2133    }
2134
2135    pPriv->videoStatus = CLIENT_VIDEO_ON;
2136
2137    return Success;
2138}
2139
2140static int
2141SavageQueryImageAttributes(
2142  ScrnInfoPtr pScrn,
2143  int id,
2144  unsigned short *w, unsigned short *h,
2145  int *pitches, int *offsets
2146){
2147    int size, tmp;
2148
2149    if(*w > 1024) *w = 1024;
2150    if(*h > 1024) *h = 1024;
2151
2152    *w = (*w + 1) & ~1;
2153    if(offsets) offsets[0] = 0;
2154
2155    switch(id) {
2156    case FOURCC_IA44:
2157        if (pitches) pitches[0]=*w;
2158        size=(*w)*(*h);
2159        break;
2160    case FOURCC_Y211:
2161	size = *w << 2;
2162	if(pitches) pitches[0] = size;
2163	size *= *h;
2164	break;
2165    case FOURCC_YV12:
2166    case FOURCC_I420:
2167	*h = (*h + 1) & ~1;
2168	size = (*w + 3) & ~3;
2169	if(pitches) pitches[0] = size;
2170	size *= *h;
2171	if(offsets) offsets[1] = size;
2172	tmp = ((*w >> 1) + 3) & ~3;
2173	if(pitches) pitches[1] = pitches[2] = tmp;
2174	tmp *= (*h >> 1);
2175	size += tmp;
2176	if(offsets) offsets[2] = size;
2177	size += tmp;
2178	break;
2179    case FOURCC_RV15:		/* RGB15 */
2180    case FOURCC_RV16:		/* RGB16 */
2181    case FOURCC_YUY2:
2182    default:
2183	size = *w << 1;
2184	if(pitches) pitches[0] = size;
2185	size *= *h;
2186	break;
2187    }
2188
2189    return size;
2190}
2191
2192/****************** Offscreen stuff ***************/
2193
2194typedef struct {
2195  void *surface_memory;
2196  Bool isOn;
2197} OffscreenPrivRec, * OffscreenPrivPtr;
2198
2199static int
2200SavageAllocateSurface(
2201    ScrnInfoPtr pScrn,
2202    int id,
2203    unsigned short w,
2204    unsigned short h,
2205    XF86SurfacePtr surface
2206){
2207    int offset, size;
2208    int pitch;
2209    void *surface_memory = NULL;
2210    OffscreenPrivPtr pPriv;
2211
2212    if((w > 1024) || (h > 1024))
2213	return BadAlloc;
2214
2215    w = (w + 1) & ~1;
2216    pitch = ((w << 1) + 15) & ~15;
2217    size = pitch * h;
2218
2219    offset = SavageAllocateMemory(pScrn, &surface_memory, size);
2220    if (offset == 0)
2221	return BadAlloc;
2222
2223    surface->width = w;
2224    surface->height = h;
2225
2226    if(!(surface->pitches = malloc(sizeof(int)))) {
2227	SavageFreeMemory(pScrn, surface_memory);
2228	return BadAlloc;
2229    }
2230    if(!(surface->offsets = malloc(sizeof(int)))) {
2231	free(surface->pitches);
2232	SavageFreeMemory(pScrn, surface_memory);
2233	return BadAlloc;
2234    }
2235    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
2236	free(surface->pitches);
2237	free(surface->offsets);
2238	SavageFreeMemory(pScrn, surface_memory);
2239	return BadAlloc;
2240    }
2241
2242    pPriv->surface_memory = surface_memory;
2243    pPriv->isOn = FALSE;
2244
2245    surface->pScrn = pScrn;
2246    surface->id = id;
2247    surface->pitches[0] = pitch;
2248    surface->offsets[0] = offset; /*area->box.y1 * fbpitch;*/
2249    surface->devPrivate.ptr = (pointer)pPriv;
2250
2251    return Success;
2252}
2253
2254static int
2255SavageStopSurface(
2256    XF86SurfacePtr surface
2257){
2258    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2259    xf86ErrorFVerb(XVTRACE,"SavageStopSurface\n");
2260
2261    if(pPriv->isOn) {
2262	/*SavagePtr psav = SAVPTR(surface->pScrn);*/
2263	/*SavageClipVWindow(surface->pScrn);*/
2264	SavageStreamsOff( surface->pScrn );
2265	pPriv->isOn = FALSE;
2266    }
2267
2268    return Success;
2269}
2270
2271
2272static int
2273SavageFreeSurface(
2274    XF86SurfacePtr surface
2275){
2276    ScrnInfoPtr pScrn = surface->pScrn;
2277    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2278
2279    if(pPriv->isOn)
2280	SavageStopSurface(surface);
2281    SavageFreeMemory(pScrn, pPriv->surface_memory);
2282    free(surface->pitches);
2283    free(surface->offsets);
2284    free(surface->devPrivate.ptr);
2285
2286    return Success;
2287}
2288
2289static int
2290SavageGetSurfaceAttribute(
2291    ScrnInfoPtr pScrn,
2292    Atom attribute,
2293    INT32 *value
2294){
2295    return SavageGetPortAttribute(pScrn, attribute, value,
2296			(pointer)(GET_PORT_PRIVATE(pScrn)));
2297}
2298
2299static int
2300SavageSetSurfaceAttribute(
2301    ScrnInfoPtr pScrn,
2302    Atom attribute,
2303    INT32 value
2304){
2305    return SavageSetPortAttribute(pScrn, attribute, value,
2306			(pointer)(GET_PORT_PRIVATE(pScrn)));
2307}
2308
2309
2310static int
2311SavageDisplaySurface(
2312    XF86SurfacePtr surface,
2313    short src_x, short src_y,
2314    short drw_x, short drw_y,
2315    short src_w, short src_h,
2316    short drw_w, short drw_h,
2317    RegionPtr clipBoxes
2318){
2319    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
2320    ScrnInfoPtr pScrn = surface->pScrn;
2321    ScreenPtr pScreen = pScrn->pScreen;
2322    SavagePortPrivPtr portPriv = GET_PORT_PRIVATE(pScrn);
2323    INT32 x1, y1, x2, y2;
2324    BoxRec dstBox;
2325    xf86ErrorFVerb(XVTRACE,"SavageDisplaySurface\n");
2326
2327    x1 = src_x;
2328    x2 = src_x + src_w;
2329    y1 = src_y;
2330    y2 = src_y + src_h;
2331
2332    dstBox.x1 = drw_x;
2333    dstBox.x2 = drw_x + drw_w;
2334    dstBox.y1 = drw_y;
2335    dstBox.y2 = drw_y + drw_h;
2336
2337    SavageClipVideo(&dstBox, &x1, &x2, &y1, &y2,
2338                	REGION_EXTENTS(pScreen, clipBoxes),
2339			surface->width, surface->height);
2340
2341    if((x1 >= x2) || (y1 >= y2))
2342	return Success;
2343
2344    dstBox.x1 -= pScrn->frameX0;
2345    dstBox.x2 -= pScrn->frameX0;
2346    dstBox.y1 -= pScrn->frameY0;
2347    dstBox.y2 -= pScrn->frameY0;
2348
2349    SavageDisplayVideo(pScrn, surface->id, surface->offsets[0],
2350	     surface->width, surface->height, surface->pitches[0],
2351	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
2352
2353    xf86XVFillKeyHelper(pScreen, portPriv->colorKey, clipBoxes);
2354
2355    pPriv->isOn = TRUE;
2356#if 0
2357    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
2358	REGION_EMPTY(pScreen, &portPriv->clip);
2359	UpdateCurrentTime();
2360	portPriv->videoStatus = FREE_TIMER;
2361	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
2362    }
2363#endif
2364
2365    return Success;
2366}
2367
2368
2369static void
2370SavageInitOffscreenImages(ScreenPtr pScreen)
2371{
2372    XF86OffscreenImagePtr offscreenImages;
2373    SavagePtr psav = SAVPTR(xf86ScreenToScrn(pScreen));
2374
2375    /* need to free this someplace */
2376    if (!psav->offscreenImages) {
2377	if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
2378	    return;
2379	psav->offscreenImages = offscreenImages;
2380    } else {
2381	offscreenImages = psav->offscreenImages;
2382    }
2383
2384    offscreenImages[0].image = &Images[0];
2385    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
2386			       VIDEO_CLIP_TO_VIEWPORT;
2387    offscreenImages[0].alloc_surface = SavageAllocateSurface;
2388    offscreenImages[0].free_surface = SavageFreeSurface;
2389    offscreenImages[0].display = SavageDisplaySurface;
2390    offscreenImages[0].stop = SavageStopSurface;
2391    offscreenImages[0].setAttribute = SavageSetSurfaceAttribute;
2392    offscreenImages[0].getAttribute = SavageGetSurfaceAttribute;
2393    offscreenImages[0].max_width = 1024;
2394    offscreenImages[0].max_height = 1024;
2395    offscreenImages[0].num_attributes = NUM_ATTRIBUTES;
2396    offscreenImages[0].attributes = Attributes;
2397
2398    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2399}
2400
2401