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