lx_video.c revision 7aef237f
1f29dbc25Smrg/* Copyright (c) 2007-2008 Advanced Micro Devices, Inc.
2f29dbc25Smrg *
3f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a copy
4f29dbc25Smrg * of this software and associated documentation files (the "Software"), to
5f29dbc25Smrg * deal in the Software without restriction, including without limitation the
6f29dbc25Smrg * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7f29dbc25Smrg * sell copies of the Software, and to permit persons to whom the Software is
8f29dbc25Smrg * furnished to do so, subject to the following conditions:
9f29dbc25Smrg *
10f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
11f29dbc25Smrg * all copies or substantial portions of the Software.
12f29dbc25Smrg *
13f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19f29dbc25Smrg * IN THE SOFTWARE.
20f29dbc25Smrg *
21f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
23f29dbc25Smrg * software without specific prior written permission.
24f29dbc25Smrg */
25f29dbc25Smrg
26f29dbc25Smrg/* TODO:
27f29dbc25Smrg   Add rotation
28f29dbc25Smrg   Add back in double buffering?
29f29dbc25Smrg
30f29dbc25Smrg*/
31f29dbc25Smrg
32f29dbc25Smrg#ifdef HAVE_CONFIG_H
33f29dbc25Smrg#include "config.h"
34f29dbc25Smrg#endif
35f29dbc25Smrg
36f29dbc25Smrg#include <stdlib.h>
37f29dbc25Smrg#include <string.h>
38f29dbc25Smrg
39f29dbc25Smrg#include "xf86.h"
40f29dbc25Smrg#include "xf86_OSproc.h"
41f29dbc25Smrg#include "compiler.h"
42f29dbc25Smrg#include "xf86PciInfo.h"
43f29dbc25Smrg#include "xf86Pci.h"
44f29dbc25Smrg#include "xf86fbman.h"
45f29dbc25Smrg#include "regionstr.h"
46f29dbc25Smrg#include "dixstruct.h"
47f29dbc25Smrg
48f29dbc25Smrg#include "geode.h"
49f29dbc25Smrg#include "xf86xv.h"
50f29dbc25Smrg#include <X11/extensions/Xv.h>
51f29dbc25Smrg#include "fourcc.h"
52f29dbc25Smrg#include "geode_fourcc.h"
53f29dbc25Smrg#include "cim/cim_defs.h"
54f29dbc25Smrg#include "cim/cim_regs.h"
55f29dbc25Smrg
56f29dbc25Smrg#define OFF_DELAY 		200
57f29dbc25Smrg#define FREE_DELAY 		60000
58f29dbc25Smrg#define OFF_TIMER 		0x01
59f29dbc25Smrg#define FREE_TIMER		0x02
60f29dbc25Smrg#define CLIENT_VIDEO_ON	0x04
61f29dbc25Smrg#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
62f29dbc25Smrg
63f29dbc25Smrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
64f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
65f29dbc25Smrg
66f29dbc25Smrg/* Local function prototypes */
67f29dbc25Smrgstatic void LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit);
68f29dbc25Smrg
69f29dbc25Smrgstatic void
70f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
71f29dbc25Smrg    BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH);
72f29dbc25Smrg
73f29dbc25Smrgstatic void LXResetVideo(ScrnInfoPtr pScrni);
74f29dbc25Smrg
75f29dbc25Smrgstatic XF86VideoEncodingRec DummyEncoding[1] = {
76f29dbc25Smrg    {0, "XV_IMAGE", 1024, 1024, {1, 1}}
77f29dbc25Smrg};
78f29dbc25Smrg
79f29dbc25Smrgstatic XF86VideoFormatRec Formats[] = {
80f29dbc25Smrg    {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
81f29dbc25Smrg};
82f29dbc25Smrg
83f29dbc25Smrgstatic XF86AttributeRec Attributes[] = {
84f29dbc25Smrg    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
85f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
86f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
87f29dbc25Smrg};
88f29dbc25Smrg
89f29dbc25Smrgstatic XF86ImageRec Images[] = {
90f29dbc25Smrg    XVIMAGE_UYVY,
91f29dbc25Smrg    XVIMAGE_YUY2,
92f29dbc25Smrg    XVIMAGE_Y2YU,
93f29dbc25Smrg    XVIMAGE_YVYU,
94f29dbc25Smrg    XVIMAGE_Y800,
95f29dbc25Smrg    XVIMAGE_I420,
96f29dbc25Smrg    XVIMAGE_YV12,
97f29dbc25Smrg    XVIMAGE_RGB565
98f29dbc25Smrg};
99f29dbc25Smrg
100f29dbc25Smrgtypedef struct
101f29dbc25Smrg{
102170d5fdcSmrg    ExaOffscreenArea *vidmem;
103f29dbc25Smrg    RegionRec clip;
104f29dbc25Smrg    CARD32 filter;
105f29dbc25Smrg    CARD32 colorKey;
106f29dbc25Smrg    CARD32 colorKeyMode;
107f29dbc25Smrg    CARD32 videoStatus;
108f29dbc25Smrg    Time offTime;
109f29dbc25Smrg    Time freeTime;
110f29dbc25Smrg    short pwidth, pheight;
111f29dbc25Smrg} GeodePortPrivRec, *GeodePortPrivPtr;
112f29dbc25Smrg
113f29dbc25Smrg#define GET_PORT_PRIVATE(pScrni) \
114f29dbc25Smrg   (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr)
115f29dbc25Smrg
116f29dbc25Smrgstatic void
117f29dbc25SmrgLXCopyFromSys(GeodeRec * pGeode, unsigned char *src, unsigned int dst,
118f29dbc25Smrg    int dstPitch, int srcPitch, int h, int w)
119f29dbc25Smrg{
120f29dbc25Smrg
121f29dbc25Smrg    gp_declare_blt(0);
122170d5fdcSmrg    gp_set_bpp((srcPitch / w) << 3);
123f29dbc25Smrg
124f29dbc25Smrg    gp_set_raster_operation(0xCC);
125f29dbc25Smrg    gp_set_strides(dstPitch, srcPitch);
126f29dbc25Smrg    gp_set_solid_pattern(0);
127f29dbc25Smrg
128f29dbc25Smrg    gp_color_bitmap_to_screen_blt(dst, 0, w, h, src, srcPitch);
129f29dbc25Smrg}
130f29dbc25Smrg
131f29dbc25Smrgstatic void
132f29dbc25SmrgLXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv)
133f29dbc25Smrg{
134f29dbc25Smrg    int red, green, blue;
135f29dbc25Smrg    unsigned long key;
136f29dbc25Smrg
137f29dbc25Smrg    switch (pScrni->depth) {
138f29dbc25Smrg    case 8:
139f29dbc25Smrg	vg_get_display_palette_entry(pPriv->colorKey & 0xFF, &key);
140f29dbc25Smrg	red = ((key >> 16) & 0xFF);
141f29dbc25Smrg	green = ((key >> 8) & 0xFF);
142f29dbc25Smrg	blue = (key & 0xFF);
143f29dbc25Smrg	break;
144f29dbc25Smrg    case 16:
145f29dbc25Smrg	red = (pPriv->colorKey & pScrni->mask.red) >>
146f29dbc25Smrg	    pScrni->offset.red << (8 - pScrni->weight.red);
147f29dbc25Smrg	green = (pPriv->colorKey & pScrni->mask.green) >>
148f29dbc25Smrg	    pScrni->offset.green << (8 - pScrni->weight.green);
149f29dbc25Smrg	blue = (pPriv->colorKey & pScrni->mask.blue) >>
150f29dbc25Smrg	    pScrni->offset.blue << (8 - pScrni->weight.blue);
151f29dbc25Smrg	break;
152f29dbc25Smrg    default:
153f29dbc25Smrg	/* for > 16 bpp we send in the mask in xf86SetWeight. This
154f29dbc25Smrg	 * function is providing the offset by 1 more. So we take
155f29dbc25Smrg	 * this as a special case and subtract 1 for > 16
156f29dbc25Smrg	 */
157f29dbc25Smrg
158f29dbc25Smrg	red = (pPriv->colorKey & pScrni->mask.red) >>
159f29dbc25Smrg	    (pScrni->offset.red - 1) << (8 - pScrni->weight.red);
160f29dbc25Smrg	green = (pPriv->colorKey & pScrni->mask.green) >>
161f29dbc25Smrg	    (pScrni->offset.green - 1) << (8 - pScrni->weight.green);
162f29dbc25Smrg	blue = (pPriv->colorKey & pScrni->mask.blue) >>
163f29dbc25Smrg	    (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue);
164f29dbc25Smrg	break;
165f29dbc25Smrg    }
166f29dbc25Smrg
167f29dbc25Smrg    df_set_video_color_key((blue | (green << 8) | (red << 16)),
168f29dbc25Smrg	0xFFFFFF, (pPriv->colorKeyMode == 0));
169f29dbc25Smrg
170f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
171f29dbc25Smrg}
172f29dbc25Smrg
173f29dbc25Smrg/* A structure full of the scratch information that originates in the copy routines,
174f29dbc25Smrg   but is needed for the video display - maybe we should figure out a way to attach
175f29dbc25Smrg   this to structures?  I hate to put it in pGeode since it will increase the size of
176f29dbc25Smrg   the structure, and possibly cause us cache issues.
177f29dbc25Smrg*/
178f29dbc25Smrg
179f29dbc25Smrgstruct
180f29dbc25Smrg{
181f29dbc25Smrg    unsigned int dstOffset;
182f29dbc25Smrg    unsigned int dstPitch;
183f29dbc25Smrg    unsigned int UVPitch;
184f29dbc25Smrg    unsigned int UDstOffset;
185f29dbc25Smrg    unsigned int VDstOffset;
186f29dbc25Smrg} videoScratch;
187f29dbc25Smrg
188f29dbc25Smrg/* Copy planar YUV data */
189f29dbc25Smrg
190f29dbc25Smrgstatic Bool
191170d5fdcSmrgLXAllocateVidMem(ScrnInfoPtr pScrni, GeodePortPrivRec *pPriv, int size)
192f29dbc25Smrg{
193f29dbc25Smrg    if (!pPriv->vidmem || pPriv->vidmem->size < size) {
194170d5fdcSmrg	if (pPriv->vidmem) {
195170d5fdcSmrg		exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
196170d5fdcSmrg		pPriv->vidmem = NULL;
197170d5fdcSmrg	}
198f29dbc25Smrg
199170d5fdcSmrg	pPriv->vidmem = exaOffscreenAlloc(pScrni->pScreen, size, 4,
200170d5fdcSmrg			TRUE, NULL, NULL);
201f29dbc25Smrg
202f29dbc25Smrg    	if (pPriv->vidmem == NULL) {
203f29dbc25Smrg		ErrorF("Could not allocate memory for the video\n");
204f29dbc25Smrg		return FALSE;
205f29dbc25Smrg    	}
206f29dbc25Smrg    }
207f29dbc25Smrg
208f29dbc25Smrg    return TRUE;
209f29dbc25Smrg}
210f29dbc25Smrg
211f29dbc25Smrgstatic Bool
212f29dbc25SmrgLXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf,
213f29dbc25Smrg    short x1, short y1, short x2, short y2,
214f29dbc25Smrg    int width, int height, pointer data)
215f29dbc25Smrg{
216f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
217f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
218f29dbc25Smrg
219f29dbc25Smrg    unsigned int YSrcPitch, YDstPitch;
220f29dbc25Smrg    unsigned int UVSrcPitch, UVDstPitch;
221f29dbc25Smrg    unsigned int YSrcOffset, YDstOffset;
222f29dbc25Smrg    unsigned int USrcOffset, UDstOffset;
223f29dbc25Smrg    unsigned int VSrcOffset, VDstOffset;
224f29dbc25Smrg
225f29dbc25Smrg    unsigned int size, lines, top, left, pixels;
226f29dbc25Smrg
227f29dbc25Smrg    YSrcPitch = (width + 3) & ~3;
228f29dbc25Smrg    YDstPitch = (width + 31) & ~31;
229f29dbc25Smrg
230f29dbc25Smrg    UVSrcPitch = ((width >> 1) + 3) & ~3;
231f29dbc25Smrg    UVDstPitch = ((width >> 1) + 15) & ~15;
232f29dbc25Smrg
233f29dbc25Smrg    USrcOffset = YSrcPitch * height;
234f29dbc25Smrg    VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
235f29dbc25Smrg
236f29dbc25Smrg    UDstOffset = YDstPitch * height;
237f29dbc25Smrg    VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
238f29dbc25Smrg
239f29dbc25Smrg    size = YDstPitch * height;
240f29dbc25Smrg    size += UVDstPitch * height;
241f29dbc25Smrg
242170d5fdcSmrg    if (LXAllocateVidMem(pScrni, pPriv, size) == FALSE) {
243170d5fdcSmrg	ErrorF("Error allocating an offscreen Planar region.\n");
244f29dbc25Smrg	return FALSE;
245170d5fdcSmrg    }
246f29dbc25Smrg
247f29dbc25Smrg    /* The top of the source region we want to copy */
248f29dbc25Smrg    top = y1 & ~1;
249f29dbc25Smrg
250f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
251f29dbc25Smrg    left = x1 & ~1;
252f29dbc25Smrg
253f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
254f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
255f29dbc25Smrg
256f29dbc25Smrg    /* Calculate the source offset */
257f29dbc25Smrg    YSrcOffset = (top * YSrcPitch) + left;
258f29dbc25Smrg    USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
259f29dbc25Smrg    VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
260f29dbc25Smrg
261f29dbc25Smrg    /* Calculate the destination offset */
262f29dbc25Smrg    YDstOffset = (top * YDstPitch) + left;
263f29dbc25Smrg    UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
264f29dbc25Smrg    VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
265f29dbc25Smrg
266f29dbc25Smrg    lines = ((y2 + 1) & ~1) - top;
267f29dbc25Smrg
268f29dbc25Smrg    /* Copy Y */
269f29dbc25Smrg
270f29dbc25Smrg    LXCopyFromSys(pGeode, buf + YSrcOffset,
271f29dbc25Smrg	pPriv->vidmem->offset + YDstOffset, YDstPitch, YSrcPitch, lines,
272f29dbc25Smrg	pixels);
273f29dbc25Smrg
274f29dbc25Smrg    /* Copy U + V at the same time */
275f29dbc25Smrg
276f29dbc25Smrg    LXCopyFromSys(pGeode, buf + USrcOffset,
277f29dbc25Smrg	pPriv->vidmem->offset + UDstOffset, UVDstPitch, UVSrcPitch, lines,
278f29dbc25Smrg	pixels >> 1);
279f29dbc25Smrg
280f29dbc25Smrg    videoScratch.dstOffset = pPriv->vidmem->offset + YDstOffset;
281f29dbc25Smrg    videoScratch.dstPitch = YDstPitch;
282f29dbc25Smrg    videoScratch.UVPitch = UVDstPitch;
283f29dbc25Smrg    videoScratch.UDstOffset = pPriv->vidmem->offset + UDstOffset;
284f29dbc25Smrg    videoScratch.VDstOffset = pPriv->vidmem->offset + VDstOffset;
285f29dbc25Smrg
286f29dbc25Smrg    return TRUE;
287f29dbc25Smrg}
288f29dbc25Smrg
289f29dbc25Smrgstatic Bool
290f29dbc25SmrgLXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf,
291f29dbc25Smrg    short x1, short y1, short x2, short y2,
292f29dbc25Smrg    int width, int height, pointer data)
293f29dbc25Smrg{
294f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
295f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
296f29dbc25Smrg    unsigned int dstPitch, srcPitch;
297f29dbc25Smrg    unsigned int srcOffset, dstOffset;
298f29dbc25Smrg    unsigned int lines, top, left, pixels;
299f29dbc25Smrg
300f29dbc25Smrg    dstPitch = ((width << 1) + 3) & ~3;
301f29dbc25Smrg    srcPitch = (width << 1);
302f29dbc25Smrg
303f29dbc25Smrg    lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
304f29dbc25Smrg
3057aef237fSmrg    if (LXAllocateVidMem(pScrni, pPriv, dstPitch * height) == FALSE) {
306170d5fdcSmrg	ErrorF("Error allocating an offscreen Packed region.\n");
307f29dbc25Smrg	return FALSE;
308170d5fdcSmrg    }
309f29dbc25Smrg
310f29dbc25Smrg    /* The top of the source region we want to copy */
311f29dbc25Smrg    top = y1;
312f29dbc25Smrg
313f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
314f29dbc25Smrg    left = x1 & ~1;
315f29dbc25Smrg
316f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
317f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
318f29dbc25Smrg
319f29dbc25Smrg    /* Adjust the incoming buffer */
320f29dbc25Smrg    srcOffset = (top * srcPitch) + left;
321f29dbc25Smrg
322f29dbc25Smrg    /* Calculate the destination offset */
323f29dbc25Smrg    dstOffset = pPriv->vidmem->offset + (top * dstPitch) + left;
324f29dbc25Smrg
325f29dbc25Smrg    /* Make the copy happen */
326f29dbc25Smrg
327f29dbc25Smrg    if (id == FOURCC_Y800) {
328f29dbc25Smrg
329f29dbc25Smrg	/* Use the shared (unaccelerated) greyscale copy - you could probably
330f29dbc25Smrg	 * accelerate it using a 2 pass blit and patterns, but it doesn't really
331f29dbc25Smrg	 * seem worth it
332f29dbc25Smrg	 */
333f29dbc25Smrg
334f29dbc25Smrg	GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset,
335f29dbc25Smrg	    srcPitch, dstPitch, height, pixels >> 1);
336f29dbc25Smrg    } else
3377aef237fSmrg	/* FIXME: should lines be used here instead of height? */
338f29dbc25Smrg	LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch,
339f29dbc25Smrg	    height, pixels);
340f29dbc25Smrg
341f29dbc25Smrg    videoScratch.dstOffset = dstOffset;
342f29dbc25Smrg    videoScratch.dstPitch = dstPitch;
343f29dbc25Smrg
344f29dbc25Smrg    return TRUE;
345f29dbc25Smrg}
346f29dbc25Smrg
347f29dbc25Smrgstatic void
348f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
349f29dbc25Smrg    BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH)
350f29dbc25Smrg{
351f29dbc25Smrg    long ystart, xend, yend;
352f29dbc25Smrg    unsigned long lines = 0;
353f29dbc25Smrg    unsigned long yExtra, uvExtra = 0;
354f29dbc25Smrg    DF_VIDEO_POSITION vidPos;
355f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vSrcParams;
356f29dbc25Smrg    int err;
357f29dbc25Smrg
358f29dbc25Smrg    memset(&vSrcParams, 0, sizeof(vSrcParams));
359f29dbc25Smrg
360f29dbc25Smrg    gp_wait_until_idle();
361f29dbc25Smrg
362f29dbc25Smrg    switch (id) {
363f29dbc25Smrg    case FOURCC_UYVY:
364f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_UYVY;
365f29dbc25Smrg	break;
366f29dbc25Smrg
367f29dbc25Smrg    case FOURCC_Y800:
368f29dbc25Smrg    case FOURCC_YV12:
369f29dbc25Smrg    case FOURCC_I420:
370f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3;
371f29dbc25Smrg	break;
372f29dbc25Smrg    case FOURCC_YUY2:
373f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_YUYV;
374f29dbc25Smrg	break;
375f29dbc25Smrg    case FOURCC_Y2YU:
376f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_Y2YU;
377f29dbc25Smrg	break;
378f29dbc25Smrg    case FOURCC_YVYU:
379f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_YVYU;
380f29dbc25Smrg	break;
381f29dbc25Smrg    case FOURCC_RGB565:
382f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_RGB;
383f29dbc25Smrg	break;
384f29dbc25Smrg    }
385f29dbc25Smrg
386f29dbc25Smrg    vSrcParams.width = width;
387f29dbc25Smrg    vSrcParams.height = height;
388f29dbc25Smrg    vSrcParams.y_pitch = videoScratch.dstPitch;
389f29dbc25Smrg    vSrcParams.uv_pitch = videoScratch.UVPitch;
390f29dbc25Smrg
391f29dbc25Smrg    /* Set up scaling */
392f29dbc25Smrg    df_set_video_filter_coefficients(NULL, 1);
393f29dbc25Smrg
394f29dbc25Smrg    err = df_set_video_scale(width, height, drawW, drawH,
395f29dbc25Smrg	DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY);
396f29dbc25Smrg    if (err != CIM_STATUS_OK) {
397f29dbc25Smrg	/* Note the problem, but do nothing for now. */
398f29dbc25Smrg	ErrorF("Video scale factor too large: %dx%d -> %dx%d\n",
399f29dbc25Smrg	    width, height, drawW, drawH);
400f29dbc25Smrg    }
401f29dbc25Smrg
402f29dbc25Smrg    /* Figure out clipping */
403f29dbc25Smrg
404f29dbc25Smrg    xend = dstBox->x2;
405f29dbc25Smrg    yend = dstBox->y2;
406f29dbc25Smrg
407f29dbc25Smrg    if (dstBox->y1 < 0) {
408f29dbc25Smrg	if (srcH < drawH)
409f29dbc25Smrg	    lines = ((-dstBox->y1) * srcH) / drawH;
410f29dbc25Smrg	else
411f29dbc25Smrg	    lines = (-dstBox->y1);
412f29dbc25Smrg
413f29dbc25Smrg	ystart = 0;
414f29dbc25Smrg	drawH += dstBox->y1;
415f29dbc25Smrg    } else {
416f29dbc25Smrg	ystart = dstBox->y1;
417f29dbc25Smrg	lines = 0;
418f29dbc25Smrg    }
419f29dbc25Smrg
420f29dbc25Smrg    yExtra = lines * videoScratch.dstPitch;
421f29dbc25Smrg    uvExtra = (lines >> 1) * videoScratch.UVPitch;
422f29dbc25Smrg
423f29dbc25Smrg    memset(&vidPos, 0, sizeof(vidPos));
424f29dbc25Smrg
425f29dbc25Smrg    vidPos.x = dstBox->x1;
426f29dbc25Smrg    vidPos.y = ystart;
427f29dbc25Smrg    vidPos.width = xend - dstBox->x1;
428f29dbc25Smrg    vidPos.height = yend - ystart;
429f29dbc25Smrg
430f29dbc25Smrg    df_set_video_position(&vidPos);
431f29dbc25Smrg
432f29dbc25Smrg    vSrcParams.y_offset = videoScratch.dstOffset + yExtra;
433f29dbc25Smrg
434f29dbc25Smrg    switch (id) {
435f29dbc25Smrg    case FOURCC_Y800:
436f29dbc25Smrg    case FOURCC_I420:
437f29dbc25Smrg	vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra;
438f29dbc25Smrg	vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra;
439f29dbc25Smrg	break;
440f29dbc25Smrg    case FOURCC_YV12:
441f29dbc25Smrg	vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra;
442f29dbc25Smrg	vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra;
443f29dbc25Smrg	break;
444f29dbc25Smrg
445f29dbc25Smrg    default:
446f29dbc25Smrg	vSrcParams.u_offset = vSrcParams.v_offset = 0;
447f29dbc25Smrg	break;
448f29dbc25Smrg    }
449f29dbc25Smrg
450f29dbc25Smrg    vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING;
451f29dbc25Smrg    df_configure_video_source(&vSrcParams, &vSrcParams);
452f29dbc25Smrg
453f29dbc25Smrg    /* Turn on the video palette */
454f29dbc25Smrg    df_set_video_palette(NULL);
455f29dbc25Smrg    df_set_video_enable(1, 0);
456f29dbc25Smrg}
457f29dbc25Smrg
458f29dbc25Smrgstatic int
459f29dbc25SmrgLXPutImage(ScrnInfoPtr pScrni,
460f29dbc25Smrg    short srcX, short srcY, short drawX, short drawY,
461f29dbc25Smrg    short srcW, short srcH, short drawW, short drawH,
462f29dbc25Smrg    int id, unsigned char *buf,
463f29dbc25Smrg    short width, short height, Bool sync, RegionPtr clipBoxes,
464f29dbc25Smrg    pointer data, DrawablePtr pDraw)
465f29dbc25Smrg{
466f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
467f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
468f29dbc25Smrg    INT32 x1, x2, y1, y2;
469f29dbc25Smrg    BoxRec dstBox;
470f29dbc25Smrg    Bool ret;
471f29dbc25Smrg
472f29dbc25Smrg    if (pGeode->rotation != RR_Rotate_0)
473f29dbc25Smrg	return Success;
474f29dbc25Smrg
475f29dbc25Smrg    if (srcW <= 0 || srcH <= 0) {
476f29dbc25Smrg	return Success;
477f29dbc25Smrg    }
478f29dbc25Smrg
479f29dbc25Smrg    if (drawW <= 0 || drawH <= 0) {
480f29dbc25Smrg	return Success;
481f29dbc25Smrg    }
482f29dbc25Smrg
483f29dbc25Smrg    if (drawW > 16384)
484f29dbc25Smrg	drawW = 16384;
485f29dbc25Smrg
486f29dbc25Smrg    memset(&videoScratch, 0, sizeof(videoScratch));
487f29dbc25Smrg
488f29dbc25Smrg    x1 = srcX;
489f29dbc25Smrg    x2 = srcX + srcW;
490f29dbc25Smrg    y1 = srcY;
491f29dbc25Smrg    y2 = srcY + srcH;
492f29dbc25Smrg
493f29dbc25Smrg    dstBox.x1 = drawX;
494f29dbc25Smrg    dstBox.x2 = drawX + drawW;
495f29dbc25Smrg    dstBox.y1 = drawY;
496f29dbc25Smrg    dstBox.y2 = drawY + drawH;
497f29dbc25Smrg
498f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
499f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
500f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
501f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
502f29dbc25Smrg
503f29dbc25Smrg    if (id == FOURCC_YV12 || id == FOURCC_I420)
504f29dbc25Smrg	ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width,
505f29dbc25Smrg			height, data);
506f29dbc25Smrg    else
507f29dbc25Smrg	ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width,
508f29dbc25Smrg			height, data);
509f29dbc25Smrg
510f29dbc25Smrg    if (ret == FALSE)
511f29dbc25Smrg	return BadAlloc;
512f29dbc25Smrg
513f29dbc25Smrg    if (!RegionsEqual(&pPriv->clip, clipBoxes) ||
514f29dbc25Smrg	(drawW != pPriv->pwidth || drawH != pPriv->pheight)) {
515f29dbc25Smrg	REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
516f29dbc25Smrg
517f29dbc25Smrg	if (pPriv->colorKeyMode == 0) {
518f29dbc25Smrg	    xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
519f29dbc25Smrg	}
520f29dbc25Smrg
521f29dbc25Smrg	LXDisplayVideo(pScrni, id, width, height, &dstBox,
522f29dbc25Smrg	    srcW, srcH, drawW, drawH);
523f29dbc25Smrg	pPriv->pwidth = drawW;
524f29dbc25Smrg	pPriv->pheight = drawH;
525f29dbc25Smrg    }
526f29dbc25Smrg
527f29dbc25Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
528f29dbc25Smrg
529f29dbc25Smrg    return Success;
530f29dbc25Smrg}
531f29dbc25Smrg
532f29dbc25Smrgstatic void
533f29dbc25SmrgLXQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
534f29dbc25Smrg    short vidW, short vidH, short drawW, short drawH,
535f29dbc25Smrg    unsigned int *retW, unsigned int *retH, pointer data)
536f29dbc25Smrg{
537f29dbc25Smrg    *retW = drawW > 16384 ? 16384 : drawW;
538f29dbc25Smrg    *retH = drawH;
539f29dbc25Smrg}
540f29dbc25Smrg
541f29dbc25Smrgstatic Atom xvColorKey, xvColorKeyMode, xvFilter;
542f29dbc25Smrg
543f29dbc25Smrgstatic int
544f29dbc25SmrgLXGetPortAttribute(ScrnInfoPtr pScrni,
545f29dbc25Smrg    Atom attribute, INT32 * value, pointer data)
546f29dbc25Smrg{
547f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
548f29dbc25Smrg
549f29dbc25Smrg    if (attribute == xvColorKey)
550f29dbc25Smrg	*value = pPriv->colorKey;
551f29dbc25Smrg    else if (attribute == xvColorKeyMode)
552f29dbc25Smrg	*value = pPriv->colorKeyMode;
553f29dbc25Smrg    else if (attribute == xvFilter)
554f29dbc25Smrg	*value = pPriv->filter;
555f29dbc25Smrg    else
556f29dbc25Smrg	return BadMatch;
557f29dbc25Smrg
558f29dbc25Smrg    return Success;
559f29dbc25Smrg}
560f29dbc25Smrg
561f29dbc25Smrgstatic int
562f29dbc25SmrgLXSetPortAttribute(ScrnInfoPtr pScrni,
563f29dbc25Smrg    Atom attribute, INT32 value, pointer data)
564f29dbc25Smrg{
565f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
566f29dbc25Smrg
567f29dbc25Smrg    gp_wait_until_idle();
568f29dbc25Smrg
569f29dbc25Smrg    if (attribute == xvColorKey) {
570f29dbc25Smrg	pPriv->colorKey = value;
571f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
572f29dbc25Smrg    } else if (attribute == xvColorKeyMode) {
573f29dbc25Smrg	pPriv->colorKeyMode = value;
574f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
575f29dbc25Smrg    } else if (attribute == xvFilter) {
576f29dbc25Smrg	if ((value < 0) || (value > 1))
577f29dbc25Smrg	    return BadValue;
578f29dbc25Smrg	pPriv->filter = value;
579f29dbc25Smrg    } else
580f29dbc25Smrg	return BadMatch;
581f29dbc25Smrg
582f29dbc25Smrg    return Success;
583f29dbc25Smrg}
584f29dbc25Smrg
585f29dbc25Smrgstatic void
586f29dbc25SmrgLXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
587f29dbc25Smrg{
588f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
589f29dbc25Smrg
590f29dbc25Smrg    if (pPriv->videoStatus == 0)
591f29dbc25Smrg	return;
592f29dbc25Smrg
593f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
594f29dbc25Smrg    gp_wait_until_idle();
595f29dbc25Smrg
596f29dbc25Smrg    if (exit) {
597f29dbc25Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
598f29dbc25Smrg	    unsigned int val;
599f29dbc25Smrg
600f29dbc25Smrg	    df_set_video_enable(0, 0);
601f29dbc25Smrg	    /* Put the LUT back in bypass */
602f29dbc25Smrg	    val = READ_VID32(DF_VID_MISC);
603f29dbc25Smrg	    WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
604f29dbc25Smrg	}
605f29dbc25Smrg
606f29dbc25Smrg	if (pPriv->vidmem) {
607170d5fdcSmrg	    exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
608f29dbc25Smrg	    pPriv->vidmem = NULL;
609f29dbc25Smrg	}
610f29dbc25Smrg
611f29dbc25Smrg	pPriv->videoStatus = 0;
612f29dbc25Smrg
613f29dbc25Smrg	/* Eh? */
614f29dbc25Smrg    } else if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
615f29dbc25Smrg	pPriv->videoStatus |= OFF_TIMER;
616f29dbc25Smrg	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
617f29dbc25Smrg    }
618f29dbc25Smrg}
619f29dbc25Smrg
620f29dbc25Smrgstatic void
621f29dbc25SmrgLXResetVideo(ScrnInfoPtr pScrni)
622f29dbc25Smrg{
623f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
624f29dbc25Smrg
625f29dbc25Smrg    if (!pGeode->NoAccel) {
626f29dbc25Smrg	GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
627f29dbc25Smrg
628f29dbc25Smrg	gp_wait_until_idle();
629f29dbc25Smrg	df_set_video_palette(NULL);
630f29dbc25Smrg
631f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
632f29dbc25Smrg    }
633f29dbc25Smrg}
634f29dbc25Smrg
635f29dbc25Smrgstatic void
636f29dbc25SmrgLXVidBlockHandler(int i, pointer blockData, pointer pTimeout,
637f29dbc25Smrg    pointer pReadmask)
638f29dbc25Smrg{
639f29dbc25Smrg    ScreenPtr pScrn = screenInfo.screens[i];
640f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[i];
641f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
642f29dbc25Smrg    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
643f29dbc25Smrg
644f29dbc25Smrg    pScrn->BlockHandler = pGeode->BlockHandler;
645f29dbc25Smrg    (*pScrn->BlockHandler) (i, blockData, pTimeout, pReadmask);
646f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
647f29dbc25Smrg
648f29dbc25Smrg    if (pPriv->videoStatus & TIMER_MASK) {
649f29dbc25Smrg	Time now = currentTime.milliseconds;
650f29dbc25Smrg
651f29dbc25Smrg	if (pPriv->videoStatus & OFF_TIMER) {
652f29dbc25Smrg	    gp_wait_until_idle();
653f29dbc25Smrg
654f29dbc25Smrg	    if (pPriv->offTime < now) {
655f29dbc25Smrg		unsigned int val;
656f29dbc25Smrg
657f29dbc25Smrg		df_set_video_enable(0, 0);
658f29dbc25Smrg		pPriv->videoStatus = FREE_TIMER;
659f29dbc25Smrg		pPriv->freeTime = now + FREE_DELAY;
660f29dbc25Smrg
661f29dbc25Smrg		/* Turn off the video palette */
662f29dbc25Smrg		val = READ_VID32(DF_VID_MISC);
663f29dbc25Smrg		WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
664f29dbc25Smrg	    }
665f29dbc25Smrg	} else {
666f29dbc25Smrg	    if (pPriv->freeTime < now) {
667f29dbc25Smrg
668f29dbc25Smrg		if (pPriv->vidmem) {
669170d5fdcSmrg		    exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
670f29dbc25Smrg		    pPriv->vidmem = NULL;
671f29dbc25Smrg		}
672f29dbc25Smrg
673f29dbc25Smrg		pPriv->videoStatus = 0;
674f29dbc25Smrg	    }
675f29dbc25Smrg	}
676f29dbc25Smrg    }
677f29dbc25Smrg}
678f29dbc25Smrg
679f29dbc25Smrgstatic XF86VideoAdaptorPtr
680f29dbc25SmrgLXSetupImageVideo(ScreenPtr pScrn)
681f29dbc25Smrg{
682f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
683f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
684f29dbc25Smrg    XF86VideoAdaptorPtr adapt;
685f29dbc25Smrg    GeodePortPrivRec *pPriv;
686f29dbc25Smrg
687170d5fdcSmrg    adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
688f29dbc25Smrg	sizeof(GeodePortPrivRec) + sizeof(DevUnion));
689f29dbc25Smrg
690f29dbc25Smrg    if (adapt == NULL) {
691f29dbc25Smrg	ErrorF("Couldn't create the rec\n");
692f29dbc25Smrg	return NULL;
693f29dbc25Smrg    }
694f29dbc25Smrg
695f29dbc25Smrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
696f29dbc25Smrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
697f29dbc25Smrg
698f29dbc25Smrg    adapt->name = "AMD Geode LX";
699f29dbc25Smrg    adapt->nEncodings = 1;
700f29dbc25Smrg    adapt->pEncodings = DummyEncoding;
701f29dbc25Smrg    adapt->nFormats = ARRAY_SIZE(Formats);
702f29dbc25Smrg    adapt->pFormats = Formats;
703f29dbc25Smrg    adapt->nPorts = 1;
704f29dbc25Smrg    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
705f29dbc25Smrg    pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
706f29dbc25Smrg    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
707f29dbc25Smrg    adapt->pAttributes = Attributes;
708f29dbc25Smrg    adapt->nImages = ARRAY_SIZE(Images);
709f29dbc25Smrg    adapt->nAttributes = ARRAY_SIZE(Attributes);
710f29dbc25Smrg    adapt->pImages = Images;
711f29dbc25Smrg    adapt->PutVideo = NULL;
712f29dbc25Smrg    adapt->PutStill = NULL;
713f29dbc25Smrg    adapt->GetVideo = NULL;
714f29dbc25Smrg    adapt->GetStill = NULL;
715f29dbc25Smrg    adapt->StopVideo = LXStopVideo;
716f29dbc25Smrg    adapt->SetPortAttribute = LXSetPortAttribute;
717f29dbc25Smrg    adapt->GetPortAttribute = LXGetPortAttribute;
718f29dbc25Smrg    adapt->QueryBestSize = LXQueryBestSize;
719f29dbc25Smrg    adapt->PutImage = LXPutImage;
720f29dbc25Smrg
721f29dbc25Smrg    /* Use the common function */
722f29dbc25Smrg    adapt->QueryImageAttributes = GeodeQueryImageAttributes;
723f29dbc25Smrg
724f29dbc25Smrg    pPriv->vidmem = NULL;
725f29dbc25Smrg    pPriv->filter = 0;
726f29dbc25Smrg    pPriv->colorKey = 0;
727f29dbc25Smrg    pPriv->colorKeyMode = 0;
728f29dbc25Smrg    pPriv->videoStatus = 0;
729f29dbc25Smrg    pPriv->pwidth = 0;
730f29dbc25Smrg    pPriv->pheight = 0;
731f29dbc25Smrg
732f29dbc25Smrg    REGION_NULL(pScrn, &pPriv->clip);
733f29dbc25Smrg
734f29dbc25Smrg    pGeode->adaptor = adapt;
735f29dbc25Smrg
736f29dbc25Smrg    pGeode->BlockHandler = pScrn->BlockHandler;
737f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
738f29dbc25Smrg
739f29dbc25Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
740f29dbc25Smrg    xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
741f29dbc25Smrg    xvFilter = MAKE_ATOM("XV_FILTER");
742f29dbc25Smrg
743f29dbc25Smrg    LXResetVideo(pScrni);
744f29dbc25Smrg
745f29dbc25Smrg    return adapt;
746f29dbc25Smrg}
747f29dbc25Smrg
748f29dbc25Smrg/* Offscreen surface allocation */
749f29dbc25Smrg
750f29dbc25Smrgstruct OffscreenPrivRec
751f29dbc25Smrg{
752170d5fdcSmrg    ExaOffscreenArea *vidmem;
753f29dbc25Smrg    Bool isOn;
754f29dbc25Smrg};
755f29dbc25Smrg
756f29dbc25Smrgstatic int
757f29dbc25SmrgLXDisplaySurface(XF86SurfacePtr surface,
758f29dbc25Smrg    short srcX, short srcY, short drawX, short drawY,
759f29dbc25Smrg    short srcW, short srcH, short drawW, short drawH, RegionPtr clipBoxes)
760f29dbc25Smrg{
761f29dbc25Smrg    struct OffscreenPrivRec *pPriv =
762f29dbc25Smrg	(struct OffscreenPrivRec *)surface->devPrivate.ptr;
763f29dbc25Smrg
764f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
765f29dbc25Smrg    GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
766f29dbc25Smrg
767f29dbc25Smrg    BoxRec dstBox;
768f29dbc25Smrg
769f29dbc25Smrg    dstBox.x1 = drawX;
770f29dbc25Smrg    dstBox.x2 = drawX + drawW;
771f29dbc25Smrg    dstBox.y1 = drawY;
772f29dbc25Smrg    dstBox.y2 = drawY + drawH;
773f29dbc25Smrg
774f29dbc25Smrg    if ((drawW <= 0) | (drawH <= 0))
775f29dbc25Smrg	return Success;
776f29dbc25Smrg
777f29dbc25Smrg    /* Is this still valid? */
778f29dbc25Smrg
779f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
780f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
781f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
782f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
783f29dbc25Smrg
784f29dbc25Smrg    xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
785f29dbc25Smrg
786f29dbc25Smrg    videoScratch.dstOffset = surface->offsets[0];
787f29dbc25Smrg    videoScratch.dstPitch = surface->pitches[0];
788f29dbc25Smrg
789f29dbc25Smrg    LXDisplayVideo(pScrni, surface->id, surface->width, surface->height,
790f29dbc25Smrg	&dstBox, srcW, srcH, drawW, drawH);
791f29dbc25Smrg
792f29dbc25Smrg    pPriv->isOn = TRUE;
793f29dbc25Smrg
794f29dbc25Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
795f29dbc25Smrg	REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
796f29dbc25Smrg	UpdateCurrentTime();
797f29dbc25Smrg	portPriv->videoStatus = FREE_TIMER;
798f29dbc25Smrg	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
799f29dbc25Smrg    }
800f29dbc25Smrg
801f29dbc25Smrg    return Success;
802f29dbc25Smrg}
803f29dbc25Smrg
804f29dbc25Smrgstatic int
805f29dbc25SmrgLXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w,
806f29dbc25Smrg    unsigned short h, XF86SurfacePtr surface)
807f29dbc25Smrg{
808f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
809f29dbc25Smrg    int pitch, lines;
810170d5fdcSmrg    ExaOffscreenArea *vidmem;
811f29dbc25Smrg    struct OffscreenPrivRec *pPriv;
812f29dbc25Smrg
813f29dbc25Smrg    if (w > 1024 || h > 1024)
814f29dbc25Smrg	return BadAlloc;
815f29dbc25Smrg
816f29dbc25Smrg    /* The width needs to be word aligned */
817f29dbc25Smrg    w = (w + 1) & ~1;
818f29dbc25Smrg
819f29dbc25Smrg    pitch = ((w << 1) + 15) & ~15;
820f29dbc25Smrg    lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch;
821f29dbc25Smrg
8227aef237fSmrg    /* FIXME: is lines the right parameter to use here,
8237aef237fSmrg     * or should it be height * pitch? */
824170d5fdcSmrg    vidmem = exaOffscreenAlloc(pScrni->pScreen, lines, 4, TRUE,
825170d5fdcSmrg		NULL, NULL);
826f29dbc25Smrg
827f29dbc25Smrg    if (vidmem == NULL) {
828f29dbc25Smrg	ErrorF("Error while allocating an offscreen region.\n");
829f29dbc25Smrg	return BadAlloc;
830f29dbc25Smrg    }
831f29dbc25Smrg
832f29dbc25Smrg    surface->width = w;
833f29dbc25Smrg    surface->height = h;
834f29dbc25Smrg
835170d5fdcSmrg    surface->pitches = malloc(sizeof(int));
836f29dbc25Smrg
837170d5fdcSmrg    surface->offsets = malloc(sizeof(int));
838f29dbc25Smrg
839170d5fdcSmrg    pPriv = malloc(sizeof(struct OffscreenPrivRec));
840f29dbc25Smrg
841f29dbc25Smrg    if (pPriv && surface->pitches && surface->offsets) {
842f29dbc25Smrg
843f29dbc25Smrg	pPriv->vidmem = vidmem;
844f29dbc25Smrg
845f29dbc25Smrg	pPriv->isOn = FALSE;
846f29dbc25Smrg
847f29dbc25Smrg	surface->pScrn = pScrni;
848f29dbc25Smrg	surface->id = id;
849f29dbc25Smrg	surface->pitches[0] = pitch;
850f29dbc25Smrg	surface->offsets[0] = vidmem->offset;
851f29dbc25Smrg	surface->devPrivate.ptr = (pointer) pPriv;
852f29dbc25Smrg
853f29dbc25Smrg	return Success;
854f29dbc25Smrg    }
855f29dbc25Smrg
856f29dbc25Smrg    if (surface->offsets)
857170d5fdcSmrg	free(surface->offsets);
858f29dbc25Smrg
859f29dbc25Smrg    if (surface->pitches)
860170d5fdcSmrg	free(surface->pitches);
861f29dbc25Smrg
862170d5fdcSmrg    if (vidmem) {
863170d5fdcSmrg	exaOffscreenFree(pScrni->pScreen, vidmem);
864170d5fdcSmrg	vidmem = NULL;
865170d5fdcSmrg    }
866f29dbc25Smrg
867f29dbc25Smrg    return BadAlloc;
868f29dbc25Smrg}
869f29dbc25Smrg
870f29dbc25Smrgstatic int
871f29dbc25SmrgLXStopSurface(XF86SurfacePtr surface)
872f29dbc25Smrg{
873f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
874f29dbc25Smrg	surface->devPrivate.ptr;
875f29dbc25Smrg
876f29dbc25Smrg    pPriv->isOn = FALSE;
877f29dbc25Smrg    return Success;
878f29dbc25Smrg}
879f29dbc25Smrg
880f29dbc25Smrgstatic int
881f29dbc25SmrgLXFreeSurface(XF86SurfacePtr surface)
882f29dbc25Smrg{
883f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
884f29dbc25Smrg	surface->devPrivate.ptr;
885f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
886f29dbc25Smrg
887f29dbc25Smrg    if (pPriv->isOn)
888f29dbc25Smrg	LXStopSurface(surface);
889f29dbc25Smrg
890f29dbc25Smrg    if (pPriv->vidmem) {
891170d5fdcSmrg	exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
892f29dbc25Smrg	pPriv->vidmem = NULL;
893f29dbc25Smrg    }
894f29dbc25Smrg
895170d5fdcSmrg    free(surface->pitches);
896170d5fdcSmrg    free(surface->offsets);
897170d5fdcSmrg    free(surface->devPrivate.ptr);
898f29dbc25Smrg
899f29dbc25Smrg    return Success;
900f29dbc25Smrg}
901f29dbc25Smrg
902f29dbc25Smrgstatic int
903f29dbc25SmrgLXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value)
904f29dbc25Smrg{
905f29dbc25Smrg    return LXGetPortAttribute(pScrni, attribute, value,
906f29dbc25Smrg	(pointer) (GET_PORT_PRIVATE(pScrni)));
907f29dbc25Smrg}
908f29dbc25Smrg
909f29dbc25Smrgstatic int
910f29dbc25SmrgLXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
911f29dbc25Smrg{
912f29dbc25Smrg    return LXSetPortAttribute(pScrni, attribute, value,
913f29dbc25Smrg	(pointer) (GET_PORT_PRIVATE(pScrni)));
914f29dbc25Smrg}
915f29dbc25Smrg
916f29dbc25Smrgstatic void
917f29dbc25SmrgLXInitOffscreenImages(ScreenPtr pScrn)
918f29dbc25Smrg{
919f29dbc25Smrg    XF86OffscreenImagePtr offscreenImages;
920f29dbc25Smrg
921f29dbc25Smrg    /* need to free this someplace */
922170d5fdcSmrg    if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
923f29dbc25Smrg	return;
924f29dbc25Smrg
925f29dbc25Smrg    offscreenImages[0].image = &Images[0];
926f29dbc25Smrg    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
927f29dbc25Smrg    offscreenImages[0].alloc_surface = LXAllocateSurface;
928f29dbc25Smrg    offscreenImages[0].free_surface = LXFreeSurface;
929f29dbc25Smrg    offscreenImages[0].display = LXDisplaySurface;
930f29dbc25Smrg    offscreenImages[0].stop = LXStopSurface;
931f29dbc25Smrg    offscreenImages[0].setAttribute = LXSetSurfaceAttribute;
932f29dbc25Smrg    offscreenImages[0].getAttribute = LXGetSurfaceAttribute;
933f29dbc25Smrg    offscreenImages[0].max_width = 1024;
934f29dbc25Smrg    offscreenImages[0].max_height = 1024;
935f29dbc25Smrg    offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes);
936f29dbc25Smrg    offscreenImages[0].attributes = Attributes;
937f29dbc25Smrg
938f29dbc25Smrg    xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
939f29dbc25Smrg}
940f29dbc25Smrg
941f29dbc25Smrgvoid
942f29dbc25SmrgLXInitVideo(ScreenPtr pScrn)
943f29dbc25Smrg{
944f29dbc25Smrg    GeodeRec *pGeode;
945f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
946f29dbc25Smrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
947f29dbc25Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
948f29dbc25Smrg    int num_adaptors;
949f29dbc25Smrg
950f29dbc25Smrg    pGeode = GEODEPTR(pScrni);
951f29dbc25Smrg
952f29dbc25Smrg    if (pGeode->NoAccel) {
953f29dbc25Smrg	ErrorF("Cannot run Xv without accelerations!\n");
954f29dbc25Smrg	return;
955f29dbc25Smrg    }
956f29dbc25Smrg
957f29dbc25Smrg    if (!(newAdaptor = LXSetupImageVideo(pScrn))) {
958f29dbc25Smrg	ErrorF("Error while setting up the adaptor.\n");
959f29dbc25Smrg	return;
960f29dbc25Smrg    }
961f29dbc25Smrg
962f29dbc25Smrg    LXInitOffscreenImages(pScrn);
963f29dbc25Smrg
964f29dbc25Smrg    num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
965f29dbc25Smrg
966f29dbc25Smrg    if (!num_adaptors) {
967f29dbc25Smrg	num_adaptors = 1;
968f29dbc25Smrg	adaptors = &newAdaptor;
969f29dbc25Smrg    } else {
970f29dbc25Smrg	newAdaptors =
971170d5fdcSmrg	    malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
972f29dbc25Smrg
973f29dbc25Smrg	if (newAdaptors) {
974f29dbc25Smrg	    memcpy(newAdaptors, adaptors, num_adaptors *
975f29dbc25Smrg		sizeof(XF86VideoAdaptorPtr));
976f29dbc25Smrg	    newAdaptors[num_adaptors] = newAdaptor;
977f29dbc25Smrg	    adaptors = newAdaptors;
978f29dbc25Smrg	    num_adaptors++;
979f29dbc25Smrg	} else
980f29dbc25Smrg	    ErrorF("Memory error while setting up the adaptor\n");
981f29dbc25Smrg    }
982f29dbc25Smrg
983f29dbc25Smrg    if (num_adaptors)
984f29dbc25Smrg	xf86XVScreenInit(pScrn, adaptors, num_adaptors);
985f29dbc25Smrg
986f29dbc25Smrg    if (newAdaptors)
987170d5fdcSmrg	free(newAdaptors);
988f29dbc25Smrg}
989