Xv extension for VMware's video driver
authorBankim Bhavsar <bbhavsar@vmware.com>
Thu, 24 Jan 2008 06:13:07 +0000 (22:13 -0800)
committerVinay Bondhugula <vinayb@vmware.com>
Thu, 24 Jan 2008 06:13:07 +0000 (22:13 -0800)
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).

README
configure.ac
src/Makefile.am
src/svga_escape.h [new file with mode: 0644]
src/svga_overlay.h [new file with mode: 0644]
src/svga_reg.h
src/vmware.c
src/vmware.h
src/vmwarevideo.c [new file with mode: 0644]

diff --git a/README b/README
index 564d57b..0ddbbac 100644 (file)
--- a/README
+++ b/README
@@ -23,6 +23,12 @@ svga_limits.h
 svga_modes.h
     A list of default display modes that are built into the driver.
 
+svga_overlay.h
+   A list of definitions required for Xv extension support. Included by vmwarevideo.c
+
+svga_escape.h
+   A list of definitions for the SVGA Escape commands.
+
 guest_os.h
     Values for the GUEST_ID register.
 
@@ -262,6 +268,7 @@ table shows which capability indicates support for which command.
     SVGA_CMD_DEFINE_ALPHA_CURSOR       SVGA_CAP_ALPHA_CURSOR
     SVGA_CMD_DRAW_GLYPH                 SVGA_CAP_GLYPH
     SVGA_CMD_DRAW_GLYPH_CLIPPED         SVGA_CAP_GLYPH_CLIPPING
+    SVGA_CMD_ESCAPE                     SVGA_FIFO_CAP_ESCAPE
 
 Note:  SVGA_CMD_DISPLAY_CURSOR and SVGA_CMD_MOVE_CURSOR should not be used.
 Drivers wishing hardware cursor support should use cursor bypass (see below).
index f33841b..91b01dc 100644 (file)
@@ -52,6 +52,7 @@ XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
 XORG_DRIVER_CHECK_EXT(DPMSExtension, xextproto)
 XORG_DRIVER_CHECK_EXT(XINERAMA, xineramaproto)
+XORG_DRIVER_CHECK_EXT(XV, videoproto)
 
 # Checks for pkg-config packages
 PKG_CHECK_MODULES(XORG, [xorg-server >= 1.0.99.901 xproto fontsproto $REQUIRED_MODULES])
index d6000fc..0cd746d 100644 (file)
@@ -45,4 +45,6 @@ vmware_drv_la_SOURCES = \
          vmwarectrl.c \
          vmwarectrl.h \
          vmwarectrlproto.h \
