diff options
Diffstat (limited to 'src/gx_video.c')
-rw-r--r-- | src/gx_video.c | 1558 |
1 files changed, 1558 insertions, 0 deletions
diff --git a/src/gx_video.c b/src/gx_video.c new file mode 100644 index 0000000..7d2f0f4 --- /dev/null +++ b/src/gx_video.c @@ -0,0 +1,1558 @@ +/* Copyright (c) 2003-2005 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 + * IMPDIs2IED, 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. + * */ + +/* + * File Contents: This file consists of main Xfree video supported routines. + * + * Project: Geode Xfree Frame buffer device driver. + * */ + +/* + * Fixes & Extensions to support Y800 greyscale modes + * Alan Hourihane <alanh@fairlite.demon.co.uk> + + * code to allocate offscreen memory from EXA - is borrowed from Radeon + */ + +#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 "geode.h" +#include "xf86xv.h" +#include <X11/extensions/Xv.h> +#include "xaa.h" +#include "xaalocal.h" +#include "dixstruct.h" +#include "fourcc.h" +#include "geode_fourcc.h" + +#define OFF_DELAY 200 /* milliseconds */ +#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 XV_PROFILE 0 +#define REINIT 1 + +#ifndef XvExtension +#error "It didn't work!" +void +GXInitVideo(ScreenPtr pScrn) +{ +} + +void +GXResetVideo(ScrnInfoPtr pScrni) +{ +} + +void +GXSetVideoPosition() +{ +} +#else + +#define DBUF 1 +void GXResetVideo(ScrnInfoPtr pScrni); +static XF86VideoAdaptorPtr GXSetupImageVideo(ScreenPtr); +static void GXInitOffscreenImages(ScreenPtr); +static void GXStopVideo(ScrnInfoPtr, pointer, Bool); +static int GXSetPortAttribute(ScrnInfoPtr, Atom, INT32, pointer); +static int GXGetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer); +static void GXQueryBestSize(ScrnInfoPtr, Bool, + short, short, short, short, unsigned int *, unsigned int *, pointer); +static int GXPutImage(ScrnInfoPtr, short, short, short, short, short, short, + short, short, int, unsigned char *, short, short, Bool, + RegionPtr, pointer, DrawablePtr pDraw); + +static void GXBlockHandler(int, pointer, pointer, pointer); +void GXSetVideoPosition(int x, int y, int width, int height, + short src_w, short src_h, short drw_w, + short drw_h, int id, int offset, ScrnInfoPtr pScrni); + +extern void GXAccelSync(ScrnInfoPtr pScrni); + +int DeltaX, DeltaY; + +unsigned long graphics_lut[256]; +static int lutflag = 0; + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvColorKey, xvColorKeyMode, xvFilter +#if DBUF + , xvDoubleBuffer +#endif + ; + +#define PALETTE_ADDRESS 0x038 +#define PALETTE_DATA 0x040 +#define DISPLAY_CONFIG 0x008 +#define MISC 0x050 + +static void get_gamma_ram(unsigned long *lut) { + + int i; + + gfx_write_vid32(PALETTE_ADDRESS, 0); + + for(i = 0; i < 256; i++) + lut[i] = gfx_read_vid32(PALETTE_DATA); +} + +/*---------------------------------------------------------------------------- + * GXInitVideo + * + * Description :This is the initialization routine.It creates a new video + * adapter and calls GXSetupImageVideo to initialize the adaptor + * by filling XF86VideoAdaptorREc.Then it lists the existing + * adaptors and adds the new one to it. Finally the list of + * XF86VideoAdaptorPtr pointers are passed to the + * xf86XVScreenInit(). + * + * Parameters. + * pScrn :Screen handler pointer having screen information. + * + * Returns :none + * + * Comments :none + *---------------------------------------------------------------------------- + */ +void +GXInitVideo(ScreenPtr pScrn) +{ + GeodeRec *pGeode; + ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; + + pGeode = GEODEPTR(pScrni); + + if (!pGeode->NoAccel) { + XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; + XF86VideoAdaptorPtr newAdaptor = NULL; + + int num_adaptors; + + newAdaptor = GXSetupImageVideo(pScrn); + GXInitOffscreenImages(pScrn); + + num_adaptors = xf86XVListGenericAdaptors(pScrni, &adaptors); + + if (newAdaptor) { + if (!num_adaptors) { + num_adaptors = 1; + adaptors = &newAdaptor; + } else { + newAdaptors = /* need to free this someplace */ + xalloc((num_adaptors + + 1) * sizeof(XF86VideoAdaptorPtr *)); + if (newAdaptors) { + memcpy(newAdaptors, adaptors, num_adaptors * + sizeof(XF86VideoAdaptorPtr)); + newAdaptors[num_adaptors] = newAdaptor; + adaptors = newAdaptors; + num_adaptors++; + } + } + } + + if (num_adaptors) + xf86XVScreenInit(pScrn, adaptors, num_adaptors); + + if (newAdaptors) + xfree(newAdaptors); + } +} + +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = { + { + 0, + "XV_IMAGE", + 1024, 1024, + {1, 1} + } +}; + +#define NUM_FORMATS 4 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = { + {8, PseudoColor}, {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#if DBUF +#define NUM_ATTRIBUTES 4 +#else +#define NUM_ATTRIBUTES 3 +#endif + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { +#if DBUF + {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}, +#endif + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, 0, 1, "XV_FILTER"}, + {XvSettable | XvGettable, 0, 1, "XV_COLORKEYMODE"} +}; + +#define NUM_IMAGES 8 + +static XF86ImageRec Images[NUM_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; +#if DBUF + Bool doubleBuffer; + int currentBuffer; +#endif +} GeodePortPrivRec, *GeodePortPrivPtr; + +#define GET_PORT_PRIVATE(pScrni) \ + (GeodePortPrivRec *)((GEODEPTR(pScrni))->adaptor->pPortPrivates[0].ptr) + +/*---------------------------------------------------------------------------- + * GXSetColorKey + * + * Description :This function reads the color key for the pallete and + * sets the video color key register. + * + * Parameters. + * ScreenInfoPtr + * pScrni :Screen pointer having screen information. + * pPriv :Video port private data + * + * Returns :none + * + * Comments :none + * + *---------------------------------------------------------------------------- + */ +static INT32 +GXSetColorkey(ScrnInfoPtr pScrni, GeodePortPrivRec * pPriv) +{ + int red, green, blue; + unsigned long key; + + switch (pScrni->depth) { + case 8: + GFX(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; + } + + GFX(set_video_color_key((blue | (green << 8) | (red << 16)), 0xFFFFFF, + (pPriv->colorKeyMode == 0))); + REGION_EMPTY(pScrni->pScreen, &pPriv->clip); + return 0; +} + +/*---------------------------------------------------------------------------- + * GXResetVideo + * + * Description : This function resets the video + * + * Parameters. + * pScrni :Screen pointer having screen information. + * + * Returns :None + * + * Comments :none + * + *---------------------------------------------------------------------------- + */ +void +GXResetVideo(ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + + if (!pGeode->NoAccel) { + GeodePortPrivRec *pPriv = pGeode->adaptor->pPortPrivates[0].ptr; + + GXAccelSync(pScrni); + GXSetColorkey(pScrni, pPriv); + GFX(set_video_filter(pPriv->filter, pPriv->filter)); + } +} + +/*---------------------------------------------------------------------------- + * GXSetupImageVideo + * + * Description : This function allocates space for a Videoadaptor and + * initializes the XF86VideoAdaptorPtr record. + * + * Parameters. + * pScrn :Screen handler pointer having screen information. + * + * Returns :pointer to the initialized video adaptor record. + * + * Comments :none + *---------------------------------------------------------------------------- + */ +static XF86VideoAdaptorPtr +GXSetupImageVideo(ScreenPtr pScrn) +{ + ScrnInfoPtr pScrni = xf86Screens[pScrn->myNum]; + GeodeRec *pGeode = GEODEPTR(pScrni); + XF86VideoAdaptorPtr adapt; + GeodePortPrivRec *pPriv; + + if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + + sizeof(GeodePortPrivRec) + sizeof(DevUnion)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "Advanced Micro Devices"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_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 = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo= GXStopVideo; + adapt->SetPortAttribute = GXSetPortAttribute; + adapt->GetPortAttribute = GXGetPortAttribute; + adapt->QueryBestSize = GXQueryBestSize; + adapt->PutImage = GXPutImage; + adapt->QueryImageAttributes = GeodeQueryImageAttributes; + + pPriv->filter = 0; + pPriv->colorKey = pGeode->videoKey; + pPriv->colorKeyMode = 0; + pPriv->videoStatus = 0; +#if DBUF + pPriv->doubleBuffer = TRUE; + pPriv->currentBuffer = 0; /* init to first buffer */ +#endif + + /* gotta uninit this someplace */ +#if defined(REGION_NULL) + REGION_NULL(pScrn, &pPriv->clip); +#else + REGION_INIT(pScrn, &pPriv->clip, NullBox, 0); +#endif + + pGeode->adaptor = adapt; + + pGeode->BlockHandler = pScrn->BlockHandler; + pScrn->BlockHandler = GXBlockHandler; + + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + xvColorKeyMode = MAKE_ATOM("XV_COLORKEYMODE"); + xvFilter = MAKE_ATOM("XV_FILTER"); +#if DBUF + xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); +#endif + + GXResetVideo(pScrni); + + return adapt; +} + +/*---------------------------------------------------------------------------- + * GXStopVideo + * + * Description :This function is used to stop input and output video + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * data :Pointer to the video port's private data + * exit :Flag indicating whether the offscreen areas used for + * video to be deallocated or not. + * + * Returns :none + * + * Comments :none + *---------------------------------------------------------------------------- + */ +static void +GXStopVideo(ScrnInfoPtr pScrni, pointer data, Bool exit) +{ + GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; + GeodeRec *pGeode = GEODEPTR(pScrni); + + REGION_EMPTY(pScrni->pScreen, &pPriv->clip); + + GXAccelSync(pScrni); + if (exit) { + if (pPriv->videoStatus & CLIENT_VIDEO_ON) { + GFX(set_video_enable(0)); + + /* If we have saved graphics LUT data - restore it */ + /* Otherwise, turn bypass on */ + + if (lutflag) + GFX(set_graphics_palette(graphics_lut)); + else + GFX(set_video_palette_bypass(1)); + + lutflag = 0; + } + + if (pPriv->area) { +#ifdef XF86EXA + if (pGeode->useEXA) + exaOffscreenFree(pScrni->pScreen, pPriv->area); +#endif + + if (!pGeode->useEXA) + xf86FreeOffscreenArea(pPriv->area); + + pPriv->area = NULL; + } + + pPriv->videoStatus = 0; + pGeode->OverlayON = FALSE; + } else { + if (pPriv->videoStatus & CLIENT_VIDEO_ON) { + pPriv->videoStatus |= OFF_TIMER; + pPriv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } +} + +/*---------------------------------------------------------------------------- + * GXSetPortAttribute + * + * Description :This function is used to set the attributes of a port + * like colorkeymode, double buffer support and filter. + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * data :Pointer to the video port's private data + * attribute :The port attribute to be set + * value :Value of the attribute to be set. + * + * Returns :Sucess if the attribute is supported, else BadMatch + * + * Comments :none + *---------------------------------------------------------------------------- + */ +static int +GXSetPortAttribute(ScrnInfoPtr pScrni, + Atom attribute, INT32 value, pointer data) +{ + GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; + + GXAccelSync(pScrni); + if (attribute == xvColorKey) { + pPriv->colorKey = value; + GXSetColorkey(pScrni, pPriv); + } +#if DBUF + else if (attribute == xvDoubleBuffer) { + if ((value < 0) || (value > 1)) + return BadValue; + pPriv->doubleBuffer = value; + } +#endif + else if (attribute == xvColorKeyMode) { + pPriv->colorKeyMode = value; + GXSetColorkey(pScrni, pPriv); + } else if (attribute == xvFilter) { + if ((value < 0) || (value > 1)) + return BadValue; + pPriv->filter = value; + } else + return BadMatch; + + return Success; +} + +/*---------------------------------------------------------------------------- + * GXGetPortAttribute + * + * Description :This function is used to get the attributes of a port + * like hue, saturation,brightness or contrast. + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * data :Pointer to the video port's private data + * attribute :The port attribute to be read + * value :Pointer to the value of the attribute to be read. + * + * Returns :Sucess if the attribute is supported, else BadMatch + * + * Comments :none + *---------------------------------------------------------------------------- + */ +static int +GXGetPortAttribute(ScrnInfoPtr pScrni, + Atom attribute, INT32 * value, pointer data) +{ + GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; + + if (attribute == xvColorKey) { + *value = pPriv->colorKey; + } +#if DBUF + else if (attribute == xvDoubleBuffer) { + *value = (pPriv->doubleBuffer) ? 1 : 0; + } +#endif + else if (attribute == xvColorKeyMode) { + *value = pPriv->colorKeyMode; + } else if (attribute == xvFilter) { + *value = pPriv->filter; + } else + return BadMatch; + + return Success; +} + +/*---------------------------------------------------------------------------- + * GXQueryBestSize + * + * Description :This function provides a way to query what the + * destination dimensions would end up being if they were to + * request that an area vid_w by vid_h from the video stream + * be scaled to rectangle of drw_w by drw_h on the screen. + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * data :Pointer to the video port's private data + * vid_w,vid_h :Width and height of the video data. + * drw_w,drw_h :Width and height of the scaled rectangle. + * p_w,p_h :Width and height of the destination rectangle. + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ +static void +GXQueryBestSize(ScrnInfoPtr pScrni, + Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, pointer data) +{ + *p_w = drw_w; + *p_h = drw_h; + + if (*p_w > 16384) + *p_w = 16384; +} + +/*---------------------------------------------------------------------------- + * GXCopyData420 + * + * Description : Copies data from src to destination + * + * Parameters. + * src : pointer to the source data + * dst : pointer to destination data + * srcPitch : pitch of the srcdata + * dstPitch : pitch of the destination data + * h & w : height and width of source data + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ +static void +GXCopyData420(unsigned char *src, unsigned char *dst, + int srcPitch, int dstPitch, int h, int w) +{ + while (h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +/*---------------------------------------------------------------------------- + * GXCopyData422 + * + * Description : Copies data from src to destination + * + * Parameters. + * src : pointer to the source data + * dst : pointer to destination data + * srcPitch : pitch of the srcdata + * dstPitch : pitch of the destination data + * h & w : height and width of source data + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ +static void +GXCopyData422(unsigned char *src, unsigned char *dst, + int srcPitch, int dstPitch, int h, int w) +{ + w <<= 1; + while (h--) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } +} + +#ifdef XF86EXA +static void +GXVideoSave(ScreenPtr pScreen, ExaOffscreenArea *area) { + ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum]; + GeodePortPrivRec *pPriv = GET_PORT_PRIVATE(pScrni); + + if (area == pPriv->area) + pPriv->area = NULL; +} +#endif + +static int +GXAllocateMemory(ScrnInfoPtr pScrni, void **memp, int numlines) +{ + ScreenPtr pScrn = screenInfo.screens[pScrni->scrnIndex]; + GeodeRec *pGeode = GEODEPTR(pScrni); + //long displayWidth = pGeode->Pitch / ((pScrni->bitsPerPixel + 7) / 8); + int size = numlines * pGeode->displayWidth; + +#if XF86EXA + if (pGeode->useEXA) { + ExaOffscreenArea *area = *memp; + + if (area != NULL) { + if (area->size >= size) + return area->offset; + + exaOffscreenFree(pScrni->pScreen, area); + } + + area = exaOffscreenAlloc(pScrni->pScreen, size, 16, + TRUE, GXVideoSave, NULL); + *memp = area; + + return area == NULL ? 0 : area->offset; + } +#endif + + if (!pGeode->useEXA) { + FBAreaPtr area = *memp; + FBAreaPtr new_area; + + if (area) { + if ((area->box.y2 - area->box.y1) >= numlines) + return (area->box.y1 * pGeode->Pitch); + + + if (xf86ResizeOffscreenArea(area, pGeode->displayWidth, numlines)) + return (area->box.y1 * pGeode->Pitch); + + xf86FreeOffscreenArea(area); + } + + new_area = xf86AllocateOffscreenArea(pScrn, pGeode->displayWidth, + numlines, 0, NULL, NULL, NULL); + + if (!new_area) { + int max_w, max_h; + + xf86QueryLargestOffscreenArea(pScrn, &max_w, &max_h, 0, + FAVOR_WIDTH_THEN_AREA, PRIORITY_EXTREME); + + if ((max_w < pGeode->displayWidth) || (max_h < numlines)) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, "No room - how sad %x, %x, %x, %x\n", max_w, pGeode->displayWidth, max_h, numlines); + return 0; + } + + xf86PurgeUnlockedOffscreenAreas(pScrn); + new_area = xf86AllocateOffscreenArea(pScrn, pGeode->displayWidth, + numlines, 0, NULL, NULL, NULL); + } + + return (new_area->box.y1 * pGeode->Pitch); + } + + return 0; +} + +static BoxRec dstBox; +static int srcPitch = 0, srcPitch2 = 0, dstPitch = 0, dstPitch2 = 0; +static INT32 Bx1, Bx2, By1, By2; +static int top, left, npixels, nlines; +static int offset, s1offset = 0, s2offset = 0, s3offset = 0; +static unsigned char *dst_start; +static int d2offset = 0, d3offset = 0; + +#if 0 +static Bool +RegionsIntersect(BoxPtr pRcl1, BoxPtr pRcl2, BoxPtr pRclResult) +{ + pRclResult->x1 = max(pRcl1->x1, pRcl2->x1); + pRclResult->x2 = min(pRcl1->x2, pRcl2->x2); + + if (pRclResult->x1 <= pRclResult->x2) { + pRclResult->y1 = max(pRcl1->y1, pRcl2->y1); + pRclResult->y2 = min(pRcl1->y2, pRcl2->y2); + + if (pRclResult->y1 <= pRclResult->y2) { + return (TRUE); + } + } + + return (FALSE); +} +#endif + +void +GXSetVideoPosition(int x, int y, int width, int height, + short src_w, short src_h, short drw_w, short drw_h, + int id, int offset, ScrnInfoPtr pScrni) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + long ystart, xend, yend; + unsigned long lines = 0; + unsigned long y_extra, uv_extra = 0; + unsigned long startAddress; +#if 0 + BoxRec ovly, display, result; +#endif + + xend = x + drw_w; + yend = y + drw_h; + + /* Take care of panning when panel is present */ + + startAddress = gfx_get_display_offset() - pGeode->FBOffset; + DeltaY = startAddress / pGeode->Pitch; + DeltaX = startAddress & (pGeode->Pitch - 1); + DeltaX /= (pScrni->bitsPerPixel >> 3); + +#if 0 + /* Thhis code is pretty dang broken - comment it out for now */ + + if (pGeode->Panel) { + ovly.x1 = x; + ovly.x2 = x + pGeode->video_dstw; + ovly.y1 = y; + ovly.y2 = y + pGeode->video_dsth; + + display.x1 = DeltaX; + display.x2 = DeltaX + pGeode->FPBX; + display.y1 = DeltaY; + display.y2 = DeltaY + pGeode->FPBY; + x = xend = 0; + if (RegionsIntersect(&display, &ovly, &result)) { + x = ovly.x1 - DeltaX; + xend = ovly.x2 - DeltaX; + y = ovly.y1 - DeltaY; + yend = ovly.y2 - DeltaY; + } + } +#endif + + /* TOP CLIPPING */ + + if (y < 0) { + if (src_h < drw_h) + lines = (-y) * src_h / drw_h; + else + lines = (-y); + ystart = 0; + drw_h += y; + y_extra = lines * dstPitch; + uv_extra = (lines >> 1) * (dstPitch2); + } else { + ystart = y; + lines = 0; + y_extra = 0; + } + + GFX(set_video_window(x, ystart, xend - x, yend - ystart)); + + if ((id == FOURCC_Y800) || (id == FOURCC_I420) || (id == FOURCC_YV12)) { + GFX(set_video_yuv_offsets(offset + y_extra, + offset + d3offset + uv_extra, offset + d2offset + uv_extra)); + } else { + GFX(set_video_offset(offset + y_extra)); + } +} + +/*---------------------------------------------------------------------------- + * GXDisplayVideo + * + * Description :This function sets up the video registers for playing video + * It sets up the video format,width, height & position of the + * video window ,video offsets( y,u,v) and video pitches(y,u,v) + * + * Parameters + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ + +static void +GXDisplayVideo(ScrnInfoPtr pScrni, + int id, + int offset, + short width, short height, + int pitch, + int x1, int y1, int x2, int y2, + BoxPtr dstBox, short src_w, short src_h, short drw_w, short drw_h) +{ + GeodeRec *pGeode = GEODEPTR(pScrni); + unsigned long dcfg, misc; + + GXAccelSync(pScrni); + + /* If the gamma LUT is already loaded with graphics data, then save it + * off + */ + + + if (id != FOURCC_RGB565) { + dcfg = gfx_read_vid32(DISPLAY_CONFIG); + misc = gfx_read_vid32(MISC); + + lutflag = (!(misc & 1) && (dcfg & (1 << 21))); + + if (lutflag) + get_gamma_ram(graphics_lut); + + /* Set the video gamma ram */ + GFX(set_video_palette(NULL)); + } + + GFX(set_video_enable(1)); + + switch (id) { + case FOURCC_UYVY: /* UYVY */ + GFX(set_video_format(VIDEO_FORMAT_UYVY)); + GFX(set_video_size(width, height)); + break; + case FOURCC_Y800: /* Y800 - greyscale - we munge it! */ + case FOURCC_YV12: /* YV12 */ + case FOURCC_I420: /* I420 */ + GFX(set_video_format(VIDEO_FORMAT_Y0Y1Y2Y3)); + GFX(set_video_size(width, height)); + GFX(set_video_yuv_pitch(dstPitch, dstPitch2)); + break; + case FOURCC_YUY2: /* YUY2 */ + GFX(set_video_format(VIDEO_FORMAT_YUYV)); + GFX(set_video_size(width, height)); + break; + case FOURCC_Y2YU: /* Y2YU */ + GFX(set_video_format(VIDEO_FORMAT_Y2YU)); + GFX(set_video_size(width, height)); + break; + case FOURCC_YVYU: /* YVYU */ + GFX(set_video_format(VIDEO_FORMAT_YVYU)); + GFX(set_video_size(width, height)); + break; + case FOURCC_RGB565: + GFX(set_video_format(VIDEO_FORMAT_RGB)); + GFX(set_video_size(width, height)); + break; + + } + + if (pGeode->Panel) { + pGeode->video_x = dstBox->x1; + pGeode->video_y = dstBox->y1; + pGeode->video_w = width; + pGeode->video_h = height; + pGeode->video_srcw = src_w; + pGeode->video_srch = src_h; + pGeode->video_dstw = drw_w; + pGeode->video_dsth = drw_h; + pGeode->video_offset = offset; + pGeode->video_id = id; + pGeode->video_scrnptr = pScrni; + } + + if ((drw_w >= src_w) && (drw_h >= src_h)) + GFX(set_video_scale(width, height, drw_w, drw_h)); + else if (drw_w < src_w) + GFX(set_video_scale(drw_w, height, drw_w, drw_h)); + else if (drw_h < src_h) + GFX(set_video_scale(width, drw_h, drw_w, drw_h)); + + GXSetVideoPosition(dstBox->x1, dstBox->y1, width, height, src_w, + src_h, drw_w, drw_h, id, offset, pScrni); +} + +/* Used by LX as well */ + +Bool +RegionsEqual(RegionPtr A, RegionPtr B) +{ + int *dataA, *dataB; + int num; + + num = REGION_NUM_RECTS(A); + if (num != REGION_NUM_RECTS(B)) { + return FALSE; + } + + if ((A->extents.x1 != B->extents.x1) || + (A->extents.x2 != B->extents.x2) || + (A->extents.y1 != B->extents.y1) || (A->extents.y2 != B->extents.y2)) + return FALSE; + + dataA = (int *)REGION_RECTS(A); + dataB = (int *)REGION_RECTS(B); + + while (num--) { + if ((dataA[0] != dataB[0]) || (dataA[1] != dataB[1])) + return FALSE; + + dataA += 2; + dataB += 2; + } + + return TRUE; +} + +/*---------------------------------------------------------------------------- + * GXPutImage :This function writes a single frame of video into a + * drawable. The position and size of the source rectangle is + * specified by src_x,src_y, src_w and src_h. This data is + * stored in a system memory buffer at buf. The position and + * size of the destination rectangle is specified by drw_x, + * drw_y,drw_w,drw_h.The data is in the format indicated by the + * image descriptor and represents a source of size width by + * height. If sync is TRUE the driver should not return from + * this function until it is through reading the data from buf. + * Returning when sync is TRUE indicates that it is safe for the + * data at buf to be replaced,freed, or modified. + * + * Parameters. + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ + +static int +GXPutImage(ScrnInfoPtr pScrni, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char *buf, + short width, short height, Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw) +{ + GeodePortPrivRec *pPriv = (GeodePortPrivRec *) data; + GeodeRec *pGeode = GEODEPTR(pScrni); + int new_h; + +#if REINIT + BOOL ReInitVideo = FALSE; + static BOOL DoReinitAgain = 0; +#endif + +#if XV_PROFILE + long oldtime, newtime; + + UpdateCurrentTime(); + oldtime = currentTime.milliseconds; +#endif + +#if REINIT +/* update cliplist */ + if (!RegionsEqual(&pPriv->clip, clipBoxes)) { + ReInitVideo = TRUE; + } + + if (DoReinitAgain) + ReInitVideo = TRUE; + + if (ReInitVideo) { + DEBUGMSG(1, (0, X_NONE, "Regional Not Equal - Init\n")); +#endif + DoReinitAgain = ~DoReinitAgain; + if (drw_w > 16384) + drw_w = 16384; + + /* Clip */ + Bx1 = src_x; + Bx2 = src_x + src_w; + By1 = src_y; + By2 = src_y + src_h; + + if ((Bx1 >= Bx2) || (By1 >= By2)) + return Success; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + dstBox.x1 -= pScrni->frameX0; + dstBox.x2 -= pScrni->frameX0; + dstBox.y1 -= pScrni->frameY0; + dstBox.y2 -= pScrni->frameY0; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + srcPitch = (width + 3) & ~3; /* of luma */ + dstPitch = (width + 31) & ~31; + + s2offset = srcPitch * height; + d2offset = dstPitch * height; + + srcPitch2 = ((width >> 1) + 3) & ~3; + dstPitch2 = ((width >> 1) + 15) & ~15; + + s3offset = (srcPitch2 * (height >> 1)) + s2offset; + d3offset = (dstPitch2 * (height >> 1)) + d2offset; + + new_h = dstPitch * height; /* Y */ + new_h += (dstPitch2 * height); /* U+V */ + new_h += pGeode->Pitch - 1; + new_h /= pGeode->Pitch; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + case FOURCC_Y800: + case FOURCC_RGB565: + default: + dstPitch = ((width << 1) + 3) & ~3; + srcPitch = (width << 1); + new_h = ((dstPitch * height) + pGeode->Pitch - 1) / pGeode->Pitch; + break; + } +#if DBUF + if (pPriv->doubleBuffer) + new_h <<= 1; +#endif + + if (!(pPriv->offset = GXAllocateMemory(pScrni, &pPriv->area, new_h))) { + xf86DrvMsg(pScrni->scrnIndex, X_ERROR, + "Could not allocate area of size %d\n", new_h); + return BadAlloc; + } + + /* copy data */ + top = By1; + left = Bx1 & ~1; + npixels = ((Bx2 + 1) & ~1) - left; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + { + int tmp; + + top &= ~1; + + offset = pPriv->offset + (top * dstPitch); + +#if DBUF + if (pPriv->doubleBuffer && pPriv->currentBuffer) + offset += (new_h >> 1) * pGeode->Pitch; +#endif + dst_start = pGeode->FBBase + offset + left; + tmp = ((top >> 1) * srcPitch2) + (left >> 1); + s2offset += tmp; + s3offset += tmp; + if (id == FOURCC_I420) { + tmp = s2offset; + s2offset = s3offset; + s3offset = tmp; + } + nlines = ((By2 + 1) & ~1) - top; + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + case FOURCC_Y800: + case FOURCC_RGB565: + default: + left <<= 1; + buf += (top * srcPitch) + left; + nlines = By2 - top; + offset = (pPriv->offset) + (top * dstPitch); + +#if DBUF + if (pPriv->doubleBuffer && pPriv->currentBuffer) + offset += (new_h >> 1) * pGeode->Pitch; +#endif + dst_start = pGeode->FBBase + offset + left; + break; + } + s1offset = (top * srcPitch) + left; +#if REINIT + /* update cliplist */ + REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes); + + if (pPriv->colorKeyMode == 0) { + xf86XVFillKeyHelper(pScrni->pScreen, pPriv->colorKey, clipBoxes); + } + + GXDisplayVideo(pScrni, id, offset, width, height, dstPitch, + Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w, drw_h); + } +#endif + switch (id) { + case FOURCC_Y800: + /* This is shared between LX and GX, so it lives in amd_common.c */ + GeodeCopyGreyscale(buf, dst_start, srcPitch, dstPitch, nlines, npixels); + break; + case FOURCC_YV12: + case FOURCC_I420: + GXCopyData420(buf + s1offset, dst_start, srcPitch, dstPitch, nlines, + npixels); + GXCopyData420(buf + s2offset, dst_start + d2offset, srcPitch2, + dstPitch2, nlines >> 1, npixels >> 1); + GXCopyData420(buf + s3offset, dst_start + d3offset, srcPitch2, + dstPitch2, nlines >> 1, npixels >> 1); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + case FOURCC_RGB565: + default: + GXCopyData422(buf, dst_start, srcPitch, dstPitch, nlines, npixels); + break; + } +#if !REINIT + /* update cliplist */ + REGION_COPY(pScrni->pScreen, &pPriv->clip, clipBoxes); + if (pPriv->colorKeyMode == 0) { + /* draw these */ + XAAFillSolidRects(pScrni, pPriv->colorKey, GXcopy, ~0, + REGION_NUM_RECTS(clipBoxes), REGION_RECTS(clipBoxes)); + } + + GXDisplayVideo(pScrni, id, offset, width, height, dstPitch, + Bx1, By1, Bx2, By2, &dstBox, src_w, src_h, drw_w, drw_h); +#endif + +#if XV_PROFILE + UpdateCurrentTime(); + newtime = currentTime.milliseconds; + DEBUGMSG(1, (0, X_NONE, "PI %d\n", newtime - oldtime)); +#endif + +#if DBUF + pPriv->currentBuffer ^= 1; +#endif + + pPriv->videoStatus = CLIENT_VIDEO_ON; + pGeode->OverlayON = TRUE; + return Success; +} + +/*---------------------------------------------------------------------------- + * GXQueryImageAttributes + * + * Description :This function is called to let the driver specify how data + * for a particular image of size width by height should be + * stored. + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * id :Id for the video format + * width :width of the image (can be modified by the driver) + * height :height of the image (can be modified by the driver) + * Returns : Size of the memory required for storing this image + * + * Comments :None + * + *---------------------------------------------------------------------------- + */ + +int +GeodeQueryImageAttributes(ScrnInfoPtr pScrni, + int id, unsigned short *w, unsigned short *h, int *pitches, int *offsets) +{ + int size; + int tmp; + + DEBUGMSG(0, (0, X_NONE, "QueryImageAttributes %X\n", id)); + + if (*w > 1024) + *w = 1024; + if (*h > 1024) + *h = 1024; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if (pitches) + pitches[0] = size; + + size *= *h; + if (offsets) + offsets[1] = size; + + tmp = ((*w >> 1) + 3) & ~3; + if (pitches) + pitches[1] = pitches[2] = tmp; + + tmp *= (*h >> 1); + size += tmp; + if (offsets) + offsets[2] = size; + + size += tmp; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + case FOURCC_Y800: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + + size *= *h; + break; + } + return size; +} + +static void +GXBlockHandler(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 = GXBlockHandler; + + if (pPriv->videoStatus & TIMER_MASK) { + GXAccelSync(pScrni); + UpdateCurrentTime(); + if (pPriv->videoStatus & OFF_TIMER) { + if (pPriv->offTime < currentTime.milliseconds) { + GFX(set_video_enable(0)); + + /* If we have saved graphics LUT data - restore it */ + /* Otherwise, turn bypass on */ + + if (lutflag) + GFX(set_graphics_palette(graphics_lut)); + else + GFX(set_video_palette_bypass(1)); + + lutflag = 0; + + pPriv->videoStatus = FREE_TIMER; + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY; + } + } else { /* FREE_TIMER */ + if (pPriv->freeTime < currentTime.milliseconds) { + + if (pPriv->area) { +#ifdef XF86EXA + if (pGeode->useEXA) + exaOffscreenFree(pScrn, pPriv->area); +#endif + if (!pGeode->useEXA) + xf86FreeOffscreenArea(pPriv->area); + + pPriv->area = NULL; + } + + pPriv->videoStatus = 0; + } + } + } +} + +/****************** Offscreen stuff ***************/ + +typedef struct +{ + void * area; + int offset; + Bool isOn; +} OffscreenPrivRec, *OffscreenPrivPtr; + +/*---------------------------------------------------------------------------- + * GXAllocateSurface + * + * Description :This function allocates an area of w by h in the offscreen + * + * Parameters. + * pScrni :Screen handler pointer having screen information. + * + * Returns :None + * + * Comments :None + *---------------------------------------------------------------------------- + */ +static int +GXAllocateSurface(ScrnInfoPtr pScrni, + int id, unsigned short w, unsigned short h, XF86SurfacePtr surface) +{ + void * area = NULL; + int pitch, fbpitch, numlines; + OffscreenPrivRec *pPriv; + + if ((w > 1024) || (h > 1024)) + return BadAlloc; + + w = (w + 1) & ~1; + pitch = ((w << 1) + 15) & ~15; + fbpitch = pScrni->bitsPerPixel * pScrni->displayWidth >> 3; + numlines = ((pitch * h) + fbpitch - 1) / fbpitch; + + if (!(offset = GXAllocateMemory(pScrni, &area, numlines))) + return BadAlloc; + + surface->width = w; + surface->height = h; + + if (!(surface->pitches = xalloc(sizeof(int)))) + return BadAlloc; + + if (!(surface->offsets = xalloc(sizeof(int)))) { + xfree(surface->pitches); + return BadAlloc; + } + + if (!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) { + xfree(surface->pitches); + xfree(surface->offsets); + return BadAlloc; + } + + 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; +} + +static int +GXStopSurface(XF86SurfacePtr surface) +{ + OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr; + + if (pPriv->isOn) { + pPriv->isOn = FALSE; + } + + return Success; +} + +static int +GXFreeSurface(XF86SurfacePtr surface) +{ + OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr; + + if (pPriv->isOn) + GXStopSurface(surface); + + xf86FreeOffscreenArea(pPriv->area); + xfree(surface->pitches); + xfree(surface->offsets); + xfree(surface->devPrivate.ptr); + + return Success; +} + +static int +GXGetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 * value) +{ + return GXGetPortAttribute(pScrni, attribute, value, + (pointer) (GET_PORT_PRIVATE(pScrni))); +} + +static int +GXSetSurfaceAttribute(ScrnInfoPtr pScrni, Atom attribute, INT32 value) +{ + return GXSetPortAttribute(pScrni, attribute, value, + (pointer) (GET_PORT_PRIVATE(pScrni))); +} + +static int +GXDisplaySurface(XF86SurfacePtr surface, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, short drw_w, short drw_h, RegionPtr clipBoxes) +{ + OffscreenPrivRec *pPriv = (OffscreenPrivRec *) surface->devPrivate.ptr; + ScrnInfoPtr pScrni = surface->pScrn; + GeodePortPrivRec *portPriv = GET_PORT_PRIVATE(pScrni); + INT32 x1, y1, x2, y2; + BoxRec dstBox; + + DEBUGMSG(0, (0, X_NONE, "DisplaySuface\n")); + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dstBox.x1 = drw_x; + dstBox.x2 = drw_x + drw_w; + dstBox.y1 = drw_y; + dstBox.y2 = drw_y + drw_h; + + if ((x1 >= x2) || (y1 >= y2)) + return Success; + + dstBox.x1 -= pScrni->frameX0; + dstBox.x2 -= pScrni->frameX0; + dstBox.y1 -= pScrni->frameY0; + dstBox.y2 -= pScrni->frameY0; + + xf86XVFillKeyHelper(pScrni->pScreen, portPriv->colorKey, clipBoxes); + + GXDisplayVideo(pScrni, surface->id, surface->offsets[0], + surface->width, surface->height, surface->pitches[0], + x1, y1, x2, y2, &dstBox, src_w, src_h, drw_w, drw_h); + + 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; +} + +/*---------------------------------------------------------------------------- + * GXInitOffscreenImages + * + * Description :This function sets up the offscreen memory management. It + * fills in the XF86OffscreenImagePtr structure with functions to + * handle offscreen memory operations. + * + * Parameters. + * pScrn :Screen handler pointer having screen information. + * + * Returns : None + * + * Comments :None + *---------------------------------------------------------------------------- + */ +static void +GXInitOffscreenImages(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 = GXAllocateSurface; + offscreenImages[0].free_surface = GXFreeSurface; + offscreenImages[0].display = GXDisplaySurface; + offscreenImages[0].stop = GXStopSurface; + offscreenImages[0].setAttribute = GXSetSurfaceAttribute; + offscreenImages[0].getAttribute = GXGetSurfaceAttribute; + offscreenImages[0].max_width = 1024; + offscreenImages[0].max_height = 1024; + offscreenImages[0].num_attributes = NUM_ATTRIBUTES; + offscreenImages[0].attributes = Attributes; + + xf86XVRegisterOffscreenImages(pScrn, offscreenImages, 1); +} + +#endif /* !XvExtension */ |