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