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