vmwgfx_tex_video.c revision 34a0776d
1/* 2 * Copyright 2009-2011 VMWare, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Author: Thomas Hellstrom <thellstrom@vmware.com> 26 * Author: Zack Rusin <zackr@vmware.com> 27 */ 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include "vmwgfx_driver.h" 33#include "vmwgfx_drmi.h" 34#include "vmwgfx_saa.h" 35 36#include <xf86xv.h> 37#include <X11/extensions/Xv.h> 38#include <fourcc.h> 39#include <xa_tracker.h> 40#include <xa_context.h> 41#include <math.h> 42 43/*XXX get these from pipe's texture limits */ 44#define IMAGE_MAX_WIDTH 2048 45#define IMAGE_MAX_HEIGHT 2048 46 47#define RES_720P_X 1280 48#define RES_720P_Y 720 49 50 51#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 52 53/* 54 * ITU-R BT.601, BT.709 transfer matrices. 55 * [R', G', B'] values are in the range [0, 1], Y' is in the range [0,1] 56 * and [Pb, Pr] components are in the range [-0.5, 0.5]. 57 * 58 * The matrices are transposed to fit the xa conversion matrix format. 59 */ 60 61static const float bt_601[] = { 62 1.f, 1.f, 1.f, 0.f, 63 0.f, -0.344136f, 1.772f, 0.f, 64 1.402f, -0.714136f, 0.f, 0.f 65}; 66 67static const float bt_709[] = { 68 1.f, 1.f, 1.f, 0.f, 69 0.f, -0.187324f, 1.8556f, 0.f, 70 1.5748f, -0.468124f, 0.f, 0.f 71}; 72 73static Atom xvBrightness, xvContrast, xvSaturation, xvHue; 74 75#define NUM_TEXTURED_ATTRIBUTES 4 76static const XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { 77 {XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS"}, 78 {XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST"}, 79 {XvSettable | XvGettable, -1000, 1000, "XV_SATURATION"}, 80 {XvSettable | XvGettable, -1000, 1000, "XV_HUE"} 81}; 82 83#define NUM_FORMATS 3 84static XF86VideoFormatRec Formats[NUM_FORMATS] = { 85 {15, TrueColor}, {16, TrueColor}, {24, TrueColor} 86}; 87 88static XF86VideoEncodingRec DummyEncoding[1] = { 89 { 90 0, 91 "XV_IMAGE", 92 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 93 {1, 1} 94 } 95}; 96 97#define NUM_IMAGES 3 98static XF86ImageRec Images[NUM_IMAGES] = { 99 XVIMAGE_UYVY, 100 XVIMAGE_YUY2, 101 XVIMAGE_YV12, 102}; 103 104struct xorg_xv_port_priv { 105 struct xa_tracker *xat; 106 struct xa_context *r; 107 struct xa_fence *fence; 108 109 RegionRec clip; 110 111 int brightness; 112 int contrast; 113 int saturation; 114 int hue; 115 116 int current_set; 117 struct xa_surface *yuv[2][3]; 118 119 struct xa_surface *bounce; 120 struct xa_box bounce_box; 121 struct xa_picture *src_pic; 122 struct xa_picture *dst_pic; 123 struct xa_composite *comp; 124 125 int drm_fd; 126 127 Bool hdtv; 128 float uv_offset; 129 float uv_scale; 130 float y_offset; 131 float y_scale; 132 float rgb_offset; 133 float rgb_scale; 134 float sinhue; 135 float coshue; 136 float cm[16]; 137}; 138 139/* 140 * vmwgfx_update_conversion_matrix - Compute the effective color conversion 141 * matrix. 142 * 143 * Applies yuv- and resulting rgb scales and offsets to compute the correct 144 * color conversion matrix. These scales and offsets are properties of the 145 * video stream and can be adjusted using XV properties as well. 146 */ 147static void 148vmwgfx_update_conversion_matrix(struct xorg_xv_port_priv *priv) 149{ 150 int i; 151 float *cm = priv->cm; 152 static const float *bt; 153 154 bt = (priv->hdtv) ? bt_709 : bt_601; 155 156 memcpy(cm, bt, sizeof(bt_601)); 157 158 /* 159 * Apply hue rotation 160 */ 161 cm[4] = priv->coshue * bt[4] - priv->sinhue * bt[8]; 162 cm[8] = priv->sinhue * bt[4] + priv->coshue * bt[8]; 163 cm[5] = priv->coshue * bt[5] - priv->sinhue * bt[9]; 164 cm[9] = priv->sinhue * bt[5] + priv->coshue * bt[9]; 165 cm[6] = priv->coshue * bt[6] - priv->sinhue * bt[10]; 166 cm[10] = priv->sinhue * bt[6] + priv->coshue * bt[10]; 167 168 /* 169 * Adjust for yuv scales in input and rgb scale in the converted output. 170 */ 171 for(i = 0; i < 3; ++i) { 172 cm[i] *= (priv->y_scale*priv->rgb_scale); 173 cm[i+4] *= (priv->uv_scale*priv->rgb_scale); 174 cm[i+8] *= (priv->uv_scale*priv->rgb_scale); 175 } 176 177 /* 178 * Adjust for yuv offsets in input and rgb offset in the converted output. 179 */ 180 for (i = 0; i < 3; ++i) 181 cm[i+12] = -cm[i]*priv->y_offset - (cm[i+4] + cm[i+8])*priv->uv_offset 182 - priv->rgb_offset*priv->rgb_scale; 183 184 /* 185 * Alpha is 1, unconditionally. 186 */ 187 cm[15] = 1.f; 188} 189 190/** 191 * vmwgfx_video_free_comp - free members used for composite bounce blit 192 * 193 * @priv: Pointer to the port private 194 * 195 * Frees any port priv resources allocated for a composite bounce blit. 196 */ 197static void 198vmwgfx_video_free_comp(struct xorg_xv_port_priv *priv) 199{ 200 if (priv->dst_pic) 201 free(priv->dst_pic); 202 if (priv->src_pic) 203 free(priv->src_pic); 204 if (priv->comp) 205 free(priv->comp); 206 207 priv->dst_pic = NULL; 208 priv->src_pic = NULL; 209 priv->comp = NULL; 210} 211 212static void 213stop_video(ScrnInfoPtr pScrn, pointer data, Bool shutdown) 214{ 215 struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; 216 int i, j; 217 218 REGION_EMPTY(pScrn->pScreen, &priv->clip); 219 if (shutdown) { 220 221 /* 222 * No need to destroy the xa context or xa tracker since 223 * they are copied from the screen resources. 224 */ 225 226 xa_fence_destroy(priv->fence); 227 priv->fence = NULL; 228 vmwgfx_video_free_comp(priv); 229 230 for (i=0; i<3; ++i) { 231 for (j=0; j<2; ++j) { 232 if (priv->yuv[i]) { 233 xa_surface_destroy(priv->yuv[j][i]); 234 priv->yuv[j][i] = NULL; 235 } 236 if (priv->bounce) { 237 xa_surface_destroy(priv->bounce); 238 priv->bounce = NULL; 239 } 240 } 241 } 242 } 243} 244 245static int 246set_port_attribute(ScrnInfoPtr pScrn, 247 Atom attribute, INT32 value, pointer data) 248{ 249 struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; 250 251 if (attribute == xvBrightness) { 252 if ((value < -1000) || (value > 1000)) 253 return BadValue; 254 255 priv->brightness = value; 256 priv->y_offset = -((float) value)/1000.f; 257 258 } else if (attribute == xvContrast) { 259 if ((value < -1000) || (value > 1000)) 260 return BadValue; 261 262 priv->contrast = value; 263 priv->rgb_scale = ((float) value + 1000.f)/1000.f; 264 265 } else if (attribute == xvSaturation) { 266 if ((value < -1000) || (value > 1000)) 267 return BadValue; 268 269 priv->saturation = value; 270 priv->uv_scale = ((float) value + 1000.f)/1000.f; 271 272 } else if (attribute == xvHue) { 273 double hue_angle; 274 275 if ((value < -1000) || (value > 1000)) 276 return BadValue; 277 278 priv->hue = value; 279 hue_angle = (double) value * M_PI / 1000.; 280 priv->sinhue = sin(hue_angle); 281 priv->coshue = cos(hue_angle); 282 283 } else 284 return BadMatch; 285 286 vmwgfx_update_conversion_matrix(priv); 287 return Success; 288} 289 290static int 291get_port_attribute(ScrnInfoPtr pScrn, 292 Atom attribute, INT32 * value, pointer data) 293{ 294 struct xorg_xv_port_priv *priv = (struct xorg_xv_port_priv *)data; 295 296 if (attribute == xvBrightness) 297 *value = priv->brightness; 298 else if (attribute == xvContrast) 299 *value = priv->contrast; 300 else if (attribute == xvSaturation) 301 *value = priv->saturation; 302 else if (attribute == xvHue) 303 *value = priv->hue; 304 else 305 return BadMatch; 306 307 return Success; 308} 309 310static void 311query_best_size(ScrnInfoPtr pScrn, 312 Bool motion, 313 short vid_w, short vid_h, 314 short drw_w, short drw_h, 315 unsigned int *p_w, unsigned int *p_h, pointer data) 316{ 317 if (vid_w > (drw_w << 1)) 318 drw_w = vid_w >> 1; 319 if (vid_h > (drw_h << 1)) 320 drw_h = vid_h >> 1; 321 322 *p_w = drw_w; 323 *p_h = drw_h; 324} 325 326static int 327check_yuv_surfaces(struct xorg_xv_port_priv *priv, int id, 328 int width, int height) 329{ 330 struct xa_surface **yuv = priv->yuv[priv->current_set]; 331 int ret = 0; 332 int i; 333 334 for (i=0; i<3; ++i) { 335 336 /* 337 * Adjust u,v texture size and DMA buffer to what's required by 338 * the format. 339 */ 340 if (i == 1) { 341 switch(id) { 342 case FOURCC_YV12: 343 height /= 2; 344 /* Fall through */ 345 case FOURCC_YUY2: 346 case FOURCC_UYVY: 347 width /= 2; 348 break; 349 default: 350 break; 351 } 352 } 353 354 if (!yuv[i]) 355 yuv[i] = xa_surface_create(priv->xat, width, height, 8, 356 xa_type_yuv_component, 357 xa_format_unknown, 0); 358 else 359 ret = xa_surface_redefine(yuv[i], width, height, 8, 360 xa_type_yuv_component, 361 xa_format_unknown, 0, 0); 362 if (ret || !yuv[i]) 363 return BadAlloc; 364 365 } 366 return Success; 367} 368 369 370/** 371 * vmwgfx_video_setup_comp - Set up port priv members for a composite 372 * bounce blit 373 * 374 * @priv: Pointer to the port priv. 375 * @format: XA format of the destination drawable surface. 376 * 377 * Tries to allocate and set up port priv resources to perform a composite 378 * bounce blit (except the bounce surface itself). On failure, all resources 379 * are freed. On success, TRUE is returned and @priv::comp is non-NULL. If 380 * resources are already allocated, update them for the current @format. 381 */ 382static Bool 383vmwgfx_video_setup_comp(struct xorg_xv_port_priv *priv, enum xa_formats format) 384{ 385 const struct xa_composite_allocation *alloc; 386 struct xa_picture *pic; 387 388 if (priv->comp) { 389 if (priv->src_pic->pict_format != format) { 390 priv->src_pic->pict_format = format; 391 priv->dst_pic->pict_format = format; 392 if (xa_composite_check_accelerated(priv->comp) != XA_ERR_NONE) { 393 vmwgfx_video_free_comp(priv); 394 return FALSE; 395 } 396 } 397 return TRUE; 398 } 399 400 alloc = xa_composite_allocation(); 401 priv->comp = calloc(1, alloc->xa_composite_size); 402 priv->src_pic = calloc(1, alloc->xa_picture_size); 403 priv->dst_pic = calloc(1, alloc->xa_picture_size); 404 405 if (!priv->comp || !priv->src_pic || !priv->dst_pic) { 406 vmwgfx_video_free_comp(priv); 407 return FALSE; 408 } 409 410 pic = priv->src_pic; 411 pic->pict_format = format; 412 pic->wrap = xa_wrap_clamp_to_border; 413 pic->filter = xa_filter_linear; 414 415 *priv->dst_pic = *pic; 416 417 priv->comp->src = priv->src_pic; 418 priv->comp->dst = priv->dst_pic; 419 priv->comp->op = xa_op_src; 420 priv->comp->no_solid = 1; 421 422 if (xa_composite_check_accelerated(priv->comp) != XA_ERR_NONE) { 423 vmwgfx_video_free_comp(priv); 424 return FALSE; 425 } 426 427 return TRUE; 428} 429 430/** 431 * vmwgfx_video_setup_coord_matrix - Set up a bounce - to destination 432 * transformation matrix 433 * 434 * @src_x: Upper left corner of source image as given to putImage. 435 * @src_y: Upper left corner of source image as given to putImage. 436 * @src_w: Width of source image. 437 * @src_h: Height of source image. 438 * @dst_x: Upper left corner of destination image as given to putImage. 439 * @dst_y: Upper left corner of destination image as given to putImage. 440 * @dst_w: Width of destination image. 441 * @dst_h: Height of destination image. 442 * @bounce_w: Width of bounce surface. 443 * @bounce_h: Height of bounce surface. 444 * @mat: Pointer to transformation matrix. 445 * 446 * Computes a transformation matrix that can be used by the XA composite API 447 * to transform between the destination coordinate space and the bounce 448 * surface coordinate space. Scaling and translation. 449 */ 450static void 451vmwgfx_video_setup_coord_matrix(int src_x, int src_y, int src_w, int src_h, 452 int dst_x, int dst_y, int dst_w, int dst_h, 453 int bounce_w, int bounce_h, 454 float *mat) 455{ 456 if (dst_w == 0 || dst_h == 0 || src_w == 0 || src_h == 0) { 457 mat[0] = mat[6] = 0.; 458 mat[4] = mat[7] = 0.; 459 mat[8] = 1.f; 460 return; 461 } 462 463 mat[0] = (float) bounce_w / (float) dst_w; 464 mat[6] = (float) src_x * (float) bounce_w / (float) src_w - 465 (float) dst_x * mat[0]; 466 mat[4] = (float) bounce_h / (float) dst_h; 467 mat[7] = (float) src_y * (float) bounce_h / (float) src_h - 468 (float) dst_y * mat[4]; 469 mat[8] = 1.f; 470} 471 472/** 473 * vmwgfx_video_bounce_surface: (Re)Allocate a bounce surface if desired. 474 * 475 * @priv: Pointer to the port private. 476 * @d_with: Width of destination image. 477 * @d_height: Height of destination image. 478 * @width: Width of source video image. 479 * @height: Height of source video image. 480 * @dst_format: Format of destination drawable surface. 481 * 482 * If the destination video image is a suitable factor larger than the source 483 * video image. Allocate a bounce RGB surface that will be the target of the 484 * more expensive color conversion blit, and source of the scaling blit. 485 */ 486static Bool 487vmwgfx_video_bounce_surface(struct xorg_xv_port_priv *priv, 488 int d_width, int d_height, 489 int width, int height, 490 enum xa_formats dst_format) 491{ 492 float bounce_area, dst_area; 493 494 if (d_width < width) 495 width = d_width; 496 497 if (d_height < height) 498 height = d_height; 499 500 bounce_area = (float) width * (float) height; 501 dst_area = (float) d_width * (float) d_height; 502 503 if (dst_area > bounce_area * 1.5f && 504 vmwgfx_video_setup_comp(priv, dst_format)) { 505 506 if (!priv->bounce) { 507 priv->bounce = xa_surface_create(priv->xat, width, height, 508 xa_format_depth(dst_format), 509 xa_format_type(dst_format), 510 dst_format, XA_FLAG_RENDER_TARGET); 511 } else { 512 if (xa_surface_redefine(priv->bounce, width, height, 513 xa_format_depth(dst_format), 514 xa_format_type(dst_format), 515 dst_format, 516 XA_FLAG_RENDER_TARGET, 0) != XA_ERR_NONE) { 517 xa_surface_destroy(priv->bounce); 518 priv->bounce = NULL; 519 } 520 } 521 522 } else { 523 xa_surface_destroy(priv->bounce); 524 priv->bounce = NULL; 525 } 526 527 if (priv->bounce) { 528 priv->bounce_box.x1 = 0; 529 priv->bounce_box.x2 = width; 530 priv->bounce_box.y1 = 0; 531 priv->bounce_box.y2 = height; 532 } 533 534 return TRUE; 535} 536 537static int 538query_image_attributes(ScrnInfoPtr pScrn, 539 int id, 540 unsigned short *w, unsigned short *h, 541 int *pitches, int *offsets) 542{ 543 int size, tmp; 544 545 if (*w > IMAGE_MAX_WIDTH) 546 *w = IMAGE_MAX_WIDTH; 547 if (*h > IMAGE_MAX_HEIGHT) 548 *h = IMAGE_MAX_HEIGHT; 549 550 *w = (*w + 1) & ~1; 551 if (offsets) 552 offsets[0] = 0; 553 554 switch (id) { 555 case FOURCC_YV12: 556 *h = (*h + 1) & ~1; 557 size = (*w + 3) & ~3; 558 if (pitches) { 559 pitches[0] = size; 560 } 561 size *= *h; 562 if (offsets) { 563 offsets[1] = size; 564 } 565 tmp = ((*w >> 1) + 3) & ~3; 566 if (pitches) { 567 pitches[1] = pitches[2] = tmp; 568 } 569 tmp *= (*h >> 1); 570 size += tmp; 571 if (offsets) { 572 offsets[2] = size; 573 } 574 size += tmp; 575 break; 576 case FOURCC_UYVY: 577 case FOURCC_YUY2: 578 default: 579 size = *w << 1; 580 if (pitches) 581 pitches[0] = size; 582 size *= *h; 583 break; 584 } 585 586 return size; 587} 588 589static int 590copy_packed_data(ScrnInfoPtr pScrn, 591 struct xorg_xv_port_priv *port, 592 int id, 593 unsigned char *buf, 594 int left, 595 int top, 596 unsigned short w, unsigned short h) 597{ 598 int i; 599 struct xa_surface **yuv = port->yuv[port->current_set]; 600 char *ymap, *vmap, *umap; 601 unsigned char y1, y2, u, v; 602 int yidx, uidx, vidx; 603 int y_array_size = w * h; 604 int ret = BadAlloc; 605 606 ymap = xa_surface_map(port->r, yuv[0], XA_MAP_WRITE); 607 if (!ymap) 608 return BadAlloc; 609 umap = xa_surface_map(port->r, yuv[1], XA_MAP_WRITE); 610 if (!umap) 611 goto out_no_umap; 612 vmap = xa_surface_map(port->r, yuv[2], XA_MAP_WRITE); 613 if (!vmap) 614 goto out_no_vmap; 615 616 617 yidx = uidx = vidx = 0; 618 619 switch (id) { 620 case FOURCC_YV12: { 621 int pitches[3], offsets[3]; 622 unsigned char *yp, *up, *vp; 623 query_image_attributes(pScrn, FOURCC_YV12, 624 &w, &h, pitches, offsets); 625 626 yp = buf + offsets[0]; 627 vp = buf + offsets[1]; 628 up = buf + offsets[2]; 629 memcpy(ymap, yp, w*h); 630 memcpy(vmap, vp, w*h/4); 631 memcpy(umap, up, w*h/4); 632 break; 633 } 634 case FOURCC_UYVY: 635 for (i = 0; i < y_array_size; i +=2 ) { 636 /* extracting two pixels */ 637 u = buf[0]; 638 y1 = buf[1]; 639 v = buf[2]; 640 y2 = buf[3]; 641 buf += 4; 642 643 ymap[yidx++] = y1; 644 ymap[yidx++] = y2; 645 umap[uidx++] = u; 646 vmap[vidx++] = v; 647 } 648 break; 649 case FOURCC_YUY2: 650 for (i = 0; i < y_array_size; i +=2 ) { 651 /* extracting two pixels */ 652 y1 = buf[0]; 653 u = buf[1]; 654 y2 = buf[2]; 655 v = buf[3]; 656 657 buf += 4; 658 659 ymap[yidx++] = y1; 660 ymap[yidx++] = y2; 661 umap[uidx++] = u; 662 vmap[vidx++] = v; 663 } 664 break; 665 default: 666 ret = BadAlloc; 667 break; 668 } 669 670 ret = Success; 671 xa_surface_unmap(yuv[2]); 672 out_no_vmap: 673 xa_surface_unmap(yuv[1]); 674 out_no_umap: 675 xa_surface_unmap(yuv[0]); 676 677 return ret; 678} 679 680 681static int 682display_video(ScreenPtr pScreen, struct xorg_xv_port_priv *pPriv, int id, 683 RegionPtr dstRegion, 684 int src_x, int src_y, int src_w, int src_h, 685 int dst_x, int dst_y, int dst_w, int dst_h, 686 int width, int height, 687 PixmapPtr pPixmap) 688{ 689 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pPixmap); 690 Bool hdtv; 691 RegionRec reg; 692 int ret = BadAlloc; 693 int blit_ret; 694 695 REGION_NULL(pScreen, ®); 696 697 if (!vmwgfx_hw_accel_validate(pPixmap, 0, XA_FLAG_RENDER_TARGET, 0, ®)) 698 goto out_no_dst; 699 700 hdtv = ((src_w >= RES_720P_X) && (src_h >= RES_720P_Y)); 701 if (hdtv != pPriv->hdtv) { 702 pPriv->hdtv = hdtv; 703 vmwgfx_update_conversion_matrix(pPriv); 704 } 705 706#ifdef COMPOSITE 707 708 /* 709 * For redirected windows, we need to fix up the destination coordinates. 710 */ 711 712 REGION_TRANSLATE(pScreen, dstRegion, -pPixmap->screen_x, 713 -pPixmap->screen_y); 714 dst_x -= pPixmap->screen_x; 715 dst_y -= pPixmap->screen_y; 716#endif 717 718 /* 719 * Throttle on previous blit. 720 */ 721 722 if (pPriv->fence) { 723 (void) xa_fence_wait(pPriv->fence, 1000000000ULL); 724 xa_fence_destroy(pPriv->fence); 725 pPriv->fence = NULL; 726 } 727 728 (void) vmwgfx_video_bounce_surface(pPriv, dst_w, dst_h, width, height, 729 xa_surface_format(vpix->hw)); 730 731 DamageRegionAppend(&pPixmap->drawable, dstRegion); 732 733 if (pPriv->bounce) { 734 BoxPtr b; 735 int i; 736 737 /* 738 * If we have a bounce buffer, First perform a (potentially down- 739 * scaling) color conversion blit with an expensive shader. 740 */ 741 blit_ret = xa_yuv_planar_blit(pPriv->r, 0, 0, src_w, src_h, 742 src_x, src_y, 743 pPriv->bounce_box.x2, 744 pPriv->bounce_box.y2, 745 &pPriv->bounce_box, 1, 746 pPriv->cm, 747 pPriv->bounce, 748 pPriv->yuv[pPriv->current_set]); 749 750 if (blit_ret) 751 goto out_blit; 752 753 /* 754 * Then an upscaling blit with a cheap shader. Note that we never 755 * scale up a dimenstion that was previously downscaled in the color 756 * conversion blit. 757 */ 758 pPriv->src_pic->srf = pPriv->bounce; 759 pPriv->dst_pic->srf = vpix->hw; 760 vmwgfx_video_setup_coord_matrix(src_x, src_y, src_w, src_h, 761 dst_x, dst_y, dst_w, dst_h, 762 pPriv->bounce_box.x2, 763 pPriv->bounce_box.y2, 764 pPriv->src_pic->transform); 765 pPriv->src_pic->has_transform = 1; 766 767 if (xa_composite_prepare(pPriv->r, pPriv->comp) != XA_ERR_NONE) { 768 blit_ret = 1; 769 goto out_blit; 770 } 771 772 b = REGION_RECTS(dstRegion); 773 for (i = 0; i < REGION_NUM_RECTS(dstRegion); ++i, ++b) { 774 xa_composite_rect(pPriv->r, b->x1, b->y1, 0, 0, 775 b->x1, b->y1, b->x2 - b->x1, 776 b->y2 - b->y1); 777 } 778 779 xa_composite_done(pPriv->r); 780 } else { 781 /* 782 * Perform color conversion and scaling in the same blit. 783 */ 784 blit_ret = xa_yuv_planar_blit(pPriv->r, src_x, src_y, src_w, src_h, 785 dst_x, dst_y, dst_w, dst_h, 786 (struct xa_box *)REGION_RECTS(dstRegion), 787 REGION_NUM_RECTS(dstRegion), 788 pPriv->cm, 789 vpix->hw, 790 pPriv->yuv[pPriv->current_set ]); 791 } 792 793 out_blit: 794 795 saa_pixmap_dirty(pPixmap, TRUE, dstRegion); 796 DamageRegionProcessPending(&pPixmap->drawable); 797 ret = Success; 798 799 if (!blit_ret) { 800 ret = Success; 801 pPriv->fence = xa_fence_get(pPriv->r); 802 } else 803 ret = BadAlloc; 804 805 out_no_dst: 806 REGION_UNINIT(pScreen, ®); 807 return ret; 808} 809 810static int 811put_image(ScrnInfoPtr pScrn, 812 short src_x, short src_y, 813 short drw_x, short drw_y, 814 short src_w, short src_h, 815 short drw_w, short drw_h, 816 int id, unsigned char *buf, 817 short width, short height, 818 Bool sync, RegionPtr clipBoxes, pointer data, 819 DrawablePtr pDraw) 820{ 821 struct xorg_xv_port_priv *pPriv = (struct xorg_xv_port_priv *) data; 822 ScreenPtr pScreen = xf86ScrnToScreen(pScrn); 823 PixmapPtr pPixmap; 824 INT32 x1, x2, y1, y2; 825 BoxRec dstBox; 826 int ret; 827 828 /* Clip */ 829 x1 = src_x; 830 x2 = src_x + src_w; 831 y1 = src_y; 832 y2 = src_y + src_h; 833 834 dstBox.x1 = drw_x; 835 dstBox.x2 = drw_x + drw_w; 836 dstBox.y1 = drw_y; 837 dstBox.y2 = drw_y + drw_h; 838 839 if (!xf86XVClipVideoHelper(&dstBox, &x1, &x2, &y1, &y2, clipBoxes, 840 width, height)) 841 return Success; 842 843 ret = check_yuv_surfaces(pPriv, id, width, height); 844 if (ret) 845 return ret; 846 847 ret = copy_packed_data(pScrn, pPriv, id, buf, 848 src_x, src_y, width, height); 849 if (ret) 850 return ret; 851 852 if (pDraw->type == DRAWABLE_WINDOW) { 853 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr)pDraw); 854 } else { 855 pPixmap = (PixmapPtr)pDraw; 856 } 857 858 display_video(pScrn->pScreen, pPriv, id, clipBoxes, 859 src_x, src_y, src_w, src_h, 860 drw_x, drw_y, 861 drw_w, drw_h, 862 width, height, pPixmap); 863 864 pPriv->current_set = (pPriv->current_set + 1) & 1; 865 return Success; 866} 867 868static struct xorg_xv_port_priv * 869port_priv_create(struct xa_tracker *xat, struct xa_context *r, 870 int drm_fd) 871{ 872 struct xorg_xv_port_priv *priv = NULL; 873 874 priv = calloc(1, sizeof(struct xorg_xv_port_priv)); 875 876 if (!priv) 877 return NULL; 878 879 priv->r = r; 880 priv->xat = xat; 881 priv->drm_fd = drm_fd; 882 REGION_NULL(pScreen, &priv->clip); 883 priv->hdtv = FALSE; 884 priv->uv_offset = 0.5f; 885 priv->uv_scale = 1.f; 886 priv->y_offset = 0.f; 887 priv->y_scale = 1.f; 888 priv->rgb_offset = 0.f; 889 priv->rgb_scale = 1.f; 890 priv->sinhue = 0.f; 891 priv->coshue = 1.f; 892 893 vmwgfx_update_conversion_matrix(priv); 894 895 return priv; 896} 897 898static void 899vmwgfx_free_textured_adaptor(XF86VideoAdaptorPtr adaptor, Bool free_ports) 900{ 901 if (free_ports) { 902 int i; 903 904 for(i=0; i<adaptor->nPorts; ++i) { 905 free(adaptor->pPortPrivates[i].ptr); 906 } 907 } 908 909 free(adaptor->pAttributes); 910 free(adaptor->pPortPrivates); 911 xf86XVFreeVideoAdaptorRec(adaptor); 912} 913 914static XF86VideoAdaptorPtr 915xorg_setup_textured_adapter(ScreenPtr pScreen) 916{ 917 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 918 modesettingPtr ms = modesettingPTR(pScrn); 919 XF86VideoAdaptorPtr adapt; 920 XF86AttributePtr attrs; 921 DevUnion *dev_unions; 922 int nports = 16, i; 923 int nattributes; 924 struct xa_context *xar; 925 926 /* 927 * Use the XA default context since we don't expect the X server 928 * to render from multiple threads. 929 */ 930 931 xar = xa_context_default(ms->xat); 932 nattributes = NUM_TEXTURED_ATTRIBUTES; 933 934 adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); 935 dev_unions = calloc(nports, sizeof(DevUnion)); 936 attrs = calloc(nattributes, sizeof(XF86AttributeRec)); 937 if (adapt == NULL || dev_unions == NULL || attrs == NULL) { 938 free(adapt); 939 free(dev_unions); 940 free(attrs); 941 return NULL; 942 } 943 944 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 945 adapt->flags = 0; 946 adapt->name = "XA G3D Textured Video"; 947 adapt->nEncodings = 1; 948 adapt->pEncodings = DummyEncoding; 949 adapt->nFormats = NUM_FORMATS; 950 adapt->pFormats = Formats; 951 adapt->nPorts = 0; 952 adapt->pPortPrivates = dev_unions; 953 adapt->nAttributes = nattributes; 954 adapt->pAttributes = attrs; 955 memcpy(attrs, TexturedAttributes, nattributes * sizeof(XF86AttributeRec)); 956 adapt->nImages = NUM_IMAGES; 957 adapt->pImages = Images; 958 adapt->PutVideo = NULL; 959 adapt->PutStill = NULL; 960 adapt->GetVideo = NULL; 961 adapt->GetStill = NULL; 962 adapt->StopVideo = stop_video; 963 adapt->SetPortAttribute = set_port_attribute; 964 adapt->GetPortAttribute = get_port_attribute; 965 adapt->QueryBestSize = query_best_size; 966 adapt->PutImage = put_image; 967 adapt->QueryImageAttributes = query_image_attributes; 968 969 970 for (i = 0; i < nports; i++) { 971 struct xorg_xv_port_priv *priv = 972 port_priv_create(ms->xat, xar, ms->fd); 973 974 adapt->pPortPrivates[i].ptr = (pointer) (priv); 975 adapt->nPorts++; 976 } 977 978 return adapt; 979} 980 981void 982xorg_xv_init(ScreenPtr pScreen) 983{ 984 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 985 modesettingPtr ms = modesettingPTR(pScrn); 986 XF86VideoAdaptorPtr *adaptors, *new_adaptors = NULL; 987 XF86VideoAdaptorPtr textured_adapter = NULL, overlay_adaptor = NULL; 988 int num_adaptors; 989 990 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 991 new_adaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); 992 if (new_adaptors == NULL) 993 return; 994 995 memcpy(new_adaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); 996 adaptors = new_adaptors; 997 998 /* Add the adaptors supported by our hardware. First, set up the atoms 999 * that will be used by both output adaptors. 1000 */ 1001 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 1002 xvContrast = MAKE_ATOM("XV_CONTRAST"); 1003 xvSaturation = MAKE_ATOM("XV_SATURATION"); 1004 xvHue = MAKE_ATOM("XV_HUE"); 1005 1006 if (ms->xat) { 1007 textured_adapter = xorg_setup_textured_adapter(pScreen); 1008 if (textured_adapter) 1009 adaptors[num_adaptors++] = textured_adapter; 1010 } else { 1011 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1012 "No 3D acceleration. Not setting up textured video.\n"); 1013 } 1014 1015 overlay_adaptor = vmw_video_init_adaptor(pScrn); 1016 if (overlay_adaptor) 1017 adaptors[num_adaptors++] = overlay_adaptor; 1018 1019 if (num_adaptors) { 1020 Bool ret; 1021 ret = xf86XVScreenInit(pScreen, adaptors, num_adaptors); 1022 if (textured_adapter) 1023 vmwgfx_free_textured_adaptor(textured_adapter, !ret); 1024 if (overlay_adaptor) 1025 vmw_video_free_adaptor(overlay_adaptor, !ret); 1026 if (!ret) 1027 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1028 "Failed to initialize Xv.\n"); 1029 } else { 1030 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1031 "Disabling Xv because no adaptors could be initialized.\n"); 1032 } 1033} 1034