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