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