1/*************************************************************************** 2 3 Copyright 2000-2011 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#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#include "sna.h" 32#include "sna_video.h" 33 34#include "intel_options.h" 35 36#include <xf86drm.h> 37#include <xf86xv.h> 38#include <xf86Crtc.h> 39#include <X11/extensions/Xv.h> 40#include <fourcc.h> 41#include <i915_drm.h> 42#include <errno.h> 43 44#define fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) 45#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ 46#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ 47#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ 48#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ 49#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ 50#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] x:Y:U:V 8:8:8:8 little endian */ 51 52#define has_hw_scaling(sna, video) ((sna)->kgem.gen < 071 || \ 53 (sna)->kgem.gen >= 0110) 54 55#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane) 56struct local_mode_set_plane { 57 uint32_t plane_id; 58 uint32_t crtc_id; 59 uint32_t fb_id; /* fb object contains surface format type */ 60 uint32_t flags; 61 62 /* Signed dest location allows it to be partially off screen */ 63 int32_t crtc_x, crtc_y; 64 uint32_t crtc_w, crtc_h; 65 66 /* Source values are 16.16 fixed point */ 67 uint32_t src_x, src_y; 68 uint32_t src_h, src_w; 69}; 70 71#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, true) 72 73static Atom xvColorKey, xvAlwaysOnTop, xvSyncToVblank, xvColorspace; 74 75static XvFormatRec formats[] = { {8}, {15}, {16}, {24}, {30} }; 76static const XvImageRec images[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 77 XVMC_RGB888 }; 78static const XvImageRec images_rgb565[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 79 XVMC_RGB888, XVMC_RGB565 }; 80static const XvImageRec images_nv12[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 81 XVIMAGE_NV12, XVMC_RGB888, XVMC_RGB565 }; 82static const XvImageRec images_ayuv[] = { XVIMAGE_AYUV, XVIMAGE_YUY2, XVIMAGE_UYVY, 83 XVIMAGE_NV12, XVMC_RGB888, XVMC_RGB565 }; 84static const XvAttributeRec attribs[] = { 85 { XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE" }, /* BT.601, BT.709 */ 86 { XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_COLORKEY" }, 87 { XvSettable | XvGettable, 0, 1, (char *)"XV_ALWAYS_ON_TOP" }, 88}; 89 90static int sna_video_sprite_stop(ddStopVideo_ARGS) 91{ 92 struct sna_video *video = port->devPriv.ptr; 93 struct local_mode_set_plane s; 94 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn); 95 int i; 96 97 for (i = 0; i < video->sna->mode.num_real_crtc; i++) { 98 xf86CrtcPtr crtc = config->crtc[i]; 99 int pipe; 100 101 pipe = sna_crtc_pipe(crtc); 102 assert(pipe < ARRAY_SIZE(video->bo)); 103 if (video->bo[pipe] == NULL) 104 continue; 105 106 memset(&s, 0, sizeof(s)); 107 s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 108 if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 109 xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 110 "failed to disable plane\n"); 111 112 if (video->bo[pipe]) 113 kgem_bo_destroy(&video->sna->kgem, video->bo[pipe]); 114 video->bo[pipe] = NULL; 115 } 116 117 sna_window_set_port((WindowPtr)draw, NULL); 118 119 return Success; 120} 121 122static int sna_video_sprite_set_attr(ddSetPortAttribute_ARGS) 123{ 124 struct sna_video *video = port->devPriv.ptr; 125 126 if (attribute == xvColorKey) { 127 video->color_key_changed = ~0; 128 video->color_key = value; 129 RegionEmpty(&video->clip); 130 DBG(("COLORKEY = %ld\n", (long)value)); 131 } else if (attribute == xvColorspace) { 132 video->colorspace_changed = ~0; 133 video->colorspace = value; 134 DBG(("COLORSPACE = %ld\n", (long)value)); 135 } else if (attribute == xvSyncToVblank) { 136 DBG(("%s: SYNC_TO_VBLANK: %d -> %d\n", __FUNCTION__, 137 video->SyncToVblank, !!value)); 138 video->SyncToVblank = !!value; 139 } else if (attribute == xvAlwaysOnTop) { 140 DBG(("%s: ALWAYS_ON_TOP: %d -> %d\n", __FUNCTION__, 141 video->AlwaysOnTop, !!value)); 142 video->color_key_changed = ~0; 143 video->AlwaysOnTop = !!value; 144 } else 145 return BadMatch; 146 147 return Success; 148} 149 150static int sna_video_sprite_get_attr(ddGetPortAttribute_ARGS) 151{ 152 struct sna_video *video = port->devPriv.ptr; 153 154 if (attribute == xvColorKey) 155 *value = video->color_key; 156 else if (attribute == xvColorspace) 157 *value = video->colorspace; 158 else if (attribute == xvAlwaysOnTop) 159 *value = video->AlwaysOnTop; 160 else if (attribute == xvSyncToVblank) 161 *value = video->SyncToVblank; 162 else 163 return BadMatch; 164 165 return Success; 166} 167 168static int sna_video_sprite_best_size(ddQueryBestSize_ARGS) 169{ 170 struct sna_video *video = port->devPriv.ptr; 171 struct sna *sna = video->sna; 172 173 if (!has_hw_scaling(sna, video) && !sna->render.video) { 174 *p_w = vid_w; 175 *p_h = vid_h; 176 } else { 177 *p_w = drw_w; 178 *p_h = drw_h; 179 } 180 181 return Success; 182} 183 184static void 185update_dst_box_to_crtc_coords(struct sna *sna, xf86CrtcPtr crtc, BoxPtr dstBox) 186{ 187 ScrnInfoPtr scrn = sna->scrn; 188 int tmp; 189 190 switch (crtc->rotation & 0xf) { 191 case RR_Rotate_0: 192 dstBox->x1 -= crtc->x; 193 dstBox->x2 -= crtc->x; 194 dstBox->y1 -= crtc->y; 195 dstBox->y2 -= crtc->y; 196 break; 197 198 case RR_Rotate_90: 199 tmp = dstBox->x1; 200 dstBox->x1 = dstBox->y1 - crtc->x; 201 dstBox->y1 = scrn->virtualX - tmp - crtc->y; 202 tmp = dstBox->x2; 203 dstBox->x2 = dstBox->y2 - crtc->x; 204 dstBox->y2 = scrn->virtualX - tmp - crtc->y; 205 tmp = dstBox->y1; 206 dstBox->y1 = dstBox->y2; 207 dstBox->y2 = tmp; 208 break; 209 210 case RR_Rotate_180: 211 tmp = dstBox->x1; 212 dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x; 213 dstBox->x2 = scrn->virtualX - tmp - crtc->x; 214 tmp = dstBox->y1; 215 dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y; 216 dstBox->y2 = scrn->virtualY - tmp - crtc->y; 217 break; 218 219 case RR_Rotate_270: 220 tmp = dstBox->x1; 221 dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x; 222 dstBox->y1 = tmp - crtc->y; 223 tmp = dstBox->x2; 224 dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x; 225 dstBox->y2 = tmp - crtc->y; 226 tmp = dstBox->x1; 227 dstBox->x1 = dstBox->x2; 228 dstBox->x2 = tmp; 229 break; 230 } 231} 232 233static uint32_t ckey_chan(uint32_t value, int weight) 234{ 235 return value << 8 >> weight; 236} 237 238static uint32_t ckey_value_chan(uint32_t value, uint32_t mask, 239 int offset, int weight) 240{ 241 return ckey_chan((value & mask) >> offset, weight); 242} 243 244static uint32_t ckey_value(struct sna *sna, 245 struct sna_video *video) 246{ 247 ScrnInfoPtr scrn = sna->scrn; 248 uint32_t r, g ,b; 249 250 if (scrn->depth == 8) { 251 r = g = b = video->color_key & 0xff; 252 } else { 253 r = ckey_value_chan(video->color_key, scrn->mask.red, 254 scrn->offset.red, scrn->weight.red); 255 g = ckey_value_chan(video->color_key, scrn->mask.green, 256 scrn->offset.green, scrn->weight.green); 257 b = ckey_value_chan(video->color_key, scrn->mask.blue, 258 scrn->offset.blue, scrn->weight.blue); 259 } 260 261 return r << 16 | g << 8 | b; 262} 263 264static uint32_t ckey_mask_chan(int weight) 265{ 266 return ckey_chan((1 << weight) - 1, weight); 267} 268 269static uint32_t ckey_mask(struct sna *sna) 270{ 271 ScrnInfoPtr scrn = sna->scrn; 272 uint32_t r = ckey_mask_chan(scrn->weight.red); 273 uint32_t g = ckey_mask_chan(scrn->weight.green); 274 uint32_t b = ckey_mask_chan(scrn->weight.blue); 275 276 return 0x7 << 24 | r << 16 | g << 8 | b; 277} 278 279static bool 280sna_video_sprite_show(struct sna *sna, 281 struct sna_video *video, 282 struct sna_video_frame *frame, 283 xf86CrtcPtr crtc, 284 BoxPtr dstBox) 285{ 286 struct local_mode_set_plane s; 287 int pipe = sna_crtc_pipe(crtc); 288 289 /* XXX handle video spanning multiple CRTC */ 290 291 VG_CLEAR(s); 292 s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 293 294#define DRM_I915_SET_SPRITE_COLORKEY 0x2b 295#define LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct local_intel_sprite_colorkey) 296#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2) 297 298 if (video->color_key_changed & (1 << pipe) && video->has_color_key) { 299 struct local_intel_sprite_colorkey { 300 uint32_t plane_id; 301 uint32_t min_value; 302 uint32_t channel_mask; 303 uint32_t max_value; 304 uint32_t flags; 305 } set; 306 307 DBG(("%s: updating color key: %x\n", 308 __FUNCTION__, video->color_key)); 309 310 set.plane_id = s.plane_id; 311 set.min_value = ckey_value(sna, video); 312 set.max_value = 0; /* not used for destkey */ 313 set.channel_mask = ckey_mask(sna); 314 set.flags = 0; 315 if (!video->AlwaysOnTop) 316 set.flags |= 1 << 1; /* COLORKEY_DESTINATION */ 317 318 if (drmIoctl(sna->kgem.fd, 319 LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY, 320 &set)) { 321 memset(&s, 0, sizeof(s)); 322 s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 323 324 /* try to disable the plane first */ 325 if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 326 xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 327 "failed to disable plane\n"); 328 329 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY, &set)) { 330 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 331 "failed to update color key, disabling future updates\n"); 332 video->has_color_key = false; 333 } 334 } 335 336 video->color_key_changed &= ~(1 << pipe); 337 } 338 339 if (video->colorspace_changed & (1 << pipe)) { 340 DBG(("%s: updating colorspace: %x\n", 341 __FUNCTION__, video->colorspace)); 342 343 sna_crtc_set_sprite_colorspace(crtc, video->idx, 344 video->colorspace); 345 346 video->colorspace_changed &= ~(1 << pipe); 347 } 348 349 update_dst_box_to_crtc_coords(sna, crtc, dstBox); 350 if (frame->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 351 int tmp = frame->width; 352 frame->width = frame->height; 353 frame->height = tmp; 354 } 355 356 if (frame->bo->delta == 0) { 357 struct local_mode_fb_cmd2 { 358 uint32_t fb_id; 359 uint32_t width, height; 360 uint32_t pixel_format; 361 uint32_t flags; 362 363 uint32_t handles[4]; 364 uint32_t pitches[4]; /* pitch for each plane */ 365 uint32_t offsets[4]; /* offset of each plane */ 366 uint64_t modifiers[4]; 367 } f; 368 bool purged = true; 369 370 memset(&f, 0, sizeof(f)); 371 f.width = frame->width; 372 f.height = frame->height; 373 f.flags = 1 << 1; /* +modifiers */ 374 375 switch (frame->bo->tiling) { 376 case I915_TILING_NONE: 377 break; 378 case I915_TILING_X: 379 /* I915_FORMAT_MOD_X_TILED */ 380 f.modifiers[0] = (uint64_t)1 << 56 | 1; 381 break; 382 case I915_TILING_Y: 383 /* I915_FORMAT_MOD_X_TILED */ 384 f.modifiers[0] = (uint64_t)1 << 56 | 2; 385 break; 386 } 387 388 if (is_nv12_fourcc(frame->id)) { 389 f.handles[0] = frame->bo->handle; 390 f.handles[1] = frame->bo->handle; 391 f.pitches[0] = frame->pitch[1]; 392 f.pitches[1] = frame->pitch[0]; 393 f.offsets[0] = 0; 394 f.offsets[1] = frame->UBufOffset; 395 } else { 396 f.handles[0] = frame->bo->handle; 397 f.pitches[0] = frame->pitch[0]; 398 } 399 400 switch (frame->id) { 401 case FOURCC_RGB565: 402 f.pixel_format = DRM_FORMAT_RGB565; 403 purged = sna->scrn->depth != 16; 404 break; 405 case FOURCC_RGB888: 406 f.pixel_format = DRM_FORMAT_XRGB8888; 407 purged = sna->scrn->depth != 24; 408 break; 409 case FOURCC_NV12: 410 f.pixel_format = DRM_FORMAT_NV12; 411 break; 412 case FOURCC_UYVY: 413 f.pixel_format = DRM_FORMAT_UYVY; 414 break; 415 case FOURCC_AYUV: 416 /* i915 doesn't support alpha, so we use XYUV */ 417 f.pixel_format = DRM_FORMAT_XYUV8888; 418 break; 419 case FOURCC_YUY2: 420 default: 421 f.pixel_format = DRM_FORMAT_YUYV; 422 break; 423 } 424 425 DBG(("%s: creating new fb for handle=%d, width=%d, height=%d, stride=%d, format=%x\n", 426 __FUNCTION__, frame->bo->handle, frame->width, frame->height, 427 f.pitches[0], f.pixel_format)); 428 429 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) { 430 ERR(("%s: ADDFB2 failed, errno=%d\n", __FUNCTION__, errno)); 431 xf86DrvMsg(sna->scrn->scrnIndex, 432 X_ERROR, "failed to add fb, unable to update video\n"); 433 return false; 434 } 435 436 frame->bo->delta = f.fb_id; 437 438 frame->bo->scanout = true; 439 /* Don't allow the scanout to be cached if not suitable for front */ 440 frame->bo->purged = purged; 441 } 442 443 assert(frame->bo->scanout); 444 assert(frame->bo->delta); 445 446 s.crtc_id = sna_crtc_id(crtc); 447 s.fb_id = frame->bo->delta; 448 s.flags = 0; 449 s.crtc_x = dstBox->x1; 450 s.crtc_y = dstBox->y1; 451 s.crtc_w = dstBox->x2 - dstBox->x1; 452 s.crtc_h = dstBox->y2 - dstBox->y1; 453 s.src_x = 0; 454 s.src_y = 0; 455 s.src_w = (frame->image.x2 - frame->image.x1) << 16; 456 s.src_h = (frame->image.y2 - frame->image.y1) << 16; 457 458 DBG(("%s: updating crtc=%d, plane=%d, handle=%d [fb %d], dst=(%d,%d)x(%d,%d), src=(%d,%d)x(%d,%d)\n", 459 __FUNCTION__, s.crtc_id, s.plane_id, frame->bo->handle, s.fb_id, 460 s.crtc_x, s.crtc_y, s.crtc_w, s.crtc_h, 461 s.src_x >> 16, s.src_y >> 16, s.src_w >> 16, s.src_h >> 16)); 462 463 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) { 464 DBG(("SET_PLANE failed: ret=%d\n", errno)); 465 if (video->bo[pipe]) { 466 kgem_bo_destroy(&sna->kgem, video->bo[pipe]); 467 video->bo[pipe] = NULL; 468 } 469 return false; 470 } 471 472 __kgem_bo_clear_dirty(frame->bo); 473 474 if (video->bo[pipe]) 475 kgem_bo_destroy(&sna->kgem, video->bo[pipe]); 476 video->bo[pipe] = kgem_bo_reference(frame->bo); 477 return true; 478} 479 480static bool need_scaling(const struct sna_video_frame *frame, 481 const BoxRec *dst) 482{ 483 /* SKL+ need the plane scaler even for unscaled NV12 */ 484 return frame->id == FOURCC_NV12 || 485 frame->src.x2 - frame->src.x1 != dst->x2 - dst->x1 || 486 frame->src.y2 - frame->src.y1 != dst->y2 - dst->y1; 487} 488 489static int sna_video_sprite_put_image(ddPutImage_ARGS) 490{ 491 struct sna_video *video = port->devPriv.ptr; 492 struct sna *sna = video->sna; 493 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 494 RegionRec clip; 495 BoxRec draw_extents; 496 int ret, i; 497 498 init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h); 499 draw_extents = clip.extents; 500 501 DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop)); 502 if (!video->AlwaysOnTop) { 503 ValidateGC(draw, gc); 504 RegionIntersect(&clip, &clip, gc->pCompositeClip); 505 } 506 507 DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n", 508 __FUNCTION__, 509 src_x, src_y, src_w, src_h, 510 drw_x, drw_y, drw_w, drw_h, 511 format->id, width, height, sync)); 512 513 DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__, 514 region_num_rects(&clip), 515 clip.extents.x1, clip.extents.y1, 516 clip.extents.x2, clip.extents.y2)); 517 518 if (RegionNil(&clip)) { 519 ret = Success; 520 goto err; 521 } 522 523 for (i = 0; i < video->sna->mode.num_real_crtc; i++) { 524 xf86CrtcPtr crtc = config->crtc[i]; 525 struct sna_video_frame frame; 526 const int pipe = sna_crtc_pipe(crtc); 527 bool hw_scaling = has_hw_scaling(sna, video); 528 INT32 x1, x2, y1, y2; 529 Rotation rotation; 530 RegionRec reg; 531 BoxRec dst; 532 bool cache_bo; 533 534retry: 535 dst = draw_extents; 536 537 sna_video_frame_init(video, format->id, width, height, &frame); 538 539 reg.extents = crtc->bounds; 540 reg.data = NULL; 541 RegionIntersect(®, ®, &clip); 542 if (RegionNil(®)) { 543off: 544 assert(pipe < ARRAY_SIZE(video->bo)); 545 if (video->bo[pipe]) { 546 struct local_mode_set_plane s; 547 memset(&s, 0, sizeof(s)); 548 s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 549 if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 550 xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 551 "failed to disable plane\n"); 552 video->bo[pipe] = NULL; 553 } 554 continue; 555 } 556 557 x1 = src_x; 558 x2 = src_x + src_w; 559 y1 = src_y; 560 y2 = src_y + src_h; 561 562 ret = xf86XVClipVideoHelper(&dst, &x1, &x2, &y1, &y2, 563 ®, frame.width, frame.height); 564 RegionUninit(®); 565 if (!ret) 566 goto off; 567 568 frame.src.x1 = x1 >> 16; 569 frame.src.y1 = y1 >> 16; 570 frame.src.x2 = (x2 + 0xffff) >> 16; 571 frame.src.y2 = (y2 + 0xffff) >> 16; 572 573 frame.image.x1 = frame.src.x1 & ~1; 574 frame.image.x2 = ALIGN(frame.src.x2, 2); 575 if (is_planar_fourcc(frame.id)) { 576 frame.image.y1 = frame.src.y1 & ~1; 577 frame.image.y2 = ALIGN(frame.src.y2, 2); 578 } else { 579 frame.image.y1 = frame.src.y1; 580 frame.image.y2 = frame.src.y2; 581 } 582 583 /* if sprite can't handle rotation natively, store it for the copy func */ 584 rotation = RR_Rotate_0; 585 if (!sna_crtc_set_sprite_rotation(crtc, video->idx, crtc->rotation)) { 586 sna_crtc_set_sprite_rotation(crtc, video->idx, RR_Rotate_0); 587 rotation = crtc->rotation; 588 } 589 sna_video_frame_set_rotation(video, &frame, rotation); 590 591 if (xvmc_passthrough(format->id)) { 592 DBG(("%s: using passthough, name=%d\n", 593 __FUNCTION__, *(uint32_t *)buf)); 594 595 if (*(uint32_t*)buf == 0) 596 goto err; 597 598 frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf); 599 if (frame.bo == NULL) { 600 ret = BadAlloc; 601 goto err; 602 } 603 604 if (kgem_bo_size(frame.bo) < frame.size) { 605 DBG(("%s: bo size=%d, expected=%d\n", 606 __FUNCTION__, kgem_bo_size(frame.bo), frame.size)); 607 kgem_bo_destroy(&sna->kgem, frame.bo); 608 ret = BadAlloc; 609 goto err; 610 } 611 612 frame.image.x1 = 0; 613 frame.image.y1 = 0; 614 frame.image.x2 = frame.width; 615 frame.image.y2 = frame.height; 616 617 cache_bo = false; 618 } else { 619 frame.bo = sna_video_buffer(video, &frame); 620 if (frame.bo == NULL) { 621 DBG(("%s: failed to allocate video bo\n", __FUNCTION__)); 622 ret = BadAlloc; 623 goto err; 624 } 625 626 if (!sna_video_copy_data(video, &frame, buf)) { 627 DBG(("%s: failed to copy video data\n", __FUNCTION__)); 628 ret = BadAlloc; 629 goto err; 630 } 631 632 cache_bo = true; 633 } 634 635 if (!hw_scaling && sna->render.video && 636 need_scaling(&frame, &dst)) { 637 ScreenPtr screen = to_screen_from_sna(sna); 638 PixmapPtr scaled; 639 RegionRec r; 640 641 r.extents.x1 = r.extents.y1 = 0; 642 r.extents.x2 = dst.x2 - dst.x1; 643 r.extents.y2 = dst.y2 - dst.y1; 644 r.data = NULL; 645 646 DBG(("%s: scaling from (%d, %d) to (%d, %d)\n", 647 __FUNCTION__, 648 frame.src.x2 - frame.src.x1, 649 frame.src.y2 - frame.src.y1, 650 r.extents.x2, r.extents.y2)); 651 652 scaled = screen->CreatePixmap(screen, 653 r.extents.x2, 654 r.extents.y2, 655 24, 656 CREATE_PIXMAP_USAGE_SCRATCH); 657 if (scaled == NULL) { 658 ret = BadAlloc; 659 goto err; 660 } 661 662 if (!sna->render.video(sna, video, &frame, &r, scaled)) { 663 screen->DestroyPixmap(scaled); 664 ret = BadAlloc; 665 goto err; 666 } 667 668 if (cache_bo) 669 sna_video_buffer_fini(video); 670 else 671 kgem_bo_destroy(&sna->kgem, frame.bo); 672 673 frame.bo = kgem_bo_reference(__sna_pixmap_get_bo(scaled)); 674 kgem_bo_submit(&sna->kgem, frame.bo); 675 676 frame.id = FOURCC_RGB888; 677 frame.src = frame.image = r.extents; 678 frame.width = frame.image.x2; 679 frame.height = frame.image.y2; 680 frame.pitch[0] = frame.bo->pitch; 681 682 screen->DestroyPixmap(scaled); 683 cache_bo = false; 684 } 685 686 ret = Success; 687 if (!sna_video_sprite_show(sna, video, &frame, crtc, &dst)) { 688 DBG(("%s: failed to show video frame\n", __FUNCTION__)); 689 ret = BadAlloc; 690 } 691 692 if (cache_bo) 693 sna_video_buffer_fini(video); 694 else 695 kgem_bo_destroy(&sna->kgem, frame.bo); 696 697 if (ret != Success) { 698 /* retry with GPU scaling */ 699 if (hw_scaling) { 700 hw_scaling = false; 701 goto retry; 702 } 703 goto err; 704 } 705 } 706 707 sna_video_fill_colorkey(video, &clip); 708 sna_window_set_port((WindowPtr)draw, port); 709 710 return Success; 711 712err: 713#if XORG_XV_VERSION < 2 714 (void)sna_video_sprite_stop(client, port, draw); 715#else 716 (void)sna_video_sprite_stop(port, draw); 717#endif 718 return ret; 719} 720 721static int sna_video_sprite_query(ddQueryImageAttributes_ARGS) 722{ 723 struct sna_video *video = port->devPriv.ptr; 724 struct sna_video_frame frame; 725 int size, tmp; 726 727 if (*w > video->sna->mode.max_crtc_width) 728 *w = video->sna->mode.max_crtc_width; 729 if (*h > video->sna->mode.max_crtc_height) 730 *h = video->sna->mode.max_crtc_height; 731 732 if (offsets) 733 offsets[0] = 0; 734 735 switch (format->id) { 736 case FOURCC_RGB888: 737 case FOURCC_RGB565: 738 if (pitches) { 739 sna_video_frame_init(video, format->id, *w, *h, &frame); 740 sna_video_frame_set_rotation(video, &frame, RR_Rotate_0); 741 pitches[0] = frame.pitch[0]; 742 } 743 size = 4; 744 break; 745 746 case FOURCC_NV12: 747 *h = (*h + 1) & ~1; 748 size = (*w + 3) & ~3; 749 if (pitches) 750 pitches[0] = size; 751 size *= *h; 752 if (offsets) 753 offsets[1] = size; 754 tmp = (*w + 3) & ~3; 755 if (pitches) 756 pitches[1] = tmp; 757 tmp *= (*h >> 1); 758 size += tmp; 759 break; 760 case FOURCC_AYUV: 761 tmp = *w << 2; 762 if (pitches) 763 pitches[0] = tmp; 764 size = *h * tmp; 765 break; 766 default: 767 *w = (*w + 1) & ~1; 768 *h = (*h + 1) & ~1; 769 770 size = *w << 1; 771 if (pitches) 772 pitches[0] = size; 773 size *= *h; 774 break; 775 } 776 777 return size; 778} 779 780static int sna_video_sprite_color_key(struct sna *sna) 781{ 782 ScrnInfoPtr scrn = sna->scrn; 783 int color_key; 784 785 if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY, 786 &color_key)) { 787 } else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY, 788 &color_key)) { 789 } else { 790 color_key = 791 (1 << scrn->offset.red) | 792 (1 << scrn->offset.green) | 793 (((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue); 794 } 795 796 return color_key & ((1 << scrn->depth) - 1); 797} 798 799static int sna_video_has_sprites(struct sna *sna) 800{ 801 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 802 unsigned min; 803 int i; 804 805 DBG(("%s: num_crtc=%d\n", __FUNCTION__, sna->mode.num_real_crtc)); 806 807 if (sna->mode.num_real_crtc == 0) 808 return 0; 809 810 min = -1; 811 for (i = 0; i < sna->mode.num_real_crtc; i++) { 812 unsigned count = sna_crtc_count_sprites(config->crtc[i]); 813 DBG(("%s: %d sprites found on pipe %d\n", __FUNCTION__, 814 count, sna_crtc_pipe(config->crtc[i]))); 815 if (count < min) 816 min = count; 817 } 818 819 DBG(("%s: min=%d\n", __FUNCTION__, min)); 820 return min; 821} 822 823void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen) 824{ 825 XvAdaptorPtr adaptor; 826 struct sna_video *video; 827 XvPortPtr port; 828 int count, i; 829 830 count = sna_video_has_sprites(sna); 831 if (!count) 832 return; 833 834 adaptor = sna_xv_adaptor_alloc(sna); 835 if (!adaptor) 836 return; 837 838 video = calloc(count, sizeof(*video)); 839 port = calloc(count, sizeof(*port)); 840 if (video == NULL || port == NULL) { 841 free(video); 842 free(port); 843 sna->xv.num_adaptors--; 844 return; 845 } 846 847 adaptor->type = XvInputMask | XvImageMask; 848 adaptor->pScreen = screen; 849 adaptor->name = (char *)"Intel(R) Video Sprite"; 850 adaptor->nEncodings = 1; 851 adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec)); 852 adaptor->pEncodings[0].id = 0; 853 adaptor->pEncodings[0].pScreen = screen; 854 adaptor->pEncodings[0].name = (char *)"XV_IMAGE"; 855 adaptor->pEncodings[0].width = sna->mode.max_crtc_width; 856 adaptor->pEncodings[0].height = sna->mode.max_crtc_height; 857 adaptor->pEncodings[0].rate.numerator = 1; 858 adaptor->pEncodings[0].rate.denominator = 1; 859 adaptor->pFormats = formats; 860 adaptor->nFormats = sna_xv_fixup_formats(screen, formats, 861 ARRAY_SIZE(formats)); 862 adaptor->nAttributes = ARRAY_SIZE(attribs); 863 adaptor->pAttributes = (XvAttributeRec *)attribs; 864 865 if (sna_has_sprite_format(sna, DRM_FORMAT_XYUV8888)) { 866 adaptor->pImages = (XvImageRec *)images_ayuv; 867 adaptor->nImages = ARRAY_SIZE(images_ayuv); 868 } else if (sna_has_sprite_format(sna, DRM_FORMAT_NV12)) { 869 adaptor->pImages = (XvImageRec *)images_nv12; 870 adaptor->nImages = ARRAY_SIZE(images_nv12); 871 } else if (sna_has_sprite_format(sna, DRM_FORMAT_RGB565)) { 872 adaptor->pImages = (XvImageRec *)images_rgb565; 873 adaptor->nImages = ARRAY_SIZE(images_rgb565); 874 } else { 875 adaptor->pImages = (XvImageRec *)images; 876 adaptor->nImages = ARRAY_SIZE(images); 877 } 878 879#if XORG_XV_VERSION < 2 880 adaptor->ddAllocatePort = sna_xv_alloc_port; 881 adaptor->ddFreePort = sna_xv_free_port; 882#endif 883 adaptor->ddPutVideo = NULL; 884 adaptor->ddPutStill = NULL; 885 adaptor->ddGetVideo = NULL; 886 adaptor->ddGetStill = NULL; 887 adaptor->ddStopVideo = sna_video_sprite_stop; 888 adaptor->ddSetPortAttribute = sna_video_sprite_set_attr; 889 adaptor->ddGetPortAttribute = sna_video_sprite_get_attr; 890 adaptor->ddQueryBestSize = sna_video_sprite_best_size; 891 adaptor->ddPutImage = sna_video_sprite_put_image; 892 adaptor->ddQueryImageAttributes = sna_video_sprite_query; 893 894 adaptor->nPorts = count; 895 adaptor->pPorts = port; 896 897 for (i = 0; i < count; i++) { 898 port->id = FakeClientID(0); 899 AddResource(port->id, XvGetRTPort(), port); 900 port->pAdaptor = adaptor; 901 port->pNotify = NULL; 902 port->pDraw = NULL; 903 port->client = NULL; 904 port->grab.client = NULL; 905 port->time = currentTime; 906 port->devPriv.ptr = video; 907 908 video->sna = sna; 909 video->idx = i; 910 video->alignment = 64; 911 video->color_key = sna_video_sprite_color_key(sna); 912 video->color_key_changed = ~0; 913 video->colorspace = 1; /* BT.709 */ 914 video->colorspace_changed = ~0; 915 video->has_color_key = true; 916 video->brightness = -19; /* (255/219) * -16 */ 917 video->contrast = 75; /* 255/219 * 64 */ 918 video->saturation = 146; /* 128/112 * 128 */ 919 video->desired_crtc = NULL; 920 video->gamma5 = 0xc0c0c0; 921 video->gamma4 = 0x808080; 922 video->gamma3 = 0x404040; 923 video->gamma2 = 0x202020; 924 video->gamma1 = 0x101010; 925 video->gamma0 = 0x080808; 926 RegionNull(&video->clip); 927 video->SyncToVblank = 1; 928 929 port++; 930 video++; 931 } 932 adaptor->base_id = adaptor->pPorts[0].id; 933 934 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 935 xvColorspace = MAKE_ATOM("XV_COLORSPACE"); 936 xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP"); 937 xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 938 939 DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts)); 940} 941