lx_video.c revision 04007eba
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)
6404007ebaSmrg#ifndef ARRAY_SIZE
65f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
6604007ebaSmrg#endif
67f29dbc25Smrg
68f29dbc25Smrg/* Local function prototypes */
69f29dbc25Smrgstatic void LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit);
70f29dbc25Smrg
71f29dbc25Smrgstatic void
7204007ebaSmrg
7304007ebaSmrg
74f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
7504007ebaSmrg               BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH);
76f29dbc25Smrg
77f29dbc25Smrgstatic void LXResetVideo(ScrnInfoPtr pScrni);
78f29dbc25Smrg
79f29dbc25Smrgstatic XF86VideoEncodingRec DummyEncoding[1] = {
80f29dbc25Smrg    {0, "XV_IMAGE", 1024, 1024, {1, 1}}
81f29dbc25Smrg};
82f29dbc25Smrg
83f29dbc25Smrgstatic XF86VideoFormatRec Formats[] = {
84f29dbc25Smrg    {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
85f29dbc25Smrg};
86f29dbc25Smrg
87f29dbc25Smrgstatic XF86AttributeRec Attributes[] = {
88f29dbc25Smrg    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
89f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
90f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
91f29dbc25Smrg};
92f29dbc25Smrg
93f29dbc25Smrgstatic XF86ImageRec Images[] = {
94f29dbc25Smrg    XVIMAGE_UYVY,
95f29dbc25Smrg    XVIMAGE_YUY2,
96f29dbc25Smrg    XVIMAGE_Y2YU,
97f29dbc25Smrg    XVIMAGE_YVYU,
98f29dbc25Smrg    XVIMAGE_Y800,
99f29dbc25Smrg    XVIMAGE_I420,
100f29dbc25Smrg    XVIMAGE_YV12,
101f29dbc25Smrg    XVIMAGE_RGB565
102f29dbc25Smrg};
103f29dbc25Smrg
10404007ebaSmrgtypedef struct {
105170d5fdcSmrg    ExaOffscreenArea *vidmem;
106f29dbc25Smrg    RegionRec clip;
107f29dbc25Smrg    CARD32 filter;
108f29dbc25Smrg    CARD32 colorKey;
109f29dbc25Smrg    CARD32 colorKeyMode;
110f29dbc25Smrg    CARD32 videoStatus;
111f29dbc25Smrg    Time offTime;
112f29dbc25Smrg    Time freeTime;
113f29dbc25Smrg    short pwidth, pheight;
114f29dbc25Smrg} GeodePortPrivRec, *GeodePortPrivPtr;
115f29dbc25Smrg
116f29dbc25Smrg#define GET_PORT_PRIVATE(pScrni) \
117f29dbc25Smrg   (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr)
118f29dbc25Smrg
119f29dbc25Smrgstatic void
120f29dbc25SmrgLXCopyFromSys(GeodeRec * pGeode, unsigned char *src, unsigned int dst,
12104007ebaSmrg              int dstPitch, int srcPitch, int h, int w)
122f29dbc25Smrg{
123f29dbc25Smrg
124f29dbc25Smrg    gp_declare_blt(0);
125170d5fdcSmrg    gp_set_bpp((srcPitch / w) << 3);
126f29dbc25Smrg
127f29dbc25Smrg    gp_set_raster_operation(0xCC);
128f29dbc25Smrg    gp_set_strides(dstPitch, srcPitch);
129f29dbc25Smrg    gp_set_solid_pattern(0);
130f29dbc25Smrg
131f29dbc25Smrg    gp_color_bitmap_to_screen_blt(dst, 0, w, h, src, srcPitch);
132f29dbc25Smrg}
133f29dbc25Smrg
134f29dbc25Smrgstatic void
135f29dbc25SmrgLXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv)
136f29dbc25Smrg{
137f29dbc25Smrg    int red, green, blue;
138f29dbc25Smrg    unsigned long key;
139f29dbc25Smrg
140f29dbc25Smrg    switch (pScrni->depth) {
141f29dbc25Smrg    case 8:
14204007ebaSmrg        vg_get_display_palette_entry(pPriv->colorKey & 0xFF, &key);
14304007ebaSmrg        red = ((key >> 16) & 0xFF);
14404007ebaSmrg        green = ((key >> 8) & 0xFF);
14504007ebaSmrg        blue = (key & 0xFF);
14604007ebaSmrg        break;
147f29dbc25Smrg    case 16:
14804007ebaSmrg        red = (pPriv->colorKey & pScrni->mask.red) >>
14904007ebaSmrg            pScrni->offset.red << (8 - pScrni->weight.red);
15004007ebaSmrg        green = (pPriv->colorKey & pScrni->mask.green) >>
15104007ebaSmrg            pScrni->offset.green << (8 - pScrni->weight.green);
15204007ebaSmrg        blue = (pPriv->colorKey & pScrni->mask.blue) >>
15304007ebaSmrg            pScrni->offset.blue << (8 - pScrni->weight.blue);
15404007ebaSmrg        break;
155f29dbc25Smrg    default:
15604007ebaSmrg        /* for > 16 bpp we send in the mask in xf86SetWeight. This
15704007ebaSmrg         * function is providing the offset by 1 more. So we take
15804007ebaSmrg         * this as a special case and subtract 1 for > 16
15904007ebaSmrg         */
16004007ebaSmrg
16104007ebaSmrg        red = (pPriv->colorKey & pScrni->mask.red) >>
16204007ebaSmrg            (pScrni->offset.red - 1) << (8 - pScrni->weight.red);
16304007ebaSmrg        green = (pPriv->colorKey & pScrni->mask.green) >>
16404007ebaSmrg            (pScrni->offset.green - 1) << (8 - pScrni->weight.green);
16504007ebaSmrg        blue = (pPriv->colorKey & pScrni->mask.blue) >>
16604007ebaSmrg            (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue);
16704007ebaSmrg        break;
168f29dbc25Smrg    }
169f29dbc25Smrg
170f29dbc25Smrg    df_set_video_color_key((blue | (green << 8) | (red << 16)),
17104007ebaSmrg                           0xFFFFFF, (pPriv->colorKeyMode == 0));
172f29dbc25Smrg
173f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
174f29dbc25Smrg}
175f29dbc25Smrg
176f29dbc25Smrg/* A structure full of the scratch information that originates in the copy routines,
177f29dbc25Smrg   but is needed for the video display - maybe we should figure out a way to attach
178f29dbc25Smrg   this to structures?  I hate to put it in pGeode since it will increase the size of
179f29dbc25Smrg   the structure, and possibly cause us cache issues.
180f29dbc25Smrg*/
181f29dbc25Smrg
18204007ebaSmrgstruct {
183f29dbc25Smrg    unsigned int dstOffset;
184f29dbc25Smrg    unsigned int dstPitch;
185f29dbc25Smrg    unsigned int UVPitch;
186f29dbc25Smrg    unsigned int UDstOffset;
187f29dbc25Smrg    unsigned int VDstOffset;
188f29dbc25Smrg} videoScratch;
189f29dbc25Smrg
190f29dbc25Smrg/* Copy planar YUV data */
191f29dbc25Smrg
192f29dbc25Smrgstatic Bool
19304007ebaSmrgLXAllocateVidMem(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv, int size)
194f29dbc25Smrg{
19504007ebaSmrg    if (!pPriv->vidmem || pPriv->vidmem->size < size) {
19604007ebaSmrg        if (pPriv->vidmem) {
19704007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
19804007ebaSmrg            pPriv->vidmem = NULL;
19904007ebaSmrg        }
20004007ebaSmrg
20104007ebaSmrg        pPriv->vidmem = exaOffscreenAlloc(pScrni->pScreen, size, 4,
20204007ebaSmrg                                          TRUE, NULL, NULL);
20304007ebaSmrg
20404007ebaSmrg        if (pPriv->vidmem == NULL) {
20504007ebaSmrg            ErrorF("Could not allocate memory for the video\n");
20604007ebaSmrg            return FALSE;
20704007ebaSmrg        }
208f29dbc25Smrg    }
209f29dbc25Smrg
210f29dbc25Smrg    return TRUE;
21104007ebaSmrg}
212f29dbc25Smrg
213f29dbc25Smrgstatic Bool
214f29dbc25SmrgLXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf,
21504007ebaSmrg             short x1, short y1, short x2, short y2,
21604007ebaSmrg             int width, int height, pointer data)
217f29dbc25Smrg{
218f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
219f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
220f29dbc25Smrg
221f29dbc25Smrg    unsigned int YSrcPitch, YDstPitch;
222f29dbc25Smrg    unsigned int UVSrcPitch, UVDstPitch;
223f29dbc25Smrg    unsigned int YSrcOffset, YDstOffset;
224f29dbc25Smrg    unsigned int USrcOffset, UDstOffset;
225f29dbc25Smrg    unsigned int VSrcOffset, VDstOffset;
226f29dbc25Smrg
227f29dbc25Smrg    unsigned int size, lines, top, left, pixels;
228f29dbc25Smrg
229f29dbc25Smrg    YSrcPitch = (width + 3) & ~3;
230f29dbc25Smrg    YDstPitch = (width + 31) & ~31;
231f29dbc25Smrg
232f29dbc25Smrg    UVSrcPitch = ((width >> 1) + 3) & ~3;
233f29dbc25Smrg    UVDstPitch = ((width >> 1) + 15) & ~15;
234f29dbc25Smrg
235f29dbc25Smrg    USrcOffset = YSrcPitch * height;
236f29dbc25Smrg    VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
237f29dbc25Smrg
238f29dbc25Smrg    UDstOffset = YDstPitch * height;
239f29dbc25Smrg    VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
240f29dbc25Smrg
241f29dbc25Smrg    size = YDstPitch * height;
242f29dbc25Smrg    size += UVDstPitch * height;
243f29dbc25Smrg
244170d5fdcSmrg    if (LXAllocateVidMem(pScrni, pPriv, size) == FALSE) {
24504007ebaSmrg        ErrorF("Error allocating an offscreen Planar region.\n");
24604007ebaSmrg        return FALSE;
247170d5fdcSmrg    }
248f29dbc25Smrg
249f29dbc25Smrg    /* The top of the source region we want to copy */
250f29dbc25Smrg    top = y1 & ~1;
251f29dbc25Smrg
252f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
253f29dbc25Smrg    left = x1 & ~1;
254f29dbc25Smrg
255f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
256f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
257f29dbc25Smrg
258f29dbc25Smrg    /* Calculate the source offset */
259f29dbc25Smrg    YSrcOffset = (top * YSrcPitch) + left;
260f29dbc25Smrg    USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
261f29dbc25Smrg    VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
262f29dbc25Smrg
263f29dbc25Smrg    /* Calculate the destination offset */
264f29dbc25Smrg    YDstOffset = (top * YDstPitch) + left;
265f29dbc25Smrg    UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
266f29dbc25Smrg    VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
267f29dbc25Smrg
268f29dbc25Smrg    lines = ((y2 + 1) & ~1) - top;
269f29dbc25Smrg
270f29dbc25Smrg    /* Copy Y */
271f29dbc25Smrg
272f29dbc25Smrg    LXCopyFromSys(pGeode, buf + YSrcOffset,
27304007ebaSmrg                  pPriv->vidmem->offset + YDstOffset, YDstPitch, YSrcPitch,
27404007ebaSmrg                  lines, pixels);
275f29dbc25Smrg
276f29dbc25Smrg    /* Copy U + V at the same time */
277f29dbc25Smrg
278f29dbc25Smrg    LXCopyFromSys(pGeode, buf + USrcOffset,
27904007ebaSmrg                  pPriv->vidmem->offset + UDstOffset, UVDstPitch, UVSrcPitch,
28004007ebaSmrg                  lines, pixels >> 1);
281f29dbc25Smrg
282f29dbc25Smrg    videoScratch.dstOffset = pPriv->vidmem->offset + YDstOffset;
283f29dbc25Smrg    videoScratch.dstPitch = YDstPitch;
284f29dbc25Smrg    videoScratch.UVPitch = UVDstPitch;
285f29dbc25Smrg    videoScratch.UDstOffset = pPriv->vidmem->offset + UDstOffset;
286f29dbc25Smrg    videoScratch.VDstOffset = pPriv->vidmem->offset + VDstOffset;
287f29dbc25Smrg
288f29dbc25Smrg    return TRUE;
289f29dbc25Smrg}
290f29dbc25Smrg
291f29dbc25Smrgstatic Bool
292f29dbc25SmrgLXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf,
29304007ebaSmrg             short x1, short y1, short x2, short y2,
29404007ebaSmrg             int width, int height, pointer data)
295f29dbc25Smrg{
296f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
297f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
298f29dbc25Smrg    unsigned int dstPitch, srcPitch;
299f29dbc25Smrg    unsigned int srcOffset, dstOffset;
300f29dbc25Smrg    unsigned int lines, top, left, pixels;
301f29dbc25Smrg
302f29dbc25Smrg    dstPitch = ((width << 1) + 3) & ~3;
303f29dbc25Smrg    srcPitch = (width << 1);
304f29dbc25Smrg
305f29dbc25Smrg    lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
306f29dbc25Smrg
3077aef237fSmrg    if (LXAllocateVidMem(pScrni, pPriv, dstPitch * height) == FALSE) {
30804007ebaSmrg        ErrorF("Error allocating an offscreen Packed region.\n");
30904007ebaSmrg        return FALSE;
310170d5fdcSmrg    }
311f29dbc25Smrg
312f29dbc25Smrg    /* The top of the source region we want to copy */
313f29dbc25Smrg    top = y1;
314f29dbc25Smrg
315f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
316f29dbc25Smrg    left = x1 & ~1;
317f29dbc25Smrg
318f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
319f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
320f29dbc25Smrg
321f29dbc25Smrg    /* Adjust the incoming buffer */
322f29dbc25Smrg    srcOffset = (top * srcPitch) + left;
323f29dbc25Smrg
324f29dbc25Smrg    /* Calculate the destination offset */
325f29dbc25Smrg    dstOffset = pPriv->vidmem->offset + (top * dstPitch) + left;
326f29dbc25Smrg
327f29dbc25Smrg    /* Make the copy happen */
328f29dbc25Smrg
329f29dbc25Smrg    if (id == FOURCC_Y800) {
330f29dbc25Smrg
33104007ebaSmrg        /* Use the shared (unaccelerated) greyscale copy - you could probably
33204007ebaSmrg         * accelerate it using a 2 pass blit and patterns, but it doesn't really
33304007ebaSmrg         * seem worth it
33404007ebaSmrg         */
335f29dbc25Smrg
33604007ebaSmrg        GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset,
33704007ebaSmrg                           srcPitch, dstPitch, height, pixels >> 1);
33804007ebaSmrg    }
33904007ebaSmrg    else
34004007ebaSmrg        /* FIXME: should lines be used here instead of height? */
34104007ebaSmrg        LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch,
34204007ebaSmrg                      height, pixels);
343f29dbc25Smrg
344f29dbc25Smrg    videoScratch.dstOffset = dstOffset;
345f29dbc25Smrg    videoScratch.dstPitch = dstPitch;
346f29dbc25Smrg
347f29dbc25Smrg    return TRUE;
348f29dbc25Smrg}
349f29dbc25Smrg
350f29dbc25Smrgstatic void
351f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
35204007ebaSmrg               BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH)
353f29dbc25Smrg{
354f29dbc25Smrg    long ystart, xend, yend;
355f29dbc25Smrg    unsigned long lines = 0;
356f29dbc25Smrg    unsigned long yExtra, uvExtra = 0;
357f29dbc25Smrg    DF_VIDEO_POSITION vidPos;
358f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vSrcParams;
359f29dbc25Smrg    int err;
360f29dbc25Smrg
361f29dbc25Smrg    memset(&vSrcParams, 0, sizeof(vSrcParams));
362f29dbc25Smrg
363f29dbc25Smrg    gp_wait_until_idle();
364f29dbc25Smrg
365f29dbc25Smrg    switch (id) {
366f29dbc25Smrg    case FOURCC_UYVY:
36704007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_UYVY;
36804007ebaSmrg        break;
369f29dbc25Smrg
370f29dbc25Smrg    case FOURCC_Y800:
371f29dbc25Smrg    case FOURCC_YV12:
372f29dbc25Smrg    case FOURCC_I420:
37304007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3;
37404007ebaSmrg        break;
375f29dbc25Smrg    case FOURCC_YUY2:
37604007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_YUYV;
37704007ebaSmrg        break;
378f29dbc25Smrg    case FOURCC_Y2YU:
37904007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_Y2YU;
38004007ebaSmrg        break;
381f29dbc25Smrg    case FOURCC_YVYU:
38204007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_YVYU;
38304007ebaSmrg        break;
384f29dbc25Smrg    case FOURCC_RGB565:
38504007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_RGB;
38604007ebaSmrg        break;
387f29dbc25Smrg    }
388f29dbc25Smrg
389f29dbc25Smrg    vSrcParams.width = width;
390f29dbc25Smrg    vSrcParams.height = height;
391f29dbc25Smrg    vSrcParams.y_pitch = videoScratch.dstPitch;
392f29dbc25Smrg    vSrcParams.uv_pitch = videoScratch.UVPitch;
393f29dbc25Smrg
394f29dbc25Smrg    /* Set up scaling */
395f29dbc25Smrg    df_set_video_filter_coefficients(NULL, 1);
396f29dbc25Smrg
397f29dbc25Smrg    err = df_set_video_scale(width, height, drawW, drawH,
39804007ebaSmrg                             DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY);
399f29dbc25Smrg    if (err != CIM_STATUS_OK) {
40004007ebaSmrg        /* Note the problem, but do nothing for now. */
40104007ebaSmrg        ErrorF("Video scale factor too large: %dx%d -> %dx%d\n",
40204007ebaSmrg               width, height, drawW, drawH);
403f29dbc25Smrg    }
404f29dbc25Smrg
405f29dbc25Smrg    /* Figure out clipping */
406f29dbc25Smrg
407f29dbc25Smrg    xend = dstBox->x2;
408f29dbc25Smrg    yend = dstBox->y2;
409f29dbc25Smrg
410f29dbc25Smrg    if (dstBox->y1 < 0) {
41104007ebaSmrg        if (srcH < drawH)
41204007ebaSmrg            lines = ((-dstBox->y1) * srcH) / drawH;
41304007ebaSmrg        else
41404007ebaSmrg            lines = (-dstBox->y1);
41504007ebaSmrg
41604007ebaSmrg        ystart = 0;
41704007ebaSmrg        drawH += dstBox->y1;
41804007ebaSmrg    }
41904007ebaSmrg    else {
42004007ebaSmrg        ystart = dstBox->y1;
42104007ebaSmrg        lines = 0;
422f29dbc25Smrg    }
423f29dbc25Smrg
424f29dbc25Smrg    yExtra = lines * videoScratch.dstPitch;
425f29dbc25Smrg    uvExtra = (lines >> 1) * videoScratch.UVPitch;
426f29dbc25Smrg
427f29dbc25Smrg    memset(&vidPos, 0, sizeof(vidPos));
428f29dbc25Smrg
429f29dbc25Smrg    vidPos.x = dstBox->x1;
430f29dbc25Smrg    vidPos.y = ystart;
431f29dbc25Smrg    vidPos.width = xend - dstBox->x1;
432f29dbc25Smrg    vidPos.height = yend - ystart;
433f29dbc25Smrg
434f29dbc25Smrg    df_set_video_position(&vidPos);
435f29dbc25Smrg
436f29dbc25Smrg    vSrcParams.y_offset = videoScratch.dstOffset + yExtra;
437f29dbc25Smrg
438f29dbc25Smrg    switch (id) {
439f29dbc25Smrg    case FOURCC_Y800:
440f29dbc25Smrg    case FOURCC_I420:
44104007ebaSmrg        vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra;
44204007ebaSmrg        vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra;
44304007ebaSmrg        break;
444f29dbc25Smrg    case FOURCC_YV12:
44504007ebaSmrg        vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra;
44604007ebaSmrg        vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra;
44704007ebaSmrg        break;
448f29dbc25Smrg
449f29dbc25Smrg    default:
45004007ebaSmrg        vSrcParams.u_offset = vSrcParams.v_offset = 0;
45104007ebaSmrg        break;
452f29dbc25Smrg    }
453f29dbc25Smrg
454f29dbc25Smrg    vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING;
455f29dbc25Smrg    df_configure_video_source(&vSrcParams, &vSrcParams);
456f29dbc25Smrg
457f29dbc25Smrg    /* Turn on the video palette */
458f29dbc25Smrg    df_set_video_palette(NULL);
459f29dbc25Smrg    df_set_video_enable(1, 0);
460f29dbc25Smrg}
461f29dbc25Smrg
462f29dbc25Smrgstatic int
463f29dbc25SmrgLXPutImage(ScrnInfoPtr pScrni,
46404007ebaSmrg           short srcX, short srcY, short drawX, short drawY,
46504007ebaSmrg           short srcW, short srcH, short drawW, short drawH,
46604007ebaSmrg           int id, unsigned char *buf,
46704007ebaSmrg           short width, short height, Bool sync, RegionPtr clipBoxes,
46804007ebaSmrg           pointer data, DrawablePtr pDraw)
469f29dbc25Smrg{
470f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
471f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
472f29dbc25Smrg    INT32 x1, x2, y1, y2;
473f29dbc25Smrg    BoxRec dstBox;
474f29dbc25Smrg    Bool ret;
475f29dbc25Smrg
476f29dbc25Smrg    if (pGeode->rotation != RR_Rotate_0)
47704007ebaSmrg        return Success;
478f29dbc25Smrg
479f29dbc25Smrg    if (srcW <= 0 || srcH <= 0) {
48004007ebaSmrg        return Success;
481f29dbc25Smrg    }
482f29dbc25Smrg
483f29dbc25Smrg    if (drawW <= 0 || drawH <= 0) {
48404007ebaSmrg        return Success;
485f29dbc25Smrg    }
486f29dbc25Smrg
487f29dbc25Smrg    if (drawW > 16384)
48804007ebaSmrg        drawW = 16384;
489f29dbc25Smrg
490f29dbc25Smrg    memset(&videoScratch, 0, sizeof(videoScratch));
491f29dbc25Smrg
492f29dbc25Smrg    x1 = srcX;
493f29dbc25Smrg    x2 = srcX + srcW;
494f29dbc25Smrg    y1 = srcY;
495f29dbc25Smrg    y2 = srcY + srcH;
496f29dbc25Smrg
497f29dbc25Smrg    dstBox.x1 = drawX;
498f29dbc25Smrg    dstBox.x2 = drawX + drawW;
499f29dbc25Smrg    dstBox.y1 = drawY;
500f29dbc25Smrg    dstBox.y2 = drawY + drawH;
501f29dbc25Smrg
502f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
503f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
504f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
505f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
506f29dbc25Smrg
507f29dbc25Smrg    if (id == FOURCC_YV12 || id == FOURCC_I420)
50804007ebaSmrg        ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width,
50904007ebaSmrg                           height, data);
510f29dbc25Smrg    else
51104007ebaSmrg        ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width,
51204007ebaSmrg                           height, data);
513f29dbc25Smrg
514f29dbc25Smrg    if (ret == FALSE)
51504007ebaSmrg        return BadAlloc;
51604007ebaSmrg
517f29dbc25Smrg    if (!RegionsEqual(&pPriv->clip, clipBoxes) ||
51804007ebaSmrg        (drawW != pPriv->pwidth || drawH != pPriv->pheight)) {
51904007ebaSmrg        REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
520f29dbc25Smrg
52104007ebaSmrg        if (pPriv->colorKeyMode == 0) {
52204007ebaSmrg            xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
52304007ebaSmrg        }
524f29dbc25Smrg
52504007ebaSmrg        LXDisplayVideo(pScrni, id, width, height, &dstBox,
52604007ebaSmrg                       srcW, srcH, drawW, drawH);
52704007ebaSmrg        pPriv->pwidth = drawW;
52804007ebaSmrg        pPriv->pheight = drawH;
529f29dbc25Smrg    }
530f29dbc25Smrg
531f29dbc25Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
532f29dbc25Smrg
533f29dbc25Smrg    return Success;
534f29dbc25Smrg}
535f29dbc25Smrg
536f29dbc25Smrgstatic void
537f29dbc25SmrgLXQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
53804007ebaSmrg                short vidW, short vidH, short drawW, short drawH,
53904007ebaSmrg                unsigned int *retW, unsigned int *retH, pointer data)
540f29dbc25Smrg{
541f29dbc25Smrg    *retW = drawW > 16384 ? 16384 : drawW;
542f29dbc25Smrg    *retH = drawH;
543f29dbc25Smrg}
544f29dbc25Smrg
545f29dbc25Smrgstatic Atom xvColorKey, xvColorKeyMode, xvFilter;
546f29dbc25Smrg
547f29dbc25Smrgstatic int
548f29dbc25SmrgLXGetPortAttribute(ScrnInfoPtr pScrni,
54904007ebaSmrg                   Atom attribute, INT32 *value, pointer data)
550f29dbc25Smrg{
551f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
552f29dbc25Smrg
553f29dbc25Smrg    if (attribute == xvColorKey)
55404007ebaSmrg        *value = pPriv->colorKey;
555f29dbc25Smrg    else if (attribute == xvColorKeyMode)
55604007ebaSmrg        *value = pPriv->colorKeyMode;
557f29dbc25Smrg    else if (attribute == xvFilter)
55804007ebaSmrg        *value = pPriv->filter;
559f29dbc25Smrg    else
56004007ebaSmrg        return BadMatch;
561f29dbc25Smrg
562f29dbc25Smrg    return Success;
563f29dbc25Smrg}
564f29dbc25Smrg
565f29dbc25Smrgstatic int
566f29dbc25SmrgLXSetPortAttribute(ScrnInfoPtr pScrni,
56704007ebaSmrg                   Atom attribute, INT32 value, pointer data)
568f29dbc25Smrg{
569f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
570f29dbc25Smrg
571f29dbc25Smrg    gp_wait_until_idle();
572f29dbc25Smrg
573f29dbc25Smrg    if (attribute == xvColorKey) {
57404007ebaSmrg        pPriv->colorKey = value;
57504007ebaSmrg        LXSetColorkey(pScrni, pPriv);
57604007ebaSmrg    }
57704007ebaSmrg    else if (attribute == xvColorKeyMode) {
57804007ebaSmrg        pPriv->colorKeyMode = value;
57904007ebaSmrg        LXSetColorkey(pScrni, pPriv);
58004007ebaSmrg    }
58104007ebaSmrg    else if (attribute == xvFilter) {
58204007ebaSmrg        if ((value < 0) || (value > 1))
58304007ebaSmrg            return BadValue;
58404007ebaSmrg        pPriv->filter = value;
58504007ebaSmrg    }
58604007ebaSmrg    else
58704007ebaSmrg        return BadMatch;
588f29dbc25Smrg
589f29dbc25Smrg    return Success;
590f29dbc25Smrg}
591f29dbc25Smrg
592f29dbc25Smrgstatic void
593f29dbc25SmrgLXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
594f29dbc25Smrg{
595f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
596f29dbc25Smrg
597f29dbc25Smrg    if (pPriv->videoStatus == 0)
59804007ebaSmrg        return;
599f29dbc25Smrg
600f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
601f29dbc25Smrg    gp_wait_until_idle();
602f29dbc25Smrg
603f29dbc25Smrg    if (exit) {
60404007ebaSmrg        if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
60504007ebaSmrg            unsigned int val;
60604007ebaSmrg
60704007ebaSmrg            df_set_video_enable(0, 0);
60804007ebaSmrg            /* Put the LUT back in bypass */
60904007ebaSmrg            val = READ_VID32(DF_VID_MISC);
61004007ebaSmrg            WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
61104007ebaSmrg        }
61204007ebaSmrg
61304007ebaSmrg        if (pPriv->vidmem) {
61404007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
61504007ebaSmrg            pPriv->vidmem = NULL;
61604007ebaSmrg        }
61704007ebaSmrg
61804007ebaSmrg        pPriv->videoStatus = 0;
61904007ebaSmrg
62004007ebaSmrg        /* Eh? */
62104007ebaSmrg    }
62204007ebaSmrg    else if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
62304007ebaSmrg        pPriv->videoStatus |= OFF_TIMER;
62404007ebaSmrg        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
625f29dbc25Smrg    }
626f29dbc25Smrg}
627f29dbc25Smrg
628f29dbc25Smrgstatic void
629f29dbc25SmrgLXResetVideo(ScrnInfoPtr pScrni)
630f29dbc25Smrg{
631f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
632f29dbc25Smrg
633f29dbc25Smrg    if (!pGeode->NoAccel) {
63404007ebaSmrg        GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
635f29dbc25Smrg
63604007ebaSmrg        gp_wait_until_idle();
63704007ebaSmrg        df_set_video_palette(NULL);
638f29dbc25Smrg
63904007ebaSmrg        LXSetColorkey(pScrni, pPriv);
640f29dbc25Smrg    }
641f29dbc25Smrg}
642f29dbc25Smrg
643f29dbc25Smrgstatic void
64404007ebaSmrgLXVidBlockHandler(BLOCKHANDLER_ARGS_DECL)
645f29dbc25Smrg{
64604007ebaSmrg    SCREEN_PTR(arg);
64704007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
648f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
649f29dbc25Smrg    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
650f29dbc25Smrg
651f29dbc25Smrg    pScrn->BlockHandler = pGeode->BlockHandler;
65204007ebaSmrg    (*pScrn->BlockHandler) (BLOCKHANDLER_ARGS);
653f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
654f29dbc25Smrg
655f29dbc25Smrg    if (pPriv->videoStatus & TIMER_MASK) {
65604007ebaSmrg        Time now = currentTime.milliseconds;
65704007ebaSmrg
65804007ebaSmrg        if (pPriv->videoStatus & OFF_TIMER) {
65904007ebaSmrg            gp_wait_until_idle();
66004007ebaSmrg
66104007ebaSmrg            if (pPriv->offTime < now) {
66204007ebaSmrg                unsigned int val;
66304007ebaSmrg
66404007ebaSmrg                df_set_video_enable(0, 0);
66504007ebaSmrg                pPriv->videoStatus = FREE_TIMER;
66604007ebaSmrg                pPriv->freeTime = now + FREE_DELAY;
66704007ebaSmrg
66804007ebaSmrg                /* Turn off the video palette */
66904007ebaSmrg                val = READ_VID32(DF_VID_MISC);
67004007ebaSmrg                WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
67104007ebaSmrg            }
67204007ebaSmrg        }
67304007ebaSmrg        else {
67404007ebaSmrg            if (pPriv->freeTime < now) {
67504007ebaSmrg
67604007ebaSmrg                if (pPriv->vidmem) {
67704007ebaSmrg                    exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
67804007ebaSmrg                    pPriv->vidmem = NULL;
67904007ebaSmrg                }
68004007ebaSmrg
68104007ebaSmrg                pPriv->videoStatus = 0;
68204007ebaSmrg            }
68304007ebaSmrg        }
684f29dbc25Smrg    }
685f29dbc25Smrg}
686f29dbc25Smrg
687f29dbc25Smrgstatic XF86VideoAdaptorPtr
688f29dbc25SmrgLXSetupImageVideo(ScreenPtr pScrn)
689f29dbc25Smrg{
69004007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
691f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
692f29dbc25Smrg    XF86VideoAdaptorPtr adapt;
693f29dbc25Smrg    GeodePortPrivRec *pPriv;
694f29dbc25Smrg
695170d5fdcSmrg    adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
69604007ebaSmrg                   sizeof(GeodePortPrivRec) + sizeof(DevUnion));
697f29dbc25Smrg
698f29dbc25Smrg    if (adapt == NULL) {
69904007ebaSmrg        ErrorF("Couldn't create the rec\n");
70004007ebaSmrg        return NULL;
701f29dbc25Smrg    }
702f29dbc25Smrg
703f29dbc25Smrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
704f29dbc25Smrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
705f29dbc25Smrg
706f29dbc25Smrg    adapt->name = "AMD Geode LX";
707f29dbc25Smrg    adapt->nEncodings = 1;
708f29dbc25Smrg    adapt->pEncodings = DummyEncoding;
709f29dbc25Smrg    adapt->nFormats = ARRAY_SIZE(Formats);
710f29dbc25Smrg    adapt->pFormats = Formats;
711f29dbc25Smrg    adapt->nPorts = 1;
712f29dbc25Smrg    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
713f29dbc25Smrg    pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
714f29dbc25Smrg    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
715f29dbc25Smrg    adapt->pAttributes = Attributes;
716f29dbc25Smrg    adapt->nImages = ARRAY_SIZE(Images);
717f29dbc25Smrg    adapt->nAttributes = ARRAY_SIZE(Attributes);
718f29dbc25Smrg    adapt->pImages = Images;
719f29dbc25Smrg    adapt->PutVideo = NULL;
720f29dbc25Smrg    adapt->PutStill = NULL;
721f29dbc25Smrg    adapt->GetVideo = NULL;
722f29dbc25Smrg    adapt->GetStill = NULL;
723f29dbc25Smrg    adapt->StopVideo = LXStopVideo;
724f29dbc25Smrg    adapt->SetPortAttribute = LXSetPortAttribute;
725f29dbc25Smrg    adapt->GetPortAttribute = LXGetPortAttribute;
726f29dbc25Smrg    adapt->QueryBestSize = LXQueryBestSize;
727f29dbc25Smrg    adapt->PutImage = LXPutImage;
728f29dbc25Smrg
729f29dbc25Smrg    /* Use the common function */
730f29dbc25Smrg    adapt->QueryImageAttributes = GeodeQueryImageAttributes;
731f29dbc25Smrg
732f29dbc25Smrg    pPriv->vidmem = NULL;
733f29dbc25Smrg    pPriv->filter = 0;
734f29dbc25Smrg    pPriv->colorKey = 0;
735f29dbc25Smrg    pPriv->colorKeyMode = 0;
736f29dbc25Smrg    pPriv->videoStatus = 0;
737f29dbc25Smrg    pPriv->pwidth = 0;
738f29dbc25Smrg    pPriv->pheight = 0;
739f29dbc25Smrg
740f29dbc25Smrg    REGION_NULL(pScrn, &pPriv->clip);
741f29dbc25Smrg
742f29dbc25Smrg    pGeode->adaptor = adapt;
743f29dbc25Smrg
744f29dbc25Smrg    pGeode->BlockHandler = pScrn->BlockHandler;
745f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
746f29dbc25Smrg
747f29dbc25Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
748f29dbc25Smrg    xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
749f29dbc25Smrg    xvFilter = MAKE_ATOM("XV_FILTER");
750f29dbc25Smrg
751f29dbc25Smrg    LXResetVideo(pScrni);
752f29dbc25Smrg
753f29dbc25Smrg    return adapt;
754f29dbc25Smrg}
755f29dbc25Smrg
756f29dbc25Smrg/* Offscreen surface allocation */
757f29dbc25Smrg
75804007ebaSmrgstruct OffscreenPrivRec {
759170d5fdcSmrg    ExaOffscreenArea *vidmem;
760f29dbc25Smrg    Bool isOn;
761f29dbc25Smrg};
762f29dbc25Smrg
763f29dbc25Smrgstatic int
764f29dbc25SmrgLXDisplaySurface(XF86SurfacePtr surface,
76504007ebaSmrg                 short srcX, short srcY, short drawX, short drawY,
76604007ebaSmrg                 short srcW, short srcH, short drawW, short drawH,
76704007ebaSmrg                 RegionPtr clipBoxes)
768f29dbc25Smrg{
769f29dbc25Smrg    struct OffscreenPrivRec *pPriv =
77004007ebaSmrg        (struct OffscreenPrivRec *) surface->devPrivate.ptr;
771f29dbc25Smrg
772f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
773f29dbc25Smrg    GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
774f29dbc25Smrg
775f29dbc25Smrg    BoxRec dstBox;
776f29dbc25Smrg
777f29dbc25Smrg    dstBox.x1 = drawX;
778f29dbc25Smrg    dstBox.x2 = drawX + drawW;
779f29dbc25Smrg    dstBox.y1 = drawY;
780f29dbc25Smrg    dstBox.y2 = drawY + drawH;
781f29dbc25Smrg
782f29dbc25Smrg    if ((drawW <= 0) | (drawH <= 0))
78304007ebaSmrg        return Success;
784f29dbc25Smrg
785f29dbc25Smrg    /* Is this still valid? */
786f29dbc25Smrg
787f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
788f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
789f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
790f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
791f29dbc25Smrg
792f29dbc25Smrg    xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
793f29dbc25Smrg
794f29dbc25Smrg    videoScratch.dstOffset = surface->offsets[0];
795f29dbc25Smrg    videoScratch.dstPitch = surface->pitches[0];
796f29dbc25Smrg
797f29dbc25Smrg    LXDisplayVideo(pScrni, surface->id, surface->width, surface->height,
79804007ebaSmrg                   &dstBox, srcW, srcH, drawW, drawH);
799f29dbc25Smrg
800f29dbc25Smrg    pPriv->isOn = TRUE;
801f29dbc25Smrg
802f29dbc25Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
80304007ebaSmrg        REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
80404007ebaSmrg        UpdateCurrentTime();
80504007ebaSmrg        portPriv->videoStatus = FREE_TIMER;
80604007ebaSmrg        portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
807f29dbc25Smrg    }
808f29dbc25Smrg
809f29dbc25Smrg    return Success;
810f29dbc25Smrg}
811f29dbc25Smrg
812f29dbc25Smrgstatic int
813f29dbc25SmrgLXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w,
81404007ebaSmrg                  unsigned short h, XF86SurfacePtr surface)
815f29dbc25Smrg{
816f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
817f29dbc25Smrg    int pitch, lines;
818170d5fdcSmrg    ExaOffscreenArea *vidmem;
819f29dbc25Smrg    struct OffscreenPrivRec *pPriv;
820f29dbc25Smrg
821f29dbc25Smrg    if (w > 1024 || h > 1024)
82204007ebaSmrg        return BadAlloc;
823f29dbc25Smrg
824f29dbc25Smrg    /* The width needs to be word aligned */
825f29dbc25Smrg    w = (w + 1) & ~1;
826f29dbc25Smrg
827f29dbc25Smrg    pitch = ((w << 1) + 15) & ~15;
828f29dbc25Smrg    lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch;
829f29dbc25Smrg
8307aef237fSmrg    /* FIXME: is lines the right parameter to use here,
8317aef237fSmrg     * or should it be height * pitch? */
83204007ebaSmrg    vidmem = exaOffscreenAlloc(pScrni->pScreen, lines, 4, TRUE, NULL, NULL);
833f29dbc25Smrg
834f29dbc25Smrg    if (vidmem == NULL) {
83504007ebaSmrg        ErrorF("Error while allocating an offscreen region.\n");
83604007ebaSmrg        return BadAlloc;
837f29dbc25Smrg    }
838f29dbc25Smrg
839f29dbc25Smrg    surface->width = w;
840f29dbc25Smrg    surface->height = h;
841f29dbc25Smrg
842170d5fdcSmrg    surface->pitches = malloc(sizeof(int));
843f29dbc25Smrg
844170d5fdcSmrg    surface->offsets = malloc(sizeof(int));
845f29dbc25Smrg
846170d5fdcSmrg    pPriv = malloc(sizeof(struct OffscreenPrivRec));
847f29dbc25Smrg
848f29dbc25Smrg    if (pPriv && surface->pitches && surface->offsets) {
849f29dbc25Smrg
85004007ebaSmrg        pPriv->vidmem = vidmem;
851f29dbc25Smrg
85204007ebaSmrg        pPriv->isOn = FALSE;
853f29dbc25Smrg
85404007ebaSmrg        surface->pScrn = pScrni;
85504007ebaSmrg        surface->id = id;
85604007ebaSmrg        surface->pitches[0] = pitch;
85704007ebaSmrg        surface->offsets[0] = vidmem->offset;
85804007ebaSmrg        surface->devPrivate.ptr = (pointer) pPriv;
859f29dbc25Smrg
86004007ebaSmrg        return Success;
861f29dbc25Smrg    }
862f29dbc25Smrg
863f29dbc25Smrg    if (surface->offsets)
86404007ebaSmrg        free(surface->offsets);
865f29dbc25Smrg
866f29dbc25Smrg    if (surface->pitches)
86704007ebaSmrg        free(surface->pitches);
868f29dbc25Smrg
869170d5fdcSmrg    if (vidmem) {
87004007ebaSmrg        exaOffscreenFree(pScrni->pScreen, vidmem);
87104007ebaSmrg        vidmem = NULL;
872170d5fdcSmrg    }
873f29dbc25Smrg
874f29dbc25Smrg    return BadAlloc;
875f29dbc25Smrg}
876f29dbc25Smrg
877f29dbc25Smrgstatic int
878f29dbc25SmrgLXStopSurface(XF86SurfacePtr surface)
879f29dbc25Smrg{
880f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
88104007ebaSmrg        surface->devPrivate.ptr;
882f29dbc25Smrg
883f29dbc25Smrg    pPriv->isOn = FALSE;
884f29dbc25Smrg    return Success;
885f29dbc25Smrg}
886f29dbc25Smrg
887f29dbc25Smrgstatic int
888f29dbc25SmrgLXFreeSurface(XF86SurfacePtr surface)
889f29dbc25Smrg{
890f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
89104007ebaSmrg        surface->devPrivate.ptr;
892f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
893f29dbc25Smrg
894f29dbc25Smrg    if (pPriv->isOn)
89504007ebaSmrg        LXStopSurface(surface);
896f29dbc25Smrg
897f29dbc25Smrg    if (pPriv->vidmem) {
89804007ebaSmrg        exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
89904007ebaSmrg        pPriv->vidmem = NULL;
900f29dbc25Smrg    }
901f29dbc25Smrg
902170d5fdcSmrg    free(surface->pitches);
903170d5fdcSmrg    free(surface->offsets);
904170d5fdcSmrg    free(surface->devPrivate.ptr);
905f29dbc25Smrg
906f29dbc25Smrg    return Success;
907f29dbc25Smrg}
908f29dbc25Smrg
909f29dbc25Smrgstatic int
91004007ebaSmrgLXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value)
911f29dbc25Smrg{
912f29dbc25Smrg    return LXGetPortAttribute(pScrni, attribute, value,
91304007ebaSmrg                              (pointer) (GET_PORT_PRIVATE(pScrni)));
914f29dbc25Smrg}
915f29dbc25Smrg
916f29dbc25Smrgstatic int
917f29dbc25SmrgLXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
918f29dbc25Smrg{
919f29dbc25Smrg    return LXSetPortAttribute(pScrni, attribute, value,
92004007ebaSmrg                              (pointer) (GET_PORT_PRIVATE(pScrni)));
921f29dbc25Smrg}
922f29dbc25Smrg
923f29dbc25Smrgstatic void
924f29dbc25SmrgLXInitOffscreenImages(ScreenPtr pScrn)
925f29dbc25Smrg{
926f29dbc25Smrg    XF86OffscreenImagePtr offscreenImages;
927f29dbc25Smrg
928f29dbc25Smrg    /* need to free this someplace */
929170d5fdcSmrg    if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
93004007ebaSmrg        return;
931f29dbc25Smrg
932f29dbc25Smrg    offscreenImages[0].image = &Images[0];
933f29dbc25Smrg    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
934f29dbc25Smrg    offscreenImages[0].alloc_surface = LXAllocateSurface;
935f29dbc25Smrg    offscreenImages[0].free_surface = LXFreeSurface;
936f29dbc25Smrg    offscreenImages[0].display = LXDisplaySurface;
937f29dbc25Smrg    offscreenImages[0].stop = LXStopSurface;
938f29dbc25Smrg    offscreenImages[0].setAttribute = LXSetSurfaceAttribute;
939f29dbc25Smrg    offscreenImages[0].getAttribute = LXGetSurfaceAttribute;
940f29dbc25Smrg    offscreenImages[0].max_width = 1024;
941f29dbc25Smrg    offscreenImages[0].max_height = 1024;
942f29dbc25Smrg    offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes);
943f29dbc25Smrg    offscreenImages[0].attributes = Attributes;
944f29dbc25Smrg
945f29dbc25Smrg    xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
946f29dbc25Smrg}
947f29dbc25Smrg
948f29dbc25Smrgvoid
949f29dbc25SmrgLXInitVideo(ScreenPtr pScrn)
950f29dbc25Smrg{
951f29dbc25Smrg    GeodeRec *pGeode;
95204007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
953f29dbc25Smrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
954f29dbc25Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
955f29dbc25Smrg    int num_adaptors;
956f29dbc25Smrg
957f29dbc25Smrg    pGeode = GEODEPTR(pScrni);
958f29dbc25Smrg
959f29dbc25Smrg    if (pGeode->NoAccel) {
96004007ebaSmrg        ErrorF("Cannot run Xv without accelerations!\n");
96104007ebaSmrg        return;
962f29dbc25Smrg    }
963f29dbc25Smrg
964f29dbc25Smrg    if (!(newAdaptor = LXSetupImageVideo(pScrn))) {
96504007ebaSmrg        ErrorF("Error while setting up the adaptor.\n");
96604007ebaSmrg        return;
967f29dbc25Smrg    }
968f29dbc25Smrg
969f29dbc25Smrg    LXInitOffscreenImages(pScrn);
970f29dbc25Smrg
971f29dbc25Smrg    num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
972f29dbc25Smrg
973f29dbc25Smrg    if (!num_adaptors) {
97404007ebaSmrg        num_adaptors = 1;
97504007ebaSmrg        adaptors = &newAdaptor;
97604007ebaSmrg    }
97704007ebaSmrg    else {
97804007ebaSmrg        newAdaptors =
97904007ebaSmrg            malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
98004007ebaSmrg
98104007ebaSmrg        if (newAdaptors) {
98204007ebaSmrg            memcpy(newAdaptors, adaptors, num_adaptors *
98304007ebaSmrg                   sizeof(XF86VideoAdaptorPtr));
98404007ebaSmrg            newAdaptors[num_adaptors] = newAdaptor;
98504007ebaSmrg            adaptors = newAdaptors;
98604007ebaSmrg            num_adaptors++;
98704007ebaSmrg        }
98804007ebaSmrg        else
98904007ebaSmrg            ErrorF("Memory error while setting up the adaptor\n");
990f29dbc25Smrg    }
991f29dbc25Smrg
992f29dbc25Smrg    if (num_adaptors)
99304007ebaSmrg        xf86XVScreenInit(pScrn, adaptors, num_adaptors);
994f29dbc25Smrg
995f29dbc25Smrg    if (newAdaptors)
99604007ebaSmrg        free(newAdaptors);
997f29dbc25Smrg}
998