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