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