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