vmwarevideo.c revision 6df26cac
1/*
2 * Copyright 2007 by VMware, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the copyright holder(s)
23 * and author(s) shall not be used in advertising or otherwise to promote
24 * the sale, use or other dealings in this Software without prior written
25 * authorization from the copyright holder(s) and author(s).
26 */
27
28/*
29 * vmwarevideo.c --
30 *
31 *      Xv extension support.
32 *      See http://www.xfree86.org/current/DESIGN16.html
33 *
34 */
35
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include "vmware.h"
42#include "xf86xv.h"
43#include "fourcc.h"
44#include "svga_escape.h"
45#include "svga_overlay.h"
46
47#include <X11/extensions/Xv.h>
48/*
49 * Need this to figure out which prototype to use for XvPutImage
50 */
51#include "xorgVersion.h"
52
53#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
54
55/*
56 * Used to pack structs
57 */
58#define PACKED __attribute__((__packed__))
59
60/*
61 * Number of videos that can be played simultaneously
62 */
63#define VMWARE_VID_NUM_PORTS 1
64
65/*
66 * Using green as the default colorKey
67 */
68#define VMWARE_VIDEO_COLORKEY 0x00ff00
69
70/*
71 * Maximum dimensions
72 */
73#define VMWARE_VID_MAX_WIDTH    2048
74#define VMWARE_VID_MAX_HEIGHT   2048
75
76#define VMWARE_VID_NUM_ENCODINGS 1
77static XF86VideoEncodingRec vmwareVideoEncodings[] =
78{
79    {
80       0,
81       "XV_IMAGE",
82       VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT,
83       {1, 1}
84    }
85};
86
87#define VMWARE_VID_NUM_FORMATS 2
88static XF86VideoFormatRec vmwareVideoFormats[] =
89{
90    { 16, TrueColor},
91    { 24, TrueColor}
92};
93
94#define VMWARE_VID_NUM_IMAGES 2
95static XF86ImageRec vmwareVideoImages[] =
96{
97    XVIMAGE_YV12,
98    XVIMAGE_YUY2
99};
100
101#define VMWARE_VID_NUM_ATTRIBUTES 1
102static XF86AttributeRec vmwareVideoAttributes[] =
103{
104    {
105        XvGettable | XvSettable,
106        0x000000,
107        0xffffff,
108        "XV_COLORKEY"
109    }
110};
111
112/*
113 * Video frames are stored in a circular list of buffers.
114 */
115#define VMWARE_VID_NUM_BUFFERS 1
116/*
117 * Defines the structure used to hold and pass video data to the host
118 */
119typedef struct {
120   uint32  dataOffset;
121   pointer data;
122} VMWAREVideoBuffer;
123
124typedef struct {
125   uint32 size;
126   uint32 offset;
127} VMWAREOffscreenRec, *VMWAREOffscreenPtr;
128
129/*
130 * Trivial offscreen manager that allocates memory from the
131 * bottom of the VRAM.
132 */
133static VMWAREOffscreenRec offscreenMgr;
134
135/*
136 * structs that reside in fmt_priv.
137 */
138typedef struct {
139    int pitches[3];
140    int offsets[3];
141} VMWAREVideoFmtData;
142
143/*
144 * Structure representing a specific video stream.
145 */
146struct VMWAREVideoRec {
147   uint32             streamId;
148   /*
149    * Function prototype same as XvPutImage.
150    */
151   int                (*play)(ScrnInfoPtr, struct VMWAREVideoRec *,
152                              short, short, short, short, short,
153                              short, short, short, int, unsigned char*,
154                              short, short);
155   /*
156    * Offscreen memory region used to pass video data to the host.
157    */
158   VMWAREOffscreenPtr fbarea;
159   VMWAREVideoBuffer  bufs[VMWARE_VID_NUM_BUFFERS];
160   uint8              currBuf;
161   uint32             size;
162   uint32             colorKey;
163   uint32             flags;
164   VMWAREVideoFmtData *fmt_priv;
165};
166
167typedef struct VMWAREVideoRec VMWAREVideoRec;
168typedef VMWAREVideoRec *VMWAREVideoPtr;
169
170/*
171 * Callback functions
172 */
173#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(7, 0, 0, 0, 0) || XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(2, 0, 0, 0, 0)
174static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
175                            short drw_x, short drw_y, short src_w, short src_h,
176                            short drw_w, short drw_h, int image,
177                            unsigned char *buf, short width, short height,
178                            Bool sync, RegionPtr clipBoxes, pointer data,
179                            DrawablePtr dst);
180#else
181static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
182                            short drw_x, short drw_y, short src_w, short src_h,
183                            short drw_w, short drw_h, int image,
184                            unsigned char *buf, short width, short height,
185                            Bool sync, RegionPtr clipBoxes, pointer data);
186#endif
187static void vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
188static int vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format,
189                                      unsigned short *width,
190                                      unsigned short *height, int *pitches,
191                                      int *offsets);
192static int vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
193                                  INT32 value, pointer data);
194static int vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
195                                  INT32 *value, pointer data);
196static void vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
197                                short vid_w, short vid_h, short drw_w,
198                                short drw_h, unsigned int *p_w,
199                                unsigned int *p_h, pointer data);
200
201/*
202 * Local functions for video streams
203 */
204static XF86VideoAdaptorPtr vmwareVideoSetup(ScrnInfoPtr pScrn);
205static int vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
206                                 short src_x, short src_y, short drw_x,
207                                 short drw_y, short src_w, short src_h,
208                                 short drw_w, short drw_h, int format,
209                                 unsigned char *buf, short width, short height);
210static int vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
211                                     int format, unsigned short width,
212                                     unsigned short height);
213static int vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
214                           short src_x, short src_y, short drw_x,
215                           short drw_y, short src_w, short src_h,
216                           short drw_w, short drw_h, int format,
217                           unsigned char *buf, short width,
218                           short height);
219static void vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId);
220static void vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId,
221                                 uint32 regId, uint32 value);
222static void vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid);
223
224/*
225 * Offscreen memory manager functions
226 */
227static void vmwareOffscreenInit(void);
228static VMWAREOffscreenPtr vmwareOffscreenAllocate(VMWAREPtr pVMWARE,
229                                                  uint32 size);
230static void vmwareOffscreenFree(VMWAREOffscreenPtr memptr);
231
232
233/*
234 *-----------------------------------------------------------------------------
235 *
236 * vmwareCheckVideoSanity --
237 *
238 *    Ensures that on ModeSwitch the offscreen memory used
239 *    by the Xv streams doesn't become part of the guest framebuffer.
240 *
241 * Results:
242 *    None
243 *
244 * Side effects:
245 *    If it is found that the offscreen used by video streams  lies
246 *    within the range of the framebuffer(after ModeSwitch) then the video
247 *    streams will be stopped.
248 *
249 *-----------------------------------------------------------------------------
250 */
251
252void
253vmwareCheckVideoSanity(ScrnInfoPtr pScrn)
254{
255    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
256    VMWAREVideoPtr pVid;
257
258   if (offscreenMgr.size == 0 ||
259       offscreenMgr.offset > pVMWARE->FbSize) {
260       return ;
261   }
262
263   pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS];
264   vmwareStopVideo(pScrn, pVid, TRUE);
265}
266
267
268/*
269 *-----------------------------------------------------------------------------
270 *
271 * vmwareOffscreenInit --
272 *
273 *    Initializes the trivial Offscreen memory manager.
274 *
275 * Results:
276 *    None.
277 *
278 * Side effects:
279 *    Initializes the Offscreen manager meta-data structure.
280 *
281 *-----------------------------------------------------------------------------
282 */
283
284static void
285vmwareOffscreenInit(void)
286{
287    offscreenMgr.size = 0;
288    offscreenMgr.offset  = 0;
289}
290
291
292/*
293 *-----------------------------------------------------------------------------
294 *
295 * vmwareOffscreenAllocate --
296 *
297 *    Allocates offscreen memory.
298 *    Memory is allocated from the bottom part of the VRAM.
299 *    The memory manager is trivial iand can handle only 1 video-stream.
300 *    ----------
301 *    |        |
302 *    |  FB    |
303 *    |        |
304 *    |---------
305 *    |        |
306 *    |        |
307 *    |--------|
308 *    | Offscr |
309 *    |--------|
310 *
311 *      VRAM
312 *
313 * Results:
314 *    Pointer to the allocated Offscreen memory.
315 *
316 * Side effects:
317 *    Updates the Offscreen memory manager meta-data structure.
318 *
319 *-----------------------------------------------------------------------------
320 */
321
322static VMWAREOffscreenPtr
323vmwareOffscreenAllocate(VMWAREPtr pVMWARE, uint32 size)
324{
325    VMWAREOffscreenPtr memptr;
326
327    if ((pVMWARE->videoRam - pVMWARE->FbSize - pVMWARE->fbPitch - 7) < size) {
328        return NULL;
329    }
330
331    memptr = xalloc(sizeof(VMWAREOffscreenRec));
332    if (!memptr) {
333        return NULL;
334    }
335    memptr->size = size;
336    memptr->offset  = (pVMWARE->videoRam - size) & ~7;
337
338    VmwareLog(("vmwareOffscreenAllocate: Offset:%x", memptr->offset));
339
340    offscreenMgr.size = memptr->size;
341    offscreenMgr.offset = memptr->offset;
342    return memptr;
343}
344
345
346/*
347 *-----------------------------------------------------------------------------
348 *
349 * vmwareOffscreenFree --
350 *
351 *    Frees the allocated offscreen memory.
352 *
353 * Results:
354 *    None.
355 *
356 * Side effects:
357 *    Updates the Offscreen memory manager meta-data structure.
358 *
359 *-----------------------------------------------------------------------------
360 */
361
362static void
363vmwareOffscreenFree(VMWAREOffscreenPtr memptr)
364{
365    if (memptr) {
366        free(memptr);
367    }
368
369    offscreenMgr.size = 0;
370    offscreenMgr.offset = 0;
371}
372
373
374/*
375 *-----------------------------------------------------------------------------
376 *
377 * vmwareVideoEnabled --
378 *
379 *    Checks if Video FIFO and Escape FIFO cap are enabled.
380 *
381 * Results:
382 *    TRUE if required caps are enabled, FALSE otherwise.
383 *
384 * Side effects:
385 *    None.
386 *
387 *-----------------------------------------------------------------------------
388 */
389
390Bool vmwareVideoEnabled(VMWAREPtr pVMWARE)
391{
392    return ((pVMWARE->vmwareCapability & SVGA_CAP_EXTENDED_FIFO) &&
393            (pVMWARE->vmwareFIFO[SVGA_FIFO_CAPABILITIES] &
394             (SVGA_FIFO_CAP_VIDEO | SVGA_FIFO_CAP_ESCAPE)));
395}
396
397
398/*
399 *-----------------------------------------------------------------------------
400 *
401 * vmwareVideoInit --
402 *
403 *    Initializes Xv support.
404 *
405 * Results:
406 *    TRUE on success, FALSE on error.
407 *
408 * Side effects:
409 *    Xv support is initialized. Memory is allocated for all supported
410 *    video streams.
411 *
412 *-----------------------------------------------------------------------------
413 */
414
415Bool vmwareVideoInit(ScreenPtr pScreen)
416{
417    ScrnInfoPtr pScrn = infoFromScreen(pScreen);
418    XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
419    XF86VideoAdaptorPtr newAdaptor = NULL;
420    int numAdaptors;
421
422    TRACEPOINT
423
424    vmwareOffscreenInit();
425
426    numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
427
428    newAdaptor = vmwareVideoSetup(pScrn);
429    if (!newAdaptor) {
430        VmwareLog(("Failed to initialize Xv extension \n"));
431        return FALSE;
432    }
433
434    if (!numAdaptors) {
435        numAdaptors = 1;
436        overlayAdaptors = &newAdaptor;
437    } else {
438         newAdaptors = xalloc((numAdaptors + 1) *
439                              sizeof(XF86VideoAdaptorPtr*));
440         if (!newAdaptors) {
441            xf86XVFreeVideoAdaptorRec(newAdaptor);
442            return FALSE;
443         }
444
445         memcpy(newAdaptors, overlayAdaptors,
446                numAdaptors * sizeof(XF86VideoAdaptorPtr));
447         newAdaptors[numAdaptors++] = newAdaptor;
448         overlayAdaptors = newAdaptors;
449    }
450
451    if (!xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors)) {
452        VmwareLog(("Failed to initialize Xv extension\n"));
453        xf86XVFreeVideoAdaptorRec(newAdaptor);
454        return FALSE;
455    }
456
457    if (newAdaptors) {
458        xfree(newAdaptors);
459    }
460
461    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
462               "Initialized VMware Xv extension successfully.\n");
463    return TRUE;
464}
465
466
467/*
468 *-----------------------------------------------------------------------------
469 *
470 * vmwareVideoEnd --
471 *
472 *    Unitializes video.
473 *
474 * Results:
475 *    None.
476 *
477 * Side effects:
478 *    pVMWARE->videoStreams = NULL
479 *
480 *-----------------------------------------------------------------------------
481 */
482
483void vmwareVideoEnd(ScreenPtr pScreen)
484{
485    ScrnInfoPtr pScrn = infoFromScreen(pScreen);
486    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
487    VMWAREVideoPtr pVid;
488    int i;
489
490    TRACEPOINT
491
492    /*
493     * Video streams are allocated after the DevUnion array
494     * (see VideoSetup)
495     */
496    pVid = (VMWAREVideoPtr) &pVMWARE->videoStreams[VMWARE_VID_NUM_PORTS];
497    for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
498        vmwareVideoEndStream(pScrn, &pVid[i]);
499    }
500
501    free(pVMWARE->videoStreams);
502    pVMWARE->videoStreams = NULL;
503}
504
505
506/*
507 *-----------------------------------------------------------------------------
508 *
509 * vmwareVideoSetup --
510 *
511 *    Initializes a XF86VideoAdaptor structure with the capabilities and
512 *    functions supported by this video driver.
513 *
514 * Results:
515 *    On success initialized XF86VideoAdaptor struct or NULL on error
516 *
517 * Side effects:
518 *    None.
519 *
520 *-----------------------------------------------------------------------------
521 */
522
523static XF86VideoAdaptorPtr vmwareVideoSetup(ScrnInfoPtr pScrn)
524{
525    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
526    XF86VideoAdaptorPtr adaptor;
527    VMWAREVideoPtr pPriv;
528    DevUnion *du;
529    int i;
530
531    TRACEPOINT
532
533    adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
534    if (!adaptor) {
535        VmwareLog(("Not enough memory\n"));
536        return NULL;
537    }
538    du = xcalloc(1, VMWARE_VID_NUM_PORTS *
539        (sizeof(DevUnion) + sizeof(VMWAREVideoRec)));
540
541    if (!du) {
542        VmwareLog(("Not enough memory.\n"));
543        xf86XVFreeVideoAdaptorRec(adaptor);
544        return NULL;
545    }
546
547    adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
548    adaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
549    adaptor->name = "VMware Video Engine";
550    adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
551    adaptor->pEncodings = vmwareVideoEncodings;
552    adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
553    adaptor->pFormats = vmwareVideoFormats;
554    adaptor->nPorts = VMWARE_VID_NUM_PORTS;
555
556    pPriv = (VMWAREVideoPtr) &du[VMWARE_VID_NUM_PORTS];
557    adaptor->pPortPrivates = du;
558
559    for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
560        pPriv[i].streamId = i;
561        pPriv[i].play = vmwareVideoInitStream;
562        pPriv[i].flags = SVGA_VIDEO_FLAG_COLORKEY;
563        pPriv[i].colorKey = VMWARE_VIDEO_COLORKEY;
564        adaptor->pPortPrivates[i].ptr = &pPriv[i];
565    }
566    pVMWARE->videoStreams = du;
567
568    adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
569    adaptor->pAttributes = vmwareVideoAttributes;
570
571    adaptor->nImages = VMWARE_VID_NUM_IMAGES;
572    adaptor->pImages = vmwareVideoImages;
573
574    adaptor->PutVideo = NULL;
575    adaptor->PutStill = NULL;
576    adaptor->GetVideo = NULL;
577    adaptor->GetStill = NULL;
578    adaptor->StopVideo = vmwareStopVideo;
579    adaptor->SetPortAttribute = vmwareSetPortAttribute;
580    adaptor->GetPortAttribute = vmwareGetPortAttribute;
581    adaptor->QueryBestSize = vmwareQueryBestSize;
582    adaptor->PutImage = vmwareXvPutImage;
583    adaptor->QueryImageAttributes = vmwareQueryImageAttributes;
584
585    return adaptor;
586}
587
588
589/*
590 *-----------------------------------------------------------------------------
591 *
592 * vmwareVideoInitStream --
593 *
594 *    Initializes a video stream in response to the first PutImage() on a
595 *    video stream. The process goes as follows:
596 *    - Figure out characteristics according to format
597 *    - Allocate offscreen memory
598 *    - Pass on video to Play() functions
599 *
600 * Results:
601 *    Success or XvBadAlloc on failure.
602 *
603 * Side effects:
604 *    Video stream is initialized and its first frame sent to the host
605 *    (done by VideoPlay() function called at the end)
606 *
607 *-----------------------------------------------------------------------------
608 */
609
610static int vmwareVideoInitStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
611                                 short src_x, short src_y, short drw_x,
612                                 short drw_y, short src_w, short src_h,
613                                 short drw_w, short drw_h, int format,
614                                 unsigned char *buf, short width, short height)
615{
616    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
617    int i;
618
619    TRACEPOINT
620
621    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
622               "Initializing Xv video-stream with id:%d format:%d\n",
623                pVid->streamId, format);
624
625    pVid->size = vmwareVideoInitAttributes(pScrn, pVid, format, width,
626                                           height);
627
628    if (pVid->size == -1) {
629        VmwareLog(("Could not initialize 0x%x video stream\n", format));
630        return XvBadAlloc;
631    }
632
633    pVid->play = vmwareVideoPlay;
634
635    pVid->fbarea = vmwareOffscreenAllocate(pVMWARE,
636                       pVid->size * VMWARE_VID_NUM_BUFFERS);
637
638    if (!pVid->fbarea) {
639       VmwareLog(("Could not allocate offscreen memory\n"));
640       vmwareVideoEndStream(pScrn, pVid);
641       return BadAlloc;
642    }
643
644    pVid->bufs[0].dataOffset = pVid->fbarea->offset;
645    pVid->bufs[0].data = pVMWARE->FbBase + pVid->bufs[0].dataOffset;
646
647    for (i = 1; i < VMWARE_VID_NUM_BUFFERS; ++i) {
648        pVid->bufs[i].dataOffset = pVid->bufs[i-1].dataOffset + pVid->size;
649        pVid->bufs[i].data = pVMWARE->FbBase + pVid->bufs[i].dataOffset;
650    }
651    pVid->currBuf = 0;
652
653    VmwareLog(("Got offscreen region, offset %d, size %d "
654               "(yuv size in bytes: %d)\n",
655               pVid->fbarea->offset, pVid->fbarea->size, pVid->size));
656
657    return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h,
658                      drw_w, drw_h, format, buf, width, height);
659}
660
661
662/*
663 *-----------------------------------------------------------------------------
664 *
665 * vmwareVideoInitAttributes --
666 *
667 *    Fetches the format specific attributes using QueryImageAttributes().
668 *
669 * Results:
670 *    size of the YUV frame on success and -1 on error.
671 *
672 * Side effects:
673 *    The video stream gets the format specific attributes(fmtData).
674 *
675 *-----------------------------------------------------------------------------
676 */
677
678static int vmwareVideoInitAttributes(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
679                                     int format, unsigned short width,
680                                     unsigned short height)
681{
682    int size;
683    VMWAREVideoFmtData *fmtData;
684
685    TRACEPOINT
686
687    fmtData = xcalloc(1, sizeof(VMWAREVideoFmtData));
688    if (!fmtData) {
689        return -1;
690    }
691
692    size = vmwareQueryImageAttributes(pScrn, format, &width, &height,
693                                      fmtData->pitches, fmtData->offsets);
694    if (size == -1) {
695        free(fmtData);
696        return -1;
697    }
698
699    pVid->fmt_priv = fmtData;
700    return size;
701}
702
703
704/*
705 *-----------------------------------------------------------------------------
706 *
707 * vmwareVideoPlay --
708 *
709 *    Sends all the attributes associated with the video frame using the
710 *    FIFO ESCAPE mechanism to the host.
711 *
712 * Results:
713 *    Always returns Success.
714 *
715 * Side effects:
716 *    None.
717 *
718 *-----------------------------------------------------------------------------
719 */
720
721static int vmwareVideoPlay(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid,
722                           short src_x, short src_y, short drw_x,
723                           short drw_y, short src_w, short src_h,
724                           short drw_w, short drw_h, int format,
725                           unsigned char *buf, short width,
726                           short height)
727{
728    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
729    uint32 *fifoItem;
730    int i, regId;
731    struct PACKED _item {
732        uint32 regId;
733        uint32 value;
734    };
735
736    struct PACKED _body {
737        uint32 escape;
738        uint32 streamId;
739        struct _item items[SVGA_VIDEO_NUM_REGS];
740    };
741
742    struct PACKED _cmdSetRegs {
743        uint32 cmd;
744        uint32 nsid;
745        uint32 size;
746        struct _body body;
747    };
748
749    struct _cmdSetRegs cmdSetRegs;
750    struct _item *items;
751
752    memcpy(pVid->bufs[pVid->currBuf].data, buf, pVid->size);
753
754    cmdSetRegs.cmd = SVGA_CMD_ESCAPE;
755    cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE;
756    cmdSetRegs.size = sizeof(cmdSetRegs.body);
757    cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
758    cmdSetRegs.body.streamId = pVid->streamId;
759
760    items = cmdSetRegs.body.items;
761    for (i = SVGA_VIDEO_ENABLED; i < SVGA_VIDEO_NUM_REGS; i++) {
762        items[i].regId = i;
763    }
764
765    items[SVGA_VIDEO_ENABLED].value = TRUE;
766    items[SVGA_VIDEO_DATA_OFFSET].value =
767        pVid->bufs[pVid->currBuf].dataOffset;
768    items[SVGA_VIDEO_SIZE].value = pVid->size;
769    items[SVGA_VIDEO_FORMAT].value = format;
770    items[SVGA_VIDEO_WIDTH].value = width;
771    items[SVGA_VIDEO_HEIGHT].value = height;
772    items[SVGA_VIDEO_SRC_X].value = src_x;
773    items[SVGA_VIDEO_SRC_Y].value = src_y;
774    items[SVGA_VIDEO_SRC_WIDTH].value = src_w;
775    items[SVGA_VIDEO_SRC_HEIGHT].value = src_h;
776    items[SVGA_VIDEO_DST_X].value = drw_x;
777    items[SVGA_VIDEO_DST_Y].value = drw_y;
778    items[SVGA_VIDEO_DST_WIDTH]. value = drw_w;
779    items[SVGA_VIDEO_DST_HEIGHT].value = drw_h;
780    items[SVGA_VIDEO_COLORKEY].value = pVid->colorKey;
781    items[SVGA_VIDEO_FLAGS].value = pVid->flags;
782
783    for (i = 0, regId = SVGA_VIDEO_PITCH_1; i < 3; i++, regId++) {
784        items[regId].value = pVid->fmt_priv->pitches[i];
785    }
786
787    fifoItem = (uint32 *) &cmdSetRegs;
788    for (i = 0; i <  sizeof(cmdSetRegs) / sizeof(uint32); i++) {
789        vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
790    }
791
792    vmwareVideoFlush(pVMWARE, pVid->streamId);
793
794    pVid->currBuf = ++pVid->currBuf & (VMWARE_VID_NUM_BUFFERS - 1);
795    return Success;
796}
797
798
799/*
800 *-----------------------------------------------------------------------------
801 *
802 * vmwareVideoFlush --
803 *
804 *    Sends the VIDEO_FLUSH command (FIFO ESCAPE mechanism) asking the host
805 *    to play the video stream or end it.
806 *
807 * Results:
808 *    None.
809 *
810 * Side effects:
811 *    None.
812 *
813 *-----------------------------------------------------------------------------
814 */
815
816static void vmwareVideoFlush(VMWAREPtr pVMWARE, uint32 streamId)
817{
818    struct PACKED _body {
819        uint32 escape;
820        uint32 streamId;
821    };
822
823    struct PACKED _cmdFlush {
824        uint32 cmd;
825        uint32 nsid;
826        uint32 size;
827        struct _body body;
828    };
829
830    struct _cmdFlush cmdFlush;
831    uint32 *fifoItem;
832    int i;
833
834    cmdFlush.cmd = SVGA_CMD_ESCAPE;
835    cmdFlush.nsid = SVGA_ESCAPE_NSID_VMWARE;
836    cmdFlush.size = sizeof(cmdFlush.body);
837    cmdFlush.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_FLUSH;
838    cmdFlush.body.streamId = streamId;
839
840    fifoItem = (uint32 *) &cmdFlush;
841    for (i = 0; i < sizeof(cmdFlush) / sizeof(uint32); i++) {
842        vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
843    }
844}
845
846
847/*
848 *-----------------------------------------------------------------------------
849 *
850 * vmwareVideoSetOneReg --
851 *
852 *    Sets one video register using the FIFO ESCAPE mechanidm.
853 *
854 * Results:
855 *    None.
856 *
857 * Side effects:
858 *    None.
859 *-----------------------------------------------------------------------------
860 */
861
862static void vmwareVideoSetOneReg(VMWAREPtr pVMWARE, uint32 streamId,
863                                 uint32 regId, uint32 value)
864{
865    struct PACKED _item {
866        uint32 regId;
867        uint32 value;
868    };
869
870    struct PACKED _body {
871        uint32 escape;
872        uint32 streamId;
873        struct _item item;
874    };
875
876    struct PACKED _cmdSetRegs {
877        uint32 cmd;
878        uint32 nsid;
879        uint32 size;
880        struct _body body;
881    };
882
883    struct _cmdSetRegs cmdSetRegs;
884    int i;
885    uint32 *fifoItem;
886
887    cmdSetRegs.cmd = SVGA_CMD_ESCAPE;
888    cmdSetRegs.nsid = SVGA_ESCAPE_NSID_VMWARE;
889    cmdSetRegs.size = sizeof(cmdSetRegs.body);
890    cmdSetRegs.body.escape = SVGA_ESCAPE_VMWARE_VIDEO_SET_REGS;
891    cmdSetRegs.body.streamId = streamId;
892    cmdSetRegs.body.item.regId = regId;
893    cmdSetRegs.body.item.value = value;
894
895    fifoItem = (uint32 *) &cmdSetRegs;
896    for (i = 0; i < sizeof(cmdSetRegs) / sizeof(uint32); i++) {
897        vmwareWriteWordToFIFO(pVMWARE, fifoItem[i]);
898    }
899}
900
901
902/*
903 *-----------------------------------------------------------------------------
904 *
905 * vmwareVideoEndStream --
906 *
907 *    Frees up all resources (if any) taken by a video stream.
908 *
909 * Results:
910 *    None.
911 *
912 * Side effects:
913 *    Same as above.
914 *
915 *-----------------------------------------------------------------------------
916 */
917
918static void vmwareVideoEndStream(ScrnInfoPtr pScrn, VMWAREVideoPtr pVid)
919{
920    uint32 id, colorKey, flags;
921
922    if (pVid->fmt_priv) {
923        free(pVid->fmt_priv);
924    }
925
926    if (pVid->fbarea) {
927        vmwareOffscreenFree(pVid->fbarea);
928        pVid->fbarea =  NULL;
929    }
930
931    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
932               "Terminating Xv video-stream id:%d\n", pVid->streamId);
933    /*
934     * reset stream for next video
935     */
936    id = pVid->streamId;
937    colorKey = pVid->colorKey;
938    flags = pVid->flags;
939    memset(pVid, 0, sizeof(*pVid));
940    pVid->streamId = id;
941    pVid->play = vmwareVideoInitStream;
942    pVid->colorKey = colorKey;
943    pVid->flags = flags;
944}
945
946
947/*
948 *-----------------------------------------------------------------------------
949 *
950 * vmwareXvPutImage --
951 *
952 *    Main video playback function. It copies the passed data which is in
953 *    the specified format (e.g. FOURCC_YV12) into the overlay.
954 *
955 *    If sync is TRUE the driver should not return from this
956 *    function until it is through reading the data from buf.
957 *
958 *    There are two function prototypes to cope with the API change in X.org
959 *    7.1
960 *
961 * Results:
962 *    Success or XvBadAlloc on failure
963 *
964 * Side effects:
965 *    Video stream will be played(initialized if 1st frame) on success
966 *    or will fail on error.
967 *
968 *-----------------------------------------------------------------------------
969 */
970
971#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(7, 0, 0, 0, 0) || XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(4, 0, 0, 0, 0)
972static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
973                            short drw_x, short drw_y, short src_w, short src_h,
974                            short drw_w, short drw_h, int format,
975                            unsigned char *buf, short width, short height,
976                            Bool sync, RegionPtr clipBoxes, pointer data,
977                            DrawablePtr dst)
978#else
979static int vmwareXvPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
980                            short drw_x, short drw_y, short src_w, short src_h,
981                            short drw_w, short drw_h, int format,
982                            unsigned char *buf, short width, short height,
983                            Bool sync, RegionPtr clipBoxes, pointer data)
984#endif
985{
986    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
987    VMWAREVideoPtr pVid = data;
988
989    TRACEPOINT
990
991    if (!vmwareVideoEnabled(pVMWARE)) {
992        return XvBadAlloc;
993    }
994
995    return pVid->play(pScrn, pVid, src_x, src_y, drw_x, drw_y, src_w, src_h,
996                      drw_w, drw_h, format, buf, width, height);
997}
998
999
1000/*
1001 *-----------------------------------------------------------------------------
1002 *
1003 * vmwareStopVideo --
1004 *
1005 *    Called when we should stop playing video for a particular stream. If
1006 *    Cleanup is FALSE, the "stop" operation is only temporary, and thus we
1007 *    don't do anything. If Cleanup is TRUE we kill the video stream by
1008 *    sending a message to the host and freeing up the stream.
1009 *
1010 * Results:
1011 *    None.
1012 *
1013 * Side effects:
1014 *    See above.
1015 *
1016 *-----------------------------------------------------------------------------
1017 */
1018
1019static void vmwareStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup)
1020{
1021    VMWAREVideoPtr pVid = data;
1022    VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
1023    TRACEPOINT
1024
1025    if (!vmwareVideoEnabled(pVMWARE)) {
1026        return;
1027    }
1028    if (!Cleanup) {
1029        return;
1030    }
1031    vmwareVideoSetOneReg(pVMWARE, pVid->streamId,
1032                         SVGA_VIDEO_ENABLED, FALSE);
1033
1034    vmwareVideoFlush(pVMWARE, pVid->streamId);
1035    vmwareVideoEndStream(pScrn, pVid);
1036
1037}
1038
1039
1040/*
1041 *-----------------------------------------------------------------------------
1042 *
1043 * vmwareQueryImageAttributes --
1044 *
1045 *    From the spec: This function is called to let the driver specify how data
1046 *    for a particular image of size width by height should be stored.
1047 *    Sometimes only the size and corrected width and height are needed. In
1048 *    that case pitches and offsets are NULL.
1049 *
1050 * Results:
1051 *    The size of the memory required for the image, or -1 on error.
1052 *
1053 * Side effects:
1054 *    None.
1055 *
1056 *-----------------------------------------------------------------------------
1057 */
1058
1059static int vmwareQueryImageAttributes(ScrnInfoPtr pScrn, int format,
1060                                      unsigned short *width,
1061                                      unsigned short *height, int *pitches,
1062                                      int *offsets)
1063{
1064    INT32 size, tmp;
1065
1066    TRACEPOINT
1067
1068    if (*width > VMWARE_VID_MAX_WIDTH) {
1069        *width = VMWARE_VID_MAX_WIDTH;
1070    }
1071    if (*height > VMWARE_VID_MAX_HEIGHT) {
1072        *height = VMWARE_VID_MAX_HEIGHT;
1073    }
1074
1075    *width = (*width + 1) & ~1;
1076    if (offsets != NULL) {
1077        offsets[0] = 0;
1078    }
1079
1080    switch (format) {
1081       case FOURCC_YV12:
1082           *height = (*height + 1) & ~1;
1083           size = (*width + 3) & ~3;
1084           if (pitches) {
1085               pitches[0] = size;
1086           }
1087           size *= *height;
1088           if (offsets) {
1089               offsets[1] = size;
1090           }
1091           tmp = ((*width >> 1) + 3) & ~3;
1092           if (pitches) {
1093                pitches[1] = pitches[2] = tmp;
1094           }
1095           tmp *= (*height >> 1);
1096           size += tmp;
1097           if (offsets) {
1098               offsets[2] = size;
1099           }
1100           size += tmp;
1101           break;
1102       case FOURCC_YUY2:
1103           size = *width * 2;
1104           if (pitches) {
1105               pitches[0] = size;
1106           }
1107           size *= *height;
1108           break;
1109       default:
1110           VmwareLog(("Query for invalid video format %d\n", format));
1111           return -1;
1112    }
1113    return size;
1114}
1115
1116
1117/*
1118 *-----------------------------------------------------------------------------
1119 *
1120 * vmwareSetPortAttribute --
1121 *
1122 *    From the spec: A port may have particular attributes such as colorKey, hue,
1123 *    saturation, brightness or contrast. Xv clients set these
1124 *    attribute values by sending attribute strings (Atoms) to the server.
1125 *
1126 * Results:
1127 *    Success if the attribute exists and XvBadAlloc otherwise.
1128 *
1129 * Side effects:
1130 *    The respective attribute gets the new value.
1131 *
1132 *-----------------------------------------------------------------------------
1133 */
1134
1135static int vmwareSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1136                                  INT32 value, pointer data)
1137{
1138    VMWAREVideoPtr pVid = (VMWAREVideoPtr) data;
1139    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
1140
1141    if (attribute == xvColorKey) {
1142        pVid->colorKey = value;
1143    } else {
1144        return XvBadAlloc;
1145    }
1146    return Success;
1147}
1148
1149
1150/*
1151 *-----------------------------------------------------------------------------
1152 *
1153 * vmwareGetPortAttribute --
1154 *
1155 *    From the spec: A port may have particular attributes such as hue,
1156 *    saturation, brightness or contrast. Xv clients get these
1157 *    attribute values by sending attribute strings (Atoms) to the server
1158 *
1159 * Results:
1160 *    Success if the attribute exists and XvBadAlloc otherwise.
1161 *
1162 * Side effects:
1163 *    "value" contains the requested attribute on success.
1164 *
1165 *-----------------------------------------------------------------------------
1166 */
1167
1168static int vmwareGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
1169                                  INT32 *value, pointer data)
1170{
1171    VMWAREVideoPtr pVid = (VMWAREVideoPtr) data;
1172    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
1173
1174    if (attribute == xvColorKey) {
1175        *value = pVid->colorKey;
1176    } else {
1177        return XvBadAlloc;
1178    }
1179    return Success;
1180}
1181
1182
1183/*
1184 *-----------------------------------------------------------------------------
1185 *
1186 * vmwareQueryBestSize --
1187 *
1188 *    From the spec: QueryBestSize provides the client with a way to query what
1189 *    the destination dimensions would end up being if they were to request
1190 *    that an area vid_w by vid_h from the video stream be scaled to rectangle
1191 *    of drw_w by drw_h on the screen. Since it is not expected that all
1192 *    hardware will be able to get the target dimensions exactly, it is
1193 *    important that the driver provide this function.
1194 *
1195 *    This function seems to never be called, but to be on the safe side
1196 *    we apply the same logic that QueryImageAttributes has for width
1197 *    and height
1198 *
1199 * Results:
1200 *    None.
1201 *
1202 * Side effects:
1203 *    None
1204 *
1205 *-----------------------------------------------------------------------------
1206 */
1207
1208static void vmwareQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
1209                                short vid_w, short vid_h, short drw_w,
1210                                short drw_h, unsigned int *p_w,
1211                                unsigned int *p_h, pointer data)
1212{
1213    *p_w = (drw_w + 1) & ~1;
1214    *p_h = drw_h;
1215
1216    return;
1217}
1218
1219