vmwgfx_overlay.c revision 25dbecb6
1/*
2 * Copyright 2007-2011 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/*
30 * vmwarevideo.c --
31 *
32 *      Xv extension support.
33 *      See http://www.xfree86.org/current/DESIGN16.html
34 *
35 */
36#ifdef HAVE_CONFIG_H
37#include "config.h"
38#endif
39
40
41#include "xorg-server.h"
42#include "xf86xv.h"
43#include "fourcc.h"
44#define debug_printf(...)
45
46/*
47 * We can't incude svga_types.h due to conflicting types for Bool.
48 */
49typedef int64_t int64;
50typedef uint64_t uint64;
51
52typedef int32_t int32;
53typedef uint32_t uint32;
54
55typedef int16_t int16;
56typedef uint16_t uint16;
57
58typedef int8_t int8;
59typedef uint8_t uint8;
60
61#include "../src/svga_reg.h"
62#include "../src/svga_escape.h"
63#include "../src/svga_overlay.h"
64#include "../src/common_compat.h"
65
66#include <X11/extensions/Xv.h>
67
68#include "xf86drm.h"
69#include "vmwgfx_drm.h"
70#include "vmwgfx_drmi.h"
71#include "vmwgfx_driver.h"
72#include "vmwgfx_hosted.h"
73
74#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
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",
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 * Must be power or two, See vmw_video_port_play.
141 */
142#define VMWARE_VID_NUM_BUFFERS 1
143
144/*
145 * Defines the structure used to hold and pass video data to the host
146 */
147struct vmw_video_buffer
148{
149    int size;
150    void *data;
151    struct vmwgfx_dmabuf *buf;
152};
153
154
155/**
156 * Structure representing a single video stream, aka port.
157 *
158 * Ports maps one to one to a SVGA stream. Port is just
159 * what Xv calls a SVGA stream.
160 */
161struct vmwgfx_overlay_port
162{
163    /*
164     * Function prototype same as XvPutImage.
165     *
166     * This is either set to vmw_video_port_init or vmw_video_port_play.
167     * At init this function is set to port_init. In port_init we set it
168     * to port_play and call it, after initializing the struct.
169     */
170    int (*play)(ScrnInfoPtr, struct vmwgfx_overlay_port *,
171                short, short, short, short, short,
172                short, short, short, int, unsigned char*,
173                short, short, RegionPtr, DrawablePtr);
174
175    /* values to go into the SVGAOverlayUnit */
176    uint32 streamId;
177    uint32 colorKey;
178    uint32 flags;
179
180    /* round robin of buffers */
181    unsigned currBuf;
182    struct vmw_video_buffer bufs[VMWARE_VID_NUM_BUFFERS];
183
184    /* properties that applies to all buffers */
185    int size;
186    int pitches[3];
187    int offsets[3];
188
189    /* things for X */
190    RegionRec clipBoxes;
191    Bool isAutoPaintColorkey;
192    int drm_fd;
193};
194
195/*
196 * Callback functions exported to Xv, prefixed with vmw_xv_*.
197 */
198static int vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
199                            short drw_x, short drw_y, short src_w, short src_h,
200                            short drw_w, short drw_h, int image,
201                            unsigned char *buf, short width, short height,
202                            Bool sync, RegionPtr clipBoxes, pointer data,
203                            DrawablePtr dst);
204static void vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool Cleanup);
205static int vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
206                                         unsigned short *width,
207                                         unsigned short *height, int *pitches,
208                                         int *offsets);
209static int vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
210                                     INT32 value, pointer data);
211static int vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
212                                     INT32 *value, pointer data);
213static void vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
214                                short vid_w, short vid_h, short drw_w,
215                                short drw_h, unsigned int *p_w,
216                                unsigned int *p_h, pointer data);
217
218
219/*
220 * Local functions.
221 */
222static int vmw_video_port_init(ScrnInfoPtr pScrn,
223                               struct vmwgfx_overlay_port *port,
224                               short src_x, short src_y, short drw_x,
225                               short drw_y, short src_w, short src_h,
226                               short drw_w, short drw_h, int format,
227                               unsigned char *buf, short width,
228                               short height, RegionPtr clipBoxes,
229                               DrawablePtr pDraw);
230static int vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
231                               short src_x, short src_y, short drw_x,
232                               short drw_y, short src_w, short src_h,
233                               short drw_w, short drw_h, int format,
234                               unsigned char *buf, short width,
235                               short height, RegionPtr clipBoxes,
236                               DrawablePtr pDraw);
237static void vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port);
238
239static int vmw_video_buffer_alloc(int drm_fd, int size,
240                                  struct vmw_video_buffer *out);
241static int vmw_video_buffer_free(struct vmw_video_buffer *out);
242
243
244static struct vmwgfx_overlay_port *
245vmwgfx_overlay_port_create(int drm_fd, ScreenPtr pScreen)
246{
247    struct vmwgfx_overlay_port *port = calloc(1, sizeof(*port));
248
249    if (!port)
250	return NULL;
251
252    port->drm_fd = drm_fd;
253    port->play = vmw_video_port_init;
254    port->flags = SVGA_VIDEO_FLAG_COLORKEY;
255    port->colorKey = VMWARE_VIDEO_COLORKEY;
256    port->isAutoPaintColorkey = TRUE;
257    return port;
258}
259
260void
261vmw_video_free_adaptor(XF86VideoAdaptorPtr adaptor)
262{
263    int i;
264
265    for (i = 0; i < adaptor->nPorts; ++i)
266	free(adaptor->pPortPrivates[i].ptr);
267
268    free(adaptor->pPortPrivates);
269    xf86XVFreeVideoAdaptorRec(adaptor);
270}
271
272/*
273 *-----------------------------------------------------------------------------
274 *
275 * vmw_video_init_adaptor --
276 *
277 *    Initializes a XF86VideoAdaptor structure with the capabilities and
278 *    functions supported by this video driver.
279 *
280 * Results:
281 *    On success initialized XF86VideoAdaptor struct or NULL on error
282 *
283 * Side effects:
284 *    None.
285 *
286 *-----------------------------------------------------------------------------
287 */
288
289XF86VideoAdaptorPtr
290vmw_video_init_adaptor(ScrnInfoPtr pScrn)
291{
292    XF86VideoAdaptorPtr adaptor;
293    modesettingPtr ms = modesettingPTR(pScrn);
294    int i;
295    DevUnion *dev_unions;
296    uint32_t ntot, nfree;
297
298    if (vmwgfx_is_hosted(ms->hdriver))
299	return NULL;
300
301    if (vmwgfx_num_streams(ms->fd, &ntot, &nfree) != 0) {
302        debug_printf("No stream ioctl support\n");
303        return NULL;
304    }
305    if (nfree == 0) {
306        debug_printf("No free streams\n");
307        return NULL;
308    }
309    adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
310    dev_unions = calloc(VMWARE_VID_NUM_PORTS, sizeof(DevUnion));
311    if (adaptor == NULL || dev_unions == NULL) {
312	xf86XVFreeVideoAdaptorRec(adaptor);
313	free(dev_unions);
314	return NULL;
315    }
316
317    adaptor->type = XvInputMask | XvImageMask | XvWindowMask;
318
319    /**
320     * Note: CLIP_TO_VIEWPORT was removed from the flags, since with the
321     * crtc/output based modesetting, the viewport is not updated on
322     * RandR modeswitches. Hence the video may incorrectly be clipped away.
323     * The correct approach, (if needed) would be to clip against the
324     * scanout area union of all active crtcs. Revisit if needed.
325     */
326
327    adaptor->flags = VIDEO_OVERLAID_IMAGES;
328    adaptor->name = "VMware Overlay Video Engine";
329    adaptor->nEncodings = VMWARE_VID_NUM_ENCODINGS;
330    adaptor->pEncodings = vmwareVideoEncodings;
331    adaptor->nFormats = VMWARE_VID_NUM_FORMATS;
332    adaptor->pFormats = vmwareVideoFormats;
333    adaptor->nPorts = VMWARE_VID_NUM_PORTS;
334    adaptor->pPortPrivates = dev_unions;
335
336    for (i = 0; i < VMWARE_VID_NUM_PORTS; ++i) {
337	struct vmwgfx_overlay_port *priv =
338	    vmwgfx_overlay_port_create(ms->fd, pScrn->pScreen);
339
340        adaptor->pPortPrivates[i].ptr = (pointer) priv;
341    }
342
343    adaptor->nAttributes = VMWARE_VID_NUM_ATTRIBUTES;
344    adaptor->pAttributes = vmwareVideoAttributes;
345    adaptor->nImages = VMWARE_VID_NUM_IMAGES;
346    adaptor->pImages = vmwareVideoImages;
347
348    adaptor->PutVideo = NULL;
349    adaptor->PutStill = NULL;
350    adaptor->GetVideo = NULL;
351    adaptor->GetStill = NULL;
352    adaptor->StopVideo = vmw_xv_stop_video;
353    adaptor->SetPortAttribute = vmw_xv_set_port_attribute;
354    adaptor->GetPortAttribute = vmw_xv_get_port_attribute;
355    adaptor->QueryBestSize = vmw_xv_query_best_size;
356    adaptor->PutImage = vmw_xv_put_image;
357    adaptor->QueryImageAttributes = vmw_xv_query_image_attributes;
358
359    return adaptor;
360}
361
362
363/*
364 *-----------------------------------------------------------------------------
365 *
366 * vmw_video_port_init --
367 *
368 *    Initializes a video stream in response to the first PutImage() on a
369 *    video stream. The process goes as follows:
370 *    - Figure out characteristics according to format
371 *    - Allocate offscreen memory
372 *    - Pass on video to Play() functions
373 *
374 * Results:
375 *    Success or XvBadAlloc on failure.
376 *
377 * Side effects:
378 *    Video stream is initialized and its first frame sent to the host
379 *    (done by VideoPlay() function called at the end)
380 *
381 *-----------------------------------------------------------------------------
382 */
383
384static int
385vmw_video_port_init(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
386                    short src_x, short src_y, short drw_x,
387                    short drw_y, short src_w, short src_h,
388                    short drw_w, short drw_h, int format,
389                    unsigned char *buf, short width,
390                    short height, RegionPtr clipBoxes, DrawablePtr pDraw)
391{
392    unsigned short w, h;
393    int i, ret;
394
395    debug_printf("\t%s: id %d, format %d\n", __func__, port->streamId, format);
396
397    ret = vmwgfx_claim_stream(port->drm_fd, &port->streamId);
398    if (ret != 0)
399	return XvBadAlloc;
400
401    w = width;
402    h = height;
403    /* init all the format attributes, used for buffers */
404    port->size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
405                                               port->pitches, port->offsets);
406
407    if (port->size == -1) {
408	ret = XvBadAlloc;
409	goto out_bad_size;
410    }
411
412    for (i = 0; i < VMWARE_VID_NUM_BUFFERS; ++i) {
413	ret = vmw_video_buffer_alloc(port->drm_fd, port->size, &port->bufs[i]);
414	if (ret != Success)
415	    goto out_no_buffer;
416    }
417
418    port->currBuf = 0;
419    REGION_NULL(pScrn->pScreen, &port->clipBoxes);
420    port->play = vmw_video_port_play;
421    return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
422                      drw_w, drw_h, format, buf, width, height, clipBoxes, pDraw);
423
424  out_no_buffer:
425    while(i-- != 0) {
426	vmw_video_buffer_free(&port->bufs[i]);
427    }
428  out_bad_size:
429    (void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
430
431    return ret;
432}
433
434
435/*
436 *-----------------------------------------------------------------------------
437 *
438 * vmw_video_port_play --
439 *
440 *    Sends all the attributes associated with the video frame using the
441 *    FIFO ESCAPE mechanism to the host.
442 *
443 * Results:
444 *    Always returns Success.
445 *
446 * Side effects:
447 *    None.
448 *
449 *-----------------------------------------------------------------------------
450 */
451
452static int
453vmw_video_port_play(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port,
454                    short src_x, short src_y, short drw_x,
455                    short drw_y, short src_w, short src_h,
456                    short drw_w, short drw_h, int format,
457                    unsigned char *buf, short width,
458                    short height, RegionPtr clipBoxes, DrawablePtr pDraw)
459{
460    struct drm_vmw_control_stream_arg arg;
461    unsigned short w, h;
462    int size;
463    int ret;
464
465    debug_printf("\t%s: enter\n", __func__);
466
467    w = width;
468    h = height;
469
470    /* we don't update the ports size */
471    size = vmw_xv_query_image_attributes(pScrn, format, &w, &h,
472                                         port->pitches, port->offsets);
473
474    if (size != port->size) {
475        vmw_xv_stop_video(pScrn, port, TRUE);
476        return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w,
477                          src_h, drw_w, drw_h, format, buf, width, height,
478                          clipBoxes, pDraw);
479    }
480
481    memcpy(port->bufs[port->currBuf].data, buf, port->size);
482
483    memset(&arg, 0, sizeof(arg));
484
485    arg.stream_id = port->streamId;
486    arg.enabled = TRUE;
487    arg.flags = port->flags;
488    arg.color_key = port->colorKey;
489    arg.handle = port->bufs[port->currBuf].buf->handle;
490    arg.format = format;
491    arg.size = port->size;
492    arg.width = w;
493    arg.height = h;
494    arg.src.x = src_x;
495    arg.src.y = src_y;
496    arg.src.w = src_w;
497    arg.src.h = src_h;
498    arg.dst.x = drw_x;
499    arg.dst.y = drw_y;
500    arg.dst.w = drw_w;
501    arg.dst.h = drw_h;
502    arg.pitch[0] = port->pitches[0];
503    arg.pitch[1] = port->pitches[1];
504    arg.pitch[2] = port->pitches[2];
505    arg.offset = 0;
506
507    /*
508     *  Update the clipList and paint the colorkey, if required.
509     */
510    if (!REGION_EQUAL(pScrn->pScreen, &port->clipBoxes, clipBoxes)) {
511        REGION_COPY(pScrn->pScreen, &port->clipBoxes, clipBoxes);
512        if (port->isAutoPaintColorkey) {
513            if (pDraw->type == DRAWABLE_WINDOW) {
514                xf86XVFillKeyHelperDrawable(pDraw, port->colorKey, clipBoxes);
515                DamageDamageRegion(pDraw, clipBoxes);
516            } else {
517                xf86XVFillKeyHelper(pScrn->pScreen, port->colorKey, clipBoxes);
518            }
519        }
520    }
521
522    xorg_flush(pScrn->pScreen);
523    ret = drmCommandWrite(port->drm_fd, DRM_VMW_CONTROL_STREAM, &arg, sizeof(arg));
524    if (ret) {
525	vmw_video_port_cleanup(pScrn, port);
526	return XvBadAlloc;
527    }
528
529    if (++(port->currBuf) >= VMWARE_VID_NUM_BUFFERS)
530	port->currBuf = 0;
531
532    return Success;
533}
534
535
536/*
537 *-----------------------------------------------------------------------------
538 *
539 * vmw_video_port_cleanup --
540 *
541 *    Frees up all resources (if any) taken by a video stream.
542 *
543 * Results:
544 *    None.
545 *
546 * Side effects:
547 *    Same as above.
548 *
549 *-----------------------------------------------------------------------------
550 */
551
552static void
553vmw_video_port_cleanup(ScrnInfoPtr pScrn, struct vmwgfx_overlay_port *port)
554{
555    int i;
556
557    debug_printf("\t%s: enter\n", __func__);
558
559    if (port->play == vmw_video_port_init)
560	return;
561
562    port->play = vmw_video_port_init;
563    (void) vmwgfx_unref_stream(port->drm_fd, port->streamId);
564
565    for (i = 0; i < VMWARE_VID_NUM_BUFFERS; i++) {
566	vmw_video_buffer_free(&port->bufs[i]);
567    }
568
569    REGION_UNINIT(pScreen->pScreen, &port->clipBoxes);
570}
571
572
573/*
574 *-----------------------------------------------------------------------------
575 *
576 * vmw_video_buffer_alloc --
577 *
578 *    Allocates and map a kernel buffer to be used as data storage.
579 *
580 * Results:
581 *    XvBadAlloc on failure, otherwise Success.
582 *
583 * Side effects:
584 *    Calls into the kernel, sets members of out.
585 *
586 *-----------------------------------------------------------------------------
587 */
588
589static int
590vmw_video_buffer_alloc(int drm_fd, int size,
591                       struct vmw_video_buffer *out)
592{
593    out->buf = vmwgfx_dmabuf_alloc(drm_fd, size);
594    if (!out->buf)
595	return XvBadAlloc;
596
597    out->data = vmwgfx_dmabuf_map(out->buf);
598    if (!out->data) {
599	vmwgfx_dmabuf_destroy(out->buf);
600	out->buf = NULL;
601	return XvBadAlloc;
602    }
603
604    out->size = size;
605    debug_printf("\t\t%s: allocated buffer %p of size %i\n", __func__, out, size);
606
607    return Success;
608}
609
610
611/*
612 *-----------------------------------------------------------------------------
613 *
614 * vmw_video_buffer_free --
615 *
616 *    Frees and unmaps an allocated kernel buffer.
617 *
618 * Results:
619 *    Success.
620 *
621 * Side effects:
622 *    Calls into the kernel, sets members of out to 0.
623 *
624 *-----------------------------------------------------------------------------
625 */
626
627static int
628vmw_video_buffer_free(struct vmw_video_buffer *out)
629{
630    if (out->size == 0)
631	return Success;
632
633    vmwgfx_dmabuf_unmap(out->buf);
634    vmwgfx_dmabuf_destroy(out->buf);
635
636    out->buf = NULL;
637    out->data = NULL;
638    out->size = 0;
639
640    debug_printf("\t\t%s: freed buffer %p\n", __func__, out);
641
642    return Success;
643}
644
645
646/*
647 *-----------------------------------------------------------------------------
648 *
649 * vmw_xv_put_image --
650 *
651 *    Main video playback function. It copies the passed data which is in
652 *    the specified format (e.g. FOURCC_YV12) into the overlay.
653 *
654 *    If sync is TRUE the driver should not return from this
655 *    function until it is through reading the data from buf.
656 *
657 * Results:
658 *    Success or XvBadAlloc on failure
659 *
660 * Side effects:
661 *    Video port will be played(initialized if 1st frame) on success
662 *    or will fail on error.
663 *
664 *-----------------------------------------------------------------------------
665 */
666
667static int
668vmw_xv_put_image(ScrnInfoPtr pScrn, short src_x, short src_y,
669                 short drw_x, short drw_y, short src_w, short src_h,
670                 short drw_w, short drw_h, int format,
671                 unsigned char *buf, short width, short height,
672                 Bool sync, RegionPtr clipBoxes, pointer data,
673                 DrawablePtr dst)
674{
675    struct vmwgfx_overlay_port *port = data;
676
677    debug_printf("%s: enter (%u, %u) (%ux%u) (%u, %u) (%ux%u) (%ux%u)\n", __func__,
678		 src_x, src_y, src_w, src_h,
679		 drw_x, drw_y, drw_w, drw_h,
680		 width, height);
681
682    return port->play(pScrn, port, src_x, src_y, drw_x, drw_y, src_w, src_h,
683                      drw_w, drw_h, format, buf, width, height, clipBoxes, dst);
684}
685
686
687/*
688 *-----------------------------------------------------------------------------
689 *
690 * vmw_xv_stop_video --
691 *
692 *    Called when we should stop playing video for a particular stream. If
693 *    Cleanup is FALSE, the "stop" operation is only temporary, and thus we
694 *    don't do anything. If Cleanup is TRUE we kill the video port by
695 *    sending a message to the host and freeing up the stream.
696 *
697 * Results:
698 *    None.
699 *
700 * Side effects:
701 *    See above.
702 *
703 *-----------------------------------------------------------------------------
704 */
705
706static void
707vmw_xv_stop_video(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
708{
709    struct vmwgfx_overlay_port *port = data;
710
711    debug_printf("%s: cleanup is %s\n", __func__, cleanup ? "TRUE" : "FALSE");
712    REGION_EMPTY(pScrn->pScreen, &port->clipBoxes);
713
714    if (!cleanup)
715        return;
716
717    vmw_video_port_cleanup(pScrn, port);
718}
719
720
721/*
722 *-----------------------------------------------------------------------------
723 *
724 * vmw_xv_query_image_attributes --
725 *
726 *    From the spec: This function is called to let the driver specify how data
727 *    for a particular image of size width by height should be stored.
728 *    Sometimes only the size and corrected width and height are needed. In
729 *    that case pitches and offsets are NULL.
730 *
731 * Results:
732 *    The size of the memory required for the image, or -1 on error.
733 *
734 * Side effects:
735 *    None.
736 *
737 *-----------------------------------------------------------------------------
738 */
739
740static int
741vmw_xv_query_image_attributes(ScrnInfoPtr pScrn, int format,
742                              unsigned short *width, unsigned short *height,
743                              int *pitches, int *offsets)
744{
745    INT32 size, tmp;
746
747    if (*width > VMWARE_VID_MAX_WIDTH) {
748        *width = VMWARE_VID_MAX_WIDTH;
749    }
750    if (*height > VMWARE_VID_MAX_HEIGHT) {
751        *height = VMWARE_VID_MAX_HEIGHT;
752    }
753
754    *width = (*width + 1) & ~1;
755    if (offsets != NULL) {
756        offsets[0] = 0;
757    }
758
759    switch (format) {
760       case FOURCC_YV12:
761           *height = (*height + 1) & ~1;
762           size = (*width + 3) & ~3;
763           if (pitches) {
764               pitches[0] = size;
765           }
766           size *= *height;
767           if (offsets) {
768               offsets[1] = size;
769           }
770           tmp = ((*width >> 1) + 3) & ~3;
771           if (pitches) {
772                pitches[1] = pitches[2] = tmp;
773           }
774           tmp *= (*height >> 1);
775           size += tmp;
776           if (offsets) {
777               offsets[2] = size;
778           }
779           size += tmp;
780           break;
781       case FOURCC_UYVY:
782       case FOURCC_YUY2:
783           size = *width * 2;
784           if (pitches) {
785               pitches[0] = size;
786           }
787           size *= *height;
788           break;
789       default:
790           debug_printf("Query for invalid video format %d\n", format);
791           return -1;
792    }
793    return size;
794}
795
796
797/*
798 *-----------------------------------------------------------------------------
799 *
800 * vmw_xv_set_port_attribute --
801 *
802 *    From the spec: A port may have particular attributes such as colorKey, hue,
803 *    saturation, brightness or contrast. Xv clients set these
804 *    attribute values by sending attribute strings (Atoms) to the server.
805 *
806 * Results:
807 *    Success if the attribute exists and XvBadAlloc otherwise.
808 *
809 * Side effects:
810 *    The respective attribute gets the new value.
811 *
812 *-----------------------------------------------------------------------------
813 */
814
815static int
816vmw_xv_set_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
817                          INT32 value, pointer data)
818{
819    struct vmwgfx_overlay_port *port = data;
820    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
821    Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
822
823    if (attribute == xvColorKey) {
824        debug_printf("%s: Set colorkey:0x%x\n", __func__, (unsigned)value);
825        port->colorKey = value;
826    } else if (attribute == xvAutoPaint) {
827        debug_printf("%s: Set autoPaint: %s\n", __func__, value? "TRUE": "FALSE");
828        port->isAutoPaintColorkey = value;
829    } else {
830        return XvBadAlloc;
831    }
832
833    return Success;
834}
835
836
837/*
838 *-----------------------------------------------------------------------------
839 *
840 * vmw_xv_get_port_attribute --
841 *
842 *    From the spec: A port may have particular attributes such as hue,
843 *    saturation, brightness or contrast. Xv clients get these
844 *    attribute values by sending attribute strings (Atoms) to the server
845 *
846 * Results:
847 *    Success if the attribute exists and XvBadAlloc otherwise.
848 *
849 * Side effects:
850 *    "value" contains the requested attribute on success.
851 *
852 *-----------------------------------------------------------------------------
853 */
854
855static int
856vmw_xv_get_port_attribute(ScrnInfoPtr pScrn, Atom attribute,
857                          INT32 *value, pointer data)
858{
859    struct vmwgfx_overlay_port *port = data;
860    Atom xvColorKey = MAKE_ATOM("XV_COLORKEY");
861    Atom xvAutoPaint = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
862
863    if (attribute == xvColorKey) {
864        *value = port->colorKey;
865    } else if (attribute == xvAutoPaint) {
866        *value = port->isAutoPaintColorkey;
867    } else {
868        return XvBadAlloc;
869    }
870
871    return Success;
872}
873
874
875/*
876 *-----------------------------------------------------------------------------
877 *
878 * vmw_xv_query_best_size --
879 *
880 *    From the spec: QueryBestSize provides the client with a way to query what
881 *    the destination dimensions would end up being if they were to request
882 *    that an area vid_w by vid_h from the video stream be scaled to rectangle
883 *    of drw_w by drw_h on the screen. Since it is not expected that all
884 *    hardware will be able to get the target dimensions exactly, it is
885 *    important that the driver provide this function.
886 *
887 *    This function seems to never be called, but to be on the safe side
888 *    we apply the same logic that QueryImageAttributes has for width
889 *    and height.
890 *
891 * Results:
892 *    None.
893 *
894 * Side effects:
895 *    None.
896 *
897 *-----------------------------------------------------------------------------
898 */
899
900static void
901vmw_xv_query_best_size(ScrnInfoPtr pScrn, Bool motion,
902                       short vid_w, short vid_h, short drw_w,
903                       short drw_h, unsigned int *p_w,
904                       unsigned int *p_h, pointer data)
905{
906    *p_w = (drw_w + 1) & ~1;
907    *p_h = drw_h;
908
909    return;
910}
911