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