1/*
2Copyright (C) 2000 The XFree86 Project, Inc.  All Rights Reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of
5this software and associated documentation files (the "Software"), to deal in
6the Software without restriction, including without limitation the rights to
7use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8of the Software, and to permit persons to whom the Software is furnished to do
9so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
16NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of the XFree86 Project shall not
22be used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from the XFree86 Project.
24*/
25
26/*
27 * s3v_xv.c
28 * X Video Extension support
29 *
30 * S3 ViRGE driver
31 *
32 * 7/2000 Kevin Brosius
33 *
34 * Useful references:
35 * X Video extension support -> xc/programs/hw/xfree86/common/xf86xv.c
36 *
37 */
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43/* Most xf86 commons are already in s3v.h */
44#include "s3v.h"
45#include "s3v_pciids.h"
46
47#if 0
48#define OFF_DELAY 	250  /* milliseconds */
49#define FREE_DELAY 	15000
50
51#define OFF_TIMER 	0x01
52#define FREE_TIMER	0x02
53#endif
54#define CLIENT_VIDEO_ON	0x04
55
56#define S3V_MAX_PORTS 1
57
58#if 0
59static void S3VInitOffscreenImages(ScreenPtr);
60#endif
61
62static XF86VideoAdaptorPtr S3VAllocAdaptor(ScrnInfoPtr pScrn);
63static XF86VideoAdaptorPtr S3VSetupImageVideoOverlay(ScreenPtr);
64static int  S3VSetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
65static int  S3VGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
66
67
68static void S3VStopVideo(ScrnInfoPtr, pointer, Bool);
69static void S3VQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short,
70			unsigned int *, unsigned int *, pointer);
71static int  S3VPutImage(ScrnInfoPtr, short, short, short, short, short,
72			short, short, short, int, unsigned char*, short,
73			short, Bool, RegionPtr, pointer, DrawablePtr);
74static int  S3VQueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
75			unsigned short *,  int *, int *);
76
77
78static void S3VResetVideoOverlay(ScrnInfoPtr);
79
80#if 0
81#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
82
83static Atom xvBrightness, xvContrast, xvColorKey;
84
85#endif /* 0 */
86
87int S3VQueryXvCapable(ScrnInfoPtr pScrn)
88{
89  S3VPtr ps3v = S3VPTR(pScrn);
90
91  if(
92     ((pScrn->bitsPerPixel == 24) ||
93      (pScrn->bitsPerPixel == 16)
94      )
95     &&
96     ((ps3v->Chipset == S3_ViRGE_DXGX)  ||
97      S3_ViRGE_MX_SERIES(ps3v->Chipset) ||
98      S3_ViRGE_GX2_SERIES(ps3v->Chipset)
99      ))
100    return TRUE;
101  else
102    return FALSE;
103}
104
105
106void S3VInitVideo(ScreenPtr pScreen)
107{
108    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
109    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
110    XF86VideoAdaptorPtr newAdaptor = NULL;
111    S3VPtr ps3v = S3VPTR(pScrn);
112    int num_adaptors;
113
114    if(
115       ((pScrn->bitsPerPixel == 24) ||
116	(pScrn->bitsPerPixel == 16)
117	)
118       &&
119       ((ps3v->Chipset == S3_ViRGE_DXGX)  ||
120	S3_ViRGE_MX_SERIES(ps3v->Chipset) ||
121	S3_ViRGE_GX2_SERIES(ps3v->Chipset) /* || */
122	/* (ps3v->Chipset == S3_ViRGE) */
123	)
124       && !ps3v->NoAccel
125       && ps3v->XVideo
126       )
127    {
128	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using overlay video\n");
129	    newAdaptor = S3VSetupImageVideoOverlay(pScreen);
130    }
131
132
133    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
134
135    if(newAdaptor) {
136	if(!num_adaptors) {
137	    num_adaptors = 1;
138	    adaptors = &newAdaptor;
139	} else {
140	    newAdaptors =  /* need to free this someplace */
141		malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
142	    if(newAdaptors) {
143		memcpy(newAdaptors, adaptors, num_adaptors *
144					sizeof(XF86VideoAdaptorPtr));
145		newAdaptors[num_adaptors] = newAdaptor;
146		adaptors = newAdaptors;
147		num_adaptors++;
148	    }
149	}
150    }
151
152    if(num_adaptors)
153        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
154
155    if(newAdaptors)
156	free(newAdaptors);
157}
158
159/* client libraries expect an encoding */
160static XF86VideoEncodingRec DummyEncoding[2] =
161{
162 {   /* overlay limit */
163   0,
164   "XV_IMAGE",
165   1024, 1024,
166   {1, 1}
167 },
168 {  /* texture limit */
169   0,
170   "XV_IMAGE",
171   2046, 2046,
172   {1, 1}
173 }
174};
175
176#define NUM_FORMATS_OVERLAY 4
177#define NUM_FORMATS_TEXTURE 4
178
179static XF86VideoFormatRec Formats[NUM_FORMATS_TEXTURE] =
180{
181  /*{15, TrueColor},*/ {16, TrueColor}, {24, TrueColor} /* ,
182    {15, DirectColor}*/, {16, DirectColor}, {24, DirectColor}
183};
184
185#if 0
186#define NUM_ATTRIBUTES_OVERLAY 3
187
188static XF86AttributeRec Attributes[NUM_ATTRIBUTES_OVERLAY] =
189{
190   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
191   {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
192   {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
193};
194#endif
195
196#define NUM_IMAGES 3
197
198static XF86ImageRec Images[NUM_IMAGES] =
199{
200  XVIMAGE_YUY2,
201  /* As in mga, YV12 & I420 are converted to YUY2 on the fly by */
202  /* copy over conversion. */
203  XVIMAGE_YV12,
204  XVIMAGE_I420
205	/* XVIMAGE_UYVY */
206};
207
208
209
210static int
211S3VSetPortAttributeOverlay(
212  ScrnInfoPtr pScrn,
213  Atom attribute,
214  INT32 value,
215  pointer data
216){
217
218return BadMatch;
219
220}
221
222static int
223S3VGetPortAttributeOverlay(
224  ScrnInfoPtr pScrn,
225  Atom attribute,
226  INT32 *value,
227  pointer data
228){
229
230
231return BadMatch;
232
233}
234
235
236
237static void
238S3VQueryBestSize(
239  ScrnInfoPtr pScrn,
240  Bool motion,
241  short vid_w, short vid_h,
242  short drw_w, short drw_h,
243  unsigned int *p_w, unsigned int *p_h,
244  pointer data
245){
246  *p_w = drw_w;
247  *p_h = drw_h;
248
249#if 0
250  /* Only support scaling up, no down scaling. */
251  /* This doesn't seem to work (at least for XMovie) */
252  /* and the DESIGN doc says this is illegal anyway... */
253  if( drw_w < vid_w ) *p_w = vid_w;
254  if( drw_h < vid_h ) *p_h = vid_h;
255#endif
256}
257
258
259
260static void
261S3VResetVideoOverlay(ScrnInfoPtr pScrn)
262{
263  /* empty for ViRGE at the moment... */
264#if 0
265  S3VPtr ps3v = S3VPTR(pScrn);
266  S3VPortPrivPtr pPriv = ps3v->portPrivate;
267
268    MGAPtr pMga = MGAPTR(pScrn);
269    MGAPortPrivPtr pPriv = pMga->portPrivate;
270
271    CHECK_DMA_QUIESCENT(pMga, pScrn);
272
273    outMGAdac(0x51, 0x01); /* keying on */
274    outMGAdac(0x52, 0xff); /* full mask */
275    outMGAdac(0x53, 0xff);
276    outMGAdac(0x54, 0xff);
277
278    outMGAdac(0x55, (pPriv->colorKey & pScrn->mask.red) >>
279		    pScrn->offset.red);
280    outMGAdac(0x56, (pPriv->colorKey & pScrn->mask.green) >>
281		    pScrn->offset.green);
282    outMGAdac(0x57, (pPriv->colorKey & pScrn->mask.blue) >>
283		    pScrn->offset.blue);
284#endif
285
286#if 0
287    OUTREG(MGAREG_BESLUMACTL, ((pPriv->brightness & 0xff) << 16) |
288			       (pPriv->contrast & 0xff));
289#endif /*0*/
290}
291
292
293
294static XF86VideoAdaptorPtr
295S3VAllocAdaptor(ScrnInfoPtr pScrn)
296{
297    XF86VideoAdaptorPtr adapt;
298    S3VPtr ps3v = S3VPTR(pScrn);
299    S3VPortPrivPtr pPriv;
300    int i;
301
302    if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
303	return NULL;
304
305    if(!(pPriv = calloc(1, sizeof(S3VPortPrivRec)  +
306			(sizeof(DevUnion) * S3V_MAX_PORTS))))
307    {
308	free(adapt);
309	return NULL;
310    }
311
312    adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
313
314    for(i = 0; i < S3V_MAX_PORTS; i++)
315	adapt->pPortPrivates[i].val = i;
316
317#if 0
318    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
319    xvContrast   = MAKE_ATOM("XV_CONTRAST");
320    xvColorKey   = MAKE_ATOM("XV_COLORKEY");
321#endif
322
323    pPriv->colorKey =
324      (1 << pScrn->offset.red) |
325      (1 << pScrn->offset.green) |
326      (((pScrn->mask.blue >> pScrn->offset.blue) - 1) << pScrn->offset.blue);
327
328#if 0
329    pPriv->brightness = 0;
330    pPriv->contrast = 128;
331#endif
332
333    pPriv->videoStatus = 0;
334    pPriv->lastPort = -1;
335
336    ps3v->adaptor = adapt;
337    ps3v->portPrivate = pPriv;
338
339    return adapt;
340}
341
342
343
344
345
346static XF86VideoAdaptorPtr
347S3VSetupImageVideoOverlay(ScreenPtr pScreen)
348{
349    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
350    S3VPtr ps3v = S3VPTR(pScrn);
351    XF86VideoAdaptorPtr adapt;
352
353    adapt = S3VAllocAdaptor(pScrn);
354    if (adapt == NULL)
355        return NULL;
356
357    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
358    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
359    adapt->name = "S3 ViRGE Backend Scaler";
360    adapt->nEncodings = 1;
361    adapt->pEncodings = &DummyEncoding[0];
362    adapt->nFormats = NUM_FORMATS_OVERLAY;
363    adapt->pFormats = Formats;
364    adapt->nPorts = 1;
365    adapt->pAttributes = NULL /*Attributes*/;
366    adapt->nImages = 3;
367    adapt->nAttributes = 0;
368    adapt->pImages = Images;
369    adapt->PutVideo = NULL;
370    adapt->PutStill = NULL;
371    adapt->GetVideo = NULL;
372    adapt->GetStill = NULL;
373    adapt->StopVideo = S3VStopVideo;
374    /* Empty Attrib functions - required anyway */
375    adapt->SetPortAttribute = S3VSetPortAttributeOverlay;
376    adapt->GetPortAttribute = S3VGetPortAttributeOverlay;
377    adapt->QueryBestSize = S3VQueryBestSize;
378    adapt->PutImage = S3VPutImage;
379    adapt->QueryImageAttributes = S3VQueryImageAttributes;
380
381    /* gotta uninit this someplace */
382    REGION_NULL(pScreen, &(ps3v->portPrivate->clip));
383
384    S3VResetVideoOverlay(pScrn);
385
386    return adapt;
387}
388
389
390static void
391S3VStopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
392{
393  S3VPtr ps3v = S3VPTR(pScrn);
394  S3VPortPrivPtr pPriv = ps3v->portPrivate;
395
396  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
397
398  if(shutdown) {
399     if(pPriv->videoStatus & CLIENT_VIDEO_ON)
400       {
401	 if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
402	      S3_ViRGE_MX_SERIES(ps3v->Chipset)
403	      )
404	   {
405	     /*  Aaarg... It .. won't.. go .. away!  */
406	     /* So let's be creative, make the overlay really */
407	     /* small and near an edge. */
408	     /* Size of 0 leaves a window sized vertical stripe */
409	     /* Size of 1 leaves a single pixel.. */
410	     OUTREG(SSTREAM_WINDOW_SIZE_REG, 1);
411	     /* And hide it at 0,0 */
412	     OUTREG(SSTREAM_START_REG, 0 );
413	   }
414	 else
415	   {
416	     /* Primary over secondary */
417	     OUTREG(BLEND_CONTROL_REG, 0x01000000);
418	   }
419       }
420
421     if(pPriv->area) {
422	xf86FreeOffscreenArea(pPriv->area);
423	pPriv->area = NULL;
424     }
425     pPriv->videoStatus = 0;
426#if 0
427  } else {
428     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
429	pPriv->videoStatus |= OFF_TIMER;
430	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
431     }
432#endif
433  }
434}
435
436
437
438static FBAreaPtr
439S3VAllocateMemory(
440   ScrnInfoPtr pScrn,
441   FBAreaPtr area,
442   int numlines
443){
444   ScreenPtr pScreen;
445   FBAreaPtr new_area;
446
447   if(area) {
448	if((area->box.y2 - area->box.y1) >= numlines)
449	   return area;
450
451        if(xf86ResizeOffscreenArea(area, pScrn->displayWidth, numlines))
452	   return area;
453
454	xf86FreeOffscreenArea(area);
455   }
456
457   pScreen = screenInfo.screens[pScrn->scrnIndex];
458
459   new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
460				numlines, 0, NULL, NULL, NULL);
461
462   if(!new_area) {
463	int max_w, max_h;
464
465	xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
466			FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
467
468	if((max_w < pScrn->displayWidth) || (max_h < numlines))
469	   return NULL;
470
471	xf86PurgeUnlockedOffscreenAreas(pScreen);
472	new_area = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth,
473				numlines, 0, NULL, NULL, NULL);
474   }
475
476   return new_area;
477}
478
479
480
481static void
482S3VDisplayVideoOverlay(
483    ScrnInfoPtr pScrn,
484    int id,
485    int offset,
486    short width, short height,
487    int pitch,
488    /* x,y src coordinates */
489    int x1, int y1, int x2, int y2,
490    /* dst in BoxPtr format */
491    BoxPtr dstBox,
492    /* src width and height */
493    short src_w, short src_h,
494    /* dst width and height */
495    short drw_w, short drw_h
496){
497    int tmp;
498
499#if 0
500    CHECK_DMA_QUIESCENT(pMga, pScrn);
501#endif
502    S3VPtr ps3v = S3VPTR(pScrn);
503    S3VPortPrivPtr pPriv = ps3v->portPrivate;
504
505  vgaHWPtr hwp = VGAHWPTR(pScrn);
506  /*  S3VPtr ps3v = S3VPTR(pScrn);*/
507  int vgaCRIndex, vgaCRReg, vgaIOBase;
508  vgaIOBase = hwp->IOBase;
509  vgaCRIndex = vgaIOBase + 4;
510  vgaCRReg = vgaIOBase + 5;
511
512   /* If streams aren't enabled, do nothing */
513   if(!ps3v->NeedSTREAMS)
514     return;
515
516
517    /* Reference at http://www.webartz.com/fourcc/ */
518      /* Looks like ViRGE only supports YUY2 and Y211?, */
519      /* listed as YUV-16 (4.2.2) and YUV (2.1.1) in manual. */
520
521#if 0
522      /* Only supporting modes we listed for the time being, */
523      /* No, switching required... #if 0'd this out */
524
525    switch(id) {
526    case FOURCC_UYVY:
527      /*
528	FOURCC=0x59565955
529	bpp=16
530	YUV 4:2:2 (Y sample at every
531	pixel, U and V sampled at
532	every second pixel
533	horizontally on each line). A
534	macropixel contains 2 pixels
535	in 1 u_int32.
536      */
537
538      /* OUTREG(MGAREG_BESGLOBCTL, 0x000000c3 | (tmp << 16));*/
539	 break;
540    case FOURCC_YUY2:
541      /*
542	FOURCC=0x32595559
543	bpp=16
544	YUV 4:2:2 as for UYVY but
545	with different component
546	ordering within the u_int32
547	macropixel.
548
549	Supports YV12 & I420 by copy over conversion of formats to YUY2,
550	copied from mga driver.  Thanks Mark!
551       */
552    default:
553      /*OUTREG(MGAREG_BESGLOBCTL, 0x00000083 | (tmp << 16));*/
554      /* YUV-16 (4.2.2) Secondary stream */
555      /* temp ... add DDA Horiz Accum. */
556      /*OUTREG(SSTREAM_CONTROL_REG, 0x02000000); / YUV-16 */
557      /* works for xvtest and suzi */
558      /* OUTREG(SSTREAM_CONTROL_REG, 0x01000000);  * YCbCr-16 * no scaling */
559
560      /* calc horizontal scale factor */
561      tmp = drw_w / src_w;
562      if (drw_w == src_w) tmp = 0;
563      else if (tmp>=4) tmp =3;
564      else if (tmp>=2) tmp =2;
565      else tmp =1;
566
567      /* YCbCr-16 */
568      OUTREG(SSTREAM_CONTROL_REG,
569	     tmp << 28 | 0x01000000 |
570	     ((((src_w-1)<<1)-(drw_w-1)) & 0xfff)
571	     );
572      break;
573    }
574#endif
575
576      /* calc horizontal scale factor */
577      if (drw_w == src_w)
578	tmp = 0;
579      else
580	tmp =2;
581      /* YCbCr-16 */
582    OUTREG(SSTREAM_CONTROL_REG,
583	   tmp << 28 | 0x01000000 |
584	   ((((src_w-1)<<1)-(drw_w-1)) & 0xfff)
585	   );
586
587    OUTREG(SSTREAM_STRETCH_REG,
588	   ((src_w - 1) & 0x7ff) | (((src_w-drw_w-1) & 0x7ff) << 16)
589	   );
590
591    /* Color key on primary */
592    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
593	 S3_ViRGE_MX_SERIES(ps3v->Chipset)
594	 )
595      {
596	/* 100% of secondary, no primary */
597	/* gx2/mx can both blend while keying, need to */
598	/* select secondary here, otherwise all you'll get */
599	/* from the primary is the color key.  (And setting */
600	/* 0 here gives you black... no primary or secondary. */
601	/* Discovered that the hard way!) */
602	OUTREG(BLEND_CONTROL_REG, 0x20 );
603      }
604    else
605      {
606	OUTREG(BLEND_CONTROL_REG, 0x05000000);
607      }
608
609    OUTREG(SSTREAM_FBADDR0_REG, offset & 0x3fffff );
610    OUTREG(SSTREAM_STRIDE_REG, pitch & 0xfff );
611
612    OUTREG(K1_VSCALE_REG, src_h-1 );
613    OUTREG(K2_VSCALE_REG, (src_h - drw_h) & 0x7ff );
614
615    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
616	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
617      {
618	/* enable vert interp. & bandwidth saving - gx2 */
619	OUTREG(DDA_VERT_REG, (((~drw_h)-1) & 0xfff ) |
620	       /* bw & vert interp */
621	       0xc000
622	       /* no bw save 0x8000*/
623	       );
624      }
625    else
626      {
627	OUTREG(DDA_VERT_REG, (((~drw_h)-1)) & 0xfff );
628      }
629
630    OUTREG(SSTREAM_START_REG, ((dstBox->x1 +1) << 16) | (dstBox->y1 +1));
631    OUTREG(SSTREAM_WINDOW_SIZE_REG,
632	   ( ((drw_w-1) << 16) | (drw_h ) ) & 0x7ff07ff
633	   );
634
635    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
636	 S3_ViRGE_MX_SERIES(ps3v->Chipset)
637	 )
638      {
639	OUTREG(COL_CHROMA_KEY_CONTROL_REG,
640	       /* color key ON - keying on primary */
641	       0x40000000  |
642	       /* # bits to compare */
643	       ((pScrn->weight.red-1) << 24) |
644
645	       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
646	       (16 + 8-pScrn->weight.red) |
647
648	       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
649	       (8 + 8-pScrn->weight.green) |
650
651	       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
652	       (8-pScrn->weight.blue)
653	       );
654      }
655    else
656      {
657	OUTREG(COL_CHROMA_KEY_CONTROL_REG,
658	       /* color key ON */
659	       0x10000000 |
660	       /* # bits to compare */
661	       ((pScrn->weight.red-1) << 24) |
662
663	       ((pPriv->colorKey & pScrn->mask.red) >> pScrn->offset.red) <<
664	       (16 + 8-pScrn->weight.red) |
665
666	       ((pPriv->colorKey & pScrn->mask.green) >> pScrn->offset.green) <<
667	       (8 + 8-pScrn->weight.green) |
668
669	       ((pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue) <<
670	       (8-pScrn->weight.blue)
671	       );
672      }
673
674    if ( S3_ViRGE_GX2_SERIES(ps3v->Chipset) ||
675	 S3_ViRGE_MX_SERIES(ps3v->Chipset) )
676      {
677	VGAOUT8(vgaCRIndex, 0x92);
678	VGAOUT8(vgaCRReg, (((pitch + 7) / 8) >> 8) | 0x80);
679	VGAOUT8(vgaCRIndex, 0x93);
680	VGAOUT8(vgaCRReg, (pitch + 7) / 8);
681      }
682
683}
684
685
686static int
687S3VPutImage(
688  ScrnInfoPtr pScrn,
689  short src_x, short src_y,
690  short drw_x, short drw_y,
691  short src_w, short src_h,
692  short drw_w, short drw_h,
693  int id, unsigned char* buf,
694  short width, short height,
695  Bool sync,
696  RegionPtr clipBoxes, pointer data,
697  DrawablePtr pDraw
698){
699   S3VPtr ps3v = S3VPTR(pScrn);
700   S3VPortPrivPtr pPriv = ps3v->portPrivate;
701   INT32 x1, x2, y1, y2;
702   unsigned char *dst_start;
703   int pitch, new_h, offset, offset2=0, offset3=0;
704   int srcPitch, srcPitch2=0, dstPitch;
705   int top, left, npixels, nlines;
706   BoxRec dstBox;
707   CARD32 tmp;
708
709   /* If streams aren't enabled, do nothing */
710   if(!ps3v->NeedSTREAMS)
711     return Success;
712
713   /* Clip */
714   x1 = src_x;
715   x2 = src_x + src_w;
716   y1 = src_y;
717   y2 = src_y + src_h;
718
719   dstBox.x1 = drw_x;
720   dstBox.x2 = drw_x + drw_w;
721   dstBox.y1 = drw_y;
722   dstBox.y2 = drw_y + drw_h;
723
724   if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2,
725			     clipBoxes, width, height))
726	return Success;
727
728   /*if(!pMga->TexturedVideo) {*/
729	dstBox.x1 -= pScrn->frameX0;
730	dstBox.x2 -= pScrn->frameX0;
731	dstBox.y1 -= pScrn->frameY0;
732	dstBox.y2 -= pScrn->frameY0;
733	/*}*/
734
735   pitch = pScrn->bitsPerPixel * pScrn->displayWidth >> 3;
736
737   dstPitch = ((width << 1) + 15) & ~15;
738   new_h = ((dstPitch * height) + pitch - 1) / pitch;
739
740   switch(id) {
741   case FOURCC_YV12:
742   case FOURCC_I420:
743	srcPitch = (width + 3) & ~3;
744	offset2 = srcPitch * height;
745	srcPitch2 = ((width >> 1) + 3) & ~3;
746	offset3 = (srcPitch2 * (height >> 1)) + offset2;
747	break;
748   case FOURCC_UYVY:
749   case FOURCC_YUY2:
750   default:
751	srcPitch = (width << 1);
752	break;
753   }
754
755   if(!(pPriv->area = S3VAllocateMemory(pScrn, pPriv->area, new_h)))
756	return BadAlloc;
757
758    /* copy data */
759    top = y1 >> 16;
760    left = (x1 >> 16) & ~1;
761    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
762    left <<= 1;
763
764    offset = pPriv->area->box.y1 * pitch;
765    dst_start = ps3v->FBStart + offset + left + (top * dstPitch);
766    /*dst_start = pMga->FbStart + offset + left + (top * dstPitch);*/
767
768
769    switch(id) {
770    case FOURCC_YV12:
771    case FOURCC_I420:
772	top &= ~1;
773	tmp = ((top >> 1) * srcPitch2) + (left >> 2);
774	offset2 += tmp;
775	offset3 += tmp;
776	if(id == FOURCC_I420) {
777	   tmp = offset2;
778	   offset2 = offset3;
779	   offset3 = tmp;
780	}
781	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
782	xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
783				buf + offset2, buf + offset3, dst_start,
784				srcPitch, srcPitch2, dstPitch, nlines, npixels);
785	break;
786    case FOURCC_UYVY:
787    case FOURCC_YUY2:
788    default:
789	buf += (top * srcPitch) + left;
790	nlines = ((y2 + 0xffff) >> 16) - top;
791	xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
792        break;
793    }
794
795
796    /* update cliplist */
797	if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
798	    REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
799	    /* draw these */
800	    xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
801	}
802
803	offset += left + (top * dstPitch);
804	S3VDisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch,
805	     x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h);
806
807	pPriv->videoStatus = CLIENT_VIDEO_ON;
808
809
810    return Success;
811}
812
813
814static int
815S3VQueryImageAttributes(
816    ScrnInfoPtr pScrn,
817    int id,
818    unsigned short *w, unsigned short *h,
819    int *pitches, int *offsets
820){
821
822    int size, tmp;
823
824	if(*w > 1024) *w = 1024;
825	if(*h > 1024) *h = 1024;
826
827    *w = (*w + 1) & ~1;
828    if(offsets) offsets[0] = 0;
829
830    switch(id) {
831    case FOURCC_YV12:
832    case FOURCC_I420:
833	*h = (*h + 1) & ~1;
834	size = (*w + 3) & ~3;
835	if(pitches) pitches[0] = size;
836	size *= *h;
837	if(offsets) offsets[1] = size;
838	tmp = ((*w >> 1) + 3) & ~3;
839	if(pitches) pitches[1] = pitches[2] = tmp;
840	tmp *= (*h >> 1);
841	size += tmp;
842	if(offsets) offsets[2] = size;
843	size += tmp;
844	break;
845    case FOURCC_UYVY:
846    case FOURCC_YUY2:
847    default:
848	size = *w << 1;
849	if(pitches) pitches[0] = size;
850	size *= *h;
851	break;
852    }
853
854    return size;
855}
856