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