radeon_textured_video.c revision 30d12090
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 aligned_height;
251#ifdef XF86DRM_MODE
252    int h_align = drmmode_get_height_align(pScrn, 0);
253#else
254    int h_align = 1;
255#endif
256    /* make the compiler happy */
257    s2offset = s3offset = srcPitch2 = 0;
258
259    /* Clip */
260    x1 = src_x;
261    x2 = src_x + src_w;
262    y1 = src_y;
263    y2 = src_y + src_h;
264
265    dstBox.x1 = drw_x;
266    dstBox.x2 = drw_x + drw_w;
267    dstBox.y1 = drw_y;
268    dstBox.y2 = drw_y + drw_h;
269
270    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
271	return Success;
272
273    if ((x1 >= x2) || (y1 >= y2))
274	return Success;
275
276    /* Bicubic filter setup */
277    pPriv->bicubic_enabled = (pPriv->bicubic_state != BICUBIC_OFF);
278    if (!(IS_R300_3D || IS_R500_3D)) {
279	pPriv->bicubic_enabled = FALSE;
280	pPriv->bicubic_state = BICUBIC_OFF;
281    }
282    if (pPriv->bicubic_enabled && (pPriv->bicubic_state == BICUBIC_AUTO)) {
283	/*
284	 * Applying the bicubic filter with a scale of less than 200%
285	 * results in a blurred picture, so disable the filter.
286	 */
287	if ((src_w > drw_w / 2) || (src_h > drw_h / 2))
288	    pPriv->bicubic_enabled = FALSE;
289    }
290
291#ifdef XF86DRM_MODE
292    if (info->cs) {
293	if (info->ChipFamily >= CHIP_FAMILY_R600)
294	    pPriv->hw_align = drmmode_get_base_align(pScrn, 2, 0);
295	else
296	    pPriv->hw_align = 64;
297    } else
298#endif
299    {
300	if (info->ChipFamily >= CHIP_FAMILY_R600)
301	    pPriv->hw_align = 256;
302	else
303	    pPriv->hw_align = 64;
304    }
305
306    aligned_height = RADEON_ALIGN(dst_height, h_align);
307
308    switch(id) {
309    case FOURCC_YV12:
310    case FOURCC_I420:
311	srcPitch = RADEON_ALIGN(width, 4);
312	srcPitch2 = RADEON_ALIGN(width >> 1, 4);
313        if (pPriv->bicubic_state != BICUBIC_OFF) {
314	    dstPitch = RADEON_ALIGN(dst_width << 1, pPriv->hw_align);
315	    dstPitch2 = 0;
316	} else {
317	    dstPitch = RADEON_ALIGN(dst_width, pPriv->hw_align);
318	    dstPitch2 = RADEON_ALIGN(dstPitch >> 1, pPriv->hw_align);
319	}
320	break;
321    case FOURCC_UYVY:
322    case FOURCC_YUY2:
323    default:
324	dstPitch = RADEON_ALIGN(dst_width << 1, pPriv->hw_align);
325	srcPitch = (width << 1);
326	srcPitch2 = 0;
327	break;
328    }
329
330    size = dstPitch * aligned_height + 2 * dstPitch2 * RADEON_ALIGN(((aligned_height + 1) >> 1), h_align);
331    size = RADEON_ALIGN(size, pPriv->hw_align);
332
333    if (size != pPriv->size) {
334	RADEONFreeVideoMemory(pScrn, pPriv);
335    }
336
337    if (pPriv->video_memory == NULL) {
338	pPriv->video_offset = radeon_legacy_allocate_memory(pScrn,
339							    &pPriv->video_memory,
340							    size, pPriv->hw_align,
341							    RADEON_GEM_DOMAIN_GTT);
342	if (pPriv->video_offset == 0)
343	    return BadAlloc;
344
345	if (info->cs) {
346	    pPriv->src_bo[0] = pPriv->video_memory;
347	    radeon_legacy_allocate_memory(pScrn, (void*)&pPriv->src_bo[1], size,
348					  pPriv->hw_align,
349					  RADEON_GEM_DOMAIN_GTT);
350	}
351    }
352
353    /* Bicubic filter loading */
354    if (pPriv->bicubic_enabled) {
355	if (info->bicubic_offset == 0)
356	    pPriv->bicubic_enabled = FALSE;
357	pPriv->bicubic_src_offset = info->bicubic_offset;
358    }
359
360    if (pDraw->type == DRAWABLE_WINDOW)
361	pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
362    else
363	pPriv->pPixmap = (PixmapPtr)pDraw;
364
365#ifdef USE_EXA
366    if (info->useEXA) {
367	/* Force the pixmap into framebuffer so we can draw to it. */
368	info->exa_force_create = TRUE;
369	exaMoveInPixmap(pPriv->pPixmap);
370	info->exa_force_create = FALSE;
371    }
372#endif
373
374    if (!info->useEXA &&
375	(((char *)pPriv->pPixmap->devPrivate.ptr < (char *)info->FB) ||
376	 ((char *)pPriv->pPixmap->devPrivate.ptr >= (char *)info->FB +
377	  info->FbMapSize))) {
378	/* If the pixmap wasn't in framebuffer, then we have no way in XAA to
379	 * force it there. So, we simply refuse to draw and fail.
380	 */
381	return BadAlloc;
382    }
383
384    /* copy data */
385    top = (y1 >> 16) & ~1;
386    nlines = RADEON_ALIGN((y2 + 0xffff) >> 16, 2) - top;
387
388    pPriv->src_offset = pPriv->video_offset;
389    if (info->cs) {
390	struct radeon_bo *src_bo;
391	int ret;
392
393	pPriv->currentBuffer ^= 1;
394
395	src_bo = pPriv->src_bo[pPriv->currentBuffer];
396
397	ret = radeon_bo_map(src_bo, 1);
398	if (ret)
399	    return BadAlloc;
400
401	pPriv->src_addr = src_bo->ptr;
402    } else {
403	pPriv->src_addr = (uint8_t *)(info->FB + pPriv->video_offset);
404	RADEONWaitForIdleMMIO(pScrn);
405    }
406    pPriv->src_pitch = dstPitch;
407
408    pPriv->planeu_offset = dstPitch * aligned_height;
409    pPriv->planeu_offset = RADEON_ALIGN(pPriv->planeu_offset, pPriv->hw_align);
410    pPriv->planev_offset = pPriv->planeu_offset + dstPitch2 * RADEON_ALIGN(((aligned_height + 1) >> 1), h_align);
411    pPriv->planev_offset = RADEON_ALIGN(pPriv->planev_offset, pPriv->hw_align);
412
413    pPriv->size = size;
414    pPriv->pDraw = pDraw;
415
416    switch(id) {
417    case FOURCC_YV12:
418    case FOURCC_I420:
419	s2offset = srcPitch * (RADEON_ALIGN(height, 2));
420	s3offset = s2offset + (srcPitch2 * ((height + 1) >> 1));
421	s2offset += ((top >> 1) * srcPitch2);
422	s3offset += ((top >> 1) * srcPitch2);
423	if (pPriv->bicubic_state != BICUBIC_OFF) {
424	    if (id == FOURCC_I420) {
425		tmp = s2offset;
426		s2offset = s3offset;
427		s3offset = tmp;
428	    }
429	    RADEONCopyMungedData(pScrn, buf + (top * srcPitch),
430				 buf + s2offset, buf + s3offset, pPriv->src_addr + (top * dstPitch),
431				 srcPitch, srcPitch2, dstPitch, nlines, width);
432	} else {
433	    if (id == FOURCC_YV12) {
434		tmp = s2offset;
435		s2offset = s3offset;
436		s3offset = tmp;
437	    }
438	    d2line = pPriv->planeu_offset + ((top >> 1) * dstPitch2);
439	    d3line = pPriv->planev_offset + ((top >> 1) * dstPitch2);
440
441	    if (info->ChipFamily >= CHIP_FAMILY_R600) {
442		R600CopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch),
443			     srcPitch, dstPitch, nlines, width, 1);
444		R600CopyData(pScrn, buf + s2offset,  pPriv->src_addr + d2line,
445			     srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
446		R600CopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line,
447			     srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
448	    } else {
449		RADEONCopyData(pScrn, buf + (top * srcPitch), pPriv->src_addr + (top * dstPitch),
450			       srcPitch, dstPitch, nlines, width, 1);
451		RADEONCopyData(pScrn, buf + s2offset,  pPriv->src_addr + d2line,
452			       srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
453		RADEONCopyData(pScrn, buf + s3offset, pPriv->src_addr + d3line,
454			       srcPitch2, dstPitch2, (nlines + 1) >> 1, width >> 1, 1);
455	    }
456	}
457	break;
458    case FOURCC_UYVY:
459    case FOURCC_YUY2:
460    default:
461	if (info->ChipFamily >= CHIP_FAMILY_R600)
462	    R600CopyData(pScrn, buf + (top * srcPitch),
463			 pPriv->src_addr + (top * dstPitch),
464			 srcPitch, dstPitch, nlines, width, 2);
465	else
466	    RADEONCopyData(pScrn, buf + (top * srcPitch),
467			   pPriv->src_addr + (top * dstPitch),
468			   srcPitch, dstPitch, nlines, width, 2);
469	break;
470    }
471
472    /* update cliplist */
473    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
474	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
475    }
476
477    pPriv->id = id;
478    pPriv->src_w = src_w;
479    pPriv->src_h = src_h;
480    pPriv->src_x = src_x;
481    pPriv->src_y = src_y;
482    pPriv->drw_x = drw_x;
483    pPriv->drw_y = drw_y;
484    pPriv->dst_w = drw_w;
485    pPriv->dst_h = drw_h;
486    pPriv->w = width;
487    pPriv->h = height;
488
489#if defined(XF86DRM_MODE)
490    if (info->cs)
491	radeon_bo_unmap(pPriv->src_bo[pPriv->currentBuffer]);
492#endif
493#ifdef XF86DRI
494    if (info->directRenderingEnabled) {
495#ifdef XF86DRM_MODE
496	if (IS_EVERGREEN_3D)
497	    EVERGREENDisplayTexturedVideo(pScrn, pPriv);
498	else
499#endif
500	  if (IS_R600_3D)
501	    R600DisplayTexturedVideo(pScrn, pPriv);
502	else if (IS_R500_3D)
503	    R500DisplayTexturedVideoCP(pScrn, pPriv);
504	else if (IS_R300_3D)
505	    R300DisplayTexturedVideoCP(pScrn, pPriv);
506	else if (IS_R200_3D)
507	    R200DisplayTexturedVideoCP(pScrn, pPriv);
508	else
509	    RADEONDisplayTexturedVideoCP(pScrn, pPriv);
510    } else
511#endif
512    {
513	if (IS_R500_3D)
514	    R500DisplayTexturedVideoMMIO(pScrn, pPriv);
515	else if (IS_R300_3D)
516	    R300DisplayTexturedVideoMMIO(pScrn, pPriv);
517	else if (IS_R200_3D)
518	    R200DisplayTexturedVideoMMIO(pScrn, pPriv);
519	else
520	    RADEONDisplayTexturedVideoMMIO(pScrn, pPriv);
521    }
522
523    return Success;
524}
525
526/* client libraries expect an encoding */
527static XF86VideoEncodingRec DummyEncoding[1] =
528{
529    {
530	0,
531	"XV_IMAGE",
532	IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
533	{1, 1}
534    }
535};
536
537static XF86VideoEncodingRec DummyEncodingR500[1] =
538{
539    {
540	0,
541	"XV_IMAGE",
542	IMAGE_MAX_WIDTH_R500, IMAGE_MAX_HEIGHT_R500,
543	{1, 1}
544    }
545};
546
547static XF86VideoEncodingRec DummyEncodingR600[1] =
548{
549    {
550	0,
551	"XV_IMAGE",
552	IMAGE_MAX_WIDTH_R600, IMAGE_MAX_HEIGHT_R600,
553	{1, 1}
554    }
555};
556
557#define NUM_FORMATS 3
558
559static XF86VideoFormatRec Formats[NUM_FORMATS] =
560{
561    {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
562};
563
564#define NUM_ATTRIBUTES 2
565
566static XF86AttributeRec Attributes[NUM_ATTRIBUTES+1] =
567{
568    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
569    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
570    {0, 0, 0, NULL}
571};
572
573#define NUM_ATTRIBUTES_R200 7
574
575static XF86AttributeRec Attributes_r200[NUM_ATTRIBUTES_R200+1] =
576{
577    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
578    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
579    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
580    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
581    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
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_R300 9
588
589static XF86AttributeRec Attributes_r300[NUM_ATTRIBUTES_R300+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, 100, 10000, "XV_GAMMA"},
598    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
599    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
600    {0, 0, 0, NULL}
601};
602
603#define NUM_ATTRIBUTES_R500 8
604
605static XF86AttributeRec Attributes_r500[NUM_ATTRIBUTES_R500+1] =
606{
607    {XvSettable | XvGettable, 0, 2, "XV_BICUBIC"},
608    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
609    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
610    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
611    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
612    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
613    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
614    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
615    {0, 0, 0, NULL}
616};
617
618#define NUM_ATTRIBUTES_R600 7
619
620static XF86AttributeRec Attributes_r600[NUM_ATTRIBUTES_R600+1] =
621{
622    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
623    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
624    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
625    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
626    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
627    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
628    {XvSettable | XvGettable, -1, 1, "XV_CRTC"},
629    {0, 0, 0, NULL}
630};
631
632static XF86AttributeRec Attributes_eg[NUM_ATTRIBUTES_R600+1] =
633{
634    {XvSettable | XvGettable, 0, 1, "XV_VSYNC"},
635    {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"},
636    {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"},
637    {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"},
638    {XvSettable | XvGettable, -1000, 1000, "XV_HUE"},
639    {XvSettable | XvGettable, 0, 1, "XV_COLORSPACE"},
640    {XvSettable | XvGettable, -1, 5, "XV_CRTC"},
641    {0, 0, 0, NULL}
642};
643
644static Atom xvBicubic;
645static Atom xvVSync;
646static Atom xvBrightness, xvContrast, xvSaturation, xvHue;
647static Atom xvGamma, xvColorspace;
648static Atom xvCRTC;
649
650#define NUM_IMAGES 4
651
652static XF86ImageRec Images[NUM_IMAGES] =
653{
654    XVIMAGE_YUY2,
655    XVIMAGE_YV12,
656    XVIMAGE_I420,
657    XVIMAGE_UYVY
658};
659
660int
661RADEONGetTexPortAttribute(ScrnInfoPtr  pScrn,
662		       Atom	    attribute,
663		       INT32	    *value,
664		       pointer	    data)
665{
666    RADEONInfoPtr	info = RADEONPTR(pScrn);
667    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;
668
669    if (info->accelOn) RADEON_SYNC(info, pScrn);
670
671    if (attribute == xvBicubic)
672	*value = pPriv->bicubic_state;
673    else if (attribute == xvVSync)
674	*value = pPriv->vsync;
675    else if (attribute == xvBrightness)
676	*value = pPriv->brightness;
677    else if (attribute == xvContrast)
678	*value = pPriv->contrast;
679    else if (attribute == xvSaturation)
680	*value = pPriv->saturation;
681    else if (attribute == xvHue)
682	*value = pPriv->hue;
683    else if (attribute == xvGamma)
684	*value = pPriv->gamma;
685    else if(attribute == xvColorspace)
686	*value = pPriv->transform_index;
687    else if(attribute == xvCRTC) {
688	int		c;
689	xf86CrtcConfigPtr	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
690	for (c = 0; c < xf86_config->num_crtc; c++)
691	    if (xf86_config->crtc[c] == pPriv->desired_crtc)
692		break;
693	if (c == xf86_config->num_crtc)
694	    c = -1;
695	*value = c;
696    } else
697	return BadMatch;
698
699    return Success;
700}
701
702int
703RADEONSetTexPortAttribute(ScrnInfoPtr  pScrn,
704		       Atom	    attribute,
705		       INT32	    value,
706		       pointer	    data)
707{
708    RADEONInfoPtr	info = RADEONPTR(pScrn);
709    RADEONPortPrivPtr	pPriv = (RADEONPortPrivPtr)data;
710
711    RADEON_SYNC(info, pScrn);
712
713    if (attribute == xvBicubic)
714	pPriv->bicubic_state = ClipValue (value, 0, 2);
715    else if (attribute == xvVSync)
716	pPriv->vsync = ClipValue (value, 0, 1);
717    else if (attribute == xvBrightness)
718	pPriv->brightness = ClipValue (value, -1000, 1000);
719    else if (attribute == xvContrast)
720	pPriv->contrast = ClipValue (value, -1000, 1000);
721    else if (attribute == xvSaturation)
722	pPriv->saturation = ClipValue (value, -1000, 1000);
723    else if (attribute == xvHue)
724	pPriv->hue = ClipValue (value, -1000, 1000);
725    else if (attribute == xvGamma)
726	pPriv->gamma = ClipValue (value, 100, 10000);
727    else if(attribute == xvColorspace)
728	pPriv->transform_index = ClipValue (value, 0, 1);
729    else if(attribute == xvCRTC) {
730	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
731	if ((value < -1) || (value > xf86_config->num_crtc))
732	    return BadValue;
733	if (value < 0)
734	    pPriv->desired_crtc = NULL;
735	else
736	    pPriv->desired_crtc = xf86_config->crtc[value];
737    } else
738	return BadMatch;
739
740    return Success;
741}
742
743Bool radeon_load_bicubic_texture(ScrnInfoPtr pScrn)
744{
745    RADEONInfoPtr    info = RADEONPTR(pScrn);
746
747    /* Bicubic filter loading */
748    info->bicubic_offset = radeon_legacy_allocate_memory(pScrn,
749							 &info->bicubic_memory,
750							 sizeof(bicubic_tex_512), 64,
751							 RADEON_GEM_DOMAIN_VRAM);
752    if (info->bicubic_offset == 0)
753	return FALSE;
754
755    if (info->cs)
756	info->bicubic_bo = info->bicubic_memory;
757
758    /* Upload bicubic filter tex */
759    if (info->ChipFamily < CHIP_FAMILY_R600) {
760	uint8_t *bicubic_addr;
761	int ret;
762	if (info->cs) {
763	    ret = radeon_bo_map(info->bicubic_bo, 1);
764	    if (ret)
765		return FALSE;
766
767	    bicubic_addr = info->bicubic_bo->ptr;
768	} else
769	    bicubic_addr = (uint8_t *)(info->FB + info->bicubic_offset);
770
771	RADEONCopySwap(bicubic_addr, (uint8_t *)bicubic_tex_512, 1024,
772#if X_BYTE_ORDER == X_BIG_ENDIAN
773		       RADEON_HOST_DATA_SWAP_16BIT
774#else
775		       RADEON_HOST_DATA_SWAP_NONE
776#endif
777);
778	if (info->cs)
779	    radeon_bo_unmap(info->bicubic_bo);
780    }
781    return TRUE;
782}
783
784#if 0
785/* XXX */
786static void radeon_unload_bicubic_texture(ScrnInfoPtr pScrn)
787{
788    RADEONInfoPtr    info = RADEONPTR(pScrn);
789
790    if (info->bicubic_memory != NULL) {
791	radeon_legacy_free_memory(pScrn, info->bicubic_memory);
792	info->bicubic_memory = NULL;
793    }
794
795}
796#endif
797
798XF86VideoAdaptorPtr
799RADEONSetupImageTexturedVideo(ScreenPtr pScreen)
800{
801    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
802    RADEONInfoPtr    info = RADEONPTR(pScrn);
803    RADEONPortPrivPtr pPortPriv;
804    XF86VideoAdaptorPtr adapt;
805    int i;
806    int num_texture_ports = 16;
807
808    adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports *
809		   (sizeof(RADEONPortPrivRec) + sizeof(DevUnion)));
810    if (adapt == NULL)
811	return NULL;
812
813    xvBicubic         = MAKE_ATOM("XV_BICUBIC");
814    xvVSync           = MAKE_ATOM("XV_VSYNC");
815    xvBrightness      = MAKE_ATOM("XV_BRIGHTNESS");
816    xvContrast        = MAKE_ATOM("XV_CONTRAST");
817    xvSaturation      = MAKE_ATOM("XV_SATURATION");
818    xvHue             = MAKE_ATOM("XV_HUE");
819    xvGamma           = MAKE_ATOM("XV_GAMMA");
820    xvColorspace      = MAKE_ATOM("XV_COLORSPACE");
821    xvCRTC            = MAKE_ATOM("XV_CRTC");
822
823    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
824    adapt->flags = 0;
825    adapt->name = "Radeon Textured Video";
826    adapt->nEncodings = 1;
827    if (IS_R600_3D)
828	adapt->pEncodings = DummyEncodingR600;
829    else if (IS_R500_3D)
830	adapt->pEncodings = DummyEncodingR500;
831    else
832	adapt->pEncodings = DummyEncoding;
833    adapt->nFormats = NUM_FORMATS;
834    adapt->pFormats = Formats;
835    adapt->nPorts = num_texture_ports;
836    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
837
838    pPortPriv =
839	(RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]);
840
841    if (IS_EVERGREEN_3D) {
842	adapt->pAttributes = Attributes_eg;
843	adapt->nAttributes = NUM_ATTRIBUTES_R600;
844    }
845    else if (IS_R600_3D) {
846	adapt->pAttributes = Attributes_r600;
847	adapt->nAttributes = NUM_ATTRIBUTES_R600;
848    }
849    else if (IS_R500_3D) {
850	adapt->pAttributes = Attributes_r500;
851	adapt->nAttributes = NUM_ATTRIBUTES_R500;
852    }
853    else if (IS_R300_3D) {
854	adapt->pAttributes = Attributes_r300;
855	adapt->nAttributes = NUM_ATTRIBUTES_R300;
856    }
857    else if (IS_R200_3D) {
858	adapt->pAttributes = Attributes_r200;
859	adapt->nAttributes = NUM_ATTRIBUTES_R200;
860    }
861    else {
862	adapt->pAttributes = Attributes;
863	adapt->nAttributes = NUM_ATTRIBUTES;
864    }
865    adapt->pImages = Images;
866    adapt->nImages = NUM_IMAGES;
867    adapt->PutVideo = NULL;
868    adapt->PutStill = NULL;
869    adapt->GetVideo = NULL;
870    adapt->GetStill = NULL;
871    adapt->StopVideo = RADEONStopVideo;
872    adapt->SetPortAttribute = RADEONSetTexPortAttribute;
873    adapt->GetPortAttribute = RADEONGetTexPortAttribute;
874    adapt->QueryBestSize = RADEONQueryBestSize;
875    adapt->PutImage = RADEONPutImageTextured;
876    adapt->ReputImage = NULL;
877    adapt->QueryImageAttributes = RADEONQueryImageAttributes;
878
879    for (i = 0; i < num_texture_ports; i++) {
880	RADEONPortPrivPtr pPriv = &pPortPriv[i];
881
882	pPriv->textured = TRUE;
883	pPriv->videoStatus = 0;
884	pPriv->currentBuffer = 0;
885	pPriv->doubleBuffer = 0;
886	pPriv->bicubic_state = BICUBIC_OFF;
887	pPriv->vsync = TRUE;
888	pPriv->brightness = 0;
889	pPriv->contrast = 0;
890	pPriv->saturation = 0;
891	pPriv->hue = 0;
892	pPriv->gamma = 1000;
893	pPriv->transform_index = 0;
894	pPriv->desired_crtc = NULL;
895
896	/* gotta uninit this someplace, XXX: shouldn't be necessary for textured */
897	REGION_NULL(pScreen, &pPriv->clip);
898	adapt->pPortPrivates[i].ptr = (pointer) (pPriv);
899    }
900
901    if (IS_R500_3D || IS_R300_3D)
902	radeon_load_bicubic_texture(pScrn);
903
904    info->xv_max_width = adapt->pEncodings->width;
905    info->xv_max_height = adapt->pEncodings->height;
906
907    return adapt;
908}
909
910