xenocara/driver/xf86-video-vmware/vmwgfx/vmwgfx_overlay.c
2012-05-06 16:29:01 +00:00

894 lines
25 KiB
C

/*
* Copyright 2007-2011 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"
#define debug_printf(...)
/*
* 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 "../src/svga_reg.h"
#include "../src/svga_escape.h"
#include "../src/svga_overlay.h"
#include <X11/extensions/Xv.h>
#include "xf86drm.h"
#include "vmwgfx_drm.h"
#include "vmwgfx_drmi.h"
#include "vmwgfx_driver.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
{
int size;
void *data;
struct vmwgfx_dmabuf *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 vmwgfx_overlay_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 vmwgfx_overlay_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;
int drm_fd;
};
/*
* 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 int vmw_video_port_init(ScrnInfoPtr pScrn,
struct vmwgfx_overlay_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 vmwgfx_overlay_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 vmwgfx_overlay_port *port);
static int vmw_video_buffer_alloc(int drm_fd, int size,
struct vmw_video_buffer *out);
static int vmw_video_buffer_free(struct vmw_video_buffer *out);
static struct vmwgfx_overlay_port *
vmwgfx_overlay_port_create(int drm_fd, ScreenPtr pScreen)
{
struct vmwgfx_overlay_port *port = calloc(1, sizeof(*port));
if (!port)
return NULL;
port->drm_fd = drm_fd;
port->play = vmw_video_port_init;
port->flags = SVGA_VIDEO_FLAG_COLORKEY;
port->colorKey = VMWARE_VIDEO_COLORKEY;
port->isAutoPaintColorkey = TRUE;
return port;
}
void
vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports)
{
if (free_ports) {
int i;
for(i=0; i<adaptor->nPorts; ++i) {
free(adaptor->pPortPrivates[i].ptr);
}
}
free(adaptor->pPortPrivates);
xf86XVFreeVideoAdaptorRec(adaptor);
}
/*
*-----------------------------------------------------------------------------
*
* 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.
*
*-----------------------------------------------------------------------------
*/
XF86VideoAdaptorPtr
vmw_video_init_adaptor(ScrnInfoPtr pScrn)
{
XF86VideoAdaptorPtr adaptor;
modesettingPtr ms = modesettingPTR(pScrn);
int i;
DevUnion *dev_unions;
uint32_t ntot, nfree;
if (vmwgfx_num_streams(ms->fd, &ntot, &nfree) != 0) {
debug_printf("No stream ioctl support\n");
return NULL;
}
if (nfree == 0) {
debug_printf("No free streams\n");
return NULL;
}
adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
dev_unions = calloc(VMWARE_VID_NUM_PORTS, sizeof(DevUnion));
if (adaptor == NULL || dev_unions == NULL) {
xf86XVFreeVideoAdaptorRec(adaptor);
free(dev_unions);
return NULL;
}
adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
/**
* Note: CLIP_TO_VIEWPORT was removed from the flags, since with the
* crtc/output based modesetting, the viewport is not updated on
* RandR modeswitches. Hence the video may incorrectly be clipped away.
* The correct approach, (if needed) would be to clip against the
* scanout area union of all active crtcs. Revisit if needed.
*/
adaptor->flags = VIDEO_OVERLAID_IMAGES;
adaptor->name = "VMware Overlay 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 = dev_unions;
for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
struct vmwgfx_overlay_port *priv =
vmwgfx_overlay_port_create(ms->fd, pScrn->pScreen);
adaptor->pPortPrivates[i].ptr = (pointer) priv;
}
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;
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 vmwgfx_overlay_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)
{
unsigned short w, h;
int i, ret;
debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
ret = vmwgfx_claim_stream(port->drm_fd, &port->streamId);
if (ret != 0)
return XvBadAlloc;
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) {
ret = XvBadAlloc;
goto out_bad_size;
}
for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
ret = vmw_video_buffer_alloc(port->drm_fd, port->size, &port->bufs[i]);
if (ret != Success)
goto out_no_buffer;
}
port->currBuf = 0;
REGION_NULL(pScrn->pScreen, &port->clipBoxes);
port->play = vmw_video_port_play;
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);
out_no_buffer:
while(i-- != 0) {
vmw_video_buffer_free(&port->bufs[i]);
}
out_bad_size:
(void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
return ret;
}
/*
*-----------------------------------------------------------------------------
*
* 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 vmwgfx_overlay_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 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) {
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].buf->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);
}
xorg_flush(pScrn->pScreen);
ret = drmCommandWrite(port->drm_fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
if (ret) {
vmw_video_port_cleanup(pScrn, port);
return XvBadAlloc;
}
if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
port->currBuf = 0;
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 vmwgfx_overlay_port *port)
{
int i;
debug_printf("\t%s: enter\n", __func__);
if (port->play == vmw_video_port_init)
return;
port->play = vmw_video_port_init;
(void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
vmw_video_buffer_free(&port->bufs[i]);
}
REGION_UNINIT(pScreen->pScreen, &port->clipBoxes);
}
/*
*-----------------------------------------------------------------------------
*
* 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(int drm_fd, int size,
struct vmw_video_buffer *out)
{
out->buf = vmwgfx_dmabuf_alloc(drm_fd, size);
if (!out->buf)
return XvBadAlloc;
out->data = vmwgfx_dmabuf_map(out->buf);
if (!out->data) {
vmwgfx_dmabuf_destroy(out->buf);
out->buf = NULL;
return XvBadAlloc;
}
out->size = 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_video_buffer *out)
{
if (out->size == 0)
return Success;
vmwgfx_dmabuf_unmap(out->buf);
vmwgfx_dmabuf_destroy(out->buf);
out->buf = NULL;
out->data = NULL;
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 vmwgfx_overlay_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);
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 vmwgfx_overlay_port *port = data;
debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
if (!cleanup)
return;
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 vmwgfx_overlay_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 vmwgfx_overlay_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;
}