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