radeon_textured_video.c revision 209ff23f
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
46#define IMAGE_MAX_WIDTH		2048
47#define IMAGE_MAX_HEIGHT	2048
48
49#define IMAGE_MAX_WIDTH_R500	4096
50#define IMAGE_MAX_HEIGHT_R500	4096
51
52static Bool
53RADEONTilingEnabled(ScrnInfoPtr pScrn, PixmapPtr pPix)
54{
55    RADEONInfoPtr info = RADEONPTR(pScrn);
56
57#ifdef USE_EXA
58    if (info->useEXA) {
59	if (info->tilingEnabled && exaGetPixmapOffset(pPix) == 0)
60	    return TRUE;
61	else
62	    return FALSE;
63    } else
64#endif
65	{
66	    if (info->tilingEnabled && ((pPix->devPrivate.ptr - info->FB) == 0))
67		return TRUE;
68	    else
69		return FALSE;
70	}
71}
72
73static __inline__ uint32_t F_TO_DW(float val)
74{
75    union {
76	float f;
77	uint32_t l;
78    } tmp;
79    tmp.f = val;
80    return tmp.l;
81}
82
83#define ACCEL_MMIO
84#define VIDEO_PREAMBLE()	unsigned char *RADEONMMIO = info->MMIO
85#define BEGIN_VIDEO(n)		RADEONWaitForFifo(pScrn, (n))
86#define OUT_VIDEO_REG(reg, val)	OUTREG(reg, val)
87#define OUT_VIDEO_REG_F(reg, val) OUTREG(reg, F_TO_DW(val))
88#define FINISH_VIDEO()
89
90#include "radeon_textured_videofuncs.c"
91
92#undef ACCEL_MMIO
93#undef VIDEO_PREAMBLE
94#undef BEGIN_VIDEO
95#undef OUT_VIDEO_REG
96#undef FINISH_VIDEO
97
98#ifdef XF86DRI
99
100#define ACCEL_CP
101#define VIDEO_PREAMBLE()						\
102    RING_LOCALS;							\
103    RADEONCP_REFRESH(pScrn, info)
104#define BEGIN_VIDEO(n)		BEGIN_RING(2*(n))
105#define OUT_VIDEO_REG(reg, val)	OUT_RING_REG(reg, val)
106#define FINISH_VIDEO()		ADVANCE_RING()
107#define OUT_VIDEO_RING_F(x) OUT_RING(F_TO_DW(x))
108
109#include "radeon_textured_videofuncs.c"
110
111#endif /* XF86DRI */
112
113static int
114RADEONPutImageTextured(ScrnInfoPtr pScrn,
115		       short src_x, short src_y,
116		       short drw_x, short drw_y,
117		       short src_w, short src_h,
118		       short drw_w, short drw_h,
119		       int id,
120		       unsigned char *buf,
121		       short width,
122		       short height,
123		       Bool sync,
124		       RegionPtr clipBoxes,
125		       pointer data,
126		       DrawablePtr pDraw)
127{
128    ScreenPtr pScreen = pScrn->pScreen;
129    RADEONInfoPtr info = RADEONPTR(pScrn);
130    RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data;
131    INT32 x1, x2, y1, y2;
132    int srcPitch, srcPitch2, dstPitch;
133    int s2offset, s3offset, tmp;
134    int top, left, npixels, nlines, size;
135    BoxRec dstBox;
136    int dst_width = width, dst_height = height;
137
138    /* make the compiler happy */
139    s2offset = s3offset = srcPitch2 = 0;
140
141    /* Clip */
142    x1 = src_x;
143    x2 = src_x + src_w;
144    y1 = src_y;
145    y2 = src_y + src_h;
146
147    dstBox.x1 = drw_x;
148    dstBox.x2 = drw_x + drw_w;
149    dstBox.y1 = drw_y;
150    dstBox.y2 = drw_y + drw_h;
151
152    if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height))
153	return Success;
154
155    src_w = (x2 - x1) >> 16;
156    src_h = (y2 - y1) >> 16;
157    drw_w = dstBox.x2 - dstBox.x1;
158    drw_h = dstBox.y2 - dstBox.y1;
159
160    if ((x1 >= x2) || (y1 >= y2))
161	return Success;
162
163    switch(id) {
164    case FOURCC_YV12:
165    case FOURCC_I420:
166	dstPitch = ((dst_width << 1) + 15) & ~15;
167	srcPitch = (width + 3) & ~3;
168	srcPitch2 = ((width >> 1) + 3) & ~3;
169	size = dstPitch * dst_height;
170	break;
171    case FOURCC_UYVY:
172    case FOURCC_YUY2:
173    default:
174	dstPitch = ((dst_width << 1) + 15) & ~15;
175	srcPitch = (width << 1);
176	srcPitch2 = 0;
177	size = dstPitch * dst_height;
178	break;
179    }
180
181#ifdef XF86DRI
182   if (info->directRenderingEnabled && info->DMAForXv)
183       /* The upload blit only supports multiples of 64 bytes */
184       dstPitch = (dstPitch + 63) & ~63;
185   else
186#endif
187       dstPitch = (dstPitch + 15) & ~15;
188
189    if (pPriv->video_memory != NULL && size != pPriv->size) {
190	RADEONFreeMemory(pScrn, pPriv->video_memory);
191	pPriv->video_memory = NULL;
192    }
193
194    if (pPriv->video_memory == NULL) {
195	pPriv->video_offset = RADEONAllocateMemory(pScrn,
196						       &pPriv->video_memory,
197						       size * 2);
198	if (pPriv->video_offset == 0)
199	    return BadAlloc;
200    }
201
202    if (pDraw->type == DRAWABLE_WINDOW)
203	pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw);
204    else
205	pPriv->pPixmap = (PixmapPtr)pDraw;
206
207#ifdef USE_EXA
208    if (info->useEXA) {
209	/* Force the pixmap into framebuffer so we can draw to it. */
210	exaMoveInPixmap(pPriv->pPixmap);
211    }
212#endif
213
214    if (!info->useEXA &&
215	(((char *)pPriv->pPixmap->devPrivate.ptr < (char *)info->FB) ||
216	 ((char *)pPriv->pPixmap->devPrivate.ptr >= (char *)info->FB +
217	  info->FbMapSize))) {
218	/* If the pixmap wasn't in framebuffer, then we have no way in XAA to
219	 * force it there. So, we simply refuse to draw and fail.
220	 */
221	return BadAlloc;
222    }
223
224    /* copy data */
225    top = y1 >> 16;
226    left = (x1 >> 16) & ~1;
227    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
228
229    pPriv->src_offset = pPriv->video_offset + info->fbLocation + pScrn->fbOffset;
230    pPriv->src_addr = (uint8_t *)(info->FB + pPriv->video_offset + (top * dstPitch));
231    pPriv->src_pitch = dstPitch;
232    pPriv->size = size;
233    pPriv->pDraw = pDraw;
234
235#if 0
236    ErrorF("src_offset: 0x%x\n", pPriv->src_offset);
237    ErrorF("src_addr: 0x%x\n", pPriv->src_addr);
238    ErrorF("src_pitch: 0x%x\n", pPriv->src_pitch);
239#endif
240
241    switch(id) {
242    case FOURCC_YV12:
243    case FOURCC_I420:
244	top &= ~1;
245	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
246	s2offset = srcPitch * height;
247	s3offset = (srcPitch2 * (height >> 1)) + s2offset;
248	top &= ~1;
249	pPriv->src_addr += left << 1;
250	tmp = ((top >> 1) * srcPitch2) + (left >> 1);
251	s2offset += tmp;
252	s3offset += tmp;
253	if (id == FOURCC_I420) {
254	    tmp = s2offset;
255	    s2offset = s3offset;
256	    s3offset = tmp;
257	}
258	RADEONCopyMungedData(pScrn, buf + (top * srcPitch) + left,
259			     buf + s2offset, buf + s3offset, pPriv->src_addr,
260			     srcPitch, srcPitch2, dstPitch, nlines, npixels);
261	break;
262    case FOURCC_UYVY:
263    case FOURCC_YUY2:
264    default:
265	nlines = ((y2 + 0xffff) >> 16) - top;
266	RADEONCopyData(pScrn, buf, pPriv->src_addr, srcPitch, dstPitch, nlines, npixels, 2);
267	break;
268    }
269
270    /* update cliplist */
271    if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
272	REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
273    }
274
275    pPriv->id = id;
276    pPriv->src_w = src_w;
277    pPriv->src_h = src_h;
278    pPriv->drw_x = drw_x;
279    pPriv->drw_y = drw_y;
280    pPriv->dst_w = drw_w;
281    pPriv->dst_h = drw_h;
282    pPriv->w = width;
283    pPriv->h = height;
284
285#ifdef XF86DRI
286    if (info->directRenderingEnabled)
287	RADEONDisplayTexturedVideoCP(pScrn, pPriv);
288    else
289#endif
290	RADEONDisplayTexturedVideoMMIO(pScrn, pPriv);
291
292    return Success;
293}
294
295/* client libraries expect an encoding */
296static XF86VideoEncodingRec DummyEncoding[1] =
297{
298    {
299	0,
300	"XV_IMAGE",
301	IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
302	{1, 1}
303    }
304};
305
306static XF86VideoEncodingRec DummyEncodingR500[1] =
307{
308    {
309	0,
310	"XV_IMAGE",
311	IMAGE_MAX_WIDTH_R500, IMAGE_MAX_HEIGHT_R500,
312	{1, 1}
313    }
314};
315
316#define NUM_FORMATS 3
317
318static XF86VideoFormatRec Formats[NUM_FORMATS] =
319{
320    {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
321};
322
323#define NUM_ATTRIBUTES 0
324
325static XF86AttributeRec Attributes[NUM_ATTRIBUTES] =
326{
327};
328
329#define NUM_IMAGES 4
330
331static XF86ImageRec Images[NUM_IMAGES] =
332{
333    XVIMAGE_YUY2,
334    XVIMAGE_YV12,
335    XVIMAGE_I420,
336    XVIMAGE_UYVY
337};
338
339XF86VideoAdaptorPtr
340RADEONSetupImageTexturedVideo(ScreenPtr pScreen)
341{
342    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
343    RADEONInfoPtr    info = RADEONPTR(pScrn);
344    RADEONPortPrivPtr pPortPriv;
345    XF86VideoAdaptorPtr adapt;
346    int i;
347    int num_texture_ports = 16;
348
349    adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports *
350		    (sizeof(RADEONPortPrivRec) + sizeof(DevUnion)));
351    if (adapt == NULL)
352	return NULL;
353
354    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
355    adapt->flags = 0;
356    adapt->name = "Radeon Textured Video";
357    adapt->nEncodings = 1;
358    if (IS_R500_3D)
359	adapt->pEncodings = DummyEncodingR500;
360    else
361	adapt->pEncodings = DummyEncoding;
362    adapt->nFormats = NUM_FORMATS;
363    adapt->pFormats = Formats;
364    adapt->nPorts = num_texture_ports;
365    adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
366
367    pPortPriv =
368	(RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]);
369
370    adapt->nAttributes = NUM_ATTRIBUTES;
371    adapt->pAttributes = Attributes;
372    adapt->pImages = Images;
373    adapt->nImages = NUM_IMAGES;
374    adapt->PutVideo = NULL;
375    adapt->PutStill = NULL;
376    adapt->GetVideo = NULL;
377    adapt->GetStill = NULL;
378    adapt->StopVideo = RADEONStopVideo;
379    adapt->SetPortAttribute = RADEONSetPortAttribute;
380    adapt->GetPortAttribute = RADEONGetPortAttribute;
381    adapt->QueryBestSize = RADEONQueryBestSize;
382    adapt->PutImage = RADEONPutImageTextured;
383    adapt->ReputImage = NULL;
384    adapt->QueryImageAttributes = RADEONQueryImageAttributes;
385
386    for (i = 0; i < num_texture_ports; i++) {
387	RADEONPortPrivPtr pPriv = &pPortPriv[i];
388
389	pPriv->textured = TRUE;
390	pPriv->videoStatus = 0;
391	pPriv->currentBuffer = 0;
392	pPriv->doubleBuffer = 0;
393
394	/* gotta uninit this someplace, XXX: shouldn't be necessary for textured */
395	REGION_NULL(pScreen, &pPriv->clip);
396	adapt->pPortPrivates[i].ptr = (pointer) (pPriv);
397    }
398
399    return adapt;
400}
401
402