diff options
Diffstat (limited to 'src/xvmc')
-rw-r--r-- | src/xvmc/I810XvMC.c | 4507 | ||||
-rw-r--r-- | src/xvmc/I810XvMC.h | 469 |
2 files changed, 4976 insertions, 0 deletions
diff --git a/src/xvmc/I810XvMC.c b/src/xvmc/I810XvMC.c new file mode 100644 index 00000000..e6731c62 --- /dev/null +++ b/src/xvmc/I810XvMC.c @@ -0,0 +1,4507 @@ +/*************************************************************************** + +Copyright 2001 Intel Corporation. All Rights Reserved. + +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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/************************************************************************* +** File libI810XvMC.c +** +** Authors: +** Matt Sottek <matthew.j.sottek@intel.com> +** Bob Paauwe <bob.j.paauwe@intel.com> +** +** +***************************************************************************/ +/* $XFree86: xc/lib/XvMC/hw/i810/I810XvMC.c,v 1.11 2002/11/19 09:35:49 alanh Exp $ */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> + +#include <sys/ioctl.h> +#include <X11/Xlibint.h> +#include <fourcc.h> +#include <Xv.h> +#include <Xvlib.h> +#include <XvMC.h> +#include <XvMClib.h> +#include "I810XvMC.h" + +static int error_base; +static int event_base; + +/*************************************************************************** +// Function: i810_get_free_buffer +// Description: Allocates a free dma page using kernel ioctls, then +// programs the data into the already allocated dma buffer list. +// Arguments: pI810XvMC private data structure from the current context. +// Notes: We faked the drmMapBufs for the i810's security so now we have +// to insert an allocated page into the correct spot in the faked +// list to keep up appearences. +// Concept for this function was taken from Mesa sources. +// Returns: drmBufPtr containing the information about the allocated page. +***************************************************************************/ +drmBufPtr i810_get_free_buffer(i810XvMCContext *pI810XvMC) { + drmI810DMA dma; + drmBufPtr buf; + + dma.granted = 0; + dma.request_size = 4096; + while(!dma.granted) { + if(GET_BUFFER(pI810XvMC, dma) || !dma.granted) + FLUSH(pI810XvMC); + } /* No DMA granted */ + + buf = &(pI810XvMC->dmabufs->list[dma.request_idx]); + buf->idx = dma.request_idx; + buf->used = 0; + buf->total = dma.request_size; + buf->address = (drmAddress)dma.virtual; + return buf; +} + +/*************************************************************************** +// Function: free_privContext +// Description: Free's the private context structure if the reference +// count is 0. +***************************************************************************/ +void i810_free_privContext(i810XvMCContext *pI810XvMC) { + + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + + pI810XvMC->ref--; + if(!pI810XvMC->ref) { + drmUnmapBufs(pI810XvMC->dmabufs); + drmUnmap(pI810XvMC->overlay.address,pI810XvMC->overlay.size); + drmUnmap(pI810XvMC->surfaces.address,pI810XvMC->surfaces.size); + drmClose(pI810XvMC->fd); + + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + } + + I810_UNLOCK(pI810XvMC); +} + + +/*************************************************************************** +// Function: XvMCCreateContext +// Description: Create a XvMC context for the given surface parameters. +// Arguments: +// display - Connection to the X server. +// port - XvPortID to use as avertised by the X connection. +// surface_type_id - Unique identifier for the Surface type. +// width - Width of the surfaces. +// height - Height of the surfaces. +// flags - one or more of the following +// XVMC_DIRECT - A direct rendered context is requested. +// +// Notes: surface_type_id and width/height parameters must match those +// returned by XvMCListSurfaceTypes. +// Returns: Status +***************************************************************************/ +Status XvMCCreateContext(Display *display, XvPortID port, + int surface_type_id, int width, int height, int flags, + XvMCContext *context) { + i810XvMCContext *pI810XvMC; + char busIdString[10]; + int priv_count; + uint *priv_data; + uint magic; + Status ret; + int major, minor; + + /* Verify Obvious things first */ + if(context == NULL) { + return XvMCBadContext; + } + + if(!flags & XVMC_DIRECT) { + /* Indirect */ + printf("Indirect Rendering not supported!\nUsing Direct."); + } + + /* Limit use to root for now */ + if(geteuid()) { + printf("Use of XvMC on i810 is currently limited to root\n"); + return BadAccess; + } + + /* FIXME: Check $DISPLAY for legal values here */ + + context->surface_type_id = surface_type_id; + context->width = (unsigned short)width; + context->height = (unsigned short)height; + context->flags = flags; + context->port = port; + /* + Width, Height, and flags are checked against surface_type_id + and port for validity inside the X server, no need to check + here. + */ + + /* Allocate private Context data */ + context->privData = (void *)malloc(sizeof(i810XvMCContext)); + if(!context->privData) { + printf("Unable to allocate resources for XvMC context.\n"); + return BadAlloc; + } + pI810XvMC = (i810XvMCContext *)context->privData; + + + /* Verify the XvMC extension exists */ + if(! XvMCQueryExtension(display, &event_base, + &error_base)) { + printf("XvMC Extension is not available!\n"); + return BadAlloc; + } + /* Verify XvMC version */ + ret = XvMCQueryVersion(display, &major, &minor); + if(ret) { + printf("XvMCQuery Version Failed, unable to determine protocol version\n"); + } + /* FIXME: Check Major and Minor here */ + + /* Check for drm */ + if(! drmAvailable()) { + printf("Direct Rendering is not avilable on this system!\n"); + return BadAlloc; + } + + /* + Build the Attribute Atoms, and Initialize the ones that exist + in Xv. + */ + pI810XvMC->xv_colorkey = XInternAtom(display,"XV_COLORKEY",0); + if(!pI810XvMC->xv_colorkey) { + return XvBadPort; + } + ret = XvGetPortAttribute(display,port,pI810XvMC->xv_colorkey, + &pI810XvMC->colorkey); + if(ret) { + return ret; + } + pI810XvMC->xv_brightness = XInternAtom(display,"XV_BRIGHTNESS",0); + pI810XvMC->xv_saturation = XInternAtom(display,"XV_SATURATION",0); + pI810XvMC->xv_contrast = XInternAtom(display,"XV_CONTRAST",0); + pI810XvMC->brightness = 0; + pI810XvMC->saturation = 0x80; /* 1.0 in 3.7 format */ + pI810XvMC->contrast = 0x40; /* 1.0 in 3.6 format */ + + /* Open DRI Device */ + if((pI810XvMC->fd = drmOpen("i810",NULL)) < 0) { + printf("DRM Device for i810 could not be opened.\n"); + free(busIdString); + free(pI810XvMC); + return BadAccess; + } /* !pI810XvMC->fd */ + + /* Get magic number and put it in privData for passing */ + drmGetMagic(pI810XvMC->fd,&magic); + context->flags = (unsigned long)magic; + + /* + Pass control to the X server to create a drmContext for us and + validate the with/height and flags. + */ + if((ret = _xvmc_create_context(display, context, &priv_count, &priv_data))) { + printf("Unable to create XvMC Context.\n"); + return ret; + } + + /* + X server returns a structure like this: + drmContext + fbBase + OverlayOffset + OverlaySize + SurfacesOffset + SurfacesSize + busIdString = 9 char + 1 + */ + if(priv_count != 9) { + printf("_xvmc_create_context() returned incorrect data size!\n"); + printf("\tExpected 9, got %d\n",priv_count); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } + pI810XvMC->drmcontext = priv_data[0]; + pI810XvMC->fb_base = priv_data[1]; + pI810XvMC->overlay.offset = priv_data[2] + priv_data[1]; + pI810XvMC->overlay.size = priv_data[3]; + pI810XvMC->surfaces.offset = priv_data[4] + priv_data[1]; + pI810XvMC->surfaces.size = priv_data[5]; + strncpy(pI810XvMC->busIdString,(char *)&priv_data[6],9); + pI810XvMC->busIdString[9] = '\0'; + + /* Must free the private data we were passed from X */ + free(priv_data); + + /* Initialize private context values */ + pI810XvMC->current = 0; + pI810XvMC->lock = 0; + pI810XvMC->last_flip = 0; + pI810XvMC->dual_prime = 0; + + /* + Map dma Buffers: Not really, this would be a drmMapBufs + but due to the i810 security model we have to just create an + empty data structure to fake it. + */ + pI810XvMC->dmabufs = (drmBufMapPtr)malloc(sizeof(drmBufMap)); + if(pI810XvMC->dmabufs == NULL) { + printf("Dma Bufs could not be mapped.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } /* pI810XvMC->dmabufs == NULL */ + memset(pI810XvMC->dmabufs, 0, sizeof(drmBufMap)); + pI810XvMC->dmabufs->list = (drmBufPtr)malloc(sizeof(drmBuf) * + I810_DMA_BUF_NR); + if(pI810XvMC->dmabufs->list == NULL) { + printf("Dma Bufs could not be mapped.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC); + return BadAlloc; + } /* pI810XvMC->dmabufs->list == NULL */ + memset(pI810XvMC->dmabufs->list, 0, sizeof(drmBuf) * I810_DMA_BUF_NR); + + /* Map the Overlay memory */ + if(drmMap(pI810XvMC->fd,pI810XvMC->overlay.offset, + pI810XvMC->overlay.size,&(pI810XvMC->overlay.address)) < 0) { + printf("Unable to map Overlay at offset 0x%x and size 0x%x\n", + (unsigned int)pI810XvMC->overlay.offset,pI810XvMC->overlay.size); + _xvmc_destroy_context(display, context); + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + return BadAlloc; + } /* drmMap() < 0 */ + + /* Overlay Regs are offset 1024 into Overlay Map */ + pI810XvMC->oregs = (i810OverlayRec *) + ((unsigned char *)pI810XvMC->overlay.address + 1024); + + /* Map Surfaces */ + if(drmMap(pI810XvMC->fd,pI810XvMC->surfaces.offset, + pI810XvMC->surfaces.size,&(pI810XvMC->surfaces.address)) < 0) { + printf("Unable to map XvMC Surfaces.\n"); + _xvmc_destroy_context(display, context); + free(pI810XvMC->dmabufs->list); + free(pI810XvMC); + return BadAlloc; + } /* drmMap() < 0 */ + + /* + There is a tiny chance that someone was using the overlay and + issued a flip that hasn't finished. To be 100% sure I'll just + take the lock and sleep for the worst case time for a flip. + */ + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + usleep(20000); /* 1/50th Sec for 50hz refresh */ + + /* Set up Overlay regs with Initial Values */ + pI810XvMC->oregs->YRGB_VPH = 0; + pI810XvMC->oregs->UV_VPH = 0; + pI810XvMC->oregs->HORZ_PH = 0; + pI810XvMC->oregs->INIT_PH = 0; + pI810XvMC->oregs->DWINPOS = 0; + pI810XvMC->oregs->DWINSZ = (I810_XVMC_MAXHEIGHT << 16) | + I810_XVMC_MAXWIDTH; + pI810XvMC->oregs->SWID = I810_XVMC_MAXWIDTH | (I810_XVMC_MAXWIDTH << 15); + pI810XvMC->oregs->SWIDQW = (I810_XVMC_MAXWIDTH >> 3) | + (I810_XVMC_MAXWIDTH << 12); + pI810XvMC->oregs->SHEIGHT = I810_XVMC_MAXHEIGHT | + (I810_XVMC_MAXHEIGHT << 15); + pI810XvMC->oregs->YRGBSCALE = 0x80004000; /* scale factor 1 */ + pI810XvMC->oregs->UVSCALE = 0x80004000; /* scale factor 1 */ + pI810XvMC->oregs->OV0CLRC0 = 0x4000; /* brightness: 0 contrast: 1.0 */ + pI810XvMC->oregs->OV0CLRC1 = 0x80; /* saturation: bypass */ + + /* Destination Colorkey Setup */ + pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey); + pI810XvMC->oregs->DCLRKM = 0x80070307; + + + pI810XvMC->oregs->SCLRKVH = 0; + pI810XvMC->oregs->SCLRKVL = 0; + pI810XvMC->oregs->SCLRKM = 0; /* source color key disable */ + pI810XvMC->oregs->OV0CONF = 0; /* two 720 pixel line buffers */ + + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST | YUV_420; + + pI810XvMC->ref = 1; + + I810_UNLOCK(pI810XvMC); + + return Success; + +} + +/*************************************************************************** +// Function: XvMCDestroyContext +// Description: Destorys the specified context. +// +// Arguments: +// display - Specifies the connection to the server. +// context - The context to be destroyed. +// +// Returns: Status +***************************************************************************/ +Status XvMCDestroyContext(Display *display, XvMCContext *context) { + i810XvMCContext *pI810XvMC; + + if(context == NULL) { + return (error_base + XvMCBadContext); + } + if(context->privData == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = (i810XvMCContext *)context->privData; + + /* Turn off the overlay */ + if(pI810XvMC->last_flip) { + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + /* Make sure last flip is done */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST; + pI810XvMC->current = !pI810XvMC->current; + if(pI810XvMC->current == 1) { + pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0; + } + OVERLAY_FLIP(pI810XvMC); + pI810XvMC->last_flip++; + + /* Wait for the flip */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + I810_UNLOCK(pI810XvMC); + } + + /* Pass Control to the X server to destroy the drmContext */ + _xvmc_destroy_context(display, context); + + i810_free_privContext(pI810XvMC); + context->privData = NULL; + + return Success; +} + + +/*************************************************************************** +// Function: XvMCCreateSurface +***************************************************************************/ +Status XvMCCreateSurface( Display *display, XvMCContext *context, + XvMCSurface *surface) { + i810XvMCContext *pI810XvMC; + i810XvMCSurface *pI810Surface; + int priv_count; + uint *priv_data; + Status ret; + + if((surface == NULL) || (context == NULL) || (display == NULL)){ + return BadValue; + } + + pI810XvMC = (i810XvMCContext *)context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + + surface->privData = (i810XvMCSurface *)malloc(sizeof(i810XvMCSurface)); + if(!surface->privData) { + return BadAlloc; + } + pI810Surface = (i810XvMCSurface *)surface->privData; + + /* Initialize private values */ + pI810Surface->privContext = pI810XvMC; + pI810Surface->last_render = 0; + pI810Surface->last_flip = 0; + pI810Surface->second_field = 0; + + if((ret = _xvmc_create_surface(display, context, surface, + &priv_count, &priv_data))) { + free(pI810Surface); + printf("Unable to create XvMCSurface.\n"); + return ret; + } + + /* + _xvmc_create_subpicture returns 2 uints with the offset into + the DRM map for the Y surface and UV surface. + */ + if(priv_count != 2) { + printf("_xvmc_create_surface() return incorrect data size.\n"); + printf("Expected 2 got %d\n",priv_count); + free(priv_data); + free(pI810Surface); + return BadAlloc; + } + /* Data == Client Address, offset == Physical address offset */ + pI810Surface->data = pI810XvMC->surfaces.address; + pI810Surface->offset = pI810XvMC->surfaces.offset; + + + /* + i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch + and the Tiler need 512k aligned surfaces, basically we are + stuck with fixed memory with pitch 1024 for Y data. UV = 512. + */ + pI810Surface->pitch = 10; + if((surface->surface_type_id == FOURCC_UYVY) || + (surface->surface_type_id == FOURCC_YUY2)) { + /* This is not implemented server side. */ + pI810Surface->pitch++; + } + + /* + offsets[0,1,2] == Offsets from either data or offset for the Y + U and V surfaces. + */ + pI810Surface->offsets[0] = priv_data[0]; + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[0]) & 4095) { + printf("XvMCCreateSurface: Surface offset 0 is not 4096 aligned\n"); + } + + if((surface->surface_type_id == FOURCC_UYVY) || + (surface->surface_type_id == FOURCC_YUY2)) { + /* Packed surface, not fully implemented */ + pI810Surface->offsets[1] = 0; + pI810Surface->offsets[2] = 0; + } + else { + /* Planar surface */ + pI810Surface->offsets[1] = priv_data[1]; + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[1]) & 2047) { + printf("XvMCCreateSurface: Surface offset 1 is not 2048 aligned\n"); + } + + pI810Surface->offsets[2] = ((unsigned long)pI810Surface->offsets[1] + + (1<<(pI810Surface->pitch - 1)) * 288); + if(((unsigned long)pI810Surface->data + pI810Surface->offsets[2]) & 2047) { + printf("XvMCCreateSurface: Surface offset 2 is not 2048 aligned\n"); + } + + } + + /* Free data returned from xvmc_create_surface */ + free(priv_data); + + /* Clear the surface to 0 */ + memset((void *)((unsigned long)pI810Surface->data + (unsigned long)pI810Surface->offsets[0]), + 0, ((1<<pI810Surface->pitch) * surface->height)); + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + /* Destination buffer info command */ + pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff) | + (pI810Surface->pitch - 9)); + pI810Surface->dbi1u = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[1]) & ~0xfc000fff) | + (pI810Surface->pitch - 10)); + pI810Surface->dbi1v = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[2]) & ~0xfc000fff) | + (pI810Surface->pitch - 10)); + + /* Destination buffer variables command */ + pI810Surface->dbv1 = (0x8<<20) | (0x8<<16); + /* Map info command */ + pI810Surface->mi1y = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 3); + pI810Surface->mi1u = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4); + pI810Surface->mi1v = (0x1<<24) | (1<<9) | (pI810Surface->pitch - 4); + + pI810Surface->mi2y = (((unsigned int)surface->height - 1)<<16) | + ((unsigned int)surface->width - 1); + pI810Surface->mi2u = (((unsigned int)surface->height - 1)<<15) | + (((unsigned int)surface->width - 1)>>1); + pI810Surface->mi2v = pI810Surface->mi2u; + + pI810Surface->mi3y = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0x0000000f; + pI810Surface->mi3u = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[1]) & ~0x0000000f; + pI810Surface->mi3v = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[2]) & ~0x0000000f; + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + /* Destination buffer info command */ + pI810Surface->dbi1y = ((((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff) | + (pI810Surface->pitch - 9)); + /* Destination buffer variables command */ + if(surface->surface_type_id == FOURCC_YUY2) { + pI810Surface->dbv1 = 0x5<<8; + pI810Surface->mi1y = 0x5<<24 | pI810Surface->pitch | 0x1<<21; + } + else { + pI810Surface->dbv1 = 0x4<<8; + pI810Surface->mi1y = 0x5<<24 | (pI810Surface->pitch - 3); + } + pI810Surface->mi2y = (((unsigned int)surface->width - 1)<<16) | + ((unsigned int)surface->height - 1); + pI810Surface->mi3y = ((unsigned int)pI810Surface->offset + + pI810Surface->offsets[0]) & ~0xfc000fff; + break; + } + pI810XvMC->ref++; + + return Success; +} + + +/*************************************************************************** +// Function: XvMCDestroySurface +***************************************************************************/ +Status XvMCDestroySurface(Display *display, XvMCSurface *surface) { + i810XvMCSurface *pI810Surface; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (surface == NULL)) { + return BadValue; + } + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + + pI810Surface = (i810XvMCSurface *)surface->privData; + if(pI810Surface->last_flip) { + XvMCSyncSurface(display,surface); + } + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + + _xvmc_destroy_surface(display,surface); + + i810_free_privContext(pI810XvMC); + + free(pI810Surface); + surface->privData = NULL; + return Success; +} + +/*************************************************************************** +// Function: XvMCCreateBlocks +***************************************************************************/ +Status XvMCCreateBlocks(Display *display, XvMCContext *context, + unsigned int num_blocks, + XvMCBlockArray *block) { + + if((display == NULL) || (context == NULL) || (num_blocks == 0)) { + return BadValue; + } + + block->blocks = (short *)malloc(num_blocks<<6 * sizeof(short)); + if(block->blocks == NULL) { + return BadAlloc; + } + + block->num_blocks = num_blocks; + block->context_id = context->context_id; + + block->privData = NULL; + + return Success; +} + +/*************************************************************************** +// Function: XvMCDestroyBlocks +***************************************************************************/ +Status XvMCDestroyBlocks(Display *display, XvMCBlockArray *block) { + if(display == NULL) { + return BadValue; + } + + free(block->blocks); + block->num_blocks = 0; + block->context_id = 0; + block->privData = NULL; + return Success; +} + +/*************************************************************************** +// Function: XvMCCreateMacroBlocks +***************************************************************************/ +Status XvMCCreateMacroBlocks(Display *display, XvMCContext *context, + unsigned int num_blocks, + XvMCMacroBlockArray *blocks) { + + if((display == NULL) || (context == NULL) || (blocks == NULL) || + (num_blocks == 0)) { + return BadValue; + } + memset(blocks,0,sizeof(XvMCMacroBlockArray)); + blocks->context_id = context->context_id; + blocks->privData = NULL; + + blocks->macro_blocks = (XvMCMacroBlock *) + malloc(num_blocks * sizeof(XvMCMacroBlock)); + if(blocks->macro_blocks == NULL) { + return BadAlloc; + } + blocks->num_blocks = num_blocks; + + return Success; +} + +/*************************************************************************** +// Function: XvMCDestroyMacroBlocks +***************************************************************************/ +Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray *block) { + if((display == NULL) || (block == NULL)) { + return BadValue; + } + if(block->macro_blocks) { + free(block->macro_blocks); + } + block->context_id = 0; + block->num_blocks = 0; + block->privData = NULL; + + return Success; +} + + +/*************************************************************************** +// Function: dp (Debug Print) +// Description: This function prints out in hex i * uint32_t at the address +// supplied. This enables you to print out the dma buffers from +// within the debugger even though they are not in your address space. +***************************************************************************/ +void dp(unsigned int *address, unsigned int i) { + int j; + + printf("DebugPrint:\n"); + for(j=0; j<i; j++) { + printf("0x%8.8x ",address[j]); + if(j && !(j & 7)) { printf("\n");} + } +} + +/*************************************************************************** +// Macro: PACK_* +// Description: Packs 16bit signed data from blocks into either 8bit unsigned +// intra data or 16bit signed correction data, both packed into +// 32 bit integers. +***************************************************************************/ +#define PACK_INTRA_DATA(d,b,n) \ + do { \ + char *dp = (char *)d; \ + char *bp = (char *)b; \ + int counter; \ + for(counter = 0; counter < n; counter++) { \ + *dp++ = *bp; \ + bp += 2; \ + } \ + }while(0); + +#define PACK_CORR_DATA(d,b,n) \ + memcpy(d,b,n); \ + d = (uint *)((unsigned long)d + n); + +#define MARK_CORR_DATA(d,n) \ + do { \ + uint* q = (uint*)((unsigned long)d - n); \ + while((unsigned long)q < (unsigned long)d) { \ + *q++ += 0x00330033; \ + } \ + }while(0); + +#define MARK_INTRA_BLOCK(d) \ + do { \ + int q; \ + for(q=0; q<16; q++) { \ + d[q] += 0x33333333; \ + } \ + }while(0); + +/* + Used for DCT 1 when we need DCT 0. Instead + of reading from one block we read from two and + interlace. +*/ +#define PACK_CORR_DATA_1to0(d,top,bottom) \ + do { \ + short *t = top,*b = bottom; \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 16); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 16); \ + }while(0); + +/* Used for DCT 0 when we need DCT 1. */ +#define PACK_CORR_DATA_0to1(d,top,bottom) \ + do{ \ + short *t = top,*b = bottom; \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,t,16); \ + t = (short *)((unsigned long)t + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + }while(0); + +#define PACK_CORR_DATA_SHORT(d,block) \ + do { \ + short *b = block; \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + PACK_CORR_DATA(d,b,16); \ + b = (short *)((unsigned long)b + 32); \ + }while(0); + +/* Lookup tables to speed common calculations */ +static unsigned int drps_table[] = {2<<6,3<<6}; + +static unsigned int mvfs_table[] = { + 0x12, + 0x1a, + 0x13, + 0x1b +}; + +static unsigned int type_table[] = { + 0x1<<12, /* This is an error so make it Forward motion */ + 0x1<<12, + 0x1<<12, + 0x1<<12, + 0x2<<12, + 0x2<<12, + 0x3<<12, + 0x3<<12, + 0x1<<12, /* Pattern but no Motion, Make motion Forward */ + 0x1<<12, + 0x1<<12, + 0x1<<12, + 0x2<<12, + 0x2<<12, + 0x3<<12, + 0x3<<12 +}; + +static unsigned int y_frame_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 128,128,128,128,256,256,256,256, + 256,256,256,256,384,384,384,384, + 128,128,128,128,256,256,256,256, + 256,256,256,256,384,384,384,384, + 256,256,256,256,384,384,384,384, + 384,384,384,384,512,512,512,512 +}; + +static unsigned int u_frame_bytes[] = { + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128, + 0,0,128,128,0,0,128,128 +}; + +static unsigned int v_frame_bytes[] = { + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128, + 0,128,0,128,0,128,0,128 +}; + +static unsigned int y_first_field_bytes[] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128, + 256,256,256,256,256,256,256,256, + 256,256,256,256,256,256,256,256 +}; + +static unsigned int y_second_field_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256 +}; + +static unsigned int y_dct0_field_bytes[] = { + 0,0,0,0,128,128,128,128, + 128,128,128,128,256,256,256,256, + 128,128,128,128,128,128,128,128, + 256,256,256,256,256,256,256,256, + 128,128,128,128,256,256,256,256, + 128,128,128,128,256,256,256,256, + 256,256,256,256,256,256,256,256, + 256,256,256,256,256,256,256,256 +}; + +static unsigned int y_dct1_frame_bytes[] = { + 0,0,0,0,256,256,256,256, + 256,256,256,256,512,512,512,512, + 256,256,256,256,256,256,256,256, + 512,512,512,512,512,512,512,512, + 256,256,256,256,512,512,512,512, + 256,256,256,256,512,512,512,512, + 512,512,512,512,512,512,512,512, + 512,512,512,512,512,512,512,512 +}; + +static unsigned int u_field_bytes[] = { + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64, + 0,0,64,64,0,0,64,64 +}; + +static unsigned int v_field_bytes[] = { + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64, + 0,64,0,64,0,64,0,64 +}; + +static short empty_block[] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0 +}; + + +/*************************************************************************** +// Function: dispatchYContext +// Description: Allocate a DMA buffer write the Y MC Context info in it, +// and dispatch it to hardware. +***************************************************************************/ + +static __inline__ void dispatchYContext(i810XvMCSurface *privTarget, + i810XvMCSurface *privPast, + i810XvMCSurface *privFuture, + i810XvMCContext *pI810XvMC) { + uint *data; + drmBufPtr pDMA; + drm_i810_mc_t mc; + + pDMA = i810_get_free_buffer(pI810XvMC); + data = pDMA->address; + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1y; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + /* Past Surface */ + *data++ = CMD_MAP_INFO; + *data++ = privPast->mi1y; + *data++ = privPast->mi2y; + *data++ = privPast->mi3y; + /* Future Surface */ + *data++ = CMD_MAP_INFO; + *data++ = privFuture->mi1y | 0x1<<28; + *data++ = privFuture->mi2y; + *data++ = privFuture->mi3y; + + mc.idx = pDMA->idx; + mc.used = (unsigned long)data - (unsigned long)pDMA->address; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); +} + +static __inline__ void renderError(void) { + printf("Invalid Macroblock Parameters found.\n"); + return; +} + +/*************************************************************************** +// Function: renderIntrainFrame +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in a Frame picture. +***************************************************************************/ +static __inline__ void renderIntrainFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb, + short *block_ptr) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Y Blocks */ + *dy++ = GFXBLOCK + 68; + *dy++ = (1<<30) | (3<<28) | (0xf<<24); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<4); + *dy++ = (16<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,256); + dy += 64; + block_ptr += 256; + /* End Y Blocks */ + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23); + *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22); + *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderIntrainFrameDCT1 +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in a Frame picture with DCT type 1. +***************************************************************************/ +static __inline__ void renderIntrainFrameDCT1(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + + /* Y Blocks */ + *dy++ = GFXBLOCK + 36; + *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x2<<6); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3); + *dy++ = (8<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,128); + dy += 32; + block_ptr += 128; + + /* Second Y block */ + *dy++ = GFXBLOCK + 36; + *dy++ = (1<<30) | (2<<28) | (0x3<<26) | (0x3<<6); + *dy++ = ((uint)mb->x<<20) | ((uint)mb->y<<3); + *dy++ = (8<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,128); + dy += 32; + block_ptr += 128; + /* End Y Blocks */ + + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23); + *du++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22); + *dv++ = (((uint)mb->x)<<19) | (((uint)mb->y)<<3); + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: renderIntrainField +// Description: inline function that sets hardware parameters for an Intra +// encoded macroblock in Field pictures. +***************************************************************************/ +static __inline__ void renderIntrainField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + uint dw1 = drps_table[~ps & 0x1]; + + /* Y Blocks */ + *dy++ = GFXBLOCK + 68; + *dy++ = (1<<30) | (3<<28) | (0xf<<24) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = 0; + *dy++ = 0; + PACK_INTRA_DATA(dy,block_ptr,256); + dy += 64; + block_ptr += 256; + /* End Y Blocks */ + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 20; + *du++ = (2<<30) | (1<<28) | (1<<23) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = 0; + *du++ = 0; + PACK_INTRA_DATA(du,block_ptr,64); + du += 16; + block_ptr += 64; + + /* V Block */ + *dv++ = GFXBLOCK + 20; + *dv++ = (3<<30) | (1<<28) | (1<<22) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = 0; + *dv++ = 0; + PACK_INTRA_DATA(dv,block_ptr,64); + dv += 16; + block_ptr += 64; + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: renderFieldinField +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a Field Picture. +***************************************************************************/ +static __inline__ void renderFieldinField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps, uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + uint parity = ~ps & XVMC_TOP_FIELD; + + uint ysize = y_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + /* i810 Specific flag used to identify the second field in a P frame */ + if(flags & 0x80000000) { + /* P Frame */ + if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) == + parity) { + /* Same parity, use reference field (map0) */ + dw1 = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + (((uint)mb->coded_block_pattern)<<22); + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = 0; + bmv[1] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1 = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + (((uint)mb->coded_block_pattern)<<22); + bmv[0] = mb->PMV[0][0][1]; + bmv[1] = mb->PMV[0][0][0]; + fmv[0] = 0; + fmv[1] = 0; + } + } + else { + dw1 = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + } + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: render16x8inField +// Description: inline function that sets hardware parameters for a 16x8 +// encoded macroblock in a field picture. +***************************************************************************/ +static __inline__ void render16x8inField(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint ps, uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint parity = ~ps & XVMC_TOP_FIELD; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + /* i810 Specific flag used to identify the second field in a P frame */ + if(flags & 0x80000000) { + /* P Frame */ + if((mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD) == + parity) { + /* Same parity, use reference field (map0) */ + dw1[0] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = 0; + bmv[1] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1[0] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + (((uint)mb->coded_block_pattern)<<22); + + bmv[0] = mb->PMV[0][0][1]; + bmv[1] = mb->PMV[0][0][0]; + fmv[0] = 0; + fmv[1] = 0; + } + if((mb->motion_vertical_field_select & XVMC_SELECT_SECOND_FORWARD) == + (parity<<2)) { + /* Same parity, use reference field (map0) */ + dw1[1] = 1<<12 | ((0x2 + parity)<<6) | ((0x2 + parity)<<3) | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + fmv[2] = mb->PMV[1][0][1]; + fmv[3] = mb->PMV[1][0][0]; + bmv[2] = 0; + bmv[3] = 0; + } + else { + /* + Opposite parity, set up as if it were backward + motion and use map1. + */ + dw1[1] = 2<<12 | ((0x2 + parity)<<6) | (0x3 - parity) | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + bmv[2] = mb->PMV[1][0][1]; + bmv[3] = mb->PMV[1][0][0]; + fmv[2] = 0; + fmv[3] = 0; + } + } + else { + dw1[0] = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | + drps_table[~ps & 0x1] | + mvfs_table[(mb->motion_vertical_field_select>>2) & 0x3] | + ((((uint)mb->coded_block_pattern<<22) & (0x3<<22)) | + (((uint)mb->coded_block_pattern<<24) & (0x3<<26))); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = (xy + 8); + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* Second U block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = (xy + 4); + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = (xy + 4); + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinField +// Description: inline function that sets hardware parameters for a Dual +// prime encoded macroblock in a field picture. +***************************************************************************/ +static __inline__ void renderDualPrimeinField(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint ps, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + + uint ysize = y_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + + if(ps & XVMC_TOP_FIELD) { + dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 2<<6 | 2<<3 | 3; + } + else { + dw1 = (mb->coded_block_pattern<<22) | 3<<12 | 3<<6 | 3<<3 | 2; + } + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFieldinFrame +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a frame picture. +***************************************************************************/ +static __inline__ void renderFieldinFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) | + mvfs_table[mb->motion_vertical_field_select & 3] | + (((uint)mb->coded_block_pattern)<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) | + mvfs_table[mb->motion_vertical_field_select>>2] | + (((mb->coded_block_pattern & 0x3) | + ((mb->coded_block_pattern & 0xc)<<2))<<22); + + fmv[0] = mb->PMV[0][0][1]/2; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]/2; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]/2; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]/2; + bmv[3] = mb->PMV[1][1][0]; + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[0]; + *dy++ = *(uint *)&bmv[0]; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[0]; + *du++ = *(uint *)&bmv[0]; + if(usize) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(usize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[0]; + *dv++ = *(uint *)&bmv[0]; + if(vsize) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(vsize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFieldinFrameDCT0 +// Description: inline function that sets hardware parameters for a Field +// encoded macroblock in a frame picture with DCT0. +***************************************************************************/ +static __inline__ void renderFieldinFrameDCT0(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* CBP */ + uint cbp = (uint)mb->coded_block_pattern; + /* gfxblock dword 1 */ + uint dw1[2]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + unsigned int ysize = y_dct0_field_bytes[cbp]; + unsigned int usize = u_field_bytes[cbp]; + unsigned int vsize = v_field_bytes[cbp]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + dw1[0] = type_table[mb->macroblock_type & 0xf] | (0x2<<6) | + mvfs_table[mb->motion_vertical_field_select & 3] | + ((cbp | ((cbp<<2) & 0x30))<<22); + + dw1[1] = type_table[mb->macroblock_type & 0xf] | (0x3<<6) | + mvfs_table[mb->motion_vertical_field_select>>2] | + ((cbp | ((cbp<<2) & 0x30))<<22); + + + fmv[0] = mb->PMV[0][0][1]/2; + fmv[1] = mb->PMV[0][0][0]; + fmv[2] = mb->PMV[1][0][1]/2; + fmv[3] = mb->PMV[1][0][0]; + + bmv[0] = mb->PMV[0][1][1]/2; + bmv[1] = mb->PMV[0][1][0]; + bmv[2] = mb->PMV[1][1][1]/2; + bmv[3] = mb->PMV[1][1][0]; + + /* + The i810 cannot use DCT0 directly with field motion, we have to + interlace the data for it. We use a zero block when the CBP has + one half of the to-be-interlaced data but not the other half. + */ + top_left_b = &empty_block[0]; + if(cbp & 0x20) { + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(cbp & 0x10) { + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(cbp & 0x8) { + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(cbp & 0x4) { + bottom_right_b = block_ptr; + block_ptr += 64; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[0]; + *dy++ = *(uint *)&bmv[0]; + if(dw1[0] & (1<<27)) { + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(dw1[0] & (1<<26)) { + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<27)) { + top_left_b = (short *)((unsigned long)top_left_b + 16); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 16); + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(dw1[1] & (1<<26)) { + top_right_b = (short *)((unsigned long)top_right_b + 16); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 16); + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + fmv[2] /= 2; + fmv[3] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[0]; + *du++ = *(uint *)&bmv[0]; + if(usize) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(usize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[0]; + *dv++ = *(uint *)&bmv[0]; + if(vsize) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(vsize) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFrameinFrame +// Description: inline function that sets hardware parameters for a Frame +// encoded macroblock in a frame picture. +***************************************************************************/ +static __inline__ void renderFrameinFrame(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb,short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[2]; + short bmv[2]; + /* gfxblock dword 1 */ + uint dw1; + + unsigned int ysize = y_frame_bytes[mb->coded_block_pattern]; + unsigned int usize = u_frame_bytes[mb->coded_block_pattern]; + unsigned int vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + dw1 = type_table[mb->macroblock_type & 0xf] | + (((uint)mb->coded_block_pattern)<<22); + + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + PACK_CORR_DATA(dy,block_ptr,ysize); + block_ptr = (short *)((unsigned long)block_ptr + ysize); + /* End Y Blocks */ + + fmv[0] /= 2; + fmv[1] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + /* End U Block */ + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + /* End V Block */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderFrameinFrameDCT1 +// Description: inline function that sets hardware parameters for a Frame +// encoded macroblock in a frame picture with DCT type 1. +***************************************************************************/ +static __inline__ void renderFrameinFrameDCT1(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + uint temp_bp = 0; + + uint ysize = y_dct1_frame_bytes[mb->coded_block_pattern]; + uint usize = u_frame_bytes[mb->coded_block_pattern]; + uint vsize = v_frame_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<4); + + uint dw1 = type_table[mb->macroblock_type & 0xf] | + (((uint)mb->coded_block_pattern)<<22); + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + + bmv[0] = mb->PMV[0][1][1]; + bmv[1] = mb->PMV[0][1][0]; + + /* + It is easiest to find out what blocks are in need of reading first + rather than as we go. + */ + top_left_b = &empty_block[0]; + if(dw1 & (1<<27)) { + temp_bp |= (1<<25); + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(dw1 & (1<<26)) { + temp_bp |= (1<<24); + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(dw1 & (1<<25)) { + temp_bp |= (1<<27); + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(dw1 & (1<<24)) { + temp_bp |= (1<<26); + bottom_right_b = block_ptr; + block_ptr += 64; + } + dw1 |= temp_bp; + + /* Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (3<<28) | dw1; + *dy++ = xy; + *dy++ = (16<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + if(dw1 & (1<<27)) { + PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b); + top_left_b = (short *)((unsigned long)top_left_b + 64); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 64); + } + if(dw1 & (1<<26)) { + PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b); + top_right_b = (short *)((unsigned long)top_right_b + 64); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 64); + } + if(dw1 & (1<<27)) { + PACK_CORR_DATA_1to0(dy,top_left_b,bottom_left_b); + } + if(dw1 & (1<<26)) { + PACK_CORR_DATA_1to0(dy,top_right_b,bottom_right_b); + } + /* End Y Block */ + + fmv[0] /= 2; + fmv[1] /= 2; + + bmv[0] /= 2; + bmv[1] /= 2; + + xy >>= 1; + + /* U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1; + *du++ = xy; + *du++ = (8<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + PACK_CORR_DATA(du,block_ptr,usize); + block_ptr = (short *)((unsigned long)block_ptr + usize); + + /* V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1; + *dv++ = xy; + *dv++ = (8<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + PACK_CORR_DATA(dv,block_ptr,vsize); + block_ptr = (short *)((unsigned long)block_ptr + vsize); + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinFrame +// Description: inline function that sets hardware parameters for a Dual +// Prime encoded macroblock in a frame picture with dct 1. +***************************************************************************/ +static __inline__ void renderDualPrimeinFrame(uint **datay,uint **datau, + uint **datav,XvMCMacroBlock *mb, + short *block_ptr,uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + uint y1size = y_first_field_bytes[mb->coded_block_pattern]; + uint y2size = y_second_field_bytes[mb->coded_block_pattern]; + uint usize = u_field_bytes[mb->coded_block_pattern]; + uint vsize = v_field_bytes[mb->coded_block_pattern]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + /* + Past Surface (map 0) is used for same parity prediction, + Future surface (map 1) is used for opposite. + */ + dw1[0] = (((uint)mb->coded_block_pattern)<<22) | + 3<<12 | 2<<6 | 2<<3 | 3; + dw1[1] = (((mb->coded_block_pattern & 0x3) | + ((mb->coded_block_pattern & 0xc)<<2))<<22) | + 3<<12 | 3<<6 | 3<<3 | 2; + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[1][0][1]; + bmv[1] = mb->PMV[1][0][0]; + + fmv[2] = mb->PMV[0][0][1]; + fmv[3] = mb->PMV[0][0][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (y1size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv;; + PACK_CORR_DATA(dy,block_ptr,y1size); + block_ptr = (short *)((unsigned long)block_ptr + y1size); + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (y2size>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + PACK_CORR_DATA(dy,block_ptr,y2size); + block_ptr = (short *)((unsigned long)block_ptr + y2size); + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + + fmv[2] /= 2; + fmv[3] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + if(dw1[0] & (1<<23)) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<23)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + if(dw1[0] & (1<<22)) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(dw1[1] & (1<<22)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + +/*************************************************************************** +// Function: renderDualPrimeinFrameDCT0 +// Description: inline function that sets hardware parameters for a Dual +// Prime encoded macroblock in a frame picture with dct 0. +***************************************************************************/ +static __inline__ void renderDualPrimeinFrameDCT0(uint **datay,uint **datau, + uint **datav, + XvMCMacroBlock *mb, + short *block_ptr, + uint flags) { + + register uint *dy = *datay; + register uint *du = *datau; + register uint *dv = *datav; + + /* Motion Vectors */ + short fmv[4]; + short bmv[4]; + /* gfxblock dword 1 */ + uint dw1[2]; + + short * top_left_b = NULL; + short * top_right_b = NULL; + short * bottom_left_b = NULL; + short * bottom_right_b = NULL; + + uint cbp = (uint)mb->coded_block_pattern; + + uint ysize = y_dct0_field_bytes[cbp]; + uint usize = u_field_bytes[cbp]; + uint vsize = v_field_bytes[cbp]; + + uint xy = ((uint)mb->x<<20) | ((uint)mb->y<<3); + + /* + Past Surface (map 0) is used for same parity prediction, + Future surface (map 1) is used for opposite. + */ + dw1[0] = ((cbp | ((cbp<<2) & 0x30))<<22) | + 3<<12 | 2<<6 | 2<<3 | 3; + dw1[1] = ((cbp | ((cbp<<2) & 0x30))<<22) | + 3<<12 | 3<<6 | 3<<3 | 2; + + fmv[0] = mb->PMV[0][0][1]; + fmv[1] = mb->PMV[0][0][0]; + bmv[0] = mb->PMV[1][0][1]; + bmv[1] = mb->PMV[1][0][0]; + + fmv[2] = mb->PMV[0][0][1]; + fmv[3] = mb->PMV[0][0][0]; + bmv[2] = mb->PMV[1][1][1]; + bmv[3] = mb->PMV[1][1][0]; + + /* + The i810 cannot use DCT0 directly with field motion, we have to + interlace the data for it. We use a zero block when the CBP has + one half of the to-be-interlaced data but not the other half. + */ + top_left_b = &empty_block[0]; + if(cbp & 0x20) { + top_left_b = block_ptr; + block_ptr += 64; + } + + top_right_b = &empty_block[0]; + if(cbp & 0x10) { + top_right_b = block_ptr; + block_ptr += 64; + } + + bottom_left_b = &empty_block[0]; + if(cbp & 0x8) { + bottom_left_b = block_ptr; + block_ptr += 64; + } + + bottom_right_b = &empty_block[0]; + if(cbp & 0x4) { + bottom_right_b = block_ptr; + block_ptr += 64; + } + + /* First Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[0]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)fmv; + *dy++ = *(uint *)bmv; + if(cbp & 0x20) { + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(cbp & 0x10) { + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + + /* Second Y Block */ + *dy++ = GFXBLOCK + 4 + (ysize>>2); + *dy++ = (1<<30) | (2<<28) | dw1[1]; + *dy++ = xy; + *dy++ = (8<<16) | 16; + *dy++ = *(uint *)&fmv[2]; + *dy++ = *(uint *)&bmv[2]; + if(cbp & 0x20) { + top_left_b = (short *)((unsigned long)top_left_b + 16); + bottom_left_b = (short *)((unsigned long)bottom_left_b + 16); + PACK_CORR_DATA_0to1(dy,top_left_b,bottom_left_b); + } + if(cbp & 0x10) { + top_right_b = (short *)((unsigned long)top_right_b + 16); + bottom_right_b = (short *)((unsigned long)bottom_right_b + 16); + PACK_CORR_DATA_0to1(dy,top_right_b,bottom_right_b); + } + /* End Y Blocks */ + + + fmv[0] /= 2; + fmv[1] /= 2; + bmv[0] /= 2; + bmv[1] /= 2; + + fmv[2] /= 2; + fmv[3] /= 2; + bmv[2] /= 2; + bmv[3] /= 2; + + xy >>= 1; + + /* U Blocks */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[0]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)fmv; + *du++ = *(uint *)bmv; + if(cbp & (1<<23)) { + PACK_CORR_DATA_SHORT(du,block_ptr); + } + + /* Second U Block */ + *du++ = GFXBLOCK + 4 + (usize>>2); + *du++ = (2<<30) | (1<<28) | dw1[1]; + *du++ = xy; + *du++ = (4<<16) | 8; + *du++ = *(uint *)&fmv[2]; + *du++ = *(uint *)&bmv[2]; + if(cbp & (1<<23)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(du,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End U Blocks */ + + /* V Blocks */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[0]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)fmv; + *dv++ = *(uint *)bmv; + if(cbp & (1<<22)) { + PACK_CORR_DATA_SHORT(dv,block_ptr); + } + + /* Second V Block */ + *dv++ = GFXBLOCK + 4 + (vsize>>2); + *dv++ = (3<<30) | (1<<28) | dw1[1]; + *dv++ = xy; + *dv++ = (4<<16) | 8; + *dv++ = *(uint *)&fmv[2]; + *dv++ = *(uint *)&bmv[2]; + if(cbp & (1<<22)) { + block_ptr = (short *)((unsigned long)block_ptr + 16); + PACK_CORR_DATA_SHORT(dv,block_ptr); + block_ptr = (short *)((unsigned long)block_ptr + 112); + } + /* End V Blocks */ + + *datay = dy; + *datau = du; + *datav = dv; +} + + +/*************************************************************************** +// Function: XvMCRenderSurface +// Description: This function does the actual HWMC. Given a list of +// macroblock structures it dispatched the hardware commands to execute +// them. DMA buffer containing Y data are dispatched as they fill up +// U and V DMA buffers are queued until all Y's are done. This minimizes +// the context flipping and flushing required when switching between Y +// U and V surfaces. +***************************************************************************/ +#define UV_QUEUE 14 +Status XvMCRenderSurface(Display *display, XvMCContext *context, + unsigned int picture_structure, + XvMCSurface *target_surface, + XvMCSurface *past_surface, + XvMCSurface *future_surface, + unsigned int flags, + unsigned int num_macroblocks, + unsigned int first_macroblock, + XvMCMacroBlockArray *macroblock_array, + XvMCBlockArray *blocks) { + /* Dma Data Structures */ + drmBufPtr pDMAy = NULL,pDMAu[UV_QUEUE],pDMAv[UV_QUEUE]; + int u_index = 0,v_index = 0; + int dirty_context = 1; + + /* Block Pointer */ + short *block_ptr; + /* Current Macroblock Pointer */ + XvMCMacroBlock *mb; + + drm_i810_mc_t mc; + int i,j; + i810XvMCSurface *privTarget; + i810XvMCSurface *privFuture = NULL; + i810XvMCSurface *privPast = NULL; + i810XvMCContext *pI810XvMC; + + /* DMA Pointers set to NULL */ + uint *datay = NULL; + uint *datau = NULL; + uint *datav = NULL; + + + /* Check Parameters for validity */ + if((target_surface == NULL) || (context == NULL) || (display == NULL)) { + printf("Error, Invalid Target,Context, or DIsplay!\n"); + return BadValue; + } + + if(num_macroblocks == 0) {return Success;} + if((macroblock_array == NULL) || (blocks == NULL)) {return BadValue;} + if(context->privData == NULL) {return BadValue;} + pI810XvMC = (i810XvMCContext *)context->privData; + + + if(target_surface->privData == NULL) { + printf("Error, Invalid Target Surface!\n"); + return BadValue; + } + privTarget = (i810XvMCSurface *)target_surface->privData; + + if(macroblock_array->num_blocks < (num_macroblocks + first_macroblock)) { + printf("Error, Too many macroblocks requested for MB array size.\n"); + return BadValue; + } + + /* Test For YV12 Surface */ + if(context->surface_type_id != FOURCC_YV12) { + printf("Error, HWMC only possible on YV12 Surfaces\n"); + return BadValue; + } + + /* P Frame Test */ + if(past_surface == NULL) { + /* Just to avoid some ifs later. */ + privPast = privTarget; + } + else { + if(past_surface->privData == NULL) { + printf("Error, Invalid Past Surface!\n"); + return BadValue; + } + privPast = (i810XvMCSurface *)past_surface->privData; + } + + + /* B Frame Test */ + if(future_surface == NULL) { + privFuture = privTarget; + if(pI810XvMC->dual_prime) { + privFuture = privPast; + /* I810 Specific flag for marking when dual prime is in use. */ + flags |= 0x40000000; + } + + /* + References are different for the Second Field Picture. The + i810 needs to know if it is the second field picture in a + P picture. We use a Private flag to mark this. + */ + if(flags & XVMC_SECOND_FIELD) { + /* I810 Specific flag for marking second fields. */ + flags |= 0x80000000; + } + } + else { + if((future_surface->privData == NULL) || (past_surface == NULL)) { + printf("Error, Invalid Future Surface or No Past Surface!\n"); + return BadValue; + } + privFuture = (i810XvMCSurface *)future_surface->privData; + + /* + Undo Second Field flag since the second field in B frames is just like + the first. + */ + flags &= ~0x80000000; + } + + /* Lock For DMA */ + I810_LOCK(pI810XvMC,0); + + for(i=first_macroblock; i<(num_macroblocks + first_macroblock); i++) { + /* Set up values needed for each macroblock */ + mb = ¯oblock_array->macro_blocks[i]; + block_ptr = &(blocks->blocks[mb->index<<6]); + + /* Lockup can happen if the coordinates are too far out of range */ + if(mb->x > target_surface->width>>4) { + mb->x = 0; + } + if(mb->y > target_surface->height>>4) { + mb->y = 0; + } + + /* If buffers are almost full dispatch them */ + if(datay) { + pDMAy->used = (unsigned long)datay - (unsigned long)pDMAy->address; + if(pDMAy->used > 3520) { + if(dirty_context) { + dispatchYContext(privTarget,privPast,privFuture,pI810XvMC); + } + dirty_context = 0; + mc.idx = pDMAy->idx; + mc.used = pDMAy->used; + datay = NULL; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } /* datay near full */ + } /* if(datay) */ + if(datau) { + pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address; + if(pDMAu[u_index]->used > 3904) { + u_index++; + datau = NULL; + if(u_index == UV_QUEUE) { + for(j=0; j<UV_QUEUE; j++) { + mc.idx = pDMAu[j]->idx; + mc.used = pDMAu[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + u_index = 0; + dirty_context = 1; + } /* if(u_index == UV_QUEUE) */ + } /* datau near full */ + } /* if(datau) */ + if(datav) { + pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address; + if(pDMAv[v_index]->used > 3904) { + v_index++; + datav = NULL; + if(v_index == UV_QUEUE) { + for(j=0; j<UV_QUEUE; j++) { + mc.idx = pDMAv[j]->idx; + mc.used = pDMAv[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + v_index = 0; + dirty_context = 1; + } /* if(v_index == UV_QUEUE) */ + } /* datav near full */ + } /* if(datav) */ + + /* Allocate buffers if this is the first loop,or if we just dispatched */ + if(datay == NULL) { + pDMAy = i810_get_free_buffer(pI810XvMC); + datay = pDMAy->address; + }/* if(datay == NULL) */ + if(datau == NULL) { + pDMAu[u_index] = i810_get_free_buffer(pI810XvMC); + datau = pDMAu[u_index]->address; + if(u_index == 0) { + *datau++ = CMD_FLUSH; + *datau++ = BOOLEAN_ENA_2; + *datau++ = CMD_FLUSH; + *datau++ = DEST_BUFFER_INFO; + *datau++ = privTarget->dbi1u; + *datau++ = DEST_BUFFER_VAR; + *datau++ = privTarget->dbv1; + /* Past Surface */ + *datau++ = CMD_MAP_INFO; + *datau++ = privPast->mi1u; + *datau++ = privPast->mi2u; + *datau++ = privPast->mi3u; + /* Future Surface */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + } + } /* if(datau == NULL) */ + if(datav == NULL) { + pDMAv[v_index] = i810_get_free_buffer(pI810XvMC); + datav = pDMAv[v_index]->address; + if(v_index == 0) { + *datav++ = CMD_FLUSH; + *datav++ = BOOLEAN_ENA_2; + *datav++ = CMD_FLUSH; + *datav++ = DEST_BUFFER_INFO; + *datav++ = privTarget->dbi1v; + *datav++ = DEST_BUFFER_VAR; + *datav++ = privTarget->dbv1; + /* Past Surface */ + *datav++ = CMD_MAP_INFO; + *datav++ = privPast->mi1v; + *datav++ = privPast->mi2v; + *datav++ = privPast->mi3v; + /* Future Surface */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + }/* if(datav == NULL) */ + + /* Catch no pattern case */ + if(!(mb->macroblock_type & 0x8)) { + mb->coded_block_pattern = 0; + } + + + if(mb->motion_type == XVMC_PREDICTION_DUAL_PRIME) { + /* + By default the maps will not be set up for dual + prime. We have to change them. + */ + if(!pI810XvMC->dual_prime) { + pI810XvMC->dual_prime = 1; + privFuture = privPast; + /* Y */ + *datay++ = CMD_MAP_INFO; + *datay++ = privFuture->mi1y | 0x1<<28; + *datay++ = privFuture->mi2y; + *datay++ = privFuture->mi3y; + /* U */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + /* V */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + } + if((pI810XvMC->dual_prime) && + (mb->motion_type != XVMC_PREDICTION_DUAL_PRIME)) { + pI810XvMC->dual_prime = 0; + privFuture = privTarget; + /* Y */ + *datay++ = CMD_MAP_INFO; + *datay++ = privFuture->mi1y | 0x1<<28; + *datay++ = privFuture->mi2y; + *datay++ = privFuture->mi3y; + /* U */ + *datau++ = CMD_MAP_INFO; + *datau++ = privFuture->mi1u | 0x1<<28; + *datau++ = privFuture->mi2u; + *datau++ = privFuture->mi3u; + /* V */ + *datav++ = CMD_MAP_INFO; + *datav++ = privFuture->mi1v | 0x1<<28; + *datav++ = privFuture->mi2v; + *datav++ = privFuture->mi3v; + } + + + /* Frame Picture */ + if((picture_structure & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) { + /* Intra Blocks */ + if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) { + if(mb->dct_type) { + renderIntrainFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + } + renderIntrainFrame(&datay,&datau,&datav,mb,block_ptr); + continue; + } + switch((mb->motion_type & 0x3) | (mb->dct_type<<2)) { + case 0x2: /* Frame DCT0 */ + renderFrameinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x5: /* Field DCT1 */ + renderFieldinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x6: /* Frame DCT1 */ + renderFrameinFrameDCT1(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x1: /* Field DCT0 */ + renderFieldinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x3: /* Dual Prime DCT0 */ + renderDualPrimeinFrame(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + case 0x7: /* Dual Prime DCT1 */ + renderDualPrimeinFrameDCT0(&datay,&datau,&datav,mb,block_ptr,flags); + continue; + default: /* No Motion Type */ + renderError(); + continue; + } /* Switch */ + } /* Frame Picture */ + + /* Field Pictures */ + if(mb->macroblock_type & XVMC_MB_TYPE_INTRA) { + renderIntrainField(&datay,&datau,&datav,mb,block_ptr,picture_structure); + continue; + } + switch(mb->motion_type & 0x3) { + case 0x1: /* Field Motion */ + renderFieldinField(&datay,&datau,&datav,mb,block_ptr,picture_structure, + flags); + continue; + case 0x2: /* 16x8 Motion */ + render16x8inField(&datay,&datau,&datav,mb,block_ptr,picture_structure, + flags); + continue; + case 0x3: /* Dual Prime */ + renderDualPrimeinField(&datay,&datau,&datav,mb,block_ptr, + picture_structure,flags); + continue; + default: /* No Motion Type */ + renderError(); + continue; + } + continue; + + } /* for each Macroblock */ + + /* Dispatch remaining DMA buffers */ + if(dirty_context) { + dispatchYContext(privTarget,privPast,privFuture,pI810XvMC); + } + mc.idx = pDMAy->idx; + mc.used = (unsigned long)datay - (unsigned long)pDMAy->address; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + + pDMAu[u_index]->used = (unsigned long)datau - (unsigned long)pDMAu[u_index]->address; + for(j=0; j<=u_index; j++) { + mc.idx = pDMAu[j]->idx; + mc.used = pDMAu[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + pDMAv[v_index]->used = (unsigned long)datav - (unsigned long)pDMAv[v_index]->address; + for(j=0; j<=v_index; j++) { + mc.idx = pDMAv[j]->idx; + mc.used = pDMAv[j]->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + } + + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// Function: XvMCPutSurface +// Description: +// Arguments: +// display: Connection to X server +// surface: Surface to be displayed +// draw: X Drawable on which to display the surface +// srcx: X coordinate of the top left corner of the region to be +// displayed within the surface. +// srcy: Y coordinate of the top left corner of the region to be +// displayed within the surface. +// srcw: Width of the region to be displayed. +// srch: Height of the region to be displayed. +// destx: X cordinate of the top left corner of the destination region +// in the drawable coordinates. +// desty: Y cordinate of the top left corner of the destination region +// in the drawable coordinates. +// destw: Width of the destination region. +// desth: Height of the destination region. +// flags: One or more of the following. +// XVMC_TOP_FIELD - Display only the Top field of the surface. +// XVMC_BOTTOM_FIELD - Display only the Bottom Field of the surface. +// XVMC_FRAME_PICTURE - Display both fields or frame. +// +// Info: Portions of this function derived from i810_video.c (XFree86) +// +// This function is organized so that we wait as long as possible before +// touching the overlay registers. Since we don't know that the last +// flip has happened yet we want to give the overlay as long as +// possible to catch up before we have to check on its progress. This +// makes it unlikely that we have to wait on the last flip. +***************************************************************************/ +Status XvMCPutSurface(Display *display,XvMCSurface *surface, + Drawable draw, short srcx, short srcy, + unsigned short srcw, unsigned short srch, + short destx, short desty, + unsigned short destw, unsigned short desth, + int flags) { + i810XvMCContext *pI810XvMC; + i810XvMCSurface *pI810Surface; + i810OverlayRecPtr pORegs; + unsigned int ysrc_offset,uvsrc_offset; + Box extents; + uint window_width,window_height; + unsigned int xscaleInt = 0,xscaleFract = 0,yscaleInt = 0,yscaleFract = 0; + unsigned int xscaleFractUV = 0,xscaleIntUV = 0,yscaleFractUV = 0; + unsigned int yscaleIntUV = 0,yPitch = 0,uvPitch = 0; + unsigned int ovcmd = 0; + uint d; + double xscale,yscale; + int diff; + int clipped_srcx, clipped_srcy, clipped_destx, clipped_desty; + int clipped_srcw, clipped_srch, clipped_destw, clipped_desth; + uint x1,y1,root_width,root_height; + int x2 = 0, y2 = 0,unused; + uint nChilds; + int stat; + Window win,root,parent,*pChilds; + + + if((display == NULL) || (surface == NULL)) { + return BadValue; + } + + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + pI810Surface = (i810XvMCSurface *)surface->privData; + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + pORegs = (i810OverlayRecPtr)pI810XvMC->oregs; + + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + yPitch = (srcw + 7) & ~7; + uvPitch = ((srcw>>1) + 7) & ~7; + if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) { + srch = srch>>1; + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + /* FIXME: Non Planar not fully implemented. */ + return BadValue; + yPitch = ((srcw + 7) & ~7) << 1; + break; + }/* switch(surface->surface_type_id) */ + + /* + FIXME: This should be using the DRI's clip rect but that isn't + all hooked up yet. This has some latency but we get by. + */ + win = draw; + XQueryTree(display,win,&root,&parent,&pChilds,&nChilds); + if(nChilds) XFree(pChilds); + XGetGeometry(display,win, &root, &x2, &y2, &window_width, + &window_height, &d, &d); + x1 = x2; + y1 = y2; + win = parent; + do { + XQueryTree(display,win,&root,&parent,&pChilds,&nChilds); + if(nChilds) XFree(pChilds); + XGetGeometry(display,win, &root, &x2, &y2, &d, &d, &d, &d); + x1 += x2; + y1 += y2; + win = parent; + }while(win != root); + XGetGeometry(display,root, &root, &unused, &unused, + &root_width, &root_height, &d, &d); + + /* Left edge of Video window clipped to screen */ + extents.x1 = 0; + if(x1 > extents.x1) { + extents.x1 = x1; + } + /* Right edge of Video window clipped to screen */ + extents.x2 = root_width; + if(extents.x2 > (x1 + window_width)) { + extents.x2 = x1 + window_width; + } + /* Top edge of Video window clipped to screen */ + extents.y1 = 0; + if(y1 > extents.y1) { + extents.y1 = y1; + } + /* Bottom edge of Video window clipped to screen */ + extents.y2 = root_height; + if(extents.y2 > (y1 + window_height)) { + extents.y2 = y1 + window_height; + } + + /* + Clipping is more difficult than is seems. We need to keep the + scaling factors even if the destination window needs to be clipped. + We clip the destination window first then apply a scaled version + to the source window. + */ + + /* Put destination coords in screen coords */ + destx += x1; + desty += y1; + + /* Scale factors requested */ + xscale = (double)srcw / (double)destw; + yscale = (double)srch / (double)desth; + + /* + If destination window needs to be clipped we actually adjust both + the src and dest window so as to keep the scaling that was requested + */ + clipped_srcx = srcx; + clipped_srcy = srcy; + clipped_destx = destx; + clipped_desty = desty; + clipped_srcw = srcw; + clipped_srch = srch; + clipped_destw = destw; + clipped_desth = desth; + + /* Clip to the source surface boundaries */ + if(clipped_srcx < 0) { + clipped_destx += (0 - clipped_srcx) / xscale; + clipped_srcw -= clipped_srcx; + clipped_destw -= clipped_srcx / xscale; + clipped_srcx = 0; + } + if((clipped_srcw + clipped_srcx) > surface->width) { + clipped_srcw = surface->width - clipped_srcx; + clipped_destw -= (clipped_srcw - srcw) / xscale; + } + if(clipped_srcy < 0) { + clipped_desty += (0 - clipped_srcy) / yscale; + clipped_srch -= clipped_srcy; + clipped_desth -= clipped_srcy / yscale; + clipped_srcy = 0; + } + if((clipped_srch + clipped_srcy) > surface->height) { + clipped_srch = surface->height - clipped_srcy; + clipped_desth -= (clipped_srch - srch) / yscale; + } + + /* Clip to the extents */ + if(clipped_destx < extents.x1) { + diff = extents.x1 - clipped_destx; + clipped_srcx += diff * xscale; + clipped_srcw -= diff * xscale; + clipped_destw -= diff; + clipped_destx = extents.x1; + } + + diff = (clipped_destx + clipped_destw) - extents.x2; + if(diff > 0) { + clipped_destw -= diff; + clipped_srcw -= diff * xscale; + } + + if(clipped_desty < extents.y1) { + diff = extents.y1 - clipped_desty; + clipped_srcy += diff * yscale; + clipped_srch -= diff * yscale; + clipped_desth -= diff; + clipped_desty = 0; + } + + diff = (clipped_desty + clipped_desth) - extents.y2; + if(diff > 0) { + clipped_desth -= diff; + clipped_srch -= diff * yscale; + } + + /* If the whole window is clipped turn off the overlay */ + if((clipped_destx + clipped_destw < extents.x1) || + (clipped_desty + clipped_desth < extents.y1) || + (clipped_destx > extents.x2) || + (clipped_desty > extents.y2)) { + return XvMCHideSurface(display, surface); + } + + /* + Adjust the source offset width and height according to the clipped + destination window. + */ + ysrc_offset = ((clipped_srcx + 1) & ~1) + + ((clipped_srcy + 1) & ~1) * (1<<pI810Surface->pitch); + uvsrc_offset = (clipped_srcx>>1) + + (clipped_srcy>>1) * (1<<(pI810Surface->pitch - 1)); + + /* + Initially, YCbCr and Overlay Enable and + vertical chrominance up interpolation and horozontal chrominance + up interpolation + */ + ovcmd = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST | OVERLAY_ENABLE; + + if ((clipped_destw != clipped_srcw) || + (clipped_desth != clipped_srch)) { + xscaleInt = (clipped_srcw / clipped_destw) & 0x3; + xscaleFract = (clipped_srcw << 12) / clipped_destw; + yscaleInt = (clipped_srch / clipped_desth) & 0x3; + yscaleFract = (clipped_srch << 12) / clipped_desth; + + if (clipped_destw > clipped_srcw) { + /* horizontal up-scaling */ + ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER; + ovcmd |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION); + } + + if (clipped_desth > clipped_srch) { + /* vertical up-scaling */ + ovcmd &= ~VERTICAL_CHROMINANCE_FILTER; + ovcmd &= ~VERTICAL_LUMINANCE_FILTER; + ovcmd |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION); + } + + if (clipped_destw < clipped_srcw) { + /* horizontal down-scaling */ + ovcmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + ovcmd &= ~HORIZONTAL_LUMINANCE_FILTER; + ovcmd |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION); + } + + if (clipped_desth < clipped_srch) { + /* vertical down-scaling */ + ovcmd &= ~VERTICAL_CHROMINANCE_FILTER; + ovcmd &= ~VERTICAL_LUMINANCE_FILTER; + ovcmd |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION); + } + + /* now calculate the UV scaling factor */ + if (xscaleFract) { + xscaleFractUV = xscaleFract >> MINUV_SCALE; + ovcmd &= ~HC_DOWN_INTERPOLATION; + ovcmd |= HC_UP_INTERPOLATION; + } + + if (xscaleInt) { + xscaleIntUV = xscaleInt >> MINUV_SCALE; + if (xscaleIntUV) { + ovcmd &= ~HC_UP_INTERPOLATION; + } + } + + if (yscaleFract) { + yscaleFractUV = yscaleFract >> MINUV_SCALE; + ovcmd &= ~VC_DOWN_INTERPOLATION; + ovcmd |= VC_UP_INTERPOLATION; + } + + if (yscaleInt) { + yscaleIntUV = yscaleInt >> MINUV_SCALE; + if (yscaleIntUV) { + ovcmd &= ~VC_UP_INTERPOLATION; + ovcmd |= VC_DOWN_INTERPOLATION; + } + } + + }/* if((destw != srcw) || (desth != srch)) */ + + /* Lock the DRM */ + I810_LOCK(pI810XvMC,0); + + /* Block until rendering on this surface is finished */ + stat = XVMC_RENDERING; + while(stat & XVMC_RENDERING) { + XvMCGetSurfaceStatus(display,surface,&stat); + } + /* Block until the last flip is finished */ + if(pI810XvMC->last_flip) { + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + } + + pI810XvMC->current = !pI810XvMC->current; + pORegs->OV0CMD = ovcmd; + + if ((clipped_destw != clipped_srcw) || + (clipped_desth != clipped_srch)) { + pORegs->YRGBSCALE = (xscaleInt << 15) | + ((xscaleFract & 0xFFF) << 3) | (yscaleInt) | + ((yscaleFract & 0xFFF) << 20); + + pORegs->UVSCALE = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + } + else { + /* Normal 1:1 scaling */ + pORegs->YRGBSCALE = 0x80004000; + pORegs->UVSCALE = 0x80004000; + } + + pORegs->SHEIGHT = clipped_srch | (clipped_srch << 15); + pORegs->DWINPOS = (clipped_desty << 16) | clipped_destx; + pORegs->DWINSZ = ((clipped_desth<< 16) | (clipped_destw)); + + /* Attributes */ + pORegs->OV0CLRC0 = ((pI810XvMC->contrast & 0x1ff)<<8) | + (pI810XvMC->brightness & 0xff); + pORegs->OV0CLRC1 = (pI810XvMC->saturation & 0x3ff); + + /* Destination Colorkey Setup */ + pI810XvMC->oregs->DCLRKV = RGB16ToColorKey(pI810XvMC->colorkey); + + /* buffer locations, add the offset from the clipping */ + if(pI810XvMC->current) { + pORegs->OBUF_1Y = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[0] + ysrc_offset; + pORegs->OBUF_1V = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[2] + uvsrc_offset; + pORegs->OBUF_1U = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[1] + uvsrc_offset; + } + else { + pORegs->OBUF_0Y = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[0] + ysrc_offset; + pORegs->OBUF_0V = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[2] + uvsrc_offset; + pORegs->OBUF_0U = (unsigned long)pI810Surface->offset + + (unsigned long)pI810Surface->offsets[1] + uvsrc_offset; + } + + switch(surface->surface_type_id) { + case FOURCC_YV12: + case FOURCC_I420: + pORegs->SWID = (uvPitch << 16) | yPitch; + pORegs->SWIDQW = (uvPitch << 13) | (yPitch >> 3); + pORegs->OV0STRIDE = (1<<pI810Surface->pitch) | + ((1<<pI810Surface->pitch) << 15); + pORegs->OV0CMD &= ~SOURCE_FORMAT; + pORegs->OV0CMD |= YUV_420; + if((flags & XVMC_FRAME_PICTURE) != XVMC_FRAME_PICTURE) { + /* Top Field Only */ + if(flags & XVMC_TOP_FIELD) { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER1_FIELD0); + } + else { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER0_FIELD0); + } + pORegs->YRGB_VPH = 1<<15 | 1<<31; + pORegs->UV_VPH = 3<<14 | 3<<30; + pORegs->INIT_PH = 0x06 | 0x18; + } + /* Bottom Field Only */ + else { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER1_FIELD1); + } + else { + pORegs->OV0CMD |= (VERTICAL_PHASE_BOTH | FLIP_TYPE_FIELD | + BUFFER0_FIELD1); + } + pORegs->YRGB_VPH = 0; + pORegs->UV_VPH = 7<<29 | 7<<13; + pORegs->INIT_PH = 0x06; + } + } + /* Frame Picture */ + else { + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + pORegs->YRGB_VPH = 0; + pORegs->UV_VPH = 0; + pORegs->INIT_PH = 0; + } + break; + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + pORegs->SWID = srcw; + pORegs->SWIDQW = srcw >> 3; + pORegs->OV0STRIDE = pI810Surface->pitch; + pORegs->OV0CMD &= ~SOURCE_FORMAT; + pORegs->OV0CMD |= YUV_422; + pORegs->OV0CMD &= ~OV_BYTE_ORDER; + if (surface->surface_type_id == FOURCC_UYVY) { + pORegs->OV0CMD |= Y_SWAP; + } + + pORegs->OV0CMD &= ~BUFFER_AND_FIELD; + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + + break; + } /* switch(surface->surface_type_id) */ + + + + OVERLAY_FLIP(pI810XvMC); + + /* + The Overlay only flips when it knows you changed + something. So the first time change stuff while it + is watching to be sure. + */ + if(!pI810XvMC->last_flip) { + pORegs->OV0CMD &= ~0x4; + if(pI810XvMC->current == 1) { + pORegs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pORegs->OV0CMD |= BUFFER0_FIELD0; + } + } + pI810Surface->last_flip = ++pI810XvMC->last_flip; + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// Function: XvMCSyncSurface +// Arguments: +// display - Connection to the X server +// surface - The surface to synchronize +// Info: +// Returns: Status +***************************************************************************/ +Status XvMCSyncSurface(Display *display,XvMCSurface *surface) { + Status ret; + int stat=0; + /* + FIXME: Perhaps a timer here to prevent lockup? + FIXME: Perhaps a usleep to not be busy waiting? + */ + do { + ret = XvMCGetSurfaceStatus(display,surface,&stat); + }while(!ret && (stat & XVMC_RENDERING)); + return ret; +} + +/*************************************************************************** +// Function: XvMCFlushSurface +// Description: +// This function commits pending rendering requests to ensure that they +// wll be completed in a finite amount of time. +// Arguments: +// display - Connection to X server +// surface - Surface to flush +// Info: +// This command is a noop for i810 becuase we always dispatch buffers in +// render. There is little gain to be had with 4k buffers. +// Returns: Status +***************************************************************************/ +Status XvMCFlushSurface(Display * display, XvMCSurface *surface) { + return Success; +} + +/*************************************************************************** +// Function: XvMCGetSurfaceStatus +// Description: +// Arguments: +// display: connection to X server +// surface: The surface to query +// stat: One of the Following +// XVMC_RENDERING - The last XvMCRenderSurface command has not +// completed. +// XVMC_DISPLAYING - The surface is currently being displayed or a +// display is pending. +***************************************************************************/ +Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface, + int *stat) { + i810XvMCSurface *privSurface; + i810XvMCContext *pI810XvMC; + int temp; + + if((display == NULL) || (surface == NULL) || (stat == NULL)) { + return BadValue; + } + if(surface->privData == NULL) { + return BadValue; + } + *stat = 0; + privSurface = surface->privData; + + pI810XvMC = privSurface->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSurface); + } + + I810_LOCK(pI810XvMC,0); + if(privSurface->last_flip) { + /* This can not happen */ + if(pI810XvMC->last_flip < privSurface->last_flip) { + printf("Error: Context last flip is less than surface last flip.\n"); + return BadValue; + } + /* + If the context has 2 or more flips after this surface it + cannot be displaying. Don't bother to check. + */ + if(!(pI810XvMC->last_flip > (privSurface->last_flip + 1))) { + /* + If this surface was the last flipped it is either displaying + or about to be so don't bother checking. + */ + if(pI810XvMC->last_flip == privSurface->last_flip) { + *stat |= XVMC_DISPLAYING; + } + else { + /* + In this case there has been one more flip since our surface's + but we need to check if it is finished or not. + */ + temp = GET_FSTATUS(pI810XvMC); + if(((temp & (1<<20))>>20) != pI810XvMC->current) { + *stat |= XVMC_DISPLAYING; + } + } + } + } + + if(privSurface->last_render && + (privSurface->last_render > GET_RSTATUS(pI810XvMC))) { + *stat |= XVMC_RENDERING; + } + I810_UNLOCK(pI810XvMC); + + return Success; +} + +/*************************************************************************** +// +// Surface manipulation functions +// +***************************************************************************/ + +/*************************************************************************** +// Function: XvMCHideSurface +// Description: Stops the display of a surface. +// Arguments: +// display - Connection to the X server. +// surface - surface to be hidden. +// +// Returns: Status +***************************************************************************/ +Status XvMCHideSurface(Display *display, XvMCSurface *surface) { + i810XvMCSurface *pI810Surface; + i810XvMCContext *pI810XvMC; + int ss, xx; + + /* Did we get a good display and surface passed into us? */ + if(display == NULL) { + return BadValue; + } + + if(surface == NULL) { + return (error_base + XvMCBadSurface); + } + + XvMCSyncSurface(display, surface); + + /* Get surface private data pointer */ + if(surface->privData == NULL) { + return (error_base + XvMCBadSurface); + } + pI810Surface = (i810XvMCSurface *)surface->privData; + + /* + Get the status of the surface, if it is not currently displayed + we don't need to worry about it. + */ + if((xx = XvMCGetSurfaceStatus(display, surface, &ss)) != Success) { + return xx; + } + if(! (ss & XVMC_DISPLAYING)) { + return Success; + } + + /* Get the associated context pointer */ + pI810XvMC = (i810XvMCContext *)pI810Surface->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSurface); + } + + if(pI810XvMC->last_flip) { + I810_LOCK(pI810XvMC,DRM_LOCK_QUIESCENT); + + /* Make sure last flip is done */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current); + + /* Set the registers to turn the overlay off */ + pI810XvMC->oregs->OV0CMD = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | + Y_ADJUST; + pI810XvMC->current = !pI810XvMC->current; + if(pI810XvMC->current == 1) { + pI810XvMC->oregs->OV0CMD |= BUFFER1_FIELD0; + } + else { + pI810XvMC->oregs->OV0CMD |= BUFFER0_FIELD0; + } + OVERLAY_FLIP(pI810XvMC); + /* + Increment the context flip but not the surface. This way no + surface has the last flip #. + */ + pI810XvMC->last_flip++; + + + /* Now wait until the hardware reads the registers and makes the change. */ + BLOCK_OVERLAY(pI810XvMC,pI810XvMC->current) + + I810_UNLOCK(pI810XvMC); + } + + return Success; +} + + + + +/*************************************************************************** +// +// Functions that deal with subpictures +// +***************************************************************************/ + + + +/*************************************************************************** +// Function: XvMCCreateSubpicture +// Description: This creates a subpicture by filling out the XvMCSubpicture +// structure passed to it and returning Success. +// Arguments: +// display - Connection to the X server. +// context - The context to create the subpicture for. +// subpicture - Pre-allocated XvMCSubpicture structure to be filled in. +// width - of subpicture +// height - of subpicture +// xvimage_id - The id describing the XvImage format. +// +// Returns: Status +***************************************************************************/ +Status XvMCCreateSubpicture(Display *display, XvMCContext *context, + XvMCSubpicture *subpicture, + unsigned short width, unsigned short height, + int xvimage_id) { + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int priv_count; + uint *priv_data; + Status ret; + + if((subpicture == NULL) || (context == NULL) || (display == NULL)){ + return BadValue; + } + + pI810XvMC = (i810XvMCContext *)context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + + subpicture->context_id = context->context_id; + subpicture->xvimage_id = xvimage_id; + + /* These need to be checked to make sure they are not too big! */ + subpicture->width = width; + subpicture->height = height; + + subpicture->privData = + (i810XvMCSubpicture *)malloc(sizeof(i810XvMCSubpicture)); + + if(!subpicture->privData) { + return BadAlloc; + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + + if((ret = _xvmc_create_subpicture(display, context, subpicture, + &priv_count, &priv_data))) { + printf("Unable to create XvMCSubpicture.\n"); + return ret; + } + + if(priv_count != 1) { + printf("_xvmc_create_subpicture() returned incorrect data size.\n"); + printf("Expected 1 got %d\n",priv_count); + free(priv_data); + return BadAlloc; + } + /* Data == Client Address, offset == Physical address offset */ + pI810Subpicture->data = pI810XvMC->surfaces.address; + pI810Subpicture->offset = pI810XvMC->surfaces.offset; + + /* Initialize private values */ + pI810Subpicture->privContext = pI810XvMC; + + pI810Subpicture->last_render = 0; + pI810Subpicture->last_flip = 0; + + /* Based on the xvimage_id we will need to set the other values */ + subpicture->num_palette_entries = 16; + subpicture->entry_bytes = 3; + strcpy(subpicture->component_order,"YUV"); + + /* + i810's MC Engine needs surfaces of 2^x (x= 9,10,11,12) pitch + and the Tiler need 512k aligned surfaces, basically we are + stuck with fixed memory with pitch 1024. + */ + pI810Subpicture->pitch = 10; + + /* + offsets[0] == offset into the map described by either + address (Client memeory address) or offset (physical offset from fb base) + */ + pI810Subpicture->offsets[0] = priv_data[0]; + if(((unsigned long)pI810Subpicture->data + pI810Subpicture->offsets[0]) & 4095) { + printf("XvMCCreateSubpicture: Subpicture offset 0 is not 4096 aligned\n"); + } + + /* Free data returned from xvmc_create_surface */ + free(priv_data); + + /* Clear the surface to 0 */ + memset((void *)((unsigned long)pI810Subpicture->data + (unsigned long)pI810Subpicture->offsets[0]), + 0, ((1<<pI810Subpicture->pitch) * subpicture->height)); + + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + case FOURCC_AI44: + /* Destination buffer info command */ + pI810Subpicture->dbi1 = ((((unsigned int)pI810Subpicture->offset + + pI810Subpicture->offsets[0]) & ~0xfc000fff) | + (pI810Subpicture->pitch - 9)); + + /* Destination buffer variables command */ + pI810Subpicture->dbv1 = (0x8<<20) | (0x8<<16); + + /* Map info command */ + pI810Subpicture->mi1 = (0x0<<24) | (3<<21) | (1<<9) | + (pI810Subpicture->pitch - 3); + + pI810Subpicture->mi2 = (((unsigned int)subpicture->height - 1)<<16) | + ((unsigned int)subpicture->width - 1); + + pI810Subpicture->mi3 = ((unsigned int)pI810Subpicture->offset + + pI810Subpicture->offsets[0]) & ~0xfc00000f; + break; + default: + free(subpicture->privData); + return BadMatch; + } + + pI810XvMC->ref++; + return Success; +} + + + +/*************************************************************************** +// Function: XvMCClearSubpicture +// Description: Clear the area of the given subpicture to "color". +// structure passed to it and returning Success. +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to clear. +// x, y, width, height - rectangle in the subpicture to clear. +// color - The data to file the rectangle with. +// +// Returns: Status +***************************************************************************/ +Status XvMCClearSubpicture(Display *display, XvMCSubpicture *subpicture, + short x, short y, + unsigned short width, unsigned short height, + unsigned int color) { + + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int i; + + if((subpicture == NULL) || (display == NULL)){ + return BadValue; + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((x < 0) || (x + width > subpicture->width)) { + return BadValue; + } + + if((y < 0) || (y + height > subpicture->height)) { + return BadValue; + } + + for(i=y; i<y + height; i++) { + memset((void *)((unsigned long)pI810Subpicture->data + + (unsigned long)pI810Subpicture->offsets[0] + x + + (1<<pI810Subpicture->pitch) * i),(char)color,width); + } + + return Success; +} + +/*************************************************************************** +// Function: XvMCCompositeSubpicture +// Description: Composite the XvImae on the subpicture. This composit uses +// non-premultiplied alpha. Destination alpha is utilized +// except for with indexed subpictures. Indexed subpictures +// use a simple "replace". +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to clear. +// image - the XvImage to be used as the source of the composite. +// srcx, srcy, width, height - The rectangle from the image to be used. +// dstx, dsty - location in the subpicture to composite the source. +// +// Returns: Status +***************************************************************************/ +Status XvMCCompositeSubpicture(Display *display, XvMCSubpicture *subpicture, + XvImage *image, + short srcx, short srcy, + unsigned short width, unsigned short height, + short dstx, short dsty) { + + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *pI810Subpicture; + int i; + + if((subpicture == NULL) || (display == NULL)){ + return BadValue; + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((srcx < 0) || (srcx + width > image->width)) { + return BadValue; + } + + if((dstx < 0) || (dstx + width > subpicture->width)) { + return BadValue; + } + + if((srcy < 0) || (srcy + height > image->height)) { + return BadValue; + } + + if((dsty < 0) || (dsty + height > subpicture->height)) { + return BadValue; + } + + for(i=0; i<height; i++) { + memcpy((void *)((unsigned long)pI810Subpicture->data + + (unsigned long)pI810Subpicture->offsets[0] + dstx + + (1<<pI810Subpicture->pitch) * (i + dsty)), + (void *)((unsigned long)image->data + + (unsigned long)image->offsets[0] + srcx + + image->pitches[0] * (i + srcy)) + ,width); + } + + return Success; + +} + + +/*************************************************************************** +// Function: XvMCDestroySubpicture +// Description: Destroys the specified subpicture. +// Arguments: +// display - Connection to the X server. +// subpicture - Subpicture to be destroyed. +// +// Returns: Status +***************************************************************************/ +Status XvMCDestroySubpicture(Display *display, XvMCSubpicture *subpicture) { + + i810XvMCSubpicture *pI810Subpicture; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (subpicture == NULL)) { + return BadValue; + } + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + pI810Subpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)pI810Subpicture->privContext; + if(!pI810XvMC) { + return (error_base + XvMCBadSubpicture); + } + + + if(pI810Subpicture->last_render) { + XvMCSyncSubpicture(display,subpicture); + } + + _xvmc_destroy_subpicture(display,subpicture); + + i810_free_privContext(pI810XvMC); + + free(pI810Subpicture); + subpicture->privData = NULL; + return Success; +} + + +/*************************************************************************** +// Function: XvMCSetSubpicturePalette +// Description: Set the subpictures palette +// Arguments: +// display - Connection to the X server. +// subpicture - Subpiture to set palette for. +// palette - A pointer to an array holding the palette data. The array +// is num_palette_entries * entry_bytes in size. +// Returns: Status +***************************************************************************/ + +Status XvMCSetSubpicturePalette(Display *display, XvMCSubpicture *subpicture, + unsigned char *palette) { + i810XvMCSubpicture *privSubpicture; + int i,j; + + if((display == NULL) || (subpicture == NULL)) { + return BadValue; + } + if(subpicture->privData == NULL) { + return (error_base + XvMCBadSubpicture); + } + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + j=0; + for(i=0; i<16; i++) { + privSubpicture->palette[0][i] = palette[j++]; + privSubpicture->palette[1][i] = palette[j++]; + privSubpicture->palette[2][i] = palette[j++]; + } + return Success; +} + +/*************************************************************************** +// Function: XvMCBlendSubpicture +// Description: +// The behavior of this function is different depending on whether +// or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo. +// i810 only support frontend behavior. +// +// XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior): +// +// XvMCBlendSubpicture is a no-op in this case. +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to be blended into the video. +// target_surface - The surface to be displayed with the blended subpic. +// source_surface - Source surface prior to blending. +// subx, suby, subw, subh - The rectangle from the subpicture to use. +// surfx, surfy, surfw, surfh - The rectangle in the surface to blend +// blend the subpicture rectangle into. Scaling can ocure if +// XVMC_SUBPICTURE_INDEPENDENT_SCALING is set. +// +// Returns: Status +***************************************************************************/ +Status XvMCBlendSubpicture(Display *display, XvMCSurface *target_surface, + XvMCSubpicture *subpicture, + short subx, short suby, + unsigned short subw, unsigned short subh, + short surfx, short surfy, + unsigned short surfw, unsigned short surfh) { + + return BadMatch; +} + + + +/*************************************************************************** +// Function: XvMCBlendSubpicture2 +// Description: +// The behavior of this function is different depending on whether +// or not the XVMC_BACKEND_SUBPICTURE flag is set in the XvMCSurfaceInfo. +// i810 only supports frontend blending. +// +// XVMC_BACKEND_SUBPICTURE not set ("frontend" behavior): +// +// XvMCBlendSubpicture2 blends the source_surface and subpicture and +// puts it in the target_surface. This does not effect the status of +// the source surface but will cause the target_surface to query +// XVMC_RENDERING until the blend is completed. +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to be blended into the video. +// target_surface - The surface to be displayed with the blended subpic. +// source_surface - Source surface prior to blending. +// subx, suby, subw, subh - The rectangle from the subpicture to use. +// surfx, surfy, surfw, surfh - The rectangle in the surface to blend +// blend the subpicture rectangle into. Scaling can ocure if +// XVMC_SUBPICTURE_INDEPENDENT_SCALING is set. +// +// Returns: Status +***************************************************************************/ +Status XvMCBlendSubpicture2(Display *display, + XvMCSurface *source_surface, + XvMCSurface *target_surface, + XvMCSubpicture *subpicture, + short subx, short suby, + unsigned short subw, unsigned short subh, + short surfx, short surfy, + unsigned short surfw, unsigned short surfh) { + drmBufPtr pDMA; + unsigned int *data; + i810XvMCContext *pI810XvMC; + i810XvMCSubpicture *privSubpicture; + i810XvMCSurface *privTarget; + i810XvMCSurface *privSource; + drm_i810_mc_t mc; + int i,j; + + if(display == NULL) { + return BadValue; + } + + if(subpicture == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if((target_surface == NULL) || (source_surface == NULL)) { + return (error_base + XvMCBadSurface); + } + + if((subpicture->xvimage_id != FOURCC_AI44) && + (subpicture->xvimage_id != FOURCC_IA44)) { + return (error_base + XvMCBadSubpicture); + } + + if(!subpicture->privData) { + return (error_base + XvMCBadSubpicture); + } + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)privSubpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + if(!target_surface->privData) { + return (error_base + XvMCBadSurface); + } + privTarget = (i810XvMCSurface *)target_surface->privData; + + if(!source_surface->privData) { + return (error_base + XvMCBadSurface); + } + privSource = (i810XvMCSurface *)source_surface->privData; + + + /* Check that size isn't bigger than subpicture */ + if((subx + subw) > subpicture->width) { + return BadValue; + } + if((suby + subh) > subpicture->height) { + return BadValue; + } + /* Check that dest isn't bigger than surface */ + if((surfx + surfw) > target_surface->width) { + return BadValue; + } + if((surfy + surfh) > target_surface->height) { + return BadValue; + } + /* Make sure surfaces match */ + if(target_surface->width != source_surface->width) { + return BadValue; + } + if(target_surface->height != source_surface->height) { + return BadValue; + } + + /* Lock For DMA */ + I810_LOCK(pI810XvMC,0); + + /* Allocate DMA buffer */ + pDMA = i810_get_free_buffer(pI810XvMC); + data = pDMA->address; + + /* Copy Y data first */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<privTarget->pitch); + *data++ = (target_surface->height<<16) | target_surface->width; + *data++ = privTarget->offset + privTarget->offsets[0]; + *data++ = (1<<privSource->pitch); + *data++ = privSource->offset + privSource->offsets[0]; + + /* Select Context 1 for loading */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + + /* Load Palette */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[0][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[0][j]; + } + } + break; + } + /* TARGET */ + /* *data++ = CMD_FLUSH; */ + /* *data++ = BOOLEAN_ENA_2; */ + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1y; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = DRAWING_RECT_INFO; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + *data++ = 0x0; + + /* GFXPRIMITIVE RECTANGLE */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right Vertex */ + *(float *)data++ = (float) (surfx + surfw); + *(float *)data++ = (float) (surfy + surfh); + *(float *)data++ = (float) (subx + subw); + *(float *)data++ = (float) (suby + subh); + /* Bottom Left Vertex */ + *(float *)data++ = (float) surfx; + *(float *)data++ = (float) (surfy + surfh); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) (suby + subh); + /* Top Left Vertex */ + *(float *)data++ = (float) surfx; + *(float *)data++ = (float) surfy; + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + /* U data */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1)); + *data++ = (target_surface->height<<15) | (target_surface->width>>1); + *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[1]; + *data++ = (1<<(privSource->pitch - 1)); + *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[1]; + + /* Context 1 select */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + /* ALPHA PALETTE */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[2][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[2][j]; + } + } + break; + } + /* TARGET */ + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1u; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + + /* Rectangle */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right */ + *(float *)data++ = (float) ((surfx + surfw)>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx + subw; + *(float *)data++ = (float) suby + subh; + /* Bottom Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby + subh; + /* Top Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) (surfy>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + /* V data */ + /* SOURCE_COPY_BLT */ + *data++ = (2<<29) | (0x43<<22) | 0x4; + *data++ = (0xcc<<16) | (1<<26) | (1<<(privTarget->pitch - 1)); + *data++ = (target_surface->height<<15) | (target_surface->width>>1); + *data++ = (unsigned long)privTarget->offset + (unsigned long)privTarget->offsets[2]; + *data++ = (1<<(privSource->pitch - 1)); + *data++ = (unsigned long)privSource->offset + (unsigned long)privSource->offsets[2]; + + /* Context 1 select */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<8); + *data++ = CMD_FLUSH; + + /* ALPHA PALETTE */ + *data++ = MAP_PALETTE_LOAD; + /* 16 levels of alpha for each Y */ + switch(subpicture->xvimage_id) { + case FOURCC_IA44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (j<<12) | (j<<8) | privSubpicture->palette[1][i]; + } + } + break; + case FOURCC_AI44: + for(i=0; i<16; i++) { + for(j=0; j<16; j++) { + *data++ = (i<<12) | (i<<8) | privSubpicture->palette[1][j]; + } + } + break; + } + /* TARGET */ + *data++ = CMD_FLUSH; + *data++ = BOOLEAN_ENA_2; + *data++ = CMD_FLUSH; + *data++ = DEST_BUFFER_INFO; + *data++ = privTarget->dbi1v; + *data++ = DEST_BUFFER_VAR; + *data++ = privTarget->dbv1; + + /* ALPHA */ + *data++ = CMD_MAP_INFO; + *data++ = privSubpicture->mi1; + *data++ = privSubpicture->mi2; + *data++ = privSubpicture->mi3; + + *data++ = VERTEX_FORMAT | (1<<8) | (3<<1); + *data++ = BOOLEAN_ENA_1; + *data++ = SRC_DEST_BLEND_MONO | (0x940); + /* Map Filter */ + *data++ = (3<<29) | (0x1c<<24) | (2<<19) | (1<<16) | (0x224); + + /* Use context 1 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<16) | 1; + *data++ = CMD_FLUSH; + + /* Drawing Rect Info */ + *data++ = (3<<29) | (0x1d<<24) | (0x80<<16) | 3; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + *data++ = 0; + + /* Rectangle */ + *data++ = (3<<29) | (0x1f<<24) | (0x7<<18) | 11; + /* Bottom Right */ + *(float *)data++ = (float) ((surfx + surfw)>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx + subw; + *(float *)data++ = (float) suby + subh; + /* Bottom Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) ((surfy + surfh)>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby + subh; + /* Top Left */ + *(float *)data++ = (float) (surfx>>1); + *(float *)data++ = (float) (surfy>>1); + *(float *)data++ = (float) subx; + *(float *)data++ = (float) suby; + + /* Load and Use Context 0 */ + *data++ = CMD_FLUSH; + *data++ = (5<<23) | (1<<17) | (1<<16); + *data++ = CMD_FLUSH; + + + /* Dispatch */ + pDMA->used = (unsigned long)data - (unsigned long)pDMA->address; + mc.idx = pDMA->idx; + mc.used = pDMA->used; + mc.last_render = ++pI810XvMC->last_render; + privTarget->last_render = pI810XvMC->last_render; + I810_MC(pI810XvMC,mc); + + I810_UNLOCK(pI810XvMC); + return Success; +} + + + +/*************************************************************************** +// Function: XvMCSyncSubpicture +// Description: This function blocks until all composite/clear requests on +// the subpicture have been complete. +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture to synchronize +// +// Returns: Status +***************************************************************************/ +Status XvMCSyncSubpicture(Display *display, XvMCSubpicture *subpicture) { + Status ret; + int stat=0; + do { + ret = XvMCGetSubpictureStatus(display,subpicture,&stat); + }while(!ret && (stat & XVMC_RENDERING)); + return ret; +} + + + +/*************************************************************************** +// Function: XvMCFlushSubpicture +// Description: This function commits pending composite/clear requests to +// ensure that they will be completed in a finite amount of +// time. +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture whos compsiting should be flushed +// +// Returns: Status +// NOTES: i810 always dispatches commands so flush is a no-op +***************************************************************************/ +Status XvMCFlushSubpicture(Display *display, XvMCSubpicture *subpicture) { + if(display == NULL) { + return BadValue; + } + if(subpicture == NULL) { + return (error_base + XvMCBadSubpicture); + } + + return Success; +} + + + +/*************************************************************************** +// Function: XvMCGetSubpictureStatus +// Description: This function gets the current status of a subpicture +// +// Arguments: +// display - Connection to the X server. +// subpicture - The subpicture whos status is being queried +// stat - The status of the subpicture. It can be any of the following +// OR'd together: +// XVMC_RENDERING - Last composite or clear request not completed +// XVMC_DISPLAYING - Suppicture currently being displayed. +// +// Returns: Status +// Notes: i810 always blends into a third surface so the subpicture is +// never actually displaying, only a copy of it is displaying. We only +// have to worry about the rendering case. +***************************************************************************/ +Status XvMCGetSubpictureStatus(Display *display, XvMCSubpicture *subpicture, + int *stat) { + + i810XvMCSubpicture *privSubpicture; + i810XvMCContext *pI810XvMC; + + if((display == NULL) || (stat == NULL)) { + return BadValue; + } + if((subpicture == NULL) || (subpicture->privData == NULL)) { + return (error_base + XvMCBadSubpicture); + } + *stat = 0; + privSubpicture = (i810XvMCSubpicture *)subpicture->privData; + + pI810XvMC = (i810XvMCContext *)privSubpicture->privContext; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadSubpicture); + } + + I810_LOCK(pI810XvMC,0); + + if(privSubpicture->last_render && + (privSubpicture->last_render > GET_RSTATUS(pI810XvMC))) { + *stat |= XVMC_RENDERING; + } + I810_UNLOCK(pI810XvMC); + + return Success; +} + +#define NUM_XVMC_ATTRIBUTES 4 +static XvAttribute I810_XVMC_ATTRIBUTES[] = { + {XvGettable | XvSettable, 0, 0xffffff, "XV_COLORKEY"}, + {XvGettable | XvSettable, -127, +127, "XV_BRIGHTNESS"}, + {XvGettable | XvSettable, 0, 0x1ff, "XV_CONTRAST"}, + {XvGettable | XvSettable, 0, 0x3ff, "XV_SATURATION"} +}; + + +/*************************************************************************** +// Function: XvMCQueryAttributes +// Description: An array of XvAttributes of size "number" is returned by +// this function. If there are no attributes, NULL is returned and number +// is set to 0. The array may be freed with xfree(). +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// number - The number of returned atoms. +// +// Returns: +// An array of XvAttributes. +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +XvAttribute *XvMCQueryAttributes(Display *display, XvMCContext *context, + int *number) { + i810XvMCContext *pI810XvMC; + XvAttribute *attributes; + + if(number == NULL) { + return NULL; + } + if(display == NULL) { + *number = 0; + return NULL; + } + if(context == NULL) { + *number = 0; + return NULL; + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + *number = 0; + return NULL; + } + + attributes = (XvAttribute *)malloc(NUM_XVMC_ATTRIBUTES * + sizeof(XvAttribute)); + if(attributes == NULL) { + *number = 0; + return NULL; + } + + memcpy(attributes,I810_XVMC_ATTRIBUTES,(NUM_XVMC_ATTRIBUTES * + sizeof(XvAttribute))); + + *number = NUM_XVMC_ATTRIBUTES; + return attributes; +} + +/*************************************************************************** +// Function: XvMCSetAttribute +// Description: This function sets a context-specific attribute. +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// attribute - The X atom of the attribute to be changed. +// value - The new value for the attribute. +// +// Returns: +// Status +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +Status XvMCSetAttribute(Display *display, XvMCContext *context, + Atom attribute, int value) { + i810XvMCContext *pI810XvMC; + + if(display == NULL) { + return BadValue; + } + if(context == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + + if(attribute == pI810XvMC->xv_colorkey) { + if((value < I810_XVMC_ATTRIBUTES[0].min_value) || + (value > I810_XVMC_ATTRIBUTES[0].max_value)) { + return BadValue; + } + pI810XvMC->colorkey = value; + return Success; + } + if(attribute == pI810XvMC->xv_brightness) { + if((value < I810_XVMC_ATTRIBUTES[1].min_value) || + (value > I810_XVMC_ATTRIBUTES[1].max_value)) { + return BadValue; + } + pI810XvMC->brightness = value; + return Success; + } + if(attribute == pI810XvMC->xv_saturation) { + if((value < I810_XVMC_ATTRIBUTES[2].min_value) || + (value > I810_XVMC_ATTRIBUTES[2].max_value)) { + return BadValue; + } + pI810XvMC->saturation = value; + return Success; + } + if(attribute == pI810XvMC->xv_contrast) { + if((value < I810_XVMC_ATTRIBUTES[3].min_value) || + (value > I810_XVMC_ATTRIBUTES[3].max_value)) { + return BadValue; + } + pI810XvMC->contrast = value; + return Success; + } + return BadValue; +} + +/*************************************************************************** +// Function: XvMCGetAttribute +// Description: This function queries a context-specific attribute and +// returns the value. +// +// Arguments: +// display - Connection to the X server. +// context - The context whos attributes we are querying. +// attribute - The X atom of the attribute to be queried +// value - The returned attribute value +// +// Returns: +// Status +// Notes: +// For i810 we support these Attributes: +// XV_COLORKEY: The colorkey value, initialized from the Xv value at +// context creation time. +// XV_BRIGHTNESS +// XV_CONTRAST +// XV_SATURATION +***************************************************************************/ +Status XvMCGetAttribute(Display *display, XvMCContext *context, + Atom attribute, int *value) { + i810XvMCContext *pI810XvMC; + + if(display == NULL) { + return BadValue; + } + if(context == NULL) { + return (error_base + XvMCBadContext); + } + pI810XvMC = context->privData; + if(pI810XvMC == NULL) { + return (error_base + XvMCBadContext); + } + if(value == NULL) { + return BadValue; + } + + if(attribute == pI810XvMC->xv_colorkey) { + *value = pI810XvMC->colorkey; + return Success; + } + if(attribute == pI810XvMC->xv_brightness) { + *value = pI810XvMC->brightness; + return Success; + } + if(attribute == pI810XvMC->xv_saturation) { + *value = pI810XvMC->saturation; + return Success; + } + if(attribute == pI810XvMC->xv_contrast) { + *value = pI810XvMC->contrast; + return Success; + } + return BadValue; +} + + + + diff --git a/src/xvmc/I810XvMC.h b/src/xvmc/I810XvMC.h new file mode 100644 index 00000000..018c80e9 --- /dev/null +++ b/src/xvmc/I810XvMC.h @@ -0,0 +1,469 @@ +/*************************************************************************** + +Copyright 2001 Intel Corporation. All Rights Reserved. + +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, sub license, 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 NON-INFRINGEMENT. +IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/*************************************************************************** + * libI810XvMC.h: MC Driver i810 includes + * + * Authors: + * Matt Sottek <matthew.j.sottek@intel.com> + * + * + ***************************************************************************/ +/* $XFree86: xc/lib/XvMC/hw/i810/I810XvMC.h,v 1.4 2002/11/19 09:35:49 alanh Exp $ */ + + +#ifndef I810XVMC_H +#define I810XVMC_H + +/* #define XVMC_DEBUG(x) do {x; }while(0); */ +#define XVMC_DEBUG(x) + +#include "xf86drm.h" +#include "i810_common.h" +#include <X11/Xlibint.h> + + +/*************************************************************************** +// i810OverlayRec: Structure that is used to reference the overlay +// register memory. A i810OverlayRecPtr is set to the address of the +// allocated overlay registers. +***************************************************************************/ +typedef struct _i810OverlayRec { + unsigned int OBUF_0Y; + unsigned int OBUF_1Y; + unsigned int OBUF_0U; + unsigned int OBUF_0V; + unsigned int OBUF_1U; + unsigned int OBUF_1V; + unsigned int OV0STRIDE; + unsigned int YRGB_VPH; + unsigned int UV_VPH; + unsigned int HORZ_PH; + unsigned int INIT_PH; + unsigned int DWINPOS; + unsigned int DWINSZ; + unsigned int SWID; + unsigned int SWIDQW; + unsigned int SHEIGHT; + unsigned int YRGBSCALE; + unsigned int UVSCALE; + unsigned int OV0CLRC0; + unsigned int OV0CLRC1; + unsigned int DCLRKV; + unsigned int DCLRKM; + unsigned int SCLRKVH; + unsigned int SCLRKVL; + unsigned int SCLRKM; + unsigned int OV0CONF; + unsigned int OV0CMD; +} i810OverlayRec, *i810OverlayRecPtr; + + +/*************************************************************************** +// i810XvMCDrmMap: Holds the data about the DRM maps +***************************************************************************/ +typedef struct _i810XvMCDrmMap { + drmHandle offset; + drmAddress address; + unsigned int size; +} i810XvMCDrmMap, *i810XvMCDrmMapPtr; + +/*************************************************************************** +// i810XvMCContext: Private Context data referenced via the privData +// pointer in the XvMCContext structure. +***************************************************************************/ +typedef struct _i810XvMCContext { + int fd; /* File descriptor for /dev/dri */ + i810XvMCDrmMap overlay; + i810XvMCDrmMap surfaces; + drmBufMapPtr dmabufs; /* Data structure to hold available dma buffers */ + drmContext drmcontext; + unsigned int last_render; + unsigned int last_flip; + unsigned short ref; + unsigned short current; + int lock; /* Lightweight lock to avoid locking twice */ + char busIdString[10]; /* PCI:0:1:0 or PCI:0:2:0 */ + i810OverlayRecPtr oregs; + unsigned int dual_prime; /* Flag to identify when dual prime is in use. */ + unsigned int fb_base; + Atom xv_colorkey; + Atom xv_brightness; + Atom xv_contrast; + Atom xv_saturation; + int brightness; + int saturation; + int contrast; + int colorkey; +} i810XvMCContext; + +/*************************************************************************** +// i810XvMCSurface: Private data structure for each XvMCSurface. This +// structure is referenced by the privData pointer in the XvMCSurface +// structure. +***************************************************************************/ +typedef struct _i810XvMCSurface { + unsigned int pitch; + unsigned int dbi1y; /* Destination buffer info command word 1 for Y */ + unsigned int dbi1u; /* Destination buffer info command word 1 for U */ + unsigned int dbi1v; /* Destination buffer info command word 1 for V */ + unsigned int dbv1; /* Destination buffer variables command word 1 */ + unsigned int mi1y; /* Map Info command word 1 (Minus bit 28) for Y */ + unsigned int mi1u; /* Map Info command word 1 (Minus bit 28) for U */ + unsigned int mi1v; /* Map Info command word 1 (Minus bit 28) for V */ + unsigned int mi2y; /* Map info command word 2 for y */ + unsigned int mi2u; /* Map info command word 2 for y */ + unsigned int mi2v; /* Map info command word 2 for y */ + unsigned int mi3y; /* Map info command word 3 */ + unsigned int mi3u; /* Map info command word 3 */ + unsigned int mi3v; /* Map info command word 3 */ + unsigned int last_render; + unsigned int last_flip; + unsigned int second_field; /* Flags a surface that is only half done */ + drmAddress data; + drmHandle offset; + unsigned int offsets[3]; + i810XvMCContext *privContext; +} i810XvMCSurface; + +/*************************************************************************** +// i810XvMCSubpicture: Private data structure for each XvMCSubpicture. This +// structure is referenced by the privData pointer in the XvMCSubpicture +// structure. +***************************************************************************/ +typedef struct _i810XvMCSubpicture { + unsigned int pitch; + unsigned int dbi1; /* Destination buffer info command word 1 */ + unsigned int dbv1; /* Destination buffer variables command word */ + unsigned int mi1; /* Map Info command word 1 (Minus bit 28) */ + unsigned int mi2; /* Map info command word 2 */ + unsigned int mi3; /* Map info command word 3 */ + unsigned int last_render; + unsigned int last_flip; + drmAddress data; + drmHandle offset; + unsigned int offsets[1]; + unsigned char palette[3][16]; + i810XvMCContext *privContext; +} i810XvMCSubpicture; + +typedef struct _Box { + int x1,y1,x2,y2; +} Box, *BoxPtr; + +/*************************************************************************** +// drm_i810_overlay_t: Structure returned by overlay info ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_overlay_t { + unsigned int offset; + unsigned int physical; +} drm_i810_overlay_t; + +/*************************************************************************** +// drm_i810_dma_t: Structure used by dma allocation ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_dma { + void *virtual; + int request_idx; + int request_size; + int granted; +} drm_i810_dma_t; + +/*************************************************************************** +// drm_i810_mc_t: Structure used by mc dispatch ioctl. +// NOTE: If you change this structure you will have to change the equiv. +// structure in the kernel. +***************************************************************************/ +typedef struct _drm_i810_mc { + int idx; /* buffer index */ + int used; /* nr bytes in use */ + int num_blocks; /* number of GFXBlocks */ + int *length; /* List of lengths for GFXBlocks */ + unsigned int last_render; /* Last render request */ +} drm_i810_mc_t; + +/* Subpicture fourcc */ +#define FOURCC_IA44 0x34344149 + +/* Static Parameters */ +#define I810_XVMC_MAXWIDTH 720 +#define I810_XVMC_MAXHEIGHT 576 +#define I810_DEFAULT16_COLORKEY 31 +#define I810_DMA_BUF_NR 256 + +/* COMMANDS */ +#define CMD_FLUSH ((4<<23) | 0x1) +#define BOOLEAN_ENA_1 ((3<<29) | (3<<24) | (3<<2)) +#define BOOLEAN_ENA_2 ((3<<29) | (4<<24) | (3<<16) | (1<<3) | (1<<2)) +#define DEST_BUFFER_INFO (0x15<<23) +#define DEST_BUFFER_VAR ((0x3<<29) | (0x1d<<24) | (0x85<<16)) +#define DRAWING_RECT_INFO ((3<<29) | (0x1d<<24) | (0x80<<16) | 3) +#define GFXBLOCK ((0x3<<29) | (0x1e<<24)) +#define CMD_MAP_INFO ((0x3<<29) | (0x1d<<24) | 0x2) +#define MAP_PALETTE_LOAD ((3<<29) | (0x1d<<24) | (0x82<<16) | 0xff) +#define VERTEX_FORMAT ((3<<29) | (0x5<<24)) +#define SRC_DEST_BLEND_MONO ((3<<29) | (8<<24)) + +/* Bit Patterns */ + +/* + * OV0CMD - Overlay Command Register + */ +#define VERTICAL_CHROMINANCE_FILTER 0x70000000 +#define VC_SCALING_OFF 0x00000000 +#define VC_LINE_REPLICATION 0x10000000 +#define VC_UP_INTERPOLATION 0x20000000 +#define VC_PIXEL_DROPPING 0x50000000 +#define VC_DOWN_INTERPOLATION 0x60000000 +#define VERTICAL_LUMINANCE_FILTER 0x0E000000 +#define VL_SCALING_OFF 0x00000000 +#define VL_LINE_REPLICATION 0x02000000 +#define VL_UP_INTERPOLATION 0x04000000 +#define VL_PIXEL_DROPPING 0x0A000000 +#define VL_DOWN_INTERPOLATION 0x0C000000 +#define HORIZONTAL_CHROMINANCE_FILTER 0x01C00000 +#define HC_SCALING_OFF 0x00000000 +#define HC_LINE_REPLICATION 0x00400000 +#define HC_UP_INTERPOLATION 0x00800000 +#define HC_PIXEL_DROPPING 0x01400000 +#define HC_DOWN_INTERPOLATION 0x01800000 +#define HORIZONTAL_LUMINANCE_FILTER 0x00380000 +#define HL_SCALING_OFF 0x00000000 +#define HL_LINE_REPLICATION 0x00080000 +#define HL_UP_INTERPOLATION 0x00100000 +#define HL_PIXEL_DROPPING 0x00280000 +#define HL_DOWN_INTERPOLATION 0x00300000 + +#define Y_ADJUST 0x00010000 +#define OV_BYTE_ORDER 0x0000C000 +#define UV_SWAP 0x00004000 +#define Y_SWAP 0x00008000 +#define Y_AND_UV_SWAP 0x0000C000 +#define SOURCE_FORMAT 0x00003C00 +#define RGB_555 0x00000800 +#define RGB_565 0x00000C00 +#define YUV_422 0x00002000 +#define YUV_411 0x00002400 +#define YUV_420 0x00003000 +#define YUV_410 0x00003800 +#define VERTICAL_PHASE_BOTH 0x00000020 +#define FLIP_TYPE_FIELD 0x00000020 +#define FLIP_TYPE_FRAME 0x00000000 +#define BUFFER_AND_FIELD 0x00000006 +#define BUFFER0_FIELD0 0x00000000 +#define BUFFER0_FIELD1 0x00000002 +#define BUFFER1_FIELD0 0x00000004 +#define BUFFER1_FIELD1 0x00000006 +#define OVERLAY_ENABLE 0x00000001 + +/* + * DOV0STA - Display/Overlay 0 Status Register + */ +#define DOV0STA 0x30008 +#define OV0ADD 0x30000 +#define MINUV_SCALE 0x1 + +#define RGB16ToColorKey(c) \ + (((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) + +/* Locking Macros lightweight lock used to prevent relocking */ +#define I810_LOCK(c,f) \ + if(!c->lock) { \ + drmGetLock(c->fd, c->drmcontext, f); \ + } \ + c->lock++; + +#define I810_UNLOCK(c) \ + c->lock--; \ + if(!c->lock) { \ + drmUnlock(c->fd, c->drmcontext); \ + } + +/* + Block until the passed in value (n) is the active + buffer on the overlay. +*/ +#define BLOCK_OVERLAY(c,n) \ + do { \ + int temp,i=0; \ + while(i < 100000) { \ + temp = GET_FSTATUS(c); \ + if(((temp & (1<<20))>>20) == n) { \ + break; \ + } \ + usleep(10); \ + } \ + if(i == 100000) { \ + printf("Overlay Lockup.\n"); \ + return BadAlloc; \ + } \ + }while(0); + +#define OVERLAY_INFO(c,i) drmCommandRead(c->fd, DRM_I810_OV0INFO, &i, sizeof(i)) +#define OVERLAY_FLIP(c) drmCommandNone(c->fd, DRM_I810_OV0FLIP) +#define GET_FSTATUS(c) drmCommandNone(c->fd, DRM_I810_FSTATUS) +#define I810_MC(c,mc) drmCommandWrite(c->fd, DRM_I810_MC, &mc, sizeof(mc)) +#define GET_RSTATUS(c) drmCommandNone(c->fd, DRM_I810_RSTATUS) +#define GET_BUFFER(c,dma) drmCommandWriteRead(c->fd, DRM_I810_GETBUF, &dma, sizeof(drmI810DMA)) +#define FLUSH(c) drmCommandNone(c->fd, DRM_I810_FLUSH) + +/* + Definitions for temporary wire protocol hooks to be replaced + when a HW independent libXvMC is created. +*/ +extern Status _xvmc_create_context(Display *dpy, XvMCContext *context, + int *priv_count, uint **priv_data); + +extern Status _xvmc_destroy_context(Display *dpy, XvMCContext *context); + +extern Status _xvmc_create_surface(Display *dpy, XvMCContext *context, + XvMCSurface *surface, int *priv_count, + uint **priv_data); + +extern Status _xvmc_destroy_surface(Display *dpy, XvMCSurface *surface); + +extern Status _xvmc_create_subpicture(Display *dpy, XvMCContext *context, + XvMCSubpicture *subpicture, + int *priv_count, uint **priv_data); + +extern Status _xvmc_destroy_subpicture(Display *dpy, + XvMCSubpicture *subpicture); + +/* + Prototypes +*/ +drmBufPtr i810_get_free_buffer(i810XvMCContext *pI810XvMC); +void i810_free_privContext(i810XvMCContext *pI810XvMC); +void dp(unsigned int *address, unsigned int i); + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |