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