-         vmwarexinerama.c
+         vmwarexinerama.c \
+         vmwarevideo.c
+
diff --git a/src/svga_escape.h b/src/svga_escape.h
new file mode 100644 (file)
index 0000000..c9e7b23
--- /dev/null
@@ -0,0 +1,30 @@
+/* **********************************************************
+ * Copyright 2007 VMware, Inc.  All rights reserved.
+ * **********************************************************/
+
+/*
+ * svga_escape.h --
+ *
+ *    Definitions for our own (vendor-specific) SVGA Escape commands.
+ */
+
+#ifndef _SVGA_ESCAPE_H_
+#define _SVGA_ESCAPE_H_
+
+/*
+ * Namespace IDs for the escape command
+ */
+
+#define SVGA_ESCAPE_NSID_VMWARE 0x00000000
+#define SVGA_ESCAPE_NSID_DEVEL  0xFFFFFFFF
+
+/*
+ * Within SVGA_ESCAPE_NSID_VMWARE, we multiplex commands according to
+ * the first DWORD of escape data (after the nsID and size). As a
+ * guideline we're using the high word and low word as a major and
+ * minor command number, respectively.
+ */
+
+#define SVGA_ESCAPE_VMWARE_MAJOR_MASK  0xFFFF0000
+
+#endif /* _SVGA_ESCAPE_H_ */
diff --git a/src/svga_overlay.h b/src/svga_overlay.h
new file mode 100644 (file)
index 0000000..58f71e4
--- /dev/null
@@ -0,0 +1,49 @@
+/* **********************************************************
+ * Copyright 2007 VMware, Inc.  All rights reserved.
+ * **********************************************************/
+
+/*
+ * svga_overlay.h --
+ *
+ *    Definitions for video-overlay support.
+ */
+
+#ifndef _SVGA_OVERLAY_H_
+#define _SVGA_OVERLAY_H_
+
+/*
+ * Video formats we support
+ */
+
+#define VMWARE_FOURCC_YV12 0x32315659 // 'Y' 'V' '1' '2'
+#define VMWARE_FOURCC_YUY2 0x32595559 // 'Y' 'U' 'Y' '2'
+
+#define SVGA_ESCAPE_VMWARE_VIDEO             0x00020000
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS    0x00020001
+        /* FIFO escape layout:
+         * Type, Stream Id, (Register Id, Value) pairs */
+
+#define SVGA_ESCAPE_VMWARE_VIDEO_FLUSH       0x00020002
+        /* FIFO escape layout:
+         * Type, Stream Id */
+
+typedef struct SVGAEscapeVideoSetRegs {
+   struct {
+      uint32 cmdType;
+      uint32 streamId;
+   } header;
+
+   // May include zero or more items.
+   struct {
+      uint32 registerId;
+      uint32 value;
+   } items[1];
+} SVGAEscapeVideoSetRegs;
+
+typedef struct SVGAEscapeVideoFlush {
+   uint32 cmdType;
+   uint32 streamId;
+} SVGAEscapeVideoFlush;
+
+#endif // _SVGA_OVERLAY_H_
index 871a8ff..4560fe7 100644 (file)
@@ -1,7 +1,5 @@
 /* **********************************************************
- * Copyright (C) 1998-2001 VMware, Inc.
- * All Rights Reserved
- * $Id$
+ * Copyright 1998 VMware, Inc.  All rights reserved.
  * **********************************************************/
 
 /*
@@ -9,13 +7,13 @@
  *
  * SVGA hardware definitions
  */
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/vmware/svga_reg.h,v 1.7 2002/12/10 04:17:19 dawes Exp $ */
 
 #ifndef _SVGA_REG_H_
 #define _SVGA_REG_H_
 
 #define INCLUDE_ALLOW_USERLEVEL
 #define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMCORE
 #include "includeCheck.h"
 
 /*
 #define SVGA_MAX_HEIGHT                        1770
 #define SVGA_MAX_BITS_PER_PIXEL                32
 #define SVGA_MAX_DEPTH                  24
+#define SVGA_MAX_DISPLAYS               10
 
+/*
+ * The maximum size of the onscreen framebuffer.  The size of the
+ * changeMap in the monitor is proportional to this number since it's
+ * the amount of memory we need to trace in VESA mode.  Therefore, we'd
+ * like to keep it as small as possible to reduce monitor overhead (using
+ * SVGA_VRAM_MAX_SIZE for this increases the size of the shared area
+ * by over 4k!).
+ */
 #define SVGA_FB_MAX_SIZE \
    ((((SVGA_MAX_WIDTH * SVGA_MAX_HEIGHT *                                    \
        SVGA_MAX_BITS_PER_PIXEL / 8) >> PAGE_SHIFT) + 1) << PAGE_SHIFT)
 #define SVGA_VALUE_PORT                0x1
 #define SVGA_BIOS_PORT         0x2
 #define SVGA_NUM_PORTS         0x3
+#define SVGA_IRQSTATUS_PORT    0x8
+
+/*
+ * Interrupt source flags for IRQSTATUS_PORT and IRQMASK.
+ *
+ * Interrupts are only supported when the
+ * SVGA_CAP_IRQMASK capability is present.
+ */
+#define SVGA_IRQFLAG_ANY_FENCE            0x1    /* Any fence was passed */
+#define SVGA_IRQFLAG_FIFO_PROGRESS        0x2    /* Made forward progress in the FIFO */
+#define SVGA_IRQFLAG_FENCE_GOAL           0x4    /* SVGA_FIFO_FENCE_GOAL reached */
 
 /* This port is deprecated, but retained because of old drivers. */
 #define SVGA_LEGACY_ACCEL_PORT 0x3
