xorg/vmwgfx: Flush even if we don't autopaint the color key
[mesa.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 adaptor->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
454 adaptor->name = "VMware Video Engine";
455 adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
456 adaptor->pEncodings = vmwareVideoEncodings;
457 adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
458 adaptor->pFormats = vmwareVideoFormats;
459 adaptor->nPorts = VMWARE_VID_NUM_PORTS;
460 adaptor->pPortPrivates = video->port_ptr;
461
462 for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
463 vmw_ioctl_claim_stream(vmw, &video->port[i].streamId);
464 video->port[i].play = vmw_video_port_init;
465 video->port[i].flags = SVGA_VIDEO_FLAG_COLORKEY;
466 video->port[i].colorKey = VMWARE_VIDEO_COLORKEY;
467 video->port[i].isAutoPaintColorkey = TRUE;
468 REGION_NULL(pScrn->pScreen, &video->port[i].clipBoxes);
469 adaptor->pPortPrivates[i].ptr = &video->port[i];
470 }
471
472 adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
473 adaptor->pAttributes = vmwareVideoAttributes;
474
475 adaptor->nImages = VMWARE_VID_NUM_IMAGES;
476 adaptor->pImages = vmwareVideoImages;
477
478 adaptor->PutVideo = NULL;
479 adaptor->PutStill = NULL;
480 adaptor->GetVideo = NULL;
481 adaptor->GetStill = NULL;
482 adaptor->StopVideo = vmw_xv_stop_video;
483 adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
484 adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
485 adaptor->QueryBestSize = vmw_xv_query_best_size;
486 adaptor->PutImage = vmw_xv_put_image;
487 adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
488
489 debug_printf("%s: done %p\n", __func__, adaptor);
490
491 return adaptor;
492 }
493
494
495 /*
496 *-----------------------------------------------------------------------------
497 *
498 * vmw_video_port_init --
499 *
500 * Initializes a video stream in response to the first PutImage() on a
501 * video stream. The process goes as follows:
502 * - Figure out characteristics according to format
503 * - Allocate offscreen memory
504 * - Pass on video to Play() functions
505 *
506 * Results:
507 * Success or XvBadAlloc on failure.
508 *
509 * Side effects:
510 * Video stream is initialized and its first frame sent to the host
511 * (done by VideoPlay() function called at the end)
512 *
513 *-----------------------------------------------------------------------------
514 */
515
516 static int
517 vmw_video_port_init(ScrnInfoPtr pScrn, struct vmw_video_port *port,
518 short src_x, short src_y, short drw_x,
519 short drw_y, short src_w, short src_h,
520 short drw_w, short drw_h, int format,
521 unsigned char *buf, short width,
522 short height, RegionPtr clipBoxes)
523 {
524 struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
525 unsigned short w, h;
526 int i, ret;
527
528 debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
529
530 w = width;
531 h = height;
532 /* init all the format attributes, used for buffers */
533 port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
534 port->pitches, port->offsets);
535
536 if (port->size == -1)
537 return XvBadAlloc;
538
539 port->play = vmw_video_port_play;
540
541 for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
542 ret = vmw_video_buffer_alloc(vmw, port->size, &port->bufs[i]);
543 if (ret != Success)
544 break;
545 }
546
547 /* Free all allocated buffers on failure */
548 if (ret != Success) {
549 for (--i; i >= 0; --i) {
550 vmw_video_buffer_free(vmw, &port->bufs[i]);
551 }
552 return ret;
553 }
554
555 port->currBuf = 0;
556
557 REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
558
559 if (port->isAutoPaintColorkey)
560 xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
561
562 xorg_flush(pScrn->pScreen);
563
564 return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
565 drw_w, drw_h, format, buf, width, height, clipBoxes);
566 }
567
568
569 /*
570 *-----------------------------------------------------------------------------
571 *
572 * vmw_video_port_play --
573 *
574 * Sends all the attributes associated with the video frame using the
575 * FIFO ESCAPE mechanism to the host.
576 *
577 * Results:
578 * Always returns Success.
579 *
580 * Side effects:
581 * None.
582 *
583 *-----------------------------------------------------------------------------
584 */
585
586 static int
587 vmw_video_port_play(ScrnInfoPtr pScrn, struct vmw_video_port *port,
588 short src_x, short src_y, short drw_x,
589 short drw_y, short src_w, short src_h,
590 short drw_w, short drw_h, int format,
591 unsigned char *buf, short width,
592 short height, RegionPtr clipBoxes)
593 {
594 struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
595 struct drm_vmw_control_stream_arg arg;
596 unsigned short w, h;
597 int size;
598 int ret;
599
600 debug_printf("\t%s: enter\n", __func__);
601
602 w = width;
603 h = height;
604
605 /* we don't update the ports size */
606 size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
607 port->pitches, port->offsets);
608
609 if (size > port->size) {
610 debug_printf("\t%s: Increase in size of Xv video frame streamId:%d.\n",
611 __func__, port->streamId);
612 vmw_xv_stop_video(pScrn, port, TRUE);
613 return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
614 src_h, drw_w, drw_h, format, buf, width, height,
615 clipBoxes);
616 }
617
618 memcpy(port->bufs[port->currBuf].data, buf, port->size);
619
620 memset(&arg, 0, sizeof(arg));
621
622 arg.stream_id = port->streamId;
623 arg.enabled = TRUE;
624 arg.flags = port->flags;
625 arg.color_key = port->colorKey;
626 arg.handle = port->bufs[port->currBuf].handle;
627 arg.format = format;
628 arg.size = port->size;
629 arg.width = w;
630 arg.height = h;
631 arg.src.x = src_x;
632 arg.src.y = src_y;
633 arg.src.w = src_w;
634 arg.src.h = src_h;
635 arg.dst.x = drw_x;
636 arg.dst.y = drw_y;
637 arg.dst.w = drw_w;
638 arg.dst.h = drw_h;
639 arg.pitch[0] = port->pitches[0];
640 arg.pitch[1] = port->pitches[1];
641 arg.pitch[2] = port->pitches[2];
642 arg.offset = 0;
643
644 /*
645 * Update the clipList and paint the colorkey, if required.
646 */
647 if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
648 REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
649 if (port->isAutoPaintColorkey)
650 xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
651 }
652
653 xorg_flush(pScrn->pScreen);
654
655 ret = drmCommandWrite(vmw->fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
656 if (ret) {
657 vmw_video_port_cleanup(pScrn, port);
658 return XvBadAlloc;
659 }
660
661 if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
662 port->currBuf = 0;
663
664 return Success;
665 }
666
667
668 /*
669 *-----------------------------------------------------------------------------
670 *
671 * vmw_video_port_cleanup --
672 *
673 * Frees up all resources (if any) taken by a video stream.
674 *
675 * Results:
676 * None.
677 *
678 * Side effects:
679 * Same as above.
680 *
681 *-----------------------------------------------------------------------------
682 */
683
684 static void
685 vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmw_video_port *port)
686 {
687 struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
688 uint32 id, colorKey, flags;
689 Bool isAutoPaintColorkey;
690 int i;
691
692 debug_printf("\t%s: enter\n", __func__);
693
694 for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
695 vmw_video_buffer_free(vmw, &port->bufs[i]);
696 }
697
698 /*
699 * reset stream for next video
700 */
701 id = port->streamId;
702 colorKey = port->colorKey;
703 flags = port->flags;
704 isAutoPaintColorkey = port->isAutoPaintColorkey;
705
706 memset(port, 0, sizeof(*port));
707
708 port->streamId = id;
709 port->play = vmw_video_port_init;
710 port->colorKey = colorKey;
711 port->flags = flags;
712 port->isAutoPaintColorkey = isAutoPaintColorkey;
713 }
714
715
716 /*
717 *-----------------------------------------------------------------------------
718 *
719 * vmw_video_buffer_alloc --
720 *
721 * Allocates and map a kernel buffer to be used as data storage.
722 *
723 * Results:
724 * XvBadAlloc on failure, otherwise Success.
725 *
726 * Side effects:
727 * Calls into the kernel, sets members of out.
728 *
729 *-----------------------------------------------------------------------------
730 */
731
732 static int
733 vmw_video_buffer_alloc(struct vmw_customizer *vmw, int size,
734 struct vmw_video_buffer *out)
735 {
736 out->buf = vmw_ioctl_buffer_create(vmw, size, &out->handle);
737 if (!out->buf)
738 return XvBadAlloc;
739
740 out->data = vmw_ioctl_buffer_map(vmw, out->buf);
741 if (!out->data) {
742 vmw_ioctl_buffer_destroy(vmw, out->buf);
743
744 out->handle = 0;
745 out->buf = NULL;
746
747 return XvBadAlloc;
748 }
749
750 out->size = size;
751 out->extra_data = calloc(1, size);
752
753 debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
754
755 return Success;
756 }
757
758
759 /*
760 *-----------------------------------------------------------------------------
761 *
762 * vmw_video_buffer_free --
763 *
764 * Frees and unmaps an allocated kernel buffer.
765 *
766 * Results:
767 * Success.
768 *
769 * Side effects:
770 * Calls into the kernel, sets members of out to 0.
771 *
772 *-----------------------------------------------------------------------------
773 */
774
775 static int
776 vmw_video_buffer_free(struct vmw_customizer *vmw,
777 struct vmw_video_buffer *out)
778 {
779 if (out->size == 0)
780 return Success;
781
782 free(out->extra_data);
783 vmw_ioctl_buffer_unmap(vmw, out->buf);
784 vmw_ioctl_buffer_destroy(vmw, out->buf);
785
786 out->buf = NULL;
787 out->data = NULL;
788 out->handle = 0;
789 out->size = 0;
790
791 debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
792
793 return Success;
794 }
795
796
797 /*
798 *-----------------------------------------------------------------------------
799 *
800 * vmw_xv_put_image --
801 *
802 * Main video playback function. It copies the passed data which is in
803 * the specified format (e.g. FOURCC_YV12) into the overlay.
804 *
805 * If sync is TRUE the driver should not return from this
806 * function until it is through reading the data from buf.
807 *
808 * Results:
809 * Success or XvBadAlloc on failure
810 *
811 * Side effects:
812 * Video port will be played(initialized if 1st frame) on success
813 * or will fail on error.
814 *
815 *-----------------------------------------------------------------------------
816 */
817
818 static int
819 vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
820 short drw_x, short drw_y, short src_w, short src_h,
821 short drw_w, short drw_h, int format,
822 unsigned char *buf, short width, short height,
823 Bool sync, RegionPtr clipBoxes, pointer data,
824 DrawablePtr dst)
825 {
826 struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
827 struct vmw_video_port *port = data;
828
829 debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
830 src_x, src_y, src_w, src_h,
831 drw_x, drw_y, drw_w, drw_h,
832 width, height);
833
834 if (!vmw->video_priv)
835 return XvBadAlloc;
836
837 return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
838 drw_w, drw_h, format, buf, width, height, clipBoxes);
839 }
840
841
842 /*
843 *-----------------------------------------------------------------------------
844 *
845 * vmw_xv_stop_video --
846 *
847 * Called when we should stop playing video for a particular stream. If
848 * Cleanup is FALSE, the "stop" operation is only temporary, and thus we
849 * don't do anything. If Cleanup is TRUE we kill the video port by
850 * sending a message to the host and freeing up the stream.
851 *
852 * Results:
853 * None.
854 *
855 * Side effects:
856 * See above.
857 *
858 *-----------------------------------------------------------------------------
859 */
860
861 static void
862 vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
863 {
864 struct vmw_customizer *vmw = vmw_customizer(xorg_customizer(pScrn));
865 struct vmw_video_port *port = data;
866 struct drm_vmw_control_stream_arg arg;
867 int ret;
868
869 debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
870
871 if (!vmw->video_priv)
872 return;
873
874 REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
875
876 if (!cleanup)
877 return;
878
879
880 memset(&arg, 0, sizeof(arg));
881 arg.stream_id = port->streamId;
882 arg.enabled = FALSE;
883
884 ret = drmCommandWrite(vmw->fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
885 assert(ret == 0);
886
887 vmw_video_port_cleanup(pScrn, port);
888 }
889
890
891 /*
892 *-----------------------------------------------------------------------------
893 *
894 * vmw_xv_query_image_attributes --
895 *
896 * From the spec: This function is called to let the driver specify how data
897 * for a particular image of size width by height should be stored.
898 * Sometimes only the size and corrected width and height are needed. In
899 * that case pitches and offsets are NULL.
900 *
901 * Results:
902 * The size of the memory required for the image, or -1 on error.
903 *
904 * Side effects:
905 * None.
906 *
907 *-----------------------------------------------------------------------------
908 */
909
910 static int
911 vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
912 unsigned short *width, unsigned short *height,
913 int *pitches, int *offsets)
914 {
915 INT32 size, tmp;
916
917 if (*width > VMWARE_VID_MAX_WIDTH) {
918 *width = VMWARE_VID_MAX_WIDTH;
919 }
920 if (*height > VMWARE_VID_MAX_HEIGHT) {
921 *height = VMWARE_VID_MAX_HEIGHT;
922 }
923
924 *width = (*width + 1) & ~1;
925 if (offsets != NULL) {
926 offsets[0] = 0;
927 }
928
929 switch (format) {
930 case FOURCC_YV12:
931 *height = (*height + 1) & ~1;
932 size = (*width + 3) & ~3;
933 if (pitches) {
934 pitches[0] = size;
935 }
936 size *= *height;
937 if (offsets) {
938 offsets[1] = size;
939 }
940 tmp = ((*width >> 1) + 3) & ~3;
941 if (pitches) {
942 pitches[1] = pitches[2] = tmp;
943 }
944 tmp *= (*height >> 1);
945 size += tmp;
946 if (offsets) {
947 offsets[2] = size;
948 }
949 size += tmp;
950 break;
951 case FOURCC_UYVY:
952 case FOURCC_YUY2:
953 size = *width * 2;
954 if (pitches) {
955 pitches[0] = size;
956 }
957 size *= *height;
958 break;
959 default:
960 debug_printf("Query for invalid video format %d\n", format);
961 return -1;
962 }
963 return size;
964 }
965
966
967 /*
968 *-----------------------------------------------------------------------------
969 *
970 * vmw_xv_set_port_attribute --
971 *
972 * From the spec: A port may have particular attributes such as colorKey, hue,
973 * saturation, brightness or contrast. Xv clients set these
974 * attribute values by sending attribute strings (Atoms) to the server.
975 *
976 * Results:
977 * Success if the attribute exists and XvBadAlloc otherwise.
978 *
979 * Side effects:
980 * The respective attribute gets the new value.
981 *
982 *-----------------------------------------------------------------------------
983 */
984
985 static int
986 vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
987 INT32 value, pointer data)
988 {
989 struct vmw_video_port *port = data;
990 Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
991 Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
992
993 if (attribute == xvColorKey) {
994 debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
995 port->colorKey = value;
996 } else if (attribute == xvAutoPaint) {
997 debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
998 port->isAutoPaintColorkey = value;
999 } else {
1000 return XvBadAlloc;
1001 }
1002
1003 return Success;
1004 }
1005
1006
1007 /*
1008 *-----------------------------------------------------------------------------
1009 *
1010 * vmw_xv_get_port_attribute --
1011 *
1012 * From the spec: A port may have particular attributes such as hue,
1013 * saturation, brightness or contrast. Xv clients get these
1014 * attribute values by sending attribute strings (Atoms) to the server
1015 *
1016 * Results:
1017 * Success if the attribute exists and XvBadAlloc otherwise.
1018 *
1019 * Side effects:
1020 * "value" contains the requested attribute on success.
1021 *
1022 *-----------------------------------------------------------------------------
1023 */
1024
1025 static int
1026 vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
1027 INT32 *value, pointer data)
1028 {
1029 struct vmw_video_port *port = data;
1030 Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
1031 Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1032
1033 if (attribute == xvColorKey) {
1034 *value = port->colorKey;
1035 } else if (attribute == xvAutoPaint) {
1036 *value = port->isAutoPaintColorkey;
1037 } else {
1038 return XvBadAlloc;
1039 }
1040
1041 return Success;
1042 }
1043
1044
1045 /*
1046 *-----------------------------------------------------------------------------
1047 *
1048 * vmw_xv_query_best_size --
1049 *
1050 * From the spec: QueryBestSize provides the client with a way to query what
1051 * the destination dimensions would end up being if they were to request
1052 * that an area vid_w by vid_h from the video stream be scaled to rectangle
1053 * of drw_w by drw_h on the screen. Since it is not expected that all
1054 * hardware will be able to get the target dimensions exactly, it is
1055 * important that the driver provide this function.
1056 *
1057 * This function seems to never be called, but to be on the safe side
1058 * we apply the same logic that QueryImageAttributes has for width
1059 * and height.
1060 *
1061 * Results:
1062 * None.
1063 *
1064 * Side effects:
1065 * None.
1066 *
1067 *-----------------------------------------------------------------------------
1068 */
1069
1070 static void
1071 vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
1072 short vid_w, short vid_h, short drw_w,
1073 short drw_h, unsigned int *p_w,
1074 unsigned int *p_h, pointer data)
1075 {
1076 *p_w = (drw_w + 1) & ~1;
1077 *p_h = drw_h;
1078
1079 return;
1080 }