/* * Copyright 2007 by VMware, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. * * Except as contained in this notice, the name of the copyright holder(s) * and author(s) shall not be used in advertising or otherwise to promote * the sale, use or other dealings in this Software without prior written * authorization from the copyright holder(s) and author(s). */ /* * vmwarevideo.c -- * * Xv extension support. * See http://www.xfree86.org/current/DESIGN16.html * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "vmware.h" #include "vmware_common.h" #include "xf86xv.h" #include "fourcc.h" #include "svga_escape.h" #include "svga_overlay.h" #include "common_compat.h" #include #ifndef HAVE_XORG_SERVER_1_5_0 #include #include #endif static CONST_ABI_16_0 char xv_adapt_name[] = "VMWare Overlay Video Engine"; /* XXXMRG see xorg-server/dist/hw/xfree86/common/xf86xv.h */ static /*CONST_ABI_16_0*/ char xv_image_name[] = "XV_IMAGE"; #define HAVE_FILLKEYHELPERDRAWABLE \ ((GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 2) || \ ((GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) == 1) && \ (GET_ABI_MINOR(ABI_VIDEODRV_VERSION) >= 2))) #if HAVE_FILLKEYHELPERDRAWABLE #include #endif #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) /* * Used to pack structs */ #define PACKED __attribute__((__packed__)) /* * Number of videos that can be played simultaneously */ #define VMWARE_VID_NUM_PORTS 1 /* * Using a dark shade as the default colorKey */ #define VMWARE_VIDEO_COLORKEY 0x100701 /* * Maximum dimensions */ #define VMWARE_VID_MAX_WIDTH 2048 #define VMWARE_VID_MAX_HEIGHT 2048 #define VMWARE_VID_NUM_ENCODINGS 1 static XF86VideoEncodingRec vmwareVideoEncodings[] = { { 0, xv_image_name, VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT, {1, 1} } }; #define VMWARE_VID_NUM_FORMATS 2 static XF86VideoFormatRec vmwareVideoFormats[] = { { 16, TrueColor}, { 24, TrueColor} }; #define VMWARE_VID_NUM_IMAGES 3 static XF86ImageRec vmwareVideoImages[] = { XVIMAGE_YV12, XVIMAGE_YUY2, XVIMAGE_UYVY }; static CONST_ABI_16_TO_19 char xv_colorkey_name[] = "XV_COLORKEY"; static CONST_ABI_16_TO_19 char xv_autopaint_name[] = "XV_AUTOPAINT_COLORKEY"; #define VMWARE_VID_NUM_ATTRIBUTES 2 static XF86AttributeRec vmwareVideoAttributes[] = { { XvGettable | XvSettable, 0x000000, 0xffffff, xv_colorkey_name, }, { XvGettable | XvSettable, 0, 1, xv_autopaint_name, } }; /* * Video frames are stored in a circular list of buffers. */ #define VMWARE_VID_NUM_BUFFERS 1 /* * Defines the structure used to hold and pass video data to the host */ typedef struct { uint32 dataOffset; pointer data; } VMWAREVideoBuffer; typedef struct { uint32 size; uint32 offset; } VMWAREOffscreenRec, *VMWAREOffscreenPtr; /* * Trivial offscreen manager that allocates memory from the * bottom of the VRAM. */ static VMWAREOffscreenRec offscreenMgr; /* * structs that reside in fmt_priv. */ typedef struct { int pitches[3]; int offsets[3]; } VMWAREVideoFmtData; /* * Structure representing a specific video stream. */ struct VMWAREVideoRec { uint32 streamId; /* * Function prototype same as XvPutImage. */ int (*play)(ScrnInfoPtr, struct VMWAREVideoRec *, short, short, short, short, short, short, short, short, int, unsigned char*, short, short, RegionPtr, DrawablePtr); /* * Offscreen memory region used to pass video data to the host. */ VMWAREOffscreenPtr fbarea; VMWAREVideoBuffer bufs[VMWARE_VID_NUM_BUFFERS]; uint8 currBuf; uint32 size; uint32 colorKey; Bool isAutoPaintColorkey; uint32 flags; RegionRec clipBoxes; VMWAREVideoFmtData *fmt_priv; }; typedef struct VMWAREVideoRec VMWAREVideoRec; typedef VMWAREVideoRec *VMWAREVideoPtr; /* * Callback functions */ #if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1) static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int image, unsigned char *buf, short width, short height, Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr dst); #else static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int image, unsigned char *buf, short width, short height, Bool sync, RegionPtr clipBoxes, pointer data); #endif static void vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup); static int vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format, unsigned short *width, unsigned short *height, int *pitches, int *offsets); static int vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data); static int vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value, pointer data); static void vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, short vid_h, short drw_w, short drw_h, unsigned int *p_w, unsigned int *p_h, pointer data); /* * Local functions for video streams */ static XF86VideoAdaptorPtr vmwareVideoSetup(ScrnInfoPtr pScrn); static int vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, RegionPtr clipBoxes, DrawablePtr draw); static int vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, int format, unsigned short width, unsigned short height); static int vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, RegionPtr clipBoxes, DrawablePtr draw); static void vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId); static void vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId, uint32 regId, uint32 value); static void vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid); /* * Offscreen memory manager functions */ static void vmwareOffscreenInit(void); static VMWAREOffscreenPtr vmwareOffscreenAllocate(VMWAREPtr pVMWARE, uint32 size); static void vmwareOffscreenFree(VMWAREOffscreenPtr memptr); /* *----------------------------------------------------------------------------- * * vmwareCheckVideoSanity -- * * Ensures that on ModeSwitch the offscreen memory used * by the Xv streams doesn't become part of the guest framebuffer. * * Results: * None * * Side effects: * If it is found that the offscreen used by video streams lies * within the range of the framebuffer(after ModeSwitch) then the video * streams will be stopped. * *----------------------------------------------------------------------------- */ void vmwareCheckVideoSanity(ScrnInfoPtr pScrn) { VMWAREPtr pVMWARE = VMWAREPTR(pScrn); VMWAREVideoPtr pVid; if (offscreenMgr.size == 0 || offscreenMgr.offset > pVMWARE->FbSize) { return ; } pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS]; vmwareStopVideo(pScrn, pVid, TRUE); } /* *----------------------------------------------------------------------------- * * vmwareOffscreenInit -- * * Initializes the trivial Offscreen memory manager. * * Results: * None. * * Side effects: * Initializes the Offscreen manager meta-data structure. * *----------------------------------------------------------------------------- */ static void vmwareOffscreenInit(void) { offscreenMgr.size = 0; offscreenMgr.offset = 0; } /* *----------------------------------------------------------------------------- * * vmwareOffscreenAllocate -- * * Allocates offscreen memory. * Memory is allocated from the bottom part of the VRAM. * The memory manager is trivial iand can handle only 1 video-stream. * ---------- * | | * | FB | * | | * |--------- * | | * | | * |--------| * | Offscr | * |--------| * * VRAM * * Results: * Pointer to the allocated Offscreen memory. * * Side effects: * Updates the Offscreen memory manager meta-data structure. * *----------------------------------------------------------------------------- */ static VMWAREOffscreenPtr vmwareOffscreenAllocate(VMWAREPtr pVMWARE, uint32 size) { VMWAREOffscreenPtr memptr; if ((pVMWARE->videoRam - pVMWARE->FbSize - pVMWARE->fbPitch - 7) < size) { return NULL; } memptr = malloc(sizeof(VMWAREOffscreenRec)); if (!memptr) { return NULL; } memptr->size = size; memptr->offset = (pVMWARE->videoRam - size) & ~7; VmwareLog(("vmwareOffscreenAllocate: Offset:%x", memptr->offset)); offscreenMgr.size = memptr->size; offscreenMgr.offset = memptr->offset; return memptr; } /* *----------------------------------------------------------------------------- * * vmwareOffscreenFree -- * * Frees the allocated offscreen memory. * * Results: * None. * * Side effects: * Updates the Offscreen memory manager meta-data structure. * *----------------------------------------------------------------------------- */ static void vmwareOffscreenFree(VMWAREOffscreenPtr memptr) { if (memptr) { free(memptr); } offscreenMgr.size = 0; offscreenMgr.offset = 0; } /* *----------------------------------------------------------------------------- * * vmwareVideoEnabled -- * * Checks if Video FIFO and Escape FIFO cap are enabled. * * Results: * TRUE if required caps are enabled, FALSE otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool vmwareVideoEnabled(VMWAREPtr pVMWARE) { return ((pVMWARE->vmwareCapability & SVGA_CAP_EXTENDED_FIFO) && (pVMWARE->vmwareFIFO[SVGA_FIFO_CAPABILITIES] & (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE))); } /* *----------------------------------------------------------------------------- * * vmwareVideoInit -- * * Initializes Xv support. * * Results: * TRUE on success, FALSE on error. * * Side effects: * Xv support is initialized. Memory is allocated for all supported * video streams. * *----------------------------------------------------------------------------- */ Bool vmwareVideoInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL; XF86VideoAdaptorPtr newAdaptor = NULL; int numAdaptors; TRACEPOINT vmwareOffscreenInit(); numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors); newAdaptor = vmwareVideoSetup(pScrn); if (!newAdaptor) { VmwareLog(("Failed to initialize Xv extension \n")); return FALSE; } if (!numAdaptors) { numAdaptors = 1; overlayAdaptors = &newAdaptor; } else { newAdaptors = malloc((numAdaptors + 1) * sizeof(XF86VideoAdaptorPtr*)); if (!newAdaptors) { xf86XVFreeVideoAdaptorRec(newAdaptor); return FALSE; } memcpy(newAdaptors, overlayAdaptors, numAdaptors * sizeof(XF86VideoAdaptorPtr)); newAdaptors[numAdaptors++] = newAdaptor; overlayAdaptors = newAdaptors; } if (!xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors)) { VmwareLog(("Failed to initialize Xv extension\n")); xf86XVFreeVideoAdaptorRec(newAdaptor); return FALSE; } if (newAdaptors) { free(newAdaptors); } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initialized VMware Xv extension successfully.\n"); return TRUE; } /* *----------------------------------------------------------------------------- * * vmwareVideoEnd -- * * Unitializes video. * * Results: * None. * * Side effects: * pVMWARE->videoStreams = NULL * *----------------------------------------------------------------------------- */ void vmwareVideoEnd(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); VMWAREPtr pVMWARE = VMWAREPTR(pScrn); VMWAREVideoPtr pVid; int i; TRACEPOINT /* * Video streams are allocated after the DevUnion array * (see VideoSetup) */ pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS]; for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) { vmwareVideoEndStream(pScrn, &pVid[i]); REGION_UNINIT(pScreen, &pVid[i].clipBoxes); } free(pVMWARE->videoStreams); pVMWARE->videoStreams = NULL; } /* *----------------------------------------------------------------------------- * * vmwareVideoSetup -- * * Initializes a XF86VideoAdaptor structure with the capabilities and * functions supported by this video driver. * * Results: * On success initialized XF86VideoAdaptor struct or NULL on error * * Side effects: * None. * *----------------------------------------------------------------------------- */ static XF86VideoAdaptorPtr vmwareVideoSetup(ScrnInfoPtr pScrn) { VMWAREPtr pVMWARE = VMWAREPTR(pScrn); XF86VideoAdaptorPtr adaptor; VMWAREVideoPtr pPriv; DevUnion *du; int i; TRACEPOINT adaptor = xf86XVAllocateVideoAdaptorRec(pScrn); if (!adaptor) { VmwareLog(("Not enough memory\n")); return NULL; } du = calloc(1, VMWARE_VID_NUM_PORTS * (sizeof(DevUnion) + sizeof(VMWAREVideoRec))); if (!du) { VmwareLog(("Not enough memory.\n")); xf86XVFreeVideoAdaptorRec(adaptor); return NULL; } adaptor->type = XvInputMask | XvImageMask | XvWindowMask; adaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; adaptor->name = xv_adapt_name; adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS; adaptor->pEncodings = vmwareVideoEncodings; adaptor->nFormats = VMWARE_VID_NUM_FORMATS; adaptor->pFormats = vmwareVideoFormats; adaptor->nPorts = VMWARE_VID_NUM_PORTS; pPriv = (VMWAREVideoPtr) &du[VMWARE_VID_NUM_PORTS]; adaptor->pPortPrivates = du; for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) { pPriv[i].streamId = i; pPriv[i].play = vmwareVideoInitStream; pPriv[i].flags = SVGA_VIDEO_FLAG_COLORKEY; pPriv[i].colorKey = VMWARE_VIDEO_COLORKEY; pPriv[i].isAutoPaintColorkey = TRUE; REGION_NULL(pScreen, &pPriv[i].clipBoxes); adaptor->pPortPrivates[i].ptr = &pPriv[i]; } pVMWARE->videoStreams = du; adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES; adaptor->pAttributes = vmwareVideoAttributes; adaptor->nImages = VMWARE_VID_NUM_IMAGES; adaptor->pImages = vmwareVideoImages; adaptor->PutVideo = NULL; adaptor->PutStill = NULL; adaptor->GetVideo = NULL; adaptor->GetStill = NULL; adaptor->StopVideo = vmwareStopVideo; adaptor->SetPortAttribute = vmwareSetPortAttribute; adaptor->GetPortAttribute = vmwareGetPortAttribute; adaptor->QueryBestSize = vmwareQueryBestSize; adaptor->PutImage = vmwareXvPutImage; adaptor->QueryImageAttributes = vmwareQueryImageAttributes; return adaptor; } /* *----------------------------------------------------------------------------- * * vmwareVideoInitStream -- * * Initializes a video stream in response to the first PutImage() on a * video stream. The process goes as follows: * - Figure out characteristics according to format * - Allocate offscreen memory * - Pass on video to Play() functions * * Results: * Success or XvBadAlloc on failure. * * Side effects: * Video stream is initialized and its first frame sent to the host * (done by VideoPlay() function called at the end) * *----------------------------------------------------------------------------- */ static int vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, RegionPtr clipBoxes, DrawablePtr draw) { VMWAREPtr pVMWARE = VMWAREPTR(pScrn); int i; TRACEPOINT xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing Xv video-stream with id:%d format:%d\n", pVid->streamId, format); pVid->size = vmwareVideoInitAttributes(pScrn, pVid, format, width, height); if (pVid->size == -1) { VmwareLog(("Could not initialize 0x%x video stream\n", format)); return XvBadAlloc; } pVid->play = vmwareVideoPlay; pVid->fbarea = vmwareOffscreenAllocate(pVMWARE, pVid->size * VMWARE_VID_NUM_BUFFERS); if (!pVid->fbarea) { VmwareLog(("Could not allocate offscreen memory\n")); vmwareVideoEndStream(pScrn, pVid); return BadAlloc; } pVid->bufs[0].dataOffset = pVid->fbarea->offset; pVid->bufs[0].data = pVMWARE->FbBase + pVid->bufs[0].dataOffset; for (i = 1; i < VMWARE_VID_NUM_BUFFERS; ++i) { pVid->bufs[i].dataOffset = pVid->bufs[i-1].dataOffset + pVid->size; pVid->bufs[i].data = pVMWARE->FbBase + pVid->bufs[i].dataOffset; } pVid->currBuf = 0; REGION_COPY(pScrn->pScreen, &pVid->clipBoxes, clipBoxes); if (pVid->isAutoPaintColorkey) { BoxPtr boxes = REGION_RECTS(&pVid->clipBoxes); int nBoxes = REGION_NUM_RECTS(&pVid->clipBoxes); #if HAVE_FILLKEYHELPERDRAWABLE if (draw->type == DRAWABLE_WINDOW) { xf86XVFillKeyHelperDrawable(draw, pVid->colorKey, clipBoxes); DamageDamageRegion(draw, clipBoxes); } else { xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes); } #else xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes); #endif /** * Force update to paint the colorkey before the overlay flush. */ while(nBoxes--) vmwareSendSVGACmdUpdate(pVMWARE, boxes++); } VmwareLog(("Got offscreen region, offset %d, size %d " "(yuv size in bytes: %d)\n", pVid->fbarea->offset, pVid->fbarea->size, pVid->size)); return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, format, buf, width, height, clipBoxes, draw); } /* *----------------------------------------------------------------------------- * * vmwareVideoInitAttributes -- * * Fetches the format specific attributes using QueryImageAttributes(). * * Results: * size of the YUV frame on success and -1 on error. * * Side effects: * The video stream gets the format specific attributes(fmtData). * *----------------------------------------------------------------------------- */ static int vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, int format, unsigned short width, unsigned short height) { int size; VMWAREVideoFmtData *fmtData; TRACEPOINT fmtData = calloc(1, sizeof(VMWAREVideoFmtData)); if (!fmtData) { return -1; } size = vmwareQueryImageAttributes(pScrn, format, &width, &height, fmtData->pitches, fmtData->offsets); if (size == -1) { free(fmtData); return -1; } pVid->fmt_priv = fmtData; return size; } /* *----------------------------------------------------------------------------- * * vmwareVideoPlay -- * * Sends all the attributes associated with the video frame using the * FIFO ESCAPE mechanism to the host. * * Results: * Always returns Success. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, RegionPtr clipBoxes, DrawablePtr draw) { VMWAREPtr pVMWARE = VMWAREPTR(pScrn); uint32 *fifoItem; int i, regId; struct PACKED _item { uint32 regId; uint32 value; }; struct PACKED _body { uint32 escape; uint32 streamId; /* Old hosts can not handle more then these regs */ struct _item items[SVGA_VIDEO_DATA_GMRID]; }; struct PACKED _cmdSetRegs { uint32 cmd; uint32 nsid; uint32 size; struct _body body; }; struct _cmdSetRegs cmdSetRegs; struct _item *items; int size; VMWAREVideoFmtData *fmtData; unsigned short w, h; w = width; h = height; fmtData = pVid->fmt_priv; size = vmwareQueryImageAttributes(pScrn, format, &w, &h, fmtData->pitches, fmtData->offsets); if (size > pVid->size) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Increase in size of Xv video " "frame streamId:%d.\n", pVid->streamId); vmwareStopVideo(pScrn, pVid, TRUE); return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, format, buf, width, height, clipBoxes, draw); } pVid->size = size; memcpy(pVid->bufs[pVid->currBuf].data, buf, pVid->size); cmdSetRegs.cmd = SVGA_CMD_ESCAPE; cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE; cmdSetRegs.size = sizeof(cmdSetRegs.body); cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; cmdSetRegs.body.streamId = pVid->streamId; items = cmdSetRegs.body.items; for (i = SVGA_VIDEO_ENABLED; i < SVGA_VIDEO_DATA_GMRID; i++) { items[i].regId = i; } items[SVGA_VIDEO_ENABLED].value = TRUE; items[SVGA_VIDEO_DATA_OFFSET].value = pVid->bufs[pVid->currBuf].dataOffset; items[SVGA_VIDEO_SIZE].value = pVid->size; items[SVGA_VIDEO_FORMAT].value = format; items[SVGA_VIDEO_WIDTH].value = w; items[SVGA_VIDEO_HEIGHT].value = h; items[SVGA_VIDEO_SRC_X].value = src_x; items[SVGA_VIDEO_SRC_Y].value = src_y; items[SVGA_VIDEO_SRC_WIDTH].value = src_w; items[SVGA_VIDEO_SRC_HEIGHT].value = src_h; items[SVGA_VIDEO_DST_X].value = drw_x; items[SVGA_VIDEO_DST_Y].value = drw_y; items[SVGA_VIDEO_DST_WIDTH]. value = drw_w; items[SVGA_VIDEO_DST_HEIGHT].value = drw_h; items[SVGA_VIDEO_COLORKEY].value = pVid->colorKey; items[SVGA_VIDEO_FLAGS].value = pVid->flags; for (i = 0, regId = SVGA_VIDEO_PITCH_1; i < 3; i++, regId++) { items[regId].value = fmtData->pitches[i]; } fifoItem = (uint32 *) &cmdSetRegs; for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) { vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]); } /* * Update the clipList and paint the colorkey, if required. */ if (!vmwareIsRegionEqual(&pVid->clipBoxes, clipBoxes)) { REGION_COPY(pScrn->pScreen, &pVid->clipBoxes, clipBoxes); if (pVid->isAutoPaintColorkey) { BoxPtr boxes = REGION_RECTS(&pVid->clipBoxes); int nBoxes = REGION_NUM_RECTS(&pVid->clipBoxes); #if HAVE_FILLKEYHELPERDRAWABLE xf86XVFillKeyHelperDrawable(draw, pVid->colorKey, clipBoxes); #else xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes); #endif /** * Force update to paint the colorkey before the overlay flush. */ while(nBoxes--) vmwareSendSVGACmdUpdate(pVMWARE, boxes++); } } vmwareVideoFlush(pVMWARE, pVid->streamId); pVid->currBuf = ++pVid->currBuf & (VMWARE_VID_NUM_BUFFERS - 1); return Success; } /* *----------------------------------------------------------------------------- * * vmwareVideoFlush -- * * Sends the VIDEO_FLUSH command (FIFO ESCAPE mechanism) asking the host * to play the video stream or end it. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId) { struct PACKED _body { uint32 escape; uint32 streamId; }; struct PACKED _cmdFlush { uint32 cmd; uint32 nsid; uint32 size; struct _body body; }; struct _cmdFlush cmdFlush; uint32 *fifoItem; int i; cmdFlush.cmd = SVGA_CMD_ESCAPE; cmdFlush.nsid = SVGA_ESCAPE_NSID_VMWARE; cmdFlush.size = sizeof(cmdFlush.body); cmdFlush.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH; cmdFlush.body.streamId = streamId; fifoItem = (uint32 *) &cmdFlush; for (i = 0; i < sizeof(cmdFlush) / sizeof(uint32); i++) { vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]); } } /* *----------------------------------------------------------------------------- * * vmwareVideoSetOneReg -- * * Sets one video register using the FIFO ESCAPE mechanidm. * * Results: * None. * * Side effects: * None. *----------------------------------------------------------------------------- */ static void vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId, uint32 regId, uint32 value) { struct PACKED _item { uint32 regId; uint32 value; }; struct PACKED _body { uint32 escape; uint32 streamId; struct _item item; }; struct PACKED _cmdSetRegs { uint32 cmd; uint32 nsid; uint32 size; struct _body body; }; struct _cmdSetRegs cmdSetRegs; int i; uint32 *fifoItem; cmdSetRegs.cmd = SVGA_CMD_ESCAPE; cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE; cmdSetRegs.size = sizeof(cmdSetRegs.body); cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS; cmdSetRegs.body.streamId = streamId; cmdSetRegs.body.item.regId = regId; cmdSetRegs.body.item.value = value; fifoItem = (uint32 *) &cmdSetRegs; for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) { vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]); } } /* *----------------------------------------------------------------------------- * * vmwareVideoEndStream -- * * Frees up all resources (if any) taken by a video stream. * * Results: * None. * * Side effects: * Same as above. * *----------------------------------------------------------------------------- */ static void vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid) { uint32 id, colorKey, flags; Bool isAutoPaintColorkey; if (pVid->fmt_priv) { free(pVid->fmt_priv); } if (pVid->fbarea) { vmwareOffscreenFree(pVid->fbarea); pVid->fbarea = NULL; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Terminating Xv video-stream id:%d\n", pVid->streamId); /* * reset stream for next video */ id = pVid->streamId; colorKey = pVid->colorKey; flags = pVid->flags; isAutoPaintColorkey = pVid->isAutoPaintColorkey; memset(pVid, 0, sizeof(*pVid)); pVid->streamId = id; pVid->play = vmwareVideoInitStream; pVid->colorKey = colorKey; pVid->flags = flags; pVid->isAutoPaintColorkey = isAutoPaintColorkey; } /* *----------------------------------------------------------------------------- * * vmwareXvPutImage -- * * Main video playback function. It copies the passed data which is in * the specified format (e.g. FOURCC_YV12) into the overlay. * * If sync is TRUE the driver should not return from this * function until it is through reading the data from buf. * * There are two function prototypes to cope with the API change in X.org * 7.1 * * Results: * Success or XvBadAlloc on failure * * Side effects: * Video stream will be played(initialized if 1st frame) on success * or will fail on error. * *----------------------------------------------------------------------------- */ #if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1) static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, Bool sync, RegionPtr clipBoxes, pointer data, DrawablePtr dst) #else static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x, short drw_y, short src_w, short src_h, short drw_w, short drw_h, int format, unsigned char *buf, short width, short height, Bool sync, RegionPtr clipBoxes, pointer data) #endif { VMWAREPtr pVMWARE = VMWAREPTR(pScrn); VMWAREVideoPtr pVid = data; TRACEPOINT if (!vmwareVideoEnabled(pVMWARE)) { return XvBadAlloc; } #if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1) return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, format, buf, width, height, clipBoxes, dst); #else return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h, drw_w, drw_h, format, buf, width, height, clipBoxes, NULL); #endif } /* *----------------------------------------------------------------------------- * * vmwareStopVideo -- * * Called when we should stop playing video for a particular stream. If * Cleanup is FALSE, the "stop" operation is only temporary, and thus we * don't do anything. If Cleanup is TRUE we kill the video stream by * sending a message to the host and freeing up the stream. * * Results: * None. * * Side effects: * See above. * *----------------------------------------------------------------------------- */ static void vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup) { VMWAREVideoPtr pVid = data; VMWAREPtr pVMWARE = VMWAREPTR(pScrn); TRACEPOINT if (!vmwareVideoEnabled(pVMWARE)) { return; } REGION_EMPTY(pScrn->pScreen, &pVid->clipBoxes); if (!Cleanup) { VmwareLog(("vmwareStopVideo: Cleanup is FALSE.\n")); return; } vmwareVideoSetOneReg(pVMWARE, pVid->streamId, SVGA_VIDEO_ENABLED, FALSE); vmwareVideoFlush(pVMWARE, pVid->streamId); vmwareVideoEndStream(pScrn, pVid); } /* *----------------------------------------------------------------------------- * * vmwareQueryImageAttributes -- * * From the spec: This function is called to let the driver specify how data * for a particular image of size width by height should be stored. * Sometimes only the size and corrected width and height are needed. In * that case pitches and offsets are NULL. * * Results: * The size of the memory required for the image, or -1 on error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format, unsigned short *width, unsigned short *height, int *pitches, int *offsets) { INT32 size, tmp; TRACEPOINT if (*width > VMWARE_VID_MAX_WIDTH) { *width = VMWARE_VID_MAX_WIDTH; } if (*height > VMWARE_VID_MAX_HEIGHT) { *height = VMWARE_VID_MAX_HEIGHT; } *width = (*width + 1) & ~1; if (offsets != NULL) { offsets[0] = 0; } switch (format) { case FOURCC_YV12: *height = (*height + 1) & ~1; size = (*width + 3) & ~3; if (pitches) { pitches[0] = size; } size *= *height; if (offsets) { offsets[1] = size; } tmp = ((*width >> 1) + 3) & ~3; if (pitches) { pitches[1] = pitches[2] = tmp; } tmp *= (*height >> 1); size += tmp; if (offsets) { offsets[2] = size; } size += tmp; break; case FOURCC_UYVY: case FOURCC_YUY2: size = *width * 2; if (pitches) { pitches[0] = size; } size *= *height; break; default: VmwareLog(("Query for invalid video format %d\n", format)); return -1; } return size; } /* *----------------------------------------------------------------------------- * * vmwareSetPortAttribute -- * * From the spec: A port may have particular attributes such as colorKey, hue, * saturation, brightness or contrast. Xv clients set these * attribute values by sending attribute strings (Atoms) to the server. * * Results: * Success if the attribute exists and XvBadAlloc otherwise. * * Side effects: * The respective attribute gets the new value. * *----------------------------------------------------------------------------- */ static int vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value, pointer data) { VMWAREVideoPtr pVid = (VMWAREVideoPtr) data; Atom xvColorKey = MAKE_ATOM("XV_COLORKEY"); Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); if (attribute == xvColorKey) { VmwareLog(("Set colorkey:0x%x\n", value)); pVid->colorKey = value; } else if (attribute == xvAutoPaint) { VmwareLog(("Set autoPaint: %s\n", value? "TRUE": "FALSE")); pVid->isAutoPaintColorkey = value; } else { return XvBadAlloc; } return Success; } /* *----------------------------------------------------------------------------- * * vmwareGetPortAttribute -- * * From the spec: A port may have particular attributes such as hue, * saturation, brightness or contrast. Xv clients get these * attribute values by sending attribute strings (Atoms) to the server * * Results: * Success if the attribute exists and XvBadAlloc otherwise. * * Side effects: * "value" contains the requested attribute on success. * *----------------------------------------------------------------------------- */ static int vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value, pointer data) { VMWAREVideoPtr pVid = (VMWAREVideoPtr) data; Atom xvColorKey = MAKE_ATOM("XV_COLORKEY"); Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY"); if (attribute == xvColorKey) { *value = pVid->colorKey; } else if (attribute == xvAutoPaint) { *value = pVid->isAutoPaintColorkey; } else { return XvBadAlloc; } return Success; } /* *----------------------------------------------------------------------------- * * vmwareQueryBestSize -- * * From the spec: QueryBestSize provides the client with a way to query what * the destination dimensions would end up being if they were to request * that an area vid_w by vid_h from the video stream be scaled to rectangle * of drw_w by drw_h on the screen. Since it is not expected that all * hardware will be able to get the target dimensions exactly, it is * important that the driver provide this function. * * This function seems to never be called, but to be on the safe side * we apply the same logic that QueryImageAttributes has for width * and height * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static void vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion, short vid_w, short vid_h, short drw_w, short drw_h, unsigned int *p_w, unsigned int *p_h, pointer data) { *p_w = (drw_w + 1) & ~1; *p_h = drw_h; return; }