Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / targets / xorg-vmwgfx / vmw_video.c
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 #include "xf86xv.h"
38 #include "fourcc.h"
39
40 #include "pipe/p_compiler.h"
41 /*
42  * We can't incude svga_types.h due to conflicting types for Bool.
43  */
44 typedef int64_t int64;
45 typedef uint64_t uint64;
46
47 typedef int32_t int32;
48 typedef uint32_t uint32;
49
50 typedef int16_t int16;
51 typedef uint16_t uint16;
52
53 typedef int8_t int8;
54 typedef uint8_t uint8;
55
56 #include "svga/include/svga_reg.h"
57 #include "svga/include/svga_escape.h"
58 #include "svga/include/svga_overlay.h"
59
60 #include "vmw_driver.h"
61
62 #include <X11/extensions/Xv.h>
63
64 #include "xf86drm.h"
65 #include "../../winsys/svga/drm/vmwgfx_drm.h"
66
67 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
68
69 /*
70  * Number of videos that can be played simultaneously
71  */
72 #define VMWARE_VID_NUM_PORTS 1
73
74 /*
75  * Using a dark shade as the default colorKey
76  */
77 #define VMWARE_VIDEO_COLORKEY 0x100701
78
79 /*
80  * Maximum dimensions
81  */
82 #define VMWARE_VID_MAX_WIDTH    2048
83 #define VMWARE_VID_MAX_HEIGHT   2048
84
85 #define VMWARE_VID_NUM_ENCODINGS 1
86 static XF86VideoEncodingRec vmwareVideoEncodings[] =
87 {
88     {
89        0,
90        "XV_IMAGE",
91        VMWARE_VID_MAX_WIDTH, VMWARE_VID_MAX_HEIGHT,
92        {1, 1}
93     }
94 };
95
96 #define VMWARE_VID_NUM_FORMATS 2
97 static XF86VideoFormatRec vmwareVideoFormats[] =
98 {
99     { 16, TrueColor},
100     { 24, TrueColor}
101 };
102
103 #define VMWARE_VID_NUM_IMAGES 3
104 static XF86ImageRec vmwareVideoImages[] =
105 {
106     XVIMAGE_YV12,
107     XVIMAGE_YUY2,
108     XVIMAGE_UYVY
109 };
110
111 #define VMWARE_VID_NUM_ATTRIBUTES 2
112 static XF86AttributeRec vmwareVideoAttributes[] =
113 {
114     {
115         XvGettable | XvSettable,
116         0x000000,
117         0xffffff,
118         "XV_COLORKEY"
119     },
120     {
121         XvGettable | XvSettable,
122         0,
123         1,
124         "XV_AUTOPAINT_COLORKEY"
125     }
126 };
127
128 /*
129  * Video frames are stored in a circular list of buffers.
130  * Must be power or two, See vmw_video_port_play.
131  */
132 #define VMWARE_VID_NUM_BUFFERS 1
133
134 /*
135  * Defines the structure used to hold and pass video data to the host
136  */
137 struct vmw_video_buffer
138 {
139     unsigned handle;
140     int size;
141     void *data;
142     void *extra_data;
143     struct vmw_dma_buffer *buf;
144 };
145
146
147 /**
148  * Structure representing a single video stream, aka port.
149  *
150  * Ports maps one to one to a SVGA stream. Port is just
151  * what Xv calls a SVGA stream.
152  */
153 struct vmw_video_port
154 {
155     /*
156      * Function prototype same as XvPutImage.
157      *
158      * This is either set to vmw_video_port_init or vmw_video_port_play.
159      * At init this function is set to port_init. In port_init we set it
160      * to port_play and call it, after initializing the struct.
161      */
162     int (*play)(ScrnInfoPtr, struct vmw_video_port *,
163                 short, short, short, short, short,
164                 short, short, short, int, unsigned char*,
165                 short, short, RegionPtr);
166
167     /* values to go into the SVGAOverlayUnit */
168     uint32 streamId;
169     uint32 colorKey;
170     uint32 flags;
171
172     /* round robin of buffers */
173     unsigned currBuf;
174     struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS];
175
176     /* properties that applies to all buffers */
177     int size;
178     int pitches[3];
179     int offsets[3];
180
181     /* things for X */
182     RegionRec clipBoxes;
183     Bool isAutoPaintColorkey;
184 };
185
186
187 /**
188  * Structure holding all the infromation for video.
189  */
190 struct vmw_video_private
191 {
192     int fd;
193
194     /** ports */
195     struct vmw_video_port port[VMWARE_VID_NUM_PORTS];
196
197     /** Used to store port pointers pointers */
198     DevUnion port_ptr[VMWARE_VID_NUM_PORTS];
199 };
200
201
202 /*
203  * Callback functions exported to Xv, prefixed with vmw_xv_*.
204  */
205 static int vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
206                             short drw_x, short drw_y, short src_w, short src_h,
207                             short drw_w, short drw_h, int image,
208                             unsigned char *buf, short width, short height,
209                             Bool sync, RegionPtr clipBoxes, pointer data,
210                             DrawablePtr dst);
211 static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
212 static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
213                                          unsigned short *width,
214                                          unsigned short *height, int *pitches,
215                                          int *offsets);
216 static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
217                                      INT32 value, pointer data);
218 static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
219                                      INT32 *value, pointer data);
220 static void vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
221                                 short vid_w, short vid_h, short drw_w,
222                                 short drw_h, unsigned int *p_w,
223                                 unsigned int *p_h, pointer data);
224
225
226 /*
227  * Local functions.
228  */
229 static XF86VideoAdaptorPtr vmw_video_init_adaptor(ScrnInfoPtr pScrn, struct vmw_customizer *vmw);
230
231 static int vmw_video_port_init(ScrnInfoPtr pScrn,
232                                struct vmw_video_port *port,
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 static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmw_video_port *port,
239                                short src_x, short src_y, short drw_x,
240                                short drw_y, short src_w, short src_h,
241                                short drw_w, short drw_h, int format,
242                                unsigned char *buf, short width,
243                                short height, RegionPtr clipBoxes);
244 static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmw_video_port *port);
245
246 static int vmw_video_buffer_alloc(struct vmw_customizer *vmw, int size,
247                                   struct vmw_video_buffer *out);
248 static int vmw_video_buffer_free(struct vmw_customizer *vmw,
249                                  struct vmw_video_buffer *out);
250
251
252 /*
253  *-----------------------------------------------------------------------------
254  *
255  * vmw_video_init --
256  *
257  *    Initializes Xv support.
258  *
259  * Results:
260  *    TRUE on success, FALSE on error.
261  *
262  * Side effects:
263  *    Xv support is initialized. Memory is allocated for all supported
264  *    video streams.
265  *
266  *-----------------------------------------------------------------------------
267  */
268
269 Bool
270 vmw_video_init(struct vmw_customizer *vmw)
271 {
272     ScrnInfoPtr pScrn = vmw->pScrn;
273     ScreenPtr pScreen = pScrn->pScreen;
274     XF86VideoAdaptorPtr *overlayAdaptors, *newAdaptors = NULL;
275     XF86VideoAdaptorPtr newAdaptor = NULL;
276     int numAdaptors;
277     unsigned int ntot, nfree;
278
279     debug_printf("%s: enter\n", __func__);
280
281     if (vmw_ioctl_num_streams(vmw, &ntot, &nfree) != 0) {
282         debug_printf("No stream ioctl support\n");
283         return FALSE;
284     }
285
286     if (nfree == 0) {
287         debug_printf("No free streams\n");
288         return FALSE;
289     }
290
291     numAdaptors = xf86XVListGenericAdaptors(pScrn, &overlayAdaptors);
292
293     newAdaptor = vmw_video_init_adaptor(pScrn, vmw);
294     if (!newAdaptor) {
295         debug_printf("Failed to initialize Xv extension\n");
296         return FALSE;
297     }
298
299     if (!numAdaptors) {
300         numAdaptors = 1;
301         overlayAdaptors = &newAdaptor;
302     } else {
303          newAdaptors = malloc((numAdaptors + 1) *
304                               sizeof(XF86VideoAdaptorPtr*));
305          if (!newAdaptors) {
306             xf86XVFreeVideoAdaptorRec(newAdaptor);
307             return FALSE;
308          }
309
310          memcpy(newAdaptors, overlayAdaptors,
311                 numAdaptors * sizeof(XF86VideoAdaptorPtr));
312          newAdaptors[numAdaptors++] = newAdaptor;
313          overlayAdaptors = newAdaptors;
314     }
315
316     if (!xf86XVScreenInit(pScreen, overlayAdaptors, numAdaptors)) {
317         debug_printf("Failed to initialize Xv extension\n");
318         xf86XVFreeVideoAdaptorRec(newAdaptor);
319         return FALSE;
320     }
321
322     if (newAdaptors) {
323         free(newAdaptors);
324     }
325
326     debug_printf("Initialized VMware Xv extension successfully\n");
327
328     return TRUE;
329 }
330
331
332 /*
333  *-----------------------------------------------------------------------------
334  *
335  * vmw_video_close --
336  *
337  *    Unitializes video.
338  *
339  * Results:
340  *    TRUE.
341  *
342  * Side effects:
343  *    vmw->video_priv = NULL
344  *
345  *-----------------------------------------------------------------------------
346  */
347
348 Bool
349 vmw_video_close(struct vmw_customizer *vmw)
350 {
351     ScrnInfoPtr pScrn = vmw->pScrn;
352     struct vmw_video_private *video;
353     int i;
354
355     debug_printf("%s: enter\n", __func__);
356
357     video = vmw->video_priv;
358     if (!video)
359         return TRUE;
360
361     for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
362         /* make sure the port is stoped as well */
363         vmw_xv_stop_video(pScrn, &video->port[i], TRUE);
364         vmw_ioctl_unref_stream(vmw, video->port[i].streamId);
365         REGION_UNINIT(pScreen, &video->port[i].clipBoxes);
366     }
367
368
369     /* XXX: I'm sure this function is missing code for turning off Xv */
370
371     free(vmw->video_priv);
372     vmw->video_priv = NULL;
373
374     return TRUE;
375 }
376
377
378 /*
379  *-----------------------------------------------------------------------------
380  *
381  * vmw_video_stop_all --
382  *
383  *    Stop all video streams from playing.
384  *
385  * Results:
386  *    None.
387  *
388  * Side effects:
389  *    All buffers are freed.
390  *
391  *-----------------------------------------------------------------------------
392  */
393
394 void vmw_video_stop_all(struct vmw_customizer *vmw)
395 {
396     ScrnInfoPtr pScrn = vmw->pScrn;
397     struct vmw_video_private *video = vmw->video_priv;
398     int i;
399
400     debug_printf("%s: enter\n", __func__);
401
402     if (!video)
403         return;
404
405     for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
406         vmw_xv_stop_video(pScrn, &video->port[i], TRUE);
407     }
408 }
409
410
411 /*
412  *-----------------------------------------------------------------------------
413  *
414  * vmw_video_init_adaptor --
415  *
416  *    Initializes a XF86VideoAdaptor structure with the capabilities and
417  *    functions supported by this video driver.
418  *
419  * Results:
420  *    On success initialized XF86VideoAdaptor struct or NULL on error
421  *
422  * Side effects:
423  *    None.
424  *
425  *-----------------------------------------------------------------------------
426  */
427
428 static XF86VideoAdaptorPtr
429 vmw_video_init_adaptor(ScrnInfoPtr pScrn, struct vmw_customizer *vmw)
430 {
431     XF86VideoAdaptorPtr adaptor;
432     struct vmw_video_private *video;
433     int i;
434
435     debug_printf("%s: enter \n", __func__);
436
437     adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
438     if (!adaptor) {
439         debug_printf("Not enough memory\n");
440         return NULL;
441     }
442
443     video = calloc(1, sizeof(*video));
444     if (!video) {
445         debug_printf("Not enough memory.\n");
446         xf86XVFreeVideoAdaptorRec(adaptor);
447         return NULL;
448     }
449
450     vmw->video_priv = video;
451
452     adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
453
454     /**
455      * Note: CLIP_TO_VIEWPORT was removed from the flags, since with the
456      * crtc/output based modesetting, the viewport is not updated on
457      * RandR modeswitches. Hence the video may incorrectly be clipped away.
458      * The correct approach, (if needed) would be to clip against the
459      * scanout area union of all active crtcs. Revisit if needed.
460      */
461
462     adaptor->flags = VIDEO_OVERLAID_IMAGES;
463     adaptor->name = "VMware Video Engine";
464     adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
465     adaptor->pEncodings = vmwareVideoEncodings;
466     adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
467     adaptor->pFormats = vmwareVideoFormats;
468     adaptor->nPorts = VMWARE_VID_NUM_PORTS;
469     adaptor->pPortPrivates = video->port_ptr;
470
471     for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
472         vmw_ioctl_claim_stream(vmw, &video->port[i].streamId);
473         video->port[i].play = vmw_video_port_init;
474         video->port[i].flags = SVGA_VIDEO_FLAG_COLORKEY;
475         video->port[i].colorKey = VMWARE_VIDEO_COLORKEY;
476         video->port[i].isAutoPaintColorkey = TRUE;
477         REGION_NULL(pScrn->pScreen, &video->port[i].clipBoxes);
478         adaptor->pPortPrivates[i].ptr = &video->port[i];
479     }
480
481     adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
482     adaptor->pAttributes = vmwareVideoAttributes;
483
484     adaptor->nImages = VMWARE_VID_NUM_IMAGES;
485     adaptor->pImages = vmwareVideoImages;
486
487     adaptor->PutVideo = NULL;
488     adaptor->PutStill = NULL;
489     adaptor->GetVideo = NULL;
490     adaptor->GetStill = NULL;
491     adaptor->StopVideo = vmw_xv_stop_video;
492     adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
493     adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
494     adaptor->QueryBestSize = vmw_xv_query_best_size;
495     adaptor->PutImage = vmw_xv_put_image;
496     adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
497
498     debug_printf("%s: done %p\n", __func__, adaptor);
499
500     return adaptor;
501 }
502
503
504 /*
505  *-----------------------------------------------------------------------------
506  *
507  * vmw_video_port_init --
508  *
509  *    Initializes a video stream in response to the first PutImage() on a
510  *    video stream. The process goes as follows:
511  *    - Figure out characteristics according to format
512  *    - Allocate offscreen memory
513  *    - Pass on video to Play() functions
514  *
515  * Results:
516  *    Success or XvBadAlloc on failure.
517  *
518  * Side effects:
519  *    Video stream is initialized and its first frame sent to the host
520  *    (done by VideoPlay() function called at the end)
521  *
522  *-----------------------------------------------------------------------------
523  */
524
525 static int
526 vmw_video_port_init(ScrnInfoPtr pScrn, struct vmw_video_port *port,
527                     short src_x, short src_y, short drw_x,
528                     short drw_y, short src_w, short src_h,
529                     short drw_w, short drw_h, int format,
530                     unsigned char *buf, short width,
531                     short height, RegionPtr clipBoxes)
532 {
533     struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
534     unsigned short w, h;
535     int i, ret;
536
537     debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
538
539     w = width;
540     h = height;
541     /* init all the format attributes, used for buffers */
542     port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
543                                                port->pitches, port->offsets);
544
545     if (port->size == -1)
546         return XvBadAlloc;
547
548     port->play = vmw_video_port_play;
549
550     for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
551         ret = vmw_video_buffer_alloc(vmw, port->size, &port->bufs[i]);
552         if (ret != Success)
553             break;
554     }
555
556     /* Free all allocated buffers on failure */
557     if (ret != Success) {
558         for (--i; i >= 0; --i) {
559             vmw_video_buffer_free(vmw, &port->bufs[i]);
560         }
561         return ret;
562     }
563
564     port->currBuf = 0;
565
566     REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
567
568     if (port->isAutoPaintColorkey)
569         xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
570
571     xorg_flush(pScrn->pScreen);
572
573     return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
574                       drw_w, drw_h, format, buf, width, height, clipBoxes);
575 }
576
577
578 /*
579  *-----------------------------------------------------------------------------
580  *
581  * vmw_video_port_play --
582  *
583  *    Sends all the attributes associated with the video frame using the
584  *    FIFO ESCAPE mechanism to the host.
585  *
586  * Results:
587  *    Always returns Success.
588  *
589  * Side effects:
590  *    None.
591  *
592  *-----------------------------------------------------------------------------
593  */
594
595 static int
596 vmw_video_port_play(ScrnInfoPtr pScrn, struct vmw_video_port *port,
597                     short src_x, short src_y, short drw_x,
598                     short drw_y, short src_w, short src_h,
599                     short drw_w, short drw_h, int format,
600                     unsigned char *buf, short width,
601                     short height, RegionPtr clipBoxes)
602 {
603     struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
604     struct drm_vmw_control_stream_arg arg;
605     unsigned short w, h;
606     int size;
607     int ret;
608
609     debug_printf("\t%s: enter\n", __func__);
610
611     w = width;
612     h = height;
613
614     /* we don't update the ports size */
615     size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
616                                          port->pitches, port->offsets);
617
618     if (size > port->size) {
619         debug_printf("\t%s: Increase in size of Xv video frame streamId:%d.\n",
620                      __func__, port->streamId);
621         vmw_xv_stop_video(pScrn, port, TRUE);
622         return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
623                           src_h, drw_w, drw_h, format, buf, width, height,
624                           clipBoxes);
625     }
626
627     memcpy(port->bufs[port->currBuf].data, buf, port->size);
628
629     memset(&arg, 0, sizeof(arg));
630
631     arg.stream_id = port->streamId;
632     arg.enabled = TRUE;
633     arg.flags = port->flags;
634     arg.color_key = port->colorKey;
635     arg.handle = port->bufs[port->currBuf].handle;
636     arg.format = format;
637     arg.size = port->size;
638     arg.width = w;
639     arg.height = h;
640     arg.src.x = src_x;
641     arg.src.y = src_y;
642     arg.src.w = src_w;
643     arg.src.h = src_h;
644     arg.dst.x = drw_x;
645     arg.dst.y = drw_y;
646     arg.dst.w = drw_w;
647     arg.dst.h = drw_h;
648     arg.pitch[0] = port->pitches[0];
649     arg.pitch[1] = port->pitches[1];
650     arg.pitch[2] = port->pitches[2];
651     arg.offset = 0;
652
653     /*
654      *  Update the clipList and paint the colorkey, if required.
655      */
656     if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
657         REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
658         if (port->isAutoPaintColorkey)
659             xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
660     }
661
662     xorg_flush(pScrn->pScreen);
663
664     ret = drmCommandWrite(vmw->fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
665     if (ret) {
666         vmw_video_port_cleanup(pScrn, port);
667         return XvBadAlloc;
668     }
669
670     if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
671         port->currBuf = 0;
672
673     return Success;
674 }
675
676
677 /*
678  *-----------------------------------------------------------------------------
679  *
680  * vmw_video_port_cleanup --
681  *
682  *    Frees up all resources (if any) taken by a video stream.
683  *
684  * Results:
685  *    None.
686  *
687  * Side effects:
688  *    Same as above.
689  *
690  *-----------------------------------------------------------------------------
691  */
692
693 static void
694 vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmw_video_port *port)
695 {
696     struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
697     uint32 id, colorKey, flags;
698     Bool isAutoPaintColorkey;
699     int i;
700
701     debug_printf("\t%s: enter\n", __func__);
702
703     for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
704         vmw_video_buffer_free(vmw, &port->bufs[i]);
705     }
706
707     /*
708      * reset stream for next video
709      */
710     id = port->streamId;
711     colorKey = port->colorKey;
712     flags = port->flags;
713     isAutoPaintColorkey = port->isAutoPaintColorkey;
714
715     memset(port, 0, sizeof(*port));
716
717     port->streamId = id;
718     port->play = vmw_video_port_init;
719     port->colorKey = colorKey;
720     port->flags = flags;
721     port->isAutoPaintColorkey = isAutoPaintColorkey;
722 }
723
724
725 /*
726  *-----------------------------------------------------------------------------
727  *
728  * vmw_video_buffer_alloc --
729  *
730  *    Allocates and map a kernel buffer to be used as data storage.
731  *
732  * Results:
733  *    XvBadAlloc on failure, otherwise Success.
734  *
735  * Side effects:
736  *    Calls into the kernel, sets members of out.
737  *
738  *-----------------------------------------------------------------------------
739  */
740
741 static int
742 vmw_video_buffer_alloc(struct vmw_customizer *vmw, int size,
743                        struct vmw_video_buffer *out)
744 {
745     out->buf = vmw_ioctl_buffer_create(vmw, size, &out->handle);
746     if (!out->buf)
747         return XvBadAlloc;
748
749     out->data = vmw_ioctl_buffer_map(vmw, out->buf);
750     if (!out->data) {
751         vmw_ioctl_buffer_destroy(vmw, out->buf);
752
753         out->handle = 0;
754         out->buf = NULL;
755
756         return XvBadAlloc;
757     }
758
759     out->size = size;
760     out->extra_data = calloc(1, size);
761
762     debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
763
764     return Success;
765 }
766
767
768 /*
769  *-----------------------------------------------------------------------------
770  *
771  * vmw_video_buffer_free --
772  *
773  *    Frees and unmaps an allocated kernel buffer.
774  *
775  * Results:
776  *    Success.
777  *
778  * Side effects:
779  *    Calls into the kernel, sets members of out to 0.
780  *
781  *-----------------------------------------------------------------------------
782  */
783
784 static int
785 vmw_video_buffer_free(struct vmw_customizer *vmw,
786                       struct vmw_video_buffer *out)
787 {
788     if (out->size == 0)
789         return Success;
790
791     free(out->extra_data);
792     vmw_ioctl_buffer_unmap(vmw, out->buf);
793     vmw_ioctl_buffer_destroy(vmw, out->buf);
794
795     out->buf = NULL;
796     out->data = NULL;
797     out->handle = 0;
798     out->size = 0;
799
800     debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
801
802     return Success;
803 }
804
805
806 /*
807  *-----------------------------------------------------------------------------
808  *
809  * vmw_xv_put_image --
810  *
811  *    Main video playback function. It copies the passed data which is in
812  *    the specified format (e.g. FOURCC_YV12) into the overlay.
813  *
814  *    If sync is TRUE the driver should not return from this
815  *    function until it is through reading the data from buf.
816  *
817  * Results:
818  *    Success or XvBadAlloc on failure
819  *
820  * Side effects:
821  *    Video port will be played(initialized if 1st frame) on success
822  *    or will fail on error.
823  *
824  *-----------------------------------------------------------------------------
825  */
826
827 static int
828 vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
829                  short drw_x, short drw_y, short src_w, short src_h,
830                  short drw_w, short drw_h, int format,
831                  unsigned char *buf, short width, short height,
832                  Bool sync, RegionPtr clipBoxes, pointer data,
833                  DrawablePtr dst)
834 {
835     struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
836     struct vmw_video_port *port = data;
837
838     debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
839                  src_x, src_y, src_w, src_h,
840                  drw_x, drw_y, drw_w, drw_h,
841                  width, height);
842
843     if (!vmw->video_priv)
844         return XvBadAlloc;
845
846     return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
847                       drw_w, drw_h, format, buf, width, height, clipBoxes);
848 }
849
850
851 /*
852  *-----------------------------------------------------------------------------
853  *
854  * vmw_xv_stop_video --
855  *
856  *    Called when we should stop playing video for a particular stream. If
857  *    Cleanup is FALSE, the "stop" operation is only temporary, and thus we
858  *    don't do anything. If Cleanup is TRUE we kill the video port by
859  *    sending a message to the host and freeing up the stream.
860  *
861  * Results:
862  *    None.
863  *
864  * Side effects:
865  *    See above.
866  *
867  *-----------------------------------------------------------------------------
868  */
869
870 static void
871 vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
872 {
873     struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
874     struct vmw_video_port *port = data;
875     struct drm_vmw_control_stream_arg arg;
876     int ret;
877
878     debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
879
880     if (!vmw->video_priv)
881         return;
882
883     REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
884
885     if (!cleanup)
886         return;
887
888
889     memset(&arg, 0, sizeof(arg));
890     arg.stream_id = port->streamId;
891     arg.enabled = FALSE;
892
893     ret = drmCommandWrite(vmw->fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
894     assert(ret == 0);
895
896     vmw_video_port_cleanup(pScrn, port);
897 }
898
899
900 /*
901  *-----------------------------------------------------------------------------
902  *
903  * vmw_xv_query_image_attributes --
904  *
905  *    From the spec: This function is called to let the driver specify how data
906  *    for a particular image of size width by height should be stored.
907  *    Sometimes only the size and corrected width and height are needed. In
908  *    that case pitches and offsets are NULL.
909  *
910  * Results:
911  *    The size of the memory required for the image, or -1 on error.
912  *
913  * Side effects:
914  *    None.
915  *
916  *-----------------------------------------------------------------------------
917  */
918
919 static int
920 vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
921                               unsigned short *width, unsigned short *height,
922                               int *pitches, int *offsets)
923 {
924     INT32 size, tmp;
925
926     if (*width > VMWARE_VID_MAX_WIDTH) {
927         *width = VMWARE_VID_MAX_WIDTH;
928     }
929     if (*height > VMWARE_VID_MAX_HEIGHT) {
930         *height = VMWARE_VID_MAX_HEIGHT;
931     }
932
933     *width = (*width + 1) & ~1;
934     if (offsets != NULL) {
935         offsets[0] = 0;
936     }
937
938     switch (format) {
939        case FOURCC_YV12:
940            *height = (*height + 1) & ~1;
941            size = (*width + 3) & ~3;
942            if (pitches) {
943                pitches[0] = size;
944            }
945            size *= *height;
946            if (offsets) {
947                offsets[1] = size;
948            }
949            tmp = ((*width >> 1) + 3) & ~3;
950            if (pitches) {
951                 pitches[1] = pitches[2] = tmp;
952            }
953            tmp *= (*height >> 1);
954            size += tmp;
955            if (offsets) {
956                offsets[2] = size;
957            }
958            size += tmp;
959            break;
960        case FOURCC_UYVY:
961        case FOURCC_YUY2:
962            size = *width * 2;
963            if (pitches) {
964                pitches[0] = size;
965            }
966            size *= *height;
967            break;
968        default:
969            debug_printf("Query for invalid video format %d\n", format);
970            return -1;
971     }
972     return size;
973 }
974
975
976 /*
977  *-----------------------------------------------------------------------------
978  *
979  * vmw_xv_set_port_attribute --
980  *
981  *    From the spec: A port may have particular attributes such as colorKey, hue,
982  *    saturation, brightness or contrast. Xv clients set these
983  *    attribute values by sending attribute strings (Atoms) to the server.
984  *
985  * Results:
986  *    Success if the attribute exists and XvBadAlloc otherwise.
987  *
988  * Side effects:
989  *    The respective attribute gets the new value.
990  *
991  *-----------------------------------------------------------------------------
992  */
993
994 static int
995 vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
996                           INT32 value, pointer data)
997 {
998     struct vmw_video_port *port = data;
999     Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
1000     Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1001
1002     if (attribute == xvColorKey) {
1003         debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
1004         port->colorKey = value;
1005     } else if (attribute == xvAutoPaint) {
1006         debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
1007         port->isAutoPaintColorkey = value;
1008     } else {
1009         return XvBadAlloc;
1010     }
1011
1012     return Success;
1013 }
1014
1015
1016 /*
1017  *-----------------------------------------------------------------------------
1018  *
1019  * vmw_xv_get_port_attribute --
1020  *
1021  *    From the spec: A port may have particular attributes such as hue,
1022  *    saturation, brightness or contrast. Xv clients get these
1023  *    attribute values by sending attribute strings (Atoms) to the server
1024  *
1025  * Results:
1026  *    Success if the attribute exists and XvBadAlloc otherwise.
1027  *
1028  * Side effects:
1029  *    "value" contains the requested attribute on success.
1030  *
1031  *-----------------------------------------------------------------------------
1032  */
1033
1034 static int
1035 vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
1036                           INT32 *value, pointer data)
1037 {
1038     struct vmw_video_port *port = data;
1039     Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
1040     Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1041
1042     if (attribute == xvColorKey) {
1043         *value = port->colorKey;
1044     } else if (attribute == xvAutoPaint) {
1045         *value = port->isAutoPaintColorkey;
1046     } else {
1047         return XvBadAlloc;
1048     }
1049
1050     return Success;
1051 }
1052
1053
1054 /*
1055  *-----------------------------------------------------------------------------
1056  *
1057  * vmw_xv_query_best_size --
1058  *
1059  *    From the spec: QueryBestSize provides the client with a way to query what
1060  *    the destination dimensions would end up being if they were to request
1061  *    that an area vid_w by vid_h from the video stream be scaled to rectangle
1062  *    of drw_w by drw_h on the screen. Since it is not expected that all
1063  *    hardware will be able to get the target dimensions exactly, it is
1064  *    important that the driver provide this function.
1065  *
1066  *    This function seems to never be called, but to be on the safe side
1067  *    we apply the same logic that QueryImageAttributes has for width
1068  *    and height.
1069  *
1070  * Results:
1071  *    None.
1072  *
1073  * Side effects:
1074  *    None.
1075  *
1076  *-----------------------------------------------------------------------------
1077  */
1078
1079 static void
1080 vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
1081                        short vid_w, short vid_h, short drw_w,
1082                        short drw_h, unsigned int *p_w,
1083                        unsigned int *p_h, pointer data)
1084 {
1085     *p_w = (drw_w + 1) & ~1;
1086     *p_h = drw_h;
1087
1088     return;
1089 }