intel_video.c revision 03b705cf
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/* 45 * XXX Could support more formats. 46 */ 47 48#ifdef HAVE_CONFIG_H 49#include "config.h" 50#endif 51 52#include <inttypes.h> 53#include <math.h> 54#include <string.h> 55#include <assert.h> 56#include <errno.h> 57 58#include "xf86.h" 59#include "xf86_OSproc.h" 60#include "compiler.h" 61#include "xf86Pci.h" 62#include "xf86fbman.h" 63#include "xf86drm.h" 64#include "regionstr.h" 65#include "randrstr.h" 66#include "windowstr.h" 67#include "damage.h" 68#include "intel.h" 69#include "intel_video.h" 70#include "i830_reg.h" 71#include "xf86xv.h" 72#include <X11/extensions/Xv.h> 73#include "dixstruct.h" 74#include "fourcc.h" 75 76#ifdef INTEL_XVMC 77#define _INTEL_XVMC_SERVER_ 78#include "intel_xvmc.h" 79#endif 80 81#define OFF_DELAY 250 /* milliseconds */ 82 83#define OFF_TIMER 0x01 84#define CLIENT_VIDEO_ON 0x02 85 86static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr); 87static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr); 88static void I830StopVideo(ScrnInfoPtr, pointer, Bool); 89static int I830SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); 90static int I830SetPortAttributeTextured(ScrnInfoPtr, Atom, INT32, pointer); 91static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer); 92static void I830QueryBestSize(ScrnInfoPtr, Bool, 93 short, short, short, short, unsigned int *, 94 unsigned int *, pointer); 95static int I830PutImageTextured(ScrnInfoPtr, short, short, short, short, short, short, 96 short, short, int, unsigned char *, short, short, 97 Bool, RegionPtr, pointer, DrawablePtr); 98static int I830PutImageOverlay(ScrnInfoPtr, short, short, short, short, short, short, 99 short, short, int, unsigned char *, short, short, 100 Bool, RegionPtr, pointer, DrawablePtr); 101static int I830QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, 102 unsigned short *, int *, int *); 103 104#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) 105 106static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe; 107static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5; 108static Atom xvSyncToVblank; 109 110/* Limits for the overlay/textured video source sizes. The documented hardware 111 * limits are 2048x2048 or better for overlay and both of our textured video 112 * implementations. Additionally, on the 830 and 845, larger sizes resulted in 113 * the card hanging, so we keep the limits lower there. 114 */ 115#define IMAGE_MAX_WIDTH 2048 116#define IMAGE_MAX_HEIGHT 2048 117#define IMAGE_MAX_WIDTH_LEGACY 1024 118#define IMAGE_MAX_HEIGHT_LEGACY 1088 119 120/* overlay debugging printf function */ 121#if 0 122#define OVERLAY_DEBUG ErrorF 123#else 124#define OVERLAY_DEBUG if (0) ErrorF 125#endif 126 127/* client libraries expect an encoding */ 128static const XF86VideoEncodingRec DummyEncoding[1] = { 129 { 130 0, 131 "XV_IMAGE", 132 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 133 {1, 1} 134 } 135}; 136 137#define NUM_FORMATS 3 138 139static XF86VideoFormatRec Formats[NUM_FORMATS] = { 140 {15, TrueColor}, {16, TrueColor}, {24, TrueColor} 141}; 142 143#define NUM_ATTRIBUTES 5 144static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { 145 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 146 {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, 147 {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}, 148 {XvSettable | XvGettable, 0, 1023, "XV_SATURATION"}, 149 {XvSettable | XvGettable, -1, 1, "XV_PIPE"} 150}; 151 152#define GAMMA_ATTRIBUTES 6 153static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = { 154 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"}, 155 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"}, 156 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"}, 157 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"}, 158 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"}, 159 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"} 160}; 161 162#ifdef INTEL_XVMC 163#define NUM_IMAGES 5 164#define XVMC_IMAGE 1 165#else 166#define NUM_IMAGES 4 167#define XVMC_IMAGE 0 168#endif 169 170static XF86ImageRec Images[NUM_IMAGES] = { 171 XVIMAGE_YUY2, 172 XVIMAGE_YV12, 173 XVIMAGE_I420, 174 XVIMAGE_UYVY, 175#ifdef INTEL_XVMC 176 { 177 /* 178 * Below, a dummy picture type that is used in XvPutImage only to do 179 * an overlay update. Introduced for the XvMC client lib. 180 * Defined to have a zero data size. 181 */ 182 FOURCC_XVMC, 183 XvYUV, 184 LSBFirst, 185 {'X', 'V', 'M', 'C', 186 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00, 187 0x38, 0x9B, 0x71}, 188 12, 189 XvPlanar, 190 3, 191 0, 0, 0, 0, 192 8, 8, 8, 193 1, 2, 2, 194 1, 2, 2, 195 {'Y', 'V', 'U', 196 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 198 XvTopToBottom}, 199#endif 200}; 201 202/* kernel modesetting overlay functions */ 203static Bool intel_has_overlay(intel_screen_private *intel) 204{ 205 struct drm_i915_getparam gp; 206 int has_overlay = 0; 207 int ret; 208 209 gp.param = I915_PARAM_HAS_OVERLAY; 210 gp.value = &has_overlay; 211 ret = drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, sizeof(gp)); 212 213 return ret == 0 && !! has_overlay; 214} 215 216static Bool intel_overlay_update_attrs(intel_screen_private *intel) 217{ 218 intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); 219 struct drm_intel_overlay_attrs attrs; 220 221 attrs.flags = I915_OVERLAY_UPDATE_ATTRS; 222 attrs.brightness = adaptor_priv->brightness; 223 attrs.contrast = adaptor_priv->contrast; 224 attrs.saturation = adaptor_priv->saturation; 225 attrs.color_key = adaptor_priv->colorKey; 226 attrs.gamma0 = adaptor_priv->gamma0; 227 attrs.gamma1 = adaptor_priv->gamma1; 228 attrs.gamma2 = adaptor_priv->gamma2; 229 attrs.gamma3 = adaptor_priv->gamma3; 230 attrs.gamma4 = adaptor_priv->gamma4; 231 attrs.gamma5 = adaptor_priv->gamma5; 232 233 return drmCommandWriteRead(intel->drmSubFD, DRM_I915_OVERLAY_ATTRS, 234 &attrs, sizeof(attrs)) == 0; 235} 236 237static void intel_overlay_off(intel_screen_private *intel) 238{ 239 struct drm_intel_overlay_put_image request; 240 int ret; 241 242 request.flags = 0; 243 244 ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, 245 &request, sizeof(request)); 246 (void) ret; 247} 248 249static Bool 250intel_overlay_put_image(intel_screen_private *intel, 251 xf86CrtcPtr crtc, 252 int id, short width, short height, 253 int dstPitch, int dstPitch2, 254 BoxPtr dstBox, short src_w, short src_h, short drw_w, 255 short drw_h) 256{ 257 intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); 258 struct drm_intel_overlay_put_image request; 259 int ret; 260 int planar = is_planar_fourcc(id); 261 float scale; 262 dri_bo *tmp; 263 264 request.flags = I915_OVERLAY_ENABLE; 265 266 request.bo_handle = adaptor_priv->buf->handle; 267 if (planar) { 268 request.stride_Y = dstPitch2; 269 request.stride_UV = dstPitch; 270 } else { 271 request.stride_Y = dstPitch; 272 request.stride_UV = 0; 273 } 274 request.offset_Y = adaptor_priv->YBufOffset; 275 request.offset_U = adaptor_priv->UBufOffset; 276 request.offset_V = adaptor_priv->VBufOffset; 277 OVERLAY_DEBUG("off_Y: %i, off_U: %i, off_V: %i\n", request.offset_Y, 278 request.offset_U, request.offset_V); 279 280 request.crtc_id = intel_crtc_id(crtc); 281 request.dst_x = dstBox->x1; 282 request.dst_y = dstBox->y1; 283 request.dst_width = dstBox->x2 - dstBox->x1; 284 request.dst_height = dstBox->y2 - dstBox->y1; 285 286 request.src_width = width; 287 request.src_height = height; 288 /* adjust src dimensions */ 289 if (request.dst_height > 1) { 290 scale = ((float)request.dst_height - 1) / ((float)drw_h - 1); 291 request.src_scan_height = src_h * scale; 292 } else 293 request.src_scan_height = 1; 294 295 if (request.dst_width > 1) { 296 scale = ((float)request.dst_width - 1) / ((float)drw_w - 1); 297 request.src_scan_width = src_w * scale; 298 } else 299 request.src_scan_width = 1; 300 301 if (planar) { 302 request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420; 303 } else { 304 request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422; 305 if (id == FOURCC_UYVY) 306 request.flags |= I915_OVERLAY_Y_SWAP; 307 } 308 309 ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, 310 &request, sizeof(request)); 311 if (ret) 312 return FALSE; 313 314 if (!adaptor_priv->reusable) { 315 drm_intel_bo_unreference(adaptor_priv->buf); 316 adaptor_priv->buf = NULL; 317 adaptor_priv->reusable = TRUE; 318 } 319 320 tmp = adaptor_priv->old_buf[1]; 321 adaptor_priv->old_buf[1] = adaptor_priv->old_buf[0]; 322 adaptor_priv->old_buf[0] = adaptor_priv->buf; 323 adaptor_priv->buf = tmp; 324 325 return TRUE; 326} 327 328void I830InitVideo(ScreenPtr screen) 329{ 330 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 331 intel_screen_private *intel = intel_get_screen_private(scrn); 332 XF86VideoAdaptorPtr *adaptors = NULL, *newAdaptors = NULL; 333 XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL; 334 int num_adaptors = xf86XVListGenericAdaptors(scrn, &adaptors); 335 /* Give our adaptor list enough space for the overlay and/or texture video 336 * adaptors. 337 */ 338 newAdaptors = realloc(adaptors, 339 (num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr)); 340 if (newAdaptors == NULL) { 341 free(adaptors); 342 return; 343 } 344 adaptors = newAdaptors; 345 346 /* Add the adaptors supported by our hardware. First, set up the atoms 347 * that will be used by both output adaptors. 348 */ 349 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 350 xvContrast = MAKE_ATOM("XV_CONTRAST"); 351 352 /* Set up textured video if we can do it at this depth and we are on 353 * supported hardware. 354 */ 355 if (scrn->bitsPerPixel >= 16 && 356 INTEL_INFO(intel)->gen >= 030) { 357 texturedAdaptor = I830SetupImageVideoTextured(screen); 358 if (texturedAdaptor != NULL) { 359 xf86DrvMsg(scrn->scrnIndex, X_INFO, 360 "Set up textured video\n"); 361 } else { 362 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 363 "Failed to set up textured video\n"); 364 } 365 } 366 367 /* Set up overlay video if it is available */ 368 intel->use_overlay = intel_has_overlay(intel); 369 if (intel->use_overlay) { 370 overlayAdaptor = I830SetupImageVideoOverlay(screen); 371 if (overlayAdaptor != NULL) { 372 xf86DrvMsg(scrn->scrnIndex, X_INFO, 373 "Set up overlay video\n"); 374 } else { 375 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 376 "Failed to set up overlay video\n"); 377 } 378 } 379 380 if (overlayAdaptor && intel->XvPreferOverlay) 381 adaptors[num_adaptors++] = overlayAdaptor; 382 383 if (texturedAdaptor) 384 adaptors[num_adaptors++] = texturedAdaptor; 385 386 if (overlayAdaptor && !intel->XvPreferOverlay) 387 adaptors[num_adaptors++] = overlayAdaptor; 388 389 if (num_adaptors) { 390 xf86XVScreenInit(screen, adaptors, num_adaptors); 391 } else { 392 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 393 "Disabling Xv because no adaptors could be initialized.\n"); 394 intel->XvEnabled = FALSE; 395 } 396 397#ifdef INTEL_XVMC 398 if (texturedAdaptor) 399 intel_xvmc_adaptor_init(screen); 400#endif 401 free(adaptors); 402} 403 404static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr screen) 405{ 406 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 407 intel_screen_private *intel = intel_get_screen_private(scrn); 408 XF86VideoAdaptorPtr adapt; 409 intel_adaptor_private *adaptor_priv; 410 XF86AttributePtr att; 411 412 OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); 413 414 if (!(adapt = calloc(1, 415 sizeof(XF86VideoAdaptorRec) + 416 sizeof(intel_adaptor_private) + 417 sizeof(DevUnion)))) 418 return NULL; 419 420 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 421 adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ; 422 adapt->name = "Intel(R) Video Overlay"; 423 adapt->nEncodings = 1; 424 adapt->pEncodings = xnfalloc(sizeof(DummyEncoding)); 425 memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding)); 426 if (IS_845G(intel) || IS_I830(intel)) { 427 adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY; 428 adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY; 429 } 430 adapt->nFormats = NUM_FORMATS; 431 adapt->pFormats = Formats; 432 adapt->nPorts = 1; 433 adapt->pPortPrivates = (DevUnion *) (&adapt[1]); 434 435 adaptor_priv = (intel_adaptor_private *)&adapt->pPortPrivates[1]; 436 437 adapt->pPortPrivates[0].ptr = (pointer) (adaptor_priv); 438 adapt->nAttributes = NUM_ATTRIBUTES; 439 if (INTEL_INFO(intel)->gen >= 030) 440 adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */ 441 adapt->pAttributes = 442 xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes); 443 /* Now copy the attributes */ 444 att = adapt->pAttributes; 445 memcpy((char *)att, (char *)Attributes, 446 sizeof(XF86AttributeRec) * NUM_ATTRIBUTES); 447 att += NUM_ATTRIBUTES; 448 if (INTEL_INFO(intel)->gen >= 030) { 449 memcpy((char *)att, (char *)GammaAttributes, 450 sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES); 451 } 452 adapt->nImages = NUM_IMAGES - XVMC_IMAGE; 453 454 adapt->pImages = Images; 455 adapt->PutVideo = NULL; 456 adapt->PutStill = NULL; 457 adapt->GetVideo = NULL; 458 adapt->GetStill = NULL; 459 adapt->StopVideo = I830StopVideo; 460 adapt->SetPortAttribute = I830SetPortAttributeOverlay; 461 adapt->GetPortAttribute = I830GetPortAttribute; 462 adapt->QueryBestSize = I830QueryBestSize; 463 adapt->PutImage = I830PutImageOverlay; 464 adapt->QueryImageAttributes = I830QueryImageAttributes; 465 466 adaptor_priv->textured = FALSE; 467 adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1); 468 adaptor_priv->videoStatus = 0; 469 adaptor_priv->brightness = -19; /* (255/219) * -16 */ 470 adaptor_priv->contrast = 75; /* 255/219 * 64 */ 471 adaptor_priv->saturation = 146; /* 128/112 * 128 */ 472 adaptor_priv->desired_crtc = NULL; 473 adaptor_priv->buf = NULL; 474 adaptor_priv->old_buf[0] = NULL; 475 adaptor_priv->old_buf[1] = NULL; 476 adaptor_priv->gamma5 = 0xc0c0c0; 477 adaptor_priv->gamma4 = 0x808080; 478 adaptor_priv->gamma3 = 0x404040; 479 adaptor_priv->gamma2 = 0x202020; 480 adaptor_priv->gamma1 = 0x101010; 481 adaptor_priv->gamma0 = 0x080808; 482 483 adaptor_priv->rotation = RR_Rotate_0; 484 485 /* gotta uninit this someplace */ 486 REGION_NULL(screen, &adaptor_priv->clip); 487 488 intel->adaptor = adapt; 489 490 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 491 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 492 xvContrast = MAKE_ATOM("XV_CONTRAST"); 493 xvSaturation = MAKE_ATOM("XV_SATURATION"); 494 495 /* Allow the pipe to be switched from pipe A to B when in clone mode */ 496 xvPipe = MAKE_ATOM("XV_PIPE"); 497 498 if (INTEL_INFO(intel)->gen >= 030) { 499 xvGamma0 = MAKE_ATOM("XV_GAMMA0"); 500 xvGamma1 = MAKE_ATOM("XV_GAMMA1"); 501 xvGamma2 = MAKE_ATOM("XV_GAMMA2"); 502 xvGamma3 = MAKE_ATOM("XV_GAMMA3"); 503 xvGamma4 = MAKE_ATOM("XV_GAMMA4"); 504 xvGamma5 = MAKE_ATOM("XV_GAMMA5"); 505 } 506 507 intel_overlay_update_attrs(intel); 508 509 return adapt; 510} 511 512static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr screen) 513{ 514 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 515 intel_screen_private *intel = intel_get_screen_private(scrn); 516 XF86VideoAdaptorPtr adapt; 517 intel_adaptor_private *adaptor_privs; 518 DevUnion *devUnions; 519 int nports = 16, i; 520 521 OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); 522 523 adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); 524 adaptor_privs = calloc(nports, sizeof(intel_adaptor_private)); 525 devUnions = calloc(nports, sizeof(DevUnion)); 526 if (adapt == NULL || adaptor_privs == NULL || devUnions == NULL) { 527 free(adapt); 528 free(adaptor_privs); 529 free(devUnions); 530 return NULL; 531 } 532 533 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 534 adapt->flags = 0; 535 adapt->name = "Intel(R) Textured Video"; 536 adapt->nEncodings = 1; 537 adapt->pEncodings = xnfalloc(sizeof(DummyEncoding)); 538 memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding)); 539 adapt->nFormats = NUM_FORMATS; 540 adapt->pFormats = Formats; 541 adapt->nPorts = nports; 542 adapt->pPortPrivates = devUnions; 543 adapt->nAttributes = 0; 544 adapt->pAttributes = NULL; 545 if (IS_I915G(intel) || IS_I915GM(intel)) 546 adapt->nImages = NUM_IMAGES - XVMC_IMAGE; 547 else 548 adapt->nImages = NUM_IMAGES; 549 550 adapt->pImages = Images; 551 adapt->PutVideo = NULL; 552 adapt->PutStill = NULL; 553 adapt->GetVideo = NULL; 554 adapt->GetStill = NULL; 555 adapt->StopVideo = I830StopVideo; 556 adapt->SetPortAttribute = I830SetPortAttributeTextured; 557 adapt->GetPortAttribute = I830GetPortAttribute; 558 adapt->QueryBestSize = I830QueryBestSize; 559 adapt->PutImage = I830PutImageTextured; 560 adapt->QueryImageAttributes = I830QueryImageAttributes; 561 562 for (i = 0; i < nports; i++) { 563 intel_adaptor_private *adaptor_priv = &adaptor_privs[i]; 564 565 adaptor_priv->textured = TRUE; 566 adaptor_priv->videoStatus = 0; 567 adaptor_priv->buf = NULL; 568 adaptor_priv->old_buf[0] = NULL; 569 adaptor_priv->old_buf[1] = NULL; 570 571 adaptor_priv->rotation = RR_Rotate_0; 572 adaptor_priv->SyncToVblank = 1; 573 574 /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ 575 REGION_NULL(screen, &adaptor_priv->clip); 576 577 adapt->pPortPrivates[i].ptr = (pointer) (adaptor_priv); 578 } 579 580 xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 581 582 return adapt; 583} 584 585static void intel_free_video_buffers(intel_adaptor_private *adaptor_priv) 586{ 587 int i; 588 589 for (i = 0; i < 2; i++) { 590 if (adaptor_priv->old_buf[i]) { 591 drm_intel_bo_disable_reuse(adaptor_priv->old_buf[i]); 592 drm_intel_bo_unreference(adaptor_priv->old_buf[i]); 593 adaptor_priv->old_buf[i] = NULL; 594 } 595 } 596 597 if (adaptor_priv->buf) { 598 drm_intel_bo_unreference(adaptor_priv->buf); 599 adaptor_priv->buf = NULL; 600 } 601} 602 603static void I830StopVideo(ScrnInfoPtr scrn, pointer data, Bool shutdown) 604{ 605 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 606 607 if (adaptor_priv->textured) 608 return; 609 610 OVERLAY_DEBUG("I830StopVideo\n"); 611 612 REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip); 613 614 if (shutdown) { 615 if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) 616 intel_overlay_off(intel_get_screen_private(scrn)); 617 618 intel_free_video_buffers(adaptor_priv); 619 adaptor_priv->videoStatus = 0; 620 } else { 621 if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) { 622 adaptor_priv->videoStatus |= OFF_TIMER; 623 adaptor_priv->offTime = currentTime.milliseconds + OFF_DELAY; 624 } 625 } 626 627} 628 629static int 630I830SetPortAttributeTextured(ScrnInfoPtr scrn, 631 Atom attribute, INT32 value, pointer data) 632{ 633 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 634 635 if (attribute == xvBrightness) { 636 if ((value < -128) || (value > 127)) 637 return BadValue; 638 adaptor_priv->brightness = value; 639 return Success; 640 } else if (attribute == xvContrast) { 641 if ((value < 0) || (value > 255)) 642 return BadValue; 643 adaptor_priv->contrast = value; 644 return Success; 645 } else if (attribute == xvSyncToVblank) { 646 if ((value < -1) || (value > 1)) 647 return BadValue; 648 adaptor_priv->SyncToVblank = value; 649 return Success; 650 } else { 651 return BadMatch; 652 } 653} 654 655static int 656I830SetPortAttributeOverlay(ScrnInfoPtr scrn, 657 Atom attribute, INT32 value, pointer data) 658{ 659 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 660 intel_screen_private *intel = intel_get_screen_private(scrn); 661 662 if (attribute == xvBrightness) { 663 if ((value < -128) || (value > 127)) 664 return BadValue; 665 adaptor_priv->brightness = value; 666 OVERLAY_DEBUG("BRIGHTNESS\n"); 667 } else if (attribute == xvContrast) { 668 if ((value < 0) || (value > 255)) 669 return BadValue; 670 adaptor_priv->contrast = value; 671 OVERLAY_DEBUG("CONTRAST\n"); 672 } else if (attribute == xvSaturation) { 673 if ((value < 0) || (value > 1023)) 674 return BadValue; 675 adaptor_priv->saturation = value; 676 } else if (attribute == xvPipe) { 677 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 678 if ((value < -1) || (value >= xf86_config->num_crtc)) 679 return BadValue; 680 if (value < 0) 681 adaptor_priv->desired_crtc = NULL; 682 else 683 adaptor_priv->desired_crtc = xf86_config->crtc[value]; 684 } else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) { 685 adaptor_priv->gamma0 = value; 686 } else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) { 687 adaptor_priv->gamma1 = value; 688 } else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) { 689 adaptor_priv->gamma2 = value; 690 } else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) { 691 adaptor_priv->gamma3 = value; 692 } else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) { 693 adaptor_priv->gamma4 = value; 694 } else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) { 695 adaptor_priv->gamma5 = value; 696 } else if (attribute == xvColorKey) { 697 adaptor_priv->colorKey = value; 698 OVERLAY_DEBUG("COLORKEY\n"); 699 } else 700 return BadMatch; 701 702 if ((attribute == xvGamma0 || 703 attribute == xvGamma1 || 704 attribute == xvGamma2 || 705 attribute == xvGamma3 || 706 attribute == xvGamma4 || 707 attribute == xvGamma5) && (INTEL_INFO(intel)->gen >= 030)) { 708 OVERLAY_DEBUG("GAMMA\n"); 709 } 710 711 if (!intel_overlay_update_attrs(intel)) 712 return BadValue; 713 714 if (attribute == xvColorKey) 715 REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip); 716 717 return Success; 718} 719 720static int 721I830GetPortAttribute(ScrnInfoPtr scrn, 722 Atom attribute, INT32 * value, pointer data) 723{ 724 intel_screen_private *intel = intel_get_screen_private(scrn); 725 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 726 727 if (attribute == xvBrightness) { 728 *value = adaptor_priv->brightness; 729 } else if (attribute == xvContrast) { 730 *value = adaptor_priv->contrast; 731 } else if (attribute == xvSaturation) { 732 *value = adaptor_priv->saturation; 733 } else if (attribute == xvPipe) { 734 int c; 735 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 736 for (c = 0; c < xf86_config->num_crtc; c++) 737 if (xf86_config->crtc[c] == adaptor_priv->desired_crtc) 738 break; 739 if (c == xf86_config->num_crtc) 740 c = -1; 741 *value = c; 742 } else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) { 743 *value = adaptor_priv->gamma0; 744 } else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) { 745 *value = adaptor_priv->gamma1; 746 } else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) { 747 *value = adaptor_priv->gamma2; 748 } else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) { 749 *value = adaptor_priv->gamma3; 750 } else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) { 751 *value = adaptor_priv->gamma4; 752 } else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) { 753 *value = adaptor_priv->gamma5; 754 } else if (attribute == xvColorKey) { 755 *value = adaptor_priv->colorKey; 756 } else if (attribute == xvSyncToVblank) { 757 *value = adaptor_priv->SyncToVblank; 758 } else 759 return BadMatch; 760 761 return Success; 762} 763 764static void 765I830QueryBestSize(ScrnInfoPtr scrn, 766 Bool motion, 767 short vid_w, short vid_h, 768 short drw_w, short drw_h, 769 unsigned int *p_w, unsigned int *p_h, pointer data) 770{ 771 if (vid_w > (drw_w << 1)) 772 drw_w = vid_w >> 1; 773 if (vid_h > (drw_h << 1)) 774 drw_h = vid_h >> 1; 775 776 *p_w = drw_w; 777 *p_h = drw_h; 778} 779 780static Bool 781I830CopyPackedData(intel_adaptor_private *adaptor_priv, 782 unsigned char *buf, 783 int srcPitch, int dstPitch, int top, int left, int h, int w) 784{ 785 unsigned char *src, *dst, *dst_base; 786 int i, j; 787 unsigned char *s; 788 789#if 0 790 ErrorF("I830CopyPackedData: (%d,%d) (%d,%d)\n" 791 "srcPitch: %d, dstPitch: %d\n", top, left, h, w, 792 srcPitch, dstPitch); 793#endif 794 795 src = buf + (top * srcPitch) + (left << 1); 796 797 if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf)) 798 return FALSE; 799 800 dst_base = adaptor_priv->buf->virtual; 801 802 dst = dst_base + adaptor_priv->YBufOffset; 803 804 switch (adaptor_priv->rotation) { 805 case RR_Rotate_0: 806 w <<= 1; 807 for (i = 0; i < h; i++) { 808 memcpy(dst, src, w); 809 src += srcPitch; 810 dst += dstPitch; 811 } 812 break; 813 case RR_Rotate_90: 814 h <<= 1; 815 for (i = 0; i < h; i += 2) { 816 s = src; 817 for (j = 0; j < w; j++) { 818 /* Copy Y */ 819 dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++; 820 (void)*s++; 821 } 822 src += srcPitch; 823 } 824 h >>= 1; 825 src = buf + (top * srcPitch) + (left << 1); 826 for (i = 0; i < h; i += 2) { 827 for (j = 0; j < w; j += 2) { 828 /* Copy U */ 829 dst[((i * 2) + 1) + ((w - j - 1) * dstPitch)] = 830 src[(j * 2) + 1 + (i * srcPitch)]; 831 dst[((i * 2) + 1) + ((w - j - 2) * dstPitch)] = 832 src[(j * 2) + 1 + ((i + 1) * srcPitch)]; 833 /* Copy V */ 834 dst[((i * 2) + 3) + ((w - j - 1) * dstPitch)] = 835 src[(j * 2) + 3 + (i * srcPitch)]; 836 dst[((i * 2) + 3) + ((w - j - 2) * dstPitch)] = 837 src[(j * 2) + 3 + ((i + 1) * srcPitch)]; 838 } 839 } 840 break; 841 case RR_Rotate_180: 842 w <<= 1; 843 for (i = 0; i < h; i++) { 844 s = src; 845 for (j = 0; j < w; j += 4) { 846 dst[(w - j - 4) + ((h - i - 1) * dstPitch)] = 847 *s++; 848 dst[(w - j - 3) + ((h - i - 1) * dstPitch)] = 849 *s++; 850 dst[(w - j - 2) + ((h - i - 1) * dstPitch)] = 851 *s++; 852 dst[(w - j - 1) + ((h - i - 1) * dstPitch)] = 853 *s++; 854 } 855 src += srcPitch; 856 } 857 break; 858 case RR_Rotate_270: 859 h <<= 1; 860 for (i = 0; i < h; i += 2) { 861 s = src; 862 for (j = 0; j < w; j++) { 863 /* Copy Y */ 864 dst[(h - i - 2) + (j * dstPitch)] = *s++; 865 (void)*s++; 866 } 867 src += srcPitch; 868 } 869 h >>= 1; 870 src = buf + (top * srcPitch) + (left << 1); 871 for (i = 0; i < h; i += 2) { 872 for (j = 0; j < w; j += 2) { 873 /* Copy U */ 874 dst[(((h - i) * 2) - 3) + (j * dstPitch)] = 875 src[(j * 2) + 1 + (i * srcPitch)]; 876 dst[(((h - i) * 2) - 3) + 877 ((j + 1) * dstPitch)] = 878 src[(j * 2) + 1 + ((i + 1) * srcPitch)]; 879 /* Copy V */ 880 dst[(((h - i) * 2) - 1) + (j * dstPitch)] = 881 src[(j * 2) + 3 + (i * srcPitch)]; 882 dst[(((h - i) * 2) - 1) + 883 ((j + 1) * dstPitch)] = 884 src[(j * 2) + 3 + ((i + 1) * srcPitch)]; 885 } 886 } 887 break; 888 } 889 890 drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf); 891 return TRUE; 892} 893 894static void intel_memcpy_plane(unsigned char *dst, unsigned char *src, 895 int height, int width, 896 int dstPitch, int srcPitch, Rotation rotation) 897{ 898 int i, j = 0; 899 unsigned char *s; 900 901 switch (rotation) { 902 case RR_Rotate_0: 903 /* optimise for the case of no clipping */ 904 if (srcPitch == dstPitch && srcPitch == width) 905 memcpy(dst, src, srcPitch * height); 906 else 907 for (i = 0; i < height; i++) { 908 memcpy(dst, src, width); 909 src += srcPitch; 910 dst += dstPitch; 911 } 912 break; 913 case RR_Rotate_90: 914 for (i = 0; i < height; i++) { 915 s = src; 916 for (j = 0; j < width; j++) { 917 dst[(i) + ((width - j - 1) * dstPitch)] = *s++; 918 } 919 src += srcPitch; 920 } 921 break; 922 case RR_Rotate_180: 923 for (i = 0; i < height; i++) { 924 s = src; 925 for (j = 0; j < width; j++) { 926 dst[(width - j - 1) + 927 ((height - i - 1) * dstPitch)] = *s++; 928 } 929 src += srcPitch; 930 } 931 break; 932 case RR_Rotate_270: 933 for (i = 0; i < height; i++) { 934 s = src; 935 for (j = 0; j < width; j++) { 936 dst[(height - i - 1) + (j * dstPitch)] = *s++; 937 } 938 src += srcPitch; 939 } 940 break; 941 } 942} 943 944static Bool 945I830CopyPlanarData(intel_adaptor_private *adaptor_priv, 946 unsigned char *buf, int srcPitch, int srcPitch2, 947 int dstPitch, int dstPitch2, 948 int srcH, int top, int left, 949 int h, int w, int id) 950{ 951 unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3; 952 953#if 0 954 ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n" 955 "nlines %d, npixels %d, top %d, left %d\n", 956 srcPitch, srcPitch2, dstPitch, h, w, top, left); 957#endif 958 959 /* Copy Y data */ 960 src1 = buf + (top * srcPitch) + left; 961#if 0 962 ErrorF("src1 is %p, offset is %ld\n", src1, 963 (unsigned long)src1 - (unsigned long)buf); 964#endif 965 966 if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf)) 967 return FALSE; 968 969 dst_base = adaptor_priv->buf->virtual; 970 971 dst1 = dst_base + adaptor_priv->YBufOffset; 972 973 intel_memcpy_plane(dst1, src1, h, w, dstPitch2, srcPitch, 974 adaptor_priv->rotation); 975 976 /* Copy V data for YV12, or U data for I420 */ 977 src2 = buf + /* start of YUV data */ 978 (srcH * srcPitch) + /* move over Luma plane */ 979 ((top >> 1) * srcPitch2) + /* move down from by top lines */ 980 (left >> 1); /* move left by left pixels */ 981 982#if 0 983 ErrorF("src2 is %p, offset is %ld\n", src2, 984 (unsigned long)src2 - (unsigned long)buf); 985#endif 986 if (id == FOURCC_I420) 987 dst2 = dst_base + adaptor_priv->UBufOffset; 988 else 989 dst2 = dst_base + adaptor_priv->VBufOffset; 990 991 intel_memcpy_plane(dst2, src2, h / 2, w / 2, 992 dstPitch, srcPitch2, adaptor_priv->rotation); 993 994 /* Copy U data for YV12, or V data for I420 */ 995 src3 = buf + /* start of YUV data */ 996 (srcH * srcPitch) + /* move over Luma plane */ 997 ((srcH >> 1) * srcPitch2) + /* move over Chroma plane */ 998 ((top >> 1) * srcPitch2) + /* move down from by top lines */ 999 (left >> 1); /* move left by left pixels */ 1000#if 0 1001 ErrorF("src3 is %p, offset is %ld\n", src3, 1002 (unsigned long)src3 - (unsigned long)buf); 1003#endif 1004 if (id == FOURCC_I420) 1005 dst3 = dst_base + adaptor_priv->VBufOffset; 1006 else 1007 dst3 = dst_base + adaptor_priv->UBufOffset; 1008 1009 intel_memcpy_plane(dst3, src3, h / 2, w / 2, 1010 dstPitch, srcPitch2, adaptor_priv->rotation); 1011 1012 drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf); 1013 return TRUE; 1014} 1015 1016static void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 1017{ 1018 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 1019 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 1020 if (dest->x1 >= dest->x2) { 1021 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 1022 return; 1023 } 1024 1025 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 1026 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 1027 if (dest->y1 >= dest->y2) 1028 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 1029} 1030 1031static void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 1032{ 1033 if (crtc->enabled) { 1034 crtc_box->x1 = crtc->x; 1035 crtc_box->x2 = 1036 crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 1037 crtc_box->y1 = crtc->y; 1038 crtc_box->y2 = 1039 crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 1040 } else 1041 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 1042} 1043 1044static int intel_box_area(BoxPtr box) 1045{ 1046 return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); 1047} 1048 1049/* 1050 * Return the crtc covering 'box'. If two crtcs cover a portion of 1051 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 1052 * with greater coverage 1053 */ 1054 1055xf86CrtcPtr 1056intel_covering_crtc(ScrnInfoPtr scrn, 1057 BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) 1058{ 1059 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1060 xf86CrtcPtr crtc, best_crtc; 1061 int coverage, best_coverage; 1062 int c; 1063 BoxRec crtc_box, cover_box; 1064 1065 best_crtc = NULL; 1066 best_coverage = 0; 1067 crtc_box_ret->x1 = 0; 1068 crtc_box_ret->x2 = 0; 1069 crtc_box_ret->y1 = 0; 1070 crtc_box_ret->y2 = 0; 1071 for (c = 0; c < xf86_config->num_crtc; c++) { 1072 crtc = xf86_config->crtc[c]; 1073 1074 /* If the CRTC is off, treat it as not covering */ 1075 if (!intel_crtc_on(crtc)) 1076 continue; 1077 1078 intel_crtc_box(crtc, &crtc_box); 1079 intel_box_intersect(&cover_box, &crtc_box, box); 1080 coverage = intel_box_area(&cover_box); 1081 if (coverage && crtc == desired) { 1082 *crtc_box_ret = crtc_box; 1083 return crtc; 1084 } 1085 if (coverage > best_coverage) { 1086 *crtc_box_ret = crtc_box; 1087 best_crtc = crtc; 1088 best_coverage = coverage; 1089 } 1090 } 1091 return best_crtc; 1092} 1093 1094static void 1095intel_update_dst_box_to_crtc_coords(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 1096 BoxPtr dstBox) 1097{ 1098 int tmp; 1099 1100 /* for overlay, we should take it from crtc's screen 1101 * coordinate to current crtc's display mode. 1102 * yeah, a bit confusing. 1103 */ 1104 switch (crtc->rotation & 0xf) { 1105 case RR_Rotate_0: 1106 dstBox->x1 -= crtc->x; 1107 dstBox->x2 -= crtc->x; 1108 dstBox->y1 -= crtc->y; 1109 dstBox->y2 -= crtc->y; 1110 break; 1111 case RR_Rotate_90: 1112 tmp = dstBox->x1; 1113 dstBox->x1 = dstBox->y1 - crtc->x; 1114 dstBox->y1 = scrn->virtualX - tmp - crtc->y; 1115 tmp = dstBox->x2; 1116 dstBox->x2 = dstBox->y2 - crtc->x; 1117 dstBox->y2 = scrn->virtualX - tmp - crtc->y; 1118 tmp = dstBox->y1; 1119 dstBox->y1 = dstBox->y2; 1120 dstBox->y2 = tmp; 1121 break; 1122 case RR_Rotate_180: 1123 tmp = dstBox->x1; 1124 dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x; 1125 dstBox->x2 = scrn->virtualX - tmp - crtc->x; 1126 tmp = dstBox->y1; 1127 dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y; 1128 dstBox->y2 = scrn->virtualY - tmp - crtc->y; 1129 break; 1130 case RR_Rotate_270: 1131 tmp = dstBox->x1; 1132 dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x; 1133 dstBox->y1 = tmp - crtc->y; 1134 tmp = dstBox->x2; 1135 dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x; 1136 dstBox->y2 = tmp - crtc->y; 1137 tmp = dstBox->x1; 1138 dstBox->x1 = dstBox->x2; 1139 dstBox->x2 = tmp; 1140 break; 1141 } 1142 1143 return; 1144} 1145 1146int is_planar_fourcc(int id) 1147{ 1148 switch (id) { 1149 case FOURCC_YV12: 1150 case FOURCC_I420: 1151#ifdef INTEL_XVMC 1152 case FOURCC_XVMC: 1153#endif 1154 return 1; 1155 case FOURCC_UYVY: 1156 case FOURCC_YUY2: 1157 return 0; 1158 default: 1159 ErrorF("Unknown format 0x%x\n", id); 1160 return 0; 1161 } 1162} 1163 1164static int xvmc_passthrough(int id) 1165{ 1166#ifdef INTEL_XVMC 1167 return id == FOURCC_XVMC; 1168#else 1169 return 0; 1170#endif 1171} 1172 1173static Bool 1174intel_display_overlay(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 1175 int id, short width, short height, 1176 int dstPitch, int dstPitch2, 1177 BoxPtr dstBox, short src_w, short src_h, short drw_w, 1178 short drw_h) 1179{ 1180 intel_screen_private *intel = intel_get_screen_private(scrn); 1181 int tmp; 1182 1183 OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height, 1184 dstPitch); 1185 1186 /* 1187 * If the video isn't visible on any CRTC, turn it off 1188 */ 1189 if (!crtc) { 1190 intel_overlay_off(intel); 1191 return TRUE; 1192 } 1193 1194 intel_update_dst_box_to_crtc_coords(scrn, crtc, dstBox); 1195 1196 if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 1197 tmp = width; 1198 width = height; 1199 height = tmp; 1200 tmp = drw_w; 1201 drw_w = drw_h; 1202 drw_h = tmp; 1203 tmp = src_w; 1204 src_w = src_h; 1205 src_h = tmp; 1206 } 1207 1208 return intel_overlay_put_image(intel, crtc, id, 1209 width, height, 1210 dstPitch, dstPitch2, dstBox, 1211 src_w, src_h, drw_w, drw_h); 1212} 1213 1214static Bool 1215intel_clip_video_helper(ScrnInfoPtr scrn, 1216 intel_adaptor_private *adaptor_priv, 1217 xf86CrtcPtr * crtc_ret, 1218 BoxPtr dst, 1219 short src_x, short src_y, 1220 short drw_x, short drw_y, 1221 short src_w, short src_h, 1222 short drw_w, short drw_h, 1223 int id, 1224 int *top, int* left, int* npixels, int *nlines, 1225 RegionPtr reg, INT32 width, INT32 height) 1226{ 1227 Bool ret; 1228 RegionRec crtc_region_local; 1229 RegionPtr crtc_region = reg; 1230 BoxRec crtc_box; 1231 INT32 x1, x2, y1, y2; 1232 xf86CrtcPtr crtc; 1233 1234 x1 = src_x; 1235 x2 = src_x + src_w; 1236 y1 = src_y; 1237 y2 = src_y + src_h; 1238 1239 dst->x1 = drw_x; 1240 dst->x2 = drw_x + drw_w; 1241 dst->y1 = drw_y; 1242 dst->y2 = drw_y + drw_h; 1243 1244 /* 1245 * For overlay video, compute the relevant CRTC and 1246 * clip video to that 1247 */ 1248 crtc = intel_covering_crtc(scrn, dst, adaptor_priv->desired_crtc, 1249 &crtc_box); 1250 1251 /* For textured video, we don't actually want to clip at all. */ 1252 if (crtc && !adaptor_priv->textured) { 1253 REGION_INIT(screen, &crtc_region_local, &crtc_box, 1); 1254 crtc_region = &crtc_region_local; 1255 REGION_INTERSECT(screen, crtc_region, crtc_region, 1256 reg); 1257 } 1258 *crtc_ret = crtc; 1259 1260 ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2, 1261 crtc_region, width, height); 1262 if (crtc_region != reg) 1263 REGION_UNINIT(screen, &crtc_region_local); 1264 1265 *top = y1 >> 16; 1266 *left = (x1 >> 16) & ~1; 1267 *npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - *left; 1268 if (is_planar_fourcc(id)) { 1269 *top &= ~1; 1270 *nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - *top; 1271 } else 1272 *nlines = ((y2 + 0xffff) >> 16) - *top; 1273 1274 return ret; 1275} 1276 1277static void 1278intel_wait_for_scanline(ScrnInfoPtr scrn, PixmapPtr pixmap, 1279 xf86CrtcPtr crtc, RegionPtr clipBoxes) 1280{ 1281 intel_screen_private *intel = intel_get_screen_private(scrn); 1282 pixman_box16_t box, crtc_box; 1283 int pipe, event; 1284 Bool full_height; 1285 int y1, y2; 1286 1287 pipe = -1; 1288 if (scrn->vtSema && pixmap_is_scanout(pixmap)) 1289 pipe = intel_crtc_to_pipe(crtc); 1290 if (pipe < 0) 1291 return; 1292 1293 box = *REGION_EXTENTS(unused, clipBoxes); 1294 1295 if (crtc->transform_in_use) 1296 pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box); 1297 1298 /* We could presume the clip was correctly computed... */ 1299 intel_crtc_box(crtc, &crtc_box); 1300 intel_box_intersect(&box, &crtc_box, &box); 1301 1302 /* 1303 * Make sure we don't wait for a scanline that will 1304 * never occur 1305 */ 1306 y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0; 1307 y2 = (box.y2 <= crtc_box.y2) ? 1308 box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1; 1309 if (y2 <= y1) 1310 return; 1311 1312 full_height = FALSE; 1313 if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1)) 1314 full_height = TRUE; 1315 1316 /* 1317 * Pre-965 doesn't have SVBLANK, so we need a bit 1318 * of extra time for the blitter to start up and 1319 * do its job for a full height blit 1320 */ 1321 if (full_height && INTEL_INFO(intel)->gen < 040) 1322 y2 -= 2; 1323 1324 if (pipe == 0) { 1325 pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 1326 event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 1327 if (full_height && INTEL_INFO(intel)->gen >= 040) 1328 event = MI_WAIT_FOR_PIPEA_SVBLANK; 1329 } else { 1330 pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 1331 event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 1332 if (full_height && INTEL_INFO(intel)->gen >= 040) 1333 event = MI_WAIT_FOR_PIPEB_SVBLANK; 1334 } 1335 1336 if (crtc->mode.Flags & V_INTERLACE) { 1337 /* DSL count field lines */ 1338 y1 /= 2; 1339 y2 /= 2; 1340 } 1341 1342 BEGIN_BATCH(5); 1343 /* The documentation says that the LOAD_SCAN_LINES command 1344 * always comes in pairs. Don't ask me why. */ 1345 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); 1346 OUT_BATCH((y1 << 16) | (y2-1)); 1347 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); 1348 OUT_BATCH((y1 << 16) | (y2-1)); 1349 OUT_BATCH(MI_WAIT_FOR_EVENT | event); 1350 ADVANCE_BATCH(); 1351} 1352 1353static Bool 1354intel_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, 1355 int alloc_size, int id, unsigned char *buf) 1356{ 1357 intel_screen_private *intel = intel_get_screen_private(scrn); 1358 1359 /* Free the current buffer if we're going to have to reallocate */ 1360 if (adaptor_priv->buf && adaptor_priv->buf->size < alloc_size) 1361 intel_free_video_buffers(adaptor_priv); 1362 1363 if (adaptor_priv->buf == NULL) { 1364 adaptor_priv->buf = drm_intel_bo_alloc(intel->bufmgr, "xv buffer", 1365 alloc_size, 4096); 1366 if (adaptor_priv->buf == NULL) 1367 return FALSE; 1368 1369 adaptor_priv->reusable = TRUE; 1370 } 1371 1372 return TRUE; 1373} 1374 1375static void 1376intel_setup_dst_params(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, short width, 1377 short height, int *dstPitch, int *dstPitch2, int *size, 1378 int id) 1379{ 1380 intel_screen_private *intel = intel_get_screen_private(scrn); 1381 int pitchAlign; 1382 1383 /* Only needs to be DWORD-aligned for textured on i915, but overlay has 1384 * stricter requirements. 1385 */ 1386 if (adaptor_priv->textured) { 1387 pitchAlign = 4; 1388 } else { 1389 if (INTEL_INFO(intel)->gen >= 040) 1390 /* Actually the alignment is 64 bytes, too. But the 1391 * stride must be at least 512 bytes. Take the easy fix 1392 * and align on 512 bytes unconditionally. */ 1393 pitchAlign = 512; 1394 else if (IS_I830(intel) || IS_845G(intel)) 1395 /* Harsh, errata on these chipsets limit the stride to be 1396 * a multiple of 256 bytes. 1397 */ 1398 pitchAlign = 256; 1399 else 1400 pitchAlign = 64; 1401 } 1402 1403#if INTEL_XVMC 1404 /* for i915 xvmc, hw requires 1kb aligned surfaces */ 1405 if ((id == FOURCC_XVMC) && IS_GEN3(intel)) 1406 pitchAlign = 1024; 1407#endif 1408 1409 /* Determine the desired destination pitch (representing the chroma's pitch, 1410 * in the planar case. 1411 */ 1412 if (is_planar_fourcc(id)) { 1413 if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 1414 *dstPitch = ALIGN((height / 2), pitchAlign); 1415 *dstPitch2 = ALIGN(height, pitchAlign); 1416 *size = *dstPitch * width * 3; 1417 } else { 1418 *dstPitch = ALIGN((width / 2), pitchAlign); 1419 *dstPitch2 = ALIGN(width, pitchAlign); 1420 *size = *dstPitch * height * 3; 1421 } 1422 } else { 1423 if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 1424 *dstPitch = ALIGN((height << 1), pitchAlign); 1425 *size = *dstPitch * width; 1426 } else { 1427 *dstPitch = ALIGN((width << 1), pitchAlign); 1428 *size = *dstPitch * height; 1429 } 1430 *dstPitch2 = 0; 1431 } 1432#if 0 1433 ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, *dstPitch, 1434 size); 1435#endif 1436 1437 adaptor_priv->YBufOffset = 0; 1438 1439 if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 1440 adaptor_priv->UBufOffset = 1441 adaptor_priv->YBufOffset + (*dstPitch2 * width); 1442 adaptor_priv->VBufOffset = 1443 adaptor_priv->UBufOffset + (*dstPitch * width / 2); 1444 } else { 1445 adaptor_priv->UBufOffset = 1446 adaptor_priv->YBufOffset + (*dstPitch2 * height); 1447 adaptor_priv->VBufOffset = 1448 adaptor_priv->UBufOffset + (*dstPitch * height / 2); 1449 } 1450} 1451 1452static Bool 1453intel_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, 1454 short width, short height, int *dstPitch, int *dstPitch2, 1455 int top, int left, int npixels, int nlines, 1456 int id, unsigned char *buf) 1457{ 1458 int srcPitch = 0, srcPitch2 = 0; 1459 int size; 1460 1461 if (is_planar_fourcc(id)) { 1462 srcPitch = ALIGN(width, 0x4); 1463 srcPitch2 = ALIGN((width >> 1), 0x4); 1464 } else { 1465 srcPitch = width << 1; 1466 } 1467 1468 intel_setup_dst_params(scrn, adaptor_priv, width, height, dstPitch, 1469 dstPitch2, &size, id); 1470 1471 if (!intel_setup_video_buffer(scrn, adaptor_priv, size, id, buf)) 1472 return FALSE; 1473 1474 /* copy data */ 1475 if (is_planar_fourcc(id)) { 1476 return I830CopyPlanarData(adaptor_priv, buf, srcPitch, srcPitch2, 1477 *dstPitch, *dstPitch2, 1478 height, top, left, nlines, 1479 npixels, id); 1480 } else { 1481 return I830CopyPackedData(adaptor_priv, buf, srcPitch, *dstPitch, top, left, 1482 nlines, npixels); 1483 } 1484} 1485 1486/* 1487 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). 1488 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). 1489 * id is a fourcc code for the format of the video. 1490 * buf is the pointer to the source data in system memory. 1491 * width and height are the w/h of the source data. 1492 * If "sync" is TRUE, then we must be finished with *buf at the point of return 1493 * (which we always are). 1494 * clipBoxes is the clipping region in screen space. 1495 * data is a pointer to our port private. 1496 * drawable is some Drawable, which might not be the screen in the case of 1497 * compositing. It's a new argument to the function in the 1.1 server. 1498 */ 1499static int 1500I830PutImageTextured(ScrnInfoPtr scrn, 1501 short src_x, short src_y, 1502 short drw_x, short drw_y, 1503 short src_w, short src_h, 1504 short drw_w, short drw_h, 1505 int id, unsigned char *buf, 1506 short width, short height, 1507 Bool sync, RegionPtr clipBoxes, pointer data, 1508 DrawablePtr drawable) 1509{ 1510 intel_screen_private *intel = intel_get_screen_private(scrn); 1511 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 1512 PixmapPtr pixmap = get_drawable_pixmap(drawable); 1513 int dstPitch, dstPitch2; 1514 BoxRec dstBox; 1515 xf86CrtcPtr crtc; 1516 int top, left, npixels, nlines; 1517 1518 if (!intel_pixmap_is_offscreen(pixmap)) 1519 return BadAlloc; 1520 1521#if 0 1522 ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" 1523 "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, 1524 drw_y, drw_w, drw_h, width, height); 1525#endif 1526 1527 if (!intel_clip_video_helper(scrn, 1528 adaptor_priv, 1529 &crtc, 1530 &dstBox, 1531 src_x, src_y, drw_x, drw_y, 1532 src_w, src_h, drw_w, drw_h, 1533 id, 1534 &top, &left, &npixels, &nlines, clipBoxes, 1535 width, height)) 1536 return Success; 1537 1538 if (xvmc_passthrough(id)) { 1539 uint32_t *gem_handle = (uint32_t *)buf; 1540 int size; 1541 1542 intel_setup_dst_params(scrn, adaptor_priv, width, height, 1543 &dstPitch, &dstPitch2, &size, id); 1544 1545 if (IS_I915G(intel) || IS_I915GM(intel)) { 1546 /* XXX: i915 is not support and needs some 1547 * serious care. grep for KMS in i915_hwmc.c */ 1548 return BadAlloc; 1549 } 1550 1551 if (adaptor_priv->buf) 1552 drm_intel_bo_unreference(adaptor_priv->buf); 1553 1554 adaptor_priv->buf = 1555 drm_intel_bo_gem_create_from_name(intel->bufmgr, 1556 "xvmc surface", 1557 *gem_handle); 1558 if (adaptor_priv->buf == NULL) 1559 return BadAlloc; 1560 1561 adaptor_priv->reusable = FALSE; 1562 } else { 1563 if (!intel_copy_video_data(scrn, adaptor_priv, width, height, 1564 &dstPitch, &dstPitch2, 1565 top, left, npixels, nlines, id, buf)) 1566 return BadAlloc; 1567 } 1568 1569 if (crtc && adaptor_priv->SyncToVblank != 0 && INTEL_INFO(intel)->gen < 060) { 1570 intel_wait_for_scanline(scrn, pixmap, crtc, clipBoxes); 1571 } 1572 1573 if (INTEL_INFO(intel)->gen >= 060) { 1574 Gen6DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 1575 width, height, dstPitch, dstPitch2, 1576 src_w, src_h, 1577 drw_w, drw_h, pixmap); 1578 } else if (INTEL_INFO(intel)->gen >= 040) { 1579 I965DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 1580 width, height, dstPitch, dstPitch2, 1581 src_w, src_h, 1582 drw_w, drw_h, pixmap); 1583 } else { 1584 I915DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 1585 width, height, dstPitch, dstPitch2, 1586 src_w, src_h, drw_w, drw_h, 1587 pixmap); 1588 } 1589 1590 intel_get_screen_private(scrn)->needs_flush = TRUE; 1591 DamageDamageRegion(drawable, clipBoxes); 1592 1593 /* And make sure the WAIT_FOR_EVENT is queued before any 1594 * modesetting/dpms operations on the pipe. 1595 */ 1596 intel_batch_submit(scrn); 1597 1598 return Success; 1599} 1600 1601static int 1602I830PutImageOverlay(ScrnInfoPtr scrn, 1603 short src_x, short src_y, 1604 short drw_x, short drw_y, 1605 short src_w, short src_h, 1606 short drw_w, short drw_h, 1607 int id, unsigned char *buf, 1608 short width, short height, 1609 Bool sync, RegionPtr clipBoxes, pointer data, 1610 DrawablePtr drawable) 1611{ 1612 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 1613 int dstPitch, dstPitch2; 1614 BoxRec dstBox; 1615 xf86CrtcPtr crtc; 1616 int top, left, npixels, nlines; 1617 1618#if 0 1619 ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" 1620 "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, 1621 drw_y, drw_w, drw_h, width, height); 1622#endif 1623 1624 /* If dst width and height are less than 1/8th the src size, the 1625 * src/dst scale factor becomes larger than 8 and doesn't fit in 1626 * the scale register. */ 1627 if (src_w >= (drw_w * 8)) 1628 drw_w = src_w / 7; 1629 1630 if (src_h >= (drw_h * 8)) 1631 drw_h = src_h / 7; 1632 1633 if (!intel_clip_video_helper(scrn, 1634 adaptor_priv, 1635 &crtc, 1636 &dstBox, 1637 src_x, src_y, drw_x, drw_y, 1638 src_w, src_h, drw_w, drw_h, 1639 id, 1640 &top, &left, &npixels, &nlines, clipBoxes, 1641 width, height)) 1642 return Success; 1643 1644 /* overlay can't handle rotation natively, store it for the copy func */ 1645 if (crtc) 1646 adaptor_priv->rotation = crtc->rotation; 1647 else { 1648 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1649 "Fail to clip video to any crtc!\n"); 1650 return Success; 1651 } 1652 1653 if (!intel_copy_video_data(scrn, adaptor_priv, width, height, 1654 &dstPitch, &dstPitch2, 1655 top, left, npixels, nlines, id, buf)) 1656 return BadAlloc; 1657 1658 if (!intel_display_overlay 1659 (scrn, crtc, id, width, height, dstPitch, dstPitch2, 1660 &dstBox, src_w, src_h, drw_w, drw_h)) 1661 return BadAlloc; 1662 1663 /* update cliplist */ 1664 if (!REGION_EQUAL(scrn->pScreen, &adaptor_priv->clip, clipBoxes)) { 1665 REGION_COPY(scrn->pScreen, &adaptor_priv->clip, clipBoxes); 1666 xf86XVFillKeyHelperDrawable(drawable, 1667 adaptor_priv->colorKey, 1668 clipBoxes); 1669 } 1670 1671 adaptor_priv->videoStatus = CLIENT_VIDEO_ON; 1672 1673 return Success; 1674} 1675 1676static int 1677I830QueryImageAttributes(ScrnInfoPtr scrn, 1678 int id, 1679 unsigned short *w, unsigned short *h, 1680 int *pitches, int *offsets) 1681{ 1682 intel_screen_private *intel = intel_get_screen_private(scrn); 1683 int size, tmp; 1684 1685#if 0 1686 ErrorF("I830QueryImageAttributes: w is %d, h is %d\n", *w, *h); 1687#endif 1688 1689 if (IS_845G(intel) || IS_I830(intel)) { 1690 if (*w > IMAGE_MAX_WIDTH_LEGACY) 1691 *w = IMAGE_MAX_WIDTH_LEGACY; 1692 if (*h > IMAGE_MAX_HEIGHT_LEGACY) 1693 *h = IMAGE_MAX_HEIGHT_LEGACY; 1694 } else { 1695 if (*w > IMAGE_MAX_WIDTH) 1696 *w = IMAGE_MAX_WIDTH; 1697 if (*h > IMAGE_MAX_HEIGHT) 1698 *h = IMAGE_MAX_HEIGHT; 1699 } 1700 1701 *w = (*w + 1) & ~1; 1702 if (offsets) 1703 offsets[0] = 0; 1704 1705 switch (id) { 1706 /* IA44 is for XvMC only */ 1707 case FOURCC_IA44: 1708 case FOURCC_AI44: 1709 if (pitches) 1710 pitches[0] = *w; 1711 size = *w * *h; 1712 break; 1713 case FOURCC_YV12: 1714 case FOURCC_I420: 1715 *h = (*h + 1) & ~1; 1716 size = (*w + 3) & ~3; 1717 if (pitches) 1718 pitches[0] = size; 1719 size *= *h; 1720 if (offsets) 1721 offsets[1] = size; 1722 tmp = ((*w >> 1) + 3) & ~3; 1723 if (pitches) 1724 pitches[1] = pitches[2] = tmp; 1725 tmp *= (*h >> 1); 1726 size += tmp; 1727 if (offsets) 1728 offsets[2] = size; 1729 size += tmp; 1730#if 0 1731 if (pitches) 1732 ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", 1733 pitches[0], pitches[1], pitches[2]); 1734 if (offsets) 1735 ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], 1736 offsets[2]); 1737 if (offsets) 1738 ErrorF("size is %d\n", size); 1739#endif 1740 break; 1741#ifdef INTEL_XVMC 1742 case FOURCC_XVMC: 1743 *h = (*h + 1) & ~1; 1744 size = sizeof(struct intel_xvmc_command); 1745 if (pitches) 1746 pitches[0] = size; 1747 break; 1748#endif 1749 case FOURCC_UYVY: 1750 case FOURCC_YUY2: 1751 default: 1752 size = *w << 1; 1753 if (pitches) 1754 pitches[0] = size; 1755 size *= *h; 1756 break; 1757 } 1758 1759 return size; 1760} 1761 1762void 1763intel_video_block_handler(intel_screen_private *intel) 1764{ 1765 intel_adaptor_private *adaptor_priv; 1766 1767 /* no overlay */ 1768 if (intel->adaptor == NULL) 1769 return; 1770 1771 adaptor_priv = intel_get_adaptor_private(intel); 1772 if (adaptor_priv->videoStatus & OFF_TIMER) { 1773 Time now = currentTime.milliseconds; 1774 if (adaptor_priv->offTime < now) { 1775 /* Turn off the overlay */ 1776 intel_overlay_off(intel); 1777 intel_free_video_buffers(adaptor_priv); 1778 adaptor_priv->videoStatus = 0; 1779 } 1780 } 1781} 1782