s3_video.c revision 340e3fbd
1/*
2 *      Copyright 2001  Ani Joshi <ajoshi@unixbox.com>
3 *
4 *      XFree86 4.x driver for S3 chipsets
5 *
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting documentation and
11 * that the name of Ani Joshi not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission.  Ani Joshi makes no representations
14 * about the suitability of this software for any purpose.  It is provided
15 * "as-is" without express or implied warranty.
16 *
17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 *
26 */
27/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/s3/s3_video.c,v 1.4tsi Exp $ */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "xf86.h"
34#include "xf86_OSproc.h"
35
36#include "compiler.h"
37
38#include "s3.h"
39#include "s3_reg.h"
40
41
42#define CLIENT_VIDEO_ON	0x04
43#define S3_MAX_PORTS	1
44#define NUM_FORMATS_OVERLAY 4
45#define NUM_FORMATS_TEXTURE 4
46
47
48static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn);
49static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr);
50static int S3SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
51static int S3GetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
52static void S3StopVideo(ScrnInfoPtr, pointer, Bool);
53static void S3QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
54                            unsigned int *, unsigned int *, pointer);
55static int  S3PutImage(ScrnInfoPtr, short, short, short, short, short,
56                       short, short, short, int, unsigned char*, short,
57                       short, Bool, RegionPtr, pointer, DrawablePtr);
58static int  S3QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
59                        	   unsigned short *,  int *, int *);
60static void S3ResetVideoOverlay(ScrnInfoPtr);
61
62
63
64void S3InitVideo(ScreenPtr pScreen)
65{
66	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
67	S3Ptr pS3 = S3PTR(pScrn);
68	XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
69	XF86VideoAdaptorPtr newAdaptor = NULL;
70	int num_adaptors;
71
72	if (((pScrn->bitsPerPixel == 16) ||
73	     (pScrn->bitsPerPixel == 24)) && (pS3->S3NewMMIO)) {
74		newAdaptor = S3SetupImageVideoOverlay(pScreen);
75		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
76	} else
77		return;
78
79	num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
80
81    	if(newAdaptor) {
82        	if(!num_adaptors) {
83            		num_adaptors = 1;
84            		adaptors = &newAdaptor;
85        	} else {
86            		newAdaptors =  /* need to free this someplace */
87                		xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
88            		if(newAdaptors) {
89                		memcpy(newAdaptors, adaptors, num_adaptors *
90                                       sizeof(XF86VideoAdaptorPtr));
91                		newAdaptors[num_adaptors] = newAdaptor;
92                		adaptors = newAdaptors;
93                		num_adaptors++;
94            		}
95        	}
96    	}
97
98    	if(num_adaptors)
99        	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
100
101    	if(newAdaptors)
102        	xfree(newAdaptors);
103}
104
105
106/* client libraries expect an encoding */
107static XF86VideoEncodingRec DummyEncoding[2] =
108{
109 	{   /* overlay limit */
110   		0,
111   		"XV_IMAGE",
112   		1024, 1024,
113   		{1, 1}
114 	},
115 	{  /* texture limit */
116   		0,
117   		"XV_IMAGE",
118   		2046, 2046,
119   		{1, 1}
120 	}
121};
122
123
124
125
126static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] =
127{
128  	/*{15, TrueColor},*/ {16, TrueColor}, {24, TrueColor} /* ,
129    	{15, DirectColor}*/, {16, DirectColor}, {24, DirectColor}
130};
131
132
133
134#define NUM_IMAGES 3
135
136static XF86ImageRec Images[NUM_IMAGES] =
137{
138  	XVIMAGE_YUY2,
139  	/* As in mga, YV12 & I420 are converted to YUY2 on the fly by */
140  	/* copy over conversion. */
141  	XVIMAGE_YV12,
142  	XVIMAGE_I420
143        /* XVIMAGE_UYVY */
144};
145
146
147
148static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute,
149				     INT32 value, pointer data)
150{
151	return BadMatch;
152}
153
154
155static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute,
156				     INT32 *value, pointer data)
157{
158	return BadMatch;
159}
160
161
162
163static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w,
164			    short vid_h, short drw_w, short drw_h,
165                            unsigned int *p_w, unsigned int *p_h,
166			    pointer data)
167{
168	*p_w = drw_w;
169	*p_h = drw_h;
170}
171
172
173
174static void S3ResetVideoOverlay(ScrnInfoPtr pScrn)
175{
176}
177
178
179static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn)
180{
181	S3Ptr pS3 = S3PTR(pScrn);
182	XF86VideoAdaptorPtr adapt;
183	S3PortPrivPtr pPriv;
184	int i;
185
186    	if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
187        	return NULL;
188
189    	if(!(pPriv = xcalloc(1, sizeof(S3PortPrivRec)  +
190        	                (sizeof(DevUnion) * S3_MAX_PORTS))))
191    	{
192        	xfree(adapt);
193        	return NULL;
194    	}
195
196    	adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
197
198    	for(i = 0; i < S3_MAX_PORTS; i++)
199        	adapt->pPortPrivates[i].val = i;
200
201	pPriv->colorKey = (1 << pScrn->offset.red) | (1 << pScrn->offset.green) |
202			  (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
203
204	pPriv->videoStatus = 0;
205	pPriv->lastPort = -1;
206
207	pS3->adaptor = adapt;
208	pS3->portPrivate = pPriv;
209
210	return adapt;
211}
212
213
214static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen)
215{
216	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
217	S3Ptr pS3 = S3PTR(pScrn);
218	XF86VideoAdaptorPtr adapt;
219
220	adapt = S3AllocAdaptor(pScrn);
221
222    	adapt->type = XvWindowMask | XvInputMask | XvImageMask;
223    	adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
224    	adapt->name = "S3 Backend Scaler";
225    	adapt->nEncodings = 1;
226    	adapt->pEncodings = &DummyEncoding[0];
227    	adapt->nFormats = NUM_FORMATS_OVERLAY;
228    	adapt->pFormats = Formats;
229    	adapt->nPorts = 1;
230    	adapt->pAttributes = NULL /*Attributes*/;
231	adapt->nImages = 3;
232	adapt->nAttributes = 0;
233
234    	adapt->pImages = Images;
235    	adapt->PutVideo = NULL;
236    	adapt->PutStill = NULL;
237    	adapt->GetVideo = NULL;
238    	adapt->GetStill = NULL;
239    	adapt->StopVideo = S3StopVideo;
240    	/* Empty Attrib functions - required anyway */
241    	adapt->SetPortAttribute = S3SetPortAttributeOverlay;
242    	adapt->GetPortAttribute = S3GetPortAttributeOverlay;
243    	adapt->QueryBestSize = S3QueryBestSize;
244    	adapt->PutImage = S3PutImage;
245    	adapt->QueryImageAttributes = S3QueryImageAttributes;
246
247    	/* gotta uninit this someplace */
248	REGION_NULL(pScreen, &(pS3->portPrivate->clip));
249
250    	S3ResetVideoOverlay(pScrn);
251
252    	return adapt;
253}
254
255
256static void S3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
257{
258	S3Ptr pS3 = S3PTR(pScrn);
259	S3PortPrivPtr pPriv = pS3->portPrivate;
260
261	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
262
263	if (exit) {
264		if (pPriv->videoStatus & CLIENT_VIDEO_ON)
265			SET_BLEND_CNTL(0x01000000);
266
267		if (pPriv->area) {
268			xf86FreeOffscreenArea(pPriv->area);
269	        	pPriv->area = NULL;
270		}
271
272		pPriv->videoStatus = 0;
273	}
274}
275
276
277static FBAreaPtr S3AllocateMemory(ScrnInfoPtr pScrn, FBAreaPtr area,
278				  int numlines)
279{
280	ScreenPtr pScreen;
281	FBAreaPtr new_area;
282
283   if(area) {
284        if((area->box.y2 - area->box.y1) >= numlines)
285           return area;
286
287        if(xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines))
288           return area;
289
290        xf86FreeOffscreenArea(area);
291   }
292
293   pScreen = screenInfo.screens[pScrn->scrnIndex];
294
295   new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
296                                numlines, 0, NULL, NULL, NULL);
297
298   if(!new_area) {
299        int max_w, max_h;
300
301        xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
302                        FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
303
304        if((max_w < pScrn->displayWidth) || (max_h < numlines))
305           return NULL;
306
307        xf86PurgeUnlockedOffscreenAreas(pScreen);
308        new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
309                                numlines, 0, NULL, NULL, NULL);
310   }
311
312   return new_area;
313}
314
315
316
317static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset,
318				  short width, short height, int pitch,
319				  int x1, int y1, int x2, int y2,
320				  BoxPtr dstBox, short src_w, short src_h,
321				  short drw_w, short drw_h)
322{
323	S3Ptr pS3 = S3PTR(pScrn);
324	S3PortPrivPtr pPriv = pS3->portPrivate;
325	int tmp;
326
327	if (drw_w == src_w)
328		tmp = 0;
329	else
330		tmp = 2;
331
332	SET_SSTREAM_CNTL(tmp << 28 | 0x01000000 |
333			 ((((src_w-1)<<1)-(drw_w-1)) & 0xfff));
334	SET_SSTRETCH(((src_w - 1) & 0x7ff) | (((src_w-drw_w) & 0x7ff) << 16));
335	SET_BLEND_CNTL(0x05000000);
336	SET_SSTREAM_FBADDR(offset & 0x3fffff);
337	SET_SSTREAM_STRIDE(pitch & 0xfff);
338
339	SET_K1_VSCALE(src_h - 1);
340	SET_K2_VSCALE((src_h - drw_h) & 0x7ff);
341
342	SET_DDA_VERT((((~drw_h)-1)) & 0xfff);
343
344	SET_SSTREAM_START(((dstBox->x1 +1) << 16) | (dstBox->y1 +1));
345	SET_SSTREAM_WIND(( ((drw_w-1) << 16) | (drw_h ) ) & 0x7ff07ff);
346
347	SET_CHROMA_KEY(0x10000000 |
348		       ((pScrn->weight.red-1) << 24) |
349		       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
350			(16 + 8-pScrn->weight.red) |
351		       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
352			(8 + 8-pScrn->weight.green) |
353		       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
354			(8-pScrn->weight.blue));
355}
356
357
358static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
359		  short drw_x, short drw_y, short src_w, short src_h,
360		  short drw_w, short drw_h, int id, unsigned char *buf,
361		  short width, short height, Bool sync, RegionPtr clipBoxes,
362		  pointer data, DrawablePtr pDraw)
363{
364	S3Ptr pS3 = S3PTR(pScrn);
365	S3PortPrivPtr pPriv = pS3->portPrivate;
366   	INT32 x1, x2, y1, y2;
367   	unsigned char *dst_start;
368   	int pitch, new_h, offset, offset2=0, offset3=0;
369   	int srcPitch, srcPitch2=0, dstPitch;
370   	int top, left, npixels, nlines;
371   	BoxRec dstBox;
372   	CARD32 tmp;
373
374   /* Clip */
375   x1 = src_x;
376   x2 = src_x + src_w;
377   y1 = src_y;
378   y2 = src_y + src_h;
379
380   dstBox.x1 = drw_x;
381   dstBox.x2 = drw_x + drw_w;
382   dstBox.y1 = drw_y;
383   dstBox.y2 = drw_y + drw_h;
384
385   if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
386			     clipBoxes, width, height))
387        return Success;
388
389   /*if(!pMga->TexturedVideo) {*/
390        dstBox.x1 -= pScrn->frameX0;
391        dstBox.x2 -= pScrn->frameX0;
392        dstBox.y1 -= pScrn->frameY0;
393        dstBox.y2 -= pScrn->frameY0;
394        /*}*/
395
396   pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
397   dstPitch = ((width << 1) + 15) & ~15;
398   new_h = ((dstPitch * height) + pitch - 1) / pitch;
399
400   switch(id) {
401   case FOURCC_YV12:
402   case FOURCC_I420:
403        srcPitch = (width + 3) & ~3;
404        offset2 = srcPitch * height;
405        srcPitch2 = ((width >> 1) + 3) & ~3;
406        offset3 = (srcPitch2 * (height >> 1)) + offset2;
407        break;
408   case FOURCC_UYVY:
409   case FOURCC_YUY2:
410   default:
411        srcPitch = (width << 1);
412        break;
413   }
414
415   if(!(pPriv->area = S3AllocateMemory(pScrn, pPriv->area, new_h)))
416        return BadAlloc;
417
418    /* copy data */
419    top = y1 >> 16;
420    left = (x1 >> 16) & ~1;
421    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
422    left <<= 1;
423
424    offset = pPriv->area->box.y1 * pitch;
425    dst_start = pS3->FBBase + offset + left + (top * dstPitch);
426    switch(id) {
427    case FOURCC_YV12:
428    case FOURCC_I420:
429        top &= ~1;
430        tmp = ((top >> 1) * srcPitch2) + (left >> 2);
431        offset2 += tmp;
432        offset3 += tmp;
433        if(id == FOURCC_I420) {
434           tmp = offset2;
435           offset2 = offset3;
436           offset3 = tmp;
437        }
438        nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
439        xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
440                                buf + offset2, buf + offset3, dst_start,
441                                srcPitch, srcPitch2, dstPitch, nlines, npixels);
442        break;
443    case FOURCC_UYVY:
444    case FOURCC_YUY2:
445    default:
446        buf += (top * srcPitch) + left;
447        nlines = ((y2 + 0xffff) >> 16) - top;
448        xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
449        break;
450    }
451
452    /* update cliplist */
453        if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
454            REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
455            /* draw these */
456	    xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
457        }
458
459        offset += left + (top * dstPitch);
460        S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
461             x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
462
463        pPriv->videoStatus = CLIENT_VIDEO_ON;
464    return Success;
465}
466
467
468
469static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id,
470				  unsigned short *w, unsigned short *h,
471				  int *pitches, int *offsets)
472{
473	int size, tmp;
474
475    *w = (*w + 1) & ~1;
476    if(offsets) offsets[0] = 0;
477
478    switch(id) {
479    case FOURCC_YV12:
480    case FOURCC_I420:
481        *h = (*h + 1) & ~1;
482        size = (*w + 3) & ~3;
483        if(pitches) pitches[0] = size;
484        size *= *h;
485        if(offsets) offsets[1] = size;
486        tmp = ((*w >> 1) + 3) & ~3;
487        if(pitches) pitches[1] = pitches[2] = tmp;
488        tmp *= (*h >> 1);
489        size += tmp;
490        if(offsets) offsets[2] = size;
491        size += tmp;
492        break;
493    case FOURCC_UYVY:
494    case FOURCC_YUY2:
495    default:
496        size = *w << 1;
497        if(pitches) pitches[0] = size;
498        size *= *h;
499        break;
500    }
501
502    return size;
503}
504
505
506
507void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode)
508{
509        S3Ptr pS3 = S3PTR(pScrn);
510        unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay);
511
512        SET_PSTREAM_CNTL(0x05000000 & 0x77000000);
513        SET_CHROMA_KEY(0x00);
514        SET_SSTREAM_CNTL(0x03000000);
515        SET_BLEND_CNTL(0x01000000);
516        SET_PSTREAM_STRIDE((pScrn->displayWidth * 2) & 0x0fff);
517        SET_SSTREAM_STRIDE(0x01);
518        SET_OPAQUE_OVERLAY(0x40000000);
519        SET_PSTREAM_START(0x00010001);
520        SET_PSTREAM_WIND(pst_wind & 0x07ff07ff);
521        SET_SSTREAM_START(0x07ff07ff);
522        SET_SSTREAM_WIND(0x00010001);
523}
524
525