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