diff options
author | Alex Deucher <alex@samba.(none)> | 2008-02-23 19:06:30 -0500 |
---|---|---|
committer | Alex Deucher <alex@samba.(none)> | 2008-02-23 19:06:30 -0500 |
commit | d9be9f34b0d3313e7b22b2a8bb0a8924ad3116bf (patch) | |
tree | 4dd3416086a3dc9b063bd8b245be973cd9fd903f /src/radeon_textured_video.c | |
parent | 9dc4acad79196e9d5d94dd710773bfa83456d47f (diff) |
RADEON: add textured video support for r1xx-r4xx radeons
Based on the kdrive ati video code by Eric Anholt.
R3xx/R4xx still have some clipping issues in certain situations
Diffstat (limited to 'src/radeon_textured_video.c')
-rw-r--r-- | src/radeon_textured_video.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/src/radeon_textured_video.c b/src/radeon_textured_video.c new file mode 100644 index 00000000..8a14024d --- /dev/null +++ b/src/radeon_textured_video.c @@ -0,0 +1,596 @@ +/* + * Copyright 2008 Alex Deucher + * + * 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 (including the next + * paragraph) 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. + * + * + * Based on radeon_exa_render.c and kdrive ati_video.c by Eric Anholt, et al. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> + +#include "radeon.h" +#include "radeon_reg.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_video.h" + +#include <X11/extensions/Xv.h> +#include "fourcc.h" + +#define IMAGE_MAX_WIDTH 2048 +#define IMAGE_MAX_HEIGHT 2048 + +static Bool +RADEONTilingEnabled(ScrnInfoPtr pScrn, PixmapPtr pPix) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef USE_EXA + if (info->useEXA) { + if (info->tilingEnabled && exaGetPixmapOffset(pPix) == 0) + return TRUE; + else + return FALSE; + } else +#endif + { + if (info->tilingEnabled) + return TRUE; + else + return FALSE; + } +} + +static __inline__ int +RADEONPow2(int num) +{ + int pot = 2; + + if (num <= 2) + return num; + + while (pot < num) { + pot *= 2; + } + + return pot; +} + +static __inline__ CARD32 F_TO_DW(float val) +{ + union { + float f; + CARD32 l; + } tmp; + tmp.f = val; + return tmp.l; +} + +#define ACCEL_MMIO +#define VIDEO_PREAMBLE() unsigned char *RADEONMMIO = info->MMIO +#define BEGIN_VIDEO(n) RADEONWaitForFifo(pScrn, (n)) +#define OUT_VIDEO_REG(reg, val) OUTREG(reg, val) +#define OUT_VIDEO_REG_F(reg, val) OUTREG(reg, F_TO_DW(val)) +#define FINISH_VIDEO() + +#include "radeon_textured_videofuncs.c" + +#undef ACCEL_MMIO +#undef VIDEO_PREAMBLE +#undef BEGIN_VIDEO +#undef OUT_VIDEO_REG +#undef FINISH_VIDEO + +#ifdef XF86DRI + +#define ACCEL_CP +#define VIDEO_PREAMBLE() \ + RING_LOCALS; \ + RADEONCP_REFRESH(pScrn, info) +#define BEGIN_VIDEO(n) BEGIN_RING(2*(n)) +#define OUT_VIDEO_REG(reg, val) OUT_RING_REG(reg, val) +#define FINISH_VIDEO() ADVANCE_RING() +#define OUT_VIDEO_RING_F(x) OUT_RING(F_TO_DW(x)) + +#include "radeon_textured_videofuncs.c" + +#endif /* XF86DRI */ + +static void +RADEONXVCopyPlanarData(CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int srcPitch2, int dstPitch, + int srcW, int srcH, int height, + int top, int left, int h, int w, int id) +{ + int i, j; + CARD8 *src1, *src2, *src3, *dst1; + int srcDown = srcPitch, srcDown2 = srcPitch2; + int srcRight = 2, srcRight2 = 1, srcNext = 1; + + /* compute source data pointers */ + src1 = src; + src2 = src1 + height * srcPitch; + src3 = src2 + (height >> 1) * srcPitch2; + switch (randr) { + case RR_Rotate_0: + srcDown = srcPitch; + srcDown2 = srcPitch2; + srcRight = 2; + srcRight2 = 1; + srcNext = 1; + break; + case RR_Rotate_90: + src1 = src1 + srcH - 1; + src2 = src2 + (srcH >> 1) - 1; + src3 = src3 + (srcH >> 1) - 1; + srcDown = -1; + srcDown2 = -1; + srcRight = srcPitch * 2; + srcRight2 = srcPitch2; + srcNext = srcPitch; + break; + case RR_Rotate_180: + src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1); + src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + srcDown = -srcPitch; + srcDown2 = -srcPitch2; + srcRight = -2; + srcRight2 = -1; + srcNext = -1; + break; + case RR_Rotate_270: + src1 = src1 + srcPitch * (srcW - 1); + src2 = src2 + srcPitch2 * ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcW >> 1) - 1); + srcDown = 1; + srcDown2 = 1; + srcRight = -srcPitch * 2; + srcRight2 = -srcPitch2; + srcNext = -srcPitch; + break; + } + + /* adjust for origin */ + src1 += top * srcDown + left * srcNext; + src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + + if (id == FOURCC_I420) { + CARD8 *srct = src2; + src2 = src3; + src3 = srct; + } + + dst1 = dst; + + w >>= 1; + for (j = 0; j < h; j++) { + CARD32 *dst = (CARD32 *)dst1; + CARD8 *s1l = src1; + CARD8 *s1r = src1 + srcNext; + CARD8 *s2 = src2; + CARD8 *s3 = src3; + + for (i = 0; i < w; i++) { + *dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24); + s1l += srcRight; + s1r += srcRight; + s2 += srcRight2; + s3 += srcRight2; + } + src1 += srcDown; + dst1 += dstPitch; + if (j & 1) { + src2 += srcDown2; + src3 += srcDown2; + } + } +} + +static void +RADEONXVCopyPackedData(CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int dstPitch, + int srcW, int srcH, int top, int left, + int h, int w) +{ + int srcDown = srcPitch, srcRight = 2, srcNext; + int p; + + switch (randr) { + case RR_Rotate_0: + srcDown = srcPitch; + srcRight = 2; + break; + case RR_Rotate_90: + src += (srcH - 1) * 2; + srcDown = -2; + srcRight = srcPitch; + break; + case RR_Rotate_180: + src += srcPitch * (srcH - 1) + (srcW - 1) * 2; + srcDown = -srcPitch; + srcRight = -2; + break; + case RR_Rotate_270: + src += srcPitch * (srcW - 1); + srcDown = 2; + srcRight = -srcPitch; + break; + } + + src = src + top * srcDown + left * srcRight; + + w >>= 1; + /* srcRight >>= 1; */ + srcNext = srcRight >> 1; + while (h--) { + CARD16 *s = (CARD16 *)src; + CARD32 *d = (CARD32 *)dst; + p = w; + while (p--) { + *d++ = s[0] | (s[srcNext] << 16); + s += srcRight; + } + src += srcPitch; + dst += dstPitch; + } +} + +static int +RADEONPutImageTextured(ScrnInfoPtr pScrn, + 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) +{ + ScreenPtr pScreen = pScrn->pScreen; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + INT32 x1, x2, y1, y2; + int randr = RR_Rotate_0 /* XXX */; + int srcPitch, srcPitch2, dstPitch; + int top, left, npixels, nlines, size; + BoxRec dstBox; + int dst_width = width, dst_height = height; + int rot_x1, rot_y1, rot_x2, rot_y2; + int dst_x1, dst_y1, dst_x2, dst_y2; + int rot_src_w, rot_src_h, rot_drw_w, rot_drw_h; + + /* Clip */ + 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 (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, width, height)) + return Success; + + src_w = (x2 - x1) >> 16; + src_h = (y2 - y1) >> 16; + drw_w = dstBox.x2 - dstBox.x1; + drw_h = dstBox.y2 - dstBox.y1; + + if ((x1 >= x2) || (y1 >= y2)) + return Success; + + if (randr & (RR_Rotate_0|RR_Rotate_180)) { + dst_width = width; + dst_height = height; + rot_src_w = src_w; + rot_src_h = src_h; + rot_drw_w = drw_w; + rot_drw_h = drw_h; + } else { + dst_width = height; + dst_height = width; + rot_src_w = src_h; + rot_src_h = src_w; + rot_drw_w = drw_h; + rot_drw_h = drw_w; + } + + switch (randr) { + case RR_Rotate_0: + default: + dst_x1 = dstBox.x1; + dst_y1 = dstBox.y1; + dst_x2 = dstBox.x2; + dst_y2 = dstBox.y2; + rot_x1 = x1; + rot_y1 = y1; + rot_x2 = x2; + rot_y2 = y2; + break; + case RR_Rotate_90: + dst_x1 = dstBox.y1; + dst_y1 = pScrn->virtualY - dstBox.x2; + dst_x2 = dstBox.y2; + dst_y2 = pScrn->virtualY - dstBox.x1; + rot_x1 = y1; + rot_y1 = (src_w << 16) - x2; + rot_x2 = y2; + rot_y2 = (src_w << 16) - x1; + break; + case RR_Rotate_180: + dst_x1 = pScrn->virtualX - dstBox.x2; + dst_y1 = pScrn->virtualY - dstBox.y2; + dst_x2 = pScrn->virtualX - dstBox.x1; + dst_y2 = pScrn->virtualY - dstBox.y1; + rot_x1 = (src_w << 16) - x2; + rot_y1 = (src_h << 16) - y2; + rot_x2 = (src_w << 16) - x1; + rot_y2 = (src_h << 16) - y1; + break; + case RR_Rotate_270: + dst_x1 = pScrn->virtualX - dstBox.y2; + dst_y1 = dstBox.x1; + dst_x2 = pScrn->virtualX - dstBox.y1; + dst_y2 = dstBox.x2; + rot_x1 = (src_h << 16) - y2; + rot_y1 = x1; + rot_x2 = (src_h << 16) - y1; + rot_y2 = x2; + break; + } + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + dstPitch = ((dst_width << 1) + 15) & ~15; + srcPitch = (width + 3) & ~3; + srcPitch2 = ((width >> 1) + 3) & ~3; + size = dstPitch * dst_height; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + dstPitch = ((dst_width << 1) + 15) & ~15; + srcPitch = (width << 1); + srcPitch2 = 0; + size = dstPitch * dst_height; + break; + } + + if (pPriv->video_memory != NULL && size != pPriv->size) { + RADEONFreeMemory(pScrn, pPriv->video_memory); + pPriv->video_memory = NULL; + } + + if (pPriv->video_memory == NULL) { + pPriv->video_offset = RADEONAllocateMemory(pScrn, + &pPriv->video_memory, + size * 2); + if (pPriv->video_offset == 0) + return BadAlloc; + } + + if (pDraw->type == DRAWABLE_WINDOW) + pPriv->pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); + else + pPriv->pPixmap = (PixmapPtr)pDraw; + +#ifdef USE_EXA + if (info->useEXA) { + /* Force the pixmap into framebuffer so we can draw to it. */ + exaMoveInPixmap(pPriv->pPixmap); + } +#endif + + if (!info->useEXA && + (((char *)pPriv->pPixmap->devPrivate.ptr < (char *)info->FB) || + ((char *)pPriv->pPixmap->devPrivate.ptr >= (char *)info->FB + + info->FbMapSize))) { + /* If the pixmap wasn't in framebuffer, then we have no way in XAA to + * force it there. So, we simply refuse to draw and fail. + */ + return BadAlloc; + } + + pPriv->src_offset = pPriv->video_offset + info->fbLocation; + pPriv->src_addr = (CARD8 *)(info->FB + pPriv->video_offset); + pPriv->src_pitch = dstPitch; + pPriv->size = size; + pPriv->pDraw = pDraw; + +#if 0 + ErrorF("src_offset: 0x%x\n", pPriv->src_offset); + ErrorF("src_addr: 0x%x\n", pPriv->src_addr); + ErrorF("src_pitch: 0x%x\n", pPriv->src_pitch); +#endif + + /* copy data */ + top = rot_y1 >> 16; + left = (rot_x1 >> 16) & ~1; + npixels = ((((rot_x2 + 0xffff) >> 16) + 1) & ~1) - left; + + /* Since we're probably overwriting the area that might still be used + * for the last PutImage request, wait for idle. + */ +#ifdef XF86DRI + if (info->directRenderingEnabled) + RADEONWaitForIdleCP(pScrn); + else +#endif + RADEONWaitForIdleMMIO(pScrn); + + + switch(id) { + case FOURCC_YV12: + case FOURCC_I420: + top &= ~1; + nlines = ((((rot_y2 + 0xffff) >> 16) + 1) & ~1) - top; + RADEONXVCopyPlanarData(buf, pPriv->src_addr, randr, + srcPitch, srcPitch2, dstPitch, rot_src_w, rot_src_h, + height, top, left, nlines, npixels, id); + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + nlines = ((rot_y2 + 0xffff) >> 16) - top; + RADEONXVCopyPackedData(buf, pPriv->src_addr, randr, + srcPitch, dstPitch, rot_src_w, rot_src_h, top, left, + nlines, npixels); + break; + } + + /* update cliplist */ + if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { + REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); + } + + pPriv->id = id; + pPriv->src_x1 = rot_x1; + pPriv->src_y1 = rot_y1; + pPriv->src_x2 = rot_x2; + pPriv->src_y2 = rot_y2; + pPriv->src_w = rot_src_w; + pPriv->src_h = rot_src_h; + pPriv->dst_x1 = dst_x1; + pPriv->dst_y1 = dst_y1; + pPriv->dst_x2 = dst_x2; + pPriv->dst_y2 = dst_y2; + pPriv->dst_w = rot_drw_w; + pPriv->dst_h = rot_drw_h; + +#ifdef XF86DRI + if (info->directRenderingEnabled) + RADEONDisplayTexturedVideoCP(pScrn, pPriv); + else +#endif + RADEONDisplayTexturedVideoMMIO(pScrn, pPriv); + + return Success; +} + +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = +{ + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 0 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; + +XF86VideoAdaptorPtr +RADEONSetupImageTexturedVideo(ScreenPtr pScreen) +{ + RADEONPortPrivPtr pPortPriv; + XF86VideoAdaptorPtr adapt; + int i; + int num_texture_ports = 16; + + adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + num_texture_ports * + (sizeof(RADEONPortPrivRec) + sizeof(DevUnion))); + if (adapt == NULL) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "Radeon Textured Video"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = num_texture_ports; + adapt->pPortPrivates = (DevUnion*)(&adapt[1]); + + pPortPriv = + (RADEONPortPrivPtr)(&adapt->pPortPrivates[num_texture_ports]); + + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pAttributes = Attributes; + adapt->pImages = Images; + adapt->nImages = NUM_IMAGES; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = RADEONStopVideo; + adapt->SetPortAttribute = RADEONSetPortAttribute; + adapt->GetPortAttribute = RADEONGetPortAttribute; + adapt->QueryBestSize = RADEONQueryBestSize; + adapt->PutImage = RADEONPutImageTextured; + adapt->ReputImage = NULL; + adapt->QueryImageAttributes = RADEONQueryImageAttributes; + + for (i = 0; i < num_texture_ports; i++) { + RADEONPortPrivPtr pPriv = &pPortPriv[i]; + + pPriv->textured = TRUE; + pPriv->videoStatus = 0; + pPriv->currentBuffer = 0; + pPriv->doubleBuffer = 0; + + /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ + REGION_NULL(pScreen, &pPriv->clip); + adapt->pPortPrivates[i].ptr = (pointer) (pPriv); + } + + return adapt; +} + |