1/*************************************************************************** 2 3 Copyright 2000 Intel Corporation. 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 INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 23 THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 **************************************************************************/ 26 27/* 28 * i830_video.c: i830/i845 Xv driver. 29 * 30 * Copyright © 2002 by Alan Hourihane and David Dawes 31 * 32 * Authors: 33 * Alan Hourihane <alanh@tungstengraphics.com> 34 * David Dawes <dawes@xfree86.org> 35 * 36 * Derived from i810 Xv driver: 37 * 38 * Authors of i810 code: 39 * Jonathan Bian <jonathan.bian@intel.com> 40 * Offscreen Images: 41 * Matt Sottek <matthew.j.sottek@intel.com> 42 */ 43 44#ifdef HAVE_CONFIG_H 45#include "config.h" 46#endif 47 48#include <inttypes.h> 49#include <math.h> 50#include <string.h> 51#include <errno.h> 52 53#include <sys/mman.h> 54 55#include "sna.h" 56#include "sna_reg.h" 57#include "sna_video.h" 58 59#include "intel_options.h" 60 61#include <xf86xv.h> 62#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) 63#include <sys/types.h> 64#include <sys/endian.h> 65#ifdef __OpenBSD__ 66#define bswap_32 swap32 67#else 68#define bswap_32 bswap32 69#endif 70#else 71#include <byteswap.h> 72#endif 73 74#ifdef SNA_XVMC 75#define _SNA_XVMC_SERVER_ 76#include "sna_video_hwmc.h" 77#else 78static inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr) 79{ 80 DBG(("%s: XvMC not compiled in\n", __FUNCTION__)); 81} 82#endif 83 84void sna_video_free_buffers(struct sna_video *video) 85{ 86 unsigned int i; 87 88 for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) { 89 if (video->old_buf[i]) { 90 kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]); 91 video->old_buf[i] = NULL; 92 } 93 } 94 95 if (video->buf) { 96 kgem_bo_destroy(&video->sna->kgem, video->buf); 97 video->buf = NULL; 98 } 99} 100 101struct kgem_bo * 102sna_video_buffer(struct sna_video *video, 103 struct sna_video_frame *frame) 104{ 105 /* Free the current buffer if we're going to have to reallocate */ 106 if (video->buf && __kgem_bo_size(video->buf) < frame->size) 107 sna_video_free_buffers(video); 108 109 if (video->buf && video->buf->scanout) { 110 if (frame->width != video->width || 111 frame->height != video->height || 112 frame->id != video->format) 113 sna_video_free_buffers(video); 114 } 115 116 if (video->buf == NULL) { 117 if (video->tiled) { 118 video->buf = kgem_create_2d(&video->sna->kgem, 119 frame->width, frame->height, 32, 120 I915_TILING_X, CREATE_EXACT); 121 } else { 122 video->buf = kgem_create_linear(&video->sna->kgem, frame->size, 123 CREATE_GTT_MAP); 124 } 125 } 126 127 video->width = frame->width; 128 video->height = frame->height; 129 video->format = frame->id; 130 131 return video->buf; 132} 133 134void sna_video_buffer_fini(struct sna_video *video) 135{ 136 struct kgem_bo *bo; 137 138 bo = video->old_buf[1]; 139 video->old_buf[1] = video->old_buf[0]; 140 video->old_buf[0] = video->buf; 141 video->buf = bo; 142} 143 144bool 145sna_video_clip_helper(struct sna_video *video, 146 struct sna_video_frame *frame, 147 xf86CrtcPtr *crtc_ret, 148 BoxPtr dst, 149 short src_x, short src_y, 150 short drw_x, short drw_y, 151 short src_w, short src_h, 152 short drw_w, short drw_h, 153 RegionPtr reg) 154{ 155 bool ret; 156 RegionRec crtc_region_local; 157 RegionPtr crtc_region = reg; 158 INT32 x1, x2, y1, y2; 159 xf86CrtcPtr crtc; 160 161 x1 = src_x; 162 x2 = src_x + src_w; 163 y1 = src_y; 164 y2 = src_y + src_h; 165 166 dst->x1 = drw_x; 167 dst->x2 = drw_x + drw_w; 168 dst->y1 = drw_y; 169 dst->y2 = drw_y + drw_h; 170 171 /* 172 * For overlay video, compute the relevant CRTC and 173 * clip video to that 174 */ 175 crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc); 176 177 /* For textured video, we don't actually want to clip at all. */ 178 if (crtc && !video->textured) { 179 crtc_region_local.extents = crtc->bounds; 180 crtc_region_local.data = NULL; 181 crtc_region = &crtc_region_local; 182 RegionIntersect(crtc_region, crtc_region, reg); 183 } 184 *crtc_ret = crtc; 185 186 ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2, 187 crtc_region, frame->width, frame->height); 188 if (crtc_region != reg) 189 RegionUninit(crtc_region); 190 191 frame->src.x1 = x1 >> 16; 192 frame->src.y1 = y1 >> 16; 193 frame->src.x2 = (x2 + 0xffff) >> 16; 194 frame->src.y2 = (y2 + 0xffff) >> 16; 195 196 frame->image.x1 = frame->src.x1 & ~1; 197 frame->image.x2 = ALIGN(frame->src.x2, 2); 198 if (is_planar_fourcc(frame->id)) { 199 frame->image.y1 = frame->src.y1 & ~1; 200 frame->image.y2 = ALIGN(frame->src.y2, 2); 201 } else { 202 frame->image.y1 = frame->src.y1; 203 frame->image.y2 = frame->src.y2; 204 } 205 206 return ret; 207} 208 209void 210sna_video_frame_init(struct sna_video *video, 211 int id, short width, short height, 212 struct sna_video_frame *frame) 213{ 214 DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n", 215 __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment)); 216 assert(width && height); 217 218 frame->bo = NULL; 219 frame->id = id; 220 frame->width = width; 221 frame->height = height; 222 frame->rotation = 0; 223} 224 225void 226sna_video_frame_set_rotation(struct sna_video *video, 227 struct sna_video_frame *frame, 228 Rotation rotation) 229{ 230 unsigned width = frame->width; 231 unsigned height = frame->height; 232 unsigned align; 233 234 DBG(("%s: rotation=%d\n", __FUNCTION__, rotation)); 235 frame->rotation = rotation; 236 237 align = video->alignment; 238#if SNA_XVMC 239 /* for i915 xvmc, hw requires 1kb aligned surfaces */ 240 if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024) 241 align = 1024; 242#endif 243 244 /* Determine the desired destination pitch (representing the 245 * chroma's pitch in the planar case). 246 */ 247 if (is_nv12_fourcc(frame->id)) { 248 assert((width & 1) == 0); 249 assert((height & 1) == 0); 250 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 251 frame->pitch[0] = ALIGN(height, align); 252 frame->pitch[1] = ALIGN(height, align); 253 frame->size = width * frame->pitch[1] + 254 width / 2 * frame->pitch[0]; 255 } else { 256 frame->pitch[0] = ALIGN(width, align); 257 frame->pitch[1] = ALIGN(width, align); 258 frame->size = height * frame->pitch[1] + 259 height / 2 * frame->pitch[0]; 260 } 261 262 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 263 frame->UBufOffset = (int)frame->pitch[1] * width; 264 frame->VBufOffset = frame->UBufOffset; 265 } else { 266 frame->UBufOffset = (int)frame->pitch[1] * height; 267 frame->VBufOffset = frame->UBufOffset; 268 } 269 } else if (is_planar_fourcc(frame->id)) { 270 assert((width & 1) == 0); 271 assert((height & 1) == 0); 272 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 273 frame->pitch[0] = ALIGN((height / 2), align); 274 frame->pitch[1] = ALIGN(height, align); 275 frame->size = width; 276 } else { 277 frame->pitch[0] = ALIGN((width / 2), align); 278 frame->pitch[1] = ALIGN(width, align); 279 frame->size = height; 280 } 281 frame->size *= frame->pitch[0] + frame->pitch[1]; 282 283 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 284 frame->UBufOffset = (int)frame->pitch[1] * width; 285 frame->VBufOffset = 286 frame->UBufOffset + (int)frame->pitch[0] * width / 2; 287 } else { 288 frame->UBufOffset = (int)frame->pitch[1] * height; 289 frame->VBufOffset = 290 frame->UBufOffset + (int)frame->pitch[0] * height / 2; 291 } 292 } else { 293 switch (frame->id) { 294 case FOURCC_RGB888: 295 case FOURCC_AYUV: 296 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 297 frame->pitch[0] = ALIGN((height << 2), align); 298 frame->size = (int)frame->pitch[0] * width; 299 } else { 300 frame->pitch[0] = ALIGN((width << 2), align); 301 frame->size = (int)frame->pitch[0] * height; 302 } 303 frame->UBufOffset = frame->VBufOffset = 0; 304 break; 305 case FOURCC_RGB565: 306 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 307 frame->pitch[0] = ALIGN((height << 1), align); 308 frame->size = (int)frame->pitch[0] * width; 309 } else { 310 frame->pitch[0] = ALIGN((width << 1), align); 311 frame->size = (int)frame->pitch[0] * height; 312 } 313 frame->UBufOffset = frame->VBufOffset = 0; 314 break; 315 316 default: 317 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 318 frame->pitch[0] = ALIGN((height << 1), align); 319 frame->size = (int)frame->pitch[0] * width; 320 } else { 321 frame->pitch[0] = ALIGN((width << 1), align); 322 frame->size = (int)frame->pitch[0] * height; 323 } 324 break; 325 } 326 frame->pitch[1] = 0; 327 frame->UBufOffset = 0; 328 frame->VBufOffset = 0; 329 } 330 331 assert(frame->size); 332} 333 334static void plane_dims(const struct sna_video_frame *frame, int sub, 335 int *x, int *y, int *w, int *h) 336{ 337 *x = frame->image.x1; 338 *y = frame->image.y1; 339 *w = frame->image.x2 - frame->image.x1; 340 *h = frame->image.y2 - frame->image.y1; 341 342 if (sub) { 343 *x >>= 1; *w >>= 1; 344 *y >>= 1; *h >>= 1; 345 } 346} 347 348static void sna_memcpy_cbcr_plane(struct sna_video *video, 349 uint16_t *dst, const uint16_t *src, 350 const struct sna_video_frame *frame) 351{ 352 int dstPitch = frame->pitch[0] >> 1, srcPitch; 353 const uint16_t *s; 354 int i, j = 0; 355 int x, y, w, h; 356 357 plane_dims(frame, 1, &x, &y, &w, &h); 358 359 srcPitch = ALIGN((frame->width >> 1), 2); 360 361 src += y * srcPitch + x; 362 if (!video->textured) 363 x = y = 0; 364 365 switch (frame->rotation) { 366 case RR_Rotate_0: 367 dst += y * dstPitch + x; 368 if (srcPitch == dstPitch && srcPitch == w) 369 memcpy(dst, src, (srcPitch * h) << 1); 370 else while (h--) { 371 memcpy(dst, src, w << 1); 372 src += srcPitch; 373 dst += dstPitch; 374 } 375 break; 376 case RR_Rotate_90: 377 for (i = 0; i < h; i++) { 378 s = src; 379 for (j = 0; j < w; j++) 380 dst[i + ((x + w - j - 1) * dstPitch)] = *s++; 381 src += srcPitch; 382 } 383 break; 384 case RR_Rotate_180: 385 for (i = 0; i < h; i++) { 386 s = src; 387 for (j = 0; j < w; j++) { 388 dst[(x + w - j - 1) + 389 ((h - i - 1) * dstPitch)] = *s++; 390 } 391 src += srcPitch; 392 } 393 break; 394 case RR_Rotate_270: 395 for (i = 0; i < h; i++) { 396 s = src; 397 for (j = 0; j < w; j++) { 398 dst[(h - i - 1) + (x + j * dstPitch)] = *s++; 399 } 400 src += srcPitch; 401 } 402 break; 403 } 404} 405 406static void sna_memcpy_plane(struct sna_video *video, 407 uint8_t *dst, const uint8_t *src, 408 const struct sna_video_frame *frame, int sub) 409{ 410 int dstPitch = frame->pitch[!sub], srcPitch; 411 const uint8_t *s; 412 int i, j = 0; 413 int x, y, w, h; 414 415 plane_dims(frame, sub, &x, &y, &w, &h); 416 417 if (sub) 418 srcPitch = ALIGN((frame->width >> 1), 4); 419 else 420 srcPitch = ALIGN(frame->width, 4); 421 422 src += y * srcPitch + x; 423 if (!video->textured) 424 x = y = 0; 425 426 switch (frame->rotation) { 427 case RR_Rotate_0: 428 dst += y * dstPitch + x; 429 if (srcPitch == dstPitch && srcPitch == w) 430 memcpy(dst, src, srcPitch * h); 431 else while (h--) { 432 memcpy(dst, src, w); 433 src += srcPitch; 434 dst += dstPitch; 435 } 436 break; 437 case RR_Rotate_90: 438 for (i = 0; i < h; i++) { 439 s = src; 440 for (j = 0; j < w; j++) 441 dst[i + ((x + w - j - 1) * dstPitch)] = *s++; 442 src += srcPitch; 443 } 444 break; 445 case RR_Rotate_180: 446 for (i = 0; i < h; i++) { 447 s = src; 448 for (j = 0; j < w; j++) { 449 dst[(x + w - j - 1) + 450 ((h - i - 1) * dstPitch)] = *s++; 451 } 452 src += srcPitch; 453 } 454 break; 455 case RR_Rotate_270: 456 for (i = 0; i < h; i++) { 457 s = src; 458 for (j = 0; j < w; j++) { 459 dst[(h - i - 1) + (x + j * dstPitch)] = *s++; 460 } 461 src += srcPitch; 462 } 463 break; 464 } 465} 466 467static void 468sna_copy_nv12_data(struct sna_video *video, 469 const struct sna_video_frame *frame, 470 const uint8_t *src, uint8_t *dst) 471{ 472 sna_memcpy_plane(video, dst, src, frame, 0); 473 src += frame->height * ALIGN(frame->width, 4); 474 dst += frame->UBufOffset; 475 sna_memcpy_cbcr_plane(video, (void*)dst, (void*)src, frame); 476} 477 478static void 479sna_copy_planar_data(struct sna_video *video, 480 const struct sna_video_frame *frame, 481 const uint8_t *src, uint8_t *dst) 482{ 483 uint8_t *d; 484 485 sna_memcpy_plane(video, dst, src, frame, 0); 486 src += frame->height * ALIGN(frame->width, 4); 487 488 if (frame->id == FOURCC_I420) 489 d = dst + frame->UBufOffset; 490 else 491 d = dst + frame->VBufOffset; 492 sna_memcpy_plane(video, d, src, frame, 1); 493 src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4); 494 495 if (frame->id == FOURCC_I420) 496 d = dst + frame->VBufOffset; 497 else 498 d = dst + frame->UBufOffset; 499 sna_memcpy_plane(video, d, src, frame, 1); 500} 501 502static void 503sna_copy_packed_data(struct sna_video *video, 504 const struct sna_video_frame *frame, 505 const uint8_t *buf, 506 uint8_t *dst) 507{ 508 int pitch = frame->width << 1; 509 const uint8_t *src, *s; 510 int x, y, w, h; 511 int i, j; 512 513 if (video->textured) { 514 /* XXX support copying cropped extents */ 515 x = y = 0; 516 w = frame->width; 517 h = frame->height; 518 } else { 519 x = frame->image.x1; 520 y = frame->image.y1; 521 w = frame->image.x2 - frame->image.x1; 522 h = frame->image.y2 - frame->image.y1; 523 } 524 525 src = buf + (y * pitch) + (x << 1); 526 527 switch (frame->rotation) { 528 case RR_Rotate_0: 529 w <<= 1; 530 for (i = 0; i < h; i++) { 531 memcpy(dst, src, w); 532 src += pitch; 533 dst += frame->pitch[0]; 534 } 535 break; 536 case RR_Rotate_90: 537 h <<= 1; 538 for (i = 0; i < h; i += 2) { 539 s = src; 540 for (j = 0; j < w; j++) { 541 /* Copy Y */ 542 dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s; 543 s += 2; 544 } 545 src += pitch; 546 } 547 h >>= 1; 548 src = buf + (y * pitch) + (x << 1); 549 for (i = 0; i < h; i += 2) { 550 for (j = 0; j < w; j += 2) { 551 /* Copy U */ 552 dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 553 dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 554 /* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 555 dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 556 } 557 } 558 break; 559 case RR_Rotate_180: 560 w <<= 1; 561 for (i = 0; i < h; i++) { 562 s = src; 563 for (j = 0; j < w; j += 4) { 564 dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++; 565 dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++; 566 dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++; 567 dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++; 568 } 569 src += pitch; 570 } 571 break; 572 case RR_Rotate_270: 573 h <<= 1; 574 for (i = 0; i < h; i += 2) { 575 s = src; 576 for (j = 0; j < w; j++) { 577 /* Copy Y */ 578 dst[(h - i - 2) + (j * frame->pitch[0])] = *s; 579 s += 2; 580 } 581 src += pitch; 582 } 583 h >>= 1; 584 src = buf + (y * pitch) + (x << 1); 585 for (i = 0; i < h; i += 2) { 586 for (j = 0; j < w; j += 2) { 587 /* Copy U */ 588 dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 589 dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 590 /* Copy V */ 591 dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 592 dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 593 } 594 } 595 break; 596 } 597} 598 599static void 600sna_copy_ayuv_data(struct sna_video *video, 601 const struct sna_video_frame *frame, 602 const uint8_t *buf, 603 uint8_t *dst) 604{ 605 int pitch = frame->width << 2; 606 const uint32_t *src_dw; 607 const uint8_t *src; 608 uint32_t *dst_dw = (uint32_t *)dst; 609 int x, y, w, h; 610 int i, j; 611 612 if (video->textured) { 613 /* XXX support copying cropped extents */ 614 x = y = 0; 615 w = frame->width; 616 h = frame->height; 617 } else { 618 x = frame->image.x1; 619 y = frame->image.y1; 620 w = frame->image.x2 - frame->image.x1; 621 h = frame->image.y2 - frame->image.y1; 622 } 623 624 src = buf + (y * pitch) + (x << 2); 625 src_dw = (uint32_t *)src; 626 627 switch (frame->rotation) { 628 case RR_Rotate_0: 629 for (i = 0; i < h; i++) { 630 for (j = 0; j < w; j++) { 631 /* 632 * Have to reverse bytes order, because the only 633 * player which supports AYUV format currently is 634 * Gstreamer and it supports in bad way, even though 635 * spec says MSB:AYUV, we get the bytes opposite way. 636 */ 637 dst_dw[i * w + j] = bswap_32(src_dw[i * w + j]); 638 } 639 } 640 break; 641 case RR_Rotate_90: 642 for (i = 0; i < h; i++) { 643 for (j = 0; j < w; j++) { 644 dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]); 645 } 646 } 647 break; 648 case RR_Rotate_180: 649 for (i = 0; i < h; i++) { 650 for (j = 0; j < w; j++) { 651 dst_dw[(h - i - 1) * w + w - j - 1] = bswap_32(src_dw[i * w + j]); 652 } 653 } 654 break; 655 case RR_Rotate_270: 656 for (i = 0; i < h; i++) { 657 for (j = 0; j < w; j++) { 658 dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]); 659 } 660 } 661 break; 662 } 663} 664 665bool 666sna_video_copy_data(struct sna_video *video, 667 struct sna_video_frame *frame, 668 const uint8_t *buf) 669{ 670 uint8_t *dst; 671 672 DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n", 673 __FUNCTION__, frame->bo ? frame->bo->handle : 0, 674 frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1], 675 frame->rotation, video->textured)); 676 DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n", 677 __FUNCTION__, 678 frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2, 679 frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2)); 680 assert(frame->width && frame->height); 681 assert(frame->rotation); 682 assert(frame->size); 683 684 /* In the common case, we can simply the upload in a single pwrite */ 685 if (frame->rotation == RR_Rotate_0 && !video->tiled && !is_ayuv_fourcc(frame->id)) { 686 DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n", 687 __FUNCTION__, is_planar_fourcc(frame->id))); 688 if (is_nv12_fourcc(frame->id)) { 689 int w = frame->image.x2 - frame->image.x1; 690 int h = frame->image.y2 - frame->image.y1; 691 if (ALIGN(h, 2) == frame->height && 692 ALIGN(w, 4) == frame->pitch[0] && 693 ALIGN(w, 4) == frame->pitch[1]) { 694 if (frame->bo) { 695 if (!kgem_bo_write(&video->sna->kgem, frame->bo, 696 buf, frame->size)) 697 goto use_gtt; 698 } else { 699 frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 700 KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 701 (void **)&dst); 702 if (frame->bo == NULL) 703 return false; 704 705 memcpy(dst, buf, frame->size); 706 } 707 return true; 708 } 709 } else if (is_planar_fourcc(frame->id)) { 710 int w = frame->image.x2 - frame->image.x1; 711 int h = frame->image.y2 - frame->image.y1; 712 if (ALIGN(h, 2) == frame->height && 713 ALIGN(w >> 1, 4) == frame->pitch[0] && 714 ALIGN(w, 4) == frame->pitch[1]) { 715 if (frame->bo) { 716 if (!kgem_bo_write(&video->sna->kgem, frame->bo, 717 buf, frame->size)) 718 goto use_gtt; 719 } else { 720 frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 721 KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 722 (void **)&dst); 723 if (frame->bo == NULL) 724 return false; 725 726 memcpy(dst, buf, frame->size); 727 } 728 if (frame->id != FOURCC_I420) { 729 uint32_t tmp; 730 tmp = frame->VBufOffset; 731 frame->VBufOffset = frame->UBufOffset; 732 frame->UBufOffset = tmp; 733 } 734 return true; 735 } 736 } else { 737 int x, y, w, h; 738 739 if (video->textured) { 740 /* XXX support copying cropped extents */ 741 x = y = 0; 742 w = frame->width; 743 h = frame->height; 744 } else { 745 x = frame->image.x1; 746 y = frame->image.y1; 747 w = frame->image.x2 - frame->image.x1; 748 h = frame->image.y2 - frame->image.y1; 749 } 750 751 if (w*2 == frame->pitch[0]) { 752 buf += (2U*y * frame->width) + (x << 1); 753 if (frame->bo) { 754 if (!kgem_bo_write(&video->sna->kgem, frame->bo, 755 buf, 2U*h*frame->width)) 756 goto use_gtt; 757 } else { 758 frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 759 KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 760 (void **)&dst); 761 if (frame->bo == NULL) 762 return false; 763 764 memcpy(dst, buf, 2U*h*frame->width); 765 } 766 return true; 767 } 768 } 769 770 DBG(("%s: source cropped, fallback\n", __FUNCTION__)); 771 } 772 773use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */ 774 if (frame->bo) { 775 dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo); 776 if (dst == NULL) 777 return false; 778 } else { 779 frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 780 KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 781 (void **)&dst); 782 if (frame->bo == NULL) 783 return false; 784 } 785 786 if (is_nv12_fourcc(frame->id)) 787 sna_copy_nv12_data(video, frame, buf, dst); 788 else if (is_planar_fourcc(frame->id)) 789 sna_copy_planar_data(video, frame, buf, dst); 790 else if (is_ayuv_fourcc(frame->id)) 791 sna_copy_ayuv_data(video, frame, buf, dst); 792 else 793 sna_copy_packed_data(video, frame, buf, dst); 794 795 return true; 796} 797 798void sna_video_fill_colorkey(struct sna_video *video, 799 const RegionRec *clip) 800{ 801 struct sna *sna = video->sna; 802 PixmapPtr front = sna->front; 803 struct kgem_bo *bo = __sna_pixmap_get_bo(front); 804 uint8_t *dst, *tmp; 805 int w, width; 806 807 if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip)) 808 return; 809 810 assert(bo); 811 if (!wedged(sna) && 812 sna_blt_fill_boxes(sna, GXcopy, bo, 813 front->drawable.bitsPerPixel, 814 video->color_key, 815 region_rects(clip), 816 region_num_rects(clip))) { 817 RegionCopy(&video->clip, (RegionPtr)clip); 818 return; 819 } 820 821 dst = kgem_bo_map__gtt(&sna->kgem, bo); 822 if (dst == NULL) 823 return; 824 825 w = front->drawable.bitsPerPixel/8; 826 width = (clip->extents.x2 - clip->extents.x1) * w; 827 tmp = malloc(width); 828 if (tmp == NULL) 829 return; 830 831 memcpy(tmp, &video->color_key, w); 832 while (2 * w < width) { 833 memcpy(tmp + w, tmp, w); 834 w *= 2; 835 } 836 if (w < width) 837 memcpy(tmp + w, tmp, width - w); 838 839 if (sigtrap_get() == 0) { 840 const BoxRec *box = region_rects(clip); 841 int n = region_num_rects(clip); 842 843 w = front->drawable.bitsPerPixel/8; 844 do { 845 int y = box->y1; 846 uint8_t *row = dst + y*bo->pitch + w*box->x1; 847 848 width = (box->x2 - box->x1) * w; 849 while (y < box->y2) { 850 memcpy(row, tmp, width); 851 row += bo->pitch; 852 y++; 853 } 854 box++; 855 } while (--n); 856 sigtrap_put(); 857 858 RegionCopy(&video->clip, (RegionPtr)clip); 859 } 860 861 free(tmp); 862} 863 864XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna) 865{ 866 XvAdaptorPtr new_adaptors; 867 868 new_adaptors = realloc(sna->xv.adaptors, 869 (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec)); 870 if (new_adaptors == NULL) 871 return NULL; 872 873 if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) { 874 XvAdaptorPtr adaptor = new_adaptors; 875 int i = sna->xv.num_adaptors, j; 876 while (i--) { 877 for (j = 0; j < adaptor->nPorts; j++) 878 adaptor->pPorts[j].pAdaptor = adaptor; 879 adaptor++; 880 } 881 } 882 883 sna->xv.adaptors = new_adaptors; 884 return &sna->xv.adaptors[sna->xv.num_adaptors++]; 885} 886 887int 888sna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out) 889{ 890 *out = in; 891 return Success; 892} 893 894int 895sna_xv_free_port(XvPortPtr port) 896{ 897 return Success; 898} 899 900int 901sna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats) 902{ 903 XvFormatPtr out = formats; 904 int count = 0; 905 906 while (num_formats--) { 907 int num_visuals = screen->numVisuals; 908 VisualPtr v = screen->visuals; 909 910 while (num_visuals--) { 911 if (v->class == TrueColor && 912 v->nplanes == formats->depth) { 913 int tmp = out[count].depth; 914 out[count].depth = formats->depth; 915 out[count].visual = v->vid; 916 formats->depth = tmp; 917 count++; 918 break; 919 } 920 v++; 921 } 922 923 formats++; 924 } 925 926 return count; 927} 928 929#if XORG_XV_VERSION < 2 930static int 931sna_xv_query_adaptors(ScreenPtr screen, 932 XvAdaptorPtr *adaptors, 933 int *num_adaptors) 934{ 935 struct sna *sna = to_sna_from_screen(screen); 936 937 *num_adaptors = sna->xv.num_adaptors; 938 *adaptors = sna->xv.adaptors; 939 return Success; 940} 941 942static Bool 943sna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL) 944{ 945 struct sna *sna = to_sna_from_screen(screen); 946 sna_video_close(sna); 947 return TRUE; 948} 949#endif 950 951void sna_video_init(struct sna *sna, ScreenPtr screen) 952{ 953 XvScreenPtr xv; 954 955 if (noXvExtension) 956 return; 957 958 if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) { 959 XF86VideoAdaptorPtr *adaptors = NULL; 960 int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors); 961 if (num_adaptors) 962 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 963 "Ignoring generic xf86XV adaptors"); 964 free(adaptors); 965 } 966 967 if (XvScreenInit(screen) != Success) 968 return; 969 970 xv = to_xv(screen); 971#if XORG_XV_VERSION < 2 972 xv->ddCloseScreen = sna_xv_close_screen; 973 xv->ddQueryAdaptors = sna_xv_query_adaptors; 974#endif 975 976 sna_video_textured_setup(sna, screen); 977 sna_video_sprite_setup(sna, screen); 978 sna_video_overlay_setup(sna, screen); 979 980 if (sna->xv.num_adaptors >= 2 && 981 xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) { 982 XvAdaptorRec tmp; 983 984 tmp = sna->xv.adaptors[0]; 985 sna->xv.adaptors[0] = sna->xv.adaptors[1]; 986 sna->xv.adaptors[1] = tmp; 987 } 988 989 xv->nAdaptors = sna->xv.num_adaptors; 990 xv->pAdaptors = sna->xv.adaptors; 991 992 sna_video_xvmc_setup(sna, screen); 993} 994 995void sna_video_destroy_window(WindowPtr win) 996{ 997 XvPortPtr port; 998 999 port = sna_window_get_port(win); 1000 if (port) { 1001#if XORG_XV_VERSION < 2 1002 port->pAdaptor->ddStopVideo(NULL, port, &win->drawable); 1003#else 1004 port->pAdaptor->ddStopVideo(port, &win->drawable); 1005#endif 1006 } 1007 assert(sna_window_get_port(win) == NULL); 1008} 1009 1010void sna_video_close(struct sna *sna) 1011{ 1012 int i; 1013 1014 for (i = 0; i < sna->xv.num_adaptors; i++) { 1015 free(sna->xv.adaptors[i].pPorts->devPriv.ptr); 1016 free(sna->xv.adaptors[i].pPorts); 1017 free(sna->xv.adaptors[i].pEncodings); 1018 } 1019 free(sna->xv.adaptors); 1020 1021 sna->xv.adaptors = NULL; 1022 sna->xv.num_adaptors = 0; 1023} 1024