| /* |
| * 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; |
| unsigned int ntot, nfree; |
| |
| debug_printf("%s: enter\n", __func__); |
| |
| if (vmw_ioctl_num_streams(vmw, &ntot, &nfree) != 0) { |
| debug_printf("No stream ioctl support\n"); |
| return FALSE; |
| } |
| |
| if (nfree == 0) { |
| debug_printf("No free streams\n"); |
| return FALSE; |
| } |
| |
| 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; |
| if (!video) |
| return TRUE; |
| |
| for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) { |
| /* make sure the port is stoped as well */ |
| vmw_xv_stop_video(pScrn, &video->port[i], TRUE); |
| vmw_ioctl_unref_stream(vmw, video->port[i].streamId); |
| } |
| |
| /* 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_stop_all -- |
| * |
| * Stop all video streams from playing. |
| * |
| * Results: |
| * None. |
| * |
| * Side effects: |
| * All buffers are freed. |
| * |
| *----------------------------------------------------------------------------- |
| */ |
| |
| void vmw_video_stop_all(ScrnInfoPtr pScrn, struct vmw_driver *vmw) |
| { |
| struct vmw_video_private *video = vmw->video_priv; |
| int i; |
| |
| debug_printf("%s: enter\n", __func__); |
| |
| if (!video) |
| return; |
| |
| for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) { |
| vmw_xv_stop_video(pScrn, &video->port[i], 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) { |
| vmw_ioctl_claim_stream(vmw, &video->port[i].streamId); |
| 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_control_stream_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_CONTROL_STREAM, &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_control_stream_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_CONTROL_STREAM, &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; |
| } |