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