apm_video.c revision 5c69f917
1
2#ifdef HAVE_CONFIG_H
3#include "config.h"
4#endif
5
6#if PSZ != 24
7#include "dixstruct.h"
8#include "fourcc.h"
9
10/*
11 * Ported from mga_video.c by Loïc Grenié
12 */
13
14#ifndef OFF_DELAY
15#define OFF_DELAY	200
16#endif
17
18static XF86VideoAdaptorPtr A(SetupImageVideo)(ScreenPtr);
19
20static void	A(StopVideo)(ScrnInfoPtr, pointer, Bool);
21static int	A(SetPortAttribute)(ScrnInfoPtr, Atom, INT32, pointer);
22static int	ApmGetPortAttribute(ScrnInfoPtr, Atom ,INT32 *, pointer);
23static void	ApmQueryBestSize(ScrnInfoPtr, Bool, short, short, short,
24				    short, unsigned int *, unsigned int *,
25				    pointer);
26static int	ApmQueryImageAttributes(ScrnInfoPtr, int,
27					    unsigned short *, unsigned short *,
28					    int *, int *);
29#ifndef XV_NEW_REPUT
30static int	A(ReputImage)(ScrnInfoPtr, short, short, RegionPtr, pointer,
31				DrawablePtr);
32#endif
33static int	A(PutImage)(ScrnInfoPtr, short, short, short, short, short,
34				short, short, short, int, unsigned char*,
35				short, short, Bool, RegionPtr, pointer,
36				DrawablePtr);
37
38static void	A(ResetVideo)(ScrnInfoPtr);
39static void	A(XvMoveCB)(FBAreaPtr, FBAreaPtr);
40static void	A(XvRemoveCB)(FBAreaPtr);
41
42#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
43
44void A(InitVideo)(ScreenPtr pScreen)
45{
46    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
47    XF86VideoAdaptorPtr *adaptors, *newAdaptors;
48    XF86VideoAdaptorPtr newAdaptor;
49    APMDECL(pScrn);
50    int num_adaptors;
51    Bool freeAdaptors = FALSE;
52
53    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
54
55    if (pApm->Chipset >= AT24) {
56	if ((newAdaptor = A(SetupImageVideo)(pScreen))) {
57
58	   newAdaptors = malloc((num_adaptors + 1) *
59				   sizeof(XF86VideoAdaptorPtr*));
60	   if(newAdaptors) {
61		if(num_adaptors)
62		    memcpy(newAdaptors, adaptors, num_adaptors *
63					sizeof(XF86VideoAdaptorPtr));
64		newAdaptors[num_adaptors] = newAdaptor;
65		adaptors = newAdaptors;
66		num_adaptors++;
67		freeAdaptors = TRUE;
68	   }
69	}
70    }
71
72    if(num_adaptors)
73        xf86XVScreenInit(pScreen, adaptors, num_adaptors);
74
75    free(adaptors);
76}
77
78#ifndef APM_VIDEO_DEFINES
79#define APM_VIDEO_DEFINES
80
81static Atom xvBrightness, xvContrast;
82
83/* client libraries expect an encoding */
84static XF86VideoEncodingRec DummyEncoding[1] =
85{
86    {
87	0,
88	"XV_IMAGE",
89	1024, 1024,
90	{1, 1}
91    }
92};
93
94#define NUM_FORMATS 24
95
96static XF86VideoFormatRec Formats[NUM_FORMATS] =
97{
98    { 8, PseudoColor},
99    {15, PseudoColor},
100    {16, PseudoColor},
101    {24, PseudoColor},
102    {32, PseudoColor},
103    { 8, DirectColor},
104    {15, DirectColor},
105    {16, DirectColor},
106    {24, DirectColor},
107    {32, DirectColor},
108    { 8,   TrueColor},
109    {15,   TrueColor},
110    {16,   TrueColor},
111    {24,   TrueColor},
112    {32,   TrueColor}
113};
114
115#define NUM_ATTRIBUTES 2
116
117static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
118{
119    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
120    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}
121};
122
123#define NUM_IMAGES 9
124typedef char c8;
125
126static XF86ImageRec Images[NUM_IMAGES] =
127{
128   {
129	0x35315652,
130        XvRGB,
131	LSBFirst,
132	{'R','V','1','5',
133	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
134	16,
135	XvPacked,
136	1,
137	15, 0x001F, 0x03E0, 0x7C00,
138	0, 0, 0,
139	0, 0, 0,
140	0, 0, 0,
141	{'R','V','B',0,
142	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
143	XvTopToBottom
144   },
145   {
146	0x36315652,
147        XvRGB,
148	LSBFirst,
149	{'R','V','1','6',
150	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
151	16,
152	XvPacked,
153	1,
154	16, 0x001F, 0x07E0, 0xF800,
155	0, 0, 0,
156	0, 0, 0,
157	0, 0, 0,
158	{'R','V','B',0,
159	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
160	XvTopToBottom
161   },
162   {
163	0x32335652,
164        XvRGB,
165	LSBFirst,
166	{'R','V','3','2',
167	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
168	32,
169	XvPacked,
170	1,
171	24, 0x0000FF, 0x00FF00, 0xFF0000,
172	0, 0, 0,
173	0, 0, 0,
174	0, 0, 0,
175	{'R','V','B',0,
176	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
177	XvTopToBottom
178   },
179   XVIMAGE_YUY2,
180   {
181	0x59595959,
182        XvYUV,
183	LSBFirst,
184	{0x00,0x00,0x00,0x00,
185	  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
186	8,
187	XvPacked,
188	1,
189	0, 0, 0, 0,
190	8, 0, 0,
191	1, 1, 1,
192	1, 1, 1,
193	{'Y','Y','Y','Y',
194	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
195	XvTopToBottom
196   },
197   {
198	0x32315659,
199        XvYUV,
200	LSBFirst,
201	{'Y','V','1','2',
202	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
203	12,
204	XvPlanar,
205	3,
206	0, 0, 0, 0 ,
207	8, 8, 8,
208	1, 2, 2,
209	1, 2, 2,
210	{'Y','V','U',
211	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
212	XvTopToBottom
213   },
214   {
215	0x59565955,
216        XvYUV,
217	LSBFirst,
218	{'U','Y','V','Y',
219	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
220	16,
221	XvPlanar,
222	1,
223	0, 0, 0, 0,
224	8, 8, 8,
225	1, 2, 2,
226	1, 1, 1,
227	{'U','Y','V','Y',
228	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
229	XvTopToBottom
230   },
231   {
232	0x55595659,
233        XvYUV,
234	LSBFirst,
235	{'Y','V','Y','U',
236	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
237	16,
238	XvPlanar,
239	1,
240	0, 0, 0, 0,
241	8, 8, 8,
242	1, 2, 2,
243	1, 1, 1,
244	{'Y','V','Y','U',
245	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
246	XvTopToBottom
247   },
248   {
249	0x59555956,
250        XvYUV,
251	LSBFirst,
252	{'V','Y','U','Y',
253	  0x00,0x00,0x00,0x10,(c8)0x80,0x00,0x00,(c8)0xAA,0x00,0x38,(c8)0x9B,0x71},
254	16,
255	XvPlanar,
256	1,
257	0, 0, 0, 0,
258	8, 8, 8,
259	1, 2, 2,
260	1, 1, 1,
261	{'V','Y','U','Y',
262	  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
263	XvTopToBottom
264   }
265};
266
267typedef struct {
268   Bool		on;
269   unsigned char	brightness;
270   unsigned char	contrast;
271   unsigned short	reg, val;
272   ApmPtr	pApm;
273   int		x1, x10, y1, drw_x, drw_y, Bpp, Bps;
274   FBAreaPtr	area;
275   RegionRec	clip;
276   int		xnum, xden, ynum, yden;
277   CARD32	scalex, scaley;
278   CARD32	data;
279} ApmPortPrivRec, *ApmPortPrivPtr;
280#endif
281
282
283static void
284A(ResetVideo)(ScrnInfoPtr pScrn)
285{
286    APMDECL(pScrn);
287
288    A(WaitForFifo)(pApm, 2);
289    ((ApmPortPrivPtr)pApm->adaptor->pPortPrivates[0].ptr)->on = 0;
290    ((ApmPortPrivPtr)pApm->adaptor->pPortPrivates[1].ptr)->on = 0;
291    WRXW(0x82, 0);
292    WRXW(0x92, 0);
293}
294
295
296static XF86VideoAdaptorPtr
297A(SetupImageVideo)(ScreenPtr pScreen)
298{
299    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
300    APMDECL(pScrn);
301    XF86VideoAdaptorPtr adapt;
302    ApmPortPrivPtr pPriv;
303
304    if(!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
305			   2 * sizeof(ApmPortPrivRec) +
306			   2 * sizeof(DevUnion))))
307	return NULL;
308
309    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
310    adapt->flags = VIDEO_OVERLAID_IMAGES;
311    adapt->name = "Alliance Pro Motion video engine";
312    adapt->nEncodings = 1;
313    adapt->pEncodings = DummyEncoding;
314    adapt->nFormats = NUM_FORMATS;
315    adapt->pFormats = Formats;
316    adapt->nPorts = 2;
317    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
318    pPriv = (ApmPortPrivPtr)(&adapt->pPortPrivates[2]);
319    pPriv->pApm = pApm;
320    pPriv[1].pApm = pApm;
321    pPriv->reg = 0x82;
322    pPriv[1].reg = 0x92;
323    adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
324    adapt->pPortPrivates[1].ptr = (pointer)(pPriv + 1);
325    adapt->nAttributes = NUM_ATTRIBUTES;
326    adapt->pAttributes = Attributes;
327    adapt->nImages = NUM_IMAGES;
328    adapt->pImages = Images;
329    adapt->PutVideo = NULL;
330    adapt->PutStill = NULL;
331    adapt->GetVideo = NULL;
332    adapt->GetStill = NULL;
333    adapt->StopVideo = A(StopVideo);
334    adapt->SetPortAttribute = A(SetPortAttribute);
335    adapt->GetPortAttribute = ApmGetPortAttribute;
336    adapt->QueryBestSize = ApmQueryBestSize;
337    adapt->PutImage = A(PutImage);
338#ifndef XV_NEW_REPUT
339    adapt->ReputImage = A(ReputImage);
340#endif
341    adapt->QueryImageAttributes = ApmQueryImageAttributes;
342
343    pPriv->brightness = 0;
344    pPriv->contrast = 128;
345    pPriv[1].brightness = 0;
346    pPriv[1].contrast = 128;
347
348    /* gotta uninit this someplace */
349    REGION_NULL(pScreen, &pPriv->clip);
350    REGION_NULL(pScreen, &(pPriv + 1)->clip);
351
352    pApm->adaptor = adapt;
353
354    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
355    xvContrast   = MAKE_ATOM("XV_CONTRAST");
356
357    A(ResetVideo)(pScrn);
358
359    return adapt;
360}
361
362/* ApmClipVideo -
363
364   Takes the dst box in standard X BoxRec form (top and left
365   edges inclusive, bottom and right exclusive).  The new dst
366   box is returned.  The source boundaries are given (x1, y1
367   inclusive, x2, y2 exclusive) and returned are the new source
368   boundaries in 16.16 fixed point.
369
370  extents is the extents of the clip region
371*/
372
373static void
374ApmClipVideo(BoxPtr dst, INT32 *x1, INT32 *x2, INT32 *y1, INT32 *y2,
375	      BoxPtr extents, INT32 width, INT32 height,
376	      CARD32 *scalex, CARD32 *scaley, INT32 mask)
377{
378    INT32 vscale, hscale;
379    int diff;
380
381    if (dst->x2 - dst->x1 < *x2 - *x1)
382	dst->x2 = dst->x1 + *x2 - *x1;
383
384    if (dst->y2 - dst->y1 < *y2 - *y1)
385	dst->y2 = dst->y1 + *y2 - *y1;
386
387    *x1 <<= 12; *x2 <<= 16;
388    *y1 <<= 12; *y2 <<= 16;
389
390    hscale = (*x2 - *x1) / (dst->x2 - dst->x1);
391    vscale = (*y2 - *y1) / (dst->y2 - dst->y1);
392
393    diff = extents->x1 - dst->x1;
394    if(diff > 0) {
395	dst->x1 = extents->x1;
396	*x1 += diff * hscale;
397    }
398    diff = dst->x2 - extents->x2;
399    if(diff > 0) {
400	dst->x2 = extents->x2;
401	*x2 -= diff * hscale;
402    }
403    diff = extents->y1 - dst->y1;
404    if(diff > 0) {
405	dst->y1 = extents->y1;
406	*y1 += diff * vscale;
407    }
408    diff = dst->y2 - extents->y2;
409    if(diff > 0) {
410	dst->y2 = extents->y2;
411	*y2 -= diff * vscale;
412    }
413
414    if (*x2 - *x1 == 0x10000 * (dst->x2 - dst->x1))	/* Shrinking */
415	*scalex = 0;
416    else
417	*scalex = ((*x2 - *x1) / (dst->x2 - dst->x1)) >> 4;
418    if (*y2 - *y1 == 0x10000 * (dst->y2 - dst->y1))	/* Shrinking */
419	*scaley = 0;
420    else
421	*scaley = ((*y2 - *y1) / (dst->y2 - dst->y1)) >> 4;
422}
423
424static void
425A(StopVideo)(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
426{
427    ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
428    APMDECL(pScrn);
429
430    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
431
432    pPriv->on = 0;
433    A(WaitForFifo)(pApm, 1);
434    WRXB(pPriv->reg, 0);
435}
436
437static int
438A(SetPortAttribute)(ScrnInfoPtr pScrn, Atom attribute, INT32 value,
439		      pointer data)
440{
441  ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
442  /*APMDECL(pScrn);*/
443
444  if(attribute == xvBrightness) {
445	if((value < -128) || (value > 127))
446	   return BadValue;
447	pPriv->brightness = value;
448	/* TODO : enable */
449  } else if(attribute == xvContrast) {
450	if((value < 0) || (value > 255))
451	   return BadValue;
452	pPriv->contrast = value;
453	/* TODO : enable */
454  }
455
456  return Success;
457}
458
459static int
460ApmGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value,
461		      pointer data)
462{
463  ApmPortPrivPtr pPriv = (ApmPortPrivPtr)data;
464
465  if(attribute == xvBrightness) {
466	*value = pPriv->brightness;
467  } else
468  if(attribute == xvContrast) {
469	*value = pPriv->contrast;
470  }
471
472  return Success;
473}
474
475static void
476ApmQueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, short vid_h,
477		  short drw_w, short drw_h,
478		  unsigned int *p_w, unsigned int *p_h, pointer data)
479{
480    APMDECL(pScrn);
481    unsigned short	round = ~pApm->CurrentLayout.mask32;
482
483    *p_w = drw_w & round;
484    *p_h = drw_h & round;
485}
486
487static void A(XvMoveCB)(FBAreaPtr area1, FBAreaPtr area2)
488{
489    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)area1->devPrivate.ptr;
490    ApmPtr		pApm = pPriv->pApm;
491
492    pPriv->on = 0;
493    A(WaitForFifo)(pApm, 1);
494    WRXB(pPriv->reg, 0);	/* Stop video for this port */
495    pPriv->area = area2;
496}
497
498static void A(XvRemoveCB)(FBAreaPtr area)
499{
500    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)area->devPrivate.ptr;
501    ApmPtr		pApm = pPriv->pApm;
502
503    pPriv->on = 0;
504    A(WaitForFifo)(pApm, 1);
505    WRXB(pPriv->reg, 0);	/* Stop video for this port */
506    pPriv->area = NULL;
507}
508
509static int
510A(ReputImage)(ScrnInfoPtr pScrn, short drw_x, short drw_y,
511		RegionPtr clipBoxes, pointer pdata, DrawablePtr pDraw)
512{
513    ScreenPtr		pScreen = pScrn->pScreen;
514    APMDECL(pScrn);
515    ApmPortPrivPtr	pPriv = pdata, pPriv0, pPriv1;
516    register int	fx, fy;
517    CARD32	mask;
518    RegionRec	Union;
519    RegionPtr	reg0;
520    int		nrects, CurrY, tile;
521    int		X1, X2, Y1, y2, xmax, ymax;
522    BoxPtr	rects;
523    Bool	didit = 0;
524
525    mask = pApm->CurrentLayout.mask32;
526    fx = pScrn->frameX0 & ~mask;
527    fy = pScrn->frameY0 + 1;
528    REGION_COPY(pScreen, &pPriv->clip, clipBoxes);
529    pPriv->x1 += drw_x - pPriv->drw_x;
530    pPriv->x10 = ((pPriv->x1 + mask) & ~mask) - fx;
531    pPriv->y1 += drw_y - pPriv->drw_y;
532    pPriv->drw_x = drw_x;
533    pPriv->drw_y = drw_y;
534    A(WaitForFifo)(pApm, 2);
535    WRXW(pPriv->reg + 0x06, 0xFFF - ((pPriv->scalex * pPriv->x10) & 0xFFF));
536    WRXW(pPriv->reg + 0x0A, 0xFFF - ((pPriv->scaley * pPriv->y1) & 0xFFF));
537    pPriv0 = (ApmPortPrivPtr)pApm->adaptor->pPortPrivates[0].ptr;
538    pPriv1 = (ApmPortPrivPtr)pApm->adaptor->pPortPrivates[1].ptr;
539    reg0 = &pPriv0->clip;
540    bzero(&Union, sizeof Union);
541    REGION_EMPTY(pScreen, &Union);
542    REGION_NULL(pScreen, &Union);
543    REGION_UNION(pScreen, &Union, reg0, &pPriv1->clip);
544    nrects = REGION_NUM_RECTS(&Union);
545    rects = REGION_RECTS(&Union);
546    tile = 0x200;
547    xmax = pScrn->frameX1 - pScrn->frameX0 + 1;
548    ymax = pScrn->frameY1 - pScrn->frameY0;
549    CurrY = -1;
550    goto BEGIN_LOOP_1;
551    do {
552	rects++;
553BEGIN_LOOP_1:
554	X1 = ((rects->x1 + mask) & ~mask) - fx;
555	if (X1 < 0)
556	    X1 = 0;
557	X2 = (rects->x2 & ~mask) - fx;
558	if (X2 > xmax)
559	    X2 = xmax;
560	y2 = rects->y2 - fy;
561    } while ((X2 <= X1 || y2 < -1) && --nrects > 0);
562    Y1 = rects->y1 - fy;
563
564    while (!(STATUS() & 0x800));
565    while (STATUS() & 0x800);
566    while (nrects-- > 0) {
567	CARD32	reg, data;
568	int	x1, x2, y1;
569
570	x1 = X1;
571	x2 = X2;
572	y1 = Y1;
573	if (y1 < -1) y1 = -1;
574	if (y1 > ymax)
575	    break;
576	didit = 1;
577	if (y1 > CurrY) {
578	    A(WaitForFifo)(pApm, 3);
579	    WRXL(tile + 0x00, 0xFFF0011);
580	    WRXL(tile + 0x04, y1 << 16);
581	    WRXL(tile + 0x08, 0);
582	    tile += 16;
583	}
584	if (RECT_IN_REGION(pScreen, reg0, rects)) {
585	    pPriv = pPriv0;
586	    reg = (x1 << 16) | 1;
587	}
588	else {
589	    pPriv = pPriv1;
590	    reg = (x1 << 16) | 2;
591	}
592	CurrY = y2;
593	if (nrects <= 0)
594	    goto BEGIN_LOOP_2;
595	do {
596	    rects++;
597BEGIN_LOOP_2:
598	    X1 = ((rects->x1 + mask) & ~mask) - fx;
599	    if (X1 < 0)
600		X1 = 0;
601	    X2 = (rects->x2 & ~mask) - fx;
602	    if (X2 > xmax)
603		X2 = xmax;
604	} while (X2 <= X1 && --nrects > 0);
605	Y1 = rects->y1 - fy;
606	y2 = rects->y2 - fy;
607	data = pPriv->data + (((x1 - pPriv->x10)
608				* pPriv->xden) / pPriv->xnum) * pPriv->Bpp +
609	    (((y1 - pPriv->y1 + fy) * pPriv->yden) / pPriv->ynum) * pPriv->Bps;
610	A(WaitForFifo)(pApm, 4);
611	if (!nrects || tile == 0x2B0 || y1 < Y1) {
612	    WRXL(tile   , 0x10 | reg);
613	}
614	else {
615	    WRXL(tile   , reg);
616	}
617	WRXL(tile + 0x04, x2 | (CurrY << 16));
618	WRXL(tile + 0x08, (((x2-x1)*pPriv->xden+pPriv->xnum-1) / pPriv->xnum) |
619				(data << 16));
620	WRXB(tile + 0x0C, data >> 16);
621	tile += 16;
622	if (tile == 0x2C0) {
623	    tile = 0x200;
624	    break;
625	}
626    }
627    REGION_UNINIT(pScreen, &Union);
628
629    if (didit) {
630	A(WaitForFifo)(pApm, 1);
631	WRXW(0x8E, tile - 0x200);
632    }
633
634    if (didit ^ ((pPriv0->val | pPriv1->val) & 1)) {
635	if (didit) {
636	    pPriv0->val |= 1;
637	    pPriv1->val |= 1;
638	}
639	else {
640	    pPriv0->val &= 0xFFFE;
641	    pPriv1->val &= 0xFFFE;
642	}
643	if (pPriv0->on) {
644	    A(WaitForFifo)(pApm, 1);
645	    WRXW(0x82, pPriv0->val);
646	}
647	if (pPriv1->on) {
648	    A(WaitForFifo)(pApm, 1);
649	    WRXW(0x92, pPriv1->val);
650	}
651    }
652
653    return Success;
654}
655
656static int
657A(PutImage)(ScrnInfoPtr pScrn, short src_x, short src_y,
658	      short drw_x, short drw_y, short src_w, short src_h,
659	      short drw_w, short drw_h, int id, unsigned char* buf,
660	      short width, short height, Bool sync, RegionPtr clipBoxes,
661	      pointer data, DrawablePtr pDraw)
662{
663    ApmPortPrivPtr	pPriv = (ApmPortPrivPtr)data;
664    ScreenPtr	pScreen = pScrn->pScreen;
665    APMDECL(pScrn);
666    INT32	x1, x2, y1, y2;
667    unsigned char	*dst_start;
668    int		pitch, Bpp, new_h, offset = 0, offset2 = 0, offset3 = 0;
669    CARD32	mask;
670    FBAreaPtr	area;
671    int		srcPitch, dstPitch, srcPitch2 = 0;
672    int		top, left, npixels, nlines;
673    BoxRec	dstBox;
674    CARD32	scalex, scaley, scale;
675    CARD32	tmp;
676    Bool	offscreen;
677
678    offscreen = (buf < (unsigned char *)pApm->FbBase ||
679		    buf > (unsigned char *)pApm->FbBase + 0x400000);
680
681    if(drw_w > 16384) drw_w = 16384;
682
683    /* Clip */
684    x1 = src_x;
685    x2 = src_x + src_w;
686    y1 = src_y;
687    y2 = src_y + src_h;
688
689    dstBox.x1 = drw_x;
690    dstBox.x2 = drw_x + drw_w;
691    dstBox.y1 = drw_y;
692    dstBox.y2 = drw_y + drw_h;
693
694    mask = pApm->CurrentLayout.mask32;
695
696    ApmClipVideo(&dstBox, &x1, &x2, &y1, &y2,
697		REGION_EXTENTS(pScreen, clipBoxes), width, height,
698		&scalex, &scaley, mask);
699
700    pPriv->drw_x = drw_x;
701    pPriv->drw_y = drw_y;
702    pPriv->xnum = drw_w;
703    if (scalex)
704	pPriv->xden = src_w;
705    else
706	pPriv->xden = drw_w;	/* If image is larger than window */
707    pPriv->ynum = drw_h;
708    if (scaley)
709	pPriv->yden = src_h;
710    else
711	pPriv->yden = drw_h;
712    if((x1 - x2 >= 0xFFFF) || (y1 - y2 >= 0xFFFF))
713     return Success;
714
715    Bpp = pScrn->bitsPerPixel >> 3;
716    pitch = Bpp * pScrn->displayWidth;
717
718    switch(id) {
719    case 0x32315659:
720	dstPitch = ((width << 1) + 3) & ~3;
721	srcPitch = (width + 3) & ~3;
722	offset2 = srcPitch * height;
723	srcPitch2 = ((width >> 1) + 3) & ~3;
724	offset = srcPitch2 * (height >> 1);
725	offset3 = offset + offset2;
726	new_h = (2 * offset2 + pitch - 1) / pitch;
727	break;
728    case 0x59595959:
729	srcPitch = width;
730	dstPitch = (srcPitch + 3) & ~3;
731	offset = dstPitch * height;
732	new_h = (offset + pitch - 1) / pitch;
733	break;
734    case 0x32335652:
735	srcPitch = (width << 2);
736	dstPitch = (srcPitch + 3) & ~3;
737	offset = dstPitch * height;
738	new_h = (offset + pitch - 1) / pitch;
739	break;
740    default:
741	if (pApm->PutImageStride)
742	    srcPitch = pApm->PutImageStride;
743	else
744	    srcPitch = (width << 1);
745	dstPitch = (srcPitch + 3) & ~3;
746	offset = dstPitch * height;
747	new_h = (offset + pitch - 1) / pitch;
748	break;
749    }
750
751    area = pPriv->area;
752
753    /* Allocate offscreen memory */
754    if (offscreen && (!area || ((area->box.y2 - area->box.y1) < new_h))) {
755	Bool nukeMem = FALSE;
756	int max_w, max_h;
757
758	xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
759			  FAVOR_WIDTH_THEN_AREA, PRIORITY_LOW);
760	if (max_w == pScrn->displayWidth && max_h >= new_h) {
761	    area = xf86AllocateOffscreenArea(pScreen,
762					pScrn->displayWidth, new_h,
763					4, A(XvMoveCB), A(XvRemoveCB), pPriv);
764	    if (area) {
765		if (pPriv->area)
766		    xf86FreeOffscreenArea(pPriv->area);
767	    }
768	    else
769		area = pPriv->area;	/* Should not happen */
770	}
771	if(!area) {
772	    if(!(area = xf86AllocateOffscreenArea(pScreen,
773					pScrn->displayWidth, new_h, 4,
774					A(XvMoveCB), A(XvRemoveCB), pPriv)))
775	    {
776	       nukeMem = TRUE;
777	    }
778	} else {
779	    if(!xf86ResizeOffscreenArea(area, pScrn->displayWidth, new_h)) {
780	       xf86FreeOffscreenArea(area);
781	       pPriv->area = area = NULL;
782	       nukeMem = TRUE;
783	    }
784	}
785	if(nukeMem) {
786	    xf86QueryLargestOffscreenArea(pScreen, &max_w, &max_h, 0,
787			    FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME);
788
789	    if((max_w < pScrn->displayWidth) || (max_h < new_h))
790		return BadAlloc;
791
792	    xf86PurgeUnlockedOffscreenAreas(pScreen);
793
794	    area = xf86AllocateOffscreenArea(pScreen,
795					pScrn->displayWidth, new_h, 4,
796					A(XvMoveCB), A(XvRemoveCB), pPriv);
797	}
798
799	pPriv->area = area;
800    }
801
802    /* copy data */
803    pPriv->x1 = dstBox.x1 /*drw_x*/;
804    pPriv->y1 = dstBox.y1 /*drw_y*/;
805    top = y1 >> 16;
806    left = (x1 >> 16) & ~1;
807    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
808
809    switch(id) {
810    case 0x59595959:
811	pPriv->Bpp = 1;
812	break;
813    default:
814	pPriv->Bpp = 2;
815	left <<= 1;
816	break;
817    case 0x32335652:
818	pPriv->Bpp = 4;
819	left <<= 2;
820	break;
821    }
822    pPriv->Bps = pPriv->Bpp * pPriv->xden;
823    if (offscreen) {
824	offset = (area->box.y1 * pitch) + (top * dstPitch);
825	dst_start = ((unsigned char *)pApm->FbBase) +
826						(pPriv->data = offset + left);
827	switch(id) {
828	case 0x32315659:
829	    top &= ~1;
830	    tmp = ((top >> 1) * srcPitch2) + (left >> 2);
831	    offset2 += tmp;
832	    offset3 += tmp;
833	    nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
834	    xf86XVCopyYUV12ToPacked(buf + (top * srcPitch) + (left >> 1),
835				    buf + offset2, buf + offset3, dst_start,
836				    srcPitch, srcPitch2, dstPitch,
837				    nlines, npixels);
838	    break;
839	default:
840	    if (id == 0x32335652)
841		npixels <<= 1;
842	    else if (id == 0x59595959)
843		npixels >>= 1;
844	    buf += (top * srcPitch) + left;
845	    nlines = ((y2 + 0xffff) >> 16) - top;
846	    if (offscreen)
847		xf86XVCopyPacked(buf, dst_start, srcPitch, dstPitch,
848				 nlines, npixels);
849	    break;
850	}
851    }
852    else
853	pPriv->data = buf - (unsigned char *)pApm->FbBase;
854    pPriv->on = 1;
855    A(WaitForFifo)(pApm, 3);
856    WRXW(pPriv->reg + 0x02, dstPitch >> 2);
857    WRXW(pPriv->reg + 0x04, scalex);
858    WRXW(pPriv->reg + 0x08, scaley);
859    pPriv->scalex = scalex;
860    pPriv->scaley = scaley;
861    if (scalex && scaley)
862	scale = 0x0E00;
863    else if (scalex)
864	scale = 0x0600;
865    else if (scaley)
866	scale = 0x0A00;
867    else
868	scale = 0;
869    switch(id) {
870    case 0x59595959:
871	pPriv->val = 0x017B | scale;
872	break;
873    case 0x32335652:
874	pPriv->val = 0x002F | (scale & 0xF7FF);/*Smoothing filter doesn't work*/
875	break;
876    case 0x36315652:
877	pPriv->val = 0x002B | (scale & 0xF7FF);
878	break;
879    case 0x35315652:
880	pPriv->val = 0x0029 | (scale & 0xF7FF);
881	break;
882    case 0x59555956:
883	pPriv->val = 0x013B | scale;
884	break;
885    case 0x55595659:
886	pPriv->val = 0x014B | scale;
887	break;
888    case 0x32315659:
889    case 0x59565955:
890    default:
891	pPriv->val = 0x016B | scale;
892	break;
893    }
894
895    (void) A(ReputImage)(pScrn, drw_x, drw_y, clipBoxes, data, pDraw);
896
897    A(WaitForFifo)(pApm, 1);
898    WRXW(pPriv->reg, pPriv->val);
899
900    return Success;
901}
902
903static int
904ApmQueryImageAttributes(ScrnInfoPtr pScrn, int id,
905			  unsigned short *w, unsigned short *h,
906			  int *pitches, int *offsets)
907{
908    int size, tmp;
909
910    if(*w > 1024) *w = 1024;
911    if(*h > 1024) *h = 1024;
912
913    *w = (*w + 1) & ~1;
914    if(offsets) offsets[0] = 0;
915
916    switch(id) {
917    case 0x32315659:
918	*h = (*h + 1) & ~1;
919	size = (*w + 3) & ~3;
920	if(pitches) pitches[0] = size;
921	size *= *h;
922	if(offsets) offsets[1] = size;
923	tmp = ((*w >> 1) + 3) & ~3;
924	if(pitches) pitches[1] = pitches[2] = tmp;
925	tmp *= (*h >> 1);
926	size += tmp;
927	if(offsets) offsets[2] = size;
928	size += tmp;
929	break;
930    case 0x59565955:
931    case 0x55595659:
932    case 0x59555956:
933    case 0x32595559:
934	size = *w << 1;
935	goto common;
936    case 0x59595959:
937    default:
938	size = *w;
939common:
940	if (pitches)
941	    pitches[0] = size;
942	size *= *h;
943	break;
944    }
945
946    return size;
947}
948
949#endif
950