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