summaryrefslogtreecommitdiff
path: root/src/vmwarevideo.c
diff options
context:
space:
mode:
authorBankim Bhavsar <bbhavsar@vmware.com>2008-01-23 22:13:07 -0800
committerVinay Bondhugula <vinayb@vmware.com>2008-01-23 22:13:07 -0800
commitbfd8398dde2d2de238c600eece9374d24d7d8549 (patch)
tree1c2cf0cdcf0713289a94eefb246eaea8a1eaff40 /src/vmwarevideo.c
parenta33ab73ffa5d3797d16c3a265ddefc56a5a93b6b (diff)
Xv extension for VMware's video driver
This patch implements the Xv extension for VMware's X video driver. The Xv specification can be found here http://www.xfree86.org/current/DESIGN16.html I've written a trivial offscreen memory manager that allocates memory from the bottom part of the Video RAM and it can handle only 1 video-stream. Eventually we intend to support upto 32 video-streams (there is already support for multiple video streams in respective backends).
Diffstat (limited to 'src/vmwarevideo.c')
-rw-r--r--src/vmwarevideo.c1218
1 files changed, 1218 insertions, 0 deletions
diff --git a/src/vmwarevideo.c b/src/vmwarevideo.c
new file mode 100644
index 0000000..6c081c8
--- /dev/null
+++ b/src/vmwarevideo.c
@@ -0,0 +1,1218 @@
+/*
+ * 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 "xf86xv.h"
+#include "fourcc.h"
+#include "svga_escape.h"
+#include "svga_overlay.h"
+
+#include <X11/extensions/Xv.h>
+/*
+ * Need this to figure out which prototype to use for XvPutImage
+ */
+#include "xorgVersion.h"
+
+#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 green as the default colorKey
+ */
+#define VMWARE_VIDEO_COLORKEY 0x00ff00
+
+/*
+ * 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",
+ 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 2
+static XF86ImageRec vmwareVideoImages[] =
+{
+ XVIMAGE_YV12,
+ XVIMAGE_YUY2
+};
+
+#define VMWARE_VID_NUM_ATTRIBUTES 1
+static XF86AttributeRec vmwareVideoAttributes[] =
+{
+ {
+ XvGettable | XvSettable,
+ 0x000000,
+ 0xffffff,
+ "XV_COLORKEY"
+ }
+};
+
+/*
+ * 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);
+ /*
+ * 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;
+ uint32 flags;
+ VMWAREVideoFmtData *fmt_priv;
+};
+
+typedef struct VMWAREVideoRec VMWAREVideoRec;
+typedef VMWAREVideoRec *VMWAREVideoPtr;
+
+/*
+ * Callback functions
+ */
+#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(7, 0, 0, 0, 0) || XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(4, 0, 0, 0, 0)
+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);
+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);
+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();
+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()
+{
+ 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 = xalloc(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 = infoFromScreen(pScreen);
+ VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+ 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 = xalloc((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) {
+ xfree(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 = infoFromScreen(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]);
+ }
+
+ 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 = xcalloc(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 = "VMware Video Engine";
+ 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;
+ 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)
+{
+ VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ 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;
+
+ 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);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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 = xcalloc(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)
+{
+ VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
+ uint32 *fifoItem;
+ int i, regId;
+ struct PACKED _item {
+ uint32 regId;
+ uint32 value;
+ };
+
+ struct PACKED _body {
+ uint32 escape;
+ uint32 streamId;
+ struct _item items[SVGA_VIDEO_NUM_REGS];
+ };
+
+ struct PACKED _cmdSetRegs {
+ uint32 cmd;
+ uint32 nsid;
+ uint32 size;
+ struct _body body;
+ };
+
+ struct _cmdSetRegs cmdSetRegs;
+
+ 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;
+
+ for (i = SVGA_VIDEO_ENABLED; i < SVGA_VIDEO_NUM_REGS; i++) {
+ cmdSetRegs.body.items[i].regId = i;
+ }
+
+ cmdSetRegs.body.items[SVGA_VIDEO_ENABLED].value = TRUE;
+ cmdSetRegs.body.items[SVGA_VIDEO_DATA_OFFSET].value =
+ pVid->bufs[pVid->currBuf].dataOffset;
+ cmdSetRegs.body.items[SVGA_VIDEO_SIZE].value = pVid->size;
+ cmdSetRegs.body.items[SVGA_VIDEO_FORMAT].value = format;
+ cmdSetRegs.body.items[SVGA_VIDEO_X].value = drw_x;
+ cmdSetRegs.body.items[SVGA_VIDEO_Y].value = drw_y;
+ cmdSetRegs.body.items[SVGA_VIDEO_SRC_WIDTH].value = width;
+ cmdSetRegs.body.items[SVGA_VIDEO_SRC_HEIGHT].value = height;
+ cmdSetRegs.body.items[SVGA_VIDEO_DST_WIDTH]. value = drw_w;
+ cmdSetRegs.body.items[SVGA_VIDEO_DST_HEIGHT].value = drw_h;
+ cmdSetRegs.body.items[SVGA_VIDEO_COLORKEY].value = pVid->colorKey;
+ cmdSetRegs.body.items[SVGA_VIDEO_FLAGS].value = pVid->flags;
+
+ for (i = 0, regId = SVGA_VIDEO_PITCH_1; i < 3; i++, regId++) {
+ cmdSetRegs.body.items[regId].value = pVid->fmt_priv->pitches[i];
+ }
+
+ fifoItem = (uint32 *) &cmdSetRegs;
+ for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) {
+ vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
+ }
+
+ 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;
+
+ 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;
+ memset(pVid, 0, sizeof(*pVid));
+ pVid->streamId = id;
+ pVid->play = vmwareVideoInitStream;
+ pVid->colorKey = colorKey;
+ pVid->flags = flags;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * XXX: src_x, src_y, src_w and src_h are used to denote that only
+ * part of the source image is to be displayed. We ignore as didn't
+ * find applications that use them.
+ *
+ * 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 XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(7, 0, 0, 0, 0) || XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(4, 0, 0, 0, 0)
+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;
+ }
+
+ 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);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+ }
+ if (!Cleanup) {
+ 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_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");
+
+ if (attribute == xvColorKey) {
+ pVid->colorKey = 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");
+
+ if (attribute == xvColorKey) {
+ *value = pVid->colorKey;
+ } 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;
+}
+