lx_video.c revision f29dbc25
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{
102f29dbc25Smrg    GeodeMemPtr 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);
122f29dbc25Smrg    gp_set_bpp(16);
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
191f29dbc25SmrgLXAllocMem(GeodeRec *pGeode, GeodePortPrivRec *pPriv, int size)
192f29dbc25Smrg{
193f29dbc25Smrg    if (!pPriv->vidmem || pPriv->vidmem->size < size) {
194f29dbc25Smrg	if (pPriv->vidmem)
195f29dbc25Smrg		GeodeFreeOffscreen(pGeode, pPriv->vidmem);
196f29dbc25Smrg
197f29dbc25Smrg    	pPriv->vidmem = GeodeAllocOffscreen(pGeode, size, 4);
198f29dbc25Smrg
199f29dbc25Smrg    	if (pPriv->vidmem == NULL) {
200f29dbc25Smrg		ErrorF("Could not allocate memory for the video\n");
201f29dbc25Smrg		return FALSE;
202f29dbc25Smrg    	}
203f29dbc25Smrg    }
204f29dbc25Smrg
205f29dbc25Smrg    return TRUE;
206f29dbc25Smrg}
207f29dbc25Smrg
208f29dbc25Smrgstatic Bool
209f29dbc25SmrgLXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf,
210f29dbc25Smrg    short x1, short y1, short x2, short y2,
211f29dbc25Smrg    int width, int height, pointer data)
212f29dbc25Smrg{
213f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
214f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
215f29dbc25Smrg
216f29dbc25Smrg    unsigned int YSrcPitch, YDstPitch;
217f29dbc25Smrg    unsigned int UVSrcPitch, UVDstPitch;
218f29dbc25Smrg    unsigned int YSrcOffset, YDstOffset;
219f29dbc25Smrg    unsigned int USrcOffset, UDstOffset;
220f29dbc25Smrg    unsigned int VSrcOffset, VDstOffset;
221f29dbc25Smrg
222f29dbc25Smrg    unsigned int size, lines, top, left, pixels;
223f29dbc25Smrg
224f29dbc25Smrg    YSrcPitch = (width + 3) & ~3;
225f29dbc25Smrg    YDstPitch = (width + 31) & ~31;
226f29dbc25Smrg
227f29dbc25Smrg    UVSrcPitch = ((width >> 1) + 3) & ~3;
228f29dbc25Smrg    UVDstPitch = ((width >> 1) + 15) & ~15;
229f29dbc25Smrg
230f29dbc25Smrg    USrcOffset = YSrcPitch * height;
231f29dbc25Smrg    VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
232f29dbc25Smrg
233f29dbc25Smrg    UDstOffset = YDstPitch * height;
234f29dbc25Smrg    VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
235f29dbc25Smrg
236f29dbc25Smrg    size = YDstPitch * height;
237f29dbc25Smrg    size += UVDstPitch * height;
238f29dbc25Smrg
239f29dbc25Smrg    if (LXAllocMem(pGeode, pPriv, size) == FALSE)
240f29dbc25Smrg	return FALSE;
241f29dbc25Smrg
242f29dbc25Smrg    /* The top of the source region we want to copy */
243f29dbc25Smrg    top = y1 & ~1;
244f29dbc25Smrg
245f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
246f29dbc25Smrg    left = x1 & ~1;
247f29dbc25Smrg
248f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
249f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
250f29dbc25Smrg
251f29dbc25Smrg    /* Calculate the source offset */
252f29dbc25Smrg    YSrcOffset = (top * YSrcPitch) + left;
253f29dbc25Smrg    USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
254f29dbc25Smrg    VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
255f29dbc25Smrg
256f29dbc25Smrg    /* Calculate the destination offset */
257f29dbc25Smrg    YDstOffset = (top * YDstPitch) + left;
258f29dbc25Smrg    UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
259f29dbc25Smrg    VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
260f29dbc25Smrg
261f29dbc25Smrg    lines = ((y2 + 1) & ~1) - top;
262f29dbc25Smrg
263f29dbc25Smrg    /* Copy Y */
264f29dbc25Smrg
265f29dbc25Smrg    LXCopyFromSys(pGeode, buf + YSrcOffset,
266f29dbc25Smrg	pPriv->vidmem->offset + YDstOffset, YDstPitch, YSrcPitch, lines,
267f29dbc25Smrg	pixels);
268f29dbc25Smrg
269f29dbc25Smrg    /* Copy U + V at the same time */
270f29dbc25Smrg
271f29dbc25Smrg    LXCopyFromSys(pGeode, buf + USrcOffset,
272f29dbc25Smrg	pPriv->vidmem->offset + UDstOffset, UVDstPitch, UVSrcPitch, lines,
273f29dbc25Smrg	pixels >> 1);
274f29dbc25Smrg
275f29dbc25Smrg    videoScratch.dstOffset = pPriv->vidmem->offset + YDstOffset;
276f29dbc25Smrg    videoScratch.dstPitch = YDstPitch;
277f29dbc25Smrg    videoScratch.UVPitch = UVDstPitch;
278f29dbc25Smrg    videoScratch.UDstOffset = pPriv->vidmem->offset + UDstOffset;
279f29dbc25Smrg    videoScratch.VDstOffset = pPriv->vidmem->offset + VDstOffset;
280f29dbc25Smrg
281f29dbc25Smrg    return TRUE;
282f29dbc25Smrg}
283f29dbc25Smrg
284f29dbc25Smrgstatic Bool
285f29dbc25SmrgLXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf,
286f29dbc25Smrg    short x1, short y1, short x2, short y2,
287f29dbc25Smrg    int width, int height, pointer data)
288f29dbc25Smrg{
289f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
290f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
291f29dbc25Smrg    unsigned int dstPitch, srcPitch;
292f29dbc25Smrg    unsigned int srcOffset, dstOffset;
293f29dbc25Smrg    unsigned int lines, top, left, pixels;
294f29dbc25Smrg
295f29dbc25Smrg    dstPitch = ((width << 1) + 3) & ~3;
296f29dbc25Smrg    srcPitch = (width << 1);
297f29dbc25Smrg
298f29dbc25Smrg    lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
299f29dbc25Smrg
300f29dbc25Smrg    if (LXAllocMem(pGeode, pPriv, lines) == FALSE)
301f29dbc25Smrg	return FALSE;
302f29dbc25Smrg
303f29dbc25Smrg    /* The top of the source region we want to copy */
304f29dbc25Smrg    top = y1;
305f29dbc25Smrg
306f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
307f29dbc25Smrg    left = x1 & ~1;
308f29dbc25Smrg
309f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
310f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
311f29dbc25Smrg
312f29dbc25Smrg    /* Adjust the incoming buffer */
313f29dbc25Smrg    srcOffset = (top * srcPitch) + left;
314f29dbc25Smrg
315f29dbc25Smrg    /* Calculate the destination offset */
316f29dbc25Smrg    dstOffset = pPriv->vidmem->offset + (top * dstPitch) + left;
317f29dbc25Smrg
318f29dbc25Smrg    /* Make the copy happen */
319f29dbc25Smrg
320f29dbc25Smrg    if (id == FOURCC_Y800) {
321f29dbc25Smrg
322f29dbc25Smrg	/* Use the shared (unaccelerated) greyscale copy - you could probably
323f29dbc25Smrg	 * accelerate it using a 2 pass blit and patterns, but it doesn't really
324f29dbc25Smrg	 * seem worth it
325f29dbc25Smrg	 */
326f29dbc25Smrg
327f29dbc25Smrg	GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset,
328f29dbc25Smrg	    srcPitch, dstPitch, height, pixels >> 1);
329f29dbc25Smrg    } else
330f29dbc25Smrg	LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch,
331f29dbc25Smrg	    height, pixels);
332f29dbc25Smrg
333f29dbc25Smrg    videoScratch.dstOffset = dstOffset;
334f29dbc25Smrg    videoScratch.dstPitch = dstPitch;
335f29dbc25Smrg
336f29dbc25Smrg    return TRUE;
337f29dbc25Smrg}
338f29dbc25Smrg
339f29dbc25Smrgstatic void
340f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
341f29dbc25Smrg    BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH)
342f29dbc25Smrg{
343f29dbc25Smrg    long ystart, xend, yend;
344f29dbc25Smrg    unsigned long lines = 0;
345f29dbc25Smrg    unsigned long yExtra, uvExtra = 0;
346f29dbc25Smrg    DF_VIDEO_POSITION vidPos;
347f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vSrcParams;
348f29dbc25Smrg    int err;
349f29dbc25Smrg
350f29dbc25Smrg    memset(&vSrcParams, 0, sizeof(vSrcParams));
351f29dbc25Smrg
352f29dbc25Smrg    gp_wait_until_idle();
353f29dbc25Smrg
354f29dbc25Smrg    switch (id) {
355f29dbc25Smrg    case FOURCC_UYVY:
356f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_UYVY;
357f29dbc25Smrg	break;
358f29dbc25Smrg
359f29dbc25Smrg    case FOURCC_Y800:
360f29dbc25Smrg    case FOURCC_YV12:
361f29dbc25Smrg    case FOURCC_I420:
362f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3;
363f29dbc25Smrg	break;
364f29dbc25Smrg    case FOURCC_YUY2:
365f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_YUYV;
366f29dbc25Smrg	break;
367f29dbc25Smrg    case FOURCC_Y2YU:
368f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_Y2YU;
369f29dbc25Smrg	break;
370f29dbc25Smrg    case FOURCC_YVYU:
371f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_YVYU;
372f29dbc25Smrg	break;
373f29dbc25Smrg    case FOURCC_RGB565:
374f29dbc25Smrg	vSrcParams.video_format = DF_VIDFMT_RGB;
375f29dbc25Smrg	break;
376f29dbc25Smrg    }
377f29dbc25Smrg
378f29dbc25Smrg    vSrcParams.width = width;
379f29dbc25Smrg    vSrcParams.height = height;
380f29dbc25Smrg    vSrcParams.y_pitch = videoScratch.dstPitch;
381f29dbc25Smrg    vSrcParams.uv_pitch = videoScratch.UVPitch;
382f29dbc25Smrg
383f29dbc25Smrg    /* Set up scaling */
384f29dbc25Smrg    df_set_video_filter_coefficients(NULL, 1);
385f29dbc25Smrg
386f29dbc25Smrg    err = df_set_video_scale(width, height, drawW, drawH,
387f29dbc25Smrg	DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY);
388f29dbc25Smrg    if (err != CIM_STATUS_OK) {
389f29dbc25Smrg	/* Note the problem, but do nothing for now. */
390f29dbc25Smrg	ErrorF("Video scale factor too large: %dx%d -> %dx%d\n",
391f29dbc25Smrg	    width, height, drawW, drawH);
392f29dbc25Smrg    }
393f29dbc25Smrg
394f29dbc25Smrg    /* Figure out clipping */
395f29dbc25Smrg
396f29dbc25Smrg    xend = dstBox->x2;
397f29dbc25Smrg    yend = dstBox->y2;
398f29dbc25Smrg
399f29dbc25Smrg    if (dstBox->y1 < 0) {
400f29dbc25Smrg	if (srcH < drawH)
401f29dbc25Smrg	    lines = ((-dstBox->y1) * srcH) / drawH;
402f29dbc25Smrg	else
403f29dbc25Smrg	    lines = (-dstBox->y1);
404f29dbc25Smrg
405f29dbc25Smrg	ystart = 0;
406f29dbc25Smrg	drawH += dstBox->y1;
407f29dbc25Smrg    } else {
408f29dbc25Smrg	ystart = dstBox->y1;
409f29dbc25Smrg	lines = 0;
410f29dbc25Smrg    }
411f29dbc25Smrg
412f29dbc25Smrg    yExtra = lines * videoScratch.dstPitch;
413f29dbc25Smrg    uvExtra = (lines >> 1) * videoScratch.UVPitch;
414f29dbc25Smrg
415f29dbc25Smrg    memset(&vidPos, 0, sizeof(vidPos));
416f29dbc25Smrg
417f29dbc25Smrg    vidPos.x = dstBox->x1;
418f29dbc25Smrg    vidPos.y = ystart;
419f29dbc25Smrg    vidPos.width = xend - dstBox->x1;
420f29dbc25Smrg    vidPos.height = yend - ystart;
421f29dbc25Smrg
422f29dbc25Smrg    df_set_video_position(&vidPos);
423f29dbc25Smrg
424f29dbc25Smrg    vSrcParams.y_offset = videoScratch.dstOffset + yExtra;
425f29dbc25Smrg
426f29dbc25Smrg    switch (id) {
427f29dbc25Smrg    case FOURCC_Y800:
428f29dbc25Smrg    case FOURCC_I420:
429f29dbc25Smrg	vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra;
430f29dbc25Smrg	vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra;
431f29dbc25Smrg	break;
432f29dbc25Smrg    case FOURCC_YV12:
433f29dbc25Smrg	vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra;
434f29dbc25Smrg	vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra;
435f29dbc25Smrg	break;
436f29dbc25Smrg
437f29dbc25Smrg    default:
438f29dbc25Smrg	vSrcParams.u_offset = vSrcParams.v_offset = 0;
439f29dbc25Smrg	break;
440f29dbc25Smrg    }
441f29dbc25Smrg
442f29dbc25Smrg    vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING;
443f29dbc25Smrg    df_configure_video_source(&vSrcParams, &vSrcParams);
444f29dbc25Smrg
445f29dbc25Smrg    /* Turn on the video palette */
446f29dbc25Smrg    df_set_video_palette(NULL);
447f29dbc25Smrg    df_set_video_enable(1, 0);
448f29dbc25Smrg}
449f29dbc25Smrg
450f29dbc25Smrgstatic int
451f29dbc25SmrgLXPutImage(ScrnInfoPtr pScrni,
452f29dbc25Smrg    short srcX, short srcY, short drawX, short drawY,
453f29dbc25Smrg    short srcW, short srcH, short drawW, short drawH,
454f29dbc25Smrg    int id, unsigned char *buf,
455f29dbc25Smrg    short width, short height, Bool sync, RegionPtr clipBoxes,
456f29dbc25Smrg    pointer data, DrawablePtr pDraw)
457f29dbc25Smrg{
458f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
459f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
460f29dbc25Smrg    INT32 x1, x2, y1, y2;
461f29dbc25Smrg    BoxRec dstBox;
462f29dbc25Smrg    Bool ret;
463f29dbc25Smrg
464f29dbc25Smrg    if (pGeode->rotation != RR_Rotate_0)
465f29dbc25Smrg	return Success;
466f29dbc25Smrg
467f29dbc25Smrg    if (srcW <= 0 || srcH <= 0) {
468f29dbc25Smrg	return Success;
469f29dbc25Smrg    }
470f29dbc25Smrg
471f29dbc25Smrg    if (drawW <= 0 || drawH <= 0) {
472f29dbc25Smrg	return Success;
473f29dbc25Smrg    }
474f29dbc25Smrg
475f29dbc25Smrg    if (drawW > 16384)
476f29dbc25Smrg	drawW = 16384;
477f29dbc25Smrg
478f29dbc25Smrg    memset(&videoScratch, 0, sizeof(videoScratch));
479f29dbc25Smrg
480f29dbc25Smrg    x1 = srcX;
481f29dbc25Smrg    x2 = srcX + srcW;
482f29dbc25Smrg    y1 = srcY;
483f29dbc25Smrg    y2 = srcY + srcH;
484f29dbc25Smrg
485f29dbc25Smrg    dstBox.x1 = drawX;
486f29dbc25Smrg    dstBox.x2 = drawX + drawW;
487f29dbc25Smrg    dstBox.y1 = drawY;
488f29dbc25Smrg    dstBox.y2 = drawY + drawH;
489f29dbc25Smrg
490f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
491f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
492f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
493f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
494f29dbc25Smrg
495f29dbc25Smrg    if (id == FOURCC_YV12 || id == FOURCC_I420)
496f29dbc25Smrg	ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width,
497f29dbc25Smrg			height, data);
498f29dbc25Smrg    else
499f29dbc25Smrg	ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width,
500f29dbc25Smrg			height, data);
501f29dbc25Smrg
502f29dbc25Smrg    if (ret == FALSE)
503f29dbc25Smrg	return BadAlloc;
504f29dbc25Smrg
505f29dbc25Smrg    if (!RegionsEqual(&pPriv->clip, clipBoxes) ||
506f29dbc25Smrg	(drawW != pPriv->pwidth || drawH != pPriv->pheight)) {
507f29dbc25Smrg	REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
508f29dbc25Smrg
509f29dbc25Smrg	if (pPriv->colorKeyMode == 0) {
510f29dbc25Smrg	    xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
511f29dbc25Smrg	}
512f29dbc25Smrg
513f29dbc25Smrg	LXDisplayVideo(pScrni, id, width, height, &dstBox,
514f29dbc25Smrg	    srcW, srcH, drawW, drawH);
515f29dbc25Smrg	pPriv->pwidth = drawW;
516f29dbc25Smrg	pPriv->pheight = drawH;
517f29dbc25Smrg    }
518f29dbc25Smrg
519f29dbc25Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
520f29dbc25Smrg
521f29dbc25Smrg    return Success;
522f29dbc25Smrg}
523f29dbc25Smrg
524f29dbc25Smrgstatic void
525f29dbc25SmrgLXQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
526f29dbc25Smrg    short vidW, short vidH, short drawW, short drawH,
527f29dbc25Smrg    unsigned int *retW, unsigned int *retH, pointer data)
528f29dbc25Smrg{
529f29dbc25Smrg    *retW = drawW > 16384 ? 16384 : drawW;
530f29dbc25Smrg    *retH = drawH;
531f29dbc25Smrg}
532f29dbc25Smrg
533f29dbc25Smrgstatic Atom xvColorKey, xvColorKeyMode, xvFilter;
534f29dbc25Smrg
535f29dbc25Smrgstatic int
536f29dbc25SmrgLXGetPortAttribute(ScrnInfoPtr pScrni,
537f29dbc25Smrg    Atom attribute, INT32 * value, pointer data)
538f29dbc25Smrg{
539f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
540f29dbc25Smrg
541f29dbc25Smrg    if (attribute == xvColorKey)
542f29dbc25Smrg	*value = pPriv->colorKey;
543f29dbc25Smrg    else if (attribute == xvColorKeyMode)
544f29dbc25Smrg	*value = pPriv->colorKeyMode;
545f29dbc25Smrg    else if (attribute == xvFilter)
546f29dbc25Smrg	*value = pPriv->filter;
547f29dbc25Smrg    else
548f29dbc25Smrg	return BadMatch;
549f29dbc25Smrg
550f29dbc25Smrg    return Success;
551f29dbc25Smrg}
552f29dbc25Smrg
553f29dbc25Smrgstatic int
554f29dbc25SmrgLXSetPortAttribute(ScrnInfoPtr pScrni,
555f29dbc25Smrg    Atom attribute, INT32 value, pointer data)
556f29dbc25Smrg{
557f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
558f29dbc25Smrg
559f29dbc25Smrg    gp_wait_until_idle();
560f29dbc25Smrg
561f29dbc25Smrg    if (attribute == xvColorKey) {
562f29dbc25Smrg	pPriv->colorKey = value;
563f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
564f29dbc25Smrg    } else if (attribute == xvColorKeyMode) {
565f29dbc25Smrg	pPriv->colorKeyMode = value;
566f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
567f29dbc25Smrg    } else if (attribute == xvFilter) {
568f29dbc25Smrg	if ((value < 0) || (value > 1))
569f29dbc25Smrg	    return BadValue;
570f29dbc25Smrg	pPriv->filter = value;
571f29dbc25Smrg    } else
572f29dbc25Smrg	return BadMatch;
573f29dbc25Smrg
574f29dbc25Smrg    return Success;
575f29dbc25Smrg}
576f29dbc25Smrg
577f29dbc25Smrgstatic void
578f29dbc25SmrgLXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
579f29dbc25Smrg{
580f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
581f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
582f29dbc25Smrg
583f29dbc25Smrg    if (pPriv->videoStatus == 0)
584f29dbc25Smrg	return;
585f29dbc25Smrg
586f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
587f29dbc25Smrg    gp_wait_until_idle();
588f29dbc25Smrg
589f29dbc25Smrg    if (exit) {
590f29dbc25Smrg	if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
591f29dbc25Smrg	    unsigned int val;
592f29dbc25Smrg
593f29dbc25Smrg	    df_set_video_enable(0, 0);
594f29dbc25Smrg	    /* Put the LUT back in bypass */
595f29dbc25Smrg	    val = READ_VID32(DF_VID_MISC);
596f29dbc25Smrg	    WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
597f29dbc25Smrg	}
598f29dbc25Smrg
599f29dbc25Smrg	if (pPriv->vidmem) {
600f29dbc25Smrg	    GeodeFreeOffscreen(pGeode, pPriv->vidmem);
601f29dbc25Smrg	    pPriv->vidmem = NULL;
602f29dbc25Smrg	}
603f29dbc25Smrg
604f29dbc25Smrg	pPriv->videoStatus = 0;
605f29dbc25Smrg
606f29dbc25Smrg	/* Eh? */
607f29dbc25Smrg    } else if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
608f29dbc25Smrg	pPriv->videoStatus |= OFF_TIMER;
609f29dbc25Smrg	pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
610f29dbc25Smrg    }
611f29dbc25Smrg}
612f29dbc25Smrg
613f29dbc25Smrgstatic void
614f29dbc25SmrgLXResetVideo(ScrnInfoPtr pScrni)
615f29dbc25Smrg{
616f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
617f29dbc25Smrg
618f29dbc25Smrg    if (!pGeode->NoAccel) {
619f29dbc25Smrg	GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
620f29dbc25Smrg
621f29dbc25Smrg	gp_wait_until_idle();
622f29dbc25Smrg	df_set_video_palette(NULL);
623f29dbc25Smrg
624f29dbc25Smrg	LXSetColorkey(pScrni, pPriv);
625f29dbc25Smrg    }
626f29dbc25Smrg}
627f29dbc25Smrg
628f29dbc25Smrgstatic void
629f29dbc25SmrgLXVidBlockHandler(int i, pointer blockData, pointer pTimeout,
630f29dbc25Smrg    pointer pReadmask)
631f29dbc25Smrg{
632f29dbc25Smrg    ScreenPtr pScrn = screenInfo.screens[i];
633f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[i];
634f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
635f29dbc25Smrg    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
636f29dbc25Smrg
637f29dbc25Smrg    pScrn->BlockHandler = pGeode->BlockHandler;
638f29dbc25Smrg    (*pScrn->BlockHandler) (i, blockData, pTimeout, pReadmask);
639f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
640f29dbc25Smrg
641f29dbc25Smrg    if (pPriv->videoStatus & TIMER_MASK) {
642f29dbc25Smrg	Time now = currentTime.milliseconds;
643f29dbc25Smrg
644f29dbc25Smrg	if (pPriv->videoStatus & OFF_TIMER) {
645f29dbc25Smrg	    gp_wait_until_idle();
646f29dbc25Smrg
647f29dbc25Smrg	    if (pPriv->offTime < now) {
648f29dbc25Smrg		unsigned int val;
649f29dbc25Smrg
650f29dbc25Smrg		df_set_video_enable(0, 0);
651f29dbc25Smrg		pPriv->videoStatus = FREE_TIMER;
652f29dbc25Smrg		pPriv->freeTime = now + FREE_DELAY;
653f29dbc25Smrg
654f29dbc25Smrg		/* Turn off the video palette */
655f29dbc25Smrg		val = READ_VID32(DF_VID_MISC);
656f29dbc25Smrg		WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
657f29dbc25Smrg	    }
658f29dbc25Smrg	} else {
659f29dbc25Smrg	    if (pPriv->freeTime < now) {
660f29dbc25Smrg
661f29dbc25Smrg		if (pPriv->vidmem) {
662f29dbc25Smrg		    GeodeFreeOffscreen(pGeode, pPriv->vidmem);
663f29dbc25Smrg		    pPriv->vidmem = NULL;
664f29dbc25Smrg		}
665f29dbc25Smrg
666f29dbc25Smrg		pPriv->videoStatus = 0;
667f29dbc25Smrg	    }
668f29dbc25Smrg	}
669f29dbc25Smrg    }
670f29dbc25Smrg}
671f29dbc25Smrg
672f29dbc25Smrgstatic XF86VideoAdaptorPtr
673f29dbc25SmrgLXSetupImageVideo(ScreenPtr pScrn)
674f29dbc25Smrg{
675f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
676f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
677f29dbc25Smrg    XF86VideoAdaptorPtr adapt;
678f29dbc25Smrg    GeodePortPrivRec *pPriv;
679f29dbc25Smrg
680f29dbc25Smrg    adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
681f29dbc25Smrg	sizeof(GeodePortPrivRec) + sizeof(DevUnion));
682f29dbc25Smrg
683f29dbc25Smrg    if (adapt == NULL) {
684f29dbc25Smrg	ErrorF("Couldn't create the rec\n");
685f29dbc25Smrg	return NULL;
686f29dbc25Smrg    }
687f29dbc25Smrg
688f29dbc25Smrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
689f29dbc25Smrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
690f29dbc25Smrg
691f29dbc25Smrg    adapt->name = "AMD Geode LX";
692f29dbc25Smrg    adapt->nEncodings = 1;
693f29dbc25Smrg    adapt->pEncodings = DummyEncoding;
694f29dbc25Smrg    adapt->nFormats = ARRAY_SIZE(Formats);
695f29dbc25Smrg    adapt->pFormats = Formats;
696f29dbc25Smrg    adapt->nPorts = 1;
697f29dbc25Smrg    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
698f29dbc25Smrg    pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
699f29dbc25Smrg    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
700f29dbc25Smrg    adapt->pAttributes = Attributes;
701f29dbc25Smrg    adapt->nImages = ARRAY_SIZE(Images);
702f29dbc25Smrg    adapt->nAttributes = ARRAY_SIZE(Attributes);
703f29dbc25Smrg    adapt->pImages = Images;
704f29dbc25Smrg    adapt->PutVideo = NULL;
705f29dbc25Smrg    adapt->PutStill = NULL;
706f29dbc25Smrg    adapt->GetVideo = NULL;
707f29dbc25Smrg    adapt->GetStill = NULL;
708f29dbc25Smrg    adapt->StopVideo = LXStopVideo;
709f29dbc25Smrg    adapt->SetPortAttribute = LXSetPortAttribute;
710f29dbc25Smrg    adapt->GetPortAttribute = LXGetPortAttribute;
711f29dbc25Smrg    adapt->QueryBestSize = LXQueryBestSize;
712f29dbc25Smrg    adapt->PutImage = LXPutImage;
713f29dbc25Smrg
714f29dbc25Smrg    /* Use the common function */
715f29dbc25Smrg    adapt->QueryImageAttributes = GeodeQueryImageAttributes;
716f29dbc25Smrg
717f29dbc25Smrg    pPriv->vidmem = NULL;
718f29dbc25Smrg    pPriv->filter = 0;
719f29dbc25Smrg    pPriv->colorKey = 0;
720f29dbc25Smrg    pPriv->colorKeyMode = 0;
721f29dbc25Smrg    pPriv->videoStatus = 0;
722f29dbc25Smrg    pPriv->pwidth = 0;
723f29dbc25Smrg    pPriv->pheight = 0;
724f29dbc25Smrg
725f29dbc25Smrg    REGION_NULL(pScrn, &pPriv->clip);
726f29dbc25Smrg
727f29dbc25Smrg    pGeode->adaptor = adapt;
728f29dbc25Smrg
729f29dbc25Smrg    pGeode->BlockHandler = pScrn->BlockHandler;
730f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
731f29dbc25Smrg
732f29dbc25Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
733f29dbc25Smrg    xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
734f29dbc25Smrg    xvFilter = MAKE_ATOM("XV_FILTER");
735f29dbc25Smrg
736f29dbc25Smrg    LXResetVideo(pScrni);
737f29dbc25Smrg
738f29dbc25Smrg    return adapt;
739f29dbc25Smrg}
740f29dbc25Smrg
741f29dbc25Smrg/* Offscreen surface allocation */
742f29dbc25Smrg
743f29dbc25Smrgstruct OffscreenPrivRec
744f29dbc25Smrg{
745f29dbc25Smrg    GeodeMemPtr vidmem;
746f29dbc25Smrg    Bool isOn;
747f29dbc25Smrg};
748f29dbc25Smrg
749f29dbc25Smrgstatic int
750f29dbc25SmrgLXDisplaySurface(XF86SurfacePtr surface,
751f29dbc25Smrg    short srcX, short srcY, short drawX, short drawY,
752f29dbc25Smrg    short srcW, short srcH, short drawW, short drawH, RegionPtr clipBoxes)
753f29dbc25Smrg{
754f29dbc25Smrg    struct OffscreenPrivRec *pPriv =
755f29dbc25Smrg	(struct OffscreenPrivRec *)surface->devPrivate.ptr;
756f29dbc25Smrg
757f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
758f29dbc25Smrg    GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
759f29dbc25Smrg
760f29dbc25Smrg    BoxRec dstBox;
761f29dbc25Smrg
762f29dbc25Smrg    dstBox.x1 = drawX;
763f29dbc25Smrg    dstBox.x2 = drawX + drawW;
764f29dbc25Smrg    dstBox.y1 = drawY;
765f29dbc25Smrg    dstBox.y2 = drawY + drawH;
766f29dbc25Smrg
767f29dbc25Smrg    if ((drawW <= 0) | (drawH <= 0))
768f29dbc25Smrg	return Success;
769f29dbc25Smrg
770f29dbc25Smrg    /* Is this still valid? */
771f29dbc25Smrg
772f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
773f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
774f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
775f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
776f29dbc25Smrg
777f29dbc25Smrg    xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
778f29dbc25Smrg
779f29dbc25Smrg    videoScratch.dstOffset = surface->offsets[0];
780f29dbc25Smrg    videoScratch.dstPitch = surface->pitches[0];
781f29dbc25Smrg
782f29dbc25Smrg    LXDisplayVideo(pScrni, surface->id, surface->width, surface->height,
783f29dbc25Smrg	&dstBox, srcW, srcH, drawW, drawH);
784f29dbc25Smrg
785f29dbc25Smrg    pPriv->isOn = TRUE;
786f29dbc25Smrg
787f29dbc25Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
788f29dbc25Smrg	REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
789f29dbc25Smrg	UpdateCurrentTime();
790f29dbc25Smrg	portPriv->videoStatus = FREE_TIMER;
791f29dbc25Smrg	portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
792f29dbc25Smrg    }
793f29dbc25Smrg
794f29dbc25Smrg    return Success;
795f29dbc25Smrg}
796f29dbc25Smrg
797f29dbc25Smrgstatic int
798f29dbc25SmrgLXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w,
799f29dbc25Smrg    unsigned short h, XF86SurfacePtr surface)
800f29dbc25Smrg{
801f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
802f29dbc25Smrg    int pitch, lines;
803f29dbc25Smrg    GeodeMemPtr vidmem;
804f29dbc25Smrg    struct OffscreenPrivRec *pPriv;
805f29dbc25Smrg
806f29dbc25Smrg    if (w > 1024 || h > 1024)
807f29dbc25Smrg	return BadAlloc;
808f29dbc25Smrg
809f29dbc25Smrg    /* The width needs to be word aligned */
810f29dbc25Smrg    w = (w + 1) & ~1;
811f29dbc25Smrg
812f29dbc25Smrg    pitch = ((w << 1) + 15) & ~15;
813f29dbc25Smrg    lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch;
814f29dbc25Smrg
815f29dbc25Smrg    vidmem = GeodeAllocOffscreen(pGeode, lines, 4);
816f29dbc25Smrg
817f29dbc25Smrg    if (vidmem == NULL) {
818f29dbc25Smrg	ErrorF("Error while allocating an offscreen region.\n");
819f29dbc25Smrg	return BadAlloc;
820f29dbc25Smrg    }
821f29dbc25Smrg
822f29dbc25Smrg    surface->width = w;
823f29dbc25Smrg    surface->height = h;
824f29dbc25Smrg
825f29dbc25Smrg    surface->pitches = xalloc(sizeof(int));
826f29dbc25Smrg
827f29dbc25Smrg    surface->offsets = xalloc(sizeof(int));
828f29dbc25Smrg
829f29dbc25Smrg    pPriv = xalloc(sizeof(struct OffscreenPrivRec));
830f29dbc25Smrg
831f29dbc25Smrg    if (pPriv && surface->pitches && surface->offsets) {
832f29dbc25Smrg
833f29dbc25Smrg	pPriv->vidmem = vidmem;
834f29dbc25Smrg
835f29dbc25Smrg	pPriv->isOn = FALSE;
836f29dbc25Smrg
837f29dbc25Smrg	surface->pScrn = pScrni;
838f29dbc25Smrg	surface->id = id;
839f29dbc25Smrg	surface->pitches[0] = pitch;
840f29dbc25Smrg	surface->offsets[0] = vidmem->offset;
841f29dbc25Smrg	surface->devPrivate.ptr = (pointer) pPriv;
842f29dbc25Smrg
843f29dbc25Smrg	return Success;
844f29dbc25Smrg    }
845f29dbc25Smrg
846f29dbc25Smrg    if (surface->offsets)
847f29dbc25Smrg	xfree(surface->offsets);
848f29dbc25Smrg
849f29dbc25Smrg    if (surface->pitches)
850f29dbc25Smrg	xfree(surface->pitches);
851f29dbc25Smrg
852f29dbc25Smrg    if (vidmem)
853f29dbc25Smrg	GeodeFreeOffscreen(pGeode, vidmem);
854f29dbc25Smrg
855f29dbc25Smrg    return BadAlloc;
856f29dbc25Smrg}
857f29dbc25Smrg
858f29dbc25Smrgstatic int
859f29dbc25SmrgLXStopSurface(XF86SurfacePtr surface)
860f29dbc25Smrg{
861f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
862f29dbc25Smrg	surface->devPrivate.ptr;
863f29dbc25Smrg
864f29dbc25Smrg    pPriv->isOn = FALSE;
865f29dbc25Smrg    return Success;
866f29dbc25Smrg}
867f29dbc25Smrg
868f29dbc25Smrgstatic int
869f29dbc25SmrgLXFreeSurface(XF86SurfacePtr surface)
870f29dbc25Smrg{
871f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
872f29dbc25Smrg	surface->devPrivate.ptr;
873f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
874f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
875f29dbc25Smrg
876f29dbc25Smrg    if (pPriv->isOn)
877f29dbc25Smrg	LXStopSurface(surface);
878f29dbc25Smrg
879f29dbc25Smrg    if (pPriv->vidmem) {
880f29dbc25Smrg	GeodeFreeOffscreen(pGeode, pPriv->vidmem);
881f29dbc25Smrg	pPriv->vidmem = NULL;
882f29dbc25Smrg    }
883f29dbc25Smrg
884f29dbc25Smrg    xfree(surface->pitches);
885f29dbc25Smrg    xfree(surface->offsets);
886f29dbc25Smrg    xfree(surface->devPrivate.ptr);
887f29dbc25Smrg
888f29dbc25Smrg    return Success;
889f29dbc25Smrg}
890f29dbc25Smrg
891f29dbc25Smrgstatic int
892f29dbc25SmrgLXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value)
893f29dbc25Smrg{
894f29dbc25Smrg    return LXGetPortAttribute(pScrni, attribute, value,
895f29dbc25Smrg	(pointer) (GET_PORT_PRIVATE(pScrni)));
896f29dbc25Smrg}
897f29dbc25Smrg
898f29dbc25Smrgstatic int
899f29dbc25SmrgLXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
900f29dbc25Smrg{
901f29dbc25Smrg    return LXSetPortAttribute(pScrni, attribute, value,
902f29dbc25Smrg	(pointer) (GET_PORT_PRIVATE(pScrni)));
903f29dbc25Smrg}
904f29dbc25Smrg
905f29dbc25Smrgstatic void
906f29dbc25SmrgLXInitOffscreenImages(ScreenPtr pScrn)
907f29dbc25Smrg{
908f29dbc25Smrg    XF86OffscreenImagePtr offscreenImages;
909f29dbc25Smrg
910f29dbc25Smrg    /* need to free this someplace */
911f29dbc25Smrg    if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
912f29dbc25Smrg	return;
913f29dbc25Smrg
914f29dbc25Smrg    offscreenImages[0].image = &Images[0];
915f29dbc25Smrg    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
916f29dbc25Smrg    offscreenImages[0].alloc_surface = LXAllocateSurface;
917f29dbc25Smrg    offscreenImages[0].free_surface = LXFreeSurface;
918f29dbc25Smrg    offscreenImages[0].display = LXDisplaySurface;
919f29dbc25Smrg    offscreenImages[0].stop = LXStopSurface;
920f29dbc25Smrg    offscreenImages[0].setAttribute = LXSetSurfaceAttribute;
921f29dbc25Smrg    offscreenImages[0].getAttribute = LXGetSurfaceAttribute;
922f29dbc25Smrg    offscreenImages[0].max_width = 1024;
923f29dbc25Smrg    offscreenImages[0].max_height = 1024;
924f29dbc25Smrg    offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes);
925f29dbc25Smrg    offscreenImages[0].attributes = Attributes;
926f29dbc25Smrg
927f29dbc25Smrg    xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
928f29dbc25Smrg}
929f29dbc25Smrg
930f29dbc25Smrgvoid
931f29dbc25SmrgLXInitVideo(ScreenPtr pScrn)
932f29dbc25Smrg{
933f29dbc25Smrg    GeodeRec *pGeode;
934f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
935f29dbc25Smrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
936f29dbc25Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
937f29dbc25Smrg    int num_adaptors;
938f29dbc25Smrg
939f29dbc25Smrg    pGeode = GEODEPTR(pScrni);
940f29dbc25Smrg
941f29dbc25Smrg    if (pGeode->NoAccel) {
942f29dbc25Smrg	ErrorF("Cannot run Xv without accelerations!\n");
943f29dbc25Smrg	return;
944f29dbc25Smrg    }
945f29dbc25Smrg
946f29dbc25Smrg    if (!(newAdaptor = LXSetupImageVideo(pScrn))) {
947f29dbc25Smrg	ErrorF("Error while setting up the adaptor.\n");
948f29dbc25Smrg	return;
949f29dbc25Smrg    }
950f29dbc25Smrg
951f29dbc25Smrg    LXInitOffscreenImages(pScrn);
952f29dbc25Smrg
953f29dbc25Smrg    num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
954f29dbc25Smrg
955f29dbc25Smrg    if (!num_adaptors) {
956f29dbc25Smrg	num_adaptors = 1;
957f29dbc25Smrg	adaptors = &newAdaptor;
958f29dbc25Smrg    } else {
959f29dbc25Smrg	newAdaptors =
960f29dbc25Smrg	    xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
961f29dbc25Smrg
962f29dbc25Smrg	if (newAdaptors) {
963f29dbc25Smrg	    memcpy(newAdaptors, adaptors, num_adaptors *
964f29dbc25Smrg		sizeof(XF86VideoAdaptorPtr));
965f29dbc25Smrg	    newAdaptors[num_adaptors] = newAdaptor;
966f29dbc25Smrg	    adaptors = newAdaptors;
967f29dbc25Smrg	    num_adaptors++;
968f29dbc25Smrg	} else
969f29dbc25Smrg	    ErrorF("Memory error while setting up the adaptor\n");
970f29dbc25Smrg    }
971f29dbc25Smrg
972f29dbc25Smrg    if (num_adaptors)
973f29dbc25Smrg	xf86XVScreenInit(pScrn, adaptors, num_adaptors);
974f29dbc25Smrg
975f29dbc25Smrg    if (newAdaptors)
976f29dbc25Smrg	xfree(newAdaptors);
977f29dbc25Smrg}
978