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