xenocara/driver/xf86-video-vmware/src/vmwarevideo.c

1368 lines
38 KiB
C

/*
* Copyright 2007 by VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
/*
* vmwarevideo.c --
*
* Xv extension support.
* See http://www.xfree86.org/current/DESIGN16.html
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vmware.h"
#include "vmware_common.h"
#include "xf86xv.h"
#include "fourcc.h"
#include "svga_escape.h"
#include "svga_overlay.h"
#include "common_compat.h"
#include <X11/extensions/Xv.h>
#ifndef HAVE_XORG_SERVER_1_5_0
#include <xf86_ansic.h>
#include <xf86_libc.h>
#endif
static CONST_ABI_16_0 char xv_adapt_name[] = "VMWare Overlay Video Engine";
static CONST_ABI_16_0 char xv_image_name[] = "XV_IMAGE";
#define HAVE_FILLKEYHELPERDRAWABLE \
((GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 2) || \
((GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) == 1) && \
(GET_ABI_MINOR(ABI_VIDEODRV_VERSION) >= 2)))
#if HAVE_FILLKEYHELPERDRAWABLE
#include <damage.h>
#endif
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
/*
* Used to pack structs
*/
#define PACKED __attribute__((__packed__))
/*
* Number of videos that can be played simultaneously
*/
#define VMWARE_VID_NUM_PORTS 1
/*
* Using 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_name,
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
};
static CONST_ABI_16_TO_19 char xv_colorkey_name[] = "XV_COLORKEY";
static CONST_ABI_16_TO_19 char xv_autopaint_name[] = "XV_AUTOPAINT_COLORKEY";
#define VMWARE_VID_NUM_ATTRIBUTES 2
static XF86AttributeRec vmwareVideoAttributes[] =
{
{
XvGettable | XvSettable,
0x000000,
0xffffff,
xv_colorkey_name,
},
{
XvGettable | XvSettable,
0,
1,
xv_autopaint_name,
}
};
/*
* Video frames are stored in a circular list of buffers.
*/
#define VMWARE_VID_NUM_BUFFERS 1
/*
* Defines the structure used to hold and pass video data to the host
*/
typedef struct {
uint32 dataOffset;
pointer data;
} VMWAREVideoBuffer;
typedef struct {
uint32 size;
uint32 offset;
} VMWAREOffscreenRec, *VMWAREOffscreenPtr;
/*
* Trivial offscreen manager that allocates memory from the
* bottom of the VRAM.
*/
static VMWAREOffscreenRec offscreenMgr;
/*
* structs that reside in fmt_priv.
*/
typedef struct {
int pitches[3];
int offsets[3];
} VMWAREVideoFmtData;
/*
* Structure representing a specific video stream.
*/
struct VMWAREVideoRec {
uint32 streamId;
/*
* Function prototype same as XvPutImage.
*/
int (*play)(ScrnInfoPtr, struct VMWAREVideoRec *,
short, short, short, short, short,
short, short, short, int, unsigned char*,
short, short, RegionPtr, DrawablePtr);
/*
* Offscreen memory region used to pass video data to the host.
*/
VMWAREOffscreenPtr fbarea;
VMWAREVideoBuffer bufs[VMWARE_VID_NUM_BUFFERS];
uint8 currBuf;
uint32 size;
uint32 colorKey;
Bool isAutoPaintColorkey;
uint32 flags;
RegionRec clipBoxes;
VMWAREVideoFmtData *fmt_priv;
};
typedef struct VMWAREVideoRec VMWAREVideoRec;
typedef VMWAREVideoRec *VMWAREVideoPtr;
/*
* Callback functions
*/
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1)
static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int image,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data,
DrawablePtr dst);
#else
static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int image,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data);
#endif
static void vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
static int vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format,
unsigned short *width,
unsigned short *height, int *pitches,
int *offsets);
static int vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 value, pointer data);
static int vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 *value, pointer data);
static void vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
short vid_w, short vid_h, short drw_w,
short drw_h, unsigned int *p_w,
unsigned int *p_h, pointer data);
/*
* Local functions for video streams
*/
static XF86VideoAdaptorPtr vmwareVideoSetup(ScrnInfoPtr pScrn);
static int vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes,
DrawablePtr draw);
static int vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
int format, unsigned short width,
unsigned short height);
static int vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes,
DrawablePtr draw);
static void vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId);
static void vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId,
uint32 regId, uint32 value);
static void vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid);
/*
* Offscreen memory manager functions
*/
static void vmwareOffscreenInit(void);
static VMWAREOffscreenPtr vmwareOffscreenAllocate(VMWAREPtr pVMWARE,
uint32 size);
static void vmwareOffscreenFree(VMWAREOffscreenPtr memptr);
/*
*-----------------------------------------------------------------------------
*
* vmwareCheckVideoSanity --
*
* Ensures that on ModeSwitch the offscreen memory used
* by the Xv streams doesn't become part of the guest framebuffer.
*
* Results:
* None
*
* Side effects:
* If it is found that the offscreen used by video streams lies
* within the range of the framebuffer(after ModeSwitch) then the video
* streams will be stopped.
*
*-----------------------------------------------------------------------------
*/
void
vmwareCheckVideoSanity(ScrnInfoPtr pScrn)
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
VMWAREVideoPtr pVid;
if (offscreenMgr.size == 0 ||
offscreenMgr.offset > pVMWARE->FbSize) {
return ;
}
pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS];
vmwareStopVideo(pScrn, pVid, TRUE);
}
/*
*-----------------------------------------------------------------------------
*
* vmwareOffscreenInit --
*
* Initializes the trivial Offscreen memory manager.
*
* Results:
* None.
*
* Side effects:
* Initializes the Offscreen manager meta-data structure.
*
*-----------------------------------------------------------------------------
*/
static void
vmwareOffscreenInit(void)
{
offscreenMgr.size = 0;
offscreenMgr.offset = 0;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareOffscreenAllocate --
*
* Allocates offscreen memory.
* Memory is allocated from the bottom part of the VRAM.
* The memory manager is trivial iand can handle only 1 video-stream.
* ----------
* | |
* | FB |
* | |
* |---------
* | |
* | |
* |--------|
* | Offscr |
* |--------|
*
* VRAM
*
* Results:
* Pointer to the allocated Offscreen memory.
*
* Side effects:
* Updates the Offscreen memory manager meta-data structure.
*
*-----------------------------------------------------------------------------
*/
static VMWAREOffscreenPtr
vmwareOffscreenAllocate(VMWAREPtr pVMWARE, uint32 size)
{
VMWAREOffscreenPtr memptr;
if ((pVMWARE->videoRam - pVMWARE->FbSize - pVMWARE->fbPitch - 7) < size) {
return NULL;
}
memptr = malloc(sizeof(VMWAREOffscreenRec));
if (!memptr) {
return NULL;
}
memptr->size = size;
memptr->offset = (pVMWARE->videoRam - size) & ~7;
VmwareLog(("vmwareOffscreenAllocate: Offset:%x", memptr->offset));
offscreenMgr.size = memptr->size;
offscreenMgr.offset = memptr->offset;
return memptr;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareOffscreenFree --
*
* Frees the allocated offscreen memory.
*
* Results:
* None.
*
* Side effects:
* Updates the Offscreen memory manager meta-data structure.
*
*-----------------------------------------------------------------------------
*/
static void
vmwareOffscreenFree(VMWAREOffscreenPtr memptr)
{
if (memptr) {
free(memptr);
}
offscreenMgr.size = 0;
offscreenMgr.offset = 0;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoEnabled --
*
* Checks if Video FIFO and Escape FIFO cap are enabled.
*
* Results:
* TRUE if required caps are enabled, FALSE otherwise.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
Bool
vmwareVideoEnabled(VMWAREPtr pVMWARE)
{
return ((pVMWARE->vmwareCapability & SVGA_CAP_EXTENDED_FIFO) &&
(pVMWARE->vmwareFIFO[SVGA_FIFO_CAPABILITIES] &
(SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE)));
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoInit --
*
* Initializes Xv support.
*
* Results:
* TRUE on success, FALSE on error.
*
* Side effects:
* Xv support is initialized. Memory is allocated for all supported
* video streams.
*
*-----------------------------------------------------------------------------
*/
Bool
vmwareVideoInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
XF86VideoAdaptorPtr newAdaptor = NULL;
int numAdaptors;
TRACEPOINT
vmwareOffscreenInit();
numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
newAdaptor = vmwareVideoSetup(pScrn);
if (!newAdaptor) {
VmwareLog(("Failed to initialize Xv extension \n"));
return FALSE;
}
if (!numAdaptors) {
numAdaptors = 1;
overlayAdaptors = &newAdaptor;
} else {
newAdaptors = malloc((numAdaptors + 1) *
sizeof(XF86VideoAdaptorPtr*));
if (!newAdaptors) {
xf86XVFreeVideoAdaptorRec(newAdaptor);
return FALSE;
}
memcpy(newAdaptors, overlayAdaptors,
numAdaptors * sizeof(XF86VideoAdaptorPtr));
newAdaptors[numAdaptors++] = newAdaptor;
overlayAdaptors = newAdaptors;
}
if (!xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors)) {
VmwareLog(("Failed to initialize Xv extension\n"));
xf86XVFreeVideoAdaptorRec(newAdaptor);
return FALSE;
}
if (newAdaptors) {
free(newAdaptors);
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Initialized VMware Xv extension successfully.\n");
return TRUE;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoEnd --
*
* Unitializes video.
*
* Results:
* None.
*
* Side effects:
* pVMWARE->videoStreams = NULL
*
*-----------------------------------------------------------------------------
*/
void
vmwareVideoEnd(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
VMWAREVideoPtr pVid;
int i;
TRACEPOINT
/*
* Video streams are allocated after the DevUnion array
* (see VideoSetup)
*/
pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS];
for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
vmwareVideoEndStream(pScrn, &pVid[i]);
REGION_UNINIT(pScreen, &pVid[i].clipBoxes);
}
free(pVMWARE->videoStreams);
pVMWARE->videoStreams = NULL;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoSetup --
*
* Initializes a XF86VideoAdaptor structure with the capabilities and
* functions supported by this video driver.
*
* Results:
* On success initialized XF86VideoAdaptor struct or NULL on error
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static XF86VideoAdaptorPtr
vmwareVideoSetup(ScrnInfoPtr pScrn)
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
XF86VideoAdaptorPtr adaptor;
VMWAREVideoPtr pPriv;
DevUnion *du;
int i;
TRACEPOINT
adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
if (!adaptor) {
VmwareLog(("Not enough memory\n"));
return NULL;
}
du = calloc(1, VMWARE_VID_NUM_PORTS *
(sizeof(DevUnion) + sizeof(VMWAREVideoRec)));
if (!du) {
VmwareLog(("Not enough memory.\n"));
xf86XVFreeVideoAdaptorRec(adaptor);
return NULL;
}
adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
adaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
adaptor->name = xv_adapt_name;
adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
adaptor->pEncodings = vmwareVideoEncodings;
adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
adaptor->pFormats = vmwareVideoFormats;
adaptor->nPorts = VMWARE_VID_NUM_PORTS;
pPriv = (VMWAREVideoPtr) &du[VMWARE_VID_NUM_PORTS];
adaptor->pPortPrivates = du;
for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
pPriv[i].streamId = i;
pPriv[i].play = vmwareVideoInitStream;
pPriv[i].flags = SVGA_VIDEO_FLAG_COLORKEY;
pPriv[i].colorKey = VMWARE_VIDEO_COLORKEY;
pPriv[i].isAutoPaintColorkey = TRUE;
REGION_NULL(pScreen, &pPriv[i].clipBoxes);
adaptor->pPortPrivates[i].ptr = &pPriv[i];
}
pVMWARE->videoStreams = du;
adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
adaptor->pAttributes = vmwareVideoAttributes;
adaptor->nImages = VMWARE_VID_NUM_IMAGES;
adaptor->pImages = vmwareVideoImages;
adaptor->PutVideo = NULL;
adaptor->PutStill = NULL;
adaptor->GetVideo = NULL;
adaptor->GetStill = NULL;
adaptor->StopVideo = vmwareStopVideo;
adaptor->SetPortAttribute = vmwareSetPortAttribute;
adaptor->GetPortAttribute = vmwareGetPortAttribute;
adaptor->QueryBestSize = vmwareQueryBestSize;
adaptor->PutImage = vmwareXvPutImage;
adaptor->QueryImageAttributes = vmwareQueryImageAttributes;
return adaptor;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoInitStream --
*
* Initializes a video stream in response to the first PutImage() on a
* video stream. The process goes as follows:
* - Figure out characteristics according to format
* - Allocate offscreen memory
* - Pass on video to Play() functions
*
* Results:
* Success or XvBadAlloc on failure.
*
* Side effects:
* Video stream is initialized and its first frame sent to the host
* (done by VideoPlay() function called at the end)
*
*-----------------------------------------------------------------------------
*/
static int
vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes,
DrawablePtr draw)
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
int i;
TRACEPOINT
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Initializing Xv video-stream with id:%d format:%d\n",
pVid->streamId, format);
pVid->size = vmwareVideoInitAttributes(pScrn, pVid, format, width,
height);
if (pVid->size == -1) {
VmwareLog(("Could not initialize 0x%x video stream\n", format));
return XvBadAlloc;
}
pVid->play = vmwareVideoPlay;
pVid->fbarea = vmwareOffscreenAllocate(pVMWARE,
pVid->size * VMWARE_VID_NUM_BUFFERS);
if (!pVid->fbarea) {
VmwareLog(("Could not allocate offscreen memory\n"));
vmwareVideoEndStream(pScrn, pVid);
return BadAlloc;
}
pVid->bufs[0].dataOffset = pVid->fbarea->offset;
pVid->bufs[0].data = pVMWARE->FbBase + pVid->bufs[0].dataOffset;
for (i = 1; i < VMWARE_VID_NUM_BUFFERS; ++i) {
pVid->bufs[i].dataOffset = pVid->bufs[i-1].dataOffset + pVid->size;
pVid->bufs[i].data = pVMWARE->FbBase + pVid->bufs[i].dataOffset;
}
pVid->currBuf = 0;
REGION_COPY(pScrn->pScreen, &pVid->clipBoxes, clipBoxes);
if (pVid->isAutoPaintColorkey) {
BoxPtr boxes = REGION_RECTS(&pVid->clipBoxes);
int nBoxes = REGION_NUM_RECTS(&pVid->clipBoxes);
#if HAVE_FILLKEYHELPERDRAWABLE
if (draw->type == DRAWABLE_WINDOW) {
xf86XVFillKeyHelperDrawable(draw, pVid->colorKey, clipBoxes);
DamageDamageRegion(draw, clipBoxes);
} else {
xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes);
}
#else
xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes);
#endif
/**
* Force update to paint the colorkey before the overlay flush.
*/
while(nBoxes--)
vmwareSendSVGACmdUpdate(pVMWARE, boxes++);
}
VmwareLog(("Got offscreen region, offset %d, size %d "
"(yuv size in bytes: %d)\n",
pVid->fbarea->offset, pVid->fbarea->size, pVid->size));
return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h,
drw_w, drw_h, format, buf, width, height, clipBoxes,
draw);
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoInitAttributes --
*
* Fetches the format specific attributes using QueryImageAttributes().
*
* Results:
* size of the YUV frame on success and -1 on error.
*
* Side effects:
* The video stream gets the format specific attributes(fmtData).
*
*-----------------------------------------------------------------------------
*/
static int
vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
int format, unsigned short width,
unsigned short height)
{
int size;
VMWAREVideoFmtData *fmtData;
TRACEPOINT
fmtData = calloc(1, sizeof(VMWAREVideoFmtData));
if (!fmtData) {
return -1;
}
size = vmwareQueryImageAttributes(pScrn, format, &width, &height,
fmtData->pitches, fmtData->offsets);
if (size == -1) {
free(fmtData);
return -1;
}
pVid->fmt_priv = fmtData;
return size;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoPlay --
*
* Sends all the attributes associated with the video frame using the
* FIFO ESCAPE mechanism to the host.
*
* Results:
* Always returns Success.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
short src_x, short src_y, short drw_x,
short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width,
short height, RegionPtr clipBoxes,
DrawablePtr draw)
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
uint32 *fifoItem;
int i, regId;
struct PACKED _item {
uint32 regId;
uint32 value;
};
struct PACKED _body {
uint32 escape;
uint32 streamId;
/* Old hosts can not handle more then these regs */
struct _item items[SVGA_VIDEO_DATA_GMRID];
};
struct PACKED _cmdSetRegs {
uint32 cmd;
uint32 nsid;
uint32 size;
struct _body body;
};
struct _cmdSetRegs cmdSetRegs;
struct _item *items;
int size;
VMWAREVideoFmtData *fmtData;
unsigned short w, h;
w = width;
h = height;
fmtData = pVid->fmt_priv;
size = vmwareQueryImageAttributes(pScrn, format, &w, &h,
fmtData->pitches, fmtData->offsets);
if (size > pVid->size) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Increase in size of Xv video "
"frame streamId:%d.\n", pVid->streamId);
vmwareStopVideo(pScrn, pVid, TRUE);
return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w,
src_h, drw_w, drw_h, format, buf, width, height,
clipBoxes, draw);
}
pVid->size = size;
memcpy(pVid->bufs[pVid->currBuf].data, buf, pVid->size);
cmdSetRegs.cmd = SVGA_CMD_ESCAPE;
cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE;
cmdSetRegs.size = sizeof(cmdSetRegs.body);
cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
cmdSetRegs.body.streamId = pVid->streamId;
items = cmdSetRegs.body.items;
for (i = SVGA_VIDEO_ENABLED; i < SVGA_VIDEO_DATA_GMRID; i++) {
items[i].regId = i;
}
items[SVGA_VIDEO_ENABLED].value = TRUE;
items[SVGA_VIDEO_DATA_OFFSET].value =
pVid->bufs[pVid->currBuf].dataOffset;
items[SVGA_VIDEO_SIZE].value = pVid->size;
items[SVGA_VIDEO_FORMAT].value = format;
items[SVGA_VIDEO_WIDTH].value = w;
items[SVGA_VIDEO_HEIGHT].value = h;
items[SVGA_VIDEO_SRC_X].value = src_x;
items[SVGA_VIDEO_SRC_Y].value = src_y;
items[SVGA_VIDEO_SRC_WIDTH].value = src_w;
items[SVGA_VIDEO_SRC_HEIGHT].value = src_h;
items[SVGA_VIDEO_DST_X].value = drw_x;
items[SVGA_VIDEO_DST_Y].value = drw_y;
items[SVGA_VIDEO_DST_WIDTH]. value = drw_w;
items[SVGA_VIDEO_DST_HEIGHT].value = drw_h;
items[SVGA_VIDEO_COLORKEY].value = pVid->colorKey;
items[SVGA_VIDEO_FLAGS].value = pVid->flags;
for (i = 0, regId = SVGA_VIDEO_PITCH_1; i < 3; i++, regId++) {
items[regId].value = fmtData->pitches[i];
}
fifoItem = (uint32 *) &cmdSetRegs;
for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) {
vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
}
/*
* Update the clipList and paint the colorkey, if required.
*/
if (!vmwareIsRegionEqual(&pVid->clipBoxes, clipBoxes)) {
REGION_COPY(pScrn->pScreen, &pVid->clipBoxes, clipBoxes);
if (pVid->isAutoPaintColorkey) {
BoxPtr boxes = REGION_RECTS(&pVid->clipBoxes);
int nBoxes = REGION_NUM_RECTS(&pVid->clipBoxes);
#if HAVE_FILLKEYHELPERDRAWABLE
xf86XVFillKeyHelperDrawable(draw, pVid->colorKey, clipBoxes);
#else
xf86XVFillKeyHelper(pScrn->pScreen, pVid->colorKey, clipBoxes);
#endif
/**
* Force update to paint the colorkey before the overlay flush.
*/
while(nBoxes--)
vmwareSendSVGACmdUpdate(pVMWARE, boxes++);
}
}
vmwareVideoFlush(pVMWARE, pVid->streamId);
pVid->currBuf = ++pVid->currBuf & (VMWARE_VID_NUM_BUFFERS - 1);
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoFlush --
*
* Sends the VIDEO_FLUSH command (FIFO ESCAPE mechanism) asking the host
* to play the video stream or end it.
*
* Results:
* None.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static void
vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId)
{
struct PACKED _body {
uint32 escape;
uint32 streamId;
};
struct PACKED _cmdFlush {
uint32 cmd;
uint32 nsid;
uint32 size;
struct _body body;
};
struct _cmdFlush cmdFlush;
uint32 *fifoItem;
int i;
cmdFlush.cmd = SVGA_CMD_ESCAPE;
cmdFlush.nsid = SVGA_ESCAPE_NSID_VMWARE;
cmdFlush.size = sizeof(cmdFlush.body);
cmdFlush.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH;
cmdFlush.body.streamId = streamId;
fifoItem = (uint32 *) &cmdFlush;
for (i = 0; i < sizeof(cmdFlush) / sizeof(uint32); i++) {
vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
}
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoSetOneReg --
*
* Sets one video register using the FIFO ESCAPE mechanidm.
*
* Results:
* None.
*
* Side effects:
* None.
*-----------------------------------------------------------------------------
*/
static void
vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId,
uint32 regId, uint32 value)
{
struct PACKED _item {
uint32 regId;
uint32 value;
};
struct PACKED _body {
uint32 escape;
uint32 streamId;
struct _item item;
};
struct PACKED _cmdSetRegs {
uint32 cmd;
uint32 nsid;
uint32 size;
struct _body body;
};
struct _cmdSetRegs cmdSetRegs;
int i;
uint32 *fifoItem;
cmdSetRegs.cmd = SVGA_CMD_ESCAPE;
cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE;
cmdSetRegs.size = sizeof(cmdSetRegs.body);
cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
cmdSetRegs.body.streamId = streamId;
cmdSetRegs.body.item.regId = regId;
cmdSetRegs.body.item.value = value;
fifoItem = (uint32 *) &cmdSetRegs;
for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) {
vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
}
}
/*
*-----------------------------------------------------------------------------
*
* vmwareVideoEndStream --
*
* Frees up all resources (if any) taken by a video stream.
*
* Results:
* None.
*
* Side effects:
* Same as above.
*
*-----------------------------------------------------------------------------
*/
static void
vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid)
{
uint32 id, colorKey, flags;
Bool isAutoPaintColorkey;
if (pVid->fmt_priv) {
free(pVid->fmt_priv);
}
if (pVid->fbarea) {
vmwareOffscreenFree(pVid->fbarea);
pVid->fbarea = NULL;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Terminating Xv video-stream id:%d\n", pVid->streamId);
/*
* reset stream for next video
*/
id = pVid->streamId;
colorKey = pVid->colorKey;
flags = pVid->flags;
isAutoPaintColorkey = pVid->isAutoPaintColorkey;
memset(pVid, 0, sizeof(*pVid));
pVid->streamId = id;
pVid->play = vmwareVideoInitStream;
pVid->colorKey = colorKey;
pVid->flags = flags;
pVid->isAutoPaintColorkey = isAutoPaintColorkey;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareXvPutImage --
*
* Main video playback function. It copies the passed data which is in
* the specified format (e.g. FOURCC_YV12) into the overlay.
*
* If sync is TRUE the driver should not return from this
* function until it is through reading the data from buf.
*
* There are two function prototypes to cope with the API change in X.org
* 7.1
*
* Results:
* Success or XvBadAlloc on failure
*
* Side effects:
* Video stream will be played(initialized if 1st frame) on success
* or will fail on error.
*
*-----------------------------------------------------------------------------
*/
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1)
static int
vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data,
DrawablePtr dst)
#else
static int
vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
short drw_x, short drw_y, short src_w, short src_h,
short drw_w, short drw_h, int format,
unsigned char *buf, short width, short height,
Bool sync, RegionPtr clipBoxes, pointer data)
#endif
{
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
VMWAREVideoPtr pVid = data;
TRACEPOINT
if (!vmwareVideoEnabled(pVMWARE)) {
return XvBadAlloc;
}
#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 1)
return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h,
drw_w, drw_h, format, buf, width, height, clipBoxes,
dst);
#else
return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h,
drw_w, drw_h, format, buf, width, height, clipBoxes,
NULL);
#endif
}
/*
*-----------------------------------------------------------------------------
*
* vmwareStopVideo --
*
* Called when we should stop playing video for a particular stream. If
* Cleanup is FALSE, the "stop" operation is only temporary, and thus we
* don't do anything. If Cleanup is TRUE we kill the video stream by
* sending a message to the host and freeing up the stream.
*
* Results:
* None.
*
* Side effects:
* See above.
*
*-----------------------------------------------------------------------------
*/
static void
vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup)
{
VMWAREVideoPtr pVid = data;
VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
TRACEPOINT
if (!vmwareVideoEnabled(pVMWARE)) {
return;
}
REGION_EMPTY(pScrn->pScreen, &pVid->clipBoxes);
if (!Cleanup) {
VmwareLog(("vmwareStopVideo: Cleanup is FALSE.\n"));
return;
}
vmwareVideoSetOneReg(pVMWARE, pVid->streamId,
SVGA_VIDEO_ENABLED, FALSE);
vmwareVideoFlush(pVMWARE, pVid->streamId);
vmwareVideoEndStream(pScrn, pVid);
}
/*
*-----------------------------------------------------------------------------
*
* vmwareQueryImageAttributes --
*
* From the spec: This function is called to let the driver specify how data
* for a particular image of size width by height should be stored.
* Sometimes only the size and corrected width and height are needed. In
* that case pitches and offsets are NULL.
*
* Results:
* The size of the memory required for the image, or -1 on error.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format,
unsigned short *width, unsigned short *height,
int *pitches, int *offsets)
{
INT32 size, tmp;
TRACEPOINT
if (*width > VMWARE_VID_MAX_WIDTH) {
*width = VMWARE_VID_MAX_WIDTH;
}
if (*height > VMWARE_VID_MAX_HEIGHT) {
*height = VMWARE_VID_MAX_HEIGHT;
}
*width = (*width + 1) & ~1;
if (offsets != NULL) {
offsets[0] = 0;
}
switch (format) {
case FOURCC_YV12:
*height = (*height + 1) & ~1;
size = (*width + 3) & ~3;
if (pitches) {
pitches[0] = size;
}
size *= *height;
if (offsets) {
offsets[1] = size;
}
tmp = ((*width >> 1) + 3) & ~3;
if (pitches) {
pitches[1] = pitches[2] = tmp;
}
tmp *= (*height >> 1);
size += tmp;
if (offsets) {
offsets[2] = size;
}
size += tmp;
break;
case FOURCC_UYVY:
case FOURCC_YUY2:
size = *width * 2;
if (pitches) {
pitches[0] = size;
}
size *= *height;
break;
default:
VmwareLog(("Query for invalid video format %d\n", format));
return -1;
}
return size;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareSetPortAttribute --
*
* From the spec: A port may have particular attributes such as colorKey, hue,
* saturation, brightness or contrast. Xv clients set these
* attribute values by sending attribute strings (Atoms) to the server.
*
* Results:
* Success if the attribute exists and XvBadAlloc otherwise.
*
* Side effects:
* The respective attribute gets the new value.
*
*-----------------------------------------------------------------------------
*/
static int
vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 value, pointer data)
{
VMWAREVideoPtr pVid = (VMWAREVideoPtr) data;
Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
if (attribute == xvColorKey) {
VmwareLog(("Set colorkey:0x%x\n", value));
pVid->colorKey = value;
} else if (attribute == xvAutoPaint) {
VmwareLog(("Set autoPaint: %s\n", value? "TRUE": "FALSE"));
pVid->isAutoPaintColorkey = value;
} else {
return XvBadAlloc;
}
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareGetPortAttribute --
*
* From the spec: A port may have particular attributes such as hue,
* saturation, brightness or contrast. Xv clients get these
* attribute values by sending attribute strings (Atoms) to the server
*
* Results:
* Success if the attribute exists and XvBadAlloc otherwise.
*
* Side effects:
* "value" contains the requested attribute on success.
*
*-----------------------------------------------------------------------------
*/
static int
vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
INT32 *value, pointer data)
{
VMWAREVideoPtr pVid = (VMWAREVideoPtr) data;
Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
if (attribute == xvColorKey) {
*value = pVid->colorKey;
} else if (attribute == xvAutoPaint) {
*value = pVid->isAutoPaintColorkey;
} else {
return XvBadAlloc;
}
return Success;
}
/*
*-----------------------------------------------------------------------------
*
* vmwareQueryBestSize --
*
* From the spec: QueryBestSize provides the client with a way to query what
* the destination dimensions would end up being if they were to request
* that an area vid_w by vid_h from the video stream be scaled to rectangle
* of drw_w by drw_h on the screen. Since it is not expected that all
* hardware will be able to get the target dimensions exactly, it is
* important that the driver provide this function.
*
* This function seems to never be called, but to be on the safe side
* we apply the same logic that QueryImageAttributes has for width
* and height
*
* Results:
* None.
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static void
vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
short vid_w, short vid_h, short drw_w,
short drw_h, unsigned int *p_w,
unsigned int *p_h, pointer data)
{
*p_w = (drw_w + 1) & ~1;
*p_h = drw_h;
return;
}