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
3900be8644Schristos#include "xorg-server.h"
4000be8644Schristos
41f29dbc25Smrg#include "xf86.h"
42f29dbc25Smrg#include "xf86_OSproc.h"
43f29dbc25Smrg#include "compiler.h"
44f29dbc25Smrg#include "xf86PciInfo.h"
45f29dbc25Smrg#include "xf86Pci.h"
46f29dbc25Smrg#include "xf86fbman.h"
47f29dbc25Smrg#include "regionstr.h"
48f29dbc25Smrg#include "dixstruct.h"
49f29dbc25Smrg
50f29dbc25Smrg#include "geode.h"
51f29dbc25Smrg#include "xf86xv.h"
52f29dbc25Smrg#include <X11/extensions/Xv.h>
53f29dbc25Smrg#include "fourcc.h"
54f29dbc25Smrg#include "geode_fourcc.h"
55f29dbc25Smrg#include "cim/cim_defs.h"
56f29dbc25Smrg#include "cim/cim_regs.h"
57f29dbc25Smrg
58f29dbc25Smrg#define OFF_DELAY 		200
59f29dbc25Smrg#define FREE_DELAY 		60000
60f29dbc25Smrg#define OFF_TIMER 		0x01
61f29dbc25Smrg#define FREE_TIMER		0x02
62f29dbc25Smrg#define CLIENT_VIDEO_ON	0x04
63f29dbc25Smrg#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
64f29dbc25Smrg
65f29dbc25Smrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
6604007ebaSmrg#ifndef ARRAY_SIZE
67f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
6804007ebaSmrg#endif
69f29dbc25Smrg
70f29dbc25Smrg/* Local function prototypes */
71f29dbc25Smrgstatic void LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit);
72f29dbc25Smrg
73f29dbc25Smrgstatic void
7404007ebaSmrg
7504007ebaSmrg
76f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
7704007ebaSmrg               BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH);
78f29dbc25Smrg
79f29dbc25Smrgstatic void LXResetVideo(ScrnInfoPtr pScrni);
80f29dbc25Smrg
81f29dbc25Smrgstatic XF86VideoEncodingRec DummyEncoding[1] = {
82f29dbc25Smrg    {0, "XV_IMAGE", 1024, 1024, {1, 1}}
83f29dbc25Smrg};
84f29dbc25Smrg
85f29dbc25Smrgstatic XF86VideoFormatRec Formats[] = {
86f29dbc25Smrg    {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
87f29dbc25Smrg};
88f29dbc25Smrg
89f29dbc25Smrgstatic XF86AttributeRec Attributes[] = {
90f29dbc25Smrg    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
91f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
92f29dbc25Smrg    {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
93f29dbc25Smrg};
94f29dbc25Smrg
95f29dbc25Smrgstatic XF86ImageRec Images[] = {
96f29dbc25Smrg    XVIMAGE_UYVY,
97f29dbc25Smrg    XVIMAGE_YUY2,
98f29dbc25Smrg    XVIMAGE_Y2YU,
99f29dbc25Smrg    XVIMAGE_YVYU,
100f29dbc25Smrg    XVIMAGE_Y800,
101f29dbc25Smrg    XVIMAGE_I420,
102f29dbc25Smrg    XVIMAGE_YV12,
103f29dbc25Smrg    XVIMAGE_RGB565
104f29dbc25Smrg};
105f29dbc25Smrg
10604007ebaSmrgtypedef struct {
107170d5fdcSmrg    ExaOffscreenArea *vidmem;
108f29dbc25Smrg    RegionRec clip;
109f29dbc25Smrg    CARD32 filter;
110f29dbc25Smrg    CARD32 colorKey;
111f29dbc25Smrg    CARD32 colorKeyMode;
112f29dbc25Smrg    CARD32 videoStatus;
113f29dbc25Smrg    Time offTime;
114f29dbc25Smrg    Time freeTime;
115f29dbc25Smrg    short pwidth, pheight;
116f29dbc25Smrg} GeodePortPrivRec, *GeodePortPrivPtr;
117f29dbc25Smrg
118f29dbc25Smrg#define GET_PORT_PRIVATE(pScrni) \
119f29dbc25Smrg   (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr)
120f29dbc25Smrg
121f29dbc25Smrgstatic void
122f29dbc25SmrgLXCopyFromSys(GeodeRec * pGeode, unsigned char *src, unsigned int dst,
12304007ebaSmrg              int dstPitch, int srcPitch, int h, int w)
124f29dbc25Smrg{
125f29dbc25Smrg
126f29dbc25Smrg    gp_declare_blt(0);
127170d5fdcSmrg    gp_set_bpp((srcPitch / w) << 3);
128f29dbc25Smrg
129f29dbc25Smrg    gp_set_raster_operation(0xCC);
130f29dbc25Smrg    gp_set_strides(dstPitch, srcPitch);
131f29dbc25Smrg    gp_set_solid_pattern(0);
132f29dbc25Smrg
133f29dbc25Smrg    gp_color_bitmap_to_screen_blt(dst, 0, w, h, src, srcPitch);
134f29dbc25Smrg}
135f29dbc25Smrg
136f29dbc25Smrgstatic void
137f29dbc25SmrgLXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv)
138f29dbc25Smrg{
139f29dbc25Smrg    int red, green, blue;
140f29dbc25Smrg    unsigned long key;
141f29dbc25Smrg
142f29dbc25Smrg    switch (pScrni->depth) {
143f29dbc25Smrg    case 8:
14404007ebaSmrg        vg_get_display_palette_entry(pPriv->colorKey & 0xFF, &key);
14504007ebaSmrg        red = ((key >> 16) & 0xFF);
14604007ebaSmrg        green = ((key >> 8) & 0xFF);
14704007ebaSmrg        blue = (key & 0xFF);
14804007ebaSmrg        break;
149f29dbc25Smrg    case 16:
15004007ebaSmrg        red = (pPriv->colorKey & pScrni->mask.red) >>
15104007ebaSmrg            pScrni->offset.red << (8 - pScrni->weight.red);
15204007ebaSmrg        green = (pPriv->colorKey & pScrni->mask.green) >>
15304007ebaSmrg            pScrni->offset.green << (8 - pScrni->weight.green);
15404007ebaSmrg        blue = (pPriv->colorKey & pScrni->mask.blue) >>
15504007ebaSmrg            pScrni->offset.blue << (8 - pScrni->weight.blue);
15604007ebaSmrg        break;
157f29dbc25Smrg    default:
15804007ebaSmrg        /* for > 16 bpp we send in the mask in xf86SetWeight. This
15904007ebaSmrg         * function is providing the offset by 1 more. So we take
16004007ebaSmrg         * this as a special case and subtract 1 for > 16
16104007ebaSmrg         */
16204007ebaSmrg
16304007ebaSmrg        red = (pPriv->colorKey & pScrni->mask.red) >>
16404007ebaSmrg            (pScrni->offset.red - 1) << (8 - pScrni->weight.red);
16504007ebaSmrg        green = (pPriv->colorKey & pScrni->mask.green) >>
16604007ebaSmrg            (pScrni->offset.green - 1) << (8 - pScrni->weight.green);
16704007ebaSmrg        blue = (pPriv->colorKey & pScrni->mask.blue) >>
16804007ebaSmrg            (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue);
16904007ebaSmrg        break;
170f29dbc25Smrg    }
171f29dbc25Smrg
172f29dbc25Smrg    df_set_video_color_key((blue | (green << 8) | (red << 16)),
17304007ebaSmrg                           0xFFFFFF, (pPriv->colorKeyMode == 0));
174f29dbc25Smrg
175f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
176f29dbc25Smrg}
177f29dbc25Smrg
178f29dbc25Smrg/* A structure full of the scratch information that originates in the copy routines,
179f29dbc25Smrg   but is needed for the video display - maybe we should figure out a way to attach
180f29dbc25Smrg   this to structures?  I hate to put it in pGeode since it will increase the size of
181f29dbc25Smrg   the structure, and possibly cause us cache issues.
182f29dbc25Smrg*/
183f29dbc25Smrg
18404007ebaSmrgstruct {
185f29dbc25Smrg    unsigned int dstOffset;
186f29dbc25Smrg    unsigned int dstPitch;
187f29dbc25Smrg    unsigned int UVPitch;
188f29dbc25Smrg    unsigned int UDstOffset;
189f29dbc25Smrg    unsigned int VDstOffset;
190f29dbc25Smrg} videoScratch;
191f29dbc25Smrg
192f29dbc25Smrg/* Copy planar YUV data */
193f29dbc25Smrg
194f29dbc25Smrgstatic Bool
19504007ebaSmrgLXAllocateVidMem(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv, int size)
196f29dbc25Smrg{
19704007ebaSmrg    if (!pPriv->vidmem || pPriv->vidmem->size < size) {
19804007ebaSmrg        if (pPriv->vidmem) {
19904007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
20004007ebaSmrg            pPriv->vidmem = NULL;
20104007ebaSmrg        }
20204007ebaSmrg
20304007ebaSmrg        pPriv->vidmem = exaOffscreenAlloc(pScrni->pScreen, size, 4,
20404007ebaSmrg                                          TRUE, NULL, NULL);
20504007ebaSmrg
20604007ebaSmrg        if (pPriv->vidmem == NULL) {
20704007ebaSmrg            ErrorF("Could not allocate memory for the video\n");
20804007ebaSmrg            return FALSE;
20904007ebaSmrg        }
210f29dbc25Smrg    }
211f29dbc25Smrg
212f29dbc25Smrg    return TRUE;
21304007ebaSmrg}
214f29dbc25Smrg
215f29dbc25Smrgstatic Bool
216f29dbc25SmrgLXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf,
21704007ebaSmrg             short x1, short y1, short x2, short y2,
21804007ebaSmrg             int width, int height, pointer data)
219f29dbc25Smrg{
220f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
221f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
222f29dbc25Smrg
223f29dbc25Smrg    unsigned int YSrcPitch, YDstPitch;
224f29dbc25Smrg    unsigned int UVSrcPitch, UVDstPitch;
225f29dbc25Smrg    unsigned int YSrcOffset, YDstOffset;
226f29dbc25Smrg    unsigned int USrcOffset, UDstOffset;
227f29dbc25Smrg    unsigned int VSrcOffset, VDstOffset;
228f29dbc25Smrg
229f29dbc25Smrg    unsigned int size, lines, top, left, pixels;
230f29dbc25Smrg
231f29dbc25Smrg    YSrcPitch = (width + 3) & ~3;
232f29dbc25Smrg    YDstPitch = (width + 31) & ~31;
233f29dbc25Smrg
234f29dbc25Smrg    UVSrcPitch = ((width >> 1) + 3) & ~3;
235f29dbc25Smrg    UVDstPitch = ((width >> 1) + 15) & ~15;
236f29dbc25Smrg
237f29dbc25Smrg    USrcOffset = YSrcPitch * height;
238f29dbc25Smrg    VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
239f29dbc25Smrg
240f29dbc25Smrg    UDstOffset = YDstPitch * height;
241f29dbc25Smrg    VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
242f29dbc25Smrg
243f29dbc25Smrg    size = YDstPitch * height;
244f29dbc25Smrg    size += UVDstPitch * height;
245f29dbc25Smrg
246170d5fdcSmrg    if (LXAllocateVidMem(pScrni, pPriv, size) == FALSE) {
24704007ebaSmrg        ErrorF("Error allocating an offscreen Planar region.\n");
24804007ebaSmrg        return FALSE;
249170d5fdcSmrg    }
250f29dbc25Smrg
251f29dbc25Smrg    /* The top of the source region we want to copy */
252f29dbc25Smrg    top = y1 & ~1;
253f29dbc25Smrg
254f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
255f29dbc25Smrg    left = x1 & ~1;
256f29dbc25Smrg
257f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
258f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
259f29dbc25Smrg
260f29dbc25Smrg    /* Calculate the source offset */
261f29dbc25Smrg    YSrcOffset = (top * YSrcPitch) + left;
262f29dbc25Smrg    USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
263f29dbc25Smrg    VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
264f29dbc25Smrg
265f29dbc25Smrg    /* Calculate the destination offset */
266f29dbc25Smrg    YDstOffset = (top * YDstPitch) + left;
267f29dbc25Smrg    UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
268f29dbc25Smrg    VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
269f29dbc25Smrg
270f29dbc25Smrg    lines = ((y2 + 1) & ~1) - top;
271f29dbc25Smrg
272f29dbc25Smrg    /* Copy Y */
273f29dbc25Smrg
274f29dbc25Smrg    LXCopyFromSys(pGeode, buf + YSrcOffset,
27504007ebaSmrg                  pPriv->vidmem->offset + YDstOffset, YDstPitch, YSrcPitch,
27604007ebaSmrg                  lines, pixels);
277f29dbc25Smrg
278f29dbc25Smrg    /* Copy U + V at the same time */
279f29dbc25Smrg
280f29dbc25Smrg    LXCopyFromSys(pGeode, buf + USrcOffset,
28104007ebaSmrg                  pPriv->vidmem->offset + UDstOffset, UVDstPitch, UVSrcPitch,
28204007ebaSmrg                  lines, pixels >> 1);
283f29dbc25Smrg
284f29dbc25Smrg    videoScratch.dstOffset = pPriv->vidmem->offset + YDstOffset;
285f29dbc25Smrg    videoScratch.dstPitch = YDstPitch;
286f29dbc25Smrg    videoScratch.UVPitch = UVDstPitch;
287f29dbc25Smrg    videoScratch.UDstOffset = pPriv->vidmem->offset + UDstOffset;
288f29dbc25Smrg    videoScratch.VDstOffset = pPriv->vidmem->offset + VDstOffset;
289f29dbc25Smrg
290f29dbc25Smrg    return TRUE;
291f29dbc25Smrg}
292f29dbc25Smrg
293f29dbc25Smrgstatic Bool
294f29dbc25SmrgLXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf,
29504007ebaSmrg             short x1, short y1, short x2, short y2,
29604007ebaSmrg             int width, int height, pointer data)
297f29dbc25Smrg{
298f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
299f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
300f29dbc25Smrg    unsigned int dstPitch, srcPitch;
301f29dbc25Smrg    unsigned int srcOffset, dstOffset;
302f29dbc25Smrg    unsigned int lines, top, left, pixels;
303f29dbc25Smrg
304f29dbc25Smrg    dstPitch = ((width << 1) + 3) & ~3;
305f29dbc25Smrg    srcPitch = (width << 1);
306f29dbc25Smrg
307f29dbc25Smrg    lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
308f29dbc25Smrg
3097aef237fSmrg    if (LXAllocateVidMem(pScrni, pPriv, dstPitch * height) == FALSE) {
31004007ebaSmrg        ErrorF("Error allocating an offscreen Packed region.\n");
31104007ebaSmrg        return FALSE;
312170d5fdcSmrg    }
313f29dbc25Smrg
314f29dbc25Smrg    /* The top of the source region we want to copy */
315f29dbc25Smrg    top = y1;
316f29dbc25Smrg
317f29dbc25Smrg    /* The left hand side of the source region, aligned on a word */
318f29dbc25Smrg    left = x1 & ~1;
319f29dbc25Smrg
320f29dbc25Smrg    /* Number of bytes to copy, also word aligned */
321f29dbc25Smrg    pixels = ((x2 + 1) & ~1) - left;
322f29dbc25Smrg
323f29dbc25Smrg    /* Adjust the incoming buffer */
324f29dbc25Smrg    srcOffset = (top * srcPitch) + left;
325f29dbc25Smrg
326f29dbc25Smrg    /* Calculate the destination offset */
327f29dbc25Smrg    dstOffset = pPriv->vidmem->offset + (top * dstPitch) + left;
328f29dbc25Smrg
329f29dbc25Smrg    /* Make the copy happen */
330f29dbc25Smrg
331f29dbc25Smrg    if (id == FOURCC_Y800) {
332f29dbc25Smrg
33304007ebaSmrg        /* Use the shared (unaccelerated) greyscale copy - you could probably
33404007ebaSmrg         * accelerate it using a 2 pass blit and patterns, but it doesn't really
33504007ebaSmrg         * seem worth it
33604007ebaSmrg         */
337f29dbc25Smrg
33804007ebaSmrg        GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset,
33904007ebaSmrg                           srcPitch, dstPitch, height, pixels >> 1);
34004007ebaSmrg    }
34104007ebaSmrg    else
34204007ebaSmrg        /* FIXME: should lines be used here instead of height? */
34304007ebaSmrg        LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch,
34404007ebaSmrg                      height, pixels);
345f29dbc25Smrg
346f29dbc25Smrg    videoScratch.dstOffset = dstOffset;
347f29dbc25Smrg    videoScratch.dstPitch = dstPitch;
348f29dbc25Smrg
349f29dbc25Smrg    return TRUE;
350f29dbc25Smrg}
351f29dbc25Smrg
352f29dbc25Smrgstatic void
353f29dbc25SmrgLXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
35404007ebaSmrg               BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH)
355f29dbc25Smrg{
356f29dbc25Smrg    long ystart, xend, yend;
357f29dbc25Smrg    unsigned long lines = 0;
358f29dbc25Smrg    unsigned long yExtra, uvExtra = 0;
359f29dbc25Smrg    DF_VIDEO_POSITION vidPos;
360f29dbc25Smrg    DF_VIDEO_SOURCE_PARAMS vSrcParams;
361f29dbc25Smrg    int err;
362f29dbc25Smrg
363f29dbc25Smrg    memset(&vSrcParams, 0, sizeof(vSrcParams));
364f29dbc25Smrg
365f29dbc25Smrg    gp_wait_until_idle();
366f29dbc25Smrg
367f29dbc25Smrg    switch (id) {
368f29dbc25Smrg    case FOURCC_UYVY:
36904007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_UYVY;
37004007ebaSmrg        break;
371f29dbc25Smrg
372f29dbc25Smrg    case FOURCC_Y800:
373f29dbc25Smrg    case FOURCC_YV12:
374f29dbc25Smrg    case FOURCC_I420:
37504007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3;
37604007ebaSmrg        break;
377f29dbc25Smrg    case FOURCC_YUY2:
37804007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_YUYV;
37904007ebaSmrg        break;
380f29dbc25Smrg    case FOURCC_Y2YU:
38104007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_Y2YU;
38204007ebaSmrg        break;
383f29dbc25Smrg    case FOURCC_YVYU:
38404007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_YVYU;
38504007ebaSmrg        break;
386f29dbc25Smrg    case FOURCC_RGB565:
38704007ebaSmrg        vSrcParams.video_format = DF_VIDFMT_RGB;
38804007ebaSmrg        break;
389f29dbc25Smrg    }
390f29dbc25Smrg
391f29dbc25Smrg    vSrcParams.width = width;
392f29dbc25Smrg    vSrcParams.height = height;
393f29dbc25Smrg    vSrcParams.y_pitch = videoScratch.dstPitch;
394f29dbc25Smrg    vSrcParams.uv_pitch = videoScratch.UVPitch;
395f29dbc25Smrg
396f29dbc25Smrg    /* Set up scaling */
397f29dbc25Smrg    df_set_video_filter_coefficients(NULL, 1);
398f29dbc25Smrg
399f29dbc25Smrg    err = df_set_video_scale(width, height, drawW, drawH,
40004007ebaSmrg                             DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY);
401f29dbc25Smrg    if (err != CIM_STATUS_OK) {
40204007ebaSmrg        /* Note the problem, but do nothing for now. */
40304007ebaSmrg        ErrorF("Video scale factor too large: %dx%d -> %dx%d\n",
40404007ebaSmrg               width, height, drawW, drawH);
405f29dbc25Smrg    }
406f29dbc25Smrg
407f29dbc25Smrg    /* Figure out clipping */
408f29dbc25Smrg
409f29dbc25Smrg    xend = dstBox->x2;
410f29dbc25Smrg    yend = dstBox->y2;
411f29dbc25Smrg
412f29dbc25Smrg    if (dstBox->y1 < 0) {
41304007ebaSmrg        if (srcH < drawH)
41404007ebaSmrg            lines = ((-dstBox->y1) * srcH) / drawH;
41504007ebaSmrg        else
41604007ebaSmrg            lines = (-dstBox->y1);
41704007ebaSmrg
41804007ebaSmrg        ystart = 0;
41904007ebaSmrg        drawH += dstBox->y1;
42004007ebaSmrg    }
42104007ebaSmrg    else {
42204007ebaSmrg        ystart = dstBox->y1;
42304007ebaSmrg        lines = 0;
424f29dbc25Smrg    }
425f29dbc25Smrg
426f29dbc25Smrg    yExtra = lines * videoScratch.dstPitch;
427f29dbc25Smrg    uvExtra = (lines >> 1) * videoScratch.UVPitch;
428f29dbc25Smrg
429f29dbc25Smrg    memset(&vidPos, 0, sizeof(vidPos));
430f29dbc25Smrg
431f29dbc25Smrg    vidPos.x = dstBox->x1;
432f29dbc25Smrg    vidPos.y = ystart;
433f29dbc25Smrg    vidPos.width = xend - dstBox->x1;
434f29dbc25Smrg    vidPos.height = yend - ystart;
435f29dbc25Smrg
436f29dbc25Smrg    df_set_video_position(&vidPos);
437f29dbc25Smrg
438f29dbc25Smrg    vSrcParams.y_offset = videoScratch.dstOffset + yExtra;
439f29dbc25Smrg
440f29dbc25Smrg    switch (id) {
441f29dbc25Smrg    case FOURCC_Y800:
442f29dbc25Smrg    case FOURCC_I420:
44304007ebaSmrg        vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra;
44404007ebaSmrg        vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra;
44504007ebaSmrg        break;
446f29dbc25Smrg    case FOURCC_YV12:
44704007ebaSmrg        vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra;
44804007ebaSmrg        vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra;
44904007ebaSmrg        break;
450f29dbc25Smrg
451f29dbc25Smrg    default:
45204007ebaSmrg        vSrcParams.u_offset = vSrcParams.v_offset = 0;
45304007ebaSmrg        break;
454f29dbc25Smrg    }
455f29dbc25Smrg
456f29dbc25Smrg    vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING;
457f29dbc25Smrg    df_configure_video_source(&vSrcParams, &vSrcParams);
458f29dbc25Smrg
459f29dbc25Smrg    /* Turn on the video palette */
460f29dbc25Smrg    df_set_video_palette(NULL);
461f29dbc25Smrg    df_set_video_enable(1, 0);
462f29dbc25Smrg}
463f29dbc25Smrg
464f29dbc25Smrgstatic int
465f29dbc25SmrgLXPutImage(ScrnInfoPtr pScrni,
46604007ebaSmrg           short srcX, short srcY, short drawX, short drawY,
46704007ebaSmrg           short srcW, short srcH, short drawW, short drawH,
46804007ebaSmrg           int id, unsigned char *buf,
46904007ebaSmrg           short width, short height, Bool sync, RegionPtr clipBoxes,
47004007ebaSmrg           pointer data, DrawablePtr pDraw)
471f29dbc25Smrg{
472f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
473f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
474f29dbc25Smrg    INT32 x1, x2, y1, y2;
475f29dbc25Smrg    BoxRec dstBox;
476f29dbc25Smrg    Bool ret;
477f29dbc25Smrg
478f29dbc25Smrg    if (pGeode->rotation != RR_Rotate_0)
47904007ebaSmrg        return Success;
480f29dbc25Smrg
481f29dbc25Smrg    if (srcW <= 0 || srcH <= 0) {
48204007ebaSmrg        return Success;
483f29dbc25Smrg    }
484f29dbc25Smrg
485f29dbc25Smrg    if (drawW <= 0 || drawH <= 0) {
48604007ebaSmrg        return Success;
487f29dbc25Smrg    }
488f29dbc25Smrg
489f29dbc25Smrg    if (drawW > 16384)
49004007ebaSmrg        drawW = 16384;
491f29dbc25Smrg
492f29dbc25Smrg    memset(&videoScratch, 0, sizeof(videoScratch));
493f29dbc25Smrg
494f29dbc25Smrg    x1 = srcX;
495f29dbc25Smrg    x2 = srcX + srcW;
496f29dbc25Smrg    y1 = srcY;
497f29dbc25Smrg    y2 = srcY + srcH;
498f29dbc25Smrg
499f29dbc25Smrg    dstBox.x1 = drawX;
500f29dbc25Smrg    dstBox.x2 = drawX + drawW;
501f29dbc25Smrg    dstBox.y1 = drawY;
502f29dbc25Smrg    dstBox.y2 = drawY + drawH;
503f29dbc25Smrg
504f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
505f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
506f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
507f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
508f29dbc25Smrg
509f29dbc25Smrg    if (id == FOURCC_YV12 || id == FOURCC_I420)
51004007ebaSmrg        ret = LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width,
51104007ebaSmrg                           height, data);
512f29dbc25Smrg    else
51304007ebaSmrg        ret = LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width,
51404007ebaSmrg                           height, data);
515f29dbc25Smrg
516f29dbc25Smrg    if (ret == FALSE)
51704007ebaSmrg        return BadAlloc;
51804007ebaSmrg
519f29dbc25Smrg    if (!RegionsEqual(&pPriv->clip, clipBoxes) ||
52004007ebaSmrg        (drawW != pPriv->pwidth || drawH != pPriv->pheight)) {
52104007ebaSmrg        REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
522f29dbc25Smrg
52304007ebaSmrg        if (pPriv->colorKeyMode == 0) {
52404007ebaSmrg            xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
52504007ebaSmrg        }
526f29dbc25Smrg
52704007ebaSmrg        LXDisplayVideo(pScrni, id, width, height, &dstBox,
52804007ebaSmrg                       srcW, srcH, drawW, drawH);
52904007ebaSmrg        pPriv->pwidth = drawW;
53004007ebaSmrg        pPriv->pheight = drawH;
531f29dbc25Smrg    }
532f29dbc25Smrg
533f29dbc25Smrg    pPriv->videoStatus = CLIENT_VIDEO_ON;
534f29dbc25Smrg
535f29dbc25Smrg    return Success;
536f29dbc25Smrg}
537f29dbc25Smrg
538f29dbc25Smrgstatic void
539f29dbc25SmrgLXQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
54004007ebaSmrg                short vidW, short vidH, short drawW, short drawH,
54104007ebaSmrg                unsigned int *retW, unsigned int *retH, pointer data)
542f29dbc25Smrg{
543f29dbc25Smrg    *retW = drawW > 16384 ? 16384 : drawW;
544f29dbc25Smrg    *retH = drawH;
545f29dbc25Smrg}
546f29dbc25Smrg
547f29dbc25Smrgstatic Atom xvColorKey, xvColorKeyMode, xvFilter;
548f29dbc25Smrg
549f29dbc25Smrgstatic int
550f29dbc25SmrgLXGetPortAttribute(ScrnInfoPtr pScrni,
55104007ebaSmrg                   Atom attribute, INT32 *value, pointer data)
552f29dbc25Smrg{
553f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
554f29dbc25Smrg
555f29dbc25Smrg    if (attribute == xvColorKey)
55604007ebaSmrg        *value = pPriv->colorKey;
557f29dbc25Smrg    else if (attribute == xvColorKeyMode)
55804007ebaSmrg        *value = pPriv->colorKeyMode;
559f29dbc25Smrg    else if (attribute == xvFilter)
56004007ebaSmrg        *value = pPriv->filter;
561f29dbc25Smrg    else
56204007ebaSmrg        return BadMatch;
563f29dbc25Smrg
564f29dbc25Smrg    return Success;
565f29dbc25Smrg}
566f29dbc25Smrg
567f29dbc25Smrgstatic int
568f29dbc25SmrgLXSetPortAttribute(ScrnInfoPtr pScrni,
56904007ebaSmrg                   Atom attribute, INT32 value, pointer data)
570f29dbc25Smrg{
571f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
572f29dbc25Smrg
573f29dbc25Smrg    gp_wait_until_idle();
574f29dbc25Smrg
575f29dbc25Smrg    if (attribute == xvColorKey) {
57604007ebaSmrg        pPriv->colorKey = value;
57704007ebaSmrg        LXSetColorkey(pScrni, pPriv);
57804007ebaSmrg    }
57904007ebaSmrg    else if (attribute == xvColorKeyMode) {
58004007ebaSmrg        pPriv->colorKeyMode = value;
58104007ebaSmrg        LXSetColorkey(pScrni, pPriv);
58204007ebaSmrg    }
58304007ebaSmrg    else if (attribute == xvFilter) {
58404007ebaSmrg        if ((value < 0) || (value > 1))
58504007ebaSmrg            return BadValue;
58604007ebaSmrg        pPriv->filter = value;
58704007ebaSmrg    }
58804007ebaSmrg    else
58904007ebaSmrg        return BadMatch;
590f29dbc25Smrg
591f29dbc25Smrg    return Success;
592f29dbc25Smrg}
593f29dbc25Smrg
594f29dbc25Smrgstatic void
595f29dbc25SmrgLXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
596f29dbc25Smrg{
597f29dbc25Smrg    GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
598f29dbc25Smrg
599f29dbc25Smrg    if (pPriv->videoStatus == 0)
60004007ebaSmrg        return;
601f29dbc25Smrg
602f29dbc25Smrg    REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
603f29dbc25Smrg    gp_wait_until_idle();
604f29dbc25Smrg
605f29dbc25Smrg    if (exit) {
60604007ebaSmrg        if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
60704007ebaSmrg            unsigned int val;
60804007ebaSmrg
60904007ebaSmrg            df_set_video_enable(0, 0);
61004007ebaSmrg            /* Put the LUT back in bypass */
61104007ebaSmrg            val = READ_VID32(DF_VID_MISC);
61204007ebaSmrg            WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
61304007ebaSmrg        }
61404007ebaSmrg
61504007ebaSmrg        if (pPriv->vidmem) {
61604007ebaSmrg            exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
61704007ebaSmrg            pPriv->vidmem = NULL;
61804007ebaSmrg        }
61904007ebaSmrg
62004007ebaSmrg        pPriv->videoStatus = 0;
62104007ebaSmrg
62204007ebaSmrg        /* Eh? */
62304007ebaSmrg    }
62404007ebaSmrg    else if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
62504007ebaSmrg        pPriv->videoStatus |= OFF_TIMER;
62604007ebaSmrg        pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
627f29dbc25Smrg    }
628f29dbc25Smrg}
629f29dbc25Smrg
630f29dbc25Smrgstatic void
631f29dbc25SmrgLXResetVideo(ScrnInfoPtr pScrni)
632f29dbc25Smrg{
633f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
634f29dbc25Smrg
635f29dbc25Smrg    if (!pGeode->NoAccel) {
63604007ebaSmrg        GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
637f29dbc25Smrg
63804007ebaSmrg        gp_wait_until_idle();
63904007ebaSmrg        df_set_video_palette(NULL);
640f29dbc25Smrg
64104007ebaSmrg        LXSetColorkey(pScrni, pPriv);
642f29dbc25Smrg    }
643f29dbc25Smrg}
644f29dbc25Smrg
645f29dbc25Smrgstatic void
64604007ebaSmrgLXVidBlockHandler(BLOCKHANDLER_ARGS_DECL)
647f29dbc25Smrg{
64804007ebaSmrg    SCREEN_PTR(arg);
64904007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
650f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
651f29dbc25Smrg    GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
652f29dbc25Smrg
653f29dbc25Smrg    pScrn->BlockHandler = pGeode->BlockHandler;
65404007ebaSmrg    (*pScrn->BlockHandler) (BLOCKHANDLER_ARGS);
655f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
656f29dbc25Smrg
657f29dbc25Smrg    if (pPriv->videoStatus & TIMER_MASK) {
65804007ebaSmrg        Time now = currentTime.milliseconds;
65904007ebaSmrg
66004007ebaSmrg        if (pPriv->videoStatus & OFF_TIMER) {
66104007ebaSmrg            gp_wait_until_idle();
66204007ebaSmrg
66304007ebaSmrg            if (pPriv->offTime < now) {
66404007ebaSmrg                unsigned int val;
66504007ebaSmrg
66604007ebaSmrg                df_set_video_enable(0, 0);
66704007ebaSmrg                pPriv->videoStatus = FREE_TIMER;
66804007ebaSmrg                pPriv->freeTime = now + FREE_DELAY;
66904007ebaSmrg
67004007ebaSmrg                /* Turn off the video palette */
67104007ebaSmrg                val = READ_VID32(DF_VID_MISC);
67204007ebaSmrg                WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
67304007ebaSmrg            }
67404007ebaSmrg        }
67504007ebaSmrg        else {
67604007ebaSmrg            if (pPriv->freeTime < now) {
67704007ebaSmrg
67804007ebaSmrg                if (pPriv->vidmem) {
67904007ebaSmrg                    exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
68004007ebaSmrg                    pPriv->vidmem = NULL;
68104007ebaSmrg                }
68204007ebaSmrg
68304007ebaSmrg                pPriv->videoStatus = 0;
68404007ebaSmrg            }
68504007ebaSmrg        }
686f29dbc25Smrg    }
687f29dbc25Smrg}
688f29dbc25Smrg
689f29dbc25Smrgstatic XF86VideoAdaptorPtr
690f29dbc25SmrgLXSetupImageVideo(ScreenPtr pScrn)
691f29dbc25Smrg{
69204007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
693f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
694f29dbc25Smrg    XF86VideoAdaptorPtr adapt;
695f29dbc25Smrg    GeodePortPrivRec *pPriv;
696f29dbc25Smrg
697170d5fdcSmrg    adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
69804007ebaSmrg                   sizeof(GeodePortPrivRec) + sizeof(DevUnion));
699f29dbc25Smrg
700f29dbc25Smrg    if (adapt == NULL) {
70104007ebaSmrg        ErrorF("Couldn't create the rec\n");
70204007ebaSmrg        return NULL;
703f29dbc25Smrg    }
704f29dbc25Smrg
705f29dbc25Smrg    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
706f29dbc25Smrg    adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
707f29dbc25Smrg
708f29dbc25Smrg    adapt->name = "AMD Geode LX";
709f29dbc25Smrg    adapt->nEncodings = 1;
710f29dbc25Smrg    adapt->pEncodings = DummyEncoding;
711f29dbc25Smrg    adapt->nFormats = ARRAY_SIZE(Formats);
712f29dbc25Smrg    adapt->pFormats = Formats;
713f29dbc25Smrg    adapt->nPorts = 1;
714f29dbc25Smrg    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
715f29dbc25Smrg    pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
716f29dbc25Smrg    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
717f29dbc25Smrg    adapt->pAttributes = Attributes;
718f29dbc25Smrg    adapt->nImages = ARRAY_SIZE(Images);
719f29dbc25Smrg    adapt->nAttributes = ARRAY_SIZE(Attributes);
720f29dbc25Smrg    adapt->pImages = Images;
721f29dbc25Smrg    adapt->PutVideo = NULL;
722f29dbc25Smrg    adapt->PutStill = NULL;
723f29dbc25Smrg    adapt->GetVideo = NULL;
724f29dbc25Smrg    adapt->GetStill = NULL;
725f29dbc25Smrg    adapt->StopVideo = LXStopVideo;
726f29dbc25Smrg    adapt->SetPortAttribute = LXSetPortAttribute;
727f29dbc25Smrg    adapt->GetPortAttribute = LXGetPortAttribute;
728f29dbc25Smrg    adapt->QueryBestSize = LXQueryBestSize;
729f29dbc25Smrg    adapt->PutImage = LXPutImage;
730f29dbc25Smrg
731f29dbc25Smrg    /* Use the common function */
732f29dbc25Smrg    adapt->QueryImageAttributes = GeodeQueryImageAttributes;
733f29dbc25Smrg
734f29dbc25Smrg    pPriv->vidmem = NULL;
735f29dbc25Smrg    pPriv->filter = 0;
736f29dbc25Smrg    pPriv->colorKey = 0;
737f29dbc25Smrg    pPriv->colorKeyMode = 0;
738f29dbc25Smrg    pPriv->videoStatus = 0;
739f29dbc25Smrg    pPriv->pwidth = 0;
740f29dbc25Smrg    pPriv->pheight = 0;
741f29dbc25Smrg
742f29dbc25Smrg    REGION_NULL(pScrn, &pPriv->clip);
743f29dbc25Smrg
744f29dbc25Smrg    pGeode->adaptor = adapt;
745f29dbc25Smrg
746f29dbc25Smrg    pGeode->BlockHandler = pScrn->BlockHandler;
747f29dbc25Smrg    pScrn->BlockHandler = LXVidBlockHandler;
748f29dbc25Smrg
749f29dbc25Smrg    xvColorKey = MAKE_ATOM("XV_COLORKEY");
750f29dbc25Smrg    xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
751f29dbc25Smrg    xvFilter = MAKE_ATOM("XV_FILTER");
752f29dbc25Smrg
753f29dbc25Smrg    LXResetVideo(pScrni);
754f29dbc25Smrg
755f29dbc25Smrg    return adapt;
756f29dbc25Smrg}
757f29dbc25Smrg
758f29dbc25Smrg/* Offscreen surface allocation */
759f29dbc25Smrg
76004007ebaSmrgstruct OffscreenPrivRec {
761170d5fdcSmrg    ExaOffscreenArea *vidmem;
762f29dbc25Smrg    Bool isOn;
763f29dbc25Smrg};
764f29dbc25Smrg
765f29dbc25Smrgstatic int
766f29dbc25SmrgLXDisplaySurface(XF86SurfacePtr surface,
76704007ebaSmrg                 short srcX, short srcY, short drawX, short drawY,
76804007ebaSmrg                 short srcW, short srcH, short drawW, short drawH,
76904007ebaSmrg                 RegionPtr clipBoxes)
770f29dbc25Smrg{
771f29dbc25Smrg    struct OffscreenPrivRec *pPriv =
77204007ebaSmrg        (struct OffscreenPrivRec *) surface->devPrivate.ptr;
773f29dbc25Smrg
774f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
775f29dbc25Smrg    GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
776f29dbc25Smrg
777f29dbc25Smrg    BoxRec dstBox;
778f29dbc25Smrg
779f29dbc25Smrg    dstBox.x1 = drawX;
780f29dbc25Smrg    dstBox.x2 = drawX + drawW;
781f29dbc25Smrg    dstBox.y1 = drawY;
782f29dbc25Smrg    dstBox.y2 = drawY + drawH;
783f29dbc25Smrg
784f29dbc25Smrg    if ((drawW <= 0) | (drawH <= 0))
78504007ebaSmrg        return Success;
786f29dbc25Smrg
787f29dbc25Smrg    /* Is this still valid? */
788f29dbc25Smrg
789f29dbc25Smrg    dstBox.x1 -= pScrni->frameX0;
790f29dbc25Smrg    dstBox.x2 -= pScrni->frameX0;
791f29dbc25Smrg    dstBox.y1 -= pScrni->frameY0;
792f29dbc25Smrg    dstBox.y2 -= pScrni->frameY0;
793f29dbc25Smrg
794f29dbc25Smrg    xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
795f29dbc25Smrg
796f29dbc25Smrg    videoScratch.dstOffset = surface->offsets[0];
797f29dbc25Smrg    videoScratch.dstPitch = surface->pitches[0];
798f29dbc25Smrg
799f29dbc25Smrg    LXDisplayVideo(pScrni, surface->id, surface->width, surface->height,
80004007ebaSmrg                   &dstBox, srcW, srcH, drawW, drawH);
801f29dbc25Smrg
802f29dbc25Smrg    pPriv->isOn = TRUE;
803f29dbc25Smrg
804f29dbc25Smrg    if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
80504007ebaSmrg        REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
80604007ebaSmrg        UpdateCurrentTime();
80704007ebaSmrg        portPriv->videoStatus = FREE_TIMER;
80804007ebaSmrg        portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
809f29dbc25Smrg    }
810f29dbc25Smrg
811f29dbc25Smrg    return Success;
812f29dbc25Smrg}
813f29dbc25Smrg
814f29dbc25Smrgstatic int
815f29dbc25SmrgLXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w,
81604007ebaSmrg                  unsigned short h, XF86SurfacePtr surface)
817f29dbc25Smrg{
818f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
819f29dbc25Smrg    int pitch, lines;
820170d5fdcSmrg    ExaOffscreenArea *vidmem;
821f29dbc25Smrg    struct OffscreenPrivRec *pPriv;
822f29dbc25Smrg
823f29dbc25Smrg    if (w > 1024 || h > 1024)
82404007ebaSmrg        return BadAlloc;
825f29dbc25Smrg
826f29dbc25Smrg    /* The width needs to be word aligned */
827f29dbc25Smrg    w = (w + 1) & ~1;
828f29dbc25Smrg
829f29dbc25Smrg    pitch = ((w << 1) + 15) & ~15;
830f29dbc25Smrg    lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch;
831f29dbc25Smrg
8327aef237fSmrg    /* FIXME: is lines the right parameter to use here,
8337aef237fSmrg     * or should it be height * pitch? */
83404007ebaSmrg    vidmem = exaOffscreenAlloc(pScrni->pScreen, lines, 4, TRUE, NULL, NULL);
835f29dbc25Smrg
836f29dbc25Smrg    if (vidmem == NULL) {
83704007ebaSmrg        ErrorF("Error while allocating an offscreen region.\n");
83804007ebaSmrg        return BadAlloc;
839f29dbc25Smrg    }
840f29dbc25Smrg
841f29dbc25Smrg    surface->width = w;
842f29dbc25Smrg    surface->height = h;
843f29dbc25Smrg
844170d5fdcSmrg    surface->pitches = malloc(sizeof(int));
845f29dbc25Smrg
846170d5fdcSmrg    surface->offsets = malloc(sizeof(int));
847f29dbc25Smrg
848170d5fdcSmrg    pPriv = malloc(sizeof(struct OffscreenPrivRec));
849f29dbc25Smrg
850f29dbc25Smrg    if (pPriv && surface->pitches && surface->offsets) {
851f29dbc25Smrg
85204007ebaSmrg        pPriv->vidmem = vidmem;
853f29dbc25Smrg
85404007ebaSmrg        pPriv->isOn = FALSE;
855f29dbc25Smrg
85604007ebaSmrg        surface->pScrn = pScrni;
85704007ebaSmrg        surface->id = id;
85804007ebaSmrg        surface->pitches[0] = pitch;
85904007ebaSmrg        surface->offsets[0] = vidmem->offset;
86004007ebaSmrg        surface->devPrivate.ptr = (pointer) pPriv;
861f29dbc25Smrg
86204007ebaSmrg        return Success;
863f29dbc25Smrg    }
864f29dbc25Smrg
865f29dbc25Smrg    if (surface->offsets)
86604007ebaSmrg        free(surface->offsets);
867f29dbc25Smrg
868f29dbc25Smrg    if (surface->pitches)
86904007ebaSmrg        free(surface->pitches);
870f29dbc25Smrg
871170d5fdcSmrg    if (vidmem) {
87204007ebaSmrg        exaOffscreenFree(pScrni->pScreen, vidmem);
87304007ebaSmrg        vidmem = NULL;
874170d5fdcSmrg    }
875f29dbc25Smrg
876f29dbc25Smrg    return BadAlloc;
877f29dbc25Smrg}
878f29dbc25Smrg
879f29dbc25Smrgstatic int
880f29dbc25SmrgLXStopSurface(XF86SurfacePtr surface)
881f29dbc25Smrg{
882f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
88304007ebaSmrg        surface->devPrivate.ptr;
884f29dbc25Smrg
885f29dbc25Smrg    pPriv->isOn = FALSE;
886f29dbc25Smrg    return Success;
887f29dbc25Smrg}
888f29dbc25Smrg
889f29dbc25Smrgstatic int
890f29dbc25SmrgLXFreeSurface(XF86SurfacePtr surface)
891f29dbc25Smrg{
892f29dbc25Smrg    struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
89304007ebaSmrg        surface->devPrivate.ptr;
894f29dbc25Smrg    ScrnInfoPtr pScrni = surface->pScrn;
895f29dbc25Smrg
896f29dbc25Smrg    if (pPriv->isOn)
89704007ebaSmrg        LXStopSurface(surface);
898f29dbc25Smrg
899f29dbc25Smrg    if (pPriv->vidmem) {
90004007ebaSmrg        exaOffscreenFree(pScrni->pScreen, pPriv->vidmem);
90104007ebaSmrg        pPriv->vidmem = NULL;
902f29dbc25Smrg    }
903f29dbc25Smrg
904170d5fdcSmrg    free(surface->pitches);
905170d5fdcSmrg    free(surface->offsets);
906170d5fdcSmrg    free(surface->devPrivate.ptr);
907f29dbc25Smrg
908f29dbc25Smrg    return Success;
909f29dbc25Smrg}
910f29dbc25Smrg
911f29dbc25Smrgstatic int
91204007ebaSmrgLXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 *value)
913f29dbc25Smrg{
914f29dbc25Smrg    return LXGetPortAttribute(pScrni, attribute, value,
91504007ebaSmrg                              (pointer) (GET_PORT_PRIVATE(pScrni)));
916f29dbc25Smrg}
917f29dbc25Smrg
918f29dbc25Smrgstatic int
919f29dbc25SmrgLXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
920f29dbc25Smrg{
921f29dbc25Smrg    return LXSetPortAttribute(pScrni, attribute, value,
92204007ebaSmrg                              (pointer) (GET_PORT_PRIVATE(pScrni)));
923f29dbc25Smrg}
924f29dbc25Smrg
925f29dbc25Smrgstatic void
926f29dbc25SmrgLXInitOffscreenImages(ScreenPtr pScrn)
927f29dbc25Smrg{
928f29dbc25Smrg    XF86OffscreenImagePtr offscreenImages;
929f29dbc25Smrg
930f29dbc25Smrg    /* need to free this someplace */
931170d5fdcSmrg    if (!(offscreenImages = malloc(sizeof(XF86OffscreenImageRec))))
93204007ebaSmrg        return;
933f29dbc25Smrg
934f29dbc25Smrg    offscreenImages[0].image = &Images[0];
935f29dbc25Smrg    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
936f29dbc25Smrg    offscreenImages[0].alloc_surface = LXAllocateSurface;
937f29dbc25Smrg    offscreenImages[0].free_surface = LXFreeSurface;
938f29dbc25Smrg    offscreenImages[0].display = LXDisplaySurface;
939f29dbc25Smrg    offscreenImages[0].stop = LXStopSurface;
940f29dbc25Smrg    offscreenImages[0].setAttribute = LXSetSurfaceAttribute;
941f29dbc25Smrg    offscreenImages[0].getAttribute = LXGetSurfaceAttribute;
942f29dbc25Smrg    offscreenImages[0].max_width = 1024;
943f29dbc25Smrg    offscreenImages[0].max_height = 1024;
944f29dbc25Smrg    offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes);
945f29dbc25Smrg    offscreenImages[0].attributes = Attributes;
946f29dbc25Smrg
947f29dbc25Smrg    xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
948f29dbc25Smrg}
949f29dbc25Smrg
950f29dbc25Smrgvoid
951f29dbc25SmrgLXInitVideo(ScreenPtr pScrn)
952f29dbc25Smrg{
953f29dbc25Smrg    GeodeRec *pGeode;
95404007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScrn);
955f29dbc25Smrg    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
956f29dbc25Smrg    XF86VideoAdaptorPtr newAdaptor = NULL;
957f29dbc25Smrg    int num_adaptors;
958f29dbc25Smrg
959f29dbc25Smrg    pGeode = GEODEPTR(pScrni);
960f29dbc25Smrg
961f29dbc25Smrg    if (pGeode->NoAccel) {
96204007ebaSmrg        ErrorF("Cannot run Xv without accelerations!\n");
96304007ebaSmrg        return;
964f29dbc25Smrg    }
965f29dbc25Smrg
966f29dbc25Smrg    if (!(newAdaptor = LXSetupImageVideo(pScrn))) {
96704007ebaSmrg        ErrorF("Error while setting up the adaptor.\n");
96804007ebaSmrg        return;
969f29dbc25Smrg    }
970f29dbc25Smrg
971f29dbc25Smrg    LXInitOffscreenImages(pScrn);
972f29dbc25Smrg
973f29dbc25Smrg    num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
974f29dbc25Smrg
975f29dbc25Smrg    if (!num_adaptors) {
97604007ebaSmrg        num_adaptors = 1;
97704007ebaSmrg        adaptors = &newAdaptor;
97804007ebaSmrg    }
97904007ebaSmrg    else {
98004007ebaSmrg        newAdaptors =
98104007ebaSmrg            malloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
98204007ebaSmrg
98304007ebaSmrg        if (newAdaptors) {
98404007ebaSmrg            memcpy(newAdaptors, adaptors, num_adaptors *
98504007ebaSmrg                   sizeof(XF86VideoAdaptorPtr));
98604007ebaSmrg            newAdaptors[num_adaptors] = newAdaptor;
98704007ebaSmrg            adaptors = newAdaptors;
98804007ebaSmrg            num_adaptors++;
98904007ebaSmrg        }
99004007ebaSmrg        else
99104007ebaSmrg            ErrorF("Memory error while setting up the adaptor\n");
992f29dbc25Smrg    }
993f29dbc25Smrg
994f29dbc25Smrg    if (num_adaptors)
99504007ebaSmrg        xf86XVScreenInit(pScrn, adaptors, num_adaptors);
996f29dbc25Smrg
997f29dbc25Smrg    if (newAdaptors)
99804007ebaSmrg        free(newAdaptors);
999f29dbc25Smrg}
1000