1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#include "xf86.h"
7#include "tdfx.h"
8#include "dixstruct.h"
9
10#include <X11/extensions/Xv.h>
11#include "fourcc.h"
12
13static Atom xvColorKey, xvFilterQuality;
14
15/* These should move into tdfxdefs.h with better names */
16#define YUV_Y_BASE              0xC00000
17#define YUV_U_BASE              0xD00000
18#define YUV_V_BASE              0xE00000
19
20#define SST_2D_FORMAT_YUYV      0x8
21#define SST_2D_FORMAT_UYVY      0x9
22
23#define YUVBASEADDR             0x80100
24#define YUVSTRIDE               0x80104
25#define VIDPROCCFGMASK          0xa2e3eb6c
26
27#define OFF_DELAY               250  /* milliseconds */
28#define FREE_DELAY              15000
29
30#define OFF_TIMER               0x01
31#define FREE_TIMER              0x02
32#define CLIENT_VIDEO_ON         0x04
33#define TIMER_MASK              (OFF_TIMER | FREE_TIMER)
34
35#define TDFX_MAX_OVERLAY_PORTS  1
36#define TDFX_MAX_TEXTURE_PORTS  32
37
38#define GET_PORT_PRIVATE(pScrn) \
39   (TDFXPortPrivPtr)((TDFXPTR(pScrn))->overlayAdaptor->pPortPrivates[0].ptr)
40
41/* Needed for attribute atoms */
42#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
43
44/*
45 * PROTOTYPES
46 */
47
48static FBAreaPtr TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height);
49static FBLinearPtr TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size);
50static void TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time);
51
52static XF86VideoAdaptorPtr TDFXSetupImageVideoTexture(ScreenPtr);
53static int  TDFXSetPortAttributeTexture(ScrnInfoPtr, Atom, INT32, pointer);
54static int  TDFXGetPortAttributeTexture(ScrnInfoPtr, Atom ,INT32 *, pointer);
55static int  TDFXPutImageTexture(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer, DrawablePtr);
56static void TDFXStopVideoTexture(ScrnInfoPtr, pointer, Bool);
57
58static XF86VideoAdaptorPtr TDFXSetupImageVideoOverlay(ScreenPtr);
59static int  TDFXSetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
60static int  TDFXGetPortAttributeOverlay(ScrnInfoPtr, Atom ,INT32 *, pointer);
61static int  TDFXPutImageOverlay(ScrnInfoPtr, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, Bool, RegionPtr, pointer, DrawablePtr);
62static void TDFXStopVideoOverlay(ScrnInfoPtr, pointer, Bool);
63static void TDFXResetVideoOverlay(ScrnInfoPtr);
64
65static void TDFXQueryBestSize(ScrnInfoPtr, Bool, short, short, short, short, unsigned int *, unsigned int *, pointer);
66static int  TDFXQueryImageAttributes(ScrnInfoPtr, int, unsigned short *, unsigned short *,  int *, int *);
67
68static void TDFXInitOffscreenImages(ScreenPtr);
69
70/*
71 * ADAPTOR INFORMATION
72 */
73
74static XF86VideoEncodingRec OverlayEncoding[] =
75{
76   { 0, "XV_IMAGE", 2048, 2048, {1, 1} }
77};
78
79static XF86VideoEncodingRec TextureEncoding[] =
80{
81   { 0, "XV_IMAGE", 1024, 1024, {1, 1} }
82};
83
84static XF86VideoFormatRec OverlayFormats[] =
85{
86   {8, TrueColor}, {8, DirectColor}, {8, PseudoColor},
87   {8, GrayScale}, {8, StaticGray}, {8, StaticColor},
88   {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
89   {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
90};
91
92static XF86VideoFormatRec TextureFormats[] =
93{
94   {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
95};
96
97static XF86AttributeRec OverlayAttributes[] =
98{
99   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
100   {XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"}
101};
102
103static XF86AttributeRec TextureAttributes[] =
104{
105   {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
106   {XvSettable | XvGettable, 0, 1, "XV_FILTER_QUALITY"}
107};
108
109static XF86ImageRec OverlayImages[] =
110{
111  XVIMAGE_YUY2, XVIMAGE_UYVY, XVIMAGE_YV12, XVIMAGE_I420
112};
113
114static XF86ImageRec TextureImages[] =
115{
116  XVIMAGE_YV12, XVIMAGE_I420
117};
118
119/*
120 * COMMON SETUP FUNCTIONS
121 */
122
123void TDFXInitVideo(ScreenPtr pScreen)
124{
125    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
126    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
127    XF86VideoAdaptorPtr newAdaptor = NULL;
128    TDFXPtr pTDFX = TDFXPTR(pScrn);
129    int num_adaptors;
130
131    /* The hardware can't convert YUV->8 bit color */
132    if(pTDFX->cpp == 1)
133      return;
134
135    if (!pTDFX->TextureXvideo) {
136	/* Offscreen support for Overlay only */
137    	TDFXInitOffscreenImages(pScreen);
138
139    	/* Overlay adaptor */
140        newAdaptor = TDFXSetupImageVideoOverlay(pScreen);
141    } else {
142    	/* Texture adaptor */
143        newAdaptor = TDFXSetupImageVideoTexture(pScreen);
144    }
145
146    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
147
148    if(newAdaptor) {
149	if (!num_adaptors) {
150	    num_adaptors = 1;
151	    adaptors = &newAdaptor;
152	} else {
153            newAdaptors =
154		malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr*));
155            if(newAdaptors) {
156                memcpy(newAdaptors, adaptors, num_adaptors *
157						sizeof(XF86VideoAdaptorPtr));
158                newAdaptors[num_adaptors] = newAdaptor;
159                adaptors = newAdaptors;
160                num_adaptors++;
161            }
162	}
163    }
164
165    if(num_adaptors)
166        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
167
168    if(newAdaptors)
169        free(newAdaptors);
170}
171
172
173void TDFXCloseVideo (ScreenPtr pScreen)
174{
175}
176
177
178static XF86VideoAdaptorPtr
179TDFXAllocAdaptor(ScrnInfoPtr pScrn, int numberPorts)
180{
181    XF86VideoAdaptorPtr adapt;
182    TDFXPtr pTDFX = TDFXPTR(pScrn);
183    TDFXPortPrivPtr pPriv;
184
185    if(!(adapt = xf86XVAllocateVideoAdaptorRec(pScrn)))
186        return NULL;
187
188    if(!(pPriv = calloc(1, sizeof(TDFXPortPrivRec) + (numberPorts * sizeof(DevUnion)))))
189    {
190        free(adapt);
191        return NULL;
192    }
193
194    adapt->pPortPrivates = (DevUnion*)(&pPriv[1]);
195    adapt->pPortPrivates[0].ptr = (pointer)pPriv;
196
197    xvColorKey = MAKE_ATOM("XV_COLORKEY");
198    xvFilterQuality = MAKE_ATOM("XV_FILTER_QUALITY");
199
200    pPriv->colorKey = pTDFX->videoKey;
201    pPriv->videoStatus = 0;
202    pPriv->filterQuality = 1;
203
204    return adapt;
205}
206
207
208static XF86VideoAdaptorPtr
209TDFXSetupImageVideoOverlay(ScreenPtr pScreen)
210{
211    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
212    TDFXPtr pTDFX = TDFXPTR(pScrn);
213    TDFXPortPrivPtr pPriv;
214    XF86VideoAdaptorPtr adapt;
215
216    if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_OVERLAY_PORTS)))
217        return NULL;
218
219    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
220    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
221    adapt->name = "3dfx Video Overlay";
222    adapt->nPorts = TDFX_MAX_OVERLAY_PORTS;
223    adapt->nEncodings = sizeof(OverlayEncoding) / sizeof(XF86VideoEncodingRec);
224    adapt->pEncodings = OverlayEncoding;
225    adapt->nFormats = sizeof(OverlayFormats) / sizeof(XF86VideoFormatRec);
226    adapt->pFormats = OverlayFormats;
227    adapt->nAttributes = sizeof(OverlayAttributes) / sizeof(XF86AttributeRec);
228    adapt->pAttributes = OverlayAttributes;
229    adapt->nImages = sizeof(OverlayImages) / sizeof(XF86ImageRec);
230    adapt->pImages = OverlayImages;
231    adapt->PutVideo = NULL;
232    adapt->PutStill = NULL;
233    adapt->GetVideo = NULL;
234    adapt->GetStill = NULL;
235    adapt->StopVideo = TDFXStopVideoOverlay;
236    adapt->SetPortAttribute = TDFXSetPortAttributeOverlay;
237    adapt->GetPortAttribute = TDFXGetPortAttributeOverlay;
238    adapt->QueryBestSize = TDFXQueryBestSize;
239    adapt->PutImage = TDFXPutImageOverlay;
240    adapt->QueryImageAttributes = TDFXQueryImageAttributes;
241
242    pTDFX->overlayAdaptor = adapt;
243
244    pPriv = (TDFXPortPrivPtr)(adapt->pPortPrivates[0].ptr);
245    REGION_NULL(pScreen, &(pPriv->clip));
246
247    TDFXResetVideoOverlay(pScrn);
248
249    return adapt;
250}
251
252static XF86VideoAdaptorPtr
253TDFXSetupImageVideoTexture(ScreenPtr pScreen)
254{
255    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
256    TDFXPtr pTDFX = TDFXPTR(pScrn);
257    XF86VideoAdaptorPtr adapt;
258    int i;
259
260    if(!(adapt = TDFXAllocAdaptor(pScrn, TDFX_MAX_TEXTURE_PORTS)))
261        return NULL;
262
263    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
264    adapt->flags = VIDEO_OVERLAID_IMAGES;
265    adapt->name = "3dfx Video Texture";
266    adapt->nPorts = TDFX_MAX_TEXTURE_PORTS;
267    adapt->nEncodings = sizeof(TextureEncoding) / sizeof(XF86VideoEncodingRec);
268    adapt->pEncodings = TextureEncoding;
269    adapt->nFormats = sizeof(TextureFormats) / sizeof(XF86VideoFormatRec);
270    adapt->pFormats = TextureFormats;
271    adapt->nAttributes = sizeof(TextureAttributes) / sizeof(XF86AttributeRec);
272    adapt->pAttributes = TextureAttributes;
273    adapt->nImages = sizeof(TextureImages) / sizeof(XF86ImageRec);
274    adapt->pImages = TextureImages;
275    adapt->PutVideo = NULL;
276    adapt->PutStill = NULL;
277    adapt->GetVideo = NULL;
278    adapt->GetStill = NULL;
279    adapt->StopVideo = TDFXStopVideoTexture;
280    adapt->SetPortAttribute = TDFXSetPortAttributeTexture;
281    adapt->GetPortAttribute = TDFXGetPortAttributeTexture;
282    adapt->QueryBestSize = TDFXQueryBestSize;
283    adapt->PutImage = TDFXPutImageTexture;
284    adapt->QueryImageAttributes = TDFXQueryImageAttributes;
285
286    for(i = 0; i < TDFX_MAX_TEXTURE_PORTS; i++)
287        adapt->pPortPrivates[i].val = i;
288
289    pTDFX->textureAdaptor = adapt;
290
291    return adapt;
292}
293
294
295/*
296 * MISCELLANEOUS ROUTINES
297 */
298
299static int
300TDFXQueryImageAttributes(
301    ScrnInfoPtr pScrn,
302    int id,
303    unsigned short *w, unsigned short *h,
304    int *pitches, int *offsets
305){
306    int size, tmp;
307
308    if(*w > 1024) *w = 1024;
309    if(*h > 1024) *h = 1024;
310
311    *w = (*w + 1) & ~1;
312    if(offsets) offsets[0] = 0;
313
314    switch(id) {
315    case FOURCC_YV12:
316    case FOURCC_I420:
317        *h = (*h + 1) & ~1;
318        size = (*w + 3) & ~3;
319        if(pitches) pitches[0] = size;
320        size *= *h;
321        if(offsets) offsets[1] = size;
322        tmp = ((*w >> 1) + 3) & ~3;
323        if(pitches) pitches[1] = pitches[2] = tmp;
324        tmp *= (*h >> 1);
325        size += tmp;
326        if(offsets) offsets[2] = size;
327        size += tmp;
328        break;
329    case FOURCC_UYVY:
330    case FOURCC_YUY2:
331    default:
332        size = *w << 1;
333        if(pitches) pitches[0] = size;
334        size *= *h;
335        break;
336    }
337
338    return size;
339}
340
341
342static int
343TDFXSetPortAttributeOverlay(
344  ScrnInfoPtr pScrn,
345  Atom attribute,
346  INT32 value,
347  pointer data
348){
349
350  TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
351  TDFXPtr pTDFX = TDFXPTR(pScrn);
352
353  if(attribute == xvColorKey) {
354        pPriv->colorKey = value;
355        pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey);
356        pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey);
357        REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
358  } else if(attribute == xvFilterQuality) {
359        if((value < 0) || (value > 1))
360           return BadValue;
361        pPriv->filterQuality = value;
362  } else return BadMatch;
363
364  return Success;
365}
366
367static int
368TDFXGetPortAttributeOverlay(
369  ScrnInfoPtr pScrn,
370  Atom attribute,
371  INT32 *value,
372  pointer data
373){
374  TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
375
376  if(attribute == xvColorKey) {
377        *value = pPriv->colorKey;
378  } else if(attribute == xvFilterQuality) {
379        *value = pPriv->filterQuality;
380  } else return BadMatch;
381
382  return Success;
383}
384
385
386static int
387TDFXSetPortAttributeTexture(
388  ScrnInfoPtr pScrn,
389  Atom attribute,
390  INT32 value,
391  pointer data
392) {
393  return Success;
394}
395
396
397static int
398TDFXGetPortAttributeTexture(
399  ScrnInfoPtr pScrn,
400  Atom attribute,
401  INT32 *value,
402  pointer data
403){
404  return Success;
405}
406
407
408static void
409TDFXQueryBestSize(
410  ScrnInfoPtr pScrn,
411  Bool motion,
412  short vid_w, short vid_h,
413  short drw_w, short drw_h,
414  unsigned int *p_w, unsigned int *p_h,
415  pointer data
416){
417   if(vid_w > drw_w) drw_w = vid_w;
418   if(vid_h > drw_h) drw_h = vid_h;
419
420  *p_w = drw_w;
421  *p_h = drw_h;
422}
423
424
425static void
426TDFXCopyData(
427  unsigned char *src,
428  unsigned char *dst,
429  int srcPitch,
430  int dstPitch,
431  int h,
432  int w
433){
434#if X_BYTE_ORDER == X_BIG_ENDIAN
435    w >>= 1;
436    while(h--) {
437      int i;
438      for (i=0; i<w; i++)
439       ((unsigned long *)dst)[i]=BE_WSWAP32(((unsigned long *)src)[i]);
440       src += srcPitch;
441       dst += dstPitch;
442    }
443#else
444     w <<= 1;
445     while(h--) {
446 	memcpy(dst, src, w);
447 	src += srcPitch;
448 	dst += dstPitch;
449     }
450#endif
451}
452
453static void
454TDFXCopyMungedData(
455   unsigned char *src1,
456   unsigned char *src2,
457   unsigned char *src3,
458   unsigned char *dst1,
459   int srcPitch,
460   int srcPitch2,
461   int dstPitch,
462   int h,
463   int w
464){
465   CARD32 *dst;
466   CARD8 *s1, *s2, *s3;
467   int i, j;
468
469   w >>= 1;
470
471   for(j = 0; j < h; j++) {
472        dst = (CARD32*)dst1;
473        s1 = src1;  s2 = src2;  s3 = src3;
474        i = w;
475        while(i > 4) {
476           dst[0] = BE_WSWAP32(s1[0] | (s1[1] << 16) | (s3[0] << 8) |
477			(s2[0] << 24));
478           dst[1] = BE_WSWAP32(s1[2] | (s1[3] << 16) | (s3[1] << 8) |
479			(s2[1] << 24));
480           dst[2] = BE_WSWAP32(s1[4] | (s1[5] << 16) | (s3[2] << 8) |
481			(s2[2] << 24));
482           dst[3] = BE_WSWAP32(s1[6] | (s1[7] << 16) | (s3[3] << 8) |
483			(s2[3] << 24));
484 	   dst += 4; s2 += 4; s3 += 4; s1 += 8;
485 	   i -= 4;
486 	}
487 	while(i--) {
488	   dst[0] = BE_WSWAP32(s1[0] | (s1[1] << 16) | (s3[0] << 8) |
489				(s2[0] << 24));
490 	   dst++; s2++; s3++;
491 	   s1 += 2;
492 	}
493
494        dst1 += dstPitch;
495        src1 += srcPitch;
496        if(j & 1) {
497            src2 += srcPitch2;
498            src3 += srcPitch2;
499        }
500   }
501}
502
503
504/*
505 * TEXTURE DRAWING FUNCTIONS
506 */
507
508
509static void
510TDFXStopVideoTexture(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
511{
512  TDFXPtr pTDFX = TDFXPTR(pScrn);
513
514  if (cleanup) {
515     if(pTDFX->textureBuffer) {
516        xf86FreeOffscreenArea(pTDFX->textureBuffer);
517        pTDFX->textureBuffer = NULL;
518     }
519  }
520}
521
522
523static void
524TDFXScreenToScreenYUVStretchBlit (ScrnInfoPtr pScrn,
525                                  short src_x1, short src_y1,
526                                  short src_x2, short src_y2,
527                                  short dst_x1, short dst_y1,
528                                  short dst_x2, short dst_y2)
529{
530   TDFXPtr pTDFX = TDFXPTR(pScrn);
531   /* reformulate the paramaters the way the hardware wants them */
532   INT32 src_x = src_x1 & 0x1FFF;
533   INT32 src_y = src_y1 & 0x1FFF;
534   INT32 dst_x = dst_x1 & 0x1FFF;
535   INT32 dst_y = dst_y1 & 0x1FFF;
536   INT32 src_w = (src_x2 - src_x1) & 0x1FFF;
537   INT32 src_h = (src_y2 - src_y1) & 0x1FFF;
538   INT32 dst_w = (dst_x2 - dst_x1) & 0x1FFF;
539   INT32 dst_h = (dst_y2 - dst_y1) & 0x1FFF;
540
541   /* Setup for blit src and dest */
542   TDFXMakeRoom(pTDFX, 4);
543   DECLARE(SSTCP_DSTSIZE|SSTCP_SRCSIZE|SSTCP_DSTXY|SSTCP_COMMAND/*|SSTCP_COMMANDEXTRA*/);
544   /* TDFXWriteLong(pTDFX, SST_2D_COMMANDEXTRA, SST_COMMANDEXTRA_VSYNC);*/
545   TDFXWriteLong(pTDFX, SST_2D_SRCSIZE, src_w | (src_h<<16));
546   TDFXWriteLong(pTDFX, SST_2D_DSTSIZE, dst_w | (dst_h<<16));
547   TDFXWriteLong(pTDFX, SST_2D_DSTXY,   dst_x | (dst_y<<16));
548   TDFXWriteLong(pTDFX, SST_2D_COMMAND, SST_2D_SCRNTOSCRNSTRETCH | 0xCC000000);
549   /* Write to the launch area to start the blit */
550   TDFXMakeRoom(pTDFX, 1);
551   DECLARE_LAUNCH(1, 0);
552   TDFXWriteLong(pTDFX, SST_2D_LAUNCH, (src_x<<1) | (src_y<<16));
553   /* Wait for it to happen */
554   TDFXSendNOPFifo2D(pScrn);
555}
556
557
558static void
559YUVPlanarToPacked (ScrnInfoPtr pScrn,
560                   short src_x, short src_y,
561                   short src_h, short src_w,
562                   int id, unsigned char *buf,
563                   short width, short height,
564                   FBAreaPtr fbarea)
565{
566   TDFXPtr pTDFX = TDFXPTR(pScrn);
567   unsigned char *psrc, *pdst;
568   int count;
569   int baseaddr;
570   INT32 yuvBaseAddr, yuvStride;
571
572   /* Save these registers so I can restore them when we are done. */
573   yuvBaseAddr = TDFXReadLongMMIO(pTDFX, YUVBASEADDR);
574   yuvStride =   TDFXReadLongMMIO(pTDFX, YUVSTRIDE);
575
576   /* Set yuvBaseAddress and yuvStride. */
577   baseaddr = pTDFX->fbOffset + pTDFX->cpp * fbarea->box.x1 + pTDFX->stride * fbarea->box.y1;
578   TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, pTDFX->stride);
579   TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, baseaddr);
580
581   /* Copy Y plane (twice as much Y as U or V) */
582   psrc = buf;
583   psrc += (src_x & ~0x1) + src_y * width;
584   pdst = pTDFX->MMIOBase[0] + YUV_Y_BASE;
585   TDFXCopyData(psrc, pdst, width, 1024, src_h, src_w + (src_x & 0x1));
586
587   /* Copy V plane */
588   psrc = buf + width * height;
589   psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1);
590   pdst = pTDFX->MMIOBase[0] + YUV_V_BASE;
591   TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1);
592
593   /* Copy U plane */
594   psrc = buf + width * height + (width >> 1) * (height >> 1);
595   psrc += (src_x >> 1) + (src_y >> 1) * (width >> 1);
596   pdst = pTDFX->MMIOBase[0] + YUV_U_BASE;
597   TDFXCopyData(psrc, pdst, width >> 1, 1024, src_h >> 1, src_w >> 1);
598
599   /* IDLE until the copy finished, timeout for safety */
600   for (count = 0; count < 1000; count++)
601     if (!((TDFXReadLongMMIO(pTDFX, STATUS) & SST_BUSY)))
602       break;
603
604   /* Restore trashed registers */
605   TDFXWriteLongMMIO(pTDFX, YUVBASEADDR, yuvBaseAddr);
606   TDFXWriteLongMMIO(pTDFX, YUVSTRIDE, yuvStride);
607
608   /* Wait for it to happen */
609   TDFXSendNOPFifo2D(pScrn);
610}
611
612
613static int
614TDFXPutImageTexture(
615             ScrnInfoPtr pScrn,
616             short src_x, short src_y,
617             short drw_x, short drw_y,
618             short src_w, short src_h,
619             short drw_w, short drw_h,
620             int id, unsigned char* buf,
621             short width, short height,
622             Bool sync,
623             RegionPtr clipBoxes, pointer data,
624             DrawablePtr pDraw
625             )
626{
627   TDFXPtr pTDFX = TDFXPTR(pScrn);
628   BoxPtr pbox;
629   int nbox;
630   int format;
631
632   TDFXTRACE("TDFXPutImageTexture(src_x=%d, src_y=%d, drw_x=%d, drw_y=%d, .. sync=%d\n",
633		   src_x, src_y, drw_x, drw_y, sync);
634
635   /* Check the source format */
636   if (id == FOURCC_YV12)      format = SST_2D_FORMAT_YUYV;
637   else if (id == FOURCC_UYVY) format = SST_2D_FORMAT_UYVY;
638   else                        return BadAlloc;
639
640   /* Get a buffer to store the packed YUV data */
641   if (!(pTDFX->textureBuffer = TDFXAllocateMemoryArea(pScrn, pTDFX->textureBuffer, src_w, src_h)))
642        return BadAlloc;
643
644   /* Pack the YUV data in offscreen memory using YUV framebuffer (0x[CDE]0000) */
645   YUVPlanarToPacked (pScrn, src_x, src_y, src_h, src_w,
646                      id, buf, width, height,
647                      pTDFX->textureBuffer);
648
649   /* Setup source and destination pixel formats (yuv -> rgb) */
650   TDFXMakeRoom(pTDFX, 2);
651   DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
652   TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->stride|((pTDFX->cpp+1)<<16));
653   TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->stride|((format)<<16));
654
655   /* Blit packed YUV data from offscreen memory, respecting clips */
656#define SRC_X1 (pTDFX->textureBuffer->box.x1)
657#define SRC_Y1 (pTDFX->textureBuffer->box.y1)
658#define SCALEX(dx) ((int)(((dx) * src_w) / drw_w))
659#define SCALEY(dy) ((int)(((dy) * src_h) / drw_h))
660   for (nbox = REGION_NUM_RECTS(clipBoxes),
661        pbox = REGION_RECTS(clipBoxes); nbox > 0; nbox--, pbox++)
662   {
663     TDFXScreenToScreenYUVStretchBlit (pScrn,
664        SRC_X1 + SCALEX(pbox->x1 - drw_x),
665        SRC_Y1 + SCALEY(pbox->y1 - drw_y),
666        SRC_X1 + SCALEX(pbox->x2 - drw_x),
667        SRC_Y1 + SCALEY(pbox->y2 - drw_y),
668        pbox->x1, pbox->y1,
669        pbox->x2, pbox->y2);
670   }
671
672   /* Restore the WAX registers we trashed */
673   TDFXMakeRoom(pTDFX, 2);
674   DECLARE(SSTCP_SRCFORMAT|SSTCP_DSTFORMAT);
675   TDFXWriteLong(pTDFX, SST_2D_DSTFORMAT, pTDFX->sst2DDstFmtShadow);
676   TDFXWriteLong(pTDFX, SST_2D_SRCFORMAT, pTDFX->sst2DSrcFmtShadow);
677
678   /* Wait for it to happen */
679   TDFXSendNOPFifo2D(pScrn);
680
681   return Success;
682}
683
684
685/*
686 * OVERLAY DRAWING FUNCTIONS
687 */
688
689
690static void
691TDFXResetVideoOverlay(ScrnInfoPtr pScrn)
692{
693    TDFXPtr pTDFX = TDFXPTR(pScrn);
694    TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
695
696    /* reset the video */
697    pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
698    pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
699    pTDFX->writeLong(pTDFX, RGBMAXDELTA, 0x0080808);
700    pTDFX->writeLong(pTDFX, VIDCHROMAMIN, pPriv->colorKey);
701    pTDFX->writeLong(pTDFX, VIDCHROMAMAX, pPriv->colorKey);
702}
703
704
705static void
706TDFXStopVideoOverlay(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
707{
708  TDFXPtr pTDFX = TDFXPTR(pScrn);
709  TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
710
711  REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
712
713  if(cleanup) {
714     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
715        pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
716        pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
717     }
718     if(pTDFX->overlayBuffer) {
719        xf86FreeOffscreenLinear(pTDFX->overlayBuffer);
720        pTDFX->overlayBuffer = NULL;
721     }
722     if(pTDFX->overlayBuffer2) {
723        xf86FreeOffscreenLinear(pTDFX->overlayBuffer2);
724        pTDFX->overlayBuffer2 = NULL;
725     }
726     pPriv->videoStatus = 0;
727  } else {
728     if(pPriv->videoStatus & CLIENT_VIDEO_ON) {
729        pPriv->videoStatus |= OFF_TIMER;
730        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
731     }
732  }
733}
734
735
736/* * * * * *
737
738Decoder...
739
740VIDPROCCFG:  0x5c:  Video Processor Configuration register
741
742#define VIDPROCCFGMASK          0xa2e3eb6c
743  3 2         1         0
744  10987654321098765432109876543210
745  10100010111000111110101101101100
746
747The "1" bits are the bits cleared to 0 in pTDFX->ModeReg.vidcfg
748
749
750Then we or in 0x320:
751
752      11
753      109876543210
754320 = 001100100000
755
756bit 11=0: Do not bypass clut (colour lookup) for overlay
757bit 10=0: Do not bypass clut for desktop
758bit  9=1: use video-in buffer address as overlay start
759          address (auto-flipping)
760bit  8=1: fetch overlay surface
761bit  7=0: do not fetch the desktop surface (?)
762bit  6=0: chromakey not inverted
763bit  5=1: chromakey enabled
764bit  4=0: half-mode disabled
765bit  3=0: not interlaced (interlace doesn't work on Avenger)
766bit  2=0: overlay stereo disabled
767bit  1=0: Windows cursor mode
768bit  0=0: Video processor off, VGA mode on
769
770SST_VIDEO_2X_MODE_EN: bit26: means 2 pixels per screen clock mode is on
771
772VIDOVERLAYSTARTCOORDS: x&y coords of overlay on the screen
773VIDOVERLAYENDSCREENCOORDS: x&y coorder of bot-right of overlay on the screen
774VIDOVERLAYDUDX: step size in source per hoz step in screen space (x-mag)
775VIDOVERLAYDUDXOFFSETSRCWIDTH:
776VIDOVERLAYDVDY: step size in sourcxe per vertical step in screen (y-mag)
777VIDOVERLAYDVDYOFFSET: initial offset of DVDY
778VIDDESKTOPOVERLAYSTRIDE: desktop surface stride
779
780SST_3D_LEFTOVERLAYBUF: starting physical address of the overlay surface buffer
781VIDINADDR0: starting address of video-in buffer-0
782 [this is set, but this is for video _input_ as I understand docs...?]
783
784* * * * * */
785
786static void
787TDFXDisplayVideoOverlay(
788    ScrnInfoPtr pScrn,
789    int id,
790    int offset,
791    short width, short height,
792    int pitch,
793    int left, int right, int top,
794    BoxPtr dstBox,
795    short src_w, short src_h,
796    short drw_w, short drw_h
797){
798    TDFXPtr pTDFX = TDFXPTR(pScrn);
799    TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
800    int dudx, dvdy;
801
802    dudx = (src_w << 20) / drw_w;
803    /* subtract 1 to eliminate garbage on last line */
804    dvdy = (( src_h - 1 )<< 20) / drw_h;
805
806    offset += ((left >> 16) & ~1) << 1;
807    left = (left & 0x0001ffff) << 3;
808
809    pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
810    pTDFX->ModeReg.vidcfg |= 0x00000320;
811
812    if(drw_w != src_w)       pTDFX->ModeReg.vidcfg |= (1 << 14);
813    if(drw_h != src_h)       pTDFX->ModeReg.vidcfg |= (1 << 15);
814    if(id == FOURCC_UYVY)    pTDFX->ModeReg.vidcfg |= (6 << 21);
815    else                     pTDFX->ModeReg.vidcfg |= (5 << 21);
816    if(pScrn->depth == 8)    pTDFX->ModeReg.vidcfg |= (1 << 11);
817    /* can't do bilinear filtering when in 2X mode */
818    if(pPriv->filterQuality && !(pTDFX->ModeReg.vidcfg & SST_VIDEO_2X_MODE_EN))
819	pTDFX->ModeReg.vidcfg |= (3 << 16);
820    pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
821
822    pTDFX->writeLong(pTDFX, VIDOVERLAYSTARTCOORDS, dstBox->x1 | (dstBox->y1 << 12));
823    pTDFX->writeLong(pTDFX, VIDOVERLAYENDSCREENCOORDS, (dstBox->x2 - 1) | ((dstBox->y2 - 1) << 12));
824    pTDFX->writeLong(pTDFX, VIDOVERLAYDUDX, dudx);
825    pTDFX->writeLong(pTDFX, VIDOVERLAYDUDXOFFSETSRCWIDTH, left | (src_w << 20));
826    pTDFX->writeLong(pTDFX, VIDOVERLAYDVDY, dvdy);
827    pTDFX->writeLong(pTDFX, VIDOVERLAYDVDYOFFSET, (top & 0x0000ffff) << 3);
828
829    pTDFX->ModeReg.stride &= 0x0000ffff;
830    pTDFX->ModeReg.stride |= pitch << 16;
831    pTDFX->writeLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE, pTDFX->ModeReg.stride);
832    pTDFX->writeLong(pTDFX, SST_3D_LEFTOVERLAYBUF, offset & ~3);
833    pTDFX->writeLong(pTDFX, VIDINADDR0, offset & ~3);
834    TDFXTRACE("TDFXDisplayVideoOverlay: done, offset=0x%x\n", offset);
835}
836
837
838#if 0
839
840/* * * * *
841
842TDFXSwapVideoOverlayBuffer tries to use the Avenger SWAPBUFFER
843capability to change frames without tearing.
844
845Use this in preference to TDFXDisplayVideoOverlay where all image
846parameters are the same as the previous frame - ie where only the
847SST_3D_LEFTOVERLAYBUF register would have been changed.
848
849NOTE: Work in progress - doesn't seem to sync to VSYNC, and only every
850other frame gets displayed...
851
852Seeing that the buffer swap initiated by DisplayVideoOverlay gets
853synced to VSYNC anyway, just adding double-buffering to PutImageOverlay
854appears to do the job.  Still - I leave this code in in case we can
855get it working later
856
857  -- Steve Davies 2002-10-04
858  -- <steve@daviesfam.org>
859
860* * * * * */
861
862static void
863TDFXSwapVideoOverlayBuffer(
864    ScrnInfoPtr pScrn,
865    int offset,
866    int left
867){
868    TDFXPtr pTDFX = TDFXPTR(pScrn);
869    offset += ((left >> 16) & ~1) << 1;
870    /* Write mew buffer address */
871    pTDFX->writeLong(pTDFX, SST_3D_LEFTOVERLAYBUF, offset & ~3);
872    /* Incremement the swap-pending counter */
873    pTDFX->writeLong(pTDFX, SST_3D_SWAPPENDING, 0);
874    /* write the swapbuffer command - triggered by (next) VSYNC */
875    pTDFX->writeLong(pTDFX, SST_3D_SWAPBUFFERCMD, 1);
876}
877
878#endif
879
880static int
881TDFXPutImageOverlay(
882  ScrnInfoPtr pScrn,
883  short src_x, short src_y,
884  short drw_x, short drw_y,
885  short src_w, short src_h,
886  short drw_w, short drw_h,
887  int id, unsigned char* buf,
888  short width, short height,
889  Bool Sync,
890  RegionPtr clipBoxes, pointer data,
891  DrawablePtr pDraw
892){
893   TDFXPtr pTDFX = TDFXPTR(pScrn);
894   TDFXPortPrivPtr pPriv = (TDFXPortPrivPtr)data;
895   INT32 xa, xb, ya, yb;
896   unsigned char *dst_start;
897   int new_size, offset;
898   int s2offset = 0, s3offset = 0;
899   int srcPitch = 0, srcPitch2 = 0;
900   int dstPitch;
901   int top, left, npixels, nlines, bpp;
902   BoxRec dstBox;
903   CARD32 tmp;
904
905   TDFXTRACE("TDFXPutImageOverlay: src_x=%d, src_y=%d, drw_x=%d, drw_y=%d, src_w=%d, src_h=%d, drw_w=%d, drw_h=%d, id=%d, width=%d, height=%d, sync=%d\n",
906		   src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, id, width, height, Sync);
907
908   /*
909    * s2offset, s3offset - byte offsets into U and V plane of the
910    *                      source where copying starts.  Y plane is
911    *                      done by editing "buf".
912    *
913    * offset - byte offset to the first line of the destination.
914    *
915    * dst_start - byte address to the first displayed pel.
916    *
917    */
918
919   if(src_w > drw_w) drw_w = src_w;
920   if(src_h > drw_h) drw_h = src_h;
921
922   /* Clip */
923   xa = src_x;
924   xb = src_x + src_w;
925   ya = src_y;
926   yb = src_y + src_h;
927
928   dstBox.x1 = drw_x;
929   dstBox.x2 = drw_x + drw_w;
930   dstBox.y1 = drw_y;
931   dstBox.y2 = drw_y + drw_h;
932
933   if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb,
934			     clipBoxes, width, height))
935        return Success;
936
937   dstBox.x1 -= pScrn->frameX0;
938   dstBox.x2 -= pScrn->frameX0;
939   dstBox.y1 -= pScrn->frameY0;
940   dstBox.y2 -= pScrn->frameY0;
941
942   bpp = pScrn->bitsPerPixel >> 3;
943
944   switch(id) {
945   case FOURCC_YV12:
946   case FOURCC_I420:
947        dstPitch = ((width << 1) + 3) & ~3;
948        new_size = ((dstPitch * height) + bpp - 1) / bpp;
949        srcPitch = (width + 3) & ~3;
950        s2offset = srcPitch * height;
951        srcPitch2 = ((width >> 1) + 3) & ~3;
952        s3offset = (srcPitch2 * (height >> 1)) + s2offset;
953        break;
954   case FOURCC_UYVY:
955   case FOURCC_YUY2:
956   default:
957        dstPitch = ((width << 1) + 3) & ~3;
958        new_size = ((dstPitch * height) + bpp - 1) / bpp;
959        srcPitch = (width << 1);
960        break;
961   }
962
963   if(!(pTDFX->overlayBuffer = TDFXAllocateMemoryLinear(pScrn, pTDFX->overlayBuffer, new_size)))
964        return BadAlloc;
965   /* Second buffer for double-buffering (If we can't get the memory then we just don't double-buffer) */
966   if (!(pTDFX->overlayBuffer2 = TDFXAllocateMemoryLinear(pScrn, pTDFX->overlayBuffer2, new_size)))
967     pTDFX->whichOverlayBuffer = 0;
968   TDFXTRACE("TDFXPutImageOverlay: %s have a second overlay buffer for double-buffering\n",
969	     pTDFX->overlayBuffer2 ? "Do" : "Do not");
970
971   /* copy data */
972   top = ya >> 16;
973   left = (xa >> 16) & ~1;
974   npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left;
975
976   /* Get buffer offset */
977   if (pTDFX->whichOverlayBuffer == 0)
978     offset = (pTDFX->overlayBuffer->offset * bpp) + (top * dstPitch) + pTDFX->fbOffset;
979   else
980     offset = (pTDFX->overlayBuffer2->offset * bpp) + (top * dstPitch) + pTDFX->fbOffset;
981
982   /* Flip to other buffer for next time */
983   pTDFX->whichOverlayBuffer ^= 1;
984
985   dst_start = pTDFX->FbBase + offset;
986
987   switch(id) {
988    case FOURCC_YV12:
989    case FOURCC_I420:
990        top &= ~1;
991        dst_start += left << 1;
992        tmp = ((top >> 1) * srcPitch2) + (left >> 1);
993        s2offset += tmp;
994        s3offset += tmp;
995        if(id == FOURCC_I420) {
996           tmp = s2offset;
997           s2offset = s3offset;
998           s3offset = tmp;
999        }
1000        nlines = ((((yb + 0xffff) >> 16) + 1) & ~1) - top;
1001	TDFXTRACE("TDFXPutImageOverlay: using copymungeddata\n");
1002        TDFXCopyMungedData(buf + (top * srcPitch) + left, buf + s2offset,
1003                           buf + s3offset, dst_start, srcPitch, srcPitch2,
1004                           dstPitch, nlines, npixels);
1005        break;
1006    case FOURCC_UYVY:
1007    case FOURCC_YUY2:
1008    default:
1009        left <<= 1;
1010        buf += (top * srcPitch) + left;
1011        nlines = ((yb + 0xffff) >> 16) - top;
1012        dst_start += left;
1013	TDFXTRACE("TDFXPutImageOverlay: using copydata\n");
1014        TDFXCopyData(buf, dst_start, srcPitch, dstPitch, nlines, npixels);
1015        break;
1016    }
1017
1018    if(!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
1019        REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
1020	xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
1021    }
1022
1023    TDFXDisplayVideoOverlay(pScrn, id, offset, width, height, dstPitch, xa, xb, ya, &dstBox, src_w, src_h, drw_w, drw_h);
1024
1025    pPriv->videoStatus = CLIENT_VIDEO_ON;
1026
1027    pTDFX->VideoTimerCallback = TDFXVideoTimerCallback;
1028
1029    /* Display some swap-buffer related info...: vidCurrOverlayStartAddr, fbiSwapHistory */
1030    /* To give us some insight into workings or otherwise of swapbuffer stuff */
1031    TDFXTRACE("TDFXPutImageOverlay: vidCurrOverlayStrtAdr=%x, fbiSwpHist=%x, whchBuf=%d, 3Dstus=%x\n",
1032	      pTDFX->readLong(pTDFX, VIDCUROVERLAYSTARTADDR),
1033	      pTDFX->readLong(pTDFX, SST_3D_FBISWAPHISTORY),
1034	      pTDFX->whichOverlayBuffer,
1035	      pTDFX->readLong(pTDFX, SST_3D_STATUS)
1036    );
1037
1038    return Success;
1039}
1040
1041
1042static void
1043TDFXVideoTimerCallback(ScrnInfoPtr pScrn, Time time)
1044{
1045    TDFXPtr pTDFX = TDFXPTR(pScrn);
1046    TDFXPortPrivPtr pPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
1047
1048    if(pPriv->videoStatus & TIMER_MASK) {
1049        if(pPriv->videoStatus & OFF_TIMER) {
1050            if(pPriv->offTime < time) {
1051                pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
1052                pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
1053                pPriv->videoStatus = FREE_TIMER;
1054                pPriv->freeTime = time + FREE_DELAY;
1055            }
1056        } else
1057        if(pPriv->videoStatus & FREE_TIMER) {
1058            if(pPriv->freeTime < time) {
1059                if(pTDFX->overlayBuffer) {
1060                   xf86FreeOffscreenLinear(pTDFX->overlayBuffer);
1061                   pTDFX->overlayBuffer = NULL;
1062                }
1063                if(pTDFX->overlayBuffer2) {
1064                   xf86FreeOffscreenLinear(pTDFX->overlayBuffer2);
1065                   pTDFX->overlayBuffer2 = NULL;
1066                }
1067                pPriv->videoStatus = 0;
1068                pTDFX->VideoTimerCallback = NULL;
1069            }
1070        }
1071    } else  /* shouldn't get here */
1072        pTDFX->VideoTimerCallback = NULL;
1073}
1074
1075
1076/*
1077 * MEMORY MANAGEMENT
1078 */
1079
1080
1081static FBAreaPtr
1082TDFXAllocateMemoryArea (ScrnInfoPtr pScrn, FBAreaPtr area, int width, int height)
1083{
1084  TDFXPtr pTDFX = TDFXPTR(pScrn);
1085  ScreenPtr pScreen;
1086  FBAreaPtr new_area;
1087
1088  if (area) {
1089    if ((area->box.x2 - area->box.x1 >= width) &&
1090        (area->box.y2 - area->box.y1 >= height))
1091      return area;
1092
1093    if (xf86ResizeOffscreenArea(area, width, height))
1094      return area;
1095
1096    xf86FreeOffscreenArea(area);
1097  }
1098
1099  pScreen = xf86ScrnToScreen(pScrn);
1100
1101  new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL);
1102
1103  if (!new_area) {
1104    int max_width, max_height;
1105
1106    xf86QueryLargestOffscreenArea(pScreen, &max_width, &max_height, pTDFX->cpp, 0, PRIORITY_EXTREME);
1107
1108    if (max_width < width || max_height < height)
1109      return NULL;
1110
1111    xf86PurgeUnlockedOffscreenAreas(pScreen);
1112    new_area = xf86AllocateOffscreenArea(pScreen, width, height, pTDFX->cpp, NULL, NULL, NULL);
1113  }
1114
1115  return new_area;
1116}
1117
1118
1119static FBLinearPtr
1120TDFXAllocateMemoryLinear (ScrnInfoPtr pScrn, FBLinearPtr linear, int size)
1121{
1122   ScreenPtr pScreen;
1123   FBLinearPtr new_linear;
1124
1125   if(linear) {
1126        if(linear->size >= size)
1127           return linear;
1128
1129        if(xf86ResizeOffscreenLinear(linear, size))
1130           return linear;
1131
1132        xf86FreeOffscreenLinear(linear);
1133   }
1134
1135   pScreen = xf86ScrnToScreen(pScrn);
1136
1137   new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL);
1138
1139   if(!new_linear) {
1140        int max_size;
1141
1142        xf86QueryLargestOffscreenLinear(pScreen, &max_size, 4, PRIORITY_EXTREME);
1143
1144        if(max_size < size)
1145           return NULL;
1146
1147        xf86PurgeUnlockedOffscreenAreas(pScreen);
1148        new_linear = xf86AllocateOffscreenLinear(pScreen, size, 4, NULL, NULL, NULL);
1149   }
1150
1151   return new_linear;
1152}
1153
1154/****************** Offscreen stuff ***************/
1155
1156typedef struct {
1157  FBLinearPtr linear;
1158  Bool isOn;
1159} OffscreenPrivRec, * OffscreenPrivPtr;
1160
1161static int
1162TDFXAllocateSurface(
1163    ScrnInfoPtr pScrn,
1164    int id,
1165    unsigned short w,
1166    unsigned short h,
1167    XF86SurfacePtr surface
1168){
1169    TDFXPtr pTDFX = TDFXPTR(pScrn);
1170    FBLinearPtr linear;
1171    int pitch, size, bpp;
1172    OffscreenPrivPtr pPriv;
1173
1174    if((w > 2048) || (h > 2048))
1175	return BadAlloc;
1176
1177    w = (w + 1) & ~1;
1178    pitch = ((w << 1) + 15) & ~15;
1179    bpp = pScrn->bitsPerPixel >> 3;
1180    size = ((pitch * h) + bpp - 1) / bpp;
1181
1182    if(!(linear = TDFXAllocateMemoryLinear(pScrn, NULL, size)))
1183	return BadAlloc;
1184
1185    surface->width = w;
1186    surface->height = h;
1187
1188    if(!(surface->pitches = malloc(sizeof(int)))) {
1189	xf86FreeOffscreenLinear(linear);
1190	return BadAlloc;
1191    }
1192    if(!(surface->offsets = malloc(sizeof(int)))) {
1193	free(surface->pitches);
1194	xf86FreeOffscreenLinear(linear);
1195	return BadAlloc;
1196    }
1197    if(!(pPriv = malloc(sizeof(OffscreenPrivRec)))) {
1198	free(surface->pitches);
1199	free(surface->offsets);
1200	xf86FreeOffscreenLinear(linear);
1201	return BadAlloc;
1202    }
1203
1204    pPriv->linear = linear;
1205    pPriv->isOn = FALSE;
1206
1207    surface->pScrn = pScrn;
1208    surface->id = id;
1209    surface->pitches[0] = pitch;
1210    surface->offsets[0] = pTDFX->fbOffset + (linear->offset * bpp);
1211    surface->devPrivate.ptr = (pointer)pPriv;
1212
1213    return Success;
1214}
1215
1216static int
1217TDFXStopSurface(
1218    XF86SurfacePtr surface
1219){
1220    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1221
1222    if(pPriv->isOn) {
1223	TDFXPtr pTDFX = TDFXPTR(surface->pScrn);
1224        pTDFX->ModeReg.vidcfg &= ~VIDPROCCFGMASK;
1225        pTDFX->writeLong(pTDFX, VIDPROCCFG, pTDFX->ModeReg.vidcfg);
1226	pPriv->isOn = FALSE;
1227    }
1228
1229    return Success;
1230}
1231
1232
1233static int
1234TDFXFreeSurface(
1235    XF86SurfacePtr surface
1236){
1237    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1238
1239    if(pPriv->isOn)
1240	TDFXStopSurface(surface);
1241    xf86FreeOffscreenLinear(pPriv->linear);
1242    free(surface->pitches);
1243    free(surface->offsets);
1244    free(surface->devPrivate.ptr);
1245
1246    return Success;
1247}
1248
1249static int
1250TDFXGetSurfaceAttribute(
1251    ScrnInfoPtr pScrn,
1252    Atom attribute,
1253    INT32 *value
1254){
1255    return TDFXGetPortAttributeOverlay(pScrn, attribute, value,
1256			(pointer)(GET_PORT_PRIVATE(pScrn)));
1257}
1258
1259static int
1260TDFXSetSurfaceAttribute(
1261    ScrnInfoPtr pScrn,
1262    Atom attribute,
1263    INT32 value
1264){
1265    return TDFXSetPortAttributeOverlay(pScrn, attribute, value,
1266			(pointer)(GET_PORT_PRIVATE(pScrn)));
1267}
1268
1269static int
1270TDFXDisplaySurface(
1271    XF86SurfacePtr surface,
1272    short src_x, short src_y,
1273    short drw_x, short drw_y,
1274    short src_w, short src_h,
1275    short drw_w, short drw_h,
1276    RegionPtr clipBoxes
1277){
1278    OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr;
1279    ScrnInfoPtr pScrn = surface->pScrn;
1280    TDFXPtr pTDFX = TDFXPTR(pScrn);
1281    TDFXPortPrivPtr portPriv = pTDFX->overlayAdaptor->pPortPrivates[0].ptr;
1282    INT32 x1, y1, x2, y2;
1283    BoxRec dstBox;
1284
1285    x1 = src_x;
1286    x2 = src_x + src_w;
1287    y1 = src_y;
1288    y2 = src_y + src_h;
1289
1290    dstBox.x1 = drw_x;
1291    dstBox.x2 = drw_x + drw_w;
1292    dstBox.y1 = drw_y;
1293    dstBox.y2 = drw_y + drw_h;
1294
1295    if(!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
1296			      surface->width, surface->height))
1297    {
1298	return Success;
1299    }
1300
1301    dstBox.x1 -= pScrn->frameX0;
1302    dstBox.x2 -= pScrn->frameX0;
1303    dstBox.y1 -= pScrn->frameY0;
1304    dstBox.y2 -= pScrn->frameY0;
1305
1306#if 0
1307    TDFXResetVideoOverlay(pScrn);
1308#endif
1309
1310    TDFXDisplayVideoOverlay(pScrn, surface->id, surface->offsets[0],
1311	     surface->width, surface->height, surface->pitches[0],
1312	     x1, y1, x2, &dstBox, src_w, src_h, drw_w, drw_h);
1313
1314    xf86XVFillKeyHelper(pScrn->pScreen, portPriv->colorKey, clipBoxes);
1315
1316    pPriv->isOn = TRUE;
1317    /* we've prempted the XvImage stream so set its free timer */
1318    if(portPriv->videoStatus & CLIENT_VIDEO_ON) {
1319	REGION_EMPTY(pScrn->pScreen, &portPriv->clip);
1320	UpdateCurrentTime();
1321	portPriv->videoStatus = FREE_TIMER;
1322	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
1323	pTDFX->VideoTimerCallback = TDFXVideoTimerCallback;
1324    }
1325
1326    return Success;
1327}
1328
1329static void
1330TDFXInitOffscreenImages(ScreenPtr pScreen)
1331{
1332    XF86OffscreenImagePtr offscreenImages;
1333
1334    /* need to free this someplace */
1335    if(!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
1336	return;
1337
1338    offscreenImages[0].image = &OverlayImages[0];
1339    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES |
1340			       VIDEO_CLIP_TO_VIEWPORT;
1341    offscreenImages[0].alloc_surface = TDFXAllocateSurface;
1342    offscreenImages[0].free_surface = TDFXFreeSurface;
1343    offscreenImages[0].display = TDFXDisplaySurface;
1344    offscreenImages[0].stop = TDFXStopSurface;
1345    offscreenImages[0].setAttribute = TDFXSetSurfaceAttribute;
1346    offscreenImages[0].getAttribute = TDFXGetSurfaceAttribute;
1347    offscreenImages[0].max_width = 2048;
1348    offscreenImages[0].max_height = 2048;
1349    offscreenImages[0].num_attributes = 2;
1350    offscreenImages[0].attributes = OverlayAttributes;
1351
1352    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
1353}
1354