summaryrefslogtreecommitdiff
path: root/src/lx_video.c
diff options
context:
space:
mode:
authorJordan Crouse <jordan.crouse@amd.com>2008-03-11 15:43:00 -0600
committerJordan Crouse <jordan.crouse@amd.com>2008-03-14 14:16:42 -0600
commitec8edd1393f482ca42b401463f0f09580aa263a0 (patch)
tree62892967de07f4db2d66f98e4d4c1001262dce9c /src/lx_video.c
parenta7bc1a7f6b439419fc27b669d9d7f99f882d83fe (diff)
First stage of the rename process - get rid of all amd_ prefixes -
change either to geode_ or just to lx_ or gx_ depending on the processor. Change the name in the Makefiles and other collateral
Diffstat (limited to 'src/lx_video.c')
-rw-r--r--src/lx_video.c1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/src/lx_video.c b/src/lx_video.c
new file mode 100644
index 0000000..a9b3672
--- /dev/null
+++ b/src/lx_video.c
@@ -0,0 +1,1025 @@
+/* Copyright (c) 2007 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ */
+
+/* TODO:
+ Add rotation
+ Add back in double buffering?
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "xf86Resources.h"
+#include "compiler.h"
+#include "xf86PciInfo.h"
+#include "xf86Pci.h"
+#include "xf86fbman.h"
+#include "regionstr.h"
+#include "dixstruct.h"
+
+#include "geode.h"
+#include "xf86xv.h"
+#include <X11/extensions/Xv.h>
+#include "fourcc.h"
+#include "geode_fourcc.h"
+#include "cim/cim_defs.h"
+#include "cim/cim_regs.h"
+
+#define OFF_DELAY 200
+#define FREE_DELAY 60000
+#define OFF_TIMER 0x01
+#define FREE_TIMER 0x02
+#define CLIENT_VIDEO_ON 0x04
+#define TIMER_MASK (OFF_TIMER | FREE_TIMER)
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
+
+/* Local function prototypes */
+static void
+LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit);
+
+static void
+LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
+ BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH);
+
+static void
+LXResetVideo(ScrnInfoPtr pScrni);
+
+
+static XF86VideoEncodingRec DummyEncoding[1] = {
+ { 0, "XV_IMAGE", 1024, 1024, {1, 1} }
+};
+
+static XF86VideoFormatRec Formats[] = {
+ {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
+};
+
+static XF86AttributeRec Attributes[] = {
+ {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
+ {XvSettable | XvGettable, 0, 1, "XV_FILTER"},
+ {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"}
+};
+
+static XF86ImageRec Images[] = {
+ XVIMAGE_UYVY,
+ XVIMAGE_YUY2,
+ XVIMAGE_Y2YU,
+ XVIMAGE_YVYU,
+ XVIMAGE_Y800,
+ XVIMAGE_I420,
+ XVIMAGE_YV12,
+ XVIMAGE_RGB565
+};
+
+typedef struct
+{
+ void *area;
+ int offset;
+ RegionRec clip;
+ CARD32 filter;
+ CARD32 colorKey;
+ CARD32 colorKeyMode;
+ CARD32 videoStatus;
+ Time offTime;
+ Time freeTime;
+ short pwidth, pheight;
+} GeodePortPrivRec, *GeodePortPrivPtr;
+
+#define GET_PORT_PRIVATE(pScrni) \
+ (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr)
+
+static void
+LXCopyFromSys(GeodeRec *pGeode, unsigned char *src, unsigned int dst,
+ int dstPitch, int srcPitch, int h, int w)
+{
+
+ gp_declare_blt(0);
+ gp_set_bpp(16);
+
+ gp_set_raster_operation(0xCC);
+ gp_set_strides(dstPitch, srcPitch);
+ gp_set_solid_pattern(0);
+
+ gp_color_bitmap_to_screen_blt(dst, 0, w, h, src, srcPitch);
+}
+
+static void
+LXVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area)
+{
+ ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum];
+
+ GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
+
+ if (area == pPriv->area)
+ pPriv->area = NULL;
+
+ LXStopVideo(pScrni, (void *) pPriv, TRUE);
+}
+
+
+static unsigned int
+LXAllocateVidMem(ScrnInfoPtr pScrni, void **memp, int size)
+{
+ ExaOffscreenArea *area = *memp;
+
+ if (area != NULL) {
+ if (area->size >= size)
+ return area->offset;
+
+ exaOffscreenFree(pScrni->pScreen, area);
+ }
+
+ area = exaOffscreenAlloc(pScrni->pScreen, size, 16, TRUE,
+ LXVideoSave, NULL);
+
+ *memp = area;
+ return (area == NULL) ? 0 : area->offset;
+}
+
+static void
+LXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv)
+{
+ int red, green, blue;
+ unsigned long key;
+
+ switch (pScrni->depth) {
+ case 8:
+ vg_get_display_palette_entry(pPriv->colorKey & 0xFF, &key);
+ red = ((key >> 16) & 0xFF);
+ green = ((key >> 8) & 0xFF);
+ blue = (key & 0xFF);
+ break;
+ case 16:
+ red = (pPriv->colorKey & pScrni->mask.red) >>
+ pScrni->offset.red << (8 - pScrni->weight.red);
+ green = (pPriv->colorKey & pScrni->mask.green) >>
+ pScrni->offset.green << (8 - pScrni->weight.green);
+ blue = (pPriv->colorKey & pScrni->mask.blue) >>
+ pScrni->offset.blue << (8 - pScrni->weight.blue);
+ break;
+ default:
+ /* for > 16 bpp we send in the mask in xf86SetWeight. This
+ * function is providing the offset by 1 more. So we take
+ * this as a special case and subtract 1 for > 16
+ */
+
+ red = (pPriv->colorKey & pScrni->mask.red) >>
+ (pScrni->offset.red - 1) << (8 - pScrni->weight.red);
+ green = (pPriv->colorKey & pScrni->mask.green) >>
+ (pScrni->offset.green - 1) << (8 - pScrni->weight.green);
+ blue = (pPriv->colorKey & pScrni->mask.blue) >>
+ (pScrni->offset.blue - 1) << (8 - pScrni->weight.blue);
+ break;
+ }
+
+ df_set_video_color_key((blue | (green << 8) | (red << 16)),
+ 0xFFFFFF, (pPriv->colorKeyMode == 0));
+
+ REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
+}
+
+/* A structure full of the scratch information that originates in the copy routines,
+ but is needed for the video display - maybe we should figure out a way to attach
+ this to structures? I hate to put it in pGeode since it will increase the size of
+ the structure, and possibly cause us cache issues.
+*/
+
+struct {
+ unsigned int dstOffset;
+ unsigned int dstPitch;
+ unsigned int UVPitch;
+ unsigned int UDstOffset;
+ unsigned int VDstOffset;
+} videoScratch;
+
+/* Copy planar YUV data */
+
+static Bool
+LXCopyPlanar(ScrnInfoPtr pScrni, int id, unsigned char *buf,
+ short x1, short y1, short x2, short y2,
+ int width, int height, pointer data)
+{
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+
+ unsigned int YSrcPitch, YDstPitch;
+ unsigned int UVSrcPitch, UVDstPitch;
+ unsigned int YSrcOffset, YDstOffset;
+ unsigned int USrcOffset, UDstOffset;
+ unsigned int VSrcOffset, VDstOffset;
+
+ unsigned int size, lines, top, left, pixels;
+
+ YSrcPitch = (width + 3) & ~3;
+ YDstPitch = (width + 31) & ~31;
+
+ UVSrcPitch = ((width >> 1) + 3) & ~3;
+ UVDstPitch = ((width >> 1) + 15) & ~15;
+
+ USrcOffset = YSrcPitch * height;
+ VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
+
+ UDstOffset = YDstPitch * height;
+ VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
+
+#if 0
+ else {
+ USrcOffset = YSrcPitch * height;
+ VSrcOffset = USrcOffset + (UVSrcPitch * (height >> 1));
+
+ UDstOffset = YDstPitch * height;
+ VDstOffset = UDstOffset + (UVDstPitch * (height >> 1));
+ }
+#endif
+
+ size = YDstPitch * height;
+ size += UVDstPitch * height;
+
+ pPriv->offset = LXAllocateVidMem(pScrni, &pPriv->area, size);
+
+ if (pPriv->offset == 0) {
+ ErrorF("Error allocating an offscreen region.\n");
+ return FALSE;
+ }
+
+ /* The top of the source region we want to copy */
+ top = y1 & ~1;
+
+ /* The left hand side of the source region, aligned on a word */
+ left = x1 & ~1;
+
+ /* Number of bytes to copy, also word aligned */
+ pixels = ((x2 + 1) & ~1) - left;
+
+ /* Calculate the source offset */
+ YSrcOffset = (top * YSrcPitch) + left;
+ USrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
+ VSrcOffset += ((top >> 1) * UVSrcPitch) + (left >> 1);
+
+ /* Calculate the destination offset */
+ YDstOffset = (top * YDstPitch) + left;
+ UDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
+ VDstOffset += ((top >> 1) * UVDstPitch) + (left >> 1);
+
+ lines = ((y2 + 1) & ~1) - top;
+
+ /* Copy Y */
+
+ LXCopyFromSys(pGeode, buf + YSrcOffset, pPriv->offset + YDstOffset,
+ YDstPitch, YSrcPitch, lines, pixels);
+
+ /* Copy U + V at the same time */
+
+ LXCopyFromSys(pGeode, buf + USrcOffset, pPriv->offset + UDstOffset,
+ UVDstPitch, UVSrcPitch, lines, pixels >> 1);
+
+ videoScratch.dstOffset = pPriv->offset + YDstOffset;
+ videoScratch.dstPitch = YDstPitch;
+ videoScratch.UVPitch = UVDstPitch;
+ videoScratch.UDstOffset = pPriv->offset + UDstOffset;
+ videoScratch.VDstOffset = pPriv->offset + VDstOffset;
+
+ return TRUE;
+}
+
+static Bool
+LXCopyPacked(ScrnInfoPtr pScrni, int id, unsigned char *buf,
+ short x1, short y1, short x2, short y2,
+ int width, int height, pointer data)
+{
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ unsigned int dstPitch, srcPitch;
+ unsigned int srcOffset, dstOffset;
+ unsigned int lines, top, left, pixels;
+
+ dstPitch = ((width << 1) + 3) & ~3;
+ srcPitch = (width << 1);
+
+ lines = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch;
+
+ pPriv->offset = LXAllocateVidMem(pScrni, &pPriv->area, height * dstPitch);
+
+ if (pPriv->offset == 0) {
+ ErrorF("Error while allocating an offscreen region.\n");
+ return FALSE;
+ }
+
+ /* The top of the source region we want to copy */
+ top = y1;
+
+ /* The left hand side of the source region, aligned on a word */
+ left = x1 & ~1;
+
+ /* Number of bytes to copy, also word aligned */
+ pixels = ((x2 + 1) & ~1) - left;
+
+ /* Adjust the incoming buffer */
+ srcOffset = (top * srcPitch) + left;
+
+ /* Calculate the destination offset */
+ dstOffset = pPriv->offset + (top * dstPitch) + left;
+
+ /* Make the copy happen */
+
+ if (id == FOURCC_Y800) {
+
+ /* Use the shared (unaccelerated) greyscale copy - you could probably
+ accelerate it using a 2 pass blit and patterns, but it doesn't really
+ seem worth it
+ */
+
+ GeodeCopyGreyscale(buf + srcOffset, pGeode->FBBase + dstOffset, srcPitch, dstPitch,
+ height, pixels >> 1);
+ }
+ else
+ LXCopyFromSys(pGeode, buf + srcOffset, dstOffset, dstPitch, srcPitch, height, pixels);
+
+ videoScratch.dstOffset = dstOffset;
+ videoScratch.dstPitch = dstPitch;
+
+ return TRUE;
+}
+
+static void
+LXDisplayVideo(ScrnInfoPtr pScrni, int id, short width, short height,
+ BoxPtr dstBox, short srcW, short srcH, short drawW, short drawH)
+{
+ long ystart, xend, yend;
+ unsigned long lines = 0;
+ unsigned long yExtra, uvExtra = 0;
+ DF_VIDEO_POSITION vidPos;
+ DF_VIDEO_SOURCE_PARAMS vSrcParams;
+ int err;
+
+ memset(&vSrcParams, 0, sizeof(vSrcParams));
+
+ gp_wait_until_idle();
+
+ switch(id) {
+ case FOURCC_UYVY:
+ vSrcParams.video_format = DF_VIDFMT_UYVY;
+ break;
+
+ case FOURCC_Y800:
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ vSrcParams.video_format = DF_VIDFMT_Y0Y1Y2Y3;
+ break;
+ case FOURCC_YUY2:
+ vSrcParams.video_format = DF_VIDFMT_YUYV;
+ break;
+ case FOURCC_Y2YU:
+ vSrcParams.video_format = DF_VIDFMT_Y2YU;
+ break;
+ case FOURCC_YVYU:
+ vSrcParams.video_format = DF_VIDFMT_YVYU;
+ break;
+ case FOURCC_RGB565:
+ vSrcParams.video_format = DF_VIDFMT_RGB;
+ break;
+ }
+
+ vSrcParams.width = width;
+ vSrcParams.height = height;
+ vSrcParams.y_pitch = videoScratch.dstPitch;
+ vSrcParams.uv_pitch = videoScratch.UVPitch;
+
+ /* Set up scaling */
+ df_set_video_filter_coefficients(NULL, 1);
+
+ err = df_set_video_scale(width, height, drawW, drawH,
+ DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY);
+ if (err != CIM_STATUS_OK) {
+ /* Note the problem, but do nothing for now. */
+ ErrorF("Video scale factor too large: %dx%d -> %dx%d\n",
+ width, height, drawW, drawH);
+ }
+
+ /* Figure out clipping */
+
+ xend = dstBox->x2;
+ yend = dstBox->y2;
+
+ if (dstBox->y1 < 0) {
+ if (srcH < drawH)
+ lines = ((-dstBox->y1) * srcH) / drawH;
+ else
+ lines = (-dstBox->y1);
+
+ ystart = 0;
+ drawH += dstBox->y1;
+ }
+ else {
+ ystart = dstBox->y1;
+ lines = 0;
+ }
+
+ yExtra = lines * videoScratch.dstPitch;
+ uvExtra = (lines >> 1) * videoScratch.UVPitch;
+
+ memset(&vidPos, 0, sizeof(vidPos));
+
+ vidPos.x = dstBox->x1;
+ vidPos.y = ystart;
+ vidPos.width = xend - dstBox->x1;
+ vidPos.height = yend - ystart;
+
+ df_set_video_position(&vidPos);
+
+ vSrcParams.y_offset = videoScratch.dstOffset + yExtra;
+
+ switch(id) {
+ case FOURCC_Y800:
+ case FOURCC_I420:
+ vSrcParams.u_offset = videoScratch.UDstOffset + uvExtra;
+ vSrcParams.v_offset = videoScratch.VDstOffset + uvExtra;
+ break;
+ case FOURCC_YV12:
+ vSrcParams.v_offset = videoScratch.UDstOffset + uvExtra;
+ vSrcParams.u_offset = videoScratch.VDstOffset + uvExtra;
+ break;
+
+ default:
+ vSrcParams.u_offset = vSrcParams.v_offset = 0;
+ break;
+ }
+
+ vSrcParams.flags = DF_SOURCEFLAG_IMPLICITSCALING;
+ df_configure_video_source(&vSrcParams, &vSrcParams);
+
+ /* Turn on the video palette */
+ df_set_video_palette(NULL);
+ df_set_video_enable(1, 0);
+}
+
+static int
+LXPutImage(ScrnInfoPtr pScrni,
+ short srcX, short srcY, short drawX, short drawY,
+ short srcW, short srcH, short drawW, short drawH,
+ int id, unsigned char *buf,
+ short width, short height, Bool sync, RegionPtr clipBoxes,
+ pointer data, DrawablePtr pDraw)
+{
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+ INT32 x1,x2,y1,y2;
+ BoxRec dstBox;
+
+ if (pGeode->rotation != RR_Rotate_0)
+ return Success;
+
+ if (srcW <= 0 || srcH <= 0) {
+ return Success;
+ }
+
+ if (drawW <= 0 || drawH <=0) {
+ return Success;
+ }
+
+ if (drawW > 16384)
+ drawW = 16384;
+
+ memset(&videoScratch, 0, sizeof(videoScratch));
+
+ x1 = srcX;
+ x2 = srcX + srcW;
+ y1 = srcY;
+ y2 = srcY + srcH;
+
+ dstBox.x1 = drawX;
+ dstBox.x2 = drawX + drawW;
+ dstBox.y1 = drawY;
+ dstBox.y2 = drawY + drawH;
+
+ dstBox.x1 -= pScrni->frameX0;
+ dstBox.x2 -= pScrni->frameX0;
+ dstBox.y1 -= pScrni->frameY0;
+ dstBox.y2 -= pScrni->frameY0;
+
+ switch(id) {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ LXCopyPlanar(pScrni, id, buf, x1, y1, x2, y2, width, height, data);
+ break;
+
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ case FOURCC_Y800:
+ case FOURCC_RGB565:
+ LXCopyPacked(pScrni, id, buf, x1, y1, x2, y2, width, height, data);
+ break;
+ }
+
+ if (!RegionsEqual(&pPriv->clip, clipBoxes) ||
+ (drawW != pPriv->pwidth || drawH != pPriv->pheight)) {
+ REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes);
+
+ if (pPriv->colorKeyMode == 0) {
+ xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes);
+ }
+
+ LXDisplayVideo(pScrni, id, width, height, &dstBox,
+ srcW, srcH, drawW, drawH);
+ pPriv->pwidth = drawW;
+ pPriv->pheight = drawH;
+ }
+
+ pPriv->videoStatus = CLIENT_VIDEO_ON;
+ pGeode->OverlayON = TRUE;
+
+ return Success;
+}
+
+static void
+LXQueryBestSize(ScrnInfoPtr pScrni, Bool motion,
+ short vidW, short vidH, short drawW, short drawH,
+ unsigned int *retW, unsigned int *retH, pointer data)
+{
+ *retW = drawW > 16384 ? 16384 : drawW;
+ *retH = drawH;
+}
+
+static Atom xvColorKey, xvColorKeyMode, xvFilter;
+
+static int
+LXGetPortAttribute(ScrnInfoPtr pScrni,
+ Atom attribute, INT32 * value, pointer data)
+{
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+
+ if (attribute == xvColorKey)
+ *value = pPriv->colorKey;
+ else if (attribute == xvColorKeyMode)
+ *value = pPriv->colorKeyMode;
+ else if (attribute == xvFilter)
+ *value = pPriv->filter;
+ else
+ return BadMatch;
+
+ return Success;
+}
+
+static int
+LXSetPortAttribute(ScrnInfoPtr pScrni,
+ Atom attribute, INT32 value, pointer data)
+{
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+
+ gp_wait_until_idle();
+
+ if (attribute == xvColorKey) {
+ pPriv->colorKey = value;
+ LXSetColorkey(pScrni, pPriv);
+ }
+ else if (attribute == xvColorKeyMode) {
+ pPriv->colorKeyMode = value;
+ LXSetColorkey(pScrni, pPriv);
+ }
+ else if (attribute == xvFilter) {
+ if ((value < 0) || (value > 1))
+ return BadValue;
+ pPriv->filter = value;
+ }
+ else
+ return BadMatch;
+
+ return Success;
+}
+
+static void
+LXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit)
+{
+ GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data;
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+
+ if (pPriv->videoStatus == 0)
+ return;
+
+ REGION_EMPTY(pScrni->pScreen, &pPriv->clip);
+ gp_wait_until_idle();
+
+ if (exit) {
+ if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ unsigned int val;
+
+ df_set_video_enable(0,0);
+ /* Put the LUT back in bypass */
+ val = READ_VID32(DF_VID_MISC);
+ WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
+ }
+
+ if (pPriv->area) {
+ exaOffscreenFree(pScrni->pScreen, pPriv->area);
+ pPriv->area = NULL;
+ }
+
+ pPriv->videoStatus = 0;
+
+ /* Eh? */
+ pGeode->OverlayON = FALSE;
+ }
+ else if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
+ pPriv->videoStatus |= OFF_TIMER;
+ pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
+ }
+}
+
+static void
+LXResetVideo(ScrnInfoPtr pScrni)
+{
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+
+ if (!pGeode->NoAccel) {
+ GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr;
+
+ gp_wait_until_idle();
+ df_set_video_palette(NULL);
+
+ LXSetColorkey(pScrni, pPriv);
+ }
+}
+
+static void
+LXVidBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
+{
+ ScreenPtr pScrn = screenInfo.screens[i];
+ ScrnInfoPtr pScrni = xf86Screens[i];
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni);
+
+ pScrn->BlockHandler = pGeode->BlockHandler;
+ (*pScrn->BlockHandler) (i, blockData, pTimeout, pReadmask);
+ pScrn->BlockHandler = LXVidBlockHandler;
+
+ if (pPriv->videoStatus & TIMER_MASK) {
+ Time now = currentTime.milliseconds;
+
+ if (pPriv->videoStatus & OFF_TIMER) {
+ gp_wait_until_idle();
+
+ if (pPriv->offTime < now) {
+ unsigned int val;
+
+ df_set_video_enable(0, 0);
+ pPriv->videoStatus = FREE_TIMER;
+ pPriv->freeTime = now + FREE_DELAY;
+
+ /* Turn off the video palette */
+ val = READ_VID32(DF_VID_MISC);
+ WRITE_VID32(DF_VID_MISC, val | DF_GAMMA_BYPASS_BOTH);
+ }
+ }
+ else {
+ if (pPriv->freeTime < now) {
+ if (pPriv->area) {
+ exaOffscreenFree(pScrni->pScreen, pPriv->area);
+ pPriv->area = NULL;
+ }
+
+ pPriv->videoStatus = 0;
+ }
+ }
+ }
+}
+
+static XF86VideoAdaptorPtr
+LXSetupImageVideo(ScreenPtr pScrn)
+{
+ ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ XF86VideoAdaptorPtr adapt;
+ GeodePortPrivRec *pPriv;
+
+ adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
+ sizeof(GeodePortPrivRec) + sizeof(DevUnion));
+
+ if (adapt == NULL) {
+ ErrorF("Couldn't create the rec\n");
+ return NULL;
+ }
+
+ adapt->type = XvWindowMask | XvInputMask | XvImageMask;
+ adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+
+ adapt->name = "AMD Geode LX";
+ adapt->nEncodings = 1;
+ adapt->pEncodings = DummyEncoding;
+ adapt->nFormats = ARRAY_SIZE(Formats);
+ adapt->pFormats = Formats;
+ adapt->nPorts = 1;
+ adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
+ pPriv = (GeodePortPrivRec *) (&adapt->pPortPrivates[1]);
+ adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
+ adapt->pAttributes = Attributes;
+ adapt->nImages = ARRAY_SIZE(Images);
+ adapt->nAttributes = ARRAY_SIZE(Attributes);
+ adapt->pImages = Images;
+ adapt->PutVideo = NULL;
+ adapt->PutStill = NULL;
+ adapt->GetVideo = NULL;
+ adapt->GetStill = NULL;
+ adapt->StopVideo= LXStopVideo;
+ adapt->SetPortAttribute = LXSetPortAttribute;
+ adapt->GetPortAttribute = LXGetPortAttribute;
+ adapt->QueryBestSize = LXQueryBestSize;
+ adapt->PutImage =LXPutImage;
+
+ /* Use the common function */
+ adapt->QueryImageAttributes = GeodeQueryImageAttributes;
+
+ pPriv->filter = 0;
+ pPriv->colorKey = pGeode->videoKey;
+ pPriv->colorKeyMode = 0;
+ pPriv->videoStatus = 0;
+ pPriv->pwidth = 0;
+ pPriv->pheight = 0;
+
+ REGION_NULL(pScrn, &pPriv->clip);
+
+ pGeode->adaptor = adapt;
+
+ pGeode->BlockHandler = pScrn->BlockHandler;
+ pScrn->BlockHandler = LXVidBlockHandler;
+
+ xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE");
+ xvFilter = MAKE_ATOM("XV_FILTER");
+
+ LXResetVideo(pScrni);
+
+ return adapt;
+}
+
+/* Offscreen surface allocation */
+
+struct OffscreenPrivRec
+{
+ void * area;
+ int offset;
+ Bool isOn;
+};
+
+static int
+LXDisplaySurface(XF86SurfacePtr surface,
+ short srcX, short srcY, short drawX, short drawY,
+ short srcW, short srcH, short drawW, short drawH,
+ RegionPtr clipBoxes)
+{
+ struct OffscreenPrivRec *pPriv =
+ (struct OffscreenPrivRec *) surface->devPrivate.ptr;
+
+ ScrnInfoPtr pScrni = surface->pScrn;
+ GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni);
+
+ BoxRec dstBox;
+
+ dstBox.x1 = drawX;
+ dstBox.x2 = drawX + drawW;
+ dstBox.y1 = drawY;
+ dstBox.y2 = drawY + drawH;
+
+ if ((drawW <= 0) | (drawH <=0))
+ return Success;
+
+ /* Is this still valid? */
+
+ dstBox.x1 -= pScrni->frameX0;
+ dstBox.x2 -= pScrni->frameX0;
+ dstBox.y1 -= pScrni->frameY0;
+ dstBox.y2 -= pScrni->frameY0;
+
+ xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes);
+
+ videoScratch.dstOffset = surface->offsets[0];
+ videoScratch.dstPitch = surface->pitches[0];
+
+ LXDisplayVideo(pScrni, surface->id, surface->width, surface->height,
+ &dstBox, srcW, srcH, drawW, drawH);
+
+ pPriv->isOn = TRUE;
+
+ if (portPriv->videoStatus & CLIENT_VIDEO_ON) {
+ REGION_EMPTY(pScrni->pScreen, &portPriv->clip);
+ UpdateCurrentTime();
+ portPriv->videoStatus = FREE_TIMER;
+ portPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
+ }
+
+ return Success;
+}
+
+static int
+LXAllocateSurface(ScrnInfoPtr pScrni, int id, unsigned short w,
+ unsigned short h, XF86SurfacePtr surface)
+{
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ void * area = NULL;
+ int pitch, lines;
+ unsigned offset;
+ struct OffscreenPrivRec *pPriv;
+
+ if (w > 1024 || h > 1024)
+ return BadAlloc;
+
+ /* The width needs to be word aligned */
+ w = (w + 1) & ~1;
+
+ pitch = ((w << 1) + 15) & ~15;
+ lines = ((pitch * h) + (pGeode->Pitch - 1)) / pGeode->Pitch;
+
+ offset = LXAllocateVidMem(pScrni, &area, lines);
+
+ if (offset == 0) {
+ ErrorF("Error while allocating an offscreen region.\n");
+ return BadAlloc;
+ }
+
+ surface->width = w;
+ surface->height = h;
+
+ surface->pitches = xalloc(sizeof(int));
+
+ surface->offsets = xalloc(sizeof(int));
+
+ pPriv = xalloc(sizeof(struct OffscreenPrivRec));
+
+ if (pPriv && surface->pitches && surface->offsets) {
+
+ pPriv->area = area;
+ pPriv->offset = offset;
+
+ pPriv->isOn = FALSE;
+
+ surface->pScrn = pScrni;
+ surface->id = id;
+ surface->pitches[0] = pitch;
+ surface->offsets[0] = offset;
+ surface->devPrivate.ptr = (pointer) pPriv;
+
+ return Success;
+ }
+
+ if (surface->offsets)
+ xfree(surface->offsets);
+
+ if (surface->pitches)
+ xfree(surface->pitches);
+
+ if (area)
+ exaOffscreenFree(pScrni->pScreen, area);
+
+ return BadAlloc;
+}
+
+static int
+LXStopSurface(XF86SurfacePtr surface)
+{
+ struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
+ surface->devPrivate.ptr;
+
+ pPriv->isOn = FALSE;
+ return Success;
+}
+
+static int
+LXFreeSurface(XF86SurfacePtr surface)
+{
+ struct OffscreenPrivRec *pPriv = (struct OffscreenPrivRec *)
+ surface->devPrivate.ptr;
+ ScrnInfoPtr pScrni = surface->pScrn;
+
+ if (pPriv->isOn)
+ LXStopSurface(surface);
+
+ if (pPriv->area) {
+ exaOffscreenFree(pScrni->pScreen, pPriv->area);
+ pPriv->area = NULL;
+ }
+
+ xfree(surface->pitches);
+ xfree(surface->offsets);
+ xfree(surface->devPrivate.ptr);
+
+ return Success;
+}
+
+static int
+LXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value)
+{
+ return LXGetPortAttribute(pScrni, attribute, value,
+ (pointer) (GET_PORT_PRIVATE(pScrni)));
+}
+
+static int
+LXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value)
+{
+ return LXSetPortAttribute(pScrni, attribute, value,
+ (pointer) (GET_PORT_PRIVATE(pScrni)));
+}
+
+
+static void
+LXInitOffscreenImages(ScreenPtr pScrn)
+{
+ XF86OffscreenImagePtr offscreenImages;
+
+ /* need to free this someplace */
+ if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec))))
+ return;
+
+ offscreenImages[0].image = &Images[0];
+ offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
+ offscreenImages[0].alloc_surface = LXAllocateSurface;
+ offscreenImages[0].free_surface = LXFreeSurface;
+ offscreenImages[0].display = LXDisplaySurface;
+ offscreenImages[0].stop = LXStopSurface;
+ offscreenImages[0].setAttribute = LXSetSurfaceAttribute;
+ offscreenImages[0].getAttribute = LXGetSurfaceAttribute;
+ offscreenImages[0].max_width = 1024;
+ offscreenImages[0].max_height = 1024;
+ offscreenImages[0].num_attributes = ARRAY_SIZE(Attributes);
+ offscreenImages[0].attributes = Attributes;
+
+ xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1);
+}
+
+void
+LXInitVideo(ScreenPtr pScrn)
+{
+ GeodeRec *pGeode;
+ ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum];
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ int num_adaptors;
+
+ pGeode = GEODEPTR(pScrni);
+
+ if (pGeode->NoAccel) {
+ ErrorF("Cannot run Xv without accelerations!\n");
+ return;
+ }
+
+ if (!(newAdaptor = LXSetupImageVideo(pScrn))) {
+ ErrorF("Error while setting up the adaptor.\n");
+ return;
+ }
+
+ LXInitOffscreenImages(pScrn);
+
+ num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors);
+
+ if (!num_adaptors) {
+ num_adaptors = 1;
+ adaptors = &newAdaptor;
+ } else {
+ newAdaptors =
+ xalloc((num_adaptors + 1) * sizeof(XF86VideoAdaptorPtr *));
+
+ if (newAdaptors) {
+ memcpy(newAdaptors, adaptors, num_adaptors *
+ sizeof(XF86VideoAdaptorPtr));
+ newAdaptors[num_adaptors] = newAdaptor;
+ adaptors = newAdaptors;
+ num_adaptors++;
+ }
+ else
+ ErrorF("Memory error while setting up the adaptor\n");
+ }
+
+ if (num_adaptors)
+ xf86XVScreenInit(pScrn, adaptors, num_adaptors);
+
+ if (newAdaptors)
+ xfree(newAdaptors);
+}