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