@@ -106,8 +125,8 @@ enum {
    SVGA_REG_MEM_START = 18,       /* Memory for command FIFO and bitmaps */
    SVGA_REG_MEM_SIZE = 19,
    SVGA_REG_CONFIG_DONE = 20,      /* Set when memory area configured */
-   SVGA_REG_SYNC = 21,             /* Write to force synchronization */
-   SVGA_REG_BUSY = 22,             /* Read to check if sync is done */
+   SVGA_REG_SYNC = 21,             /* See "FIFO Synchronization Registers" */
+   SVGA_REG_BUSY = 22,             /* See "FIFO Synchronization Registers" */
    SVGA_REG_GUEST_ID = 23,        /* Set guest OS identifier */
    SVGA_REG_CURSOR_ID = 24,       /* ID of cursor */
    SVGA_REG_CURSOR_X = 25,        /* Set cursor X position */
@@ -118,7 +137,8 @@ enum {
    SVGA_REG_MEM_REGS = 30,         /* Number of FIFO registers */
    SVGA_REG_NUM_DISPLAYS = 31,     /* Number of guest displays */
    SVGA_REG_PITCHLOCK = 32,        /* Fixed pitch for all modes */
-   SVGA_REG_TOP = 33,             /* Must be 1 more than the last register */
+   SVGA_REG_IRQMASK = 33,          /* Interrupt mask */
+   SVGA_REG_TOP = 34,             /* Must be 1 more than the last register */
 
    SVGA_PALETTE_BASE = 1024,      /* Base of SVGA color map */
    /* Next 768 (== 256*3) registers exist for colormap */
@@ -153,6 +173,7 @@ enum {
 #define SVGA_CAP_EXTENDED_FIFO      0x08000
 #define SVGA_CAP_MULTIMON           0x10000
 #define SVGA_CAP_PITCHLOCK          0x20000
+#define SVGA_CAP_IRQMASK            0x40000
 
 /*
  *  Raster op codes (same encoding as X) used by FIFO drivers.
@@ -247,12 +268,24 @@ enum {
 
 
 /*
- *  FIFO offsets (viewed as an array of 32-bit words)
+ * FIFO register indices.
+ *
+ * The FIFO is a chunk of device memory mapped into guest physmem.  It
+ * is always treated as 32-bit words.
+ *
+ * The guest driver gets to decide how to partition it between
+ * - FIFO registers (there are always at least 4, specifying where the
+ *   following data area is and how much data it contains; there may be
+ *   more registers following these, depending on the FIFO protocol
+ *   version in use)
+ * - FIFO data, written by the guest and slurped out by the VMX.
+ * These indices are 32-bit word offsets into the FIFO.
  */
 
 enum {
    /*
-    * The original defined FIFO offsets
+    * Block 1 (basic registers): The originally defined FIFO registers.
+    * These exist and are valid for all versions of the FIFO protocol.
     */
 
    SVGA_FIFO_MIN = 0,
@@ -261,35 +294,244 @@ enum {
    SVGA_FIFO_STOP,
 
    /*
-    * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
+    * Block 2 (extended registers): Mandatory registers for the extended
+    * FIFO.  These exist if the SVGA caps register includes
+    * SVGA_CAP_EXTENDED_FIFO; some of them are valid only if their
+    * associated capability bit is enabled.
+    *
+    * Note that when originally defined, SVGA_CAP_EXTENDED_FIFO implied
+    * support only for (FIFO registers) CAPABILITIES, FLAGS, and FENCE.
+    * This means that the guest has to test individually (in most cases
+    * using FIFO caps) for the presence of registers after this; the VMX
+    * can define "extended FIFO" to mean whatever it wants, and currently
+    * won't enable it unless there's room for that set and much more.
     */
 
    SVGA_FIFO_CAPABILITIES = 4,
    SVGA_FIFO_FLAGS,
+   // Valid with SVGA_FIFO_CAP_FENCE:
    SVGA_FIFO_FENCE,
-   SVGA_FIFO_3D_HWVERSION,     /* Check SVGA3dHardwareVersion in svga3d_reg.h */
+
+   /*
+    * Block 3a (optional extended registers): Additional registers for the
+    * extended FIFO, whose presence isn't actually implied by
+    * SVGA_CAP_EXTENDED_FIFO; these exist if SVGA_FIFO_MIN is high enough to
+    * leave room for them.
+    *
+    * These in block 3a, the VMX currently considers mandatory for the
+    * extended FIFO.
+    */
+   
+   // Valid if exists (i.e. if extended FIFO enabled):
+   SVGA_FIFO_3D_HWVERSION,       /* See SVGA3dHardwareVersion in svga3d_reg.h */
+   // Valid with SVGA_FIFO_CAP_PITCHLOCK:
    SVGA_FIFO_PITCHLOCK,
+   // Valid with SVGA_FIFO_CAP_CURSOR_BYPASS_3:
+   SVGA_FIFO_CURSOR_ON,          /* Cursor bypass 3 show/hide register */
+   SVGA_FIFO_CURSOR_X,           /* Cursor bypass 3 x register */
+   SVGA_FIFO_CURSOR_Y,           /* Cursor bypass 3 y register */
+   SVGA_FIFO_CURSOR_COUNT,       /* Incremented when any of the other 3 change */
+   SVGA_FIFO_CURSOR_LAST_UPDATED,/* Last time the host updated the cursor */
+   // Valid with SVGA_FIFO_CAP_RESERVE:
+   SVGA_FIFO_RESERVED,           /* Bytes past NEXT_CMD with real contents */
+   /*
+    * XXX: The gap here, up until SVGA_FIFO_3D_CAPS, can be used for new
+    * registers, but this must be done carefully and with judicious use of
+    * capability bits, since comparisons based on SVGA_FIFO_MIN aren't
+    * enough to tell you whether the register exists: we've shipped drivers
+    * and products that used SVGA_FIFO_3D_CAPS but didn't know about some of
+    * the earlier ones.  The actual order of introduction was:
+    * - PITCHLOCK
+    * - 3D_CAPS
+    * - CURSOR_* (cursor bypass 3)
+    * - RESERVED
+    * So, code that wants to know whether it can use any of the
+    * aforementioned registers, or anything else added after PITCHLOCK and
+    * before 3D_CAPS, needs to reason about something other than
+    * SVGA_FIFO_MIN.
+    */
+   /*
+    * 3D caps block space; valid with 3D hardware version >=
+    * SVGA3D_HWVERSION_WS6_B1.
+    */
+   SVGA_FIFO_3D_CAPS      = 32,
+   SVGA_FIFO_3D_CAPS_LAST = 32 + 255,
 
    /*
-    * Always keep this last.  It's not an offset with semantic value, but
-    * rather a convenient way to produce the value of fifo[SVGA_FIFO_NUM_REGS]
+    * End of VMX's current definition of "extended-FIFO registers".
+    * Registers before here are always enabled/disabled as a block; either
+    * the extended FIFO is enabled and includes all preceding registers, or
+    * it's disabled entirely.
+    *
+    * Block 3b (truly optional extended registers): Additional registers for
+    * the extended FIFO, which the VMX already knows how to enable and
+    * disable with correct granularity.
+    *
+    * Registers after here exist if and only if the guest SVGA driver
+    * sets SVGA_FIFO_MIN high enough to leave room for them.
     */
 
-   SVGA_FIFO_NUM_REGS
+   // Valid if register exists:
+   SVGA_FIFO_GUEST_3D_HWVERSION, /* Guest driver's 3D version */
+   SVGA_FIFO_FENCE_GOAL,         /* Matching target for SVGA_IRQFLAG_FENCE_GOAL */
+   SVGA_FIFO_BUSY,               /* See "FIFO Synchronization Registers" */
+
+   /*
+    * Always keep this last.  This defines the maximum number of
+    * registers we know about.  At power-on, this value is placed in
+    * the SVGA_REG_MEM_REGS register, and we expect the guest driver
+    * to allocate this much space in FIFO memory for registers.
+    */
+    SVGA_FIFO_NUM_REGS
 };
 
+
+/*
+ * Definition of registers included in extended FIFO support.
+ *
+ * The guest SVGA driver gets to allocate the FIFO between registers
+ * and data.  It must always allocate at least 4 registers, but old
+ * drivers stopped there.
+ *
+ * The VMX will enable extended FIFO support if and only if the guest
+ * left enough room for all registers defined as part of the mandatory
+ * set for the extended FIFO.
+ *
+ * Note that the guest drivers typically allocate the FIFO only at
+ * initialization time, not at mode switches, so it's likely that the
+ * number of FIFO registers won't change without a reboot.
+ *
+ * All registers less than this value are guaranteed to be present if
+ * svgaUser->fifo.extended is set. Any later registers must be tested
+ * individually for compatibility at each use (in the VMX).
+ *
+ * This value is used only by the VMX, so it can change without
+ * affecting driver compatibility; keep it that way?
+ */
+#define SVGA_FIFO_EXTENDED_MANDATORY_REGS  (SVGA_FIFO_3D_CAPS_LAST + 1)
+
+
+/*
+ * FIFO Synchronization Registers
+ *
+ *  This explains the relationship between the various FIFO
+ *  sync-related registers in IOSpace and in FIFO space.
+ *
+ *  SVGA_REG_SYNC --
+ *
+ *       The SYNC register can be used in two different ways by the guest:
+ *
+ *         1. If the guest wishes to fully sync (drain) the FIFO,
+ *            it will write once to SYNC then poll on the BUSY
+ *            register. The FIFO is sync'ed once BUSY is zero.
+ *
+ *         2. If the guest wants to asynchronously wake up the host,
+ *            it will write once to SYNC without polling on BUSY.
+ *            Ideally it will do this after some new commands have
+ *            been placed in the FIFO, and after reading a zero
+ *            from SVGA_FIFO_BUSY.
+ *
+ *       (1) is the original behaviour that SYNC was designed to
+ *       support.  Originally, a write to SYNC would implicitly
+ *       trigger a read from BUSY. This causes us to synchronously
+ *       process the FIFO.
+ *
+ *       This behaviour has since been changed so that writing SYNC
+ *       will *not* implicitly cause a read from BUSY. Instead, it
+ *       makes a channel call which asynchronously wakes up the MKS
+ *       thread.
+ *
+ *       New guests can use this new behaviour to implement (2)
+ *       efficiently. This lets guests get the host's attention
+ *       without waiting for the MKS to poll, which gives us much
+ *       better CPU utilization on SMP hosts and on UP hosts while
+ *       we're blocked on the host GPU.
+ *
+ *       Old guests shouldn't notice the behaviour change. SYNC was
+ *       never guaranteed to process the entire FIFO, since it was
+ *       bounded to a particular number of CPU cycles. Old guests will
+ *       still loop on the BUSY register until the FIFO is empty.
+ *
+ *       Writing to SYNC currently has the following side-effects:
+ *
+ *         - Sets SVGA_REG_BUSY to TRUE (in the monitor)
+ *         - Asynchronously wakes up the MKS thread for FIFO processing
+ *         - The value written to SYNC is recorded as a "reason", for
+ *           stats purposes.
+ *
+ *       If SVGA_FIFO_BUSY is available, drivers are advised to only
+ *       write to SYNC if SVGA_FIFO_BUSY is FALSE. Drivers should set
+ *       SVGA_FIFO_BUSY to TRUE after writing to SYNC. The MKS will
+ *       eventually set SVGA_FIFO_BUSY on its own, but this approach
+ *       lets the driver avoid sending multiple asynchronous wakeup
+ *       messages to the MKS thread.
+ *
+ *  SVGA_REG_BUSY --
+ *
+ *       This register is set to TRUE when SVGA_REG_SYNC is written,
+ *       and it reads as FALSE when the FIFO has been completely
+ *       drained.
+ *
+ *       Every read from this register causes us to synchronously
+ *       process FIFO commands. There is no guarantee as to how many
+ *       commands each read will process.
+ *
+ *       CPU time spent processing FIFO commands will be billed to
+ *       the guest.
+ *
+ *       New drivers should avoid using this register unless they
+ *       need to guarantee that the FIFO is completely drained. It
+ *       is overkill for performing a sync-to-fence. Older drivers
+ *       will use this register for any type of synchronization.
+ *
+ *  SVGA_FIFO_BUSY --
+ *
+ *       This register is a fast way for the guest driver to check
+ *       whether the FIFO is already being processed. It reads and
+ *       writes at normal RAM speeds, with no monitor intervention.
+ *
+ *       If this register reads as TRUE, the host is guaranteeing that
+ *       any new commands written into the FIFO will be noticed before
+ *       the MKS goes back to sleep.
+ *
+ *       If this register reads as FALSE, no such guarantee can be
+ *       made.
+ *
+ *       The guest should use this register to quickly determine
+ *       whether or not it needs to wake up the host. If the guest
+ *       just wrote a command or group of commands that it would like
+ *       the host to begin processing, it should:
+ *
+ *         1. Read SVGA_FIFO_BUSY. If it reads as TRUE, no further
+ *            action is necessary.
+ *
+ *         2. Write TRUE to SVGA_FIFO_BUSY. This informs future guest
+ *            code that we've already sent a SYNC to the host and we
+ *            don't need to send a duplicate.
+ *
+ *         3. Write a reason to SVGA_REG_SYNC. This will send an
+ *            asynchronous wakeup to the MKS thread.
+ */
+
+
 /*
  * FIFO Capabilities
  *
  *      Fence -- Fence register and command are supported
  *      Accel Front -- Front buffer only commands are supported
  *      Pitch Lock -- Pitch lock register is supported
+ *      Video -- SVGA Video overlay units are supported
+ *      Escape -- Escape command is supported
  */
 
 #define SVGA_FIFO_CAP_NONE                  0
 #define SVGA_FIFO_CAP_FENCE             (1<<0)
 #define SVGA_FIFO_CAP_ACCELFRONT        (1<<1)
 #define SVGA_FIFO_CAP_PITCHLOCK         (1<<2)
+#define SVGA_FIFO_CAP_VIDEO             (1<<3)
+#define SVGA_FIFO_CAP_CURSOR_BYPASS_3   (1<<4)
+#define SVGA_FIFO_CAP_ESCAPE            (1<<5)
+#define SVGA_FIFO_CAP_RESERVE           (1<<6)
 
 
 /*
@@ -300,6 +542,72 @@ enum {
 
 #define SVGA_FIFO_FLAG_NONE                 0
 #define SVGA_FIFO_FLAG_ACCELFRONT       (1<<0)
+#define SVGA_FIFO_FLAG_RESERVED        (1<<31) // Internal use only
+
+/*
+ * FIFO reservation sentinel value
+ */
+
+#define SVGA_FIFO_RESERVED_UNKNOWN      0xffffffff
+
+
+/*
+ * Video overlay support
+ */
+
+#define SVGA_NUM_OVERLAY_UNITS 32
+
+
+/*
+ * Video capabilities that the guest is currently using
+ */
+
+#define SVGA_VIDEO_FLAG_COLORKEY        0x0001
+
+
+/*
+ * Offsets for the video overlay registers
+ */
+
+enum {
+   SVGA_VIDEO_ENABLED = 0,
+   SVGA_VIDEO_FLAGS,
+   SVGA_VIDEO_DATA_OFFSET,
+   SVGA_VIDEO_FORMAT,
+   SVGA_VIDEO_COLORKEY,
+   SVGA_VIDEO_SIZE,
+   SVGA_VIDEO_X,
+   SVGA_VIDEO_Y,
+   SVGA_VIDEO_SRC_WIDTH,
+   SVGA_VIDEO_SRC_HEIGHT,
+   SVGA_VIDEO_DST_WIDTH,
+   SVGA_VIDEO_DST_HEIGHT,
+   SVGA_VIDEO_PITCH_1,
+   SVGA_VIDEO_PITCH_2,
+   SVGA_VIDEO_PITCH_3,
+   SVGA_VIDEO_NUM_REGS
+};
+
+
+/*
+ * SVGA Overlay Units
+ */
+
+typedef struct SVGAOverlayUnit {
+   uint32 enabled;
+   uint32 flags;
+   uint32 dataOffset; 
+   uint32 format;
+   uint32 colorKey;
+   uint32 size;
+   uint32 x;
+   uint32 y;
+   uint32 srcWidth;
+   uint32 srcHeight;
+   uint32 dstWidth;
+   uint32 dstHeight;
+   uint32 pitches[3];
+} SVGAOverlayUnit;
 
 
 /*
@@ -319,6 +627,7 @@ enum {
 #define SVGA_PIXMAP_SCANLINE_SIZE(w,bpp) (( ((w)*(bpp))+31 ) >> 5)
 #define SVGA_GLYPH_SIZE(w,h) ((((((w) + 7) >> 3) * (h)) + 3) >> 2)
 #define SVGA_GLYPH_SCANLINE_SIZE(w) (((w) + 7) >> 3)
+#define SVGA_ESCAPE_SIZE(s) (((s) + 3) >> 2)
 
 /*
  *  Increment from one scanline to the next of a bitmap or pixmap
@@ -468,14 +777,25 @@ enum {
          /* FIFO layout:
             Fence value */
 
-#define        SVGA_CMD_MAX                      31
+#define SVGA_CMD_VIDEO_PLAY_OBSOLETE      31
+         /* Obsolete; do not use. */
+
+#define SVGA_CMD_VIDEO_END_OBSOLETE       32
+         /* Obsolete; do not use. */
+
+#define SVGA_CMD_ESCAPE                   33
+         /* FIFO layout:
+            Namespace ID, size(bytes), data */
+
+#define        SVGA_CMD_MAX                      34
 
 #define SVGA_CMD_MAX_ARGS                 64
 
 /*
  * Location and size of SVGA frame buffer and the FIFO.
  */
-#define SVGA_VRAM_MAX_SIZE     (16 * 1024 * 1024)
+#define SVGA_VRAM_MIN_SIZE   (4 * 640 * 480)  // bytes
+#define SVGA_VRAM_MAX_SIZE   (128 * 1024 * 1024)
 
 #define SVGA_VRAM_SIZE_WS       (16 * 1024 * 1024) // 16 MB
 #define SVGA_MEM_SIZE_WS        (2  * 1024 * 1024) // 2  MB
index d71e48e..3ea425e 100644 (file)
@@ -1176,6 +1176,8 @@ VMWAREModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool rebuildPixmap)
     VmwareLog(("fbSize:        %u\n", pVMWARE->FbSize));
     VmwareLog(("New dispWidth: %u\n", pScrn->displayWidth));
 
+    vmwareCheckVideoSanity(pScrn);
+
     if (rebuildPixmap) {
         pScrn->pScreen->ModifyPixmapHeader((*pScrn->pScreen->GetScreenPixmap)(pScrn->pScreen),
                                            pScrn->pScreen->width,
@@ -1303,6 +1305,10 @@ VMWARECloseScreen(int scrnIndex, ScreenPtr pScreen)
     VmwareLog(("cursorSema: %d\n", pVMWARE->cursorSema));
 
     if (*pVMWARE->pvtSema) {
+        if (pVMWARE->videoStreams) {
+            vmwareVideoEnd(pScreen);
+        }
+
         if (pVMWARE->CursorInfoRec) {
             vmwareCursorCloseScreen(pScreen);
         }
@@ -1688,6 +1694,15 @@ VMWAREScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
         xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
     }
 
+    /* Initialize Xv extension */
+    pVMWARE->videoStreams = NULL;
+    if (vmwareVideoEnabled(pVMWARE)) {
+        if (!vmwareVideoInit(pScreen)) {
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Xv initialization failed\n");
+        }
+    }
+
+
     /* Done */
     return TRUE;
 }
index 527e3fa..7edefd5 100644 (file)
@@ -142,6 +142,11 @@ typedef struct {
     VMWAREXineramaPtr xineramaNextState;
     unsigned int xineramaNextNumOutputs;
 
+    /*
+     * Xv
+     */
+    DevUnion *videoStreams;
+
 } VMWARERec, *VMWAREPtr;
 
 #define VMWAREPTR(p) ((VMWAREPtr)((p)->driverPrivate))
@@ -263,4 +268,19 @@ void VMwareCtrl_ExtInit(ScrnInfoPtr pScrn);
 /* vmwarexinerama.c */
 void VMwareXinerama_ExtInit(ScrnInfoPtr pScrn);
 
+/* vmwarevideo.c */
+Bool vmwareInitVideo(
+   ScreenPtr pScreen
+   );
+void vmwareVideoEnd(
+   ScreenPtr pScreen
+   );
+Bool vmwareVideoEnabled(
+   VMWAREPtr pVMWARE
+   );
+
+void vmwareCheckVideoSanity(
+   ScrnInfoPtr pScrn
+   );
+
 #endif
diff --git a/src/vmwarevideo.c b/src/vmwarevideo.c
new file mode 100644 (file)
index 0000000..6c081c8
--- /dev/null
@@ -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;
+}
+