diff options
author | Jakob Bornecrantz <[email protected]> | 2009-12-01 17:13:41 +0100 |
---|---|---|
committer | Jakob Bornecrantz <[email protected]> | 2009-12-01 17:29:42 +0100 |
commit | 77ff3a5619721cfd917f9fd45e4b3a1c866c578f (patch) | |
tree | 58513de2a8f4ac5df6ffc9849e9e27300da47dd5 /src/gallium/winsys/drm/vmware | |
parent | 64102a56256c95f17f59456a78d9ff2b05889bfb (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.
Diffstat (limited to 'src/gallium/winsys/drm/vmware')
-rw-r--r-- | src/gallium/winsys/drm/vmware/xorg/Makefile | 3 | ||||
-rw-r--r-- | src/gallium/winsys/drm/vmware/xorg/vmw_driver.h | 31 | ||||
-rw-r--r-- | src/gallium/winsys/drm/vmware/xorg/vmw_ioctl.c | 140 | ||||
-rw-r--r-- | src/gallium/winsys/drm/vmware/xorg/vmw_screen.c | 4 | ||||
-rw-r--r-- | src/gallium/winsys/drm/vmware/xorg/vmw_video.c | 1021 |
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 <[email protected]> + */ + +#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; +} |