s3_video.c revision 4178061c
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
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33#include "xf86_OSproc.h"
34
35#include "compiler.h"
36
37#include "s3.h"
38#include "s3_reg.h"
39
40
41#define CLIENT_VIDEO_ON	0x04
42#define S3_MAX_PORTS	1
43#define NUM_FORMATS_OVERLAY 4
44#define NUM_FORMATS_TEXTURE 4
45
46
47static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn);
48static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr);
49static int S3SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
50static int S3GetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
51static void S3StopVideo(ScrnInfoPtr, pointer, Bool);
52static void S3QueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
53                            unsigned int *, unsigned int *, pointer);
54static int  S3PutImage(ScrnInfoPtr, short, short, short, short, short,
55                       short, short, short, int, unsigned char*, short,
56                       short, Bool, RegionPtr, pointer, DrawablePtr);
57static int  S3QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
58                        	   unsigned short *,  int *, int *);
59static void S3ResetVideoOverlay(ScrnInfoPtr);
60static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size);
61
62
63void S3InitVideo(ScreenPtr pScreen)
64{
65	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
66	S3Ptr pS3 = S3PTR(pScrn);
67	XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
68	XF86VideoAdaptorPtr newAdaptor = NULL;
69	int num_adaptors;
70
71	newAdaptor = S3SetupImageVideoOverlay(pScreen);
72	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
73
74	num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
75
76    	if(newAdaptor) {
77        	if(!num_adaptors) {
78            		num_adaptors = 1;
79            		adaptors = &newAdaptor;
80        	} else {
81            		newAdaptors =  /* need to free this someplace */
82                		xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
83            		if(newAdaptors) {
84                		memcpy(newAdaptors, adaptors, num_adaptors *
85                                       sizeof(XF86VideoAdaptorPtr));
86                		newAdaptors[num_adaptors] = newAdaptor;
87                		adaptors = newAdaptors;
88                		num_adaptors++;
89           		}
90        	}
91    	}
92
93    	if(num_adaptors)
94        	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
95
96    	if(newAdaptors)
97        	xfree(newAdaptors);
98}
99
100
101/* client libraries expect an encoding */
102static XF86VideoEncodingRec DummyEncoding[2] =
103{
104 	{   /* overlay limit */
105   		0,
106   		"XV_IMAGE",
107   		1024, 1024,
108   		{1, 1}
109 	},
110 	{  /* texture limit */
111   		0,
112   		"XV_IMAGE",
113   		2046, 2046,
114   		{1, 1}
115 	}
116};
117
118
119static FBLinearPtr S3XVMemAlloc(ScrnInfoPtr pScrn, pointer pVideo, int size)
120{
121	FBLinearPtr pLinear = (FBLinearPtr)pVideo;
122	ScreenPtr pScreen = pScrn->pScreen;
123
124	if (pLinear) {
125		if ((pLinear->size >= size) ||
126		    xf86ResizeOffscreenLinear(pLinear, size)) {
127			pLinear->MoveLinearCallback = NULL;
128			pLinear->RemoveLinearCallback = NULL;
129			return pLinear;
130		}
131		xf86FreeOffscreenLinear(pLinear);
132	}
133	pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16,
134					      NULL, NULL, NULL);
135
136	if (!pLinear) {
137		int maxSize;
138
139		xf86QueryLargestOffscreenLinear(pScreen, &maxSize, 16,
140						PRIORITY_EXTREME);
141		if (maxSize < size)
142			return NULL;
143
144		xf86PurgeUnlockedOffscreenAreas(pScreen);
145		pLinear = xf86AllocateOffscreenLinear(pScreen, size, 16,
146						      NULL, NULL, NULL);
147	}
148	return pLinear;
149}
150
151static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] =
152{
153  	{16, TrueColor}, {24, TrueColor},
154	{16, DirectColor}, {24, DirectColor}
155};
156
157
158
159#define NUM_IMAGES 3
160
161static XF86ImageRec Images[NUM_IMAGES] =
162{
163  	XVIMAGE_YUY2,
164  	/* As in mga, YV12 & I420 are converted to YUY2 on the fly by */
165  	/* copy over conversion. */
166  	XVIMAGE_YV12,
167  	XVIMAGE_I420
168        /* XVIMAGE_UYVY */
169};
170
171
172
173static int S3SetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute,
174				     INT32 value, pointer data)
175{
176	return BadMatch;
177}
178
179
180static int S3GetPortAttributeOverlay(ScrnInfoPtr pScrn, Atom attribute,
181				     INT32 *value, pointer data)
182{
183	return BadMatch;
184}
185
186
187
188static void S3QueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w,
189			    short vid_h, short drw_w, short drw_h,
190                            unsigned int *p_w, unsigned int *p_h,
191			    pointer data)
192{
193	*p_w = drw_w;
194	*p_h = drw_h;
195}
196
197
198
199static void S3ResetVideoOverlay(ScrnInfoPtr pScrn)
200{
201}
202
203
204static XF86VideoAdaptorPtr S3AllocAdaptor(ScrnInfoPtr pScrn)
205{
206	S3Ptr pS3 = S3PTR(pScrn);
207	XF86VideoAdaptorPtr adapt;
208	S3PortPrivPtr pPriv;
209	int i;
210
211    	if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
212        	return NULL;
213
214    	if(!(pPriv = xcalloc(1, sizeof(S3PortPrivRec)  +
215			     (sizeof(DevUnion) * S3_MAX_PORTS))))
216    	{
217        	xfree(adapt);
218        	return NULL;
219    	}
220
221    	adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
222
223    	for(i = 0; i < S3_MAX_PORTS; i++)
224        	adapt->pPortPrivates[i].val = i;
225
226	pPriv->colorKey = (1 << pScrn->offset.red) |
227		(1 << pScrn->offset.green) |
228		(((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
229
230	pPriv->videoStatus = 0;
231	pPriv->lastPort = -1;
232
233	pS3->adaptor = adapt;
234	pS3->portPrivate = pPriv;
235
236	return adapt;
237}
238
239
240static XF86VideoAdaptorPtr S3SetupImageVideoOverlay(ScreenPtr pScreen)
241{
242	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
243	S3Ptr pS3 = S3PTR(pScrn);
244	XF86VideoAdaptorPtr adapt;
245
246	adapt = S3AllocAdaptor(pScrn);
247
248    	adapt->type = XvWindowMask | XvInputMask | XvImageMask;
249    	adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
250    	adapt->name = "S3 Backend Scaler";
251    	adapt->nEncodings = 1;
252    	adapt->pEncodings = &DummyEncoding[0];
253    	adapt->nFormats = NUM_FORMATS_OVERLAY;
254    	adapt->pFormats = Formats;
255    	adapt->nPorts = 1;
256    	adapt->pAttributes = NULL /*Attributes*/;
257	adapt->nImages = 3;
258	adapt->nAttributes = 0;
259
260    	adapt->pImages = Images;
261    	adapt->PutVideo = NULL;
262    	adapt->PutStill = NULL;
263    	adapt->GetVideo = NULL;
264    	adapt->GetStill = NULL;
265    	adapt->StopVideo = S3StopVideo;
266    	/* Empty Attrib functions - required anyway */
267    	adapt->SetPortAttribute = S3SetPortAttributeOverlay;
268    	adapt->GetPortAttribute = S3GetPortAttributeOverlay;
269    	adapt->QueryBestSize = S3QueryBestSize;
270    	adapt->PutImage = S3PutImage;
271    	adapt->QueryImageAttributes = S3QueryImageAttributes;
272
273    	/* gotta uninit this someplace */
274	REGION_NULL(pScreen, &(pS3->portPrivate->clip));
275
276    	S3ResetVideoOverlay(pScrn);
277
278    	return adapt;
279}
280
281
282static void S3StopVideo(ScrnInfoPtr pScrn, pointer data, Bool exit)
283{
284	S3Ptr pS3 = S3PTR(pScrn);
285	S3PortPrivPtr pPriv = pS3->portPrivate;
286
287	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
288
289	if (exit) {
290		SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0);
291
292		if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
293			WaitVSync();
294			SET_SSTREAM_CNTL(0x03000000);
295			SET_SSTREAM_FBADDR0(0x00000000);
296			SET_SSTREAM_FBADDR1(0x00000000);
297			SET_SSTREAM_STRIDE(0x00000001);
298			SET_SSTREAM_START(0x07ff07ff);
299			SET_SSTREAM_WIND(0x00010001);
300
301			SET_CHROMA_KEY(0x00000000);
302			SET_SSTRETCH(0x00000000);
303			SET_OPAQUE_OVERLAY(0x40000000);
304			SET_K1_VSCALE(0x00000000);
305			SET_K2_VSCALE(0x00000000);
306			SET_DDA_VERT(0x00000000);
307			SET_BLEND_CNTL(0x01000000);
308			WaitVSync();
309		}
310
311		if (pPriv->area) {
312			xf86FreeOffscreenLinear(pPriv->area);
313	        	pPriv->area = NULL;
314		}
315
316		pPriv->videoStatus = 0;
317	}
318}
319
320static void S3DisplayVideoOverlay(ScrnInfoPtr pScrn, int id, int offset,
321				  short width, short height, int pitch,
322				  int x1, int y1, int x2, int y2,
323				  BoxPtr dstBox, short src_w, short src_h,
324				  short drw_w, short drw_h)
325{
326	S3Ptr pS3 = S3PTR(pScrn);
327	S3PortPrivPtr pPriv = pS3->portPrivate;
328	int tmp;
329
330	if (drw_w == src_w)
331		tmp = 0;
332	else
333		tmp = 2;
334
335	SET_SSTREAM_CNTL((tmp << 28) | 0x01000000 |
336			 ((((src_w - 1) << 1) - (drw_w - 1)) & 0xfff));
337	SET_SSTRETCH(((src_w - 1) & 0x7ff) |
338		     (((src_w - drw_w) & 0x7ff) << 16));
339	SET_BLEND_CNTL(0x05000000);
340	SET_SSTREAM_FBADDR0(offset & 0x3fffff);
341	SET_SSTREAM_FBADDR1(offset & 0x3fffff);
342	SET_SSTREAM_STRIDE(pitch & 0xfff);
343	SET_SSTREAM_START(((dstBox->x1 + 1) << 16) | (dstBox->y1 + 1));
344	SET_SSTREAM_WIND((((drw_w - 1) << 16) | drw_h) & 0x7ff07ff);
345
346	SET_K1_VSCALE(src_h - 1);
347	SET_K2_VSCALE((src_h - drw_h) & 0x7ff);
348	SET_DDA_VERT(((~drw_h - 1)) & 0xfff);
349
350	SET_CHROMA_KEY(0x10000000 |
351		       ((pScrn->weight.red-1) << 24) |
352		       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
353		       (16 + 8-pScrn->weight.red) |
354		       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
355		       (8 + 8-pScrn->weight.green) |
356		       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
357		       (8-pScrn->weight.blue));
358
359	SET_FIFO_CNTL(0x00080000 | pS3->Streams_FIFO);
360}
361
362static int S3PutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
363		      short drw_x, short drw_y, short src_w, short src_h,
364		      short drw_w, short drw_h, int id, unsigned char *buf,
365		      short width, short height, Bool sync,
366		      RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
367{
368	S3Ptr pS3 = S3PTR(pScrn);
369	S3PortPrivPtr pPriv = pS3->portPrivate;
370   	INT32 x1, x2, y1, y2;
371   	CARD8 *dst_start;
372   	int offset, offsetV = 0, offsetU = 0;
373   	int srcPitch, srcPitchUV = 0, dstPitch, dstSize;
374   	int top, bottom, right, left, npixels, nlines;
375   	BoxRec dstBox;
376	CARD32 tmp;
377	int cpp = (pScrn->bitsPerPixel + 7) >> 3;
378
379	/* Clip */
380	x1 = src_x;
381	x2 = src_x + src_w;
382	y1 = src_y;
383	y2 = src_y + src_h;
384
385	dstBox.x1 = drw_x;
386	dstBox.x2 = drw_x + drw_w;
387	dstBox.y1 = drw_y;
388	dstBox.y2 = drw_y + drw_h;
389
390	if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
391				  width, height))
392		return Success;
393
394	dstBox.x1 -= pScrn->frameX0;
395	dstBox.x2 -= pScrn->frameX0;
396	dstBox.y1 -= pScrn->frameY0;
397	dstBox.y2 -= pScrn->frameY0;
398
399	/* requested size in bytes */
400	dstPitch = ((width << 1) + 15) & ~15;
401	dstSize = dstPitch * height;
402
403	pPriv->area = S3XVMemAlloc(pScrn, pPriv->area,
404				   (dstSize + cpp - 1) / cpp);
405	if (!pPriv->area)
406		return BadAlloc;
407
408	offset = pPriv->area->offset * cpp;
409	dst_start = pS3->FBBase + offset;
410
411	switch (id) {
412        case FOURCC_YV12:
413        case FOURCC_I420:
414		left = (x1 >> 16) & ~1;
415		right = ((x2 + 0x1ffff) >> 16) & ~1;
416		top = (y1 >> 16) & ~1;
417		bottom = ((y2 + 0x1ffff) >> 16) & ~1;
418
419		if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff)))
420			right += 2;
421		if ((bottom < height) && ((y1 & 0x1ffff) <= (y2 & 0x1ffff)))
422			bottom += 2;
423
424		npixels = right - left;
425		nlines = bottom - top;
426
427		srcPitch = (width + 3) & ~3;
428		offsetV = srcPitch * height;
429		srcPitchUV = ((width >> 1) + 3) & ~3;
430		offsetU = ((height >> 1) * srcPitchUV) + offsetV;
431
432		tmp = ((top >> 1) * srcPitchUV) + (left >> 1);
433		offsetV += tmp;
434		offsetU += tmp;
435
436		if (id == FOURCC_I420)
437		{
438			tmp = offsetV;
439			offsetV = offsetU;
440			offsetU = tmp;
441		}
442
443		dst_start += top * dstPitch + (left << 1);
444
445		xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + left,
446					buf + offsetV, buf + offsetU,
447					dst_start, srcPitch, srcPitchUV,
448					dstPitch, nlines, npixels);
449		break;
450
451        case FOURCC_UYVY:
452        case FOURCC_YUY2:
453        default:
454		left = (x1 >> 16) & ~1;
455		right = ((x2 + 0x1ffff) >> 16) & ~1;
456		top = y1 >> 16;
457		bottom = (y2 + 0x0ffff) >> 16;
458
459		if ((right < width) && ((x1 & 0x1ffff) <= (x2 & 0x1ffff)))
460			right += 2;
461		if ((bottom < height) && ((y1 & 0x0ffff) <= (y2 & 0x0ffff)))
462			bottom++;
463
464		npixels = right - left;
465		nlines = bottom - top;
466
467		srcPitch = width << 1;
468		buf += (top * srcPitch) + (left << 1);
469		dst_start += top * dstPitch + (left << 1);
470
471		xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch,
472				 nlines, npixels);
473		break;
474	}
475
476	/* update cliplist */
477	if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
478		REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
479		/* draw these */
480		xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey,
481				    clipBoxes);
482	}
483
484	offset += (left << 1) + (top * dstPitch);
485	S3DisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
486			      x1, y1, x2, y2, &dstBox,
487			      src_w, src_h, drw_w, drw_h);
488
489	pPriv->videoStatus = CLIENT_VIDEO_ON;
490	return Success;
491}
492
493
494
495static int S3QueryImageAttributes(ScrnInfoPtr pScrn, int id,
496				  unsigned short *w, unsigned short *h,
497				  int *pitches, int *offsets)
498{
499	int size, tmp;
500
501	*w = (*w + 1) & ~1;
502	if(offsets) offsets[0] = 0;
503
504	switch(id) {
505	case FOURCC_YV12:
506	case FOURCC_I420:
507		*h = (*h + 1) & ~1;
508		size = (*w + 3) & ~3;
509		if(pitches) pitches[0] = size;
510		size *= *h;
511		if(offsets) offsets[1] = size;
512		tmp = ((*w >> 1) + 3) & ~3;
513		if(pitches) pitches[1] = pitches[2] = tmp;
514		tmp *= (*h >> 1);
515		size += tmp;
516		if(offsets) offsets[2] = size;
517		size += tmp;
518		break;
519	case FOURCC_UYVY:
520	case FOURCC_YUY2:
521	default:
522		size = *w << 1;
523		if(pitches) pitches[0] = size;
524		size *= *h;
525		break;
526	}
527
528	return size;
529}
530
531
532void S3InitStreams(ScrnInfoPtr pScrn, DisplayModePtr mode)
533{
534        S3Ptr pS3 = S3PTR(pScrn);
535        unsigned int pst_wind = (mode->HDisplay-1) << 16 | (mode->VDisplay);
536
537	WaitVSync();
538
539	switch (pScrn->bitsPerPixel) {
540	case 8:
541		SET_PSTREAM_CNTL(0x00000000);
542		break;
543	case 15:
544		SET_PSTREAM_CNTL(0x03000000);
545		break;
546	case 16:
547		SET_PSTREAM_CNTL(0x05000000);
548		break;
549	case 24:
550		SET_PSTREAM_CNTL(0x06000000);
551		break;
552	case 32:
553		SET_PSTREAM_CNTL(0x07000000);
554		break;
555	}
556
557	SET_PSTREAM_FBADDR0(0x00000000);
558	SET_PSTREAM_FBADDR1(0x00000000);
559
560	SET_PSTREAM_STRIDE(pS3->s3BppDisplayWidth & 0x0fff);
561
562        SET_PSTREAM_WIND(pst_wind & 0x07ff07ff);
563        SET_PSTREAM_START(0x00010001);
564
565        SET_CHROMA_KEY(0x00000000);
566	SET_SSTRETCH(0x00000000);
567        SET_BLEND_CNTL(0x01000000);
568	SET_DOUBLE_BUFFER(0x00000000);
569
570        SET_SSTREAM_CNTL(0x03000000);
571	SET_SSTREAM_FBADDR0(0x00000000);
572	SET_SSTREAM_FBADDR1(0x00000000);
573        SET_SSTREAM_STRIDE(0x00000001);
574        SET_SSTREAM_START(0x07ff07ff);
575        SET_SSTREAM_WIND(0x00010001);
576
577        SET_OPAQUE_OVERLAY(0x40000000);
578	SET_K1_VSCALE(0x00000000);
579	SET_K2_VSCALE(0x00000000);
580	SET_DDA_VERT(0x00000000);
581
582	/*
583	  ps thr | ss thr | ss fifo slots
584	  set primary stream FIFO to 24 slots and 12 slots for threshold
585	*/
586	SET_FIFO_CNTL(0x00080000 | FIFO_PS24_SS0);
587}
588
589