radeon_textured_video.c revision 2f39173d
1/*
2 * Copyright 2008 Alex Deucher
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 *
24 * Based on radeon_exa_render.c and kdrive ati_video.c by Eric Anholt, et al.
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <stdlib.h>
33#include <string.h>
34#include <stdio.h>
35#include <math.h>
36
37#include "radeon.h"
38#include "radeon_reg.h"
39#include "r600_reg.h"
40#include "radeon_macros.h"
41#include "radeon_probe.h"
42#include "radeon_video.h"
43
44#include <X11/extensions/Xv.h>
45#include "fourcc.h"
46
47extern void
48R600DisplayTexturedVideo(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv);
49
50extern Bool
51R600CopyToVRAM(ScrnInfoPtr pScrn,
52	       char *src, int src_pitch,
53	       uint32_t dst_pitch, uint32_t dst_mc_addr, uint32_t dst_width, uint32_t dst_height, int bpp,
54	       int x, int y, int w, int h);
55
56#define IMAGE_MAX_WIDTH		2048
57#define IMAGE_MAX_HEIGHT	2048
58
59#define IMAGE_MAX_WIDTH_R500	4096
60#define IMAGE_MAX_HEIGHT_R500	4096
61
62#define IMAGE_MAX_WIDTH_R600	8192
63#define IMAGE_MAX_HEIGHT_R600	8192
64
65static Bool
66RADEONTilingEnabled(ScrnInfoPtr pScrn, PixmapPtr pPix)
67{
68    RADEONInfoPtr info = RADEONPTR(pScrn);
69
70#ifdef USE_EXA
71    if (info->useEXA) {
72	if (info->tilingEnabled && exaGetPixmapOffset(pPix) == 0)
73	    return TRUE;
74	else
75	    return FALSE;
76    } else
77#endif
78	{
79	    if (info->tilingEnabled && ((pPix->devPrivate.ptr - info->FB) == 0))
80		return TRUE;
81	    else
82		return FALSE;
83	}
84}
85
86static __inline__ uint32_t F_TO_DW(float val)
87{
88    union {
89	float f;
90	uint32_t l;
91    } tmp;
92    tmp.f = val;
93    return tmp.l;
94}
95
96/* Borrowed from Mesa */
97static __inline__ uint32_t F_TO_24(float val)
98{
99	float mantissa;
100	int exponent;
101	uint32_t float24 = 0;
102
103	if (val == 0.0)
104		return 0;
105
106	mantissa = frexpf(val, &exponent);
107
108	/* Handle -ve */
109	if (mantissa < 0) {
110		float24 |= (1 << 23);
111		mantissa = mantissa * -1.0;
112	}
113	/* Handle exponent, bias of 63 */
114	exponent += 62;
115	float24 |= (exponent << 16);
116	/* Kill 7 LSB of mantissa */
117	float24 |= (F_TO_DW(mantissa) & 0x7FFFFF) >> 7;
118
119	return float24;
120}
121
122static __inline__ uint32_t float4touint(float fr, float fg, float fb, float fa)
123{
124    unsigned ur = fr * 255.0 + 0.5;
125    unsigned ug = fg * 255.0 + 0.5;
126    unsigned ub = fb * 255.0 + 0.5;
127    unsigned ua = fa * 255.0 + 0.5;
128    return (ua << 24) | (ur << 16) | (ug << 8) | ub;
129}
130
131/* Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces
132   note the difference to the parameters used in overlay are due
133   to 10bit vs. float calcs */
134static REF_TRANSFORM trans[2] =
135{
136    {1.1643, 0.0, 1.5960, -0.3918, -0.8129, 2.0172, 0.0}, /* BT.601 */
137    {1.1643, 0.0, 1.7927, -0.2132, -0.5329, 2.1124, 0.0}  /* BT.709 */
138};
139
140#define ACCEL_MMIO
141#define ACCEL_PREAMBLE()	unsigned char *RADEONMMIO = info->MMIO
142#define BEGIN_ACCEL(n)		RADEONWaitForFifo(pScrn, (n))
143#define OUT_ACCEL_REG(reg, val)	OUTREG(reg, val)
144#define OUT_ACCEL_REG_F(reg, val) OUTREG(reg, F_TO_DW(val))
145#define OUT_RELOC(x, read, write) do {} while(0)
146#define FINISH_ACCEL()
147
148#include "radeon_textured_videofuncs.c"
149
150#undef ACCEL_MMIO
151#undef ACCEL_PREAMBLE
152#undef BEGIN_ACCEL
153#undef OUT_ACCEL_REG
154#undef OUT_ACCEL_REG_F
155#undef OUT_RELOC
156#undef FINISH_ACCEL
157
158#ifdef XF86DRI
159
160#define ACCEL_CP
161#define ACCEL_PREAMBLE()						\
162    RING_LOCALS;							\
163    RADEONCP_REFRESH(pScrn, info)
164#define BEGIN_ACCEL(n)		BEGIN_RING(2*(n))
165#define OUT_ACCEL_REG(reg, val)	OUT_RING_REG(reg, val)
166#define OUT_ACCEL_REG_F(reg, val)	OUT_ACCEL_REG(reg, F_TO_DW(val))
167#define FINISH_ACCEL()		ADVANCE_RING()
168#define OUT_RING_F(x) OUT_RING(F_TO_DW(x))
169#define OUT_RELOC(x, read, write) OUT_RING_RELOC(x, read, write)
170
171#include "radeon_textured_videofuncs.c"
172
173#undef ACCEL_CP
174#undef ACCEL_PREAMBLE
175#undef BEGIN_ACCEL
176#undef OUT_ACCEL_REG
177#undef OUT_ACCEL_REG_F
178#undef FINISH_ACCEL
179#undef OUT_RING_F
180
181#endif /* XF86DRI */
182
183static void
184R600CopyData(
185    ScrnInfoPtr pScrn,
186    unsigned char *src,
187    unsigned char *dst,
188    unsigned int srcPitch,
189    unsigned int dstPitch,
190    unsigned int h,
191    unsigned int w,
192    unsigned int cpp
193){
194    RADEONInfoPtr info = RADEONPTR( pScrn );
195
196    if (cpp == 2) {
197	w *= 2;
198	cpp = 1;
199    }
200
201    if (info->DMAForXv) {
202	uint32_t dst_mc_addr = dst - (unsigned char *)info->FB + info->fbLocation;
203
204	R600CopyToVRAM(pScrn,
205		       (char *)src, srcPitch,
206		       dstPitch, dst_mc_addr, w, h, cpp * 8,
207		       0, 0, w, h);
208    } else {
209	if (srcPitch == dstPitch)
210	    memcpy(dst, src, srcPitch * h);
211	else {
212	    while (h--) {
213		memcpy(dst, src, srcPitch);
214		src += srcPitch;
215		dst += dstPitch;
216	    }
217	}
218    }
219}
220
221static int
222RADEONPutImageTextured(ScrnInfoPtr pScrn,
223		       short src_x, short src_y,
224		       short drw_x, short drw_y,
225		       short src_w, short src_h,
226		       short drw_w, short drw_h,
227		       int id,
228		       unsigned char *buf,
229		       short width,
230		       short height,
231		       Bool sync,
232		       RegionPtr clipBoxes,
233		       pointer data,
234		       DrawablePtr pDraw)
235{
236    ScreenPtr pScreen = pScrn->pScreen;
237    RADEONInfoPtr info = RADEONPTR(pScrn);
238    RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
239    INT32 x1, x2, y1, y2;
240    int srcPitch, srcPitch2, dstPitch, dstPitch2 = 0;
241    int s2offset, s3offset, tmp;
242    int d2line, d3line;
243    int top, nlines, size;
244    BoxRec dstBox;
245    int dst_width = width, dst_height = height;
246    int hw_align;
247
248    /* make the compiler happy */
249    s2offset = s3offset = srcPitch2 = 0;
250
251    /* Clip */
252    x1 = src_x;
253    x2 = src_x + src_w;
254    y1 = src_y;
255    y2 = src_y + src_h;
256
257    dstBox.x1 = drw_x;
258    dstBox.x2 = drw_x + drw_w;
259    dstBox.y1 = drw_y;
260    dstBox.y2 = drw_y + drw_h;
261
262    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
263	return Success;
264
265    if ((x1 >= x2) || (y1 >= y2))
266	return Success;
267
268    /* Bicubic filter setup */
269    pPriv->bicubic_enabled = (pPriv->bicubic_state != BICUBIC_OFF);
270    if (!(IS_R300_3D || IS_R500_3D)) {
271	pPriv->bicubic_enabled = FALSE;
272	pPriv->bicubic_state = BICUBIC_OFF;
273    }
274    if (pPriv->bicubic_enabled && (pPriv->bicubic_state == BICUBIC_AUTO)) {
275	/*
276	 * Applying the bicubic filter with a scale of less than 200%
277	 * results in a blurred picture, so disable the filter.
278	 */
279	if ((src_w > drw_w / 2) || (src_h > drw_h / 2))
280	    pPriv->bicubic_enabled = FALSE;
281    }
282
283    if (info->ChipFamily >= CHIP_FAMILY_R600)
284	hw_align = 256;
285    else
286	hw_align = 64;
287
288    switch(id) {
289    case FOURCC_YV12:
290    case FOURCC_I420:
291	srcPitch = RADEON_ALIGN(width, 4);
292	srcPitch2 = RADEON_ALIGN(width >> 1, 4);
293        if (pPriv->bicubic_state != BICUBIC_OFF) {
294	    dstPitch = RADEON_ALIGN(dst_width << 1, hw_align);
295	    dstPitch2 = 0;
296	} else {
297	    dstPitch = RADEON_ALIGN(dst_width, hw_align);
298	    dstPitch2 = RADEON_ALIGN(dstPitch >> 1, hw_align);
299	}
300	break;
301    case FOURCC_UYVY:
302    case FOURCC_YUY2:
303    default:
304	dstPitch = RADEON_ALIGN(dst_width << 1, hw_align);
305	srcPitch = (width << 1);
306	srcPitch2 = 0;
307	break;
308    }
309
310    size = dstPitch * dst_height + 2 * dstPitch2 * ((dst_height + 1) >> 1);
311    size = RADEON_ALIGN(size, hw_align);
312
313    if (pPriv->video_memory != NULL && size != pPriv->size) {
314	radeon_legacy_free_memory(pScrn, pPriv->video_memory);
315	pPriv->video_memory = NULL;
316    }
317
318    if (pPriv->video_memory == NULL) {
319	pPriv->video_offset = radeon_legacy_allocate_memory(pScrn,
320							    &pPriv->video_memory,
321							    size, hw_align,
322							    RADEON_GEM_DOMAIN_GTT);
323	if (pPriv->video_offset == 0)
324	    return BadAlloc;
325
326	if (info->cs) {
327	    pPriv->src_bo[0] = pPriv->video_memory;
328	    radeon_legacy_allocate_memory(pScrn, (void*)&pPriv->src_bo[1], size,
329					  hw_align,
330					  RADEON_GEM_DOMAIN_GTT);
331	}
332    }
333
334    /* Bicubic filter loading */
335    if (pPriv->bicubic_enabled) {
336	if (info->bicubic_offset == 0)
337	    pPriv->bicubic_enabled = FALSE;
338	pPriv->bicubic_src_offset = info->bicubic_offset;
339    }
340
341    if (pDraw->type == DRAWABLE_WINDOW)
342	pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
343    else
344	pPriv->pPixmap = (PixmapPtr)pDraw;
345
346#ifdef USE_EXA
347    if (info->useEXA) {
348	/* Force the pixmap into framebuffer so we can draw to it. */
349	info->exa_force_create = TRUE;
350	exaMoveInPixmap(pPriv->pPixmap);
351	info->exa_force_create = FALSE;
352    }
353#endif
354
355    if (!info->useEXA &&
356	(((char *)pPriv->pPixmap->devPrivate.ptr < (char *)info->FB) ||
357	 ((char *)pPriv->pPixmap->devPrivate.ptr >= (char *)info->FB +
358	  info->FbMapSize))) {
359	/* If the pixmap wasn't in framebuffer, then we have no way in XAA to
360	 * force it there. So, we simply refuse to draw and fail.
361	 */
362	return BadAlloc;
363    }
364
365    /* copy data */
366    top = (y1 >> 16) & ~1;
367    nlines = RADEON_ALIGN((y2 + 0xffff) >> 16, 2) - top;
368
369    pPriv->src_offset = pPriv->video_offset;
370    if (info->cs) {
371	struct radeon_bo *src_bo;
372	int ret;
373
374	pPriv->currentBuffer ^= 1;
375
376	src_bo = pPriv->src_bo[pPriv->currentBuffer];
377
378	ret = radeon_bo_map(src_bo, 1);
379	if (ret)
380	    return BadAlloc;
381
382	pPriv->src_addr = src_bo->ptr;
383    } else {
384	pPriv->src_addr = (uint8_t *)(info->FB + pPriv->video_offset);
385	RADEONWaitForIdleMMIO(pScrn);
386    }
387    pPriv->src_pitch = dstPitch;
388
389    pPriv->planeu_offset = dstPitch * dst_height;
390    pPriv->planeu_offset = RADEON_ALIGN(pPriv->planeu_offset, hw_align);
391    pPriv->planev_offset = pPriv->planeu_offset + dstPitch2 * ((dst_height + 1) >> 1);
392    pPriv->planev_offset = RADEON_ALIGN(pPriv->planev_offset, hw_align);
393
394    pPriv->size = size;
395    pPriv->pDraw = pDraw;
396
397    switch(id) {
398    case FOURCC_YV12:
399    case FOURCC_I420:
400	s2offset = srcPitch * (RADEON_ALIGN(height, 2));
401	s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
402	s2offset += ((top >> 1) * srcPitch2);
403	s3offset += ((top >> 1) * srcPitch2);
404	if (pPriv->bicubic_state != BICUBIC_OFF) {
405	    if (id == FOURCC_I420) {
406		tmp = s2offset;
407		s2offset = s3offset;
408		s3offset = tmp;
409	    }
410	    RADEONCopyMungedData(pScrn, buf + (top * srcPitch),
411				 buf + s2offset, buf + s3offset, pPriv->src_addr + (top * dstPitch),
412				 srcPitch, srcPitch2, dstPitch, nlines, width);
413	} else {
414	    if (id == FOURCC_YV12) {
415		tmp = s2offset;
416		s2offset = s3offset;
417		s3offset = tmp;
418	    }
419	    d2line = pPriv->planeu_offset + ((top >> 1) * dstPitch2);
420	    d3line = pPriv->planev_offset + ((top >> 1) * dstPitch2);
421
422	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
423		R600CopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch),
424			     srcPitch, dstPitch, nlines, width, 1);
425		R600CopyData(pScrn, buf + s2offset,  pPriv->src_addr + d2line,
426			     srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
427		R600CopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line,
428			     srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
429	    } else {
430		RADEONCopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch),
431			       srcPitch, dstPitch, nlines, width, 1);
432		RADEONCopyData(pScrn, buf + s2offset,  pPriv->src_addr + d2line,
433			       srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
434		RADEONCopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line,
435			       srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
436	    }
437	}
438	break;
439    case FOURCC_UYVY:
440    case FOURCC_YUY2:
441    default:
442	if (info->ChipFamily >= CHIP_FAMILY_R600)
443	    R600CopyData(pScrn, buf + (top * srcPitch),
444			 pPriv->src_addr + (top * dstPitch),
445			 srcPitch, dstPitch, nlines, width, 2);
446	else
447	    RADEONCopyData(pScrn, buf + (top * srcPitch),
448			   pPriv->src_addr + (top * dstPitch),
449			   srcPitch, dstPitch, nlines, width, 2);
450	break;
451    }
452
453    /* update cliplist */
454    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
455	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
456    }
457
458    pPriv->id = id;
459    pPriv->src_w = src_w;
460    pPriv->src_h = src_h;
461    pPriv->src_x = src_x;
462    pPriv->src_y = src_y;
463    pPriv->drw_x = drw_x;
464    pPriv->drw_y = drw_y;
465    pPriv->dst_w = drw_w;
466    pPriv->dst_h = drw_h;
467    pPriv->w = width;
468    pPriv->h = height;
469
470#if defined(XF86DRM_MODE)
471    if (info->cs)
472	radeon_bo_unmap(pPriv->src_bo[pPriv->currentBuffer]);
473#endif
474#ifdef XF86DRI
475    if (info->directRenderingEnabled) {
476	if (IS_R600_3D)
477	    R600DisplayTexturedVideo(pScrn, pPriv);
478	else if (IS_R500_3D)
479	    R500DisplayTexturedVideoCP(pScrn, pPriv);
480	else if (IS_R300_3D)
481	    R300DisplayTexturedVideoCP(pScrn, pPriv);
482	else if (IS_R200_3D)
483	    R200DisplayTexturedVideoCP(pScrn, pPriv);
484	else
485	    RADEONDisplayTexturedVideoCP(pScrn, pPriv);
486    } else
487#endif
488    {
489	if (IS_R500_3D)
490	    R500DisplayTexturedVideoMMIO(pScrn, pPriv);
491	else if (IS_R300_3D)
492	    R300DisplayTexturedVideoMMIO(pScrn, pPriv);
493	else if (IS_R200_3D)
494	    R200DisplayTexturedVideoMMIO(pScrn, pPriv);
495	else
496	    RADEONDisplayTexturedVideoMMIO(pScrn, pPriv);
497    }
498
499    return Success;
500}
501
502/* client libraries expect an encoding */
503static XF86VideoEncodingRec DummyEncoding[1] =
504{
505    {
506	0,
507	"XV_IMAGE",
508	IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
509	{1, 1}
510    }
511};
512
513static XF86VideoEncodingRec DummyEncodingR500[1] =
514{
515    {
516	0,
517	"XV_IMAGE",
518	IMAGE_MAX_WIDTH_R500, IMAGE_MAX_HEIGHT_R500,
519	{1, 1}
520    }
521};
522
523static XF86VideoEncodingRec DummyEncodingR600[1] =
524{
525    {
526	0,
527	"XV_IMAGE",
528	IMAGE_MAX_WIDTH_R600, IMAGE_MAX_HEIGHT_R600,
529	{1, 1}
530    }
531};
532
533#define NUM_FORMATS 3
534
535static XF86VideoFormatRec Formats[NUM_FORMATS] =
536{
537    {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
538};
539
540#define NUM_ATTRIBUTES 2
541
542static XF86AttributeRec Attributes[NUM_ATTRIBUTES+1] =
543{
544    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
545    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
546    {0, 0, 0, NULL}
547};
548
549#define NUM_ATTRIBUTES_R200 7
550
551static XF86AttributeRec Attributes_r200[NUM_ATTRIBUTES_R200+1] =
552{
553    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
554    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
555    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
556    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
557    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
558    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
559    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
560    {0, 0, 0, NULL}
561};
562
563#define NUM_ATTRIBUTES_R300 9
564
565static XF86AttributeRec Attributes_r300[NUM_ATTRIBUTES_R300+1] =
566{
567    {XvSettable | XvGettable, 0, 2, "XV_BICUBIC"},
568    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
569    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
570    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
571    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
572    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
573    {XvSettable | XvGettable, 100, 10000, "XV_GAMMA"},
574    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
575    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
576    {0, 0, 0, NULL}
577};
578
579#define NUM_ATTRIBUTES_R500 8
580
581static XF86AttributeRec Attributes_r500[NUM_ATTRIBUTES_R500+1] =
582{
583    {XvSettable | XvGettable, 0, 2, "XV_BICUBIC"},
584    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
585    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
586    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
587    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
588    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
589    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
590    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
591    {0, 0, 0, NULL}
592};
593
594#define NUM_ATTRIBUTES_R600 7
595
596static XF86AttributeRec Attributes_r600[NUM_ATTRIBUTES_R600+1] =
597{
598    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
599    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
600    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
601    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
602    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
603    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
604    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
605    {0, 0, 0, NULL}
606};
607
608static Atom xvBicubic;
609static Atom xvVSync;
610static Atom xvBrightness, xvContrast, xvSaturation, xvHue;
611static Atom xvGamma, xvColorspace;
612static Atom xvCRTC;
613
614#define NUM_IMAGES 4
615
616static XF86ImageRec Images[NUM_IMAGES] =
617{
618    XVIMAGE_YUY2,
619    XVIMAGE_YV12,
620    XVIMAGE_I420,
621    XVIMAGE_UYVY
622};
623
624int
625RADEONGetTexPortAttribute(ScrnInfoPtr  pScrn,
626		       Atom	    attribute,
627		       INT32	    *value,
628		       pointer	    data)
629{
630    RADEONInfoPtr	info = RADEONPTR(pScrn);
631    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;
632
633    if (info->accelOn) RADEON_SYNC(info, pScrn);
634
635    if (attribute == xvBicubic)
636	*value = pPriv->bicubic_state;
637    else if (attribute == xvVSync)
638	*value = pPriv->vsync;
639    else if (attribute == xvBrightness)
640	*value = pPriv->brightness;
641    else if (attribute == xvContrast)
642	*value = pPriv->contrast;
643    else if (attribute == xvSaturation)
644	*value = pPriv->saturation;
645    else if (attribute == xvHue)
646	*value = pPriv->hue;
647    else if (attribute == xvGamma)
648	*value = pPriv->gamma;
649    else if(attribute == xvColorspace)
650	*value = pPriv->transform_index;
651    else if(attribute == xvCRTC) {
652	int		c;
653	xf86CrtcConfigPtr	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
654	for (c = 0; c < xf86_config->num_crtc; c++)
655	    if (xf86_config->crtc[c] == pPriv->desired_crtc)
656		break;
657	if (c == xf86_config->num_crtc)
658	    c = -1;
659	*value = c;
660    } else
661	return BadMatch;
662
663    return Success;
664}
665
666int
667RADEONSetTexPortAttribute(ScrnInfoPtr  pScrn,
668		       Atom	    attribute,
669		       INT32	    value,
670		       pointer	    data)
671{
672    RADEONInfoPtr	info = RADEONPTR(pScrn);
673    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;
674
675    RADEON_SYNC(info, pScrn);
676
677    if (attribute == xvBicubic)
678	pPriv->bicubic_state = ClipValue (value, 0, 2);
679    else if (attribute == xvVSync)
680	pPriv->vsync = ClipValue (value, 0, 1);
681    else if (attribute == xvBrightness)
682	pPriv->brightness = ClipValue (value, -1000, 1000);
683    else if (attribute == xvContrast)
684	pPriv->contrast = ClipValue (value, -1000, 1000);
685    else if (attribute == xvSaturation)
686	pPriv->saturation = ClipValue (value, -1000, 1000);
687    else if (attribute == xvHue)
688	pPriv->hue = ClipValue (value, -1000, 1000);
689    else if (attribute == xvGamma)
690	pPriv->gamma = ClipValue (value, 100, 10000);
691    else if(attribute == xvColorspace)
692	pPriv->transform_index = ClipValue (value, 0, 1);
693    else if(attribute == xvCRTC) {
694	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
695	if ((value < -1) || (value > xf86_config->num_crtc))
696	    return BadValue;
697	if (value < 0)
698	    pPriv->desired_crtc = NULL;
699	else
700	    pPriv->desired_crtc = xf86_config->crtc[value];
701    } else
702	return BadMatch;
703
704    return Success;
705}
706
707Bool radeon_load_bicubic_texture(ScrnInfoPtr pScrn)
708{
709    RADEONInfoPtr    info = RADEONPTR(pScrn);
710
711    /* Bicubic filter loading */
712    info->bicubic_offset = radeon_legacy_allocate_memory(pScrn,
713							 &info->bicubic_memory,
714							 sizeof(bicubic_tex_512), 64,
715							 RADEON_GEM_DOMAIN_VRAM);
716    if (info->bicubic_offset == 0)
717	return FALSE;
718
719    if (info->cs)
720	info->bicubic_bo = info->bicubic_memory;
721
722    /* Upload bicubic filter tex */
723    if (info->ChipFamily < CHIP_FAMILY_R600) {
724	uint8_t *bicubic_addr;
725	int ret;
726	if (info->cs) {
727	    ret = radeon_bo_map(info->bicubic_bo, 1);
728	    if (ret)
729		return FALSE;
730
731	    bicubic_addr = info->bicubic_bo->ptr;
732	} else
733	    bicubic_addr = (uint8_t *)(info->FB + info->bicubic_offset);
734
735	RADEONCopySwap(bicubic_addr, (uint8_t *)bicubic_tex_512, 1024,
736#if X_BYTE_ORDER == X_BIG_ENDIAN
737		       RADEON_HOST_DATA_SWAP_16BIT
738#else
739		       RADEON_HOST_DATA_SWAP_NONE
740#endif
741);
742	if (info->cs)
743	    radeon_bo_unmap(info->bicubic_bo);
744    }
745    return TRUE;
746}
747
748#if 0
749/* XXX */
750static void radeon_unload_bicubic_texture(ScrnInfoPtr pScrn)
751{
752    RADEONInfoPtr    info = RADEONPTR(pScrn);
753
754    if (info->bicubic_memory != NULL) {
755	radeon_legacy_free_memory(pScrn, info->bicubic_memory);
756	info->bicubic_memory = NULL;
757    }
758
759}
760#endif
761
762XF86VideoAdaptorPtr
763RADEONSetupImageTexturedVideo(ScreenPtr pScreen)
764{
765    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
766    RADEONInfoPtr    info = RADEONPTR(pScrn);
767    RADEONPortPrivPtr pPortPriv;
768    XF86VideoAdaptorPtr adapt;
769    int i;
770    int num_texture_ports = 16;
771
772    adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports *
773		   (sizeof(RADEONPortPrivRec) + sizeof(DevUnion)));
774    if (adapt == NULL)
775	return NULL;
776
777    xvBicubic         = MAKE_ATOM("XV_BICUBIC");
778    xvVSync           = MAKE_ATOM("XV_VSYNC");
779    xvBrightness      = MAKE_ATOM("XV_BRIGHTNESS");
780    xvContrast        = MAKE_ATOM("XV_CONTRAST");
781    xvSaturation      = MAKE_ATOM("XV_SATURATION");
782    xvHue             = MAKE_ATOM("XV_HUE");
783    xvGamma           = MAKE_ATOM("XV_GAMMA");
784    xvColorspace      = MAKE_ATOM("XV_COLORSPACE");
785    xvCRTC            = MAKE_ATOM("XV_CRTC");
786
787    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
788    adapt->flags = 0;
789    adapt->name = "Radeon Textured Video";
790    adapt->nEncodings = 1;
791    if (IS_R600_3D)
792	adapt->pEncodings = DummyEncodingR600;
793    else if (IS_R500_3D)
794	adapt->pEncodings = DummyEncodingR500;
795    else
796	adapt->pEncodings = DummyEncoding;
797    adapt->nFormats = NUM_FORMATS;
798    adapt->pFormats = Formats;
799    adapt->nPorts = num_texture_ports;
800    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
801
802    pPortPriv =
803	(RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]);
804
805    if (IS_R600_3D) {
806	adapt->pAttributes = Attributes_r600;
807	adapt->nAttributes = NUM_ATTRIBUTES_R600;
808    }
809    else if (IS_R500_3D) {
810	adapt->pAttributes = Attributes_r500;
811	adapt->nAttributes = NUM_ATTRIBUTES_R500;
812    }
813    else if (IS_R300_3D) {
814	adapt->pAttributes = Attributes_r300;
815	adapt->nAttributes = NUM_ATTRIBUTES_R300;
816    }
817    else if (IS_R200_3D) {
818	adapt->pAttributes = Attributes_r200;
819	adapt->nAttributes = NUM_ATTRIBUTES_R200;
820    }
821    else {
822	adapt->pAttributes = Attributes;
823	adapt->nAttributes = NUM_ATTRIBUTES;
824    }
825    adapt->pImages = Images;
826    adapt->nImages = NUM_IMAGES;
827    adapt->PutVideo = NULL;
828    adapt->PutStill = NULL;
829    adapt->GetVideo = NULL;
830    adapt->GetStill = NULL;
831    adapt->StopVideo = RADEONStopVideo;
832    adapt->SetPortAttribute = RADEONSetTexPortAttribute;
833    adapt->GetPortAttribute = RADEONGetTexPortAttribute;
834    adapt->QueryBestSize = RADEONQueryBestSize;
835    adapt->PutImage = RADEONPutImageTextured;
836    adapt->ReputImage = NULL;
837    adapt->QueryImageAttributes = RADEONQueryImageAttributes;
838
839    for (i = 0; i < num_texture_ports; i++) {
840	RADEONPortPrivPtr pPriv = &pPortPriv[i];
841
842	pPriv->textured = TRUE;
843	pPriv->videoStatus = 0;
844	pPriv->currentBuffer = 0;
845	pPriv->doubleBuffer = 0;
846	pPriv->bicubic_state = BICUBIC_OFF;
847	pPriv->vsync = TRUE;
848	pPriv->brightness = 0;
849	pPriv->contrast = 0;
850	pPriv->saturation = 0;
851	pPriv->hue = 0;
852	pPriv->gamma = 1000;
853	pPriv->transform_index = 0;
854	pPriv->desired_crtc = NULL;
855
856	/* gotta uninit this someplace, XXX: shouldn't be necessary for textured */
857	REGION_NULL(pScreen, &pPriv->clip);
858	adapt->pPortPrivates[i].ptr = (pointer) (pPriv);
859    }
860
861    if (IS_R500_3D || IS_R300_3D)
862	radeon_load_bicubic_texture(pScrn);
863
864    info->xv_max_width = adapt->pEncodings->width;
865    info->xv_max_height = adapt->pEncodings->height;
866
867    return adapt;
868}
869
870