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