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