summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@vmware.com>2009-12-01 17:13:41 +0100
committerJakob Bornecrantz <jakob@vmware.com>2009-12-01 17:29:42 +0100
commit77ff3a5619721cfd917f9fd45e4b3a1c866c578f (patch)
tree58513de2a8f4ac5df6ffc9849e9e27300da47dd5
parent64102a56256c95f17f59456a78d9ff2b05889bfb (diff)
vmware/xorg: Add video support
By using the hooks st/xorg provides us we can create a driver specific implementation that uses the svga overlay engines.
-rw-r--r--src/gallium/winsys/drm/vmware/xorg/Makefile3
-rw-r--r--src/gallium/winsys/drm/vmware/xorg/vmw_driver.h31
-rw-r--r--src/gallium/winsys/drm/vmware/xorg/vmw_ioctl.c140
-rw-r--r--src/gallium/winsys/drm/vmware/xorg/vmw_screen.c4
-rw-r--r--src/gallium/winsys/drm/vmware/xorg/vmw_video.c1021
5 files changed, 1199 insertions, 0 deletions
diff --git a/src/gallium/winsys/drm/vmware/xorg/Makefile b/src/gallium/winsys/drm/vmware/xorg/Makefile
index d9fee4bf3b6..49e28ae17f5 100644
--- a/src/gallium/winsys/drm/vmware/xorg/Makefile
+++ b/src/gallium/winsys/drm/vmware/xorg/Makefile
@@ -6,6 +6,8 @@ TARGET = vmwgfx_drv.so
CFILES = \
vmw_xorg.c \
+ vmw_video.c \
+ vmw_ioctl.c \
vmw_screen.c
OBJECTS = $(patsubst %.c,%.o,$(CFILES))
@@ -29,6 +31,7 @@ LINKS = \
$(shell pkg-config --libs libdrm)
DRIVER_DEFINES = \
+ -std=gnu99 \
-DHAVE_CONFIG_H
TARGET_STAGING = $(TOP)/$(LIB_DIR)/gallium/$(TARGET)
diff --git a/src/gallium/winsys/drm/vmware/xorg/vmw_driver.h b/src/gallium/winsys/drm/vmware/xorg/vmw_driver.h
index e964cb4b57e..04d446a2dfb 100644
--- a/src/gallium/winsys/drm/vmware/xorg/vmw_driver.h
+++ b/src/gallium/winsys/drm/vmware/xorg/vmw_driver.h
@@ -38,10 +38,14 @@
#include "state_trackers/xorg/xorg_tracker.h"
+struct vmw_dma_buffer;
+
struct vmw_driver
{
int fd;
+ /* vmw_video.c */
+ void *video_priv;
};
static INLINE struct vmw_driver *
@@ -52,4 +56,31 @@ vmw_driver(ScrnInfoPtr pScrn)
}
+/***********************************************************************
+ * vmw_video.c
+ */
+
+Bool vmw_video_init(ScrnInfoPtr pScrn, struct vmw_driver *vmw);
+
+Bool vmw_video_close(ScrnInfoPtr pScrn, struct vmw_driver *vmw);
+
+
+/***********************************************************************
+ * vmw_ioctl.c
+ */
+
+struct vmw_dma_buffer * vmw_ioctl_buffer_create(struct vmw_driver *vmw,
+ uint32_t size,
+ unsigned *handle);
+
+void * vmw_ioctl_buffer_map(struct vmw_driver *vmw,
+ struct vmw_dma_buffer *buf);
+
+void vmw_ioctl_buffer_unmap(struct vmw_driver *vmw,
+ struct vmw_dma_buffer *buf);
+
+void vmw_ioctl_buffer_destroy(struct vmw_driver *vmw,
+ struct vmw_dma_buffer *buf);
+
+
#endif
diff --git a/src/gallium/winsys/drm/vmware/xorg/vmw_ioctl.c b/src/gallium/winsys/drm/vmware/xorg/vmw_ioctl.c
new file mode 100644
index 00000000000..3cac5b7760c
--- /dev/null
+++ b/src/gallium/winsys/drm/vmware/xorg/vmw_ioctl.c
@@ -0,0 +1,140 @@
+/**********************************************************
+ * Copyright 2009 VMware, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, 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 AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ **********************************************************/
+
+/**
+ * @file
+ * Contains the functions for creating dma buffers by calling
+ * the kernel via driver specific ioctls.
+ *
+ * @author Jakob Bornecrantz <jakob@vmware.com>
+ */
+
+#define HAVE_STDINT_H
+#define _FILE_OFFSET_BITS 64
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/mman.h>
+#include "xf86drm.h"
+#include "../core/vmwgfx_drm.h"
+
+#include "vmw_driver.h"
+#include "util/u_debug.h"
+
+struct vmw_dma_buffer
+{
+ void *data;
+ unsigned handle;
+ uint64_t map_handle;
+ unsigned map_count;
+ uint32_t size;
+};
+
+struct vmw_dma_buffer *
+vmw_ioctl_buffer_create(struct vmw_driver *vmw, uint32_t size, unsigned *handle)
+{
+ struct vmw_dma_buffer *buf;
+ union drm_vmw_alloc_dmabuf_arg arg;
+ struct drm_vmw_alloc_dmabuf_req *req = &arg.req;
+ struct drm_vmw_dmabuf_rep *rep = &arg.rep;
+ int ret;
+
+ buf = xcalloc(1, sizeof(*buf));
+ if (!buf)
+ goto err;
+
+ memset(&arg, 0, sizeof(arg));
+ req->size = size;
+ do {
+ ret = drmCommandWriteRead(vmw->fd, DRM_VMW_ALLOC_DMABUF, &arg, sizeof(arg));
+ } while (ret == -ERESTART);
+
+ if (ret) {
+ debug_printf("IOCTL failed %d: %s\n", ret, strerror(-ret));
+ goto err_free;
+ }
+
+
+ buf->data = NULL;
+ buf->handle = rep->handle;
+ buf->map_handle = rep->map_handle;
+ buf->map_count = 0;
+ buf->size = size;
+
+ *handle = rep->handle;
+
+ return buf;
+
+err_free:
+ xfree(buf);
+err:
+ return NULL;
+}
+
+void
+vmw_ioctl_buffer_destroy(struct vmw_driver *vmw, struct vmw_dma_buffer *buf)
+{
+ struct drm_vmw_unref_dmabuf_arg arg;
+
+ if (buf->data) {
+ munmap(buf->data, buf->size);
+ buf->data = NULL;
+ }
+
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = buf->handle;
+ drmCommandWrite(vmw->fd, DRM_VMW_UNREF_DMABUF, &arg, sizeof(arg));
+
+ xfree(buf);
+}
+
+void *
+vmw_ioctl_buffer_map(struct vmw_driver *vmw, struct vmw_dma_buffer *buf)
+{
+ void *map;
+
+ if (buf->data == NULL) {
+ map = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED,
+ vmw->fd, buf->map_handle);
+ if (map == MAP_FAILED) {
+ debug_printf("%s: Map failed.\n", __FUNCTION__);
+ return NULL;
+ }
+
+ buf->data = map;
+ }
+
+ ++buf->map_count;
+
+ return buf->data;
+}
+
+void
+vmw_ioctl_buffer_unmap(struct vmw_driver *vmw, struct vmw_dma_buffer *buf)
+{
+ --buf->map_count;
+}
diff --git a/src/gallium/winsys/drm/vmware/xorg/vmw_screen.c b/src/gallium/winsys/drm/vmware/xorg/vmw_screen.c
index 969d48157ca..344ef0b3159 100644
--- a/src/gallium/winsys/drm/vmware/xorg/vmw_screen.c
+++ b/src/gallium/winsys/drm/vmware/xorg/vmw_screen.c
@@ -50,6 +50,8 @@ vmw_screen_init(ScrnInfoPtr pScrn)
vmw->fd = ms->fd;
ms->winsys_priv = vmw;
+ vmw_video_init(pScrn, vmw);
+
return TRUE;
}
@@ -62,6 +64,8 @@ vmw_screen_close(ScrnInfoPtr pScrn)
if (!vmw)
return TRUE;
+ vmw_video_close(pScrn, vmw);
+
ms->winsys_priv = NULL;
xfree(vmw);
diff --git a/src/gallium/winsys/drm/vmware/xorg/vmw_video.c b/src/gallium/winsys/drm/vmware/xorg/vmw_video.c
new file mode 100644
index 00000000000..6e34aa21f38
--- /dev/null
+++ b/src/gallium/winsys/drm/vmware/xorg/vmw_video.c
@@ -0,0 +1,1021 @@
+/*
+ * 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
+ *
+ */
+
+
+#include "xf86xv.h"
+#include "fourcc.h"
+
+#include "pipe/p_compiler.h"
+/*
+ * We can't incude svga_types.h due to conflicting types for Bool.
+ */
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+typedef int32_t int32;
+typedef uint32_t uint32;
+
+typedef int16_t int16;
+typedef uint16_t uint16;
+
+typedef int8_t int8;
+typedef uint8_t uint8;
+
+#include "svga/include/svga_reg.h"
+#include "svga/include/svga_escape.h"
+#include "svga/include/svga_overlay.h"
+
+#include "vmw_driver.h"
+
+#include <X11/extensions/Xv.h>
+
+#include "xf86drm.h"
+#include "../core/vmwgfx_drm.h"
+
+#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+/*
+ * Number of videos that can be played simultaneously
+ */
+#define VMWARE_VID_NUM_PORTS 1
+
+/*
+ * Using a dark shade as the default colorKey
+ */
+#define VMWARE_VIDEO_COLORKEY 0x100701
+
+/*
+ * Maximum dimensions
+ */
+#define VMWARE_VID_MAX_WIDTH 2048
+#define VMWARE_VID_MAX_HEIGHT 2048
+
+#define VMWARE_VID_NUM_ENCODINGS 1
+static XF86VideoEncodingRec vmwareVideoEncodings[] =
+{
+ {
+ 0,
+ "XV_IMAGE",
+ VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT,
+ {1, 1}
+ }
+};
+
+#define VMWARE_VID_NUM_FORMATS 2
+static XF86VideoFormatRec vmwareVideoFormats[] =
+{
+ { 16, TrueColor},
+ { 24, TrueColor}
+};
+
+#define VMWARE_VID_NUM_IMAGES 3
+static XF86ImageRec vmwareVideoImages[] =
+{
+ XVIMAGE_YV12,
+ XVIMAGE_YUY2,
+ XVIMAGE_UYVY
+};
+
+#define VMWARE_VID_NUM_ATTRIBUTES 2
+static XF86AttributeRec vmwareVideoAttributes[] =
+{
+ {
+ XvGettable | XvSettable,
+ 0x000000,
+ 0xffffff,
+ "XV_COLORKEY"
+ },
+ {
+ XvGettable | XvSettable,
+ 0,
+ 1,
+ "XV_AUTOPAINT_COLORKEY"
+ }
+};
+
+/*
+ * Video frames are stored in a circular list of buffers.
+ * Must be power or two, See vmw_video_port_play.
+ */
+#define VMWARE_VID_NUM_BUFFERS 1
+
+/*
+ * Defines the structure used to hold and pass video data to the host
+ */
+struct vmw_video_buffer
+{
+ unsigned handle;
+ int size;
+ void *data;
+ void *extra_data;
+ struct vmw_dma_buffer *buf;
+};
+
+
+/**
+ * Structure representing a single video stream, aka port.
+ *
+ * Ports maps one to one to a SVGA stream. Port is just
+ * what Xv calls a SVGA stream.
+ */
+struct vmw_video_port
+{
+ /*
+ * Function prototype same as XvPutImage.
+ *
+ * This is either set to vmw_video_port_init or vmw_video_port_play.
+ * At init this function is set to port_init. In port_init we set it
+ * to port_play and call it, after initializing the struct.
+ */
+ int (*play)(ScrnInfoPtr, struct vmw_video_port *,
+ short, short, short, short, short,
+ short, short, short, int, unsigned char*,
+ short, short, RegionPtr);
+
+ /* values to go into the SVGAOverlayUnit */
+ uint32 streamId;
+ uint32 colorKey;
+ uint32 flags;
+
+ /* round robin of buffers */
+ unsigned currBuf;
+ struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS];
+
+ /* properties that applies to all buffers */
+ int size;
+ int pitches[3];
+ int offsets[3];
+
+ /* things for X */
+ RegionRec clipBoxes;
+ Bool isAutoPaintColorkey;
+};
+
+
+/**
+ * Structure holding all the infromation for video.
+ */
+struct vmw_video_private
+{
+ int fd;
+
+ /** ports */
+ struct vmw_video_port port[VMWARE_VID_NUM_PORTS];
+
+ /** Used to store port pointers pointers */
+ DevUnion port_ptr[VMWARE_VID_NUM_PORTS];
+};
+
+
+/*
+ * Callback functions exported to Xv, prefixed with vmw_xv_*.
+ */
+static int vmw_xv_put_image(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);
+static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
+static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
+ unsigned short *width,
+ unsigned short *height, int *pitches,
+ int *offsets);
+static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 value, pointer data);
+static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 *value, pointer data);
+static void vmw_xv_query_best_size(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.
+ */
+static XF86VideoAdaptorPtr vmw_video_init_adaptor(ScrnInfoPtr pScrn, struct vmw_driver *vmw);
+
+static int vmw_video_port_init(ScrnInfoPtr pScrn,
+ struct vmw_video_port *port,
+ short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h,
+ short drw_w, short drw_h, int format,
+ unsigned char *buf, short width,
+ short height, RegionPtr clipBoxes);
+static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmw_video_port *port,
+ short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h,
+ short drw_w, short drw_h, int format,
+ unsigned char *buf, short width,
+ short height, RegionPtr clipBoxes);
+static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmw_video_port *port);
+
+static int vmw_video_buffer_alloc(struct vmw_driver *vmw, int size,
+ struct vmw_video_buffer *out);
+static int vmw_video_buffer_free(struct vmw_driver *vmw,
+ struct vmw_video_buffer *out);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_init --
+ *
+ * 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
+vmw_video_init(ScrnInfoPtr pScrn, struct vmw_driver *vmw)
+{
+ ScreenPtr pScreen = pScrn->pScreen;
+ XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
+ XF86VideoAdaptorPtr newAdaptor = NULL;
+ int numAdaptors;
+
+ debug_printf("%s: enter\n", __func__);
+
+ numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
+
+ newAdaptor = vmw_video_init_adaptor(pScrn, vmw);
+ if (!newAdaptor) {
+ debug_printf("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)) {
+ debug_printf("Failed to initialize Xv extension\n");
+ xf86XVFreeVideoAdaptorRec(newAdaptor);
+ return FALSE;
+ }
+
+ if (newAdaptors) {
+ xfree(newAdaptors);
+ }
+
+ debug_printf("Initialized VMware Xv extension successfully\n");
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_close --
+ *
+ * Unitializes video.
+ *
+ * Results:
+ * TRUE.
+ *
+ * Side effects:
+ * vmw->video_priv = NULL
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+vmw_video_close(ScrnInfoPtr pScrn, struct vmw_driver *vmw)
+{
+ struct vmw_video_private *video;
+ int i;
+
+ debug_printf("%s: enter\n", __func__);
+
+ video = vmw->video_priv;
+
+ for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
+ vmw_video_port_cleanup(pScrn, &video->port[i]);
+ }
+
+ /* XXX: I'm sure this function is missing code for turning off Xv */
+
+ free(vmw->video_priv);
+ vmw->video_priv = NULL;
+
+ return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_init_adaptor --
+ *
+ * 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
+vmw_video_init_adaptor(ScrnInfoPtr pScrn, struct vmw_driver *vmw)
+{
+ XF86VideoAdaptorPtr adaptor;
+ struct vmw_video_private *video;
+ int i;
+
+ debug_printf("%s: enter \n", __func__);
+
+ adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
+ if (!adaptor) {
+ debug_printf("Not enough memory\n");
+ return NULL;
+ }
+
+ video = xcalloc(1, sizeof(*video));
+ if (!video) {
+ debug_printf("Not enough memory.\n");
+ xf86XVFreeVideoAdaptorRec(adaptor);
+ return NULL;
+ }
+
+ vmw->video_priv = video;
+
+ 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;
+ adaptor->pPortPrivates = video->port_ptr;
+
+ for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
+ video->port[i].streamId = i;
+ video->port[i].play = vmw_video_port_init;
+ video->port[i].flags = SVGA_VIDEO_FLAG_COLORKEY;
+ video->port[i].colorKey = VMWARE_VIDEO_COLORKEY;
+ video->port[i].isAutoPaintColorkey = TRUE;
+ adaptor->pPortPrivates[i].ptr = &video->port[i];
+ }
+
+ 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 = vmw_xv_stop_video;
+ adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
+ adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
+ adaptor->QueryBestSize = vmw_xv_query_best_size;
+ adaptor->PutImage = vmw_xv_put_image;
+ adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
+
+ debug_printf("%s: done %p\n", __func__, adaptor);
+
+ return adaptor;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_init --
+ *
+ * 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
+vmw_video_port_init(ScrnInfoPtr pScrn, struct vmw_video_port *port,
+ short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h,
+ short drw_w, short drw_h, int format,
+ unsigned char *buf, short width,
+ short height, RegionPtr clipBoxes)
+{
+ struct vmw_driver *vmw = vmw_driver(pScrn);
+ unsigned short w, h;
+ int i, ret;
+
+ debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
+
+ w = width;
+ h = height;
+ /* init all the format attributes, used for buffers */
+ port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
+ port->pitches, port->offsets);
+
+ if (port->size == -1)
+ return XvBadAlloc;
+
+ port->play = vmw_video_port_play;
+
+ for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
+ ret = vmw_video_buffer_alloc(vmw, port->size, &port->bufs[i]);
+ if (ret != Success)
+ break;
+ }
+
+ /* Free all allocated buffers on failure */
+ if (ret != Success) {
+ for (--i; i >= 0; --i) {
+ vmw_video_buffer_free(vmw, &port->bufs[i]);
+ }
+ return ret;
+ }
+
+ port->currBuf = 0;
+
+ REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
+
+ if (port->isAutoPaintColorkey)
+ xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
+
+ return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
+ drw_w, drw_h, format, buf, width, height, clipBoxes);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_play --
+ *
+ * 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
+vmw_video_port_play(ScrnInfoPtr pScrn, struct vmw_video_port *port,
+ short src_x, short src_y, short drw_x,
+ short drw_y, short src_w, short src_h,
+ short drw_w, short drw_h, int format,
+ unsigned char *buf, short width,
+ short height, RegionPtr clipBoxes)
+{
+ struct vmw_driver *vmw = vmw_driver(pScrn);
+ struct drm_vmw_overlay_arg arg;
+ unsigned short w, h;
+ int size;
+ int ret;
+
+ debug_printf("\t%s: enter\n", __func__);
+
+ w = width;
+ h = height;
+
+ /* we don't update the ports size */
+ size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
+ port->pitches, port->offsets);
+
+ if (size > port->size) {
+ debug_printf("\t%s: Increase in size of Xv video frame streamId:%d.\n",
+ __func__, port->streamId);
+ vmw_xv_stop_video(pScrn, port, TRUE);
+ return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
+ src_h, drw_w, drw_h, format, buf, width, height,
+ clipBoxes);
+ }
+
+ memcpy(port->bufs[port->currBuf].data, buf, port->size);
+
+ memset(&arg, 0, sizeof(arg));
+
+ arg.stream_id = port->streamId;
+ arg.enabled = TRUE;
+ arg.flags = port->flags;
+ arg.color_key = port->colorKey;
+ arg.handle = port->bufs[port->currBuf].handle;
+ arg.format = format;
+ arg.size = port->size;
+ arg.width = w;
+ arg.height = h;
+ arg.src.x = src_x;
+ arg.src.y = src_y;
+ arg.src.w = src_w;
+ arg.src.h = src_h;
+ arg.dst.x = drw_x;
+ arg.dst.y = drw_y;
+ arg.dst.w = drw_w;
+ arg.dst.h = drw_h;
+ arg.pitch[0] = port->pitches[0];
+ arg.pitch[1] = port->pitches[1];
+ arg.pitch[2] = port->pitches[2];
+ arg.offset = 0;
+
+ /*
+ * Update the clipList and paint the colorkey, if required.
+ */
+ if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
+ REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
+ if (port->isAutoPaintColorkey) {
+ xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
+ }
+ }
+
+ ret = drmCommandWrite(vmw->fd, DRM_VMW_OVERLAY, &arg, sizeof(arg));
+ if (ret) {
+ vmw_video_port_cleanup(pScrn, port);
+ return XvBadAlloc;
+ }
+
+ port->currBuf = ++port->currBuf & (VMWARE_VID_NUM_BUFFERS - 1);
+
+ return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_port_cleanup --
+ *
+ * Frees up all resources (if any) taken by a video stream.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Same as above.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmw_video_port *port)
+{
+ struct vmw_driver *vmw = vmw_driver(pScrn);
+ uint32 id, colorKey, flags;
+ Bool isAutoPaintColorkey;
+ int i;
+
+ debug_printf("\t%s: enter\n", __func__);
+
+ for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
+ vmw_video_buffer_free(vmw, &port->bufs[i]);
+ }
+
+ /*
+ * reset stream for next video
+ */
+ id = port->streamId;
+ colorKey = port->colorKey;
+ flags = port->flags;
+ isAutoPaintColorkey = port->isAutoPaintColorkey;
+
+ memset(port, 0, sizeof(*port));
+
+ port->streamId = id;
+ port->play = vmw_video_port_init;
+ port->colorKey = colorKey;
+ port->flags = flags;
+ port->isAutoPaintColorkey = isAutoPaintColorkey;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_buffer_alloc --
+ *
+ * Allocates and map a kernel buffer to be used as data storage.
+ *
+ * Results:
+ * XvBadAlloc on failure, otherwise Success.
+ *
+ * Side effects:
+ * Calls into the kernel, sets members of out.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_buffer_alloc(struct vmw_driver *vmw, int size,
+ struct vmw_video_buffer *out)
+{
+ out->buf = vmw_ioctl_buffer_create(vmw, size, &out->handle);
+ if (!out->buf)
+ return XvBadAlloc;
+
+ out->data = vmw_ioctl_buffer_map(vmw, out->buf);
+ if (!out->data) {
+ vmw_ioctl_buffer_destroy(vmw, out->buf);
+
+ out->handle = 0;
+ out->buf = NULL;
+
+ return XvBadAlloc;
+ }
+
+ out->size = size;
+ out->extra_data = xcalloc(1, size);
+
+ debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
+
+ return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_video_buffer_free --
+ *
+ * Frees and unmaps an allocated kernel buffer.
+ *
+ * Results:
+ * Success.
+ *
+ * Side effects:
+ * Calls into the kernel, sets members of out to 0.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_video_buffer_free(struct vmw_driver *vmw,
+ struct vmw_video_buffer *out)
+{
+ if (out->size == 0)
+ return Success;
+
+ xfree(out->extra_data);
+ vmw_ioctl_buffer_unmap(vmw, out->buf);
+ vmw_ioctl_buffer_destroy(vmw, out->buf);
+
+ out->buf = NULL;
+ out->data = NULL;
+ out->handle = 0;
+ out->size = 0;
+
+ debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
+
+ return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_put_image --
+ *
+ * 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.
+ *
+ * Results:
+ * Success or XvBadAlloc on failure
+ *
+ * Side effects:
+ * Video port will be played(initialized if 1st frame) on success
+ * or will fail on error.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+vmw_xv_put_image(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)
+{
+ struct vmw_driver *vmw = vmw_driver(pScrn);
+ struct vmw_video_port *port = data;
+
+ debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
+ src_x, src_y, src_w, src_h,
+ drw_x, drw_y, drw_w, drw_h,
+ width, height);
+
+ if (!vmw->video_priv)
+ return XvBadAlloc;
+
+ return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
+ drw_w, drw_h, format, buf, width, height, clipBoxes);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_stop_video --
+ *
+ * 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 port by
+ * sending a message to the host and freeing up the stream.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * See above.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
+{
+ struct vmw_driver *vmw = vmw_driver(pScrn);
+ struct vmw_video_port *port = data;
+ struct drm_vmw_overlay_arg arg;
+ int ret;
+
+ debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
+
+ if (!vmw->video_priv)
+ return;
+
+ if (!cleanup)
+ return;
+
+
+ memset(&arg, 0, sizeof(arg));
+ arg.stream_id = port->streamId;
+ arg.enabled = FALSE;
+
+ ret = drmCommandWrite(vmw->fd, DRM_VMW_OVERLAY, &arg, sizeof(arg));
+ assert(ret == 0);
+
+ vmw_video_port_cleanup(pScrn, port);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_query_image_attributes --
+ *
+ * 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
+vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
+ unsigned short *width, unsigned short *height,
+ int *pitches, int *offsets)
+{
+ INT32 size, tmp;
+
+ if (*width > VMWARE_VID_MAX_WIDTH) {
+ *width = VMWARE_VID_MAX_WIDTH;
+ }
+ if (*height > VMWARE_VID_MAX_HEIGHT) {
+ *height = VMWARE_VID_MAX_HEIGHT;
+ }
+
+ *width = (*width + 1) & ~1;
+ if (offsets != NULL) {
+ offsets[0] = 0;
+ }
+
+ switch (format) {
+ case FOURCC_YV12:
+ *height = (*height + 1) & ~1;
+ size = (*width + 3) & ~3;
+ if (pitches) {
+ pitches[0] = size;
+ }
+ size *= *height;
+ if (offsets) {
+ offsets[1] = size;
+ }
+ tmp = ((*width >> 1) + 3) & ~3;
+ if (pitches) {
+ pitches[1] = pitches[2] = tmp;
+ }
+ tmp *= (*height >> 1);
+ size += tmp;
+ if (offsets) {
+ offsets[2] = size;
+ }
+ size += tmp;
+ break;
+ case FOURCC_UYVY:
+ case FOURCC_YUY2:
+ size = *width * 2;
+ if (pitches) {
+ pitches[0] = size;
+ }
+ size *= *height;
+ break;
+ default:
+ debug_printf("Query for invalid video format %d\n", format);
+ return -1;
+ }
+ return size;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_set_port_attribute --
+ *
+ * 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
+vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 value, pointer data)
+{
+ struct vmw_video_port *port = data;
+ Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
+
+ if (attribute == xvColorKey) {
+ debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
+ port->colorKey = value;
+ } else if (attribute == xvAutoPaint) {
+ debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
+ port->isAutoPaintColorkey = value;
+ } else {
+ return XvBadAlloc;
+ }
+
+ return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_get_port_attribute --
+ *
+ * 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
+vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 *value, pointer data)
+{
+ struct vmw_video_port *port = data;
+ Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
+ Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
+
+ if (attribute == xvColorKey) {
+ *value = port->colorKey;
+ } else if (attribute == xvAutoPaint) {
+ *value = port->isAutoPaintColorkey;
+ } else {
+ return XvBadAlloc;
+ }
+
+ return Success;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmw_xv_query_best_size --
+ *
+ * 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
+vmw_xv_query_best_size(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;
+}