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 57#include "xf86.h" 58#include "xf86_OSproc.h" 59#include "compiler.h" 60#include "xf86PciInfo.h" 61#include "xf86Pci.h" 62#include "xf86fbman.h" 63#include "regionstr.h" 64#include "randrstr.h" 65#include "windowstr.h" 66#include "damage.h" 67#include "i830.h" 68#include "i830_video.h" 69#include "xf86xv.h" 70#include <X11/extensions/Xv.h> 71#include "dixstruct.h" 72#include "fourcc.h" 73 74#ifdef INTEL_XVMC 75#define _INTEL_XVMC_SERVER_ 76#include "i830_hwmc.h" 77#include "i915_hwmc.h" 78#endif 79 80#define OFF_DELAY 250 /* milliseconds */ 81#define FREE_DELAY 15000 82 83#define OFF_TIMER 0x01 84#define FREE_TIMER 0x02 85#define CLIENT_VIDEO_ON 0x04 86 87#define TIMER_MASK (OFF_TIMER | FREE_TIMER) 88 89static void I830InitOffscreenImages(ScreenPtr); 90 91static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr); 92static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr); 93static void I830StopVideo(ScrnInfoPtr, pointer, Bool); 94static int I830SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); 95static int I830SetPortAttributeTextured(ScrnInfoPtr, Atom, INT32, pointer); 96static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer); 97static void I830QueryBestSize(ScrnInfoPtr, Bool, 98 short, short, short, short, unsigned int *, 99 unsigned int *, pointer); 100static int I830PutImage(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, xvDoubleBuffer; 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/* 130 * OCMD - Overlay Command Register 131 */ 132#define OCMD_REGISTER 0x30168 133#define MIRROR_MODE (0x3<<17) 134#define MIRROR_HORIZONTAL (0x1<<17) 135#define MIRROR_VERTICAL (0x2<<17) 136#define MIRROR_BOTH (0x3<<17) 137#define OV_BYTE_ORDER (0x3<<14) 138#define UV_SWAP (0x1<<14) 139#define Y_SWAP (0x2<<14) 140#define Y_AND_UV_SWAP (0x3<<14) 141#define SOURCE_FORMAT (0xf<<10) 142#define RGB_888 (0x1<<10) 143#define RGB_555 (0x2<<10) 144#define RGB_565 (0x3<<10) 145#define YUV_422 (0x8<<10) 146#define YUV_411 (0x9<<10) 147#define YUV_420 (0xc<<10) 148#define YUV_422_PLANAR (0xd<<10) 149#define YUV_410 (0xe<<10) 150#define TVSYNC_FLIP_PARITY (0x1<<9) 151#define TVSYNC_FLIP_ENABLE (0x1<<7) 152#define BUF_TYPE (0x1<<5) 153#define BUF_TYPE_FRAME (0x0<<5) 154#define BUF_TYPE_FIELD (0x1<<5) 155#define TEST_MODE (0x1<<4) 156#define BUFFER_SELECT (0x3<<2) 157#define BUFFER0 (0x0<<2) 158#define BUFFER1 (0x1<<2) 159#define FIELD_SELECT (0x1<<1) 160#define FIELD0 (0x0<<1) 161#define FIELD1 (0x1<<1) 162#define OVERLAY_ENABLE 0x1 163 164#define OFC_UPDATE 0x1 165 166/* OCONFIG register */ 167#define CC_OUT_8BIT (0x1<<3) 168#define OVERLAY_PIPE_MASK (0x1<<18) 169#define OVERLAY_PIPE_A (0x0<<18) 170#define OVERLAY_PIPE_B (0x1<<18) 171#define GAMMA2_ENBL (0x1<<16) 172#define CSC_MODE_BT709 (0x1<<5) 173#define CSC_MODE_BT601 (0x0<<5) 174#define THREE_LINE_BUFFERS (0x1<<0) 175#define TWO_LINE_BUFFERS (0x0<<0) 176 177/* DCLRKM register */ 178#define DEST_KEY_ENABLE (0x1<<31) 179 180/* Polyphase filter coefficients */ 181#define N_HORIZ_Y_TAPS 5 182#define N_VERT_Y_TAPS 3 183#define N_HORIZ_UV_TAPS 3 184#define N_VERT_UV_TAPS 3 185#define N_PHASES 17 186#define MAX_TAPS 5 187 188/* Filter cutoff frequency limits. */ 189#define MIN_CUTOFF_FREQ 1.0 190#define MAX_CUTOFF_FREQ 3.0 191 192#define RGB16ToColorKey(c) \ 193(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3)) 194 195#define RGB15ToColorKey(c) \ 196(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3)) 197 198/* client libraries expect an encoding */ 199static XF86VideoEncodingRec DummyEncoding[1] = { 200 { 201 0, 202 "XV_IMAGE", 203 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, 204 {1, 1} 205 } 206}; 207 208#define NUM_FORMATS 3 209 210static XF86VideoFormatRec Formats[NUM_FORMATS] = { 211 {15, TrueColor}, {16, TrueColor}, {24, TrueColor} 212}; 213 214#define CLONE_ATTRIBUTES 1 215static XF86AttributeRec CloneAttributes[CLONE_ATTRIBUTES] = { 216 {XvSettable | XvGettable, -1, 1, "XV_PIPE"} 217}; 218 219#define NUM_ATTRIBUTES 5 220static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { 221 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, 222 {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, 223 {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}, 224 {XvSettable | XvGettable, 0, 1023, "XV_SATURATION"}, 225 {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"} 226}; 227 228#define NUM_TEXTURED_ATTRIBUTES 3 229static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = { 230 {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, 231 {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}, 232 {XvSettable | XvGettable, -1, 1, "XV_SYNC_TO_VBLANK"}, 233}; 234 235#define GAMMA_ATTRIBUTES 6 236static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = { 237 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"}, 238 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"}, 239 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"}, 240 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"}, 241 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"}, 242 {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"} 243}; 244 245#define NUM_IMAGES 5 246 247static XF86ImageRec Images[NUM_IMAGES] = { 248 XVIMAGE_YUY2, 249 XVIMAGE_YV12, 250 XVIMAGE_I420, 251 XVIMAGE_UYVY, 252#ifdef INTEL_XVMC 253 { 254 /* 255 * Below, a dummy picture type that is used in XvPutImage only to do 256 * an overlay update. Introduced for the XvMC client lib. 257 * Defined to have a zero data size. 258 */ 259 FOURCC_XVMC, 260 XvYUV, 261 LSBFirst, 262 {'X', 'V', 'M', 'C', 263 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00, 264 0x38, 0x9B, 0x71}, 265 12, 266 XvPlanar, 267 3, 268 0, 0, 0, 0, 269 8, 8, 8, 270 1, 2, 2, 271 1, 2, 2, 272 {'Y', 'V', 'U', 273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 275 XvTopToBottom 276 }, 277#endif 278}; 279 280typedef struct { 281 uint32_t OBUF_0Y; 282 uint32_t OBUF_1Y; 283 uint32_t OBUF_0U; 284 uint32_t OBUF_0V; 285 uint32_t OBUF_1U; 286 uint32_t OBUF_1V; 287 uint32_t OSTRIDE; 288 uint32_t YRGB_VPH; 289 uint32_t UV_VPH; 290 uint32_t HORZ_PH; 291 uint32_t INIT_PHS; 292 uint32_t DWINPOS; 293 uint32_t DWINSZ; 294 uint32_t SWIDTH; 295 uint32_t SWIDTHSW; 296 uint32_t SHEIGHT; 297 uint32_t YRGBSCALE; 298 uint32_t UVSCALE; 299 uint32_t OCLRC0; 300 uint32_t OCLRC1; 301 uint32_t DCLRKV; 302 uint32_t DCLRKM; 303 uint32_t SCLRKVH; 304 uint32_t SCLRKVL; 305 uint32_t SCLRKEN; 306 uint32_t OCONFIG; 307 uint32_t OCMD; 308 uint32_t RESERVED1; /* 0x6C */ 309 uint32_t OSTART_0Y; /* for i965 */ 310 uint32_t OSTART_1Y; /* for i965 */ 311 uint32_t OSTART_0U; 312 uint32_t OSTART_0V; 313 uint32_t OSTART_1U; 314 uint32_t OSTART_1V; 315 uint32_t OTILEOFF_0Y; 316 uint32_t OTILEOFF_1Y; 317 uint32_t OTILEOFF_0U; 318 uint32_t OTILEOFF_0V; 319 uint32_t OTILEOFF_1U; 320 uint32_t OTILEOFF_1V; 321 uint32_t FASTHSCALE; /* 0xA0 */ 322 uint32_t UVSCALEV; /* 0xA4 */ 323 324 uint32_t RESERVEDC[(0x200 - 0xA8) / 4]; /* 0xA8 - 0x1FC */ 325 uint16_t Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES]; /* 0x200 */ 326 uint16_t RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES]; 327 uint16_t Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES]; /* 0x300 */ 328 uint16_t RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES]; 329 uint16_t UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES]; /* 0x500 */ 330 uint16_t RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES]; 331 uint16_t UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES]; /* 0x600 */ 332 uint16_t RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES]; 333} I830OverlayRegRec, *I830OverlayRegPtr; 334 335#define I830OVERLAYREG(pI830) ((I830OverlayRegPtr)\ 336 ((pI830)->FbBase + \ 337 (pI830)->overlay_regs->offset)) 338#if VIDEO_DEBUG 339static void 340CompareOverlay(I830Ptr pI830, uint32_t * overlay, int size) 341{ 342 int i; 343 uint32_t val; 344 int bad = 0; 345 346 for (i = 0; i < size; i += 4) { 347 val = INREG(0x30100 + i); 348 if (val != overlay[i / 4]) { 349 OVERLAY_DEBUG("0x%05x value doesn't match (0x%lx != 0x%lx)\n", 350 0x30100 + i, val, overlay[i / 4]); 351 bad++; 352 } 353 } 354 if (!bad) 355 OVERLAY_DEBUG("CompareOverlay: no differences\n"); 356} 357#endif 358 359static void 360I830SetOneLineModeRatio(ScrnInfoPtr pScrn); 361 362static void 363i830_overlay_switch_to_crtc (ScrnInfoPtr pScrn, xf86CrtcPtr crtc) 364{ 365 I830Ptr pI830 = I830PTR(pScrn); 366 I830PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn); 367 I830CrtcPrivatePtr intel_crtc = crtc->driver_private; 368 int pipeconf_reg = intel_crtc->pipe == 0 ? PIPEACONF : PIPEBCONF; 369 370 /* overlay can't be used on pipe with double wide, and pipe must be enabled. */ 371 if ((!IS_I965G(pI830) && (INREG(pipeconf_reg) & PIPEACONF_DOUBLE_WIDE)) 372 || (intel_crtc->dpms_mode == DPMSModeOff)) 373 pPriv->overlayOK = FALSE; 374 else 375 pPriv->overlayOK = TRUE; 376 377 if (!pPriv->overlayOK) 378 return; 379 380 /* Check we have an LFP connected */ 381 if (i830PipeHasType(crtc, I830_OUTPUT_LVDS)) 382 { 383 384 int vtotal_reg = intel_crtc->pipe == 0 ? VTOTAL_A : VTOTAL_B; 385 uint32_t size = intel_crtc->pipe ? INREG(PIPEBSRC) : INREG(PIPEASRC); 386 uint32_t active; 387 uint32_t hsize, vsize; 388 389 hsize = (size >> 16) & 0x7FF; 390 vsize = size & 0x7FF; 391 active = INREG(vtotal_reg) & 0x7FF; 392 393 if (vsize < active && hsize > 1024) 394 I830SetOneLineModeRatio(pScrn); 395 396 if (pPriv->scaleRatio & 0xFFFE0000) 397 { 398 /* Possible bogus ratio, using in-accurate fallback */ 399 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 400 "Bogus panel fit register, Xvideo positioning may not " 401 "be accurate.\n"); 402 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 403 "Using fallback ratio - was 0x%x, now 0x%x\n", 404 pPriv->scaleRatio, 405 (int)(((float)active * 65536)/(float)vsize)); 406 407 pPriv->scaleRatio = (int)(((float)active * 65536) / (float)vsize); 408 } 409 } 410} 411 412/* 413 * This is more or less the correct way to initalise, update, and shut down 414 * the overlay. 415 * 416 * XXX Need to make sure that the overlay engine is cleanly shutdown in 417 * all modes of server exit. 418 */ 419 420static void 421i830_overlay_on(ScrnInfoPtr pScrn) 422{ 423 I830Ptr pI830 = I830PTR(pScrn); 424 I830OverlayRegPtr overlay = I830OVERLAYREG(pI830); 425 I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; 426 Bool deactivate = FALSE; 427 428 if (pI830->overlayOn) 429 return; 430 431 /* 432 * On I830, if pipe A is off when the overlayis enabled, it will fail to 433 * turn on and blank the entire screen or lock up the ring. Light up pipe 434 * A in this case to provide a clock for the overlay hardware 435 */ 436 if (pPriv->current_crtc && i830_crtc_pipe (pPriv->current_crtc) != 0) 437 deactivate = i830_pipe_a_require_activate (pScrn); 438 439 overlay->OCMD &= ~OVERLAY_ENABLE; 440 BEGIN_BATCH(6); 441 OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE); 442 OUT_BATCH(MI_NOOP); 443 OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_ON); 444 if (OVERLAY_NOPHYSICAL(pI830)) 445 OUT_BATCH(pI830->overlay_regs->offset | OFC_UPDATE); 446 else 447 OUT_BATCH(pI830->overlay_regs->bus_addr | OFC_UPDATE); 448 /* Wait for the overlay to light up before attempting to use it */ 449 OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 450 OUT_BATCH(MI_NOOP); 451 ADVANCE_BATCH(); 452 I830Sync(pScrn); 453 454 /* 455 * If we turned pipe A on up above, turn it 456 * back off 457 */ 458 if (deactivate) 459 i830_pipe_a_require_deactivate (pScrn); 460 461 OVERLAY_DEBUG("overlay_on\n"); 462 pI830->overlayOn = TRUE; 463 464 overlay->OCMD |= OVERLAY_ENABLE; 465} 466 467static void 468i830_overlay_continue(ScrnInfoPtr pScrn, Bool update_filter) 469{ 470 I830Ptr pI830 = I830PTR(pScrn); 471 uint32_t flip_addr; 472 I830OverlayRegPtr overlay = I830OVERLAYREG(pI830); 473 474 if (!pI830->overlayOn) 475 return; 476 477 if (OVERLAY_NOPHYSICAL(pI830)) 478 flip_addr = pI830->overlay_regs->offset; 479 else 480 flip_addr = pI830->overlay_regs->bus_addr; 481 if (update_filter) 482 flip_addr |= OFC_UPDATE; 483 OVERLAY_DEBUG ("overlay_continue cmd 0x%08x -> 0x%08x sta 0x%08x\n", 484 overlay->OCMD, INREG(OCMD_REGISTER), INREG(DOVSTA)); 485 BEGIN_BATCH(4); 486 OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE); 487 OUT_BATCH(MI_NOOP); 488 OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE); 489 OUT_BATCH(flip_addr); 490 ADVANCE_BATCH(); 491 OVERLAY_DEBUG("overlay_continue\n"); 492} 493 494static void 495i830_overlay_off(ScrnInfoPtr pScrn) 496{ 497 I830Ptr pI830 = I830PTR(pScrn); 498 I830OverlayRegPtr overlay = I830OVERLAYREG(pI830); 499 500 if (!pI830->overlayOn) 501 return; 502 503 /* 504 * Wait for overlay to go idle. This has to be 505 * separated from the turning off state by a Sync 506 * to ensure the overlay will not read OCMD early and 507 * disable the overlay before the commands here are 508 * executed 509 */ 510 { 511 BEGIN_BATCH(2); 512 OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 513 OUT_BATCH(MI_NOOP); 514 ADVANCE_BATCH(); 515 I830Sync(pScrn); 516 } 517 518 /* 519 * Turn overlay off 520 */ 521 { 522 overlay->OCMD &= ~OVERLAY_ENABLE; 523 OVERLAY_DEBUG ("overlay_off cmd 0x%08x -> 0x%08x sta 0x%08x\n", 524 overlay->OCMD, INREG(OCMD_REGISTER), INREG(DOVSTA)); 525 BEGIN_BATCH(6); 526 OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE); 527 OUT_BATCH(MI_NOOP); 528 OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE); 529 if (OVERLAY_NOPHYSICAL(pI830)) 530 OUT_BATCH(pI830->overlay_regs->offset); 531 else 532 OUT_BATCH(pI830->overlay_regs->bus_addr); 533 OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); 534 OUT_BATCH(MI_NOOP); 535 ADVANCE_BATCH(); 536 I830Sync(pScrn); 537 } 538 pI830->overlayOn = FALSE; 539 OVERLAY_DEBUG("overlay_off\n"); 540} 541 542void 543I830InitVideo(ScreenPtr pScreen) 544{ 545 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 546 I830Ptr pI830 = I830PTR(pScrn); 547 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL; 548 XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL; 549 int num_adaptors; 550#ifdef INTEL_XVMC 551 Bool xvmc_status = FALSE; 552#endif 553 554#if 0 555 { 556 I830OverlayRegRec tmp; 557 558 ErrorF("sizeof I830OverlayRegRec is 0x%x\n", sizeof(I830OverlayRegRec)); 559 ErrorF("Reserved C, D, E, F, G are %x, %x, %x, %x, %x\n", 560 (unsigned long)&(tmp.RESERVEDC[0]) - (unsigned long)&tmp, 561 (unsigned long)&(tmp.RESERVEDD[0]) - (unsigned long)&tmp, 562 (unsigned long)&(tmp.RESERVEDE[0]) - (unsigned long)&tmp, 563 (unsigned long)&(tmp.RESERVEDF[0]) - (unsigned long)&tmp, 564 (unsigned long)&(tmp.RESERVEDG[0]) - (unsigned long)&tmp); 565 } 566#endif 567 568 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); 569 /* Give our adaptor list enough space for the overlay and/or texture video 570 * adaptors. 571 */ 572 newAdaptors = xalloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); 573 if (newAdaptors == NULL) 574 return; 575 576 memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr)); 577 adaptors = newAdaptors; 578 579 /* Add the adaptors supported by our hardware. First, set up the atoms 580 * that will be used by both output adaptors. 581 */ 582 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 583 xvContrast = MAKE_ATOM("XV_CONTRAST"); 584 585 /* Set up textured video if we can do it at this depth and we are on 586 * supported hardware. 587 */ 588 if (pScrn->bitsPerPixel >= 16 && (IS_I9XX(pI830) || IS_I965G(pI830)) && 589 !(!IS_I965G(pI830) && pScrn->displayWidth > 2048)) 590 { 591 texturedAdaptor = I830SetupImageVideoTextured(pScreen); 592 if (texturedAdaptor != NULL) { 593 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n"); 594 } else { 595 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 596 "Failed to set up textured video\n"); 597 } 598 } 599 600 /* Set up overlay video if we can do it at this depth. */ 601 if (!OVERLAY_NOEXIST(pI830) && pScrn->bitsPerPixel != 8 && 602 !pI830->use_drm_mode && pI830->overlay_regs != NULL) 603 { 604 overlayAdaptor = I830SetupImageVideoOverlay(pScreen); 605 if (overlayAdaptor != NULL) { 606 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up overlay video\n"); 607 } else { 608 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 609 "Failed to set up overlay video\n"); 610 } 611 I830InitOffscreenImages(pScreen); 612 } 613 614 if (overlayAdaptor && pI830->XvPreferOverlay) 615 adaptors[num_adaptors++] = overlayAdaptor; 616 617 if (texturedAdaptor) 618 adaptors[num_adaptors++] = texturedAdaptor; 619 620 if (overlayAdaptor && !pI830->XvPreferOverlay) 621 adaptors[num_adaptors++] = overlayAdaptor; 622 623#ifdef INTEL_XVMC 624 if (intel_xvmc_probe(pScrn)) { 625 if (texturedAdaptor) 626 xvmc_status = intel_xvmc_driver_init(pScreen, texturedAdaptor); 627 } 628#endif 629 630 if (num_adaptors) { 631 xf86XVScreenInit(pScreen, adaptors, num_adaptors); 632 } else { 633 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 634 "Disabling Xv because no adaptors could be initialized.\n"); 635 pI830->XvEnabled = FALSE; 636 } 637 638#ifdef INTEL_XVMC 639 if (xvmc_status) 640 intel_xvmc_screen_init(pScreen); 641#endif 642 xfree(adaptors); 643} 644 645static void 646I830ResetVideo(ScrnInfoPtr pScrn) 647{ 648 I830Ptr pI830 = I830PTR(pScrn); 649 I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; 650 I830OverlayRegPtr overlay = I830OVERLAYREG(pI830); 651 652 OVERLAY_DEBUG("I830ResetVideo: base: %p, offset: 0x%lx, obase: %p\n", 653 pI830->FbBase, pI830->overlay_regs->offset, overlay); 654 /* 655 * Default to maximum image size in YV12 656 */ 657 658 memset(overlay, 0, sizeof(*overlay)); 659 overlay->YRGB_VPH = 0; 660 overlay->UV_VPH = 0; 661 overlay->HORZ_PH = 0; 662 overlay->INIT_PHS = 0; 663 overlay->DWINPOS = 0; 664 overlay->DWINSZ = 0; 665 overlay->SWIDTH = 0; 666 overlay->SWIDTHSW = 0; 667 overlay->SHEIGHT = 0; 668 overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff); 669 overlay->OCLRC1 = pPriv->saturation; 670#if 0 671 overlay->AWINPOS = 0; 672 overlay->AWINSZ = 0; 673#endif 674 overlay->FASTHSCALE = 0; 675 676 /* 677 * Enable destination color keying 678 */ 679 switch (pScrn->depth) { 680 case 8: 681 overlay->DCLRKV = 0; 682 overlay->DCLRKM = 0xffffff | DEST_KEY_ENABLE; 683 break; 684 case 15: 685 overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); 686 overlay->DCLRKM = 0x070707 | DEST_KEY_ENABLE; 687 break; 688 case 16: 689 overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); 690 overlay->DCLRKM = 0x070307 | DEST_KEY_ENABLE; 691 break; 692 default: 693 overlay->DCLRKV = pPriv->colorKey; 694 overlay->DCLRKM = DEST_KEY_ENABLE; 695 break; 696 } 697 698 overlay->SCLRKVH = 0; 699 overlay->SCLRKVL = 0; 700 overlay->SCLRKEN = 0; /* source color key disable */ 701 overlay->OCONFIG = CC_OUT_8BIT; 702 if (IS_I965GM(pI830)) 703 overlay->OCONFIG |= CSC_MODE_BT709; 704 705 /* 706 * Select which pipe the overlay is enabled on. 707 */ 708 overlay->OCONFIG &= ~OVERLAY_PIPE_MASK; 709 if (i830_crtc_pipe (pPriv->current_crtc) == 0) 710 overlay->OCONFIG |= OVERLAY_PIPE_A; 711 else 712 overlay->OCONFIG |= OVERLAY_PIPE_B; 713 714#if 0 715 /* 716 * XXX DUMP REGISTER CODE !!! 717 * This allows us to dump the complete i845 registers and compare 718 * with warm boot situations before we upload our first copy. 719 */ 720 { 721 int i; 722 for (i = 0x30000; i < 0x31000; i += 4) 723 ErrorF("0x%x 0x%" PRIx32 "\n", i, INREG(i)); 724 } 725#endif 726} 727 728#define PFIT_CONTROLS 0x61230 729#define PFIT_AUTOVSCALE_MASK 0x200 730#define PFIT_ON_MASK 0x80000000 731#define PFIT_AUTOSCALE_RATIO 0x61238 732#define PFIT_PROGRAMMED_SCALE_RATIO 0x61234 733 734static void 735I830SetOneLineModeRatio(ScrnInfoPtr pScrn) 736{ 737 I830Ptr pI830 = I830PTR(pScrn); 738 I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; 739 uint32_t panelFitControl = INREG(PFIT_CONTROLS); 740 int vertScale; 741 742 pPriv->scaleRatio = 0x10000; 743 744 if (panelFitControl & PFIT_ON_MASK) { 745 if (panelFitControl & PFIT_AUTOVSCALE_MASK) { 746 vertScale = INREG(PFIT_AUTOSCALE_RATIO) >> 16; 747 } else { 748 vertScale = INREG(PFIT_PROGRAMMED_SCALE_RATIO) >> 16; 749 } 750 751 if (vertScale != 0) 752 pPriv->scaleRatio = ((double) 0x10000 / (double)vertScale) * 0x10000; 753 754 pPriv->oneLineMode = TRUE; 755 756 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling Xvideo one-line mode\n"); 757 } 758 759 if (pPriv->scaleRatio == 0x10000) 760 pPriv->oneLineMode = FALSE; 761} 762 763static uint32_t I830BoundGammaElt (uint32_t elt, uint32_t eltPrev) 764{ 765 elt &= 0xff; 766 eltPrev &= 0xff; 767 if (elt < eltPrev) 768 elt = eltPrev; 769 else if ((elt - eltPrev) > 0x7e) 770 elt = eltPrev + 0x7e; 771 return elt; 772} 773 774static uint32_t I830BoundGamma (uint32_t gamma, uint32_t gammaPrev) 775{ 776 return (I830BoundGammaElt (gamma >> 16, gammaPrev >> 16) << 16 | 777 I830BoundGammaElt (gamma >> 8, gammaPrev >> 8) << 8 | 778 I830BoundGammaElt (gamma , gammaPrev )); 779} 780 781static uint32_t I830Gamma5Errata(uint32_t gamma) 782{ 783 int i; 784 785 for (i = 0; i < 3; i++) { 786 if ((gamma >> i*8 & 0xff) == 0x80) { 787 /* According to Intel docs, overlay fails if GAMMA5 is 0x80. 788 * In this case, change the value to 0x81 */ 789 gamma += 1 << i*8; 790 } 791 } 792 793 return gamma; 794} 795 796static void 797I830UpdateGamma(ScrnInfoPtr pScrn) 798{ 799 I830Ptr pI830 = I830PTR(pScrn); 800 I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; 801 uint32_t gamma0 = pPriv->gamma0; 802 uint32_t gamma1 = pPriv->gamma1; 803 uint32_t gamma2 = pPriv->gamma2; 804 uint32_t gamma3 = pPriv->gamma3; 805 uint32_t gamma4 = pPriv->gamma4; 806 uint32_t gamma5 = pPriv->gamma5; 807 808#if 0 809 ErrorF ("Original gamma: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 810 gamma0, gamma1, gamma2, gamma3, gamma4, gamma5); 811#endif 812 gamma1 = I830BoundGamma (gamma1, gamma0); 813 gamma2 = I830BoundGamma (gamma2, gamma1); 814 gamma3 = I830BoundGamma (gamma3, gamma2); 815 gamma4 = I830BoundGamma (gamma4, gamma3); 816 gamma5 = I830BoundGamma (gamma5, gamma4); 817 gamma5 = I830Gamma5Errata(gamma5); 818#if 0 819 ErrorF ("Bounded gamma: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 820 gamma0, gamma1, gamma2, gamma3, gamma4, gamma5); 821#endif 822 823 OUTREG(OGAMC5, gamma5); 824 OUTREG(OGAMC4, gamma4); 825 OUTREG(OGAMC3, gamma3); 826 OUTREG(OGAMC2, gamma2); 827 OUTREG(OGAMC1, gamma1); 828 OUTREG(OGAMC0, gamma0); 829} 830 831static XF86VideoAdaptorPtr 832I830SetupImageVideoOverlay(ScreenPtr pScreen) 833{ 834 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 835 I830Ptr pI830 = I830PTR(pScrn); 836 XF86VideoAdaptorPtr adapt; 837 I830PortPrivPtr pPriv; 838 XF86AttributePtr att; 839 840 OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); 841 842 if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) + 843 sizeof(I830PortPrivRec) + sizeof(DevUnion)))) 844 return NULL; 845 846 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 847 adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/; 848 adapt->name = "Intel(R) Video Overlay"; 849 adapt->nEncodings = 1; 850 adapt->pEncodings = DummyEncoding; 851 /* update the DummyEncoding for these two chipsets */ 852 if (IS_845G(pI830) || IS_I830(pI830)) { 853 adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY; 854 adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY; 855 } 856 adapt->nFormats = NUM_FORMATS; 857 adapt->pFormats = Formats; 858 adapt->nPorts = 1; 859 adapt->pPortPrivates = (DevUnion *) (&adapt[1]); 860 861 pPriv = (I830PortPrivPtr) (&adapt->pPortPrivates[1]); 862 863 adapt->pPortPrivates[0].ptr = (pointer) (pPriv); 864 adapt->nAttributes = NUM_ATTRIBUTES; 865 adapt->nAttributes += CLONE_ATTRIBUTES; 866 if (IS_I9XX(pI830)) 867 adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */ 868 adapt->pAttributes = xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes); 869 /* Now copy the attributes */ 870 att = adapt->pAttributes; 871 memcpy((char *)att, (char*)Attributes, sizeof(XF86AttributeRec)* NUM_ATTRIBUTES); 872 att+=NUM_ATTRIBUTES; 873 memcpy((char*)att, (char*)CloneAttributes, sizeof(XF86AttributeRec) * CLONE_ATTRIBUTES); 874 att+=CLONE_ATTRIBUTES; 875 if (IS_I9XX(pI830)) { 876 memcpy((char*)att, (char*)GammaAttributes, sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES); 877 att+=GAMMA_ATTRIBUTES; 878 } 879 adapt->nImages = NUM_IMAGES; 880 adapt->pImages = Images; 881 adapt->PutVideo = NULL; 882 adapt->PutStill = NULL; 883 adapt->GetVideo = NULL; 884 adapt->GetStill = NULL; 885 adapt->StopVideo = I830StopVideo; 886 adapt->SetPortAttribute = I830SetPortAttributeOverlay; 887 adapt->GetPortAttribute = I830GetPortAttribute; 888 adapt->QueryBestSize = I830QueryBestSize; 889 adapt->PutImage = I830PutImage; 890 adapt->QueryImageAttributes = I830QueryImageAttributes; 891 892 pPriv->textured = FALSE; 893 pPriv->colorKey = pI830->colorKey & ((1 << pScrn->depth) - 1); 894 pPriv->videoStatus = 0; 895 pPriv->brightness = -19; /* (255/219) * -16 */ 896 pPriv->contrast = 75; /* 255/219 * 64 */ 897 pPriv->saturation = 146; /* 128/112 * 128 */ 898 pPriv->current_crtc = NULL; 899 pPriv->desired_crtc = NULL; 900 pPriv->buf = NULL; 901 pPriv->currentBuf = 0; 902 pPriv->gamma5 = 0xc0c0c0; 903 pPriv->gamma4 = 0x808080; 904 pPriv->gamma3 = 0x404040; 905 pPriv->gamma2 = 0x202020; 906 pPriv->gamma1 = 0x101010; 907 pPriv->gamma0 = 0x080808; 908 pPriv->doubleBuffer = 1; 909 910 pPriv->rotation = RR_Rotate_0; 911 912 /* gotta uninit this someplace */ 913 REGION_NULL(pScreen, &pPriv->clip); 914 915 pI830->adaptor = adapt; 916 917 /* With LFP's we need to detect whether we're in One Line Mode, which 918 * essentially means a resolution greater than 1024x768, and fix up 919 * the scaler accordingly. */ 920 pPriv->scaleRatio = 0x10000; 921 pPriv->oneLineMode = FALSE; 922 923 /* 924 * Initialise pPriv->overlayOK. Set it to TRUE here so that a warning will 925 * be generated if i830_crtc_dpms_video() sets it to FALSE during mode 926 * setup. 927 */ 928 pPriv->overlayOK = TRUE; 929 930 xvColorKey = MAKE_ATOM("XV_COLORKEY"); 931 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 932 xvContrast = MAKE_ATOM("XV_CONTRAST"); 933 xvSaturation = MAKE_ATOM("XV_SATURATION"); 934 xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER"); 935 936 /* Allow the pipe to be switched from pipe A to B when in clone mode */ 937 xvPipe = MAKE_ATOM("XV_PIPE"); 938 939 if (IS_I9XX(pI830)) { 940 xvGamma0 = MAKE_ATOM("XV_GAMMA0"); 941 xvGamma1 = MAKE_ATOM("XV_GAMMA1"); 942 xvGamma2 = MAKE_ATOM("XV_GAMMA2"); 943 xvGamma3 = MAKE_ATOM("XV_GAMMA3"); 944 xvGamma4 = MAKE_ATOM("XV_GAMMA4"); 945 xvGamma5 = MAKE_ATOM("XV_GAMMA5"); 946 } 947 948 I830ResetVideo(pScrn); 949 950 I830UpdateGamma(pScrn); 951 952 return adapt; 953} 954 955static XF86VideoAdaptorPtr 956I830SetupImageVideoTextured(ScreenPtr pScreen) 957{ 958 XF86VideoAdaptorPtr adapt; 959 XF86AttributePtr attrs; 960 I830PortPrivPtr portPrivs; 961 DevUnion *devUnions; 962 int nports = 16, i; 963 int nAttributes; 964 965 OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); 966 967 nAttributes = NUM_TEXTURED_ATTRIBUTES; 968 969 adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec)); 970 portPrivs = xcalloc(nports, sizeof(I830PortPrivRec)); 971 devUnions = xcalloc(nports, sizeof(DevUnion)); 972 attrs = xcalloc(nAttributes, sizeof(XF86AttributeRec)); 973 if (adapt == NULL || portPrivs == NULL || devUnions == NULL || 974 attrs == NULL) 975 { 976 xfree(adapt); 977 xfree(portPrivs); 978 xfree(devUnions); 979 xfree(attrs); 980 return NULL; 981 } 982 983 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 984 adapt->flags = 0; 985 adapt->name = "Intel(R) Textured Video"; 986 adapt->nEncodings = 1; 987 adapt->pEncodings = DummyEncoding; 988 adapt->nFormats = NUM_FORMATS; 989 adapt->pFormats = Formats; 990 adapt->nPorts = nports; 991 adapt->pPortPrivates = devUnions; 992 adapt->nAttributes = nAttributes; 993 adapt->pAttributes = attrs; 994 memcpy(attrs, TexturedAttributes, nAttributes * sizeof(XF86AttributeRec)); 995 adapt->nImages = NUM_IMAGES; 996 adapt->pImages = Images; 997 adapt->PutVideo = NULL; 998 adapt->PutStill = NULL; 999 adapt->GetVideo = NULL; 1000 adapt->GetStill = NULL; 1001 adapt->StopVideo = I830StopVideo; 1002 adapt->SetPortAttribute = I830SetPortAttributeTextured; 1003 adapt->GetPortAttribute = I830GetPortAttribute; 1004 adapt->QueryBestSize = I830QueryBestSize; 1005 adapt->PutImage = I830PutImage; 1006 adapt->QueryImageAttributes = I830QueryImageAttributes; 1007 1008 for (i = 0; i < nports; i++) { 1009 I830PortPrivPtr pPriv = &portPrivs[i]; 1010 1011 pPriv->textured = TRUE; 1012 pPriv->videoStatus = 0; 1013 pPriv->buf = NULL; 1014 pPriv->currentBuf = 0; 1015 pPriv->doubleBuffer = 0; 1016 1017 pPriv->rotation = RR_Rotate_0; 1018 pPriv->SyncToVblank = 1; 1019 1020 /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ 1021 REGION_NULL(pScreen, &pPriv->clip); 1022 1023 adapt->pPortPrivates[i].ptr = (pointer) (pPriv); 1024 } 1025 1026 xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 1027 1028 return adapt; 1029} 1030 1031static void 1032I830StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown) 1033{ 1034 I830PortPrivPtr pPriv = (I830PortPrivPtr) data; 1035 1036 if (pPriv->textured) 1037 return; 1038 1039 OVERLAY_DEBUG("I830StopVideo\n"); 1040 1041 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 1042 1043 if (shutdown) { 1044 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 1045 i830_overlay_off(pScrn); 1046 } 1047 1048 if (pPriv->buf) { 1049 drm_intel_bo_unpin(pPriv->buf); 1050 drm_intel_bo_unreference(pPriv->buf); 1051 pPriv->buf = NULL; 1052 pPriv->videoStatus = 0; 1053 } 1054 } else { 1055 if (pPriv->videoStatus & CLIENT_VIDEO_ON) { 1056 pPriv->videoStatus |= OFF_TIMER; 1057 pPriv->offTime = currentTime.milliseconds + OFF_DELAY; 1058 } 1059 } 1060 1061} 1062 1063static int 1064I830SetPortAttributeTextured(ScrnInfoPtr pScrn, 1065 Atom attribute, INT32 value, pointer data) 1066{ 1067 I830PortPrivPtr pPriv = (I830PortPrivPtr) data; 1068 1069 if (attribute == xvBrightness) { 1070 if ((value < -128) || (value > 127)) 1071 return BadValue; 1072 pPriv->brightness = value; 1073 return Success; 1074 } else if (attribute == xvContrast) { 1075 if ((value < 0) || (value > 255)) 1076 return BadValue; 1077 pPriv->contrast = value; 1078 return Success; 1079 } else if (attribute == xvSyncToVblank) { 1080 if ((value < -1) || (value > 1)) 1081 return BadValue; 1082 1083 pPriv->SyncToVblank = value; 1084 return Success; 1085 } else { 1086 return BadMatch; 1087 } 1088} 1089 1090static int 1091I830SetPortAttributeOverlay(ScrnInfoPtr pScrn, 1092 Atom attribute, INT32 value, pointer data) 1093{ 1094 I830PortPrivPtr pPriv = (I830PortPrivPtr) data; 1095 I830Ptr pI830 = I830PTR(pScrn); 1096 I830OverlayRegPtr overlay; 1097 1098 overlay = I830OVERLAYREG(pI830); 1099 1100 if (attribute == xvBrightness) { 1101 if ((value < -128) || (value > 127)) 1102 return BadValue; 1103 pPriv->brightness = value; 1104 overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff); 1105 OVERLAY_DEBUG("BRIGHTNESS\n"); 1106 i830_overlay_continue (pScrn, FALSE); 1107 } else if (attribute == xvContrast) { 1108 if ((value < 0) || (value > 255)) 1109 return BadValue; 1110 pPriv->contrast = value; 1111 overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff); 1112 OVERLAY_DEBUG("CONTRAST\n"); 1113 i830_overlay_continue (pScrn, FALSE); 1114 } else if (attribute == xvSaturation) { 1115 if ((value < 0) || (value > 1023)) 1116 return BadValue; 1117 pPriv->saturation = value; 1118 overlay->OCLRC1 = pPriv->saturation; 1119 i830_overlay_continue (pScrn, FALSE); 1120 } else if (attribute == xvPipe) { 1121 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1122 if ((value < -1) || (value > xf86_config->num_crtc)) 1123 return BadValue; 1124 if (value < 0) 1125 pPriv->desired_crtc = NULL; 1126 else 1127 pPriv->desired_crtc = xf86_config->crtc[value]; 1128 /* 1129 * Leave this to be updated at the next frame 1130 */ 1131 } else if (attribute == xvGamma0 && (IS_I9XX(pI830))) { 1132 pPriv->gamma0 = value; 1133 } else if (attribute == xvGamma1 && (IS_I9XX(pI830))) { 1134 pPriv->gamma1 = value; 1135 } else if (attribute == xvGamma2 && (IS_I9XX(pI830))) { 1136 pPriv->gamma2 = value; 1137 } else if (attribute == xvGamma3 && (IS_I9XX(pI830))) { 1138 pPriv->gamma3 = value; 1139 } else if (attribute == xvGamma4 && (IS_I9XX(pI830))) { 1140 pPriv->gamma4 = value; 1141 } else if (attribute == xvGamma5 && (IS_I9XX(pI830))) { 1142 pPriv->gamma5 = value; 1143 } else if (attribute == xvColorKey) { 1144 pPriv->colorKey = value; 1145 switch (pScrn->depth) { 1146 case 16: 1147 overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey); 1148 break; 1149 case 15: 1150 overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey); 1151 break; 1152 default: 1153 overlay->DCLRKV = pPriv->colorKey; 1154 break; 1155 } 1156 OVERLAY_DEBUG("COLORKEY\n"); 1157 i830_overlay_continue (pScrn, FALSE); 1158 REGION_EMPTY(pScrn->pScreen, &pPriv->clip); 1159 } else if(attribute == xvDoubleBuffer) { 1160 if ((value < 0) || (value > 1)) 1161 return BadValue; 1162 /* Do not allow buffer change while playing video */ 1163 if(!pI830->overlayOn) 1164 pPriv->doubleBuffer = value; 1165 } else 1166 return BadMatch; 1167 1168 /* Ensure that the overlay is off, ready for updating */ 1169 if ((attribute == xvGamma0 || 1170 attribute == xvGamma1 || 1171 attribute == xvGamma2 || 1172 attribute == xvGamma3 || 1173 attribute == xvGamma4 || 1174 attribute == xvGamma5) && (IS_I9XX(pI830))) { 1175 OVERLAY_DEBUG("GAMMA\n"); 1176 I830UpdateGamma(pScrn); 1177 } 1178 1179 return Success; 1180} 1181 1182static int 1183I830GetPortAttribute(ScrnInfoPtr pScrn, 1184 Atom attribute, INT32 * value, pointer data) 1185{ 1186 I830Ptr pI830 = I830PTR(pScrn); 1187 I830PortPrivPtr pPriv = (I830PortPrivPtr) data; 1188 1189 if (attribute == xvBrightness) { 1190 *value = pPriv->brightness; 1191 } else if (attribute == xvContrast) { 1192 *value = pPriv->contrast; 1193 } else if (attribute == xvSaturation) { 1194 *value = pPriv->saturation; 1195 } else if (attribute == xvPipe) { 1196 int c; 1197 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1198 for (c = 0; c < xf86_config->num_crtc; c++) 1199 if (xf86_config->crtc[c] == pPriv->desired_crtc) 1200 break; 1201 if (c == xf86_config->num_crtc) 1202 c = -1; 1203 *value = c; 1204 } else if (attribute == xvGamma0 && (IS_I9XX(pI830))) { 1205 *value = pPriv->gamma0; 1206 } else if (attribute == xvGamma1 && (IS_I9XX(pI830))) { 1207 *value = pPriv->gamma1; 1208 } else if (attribute == xvGamma2 && (IS_I9XX(pI830))) { 1209 *value = pPriv->gamma2; 1210 } else if (attribute == xvGamma3 && (IS_I9XX(pI830))) { 1211 *value = pPriv->gamma3; 1212 } else if (attribute == xvGamma4 && (IS_I9XX(pI830))) { 1213 *value = pPriv->gamma4; 1214 } else if (attribute == xvGamma5 && (IS_I9XX(pI830))) { 1215 *value = pPriv->gamma5; 1216 } else if (attribute == xvColorKey) { 1217 *value = pPriv->colorKey; 1218 } else if (attribute == xvDoubleBuffer) { 1219 *value = pPriv->doubleBuffer; 1220 } else if (attribute == xvSyncToVblank) { 1221 *value = pPriv->SyncToVblank; 1222 } else 1223 return BadMatch; 1224 1225 return Success; 1226} 1227 1228static void 1229I830QueryBestSize(ScrnInfoPtr pScrn, 1230 Bool motion, 1231 short vid_w, short vid_h, 1232 short drw_w, short drw_h, 1233 unsigned int *p_w, unsigned int *p_h, pointer data) 1234{ 1235 if (vid_w > (drw_w << 1)) 1236 drw_w = vid_w >> 1; 1237 if (vid_h > (drw_h << 1)) 1238 drw_h = vid_h >> 1; 1239 1240 *p_w = drw_w; 1241 *p_h = drw_h; 1242} 1243 1244static void 1245I830CopyPackedData(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, 1246 unsigned char *buf, 1247 int srcPitch, 1248 int dstPitch, int top, int left, int h, int w) 1249{ 1250 I830Ptr pI830 = I830PTR(pScrn); 1251 unsigned char *src, *dst, *dst_base; 1252 int i,j; 1253 unsigned char *s; 1254 1255#if 0 1256 ErrorF("I830CopyPackedData: (%d,%d) (%d,%d)\n" 1257 "srcPitch: %d, dstPitch: %d\n", top, left, h, w, 1258 srcPitch, dstPitch); 1259#endif 1260 1261 src = buf + (top * srcPitch) + (left << 1); 1262 1263 if (pPriv->textured) { 1264 drm_intel_bo_map(pPriv->buf, TRUE); 1265 dst_base = pPriv->buf->virtual; 1266 } else { 1267 drm_intel_gem_bo_start_gtt_access(pPriv->buf, TRUE); 1268 dst_base = pI830->FbBase; 1269 } 1270 1271 if (pPriv->currentBuf == 0) 1272 dst = dst_base + pPriv->YBuf0offset; 1273 else 1274 dst = dst_base + pPriv->YBuf1offset; 1275 1276 switch (pPriv->rotation) { 1277 case RR_Rotate_0: 1278 w <<= 1; 1279 for (i = 0; i < h; i++) { 1280 memcpy(dst, src, w); 1281 src += srcPitch; 1282 dst += dstPitch; 1283 } 1284 break; 1285 case RR_Rotate_90: 1286 h <<= 1; 1287 for (i = 0; i < h; i+=2) { 1288 s = src; 1289 for (j = 0; j < w; j++) { 1290 /* Copy Y */ 1291 dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++; 1292 (void)*s++; 1293 } 1294 src += srcPitch; 1295 } 1296 h >>= 1; 1297 src = buf + (top * srcPitch) + (left << 1); 1298 for (i = 0; i < h; i+=2) { 1299 for (j = 0; j < w; j+=2) { 1300 /* Copy U */ 1301 dst[((i*2) + 1) + ((w - j - 1) * dstPitch)] = src[(j*2) + 1 + (i * srcPitch)]; 1302 dst[((i*2) + 1) + ((w - j - 2) * dstPitch)] = src[(j*2) + 1 + ((i+1) * srcPitch)]; 1303 /* Copy V */ 1304 dst[((i*2) + 3) + ((w - j - 1) * dstPitch)] = src[(j*2) + 3 + (i * srcPitch)]; 1305 dst[((i*2) + 3) + ((w - j - 2) * dstPitch)] = src[(j*2) + 3 + ((i+1) * srcPitch)]; 1306 } 1307 } 1308 break; 1309 case RR_Rotate_180: 1310 w <<= 1; 1311 for (i = 0; i < h; i++) { 1312 s = src; 1313 for (j = 0; j < w; j+=4) { 1314 dst[(w - j - 4) + ((h - i - 1) * dstPitch)] = *s++; 1315 dst[(w - j - 3) + ((h - i - 1) * dstPitch)] = *s++; 1316 dst[(w - j - 2) + ((h - i - 1) * dstPitch)] = *s++; 1317 dst[(w - j - 1) + ((h - i - 1) * dstPitch)] = *s++; 1318 } 1319 src += srcPitch; 1320 } 1321 break; 1322 case RR_Rotate_270: 1323 h <<= 1; 1324 for (i = 0; i < h; i+=2) { 1325 s = src; 1326 for (j = 0; j < w; j++) { 1327 /* Copy Y */ 1328 dst[(h - i - 2) + (j * dstPitch)] = *s++; 1329 (void)*s++; 1330 } 1331 src += srcPitch; 1332 } 1333 h >>= 1; 1334 src = buf + (top * srcPitch) + (left << 1); 1335 for (i = 0; i < h; i+=2) { 1336 for (j = 0; j < w; j+=2) { 1337 /* Copy U */ 1338 dst[(((h - i)*2) - 3) + (j * dstPitch)] = src[(j*2) + 1 + (i * srcPitch)]; 1339 dst[(((h - i)*2) - 3) + ((j - 1) * dstPitch)] = src[(j*2) + 1 + ((i+1) * srcPitch)]; 1340 /* Copy V */ 1341 dst[(((h - i)*2) - 1) + (j * dstPitch)] = src[(j*2) + 3 + (i * srcPitch)]; 1342 dst[(((h - i)*2) - 1) + ((j - 1) * dstPitch)] = src[(j*2) + 3 + ((i+1) * srcPitch)]; 1343 } 1344 } 1345 break; 1346 } 1347 1348 if (pPriv->textured) 1349 drm_intel_bo_unmap(pPriv->buf); 1350} 1351 1352static void 1353I830CopyPlanarData(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv, 1354 unsigned char *buf, int srcPitch, 1355 int srcPitch2, int dstPitch, int srcH, int top, int left, 1356 int h, int w, int id) 1357{ 1358 I830Ptr pI830 = I830PTR(pScrn); 1359 int i, j = 0; 1360 unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3; 1361 unsigned char *s; 1362 int dstPitch2 = dstPitch << 1; 1363 1364#if 0 1365 ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n" 1366 "nlines %d, npixels %d, top %d, left %d\n", 1367 srcPitch, srcPitch2, dstPitch, 1368 h, w, top, left); 1369#endif 1370 1371 /* Copy Y data */ 1372 src1 = buf + (top * srcPitch) + left; 1373#if 0 1374 ErrorF("src1 is %p, offset is %ld\n", src1, 1375 (unsigned long)src1 - (unsigned long)buf); 1376#endif 1377 1378 if (pPriv->textured) { 1379 drm_intel_bo_map(pPriv->buf, TRUE); 1380 dst_base = pPriv->buf->virtual; 1381 } else { 1382 drm_intel_gem_bo_start_gtt_access(pPriv->buf, TRUE); 1383 dst_base = pI830->FbBase; 1384 } 1385 1386 if (pPriv->currentBuf == 0) 1387 dst1 = dst_base + pPriv->YBuf0offset; 1388 else 1389 dst1 = dst_base + pPriv->YBuf1offset; 1390 1391 switch (pPriv->rotation) { 1392 case RR_Rotate_0: 1393 /* optimise for the case of no clipping */ 1394 if (srcPitch == dstPitch2 && srcPitch == w) 1395 memcpy (dst1, src1, srcPitch * h); 1396 else 1397 for (i = 0; i < h; i++) { 1398 memcpy(dst1, src1, w); 1399 src1 += srcPitch; 1400 dst1 += dstPitch2; 1401 } 1402 break; 1403 case RR_Rotate_90: 1404 for (i = 0; i < h; i++) { 1405 s = src1; 1406 for (j = 0; j < w; j++) { 1407 dst1[(i) + ((w - j - 1) * dstPitch2)] = *s++; 1408 } 1409 src1 += srcPitch; 1410 } 1411 break; 1412 case RR_Rotate_180: 1413 for (i = 0; i < h; i++) { 1414 s = src1; 1415 for (j = 0; j < w; j++) { 1416 dst1[(w - j - 1) + ((h - i - 1) * dstPitch2)] = *s++; 1417 } 1418 src1 += srcPitch; 1419 } 1420 break; 1421 case RR_Rotate_270: 1422 for (i = 0; i < h; i++) { 1423 s = src1; 1424 for (j = 0; j < w; j++) { 1425 dst1[(h - i - 1) + (j * dstPitch2)] = *s++; 1426 } 1427 src1 += srcPitch; 1428 } 1429 break; 1430 } 1431 1432 /* Copy V data for YV12, or U data for I420 */ 1433 src2 = buf + /* start of YUV data */ 1434 (srcH * srcPitch) + /* move over Luma plane */ 1435 ((top * srcPitch) >> 2) + /* move down from by top lines */ 1436 (left >> 1); /* move left by left pixels */ 1437 1438#if 0 1439 ErrorF("src2 is %p, offset is %ld\n", src2, 1440 (unsigned long)src2 - (unsigned long)buf); 1441#endif 1442 if (pPriv->currentBuf == 0) { 1443 if (id == FOURCC_I420) 1444 dst2 = dst_base + pPriv->UBuf0offset; 1445 else 1446 dst2 = dst_base + pPriv->VBuf0offset; 1447 } else { 1448 if (id == FOURCC_I420) 1449 dst2 = dst_base + pPriv->UBuf1offset; 1450 else 1451 dst2 = dst_base + pPriv->VBuf1offset; 1452 } 1453 1454 switch (pPriv->rotation) { 1455 case RR_Rotate_0: 1456 /* optimise for the case of no clipping */ 1457 if (srcPitch2 == dstPitch && srcPitch2 == (w/2)) 1458 memcpy (dst2, src2, h/2 * srcPitch2); 1459 else 1460 for (i = 0; i < h / 2; i++) { 1461 memcpy(dst2, src2, w / 2); 1462 src2 += srcPitch2; 1463 dst2 += dstPitch; 1464 } 1465 break; 1466 case RR_Rotate_90: 1467 for (i = 0; i < (h/2); i++) { 1468 s = src2; 1469 for (j = 0; j < (w/2); j++) { 1470 dst2[(i) + (((w/2) - j - 1) * (dstPitch))] = *s++; 1471 } 1472 src2 += srcPitch2; 1473 } 1474 break; 1475 case RR_Rotate_180: 1476 for (i = 0; i < (h/2); i++) { 1477 s = src2; 1478 for (j = 0; j < (w/2); j++) { 1479 dst2[((w/2) - j - 1) + (((h/2) - i - 1) * dstPitch)] = *s++; 1480 } 1481 src2 += srcPitch2; 1482 } 1483 break; 1484 case RR_Rotate_270: 1485 for (i = 0; i < (h/2); i++) { 1486 s = src2; 1487 for (j = 0; j < (w/2); j++) { 1488 dst2[((h/2) - i - 1) + (j * dstPitch)] = *s++; 1489 } 1490 src2 += srcPitch2; 1491 } 1492 break; 1493 } 1494 1495 /* Copy U data for YV12, or V data for I420 */ 1496 src3 = buf + /* start of YUV data */ 1497 (srcH * srcPitch) + /* move over Luma plane */ 1498 ((srcH >> 1) * srcPitch2) + /* move over Chroma plane */ 1499 ((top * srcPitch) >> 2) + /* move down from by top lines */ 1500 (left >> 1); /* move left by left pixels */ 1501#if 0 1502 ErrorF("src3 is %p, offset is %ld\n", src3, 1503 (unsigned long)src3 - (unsigned long)buf); 1504#endif 1505 if (pPriv->currentBuf == 0) { 1506 if (id == FOURCC_I420) 1507 dst3 = dst_base + pPriv->VBuf0offset; 1508 else 1509 dst3 = dst_base + pPriv->UBuf0offset; 1510 } else { 1511 if (id == FOURCC_I420) 1512 dst3 = dst_base + pPriv->VBuf1offset; 1513 else 1514 dst3 = dst_base + pPriv->UBuf1offset; 1515 } 1516 1517 switch (pPriv->rotation) { 1518 case RR_Rotate_0: 1519 /* optimise for the case of no clipping */ 1520 if (srcPitch2 == dstPitch && srcPitch2 == (w/2)) 1521 memcpy (dst3, src3, srcPitch2 * h/2); 1522 else 1523 for (i = 0; i < h / 2; i++) { 1524 memcpy(dst3, src3, w / 2); 1525 src3 += srcPitch2; 1526 dst3 += dstPitch; 1527 } 1528 break; 1529 case RR_Rotate_90: 1530 for (i = 0; i < (h/2); i++) { 1531 s = src3; 1532 for (j = 0; j < (w/2); j++) { 1533 dst3[(i) + (((w/2) - j - 1) * (dstPitch))] = *s++; 1534 } 1535 src3 += srcPitch2; 1536 } 1537 break; 1538 case RR_Rotate_180: 1539 for (i = 0; i < (h/2); i++) { 1540 s = src3; 1541 for (j = 0; j < (w/2); j++) { 1542 dst3[((w/2) - j - 1) + (((h/2) - i - 1) * dstPitch)] = *s++; 1543 } 1544 src3 += srcPitch2; 1545 } 1546 break; 1547 case RR_Rotate_270: 1548 for (i = 0; i < (h/2); i++) { 1549 s = src3; 1550 for (j = 0; j < (w/2); j++) { 1551 dst3[((h/2) - i - 1) + (j * dstPitch)] = *s++; 1552 } 1553 src3 += srcPitch2; 1554 } 1555 break; 1556 } 1557 1558 if (pPriv->textured) 1559 drm_intel_bo_unmap(pPriv->buf); 1560} 1561 1562typedef struct { 1563 uint8_t sign; 1564 uint16_t mantissa; 1565 uint8_t exponent; 1566} coeffRec, *coeffPtr; 1567 1568static Bool 1569SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos) 1570{ 1571 int maxVal, icoeff, res; 1572 int sign; 1573 double c; 1574 1575 sign = 0; 1576 maxVal = 1 << mantSize; 1577 c = *coeff; 1578 if (c < 0.0) { 1579 sign = 1; 1580 c = -c; 1581 } 1582 1583 res = 12 - mantSize; 1584 if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) { 1585 pCoeff[pos].exponent = 3; 1586 pCoeff[pos].mantissa = icoeff << res; 1587 *coeff = (double)icoeff / (double)(4 * maxVal); 1588 } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) { 1589 pCoeff[pos].exponent = 2; 1590 pCoeff[pos].mantissa = icoeff << res; 1591 *coeff = (double)icoeff / (double)(2 * maxVal); 1592 } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) { 1593 pCoeff[pos].exponent = 1; 1594 pCoeff[pos].mantissa = icoeff << res; 1595 *coeff = (double)icoeff / (double)(maxVal); 1596 } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) { 1597 pCoeff[pos].exponent = 0; 1598 pCoeff[pos].mantissa = icoeff << res; 1599 *coeff = (double)icoeff / (double)(maxVal / 2); 1600 } else { 1601 /* Coeff out of range */ 1602 return FALSE; 1603 } 1604 1605 pCoeff[pos].sign = sign; 1606 if (sign) 1607 *coeff = -(*coeff); 1608 return TRUE; 1609} 1610 1611static void 1612UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff) 1613{ 1614 int i, j, j1, num, pos, mantSize; 1615 double pi = 3.1415926535, val, sinc, window, sum; 1616 double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS]; 1617 double diff; 1618 int tapAdjust[MAX_TAPS], tap2Fix; 1619 Bool isVertAndUV; 1620 1621 if (isHoriz) 1622 mantSize = 7; 1623 else 1624 mantSize = 6; 1625 1626 isVertAndUV = !isHoriz && !isY; 1627 num = taps * 16; 1628 for (i = 0; i < num * 2; i++) { 1629 val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num); 1630 if (val == 0.0) 1631 sinc = 1.0; 1632 else 1633 sinc = sin(val) / val; 1634 1635 /* Hamming window */ 1636 window = (0.5 - 0.5 * cos(i * pi / num)); 1637 rawCoeff[i] = sinc * window; 1638 } 1639 1640 for (i = 0; i < N_PHASES; i++) { 1641 /* Normalise the coefficients. */ 1642 sum = 0.0; 1643 for (j = 0; j < taps; j++) { 1644 pos = i + j * 32; 1645 sum += rawCoeff[pos]; 1646 } 1647 for (j = 0; j < taps; j++) { 1648 pos = i + j * 32; 1649 coeffs[i][j] = rawCoeff[pos] / sum; 1650 } 1651 1652 /* Set the register values. */ 1653 for (j = 0; j < taps; j++) { 1654 pos = j + i * taps; 1655 if ((j == (taps - 1) / 2) && !isVertAndUV) 1656 SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos); 1657 else 1658 SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos); 1659 } 1660 1661 tapAdjust[0] = (taps - 1) / 2; 1662 for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) { 1663 tapAdjust[j1] = tapAdjust[0] - j; 1664 tapAdjust[++j1] = tapAdjust[0] + j; 1665 } 1666 1667 /* Adjust the coefficients. */ 1668 sum = 0.0; 1669 for (j = 0; j < taps; j++) 1670 sum += coeffs[i][j]; 1671 if (sum != 1.0) { 1672 for (j1 = 0; j1 < taps; j1++) { 1673 tap2Fix = tapAdjust[j1]; 1674 diff = 1.0 - sum; 1675 coeffs[i][tap2Fix] += diff; 1676 pos = tap2Fix + i * taps; 1677 if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV) 1678 SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos); 1679 else 1680 SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos); 1681 1682 sum = 0.0; 1683 for (j = 0; j < taps; j++) 1684 sum += coeffs[i][j]; 1685 if (sum == 1.0) 1686 break; 1687 } 1688 } 1689 } 1690} 1691 1692static void 1693i830_box_intersect (BoxPtr dest, BoxPtr a, BoxPtr b) 1694{ 1695 dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 1696 dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 1697 dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 1698 dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 1699 if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) 1700 dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 1701} 1702 1703static void 1704i830_crtc_box (xf86CrtcPtr crtc, BoxPtr crtc_box) 1705{ 1706 if (crtc->enabled) 1707 { 1708 crtc_box->x1 = crtc->x; 1709 crtc_box->x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); 1710 crtc_box->y1 = crtc->y; 1711 crtc_box->y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); 1712 } 1713 else 1714 crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 1715} 1716 1717static int 1718i830_box_area (BoxPtr box) 1719{ 1720 return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1); 1721} 1722 1723/* 1724 * Return the crtc covering 'box'. If two crtcs cover a portion of 1725 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 1726 * with greater coverage 1727 */ 1728 1729xf86CrtcPtr 1730i830_covering_crtc (ScrnInfoPtr pScrn, 1731 BoxPtr box, 1732 xf86CrtcPtr desired, 1733 BoxPtr crtc_box_ret) 1734{ 1735 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1736 xf86CrtcPtr crtc, best_crtc; 1737 int coverage, best_coverage; 1738 int c; 1739 BoxRec crtc_box, cover_box; 1740 1741 best_crtc = NULL; 1742 best_coverage = 0; 1743 crtc_box_ret->x1 = 0; 1744 crtc_box_ret->x2 = 0; 1745 crtc_box_ret->y1 = 0; 1746 crtc_box_ret->y2 = 0; 1747 for (c = 0; c < xf86_config->num_crtc; c++) 1748 { 1749 crtc = xf86_config->crtc[c]; 1750 1751 /* If the CRTC is off, treat it as not covering */ 1752 if (!i830_crtc_on(crtc)) 1753 continue; 1754 1755 i830_crtc_box (crtc, &crtc_box); 1756 i830_box_intersect (&cover_box, &crtc_box, box); 1757 coverage = i830_box_area (&cover_box); 1758 if (coverage && crtc == desired) 1759 { 1760 *crtc_box_ret = crtc_box; 1761 return crtc; 1762 } 1763 if (coverage > best_coverage) 1764 { 1765 *crtc_box_ret = crtc_box; 1766 best_crtc = crtc; 1767 best_coverage = coverage; 1768 } 1769 } 1770 return best_crtc; 1771} 1772 1773static int 1774i830_swidth (I830Ptr pI830, unsigned int offset, 1775 unsigned int width, unsigned int mask, int shift) 1776{ 1777 int swidth = ((offset + width + mask) >> shift) - (offset >> shift); 1778 if (IS_I9XX(pI830)) 1779 swidth <<= 1; 1780 swidth -= 1; 1781 return swidth << 2; 1782} 1783 1784static void 1785i830_update_dst_box_to_crtc_coords(ScrnInfoPtr pScrn, xf86CrtcPtr crtc, 1786 BoxPtr dstBox) 1787{ 1788 int tmp; 1789 1790 /* for overlay, we should take it from crtc's screen 1791 * coordinate to current crtc's display mode. 1792 * yeah, a bit confusing. 1793 */ 1794 switch (crtc->rotation & 0xf) { 1795 case RR_Rotate_0: 1796 dstBox->x1 -= crtc->x; 1797 dstBox->x2 -= crtc->x; 1798 dstBox->y1 -= crtc->y; 1799 dstBox->y2 -= crtc->y; 1800 break; 1801 case RR_Rotate_90: 1802 tmp = dstBox->x1; 1803 dstBox->x1 = dstBox->y1 - crtc->x; 1804 dstBox->y1 = pScrn->virtualX - tmp - crtc->y; 1805 tmp = dstBox->x2; 1806 dstBox->x2 = dstBox->y2 - crtc->x; 1807 dstBox->y2 = pScrn->virtualX - tmp - crtc->y; 1808 tmp = dstBox->y1; 1809 dstBox->y1 = dstBox->y2; 1810 dstBox->y2 = tmp; 1811 break; 1812 case RR_Rotate_180: 1813 tmp = dstBox->x1; 1814 dstBox->x1 = pScrn->virtualX - dstBox->x2 - crtc->x; 1815 dstBox->x2 = pScrn->virtualX - tmp - crtc->x; 1816 tmp = dstBox->y1; 1817 dstBox->y1 = pScrn->virtualY - dstBox->y2 - crtc->y; 1818 dstBox->y2 = pScrn->virtualY - tmp - crtc->y; 1819 break; 1820 case RR_Rotate_270: 1821 tmp = dstBox->x1; 1822 dstBox->x1 = pScrn->virtualY - dstBox->y1 - crtc->x; 1823 dstBox->y1 = tmp - crtc->y; 1824 tmp = dstBox->x2; 1825 dstBox->x2 = pScrn->virtualY - dstBox->y2 - crtc->x; 1826 dstBox->y2 = tmp - crtc->y; 1827 tmp = dstBox->x1; 1828 dstBox->x1 = dstBox->x2; 1829 dstBox->x2 = tmp; 1830 break; 1831 } 1832 1833 return; 1834} 1835 1836static void 1837i830_store_coeffs_in_overlay_regs(uint16_t *reg_coeffs, coeffPtr new_coeffs, 1838 int max_taps) 1839{ 1840 int i, j, pos; 1841 1842 for (i = 0; i < N_PHASES; i++) { 1843 for (j = 0; j < max_taps; j++) { 1844 pos = i * max_taps + j; 1845 reg_coeffs[pos] = (new_coeffs[pos].sign << 15 | 1846 new_coeffs[pos].exponent << 12 | 1847 new_coeffs[pos].mantissa); 1848 } 1849 } 1850} 1851 1852static double 1853i830_limit_coeff(double coeff) 1854{ 1855 /* Limit to between 1.0 and 3.0. */ 1856 if (coeff < MIN_CUTOFF_FREQ) 1857 coeff = MIN_CUTOFF_FREQ; 1858 if (coeff > MAX_CUTOFF_FREQ) 1859 coeff = MAX_CUTOFF_FREQ; 1860 1861 return coeff; 1862} 1863 1864static void 1865i830_update_polyphase_coeffs(I830OverlayRegPtr overlay, 1866 int xscaleFract, int xscaleFractUV) 1867{ 1868 /* 1869 * Only Horizontal coefficients so far. 1870 */ 1871 double fCutoffY; 1872 double fCutoffUV; 1873 coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES]; 1874 coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES]; 1875 1876 fCutoffY = xscaleFract / 4096.0; 1877 fCutoffUV = xscaleFractUV / 4096.0; 1878 1879 fCutoffUV = i830_limit_coeff(fCutoffUV); 1880 fCutoffY = i830_limit_coeff(fCutoffY); 1881 1882 UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY); 1883 UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV); 1884 1885 i830_store_coeffs_in_overlay_regs(overlay->Y_HCOEFS, xcoeffY, 1886 N_HORIZ_Y_TAPS); 1887 i830_store_coeffs_in_overlay_regs(overlay->UV_HCOEFS, xcoeffUV, 1888 N_HORIZ_UV_TAPS); 1889} 1890 1891/* 1892 * Calculate horizontal and vertical scaling factors and polyphase 1893 * coefficients. 1894 */ 1895 1896static Bool 1897i830_update_scaling_factors(I830OverlayRegPtr overlay, 1898 short src_w, short src_h, short drw_w, short drw_h) 1899{ 1900 int xscaleInt, xscaleFract, yscaleInt, yscaleFract; 1901 int xscaleIntUV, xscaleFractUV; 1902 int yscaleIntUV, yscaleFractUV; 1903 uint32_t newval; 1904 Bool scaleChanged = FALSE; 1905 1906 /* 1907 * Y down-scale factor as a multiple of 4096. 1908 */ 1909 xscaleFract = ((src_w - 1) << 12) / drw_w; 1910 yscaleFract = ((src_h - 1) << 12) / drw_h; 1911 1912 /* Calculate the UV scaling factor. 1913 * UV is half the size of Y -- YUV420 */ 1914 xscaleFractUV = xscaleFract / 2; 1915 yscaleFractUV = yscaleFract / 2; 1916 1917 /* 1918 * To keep the relative Y and UV ratios exact, round the Y scales 1919 * to a multiple of the Y/UV ratio. 1920 */ 1921 xscaleFract = xscaleFractUV * 2; 1922 yscaleFract = yscaleFractUV * 2; 1923 1924 /* Integer (un-multiplied) values. */ 1925 xscaleInt = xscaleFract >> 12; 1926 yscaleInt = yscaleFract >> 12; 1927 1928 xscaleIntUV = xscaleFractUV >> 12; 1929 yscaleIntUV = yscaleFractUV >> 12; 1930 1931 OVERLAY_DEBUG("xscale: %x.%03x, yscale: %x.%03x\n", xscaleInt, 1932 xscaleFract & 0xFFF, yscaleInt, yscaleFract & 0xFFF); 1933 OVERLAY_DEBUG("UV xscale: %x.%03x, UV yscale: %x.%03x\n", xscaleIntUV, 1934 xscaleFractUV & 0xFFF, yscaleIntUV, yscaleFractUV & 0xFFF); 1935 1936 /* shouldn't get here */ 1937 if (xscaleInt > 7) { 1938 OVERLAY_DEBUG("xscale: bad scale\n"); 1939 return FALSE; 1940 } 1941 1942 /* shouldn't get here */ 1943 if (xscaleIntUV > 7) { 1944 OVERLAY_DEBUG("xscaleUV: bad scale\n"); 1945 return FALSE; 1946 } 1947 1948 newval = (xscaleInt << 16) | 1949 ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20); 1950 if (newval != overlay->YRGBSCALE) { 1951 scaleChanged = TRUE; 1952 overlay->YRGBSCALE = newval; 1953 } 1954 1955 newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) | 1956 ((yscaleFractUV & 0xFFF) << 20); 1957 if (newval != overlay->UVSCALE) { 1958 scaleChanged = TRUE; 1959 overlay->UVSCALE = newval; 1960 } 1961 1962 newval = yscaleInt << 16 | yscaleIntUV; 1963 if (newval != overlay->UVSCALEV) { 1964 scaleChanged = TRUE; 1965 overlay->UVSCALEV = newval; 1966 } 1967 1968 if (scaleChanged) { 1969 i830_update_polyphase_coeffs(overlay, xscaleFract, xscaleFractUV); 1970 } 1971 1972 return scaleChanged; 1973} 1974 1975static void 1976i830_display_video(ScrnInfoPtr pScrn, xf86CrtcPtr crtc, 1977 int id, short width, short height, 1978 int dstPitch, int x1, int y1, int x2, int y2, BoxPtr dstBox, 1979 short src_w, short src_h, short drw_w, short drw_h) 1980{ 1981 I830Ptr pI830 = I830PTR(pScrn); 1982 I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr; 1983 I830OverlayRegPtr overlay = I830OVERLAYREG(pI830); 1984 unsigned int swidth, swidthy, swidthuv; 1985 unsigned int mask, shift, offsety, offsetu; 1986 int tmp; 1987 uint32_t OCMD; 1988 Bool scaleChanged = FALSE; 1989 1990 OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height, 1991 dstPitch); 1992 1993#if VIDEO_DEBUG 1994 CompareOverlay(pI830, (uint32_t *) overlay, 0x100); 1995#endif 1996 1997 /* 1998 * If the video isn't visible on any CRTC, turn it off 1999 */ 2000 if (!crtc) 2001 { 2002 pPriv->current_crtc = NULL; 2003 i830_overlay_off (pScrn); 2004 return; 2005 } 2006 2007 if (crtc != pPriv->current_crtc) 2008 { 2009 i830_overlay_switch_to_crtc (pScrn, crtc); 2010 if (pPriv->overlayOK) { 2011 pPriv->current_crtc = crtc; 2012 I830ResetVideo (pScrn); 2013 } 2014 } 2015 2016 if (!pPriv->overlayOK) 2017 return; 2018 2019 i830_update_dst_box_to_crtc_coords(pScrn, crtc, dstBox); 2020 2021 if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 2022 tmp = width; 2023 width = height; 2024 height = tmp; 2025 tmp = drw_w; 2026 drw_w = drw_h; 2027 drw_h = tmp; 2028 tmp = src_w; 2029 src_w = src_h; 2030 src_h = tmp; 2031 } 2032 2033 if (pPriv->oneLineMode) { 2034 /* change the coordinates with panel fitting active */ 2035 dstBox->y1 = (((dstBox->y1 - 1) * pPriv->scaleRatio) >> 16) + 1; 2036 dstBox->y2 = ((dstBox->y2 * pPriv->scaleRatio) >> 16) + 1; 2037 2038 /* Now, alter the height, so we scale to the correct size */ 2039 drw_h = ((drw_h * pPriv->scaleRatio) >> 16) + 1; 2040 } 2041 2042 if (IS_I9XX(pI830)) { 2043 shift = 6; 2044 mask = 0x3f; 2045 } else { 2046 shift = 5; 2047 mask = 0x1f; 2048 } 2049 2050 if (pPriv->currentBuf == 0) { 2051 offsety = pPriv->YBuf0offset; 2052 offsetu = pPriv->UBuf0offset; 2053 } else { 2054 offsety = pPriv->YBuf1offset; 2055 offsetu = pPriv->UBuf1offset; 2056 } 2057 2058 switch (id) { 2059 case FOURCC_YV12: 2060 case FOURCC_I420: 2061 overlay->SWIDTH = width | ((width/2 & 0x7ff) << 16); 2062 swidthy = i830_swidth (pI830, offsety, width, mask, shift); 2063 swidthuv = i830_swidth (pI830, offsetu, width/2, mask, shift); 2064 overlay->SWIDTHSW = (swidthy) | (swidthuv << 16); 2065 overlay->SHEIGHT = height | ((height / 2) << 16); 2066 break; 2067 case FOURCC_UYVY: 2068 case FOURCC_YUY2: 2069 default: 2070 overlay->SWIDTH = width; 2071 swidth = ((offsety + (width << 1) + mask) >> shift) - 2072 (offsety >> shift); 2073 2074 if (IS_I9XX(pI830)) 2075 swidth <<= 1; 2076 2077 swidth -= 1; 2078 2079 swidth <<= 2; 2080 2081 OVERLAY_DEBUG("swidthsw is old %d new %d\n", 2082 swidth, 2083 i830_swidth (pI830, offsety, width << 1, 2084 mask, shift)); 2085 2086 overlay->SWIDTHSW = swidth; 2087 overlay->SHEIGHT = height; 2088 break; 2089 } 2090 2091 overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1; 2092 2093 overlay->DWINSZ = (((dstBox->y2 - dstBox->y1) << 16) | 2094 (dstBox->x2 - dstBox->x1)); 2095 2096 OVERLAY_DEBUG("dstBox: x1: %d, y1: %d, x2: %d, y2: %d\n", 2097 dstBox->x1, dstBox->y1, dstBox->x2, dstBox->y2); 2098 2099 /* buffer locations */ 2100 overlay->OBUF_0Y = pPriv->YBuf0offset; 2101 overlay->OBUF_0U = pPriv->UBuf0offset; 2102 overlay->OBUF_0V = pPriv->VBuf0offset; 2103 if(pPriv->doubleBuffer) { 2104 overlay->OBUF_1Y = pPriv->YBuf1offset; 2105 overlay->OBUF_1U = pPriv->UBuf1offset; 2106 overlay->OBUF_1V = pPriv->VBuf1offset; 2107 } 2108 2109 OVERLAY_DEBUG("pos: 0x%x, size: 0x%x\n", 2110 overlay->DWINPOS, overlay->DWINSZ); 2111 OVERLAY_DEBUG("dst: %d x %d, src: %d x %d\n", drw_w, drw_h, src_w, src_h); 2112 2113 scaleChanged = i830_update_scaling_factors(overlay, 2114 src_w, src_h, drw_w, drw_h); 2115 2116 OCMD = OVERLAY_ENABLE; 2117 2118 switch (id) { 2119 case FOURCC_YV12: 2120 case FOURCC_I420: 2121#ifdef INTEL_XVMC 2122 case FOURCC_XVMC: 2123#endif 2124 OVERLAY_DEBUG("YUV420\n"); 2125#if 0 2126 /* set UV vertical phase to -0.25 */ 2127 overlay->UV_VPH = 0x30003000; 2128#endif 2129 OVERLAY_DEBUG("UV stride is %d, Y stride is %d\n", 2130 dstPitch, dstPitch * 2); 2131 overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16); 2132 OCMD &= ~SOURCE_FORMAT; 2133 OCMD &= ~OV_BYTE_ORDER; 2134 OCMD |= YUV_420; 2135 break; 2136 case FOURCC_UYVY: 2137 case FOURCC_YUY2: 2138 OVERLAY_DEBUG("YUV422\n"); 2139 overlay->OSTRIDE = dstPitch; 2140 OCMD &= ~SOURCE_FORMAT; 2141 OCMD |= YUV_422; 2142 OCMD &= ~OV_BYTE_ORDER; 2143 if (id == FOURCC_UYVY) 2144 OCMD |= Y_SWAP; 2145 break; 2146 } 2147 2148 OCMD &= ~(BUFFER_SELECT | FIELD_SELECT); 2149 if (pPriv->currentBuf == 0) 2150 OCMD |= BUFFER0; 2151 else 2152 OCMD |= BUFFER1; 2153 2154 overlay->OCMD = OCMD; 2155 OVERLAY_DEBUG("OCMD is 0x%x\n", OCMD); 2156 2157 /* make sure the overlay is on */ 2158 i830_overlay_on (pScrn); 2159 /* and show this frame */ 2160 i830_overlay_continue (pScrn, scaleChanged); 2161} 2162 2163static Bool 2164i830_clip_video_helper (ScrnInfoPtr pScrn, 2165 I830PortPrivPtr pPriv, 2166 xf86CrtcPtr *crtc_ret, 2167 BoxPtr dst, 2168 INT32 *xa, 2169 INT32 *xb, 2170 INT32 *ya, 2171 INT32 *yb, 2172 RegionPtr reg, 2173 INT32 width, 2174 INT32 height) 2175{ 2176 Bool ret; 2177 RegionRec crtc_region_local; 2178 RegionPtr crtc_region = reg; 2179 2180 /* 2181 * For overlay video, compute the relevant CRTC and 2182 * clip video to that 2183 */ 2184 if (crtc_ret) 2185 { 2186 BoxRec crtc_box; 2187 xf86CrtcPtr crtc = i830_covering_crtc (pScrn, dst, 2188 pPriv->desired_crtc, 2189 &crtc_box); 2190 2191 /* For textured video, we don't actually want to clip at all. */ 2192 if (crtc && !pPriv->textured) 2193 { 2194 REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1); 2195 crtc_region = &crtc_region_local; 2196 REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg); 2197 } 2198 *crtc_ret = crtc; 2199 } 2200 ret = xf86XVClipVideoHelper (dst, xa, xb, ya, yb, 2201 crtc_region, width, height); 2202 if (crtc_region != reg) 2203 REGION_UNINIT (pScreen, &crtc_region_local); 2204 return ret; 2205} 2206 2207/* 2208 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). 2209 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). 2210 * id is a fourcc code for the format of the video. 2211 * buf is the pointer to the source data in system memory. 2212 * width and height are the w/h of the source data. 2213 * If "sync" is TRUE, then we must be finished with *buf at the point of return 2214 * (which we always are). 2215 * clipBoxes is the clipping region in screen space. 2216 * data is a pointer to our port private. 2217 * pDraw is a Drawable, which might not be the screen in the case of 2218 * compositing. It's a new argument to the function in the 1.1 server. 2219 */ 2220static int 2221I830PutImage(ScrnInfoPtr pScrn, 2222 short src_x, short src_y, 2223 short drw_x, short drw_y, 2224 short src_w, short src_h, 2225 short drw_w, short drw_h, 2226 int id, unsigned char *buf, 2227 short width, short height, 2228 Bool sync, RegionPtr clipBoxes, pointer data, 2229 DrawablePtr pDraw) 2230{ 2231 I830Ptr pI830 = I830PTR(pScrn); 2232 I830PortPrivPtr pPriv = (I830PortPrivPtr) data; 2233 ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; 2234 I830OverlayRegPtr overlay; 2235 PixmapPtr pPixmap = get_drawable_pixmap(pDraw);; 2236 INT32 x1, x2, y1, y2; 2237 int srcPitch = 0, srcPitch2 = 0, dstPitch, destId; 2238 int dstPitch2 = 0; 2239 int top, left, npixels, nlines, size; 2240 BoxRec dstBox; 2241 int pitchAlignMask; 2242 int alloc_size; 2243 xf86CrtcPtr crtc; 2244 2245 if (pPriv->textured) 2246 overlay = NULL; 2247 else 2248 overlay = I830OVERLAYREG(pI830); 2249 2250#if 0 2251 ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" 2252 "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, drw_y, 2253 drw_w, drw_h, width, height); 2254#endif 2255 2256 if (!pPriv->textured) { 2257 /* If dst width and height are less than 1/8th the src size, the 2258 * src/dst scale factor becomes larger than 8 and doesn't fit in 2259 * the scale register. */ 2260 if(src_w >= (drw_w * 8)) 2261 drw_w = src_w/7; 2262 2263 if(src_h >= (drw_h * 8)) 2264 drw_h = src_h/7; 2265 } 2266 2267 /* Clip */ 2268 x1 = src_x; 2269 x2 = src_x + src_w; 2270 y1 = src_y; 2271 y2 = src_y + src_h; 2272 2273 dstBox.x1 = drw_x; 2274 dstBox.x2 = drw_x + drw_w; 2275 dstBox.y1 = drw_y; 2276 dstBox.y2 = drw_y + drw_h; 2277 2278 if (!i830_clip_video_helper(pScrn, 2279 pPriv, 2280 &crtc, 2281 &dstBox, &x1, &x2, &y1, &y2, clipBoxes, 2282 width, height)) 2283 return Success; 2284 2285 if (!pPriv->textured) { 2286 /* texture video handles rotation differently. */ 2287 if (crtc) 2288 pPriv->rotation = crtc->rotation; 2289 else { 2290 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2291 "Fail to clip video to any crtc!\n"); 2292 return Success; 2293 } 2294 } 2295 2296 destId = id; 2297 switch (id) { 2298 case FOURCC_YV12: 2299 case FOURCC_I420: 2300 srcPitch = (width + 0x3) & ~0x3; 2301 srcPitch2 = ((width >> 1) + 0x3) & ~0x3; 2302 break; 2303#ifdef INTEL_XVMC 2304 case FOURCC_XVMC: 2305 srcPitch = (width + 0x3) & ~0x3; 2306 srcPitch2 = ((width >> 1) + 0x3) & ~0x3; 2307 break; 2308#endif 2309 case FOURCC_UYVY: 2310 case FOURCC_YUY2: 2311 default: 2312 srcPitch = width << 1; 2313 break; 2314 } 2315 2316 /* Only needs to be DWORD-aligned for textured on i915, but overlay has 2317 * stricter requirements. 2318 */ 2319 if (pPriv->textured) { 2320 pitchAlignMask = 3; 2321#ifdef INTEL_XVMC 2322 /* for i915 xvmc, hw requires at least 1kb aligned surface */ 2323 if ((id == FOURCC_XVMC) && IS_I915(pI830)) 2324 pitchAlignMask = 0x3ff; 2325#endif 2326 } else { 2327 if (IS_I965G(pI830)) 2328 pitchAlignMask = 255; 2329 else 2330 pitchAlignMask = 63; 2331 } 2332 2333 /* Determine the desired destination pitch (representing the chroma's pitch, 2334 * in the planar case. 2335 */ 2336 switch (destId) { 2337 case FOURCC_YV12: 2338 case FOURCC_I420: 2339 if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 2340 dstPitch = ((height / 2) + pitchAlignMask) & ~pitchAlignMask; 2341 size = dstPitch * width * 3; 2342 } else { 2343 dstPitch = ((width / 2) + pitchAlignMask) & ~pitchAlignMask; 2344 size = dstPitch * height * 3; 2345 } 2346 break; 2347 case FOURCC_UYVY: 2348 case FOURCC_YUY2: 2349 2350 if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 2351 dstPitch = ((height << 1) + pitchAlignMask) & ~pitchAlignMask; 2352 size = dstPitch * width; 2353 } else { 2354 dstPitch = ((width << 1) + pitchAlignMask) & ~pitchAlignMask; 2355 size = dstPitch * height; 2356 } 2357 break; 2358#ifdef INTEL_XVMC 2359 case FOURCC_XVMC: 2360 dstPitch = ((width / 2) + pitchAlignMask ) & ~pitchAlignMask; 2361 dstPitch2 = (width + pitchAlignMask ) & ~pitchAlignMask; 2362 size = 0; 2363 break; 2364#endif 2365 default: 2366 dstPitch = 0; 2367 size = 0; 2368 break; 2369 } 2370#if 0 2371 ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, dstPitch, size); 2372#endif 2373 2374 alloc_size = size; 2375 if (pPriv->doubleBuffer) 2376 alloc_size *= 2; 2377 2378 /* Free the current buffer if we're going to have to reallocate */ 2379 if (pPriv->buf && pPriv->buf->size < alloc_size) { 2380 if (!pPriv->textured) 2381 drm_intel_bo_unpin(pPriv->buf); 2382 drm_intel_bo_unreference(pPriv->buf); 2383 pPriv->buf = NULL; 2384 } 2385 2386#ifdef INTEL_XVMC 2387 if (id == FOURCC_XVMC && 2388 pPriv->rotation == RR_Rotate_0) { 2389 if (pPriv->buf) { 2390 assert(pPriv->textured); 2391 drm_intel_bo_unreference(pPriv->buf); 2392 pPriv->buf = NULL; 2393 } 2394 } else { 2395#endif 2396 if (pPriv->buf == NULL) { 2397 pPriv->buf = drm_intel_bo_alloc(pI830->bufmgr, 2398 "xv buffer", alloc_size, 4096); 2399 if (pPriv->buf == NULL) 2400 return BadAlloc; 2401 if (!pPriv->textured && drm_intel_bo_pin(pPriv->buf, 4096) != 0) { 2402 drm_intel_bo_unreference(pPriv->buf); 2403 pPriv->buf = NULL; 2404 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 2405 "Failed to pin xv buffer\n"); 2406 return BadAlloc; 2407 } 2408 } 2409#ifdef INTEL_XVMC 2410 } 2411#endif 2412 2413 /* fixup pointers */ 2414#ifdef INTEL_XVMC 2415 if (id == FOURCC_XVMC && IS_I915(pI830)) { 2416 pPriv->YBuf0offset = (uint32_t)((uintptr_t)buf); 2417 pPriv->VBuf0offset = pPriv->YBuf0offset + (dstPitch2 * height); 2418 pPriv->UBuf0offset = pPriv->VBuf0offset + (dstPitch * height / 2); 2419 destId = FOURCC_YV12; 2420 } else { 2421#endif 2422 if (pPriv->textured) 2423 pPriv->YBuf0offset = 0; 2424 else 2425 pPriv->YBuf0offset = pPriv->buf->offset; 2426 2427 if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 2428 pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * width); 2429 pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * width / 2); 2430 if(pPriv->doubleBuffer) { 2431 pPriv->YBuf1offset = pPriv->YBuf0offset + size; 2432 pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * width); 2433 pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * width / 2); 2434 } 2435 } else { 2436 pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height); 2437 pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height / 2); 2438 if(pPriv->doubleBuffer) { 2439 pPriv->YBuf1offset = pPriv->YBuf0offset + size; 2440 pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height); 2441 pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height / 2); 2442 } 2443 } 2444#ifdef INTEL_XVMC 2445 } 2446#endif 2447 2448 /* Pick the idle buffer */ 2449 if (!pPriv->textured && pI830->overlayOn && pPriv->doubleBuffer) 2450 pPriv->currentBuf = !((INREG(DOVSTA) & OC_BUF) >> 20); 2451 2452 /* copy data */ 2453 top = y1 >> 16; 2454 left = (x1 >> 16) & ~1; 2455 npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left; 2456 2457 switch (id) { 2458 case FOURCC_YV12: 2459 case FOURCC_I420: 2460 top &= ~1; 2461 nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; 2462 I830CopyPlanarData(pScrn, pPriv, buf, srcPitch, srcPitch2, dstPitch, 2463 height, top, left, nlines, npixels, id); 2464 break; 2465 case FOURCC_UYVY: 2466 case FOURCC_YUY2: 2467 nlines = ((y2 + 0xffff) >> 16) - top; 2468 I830CopyPackedData(pScrn, pPriv, buf, srcPitch, dstPitch, top, left, 2469 nlines, npixels); 2470 break; 2471#ifdef INTEL_XVMC 2472 case FOURCC_XVMC: 2473 if (pPriv->rotation != RR_Rotate_0) { 2474 top &= ~1; 2475 nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top; 2476 I830CopyPlanarData(pScrn, pPriv, buf, srcPitch, srcPitch2, dstPitch, 2477 height, top, left, nlines, npixels, id); 2478 } 2479 2480 break; 2481#endif 2482 default: 2483 break; 2484 } 2485 2486 if (!pPriv->textured) { 2487 i830_display_video(pScrn, crtc, destId, width, height, dstPitch, 2488 x1, y1, x2, y2, &dstBox, src_w, src_h, 2489 drw_w, drw_h); 2490 2491 /* update cliplist */ 2492 if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) { 2493 REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes); 2494 xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes); 2495 } 2496 } else { 2497 Bool sync = TRUE; 2498 2499 if (crtc == NULL) { 2500 sync = FALSE; 2501 } else if (pPriv->SyncToVblank == 0) { 2502 sync = FALSE; 2503 } 2504 2505 if (sync) { 2506 BoxPtr box; 2507 pixman_box16_t box_in_crtc_coordinates; 2508 int pipe = -1, event, load_scan_lines_pipe; 2509 2510 if (pixmap_is_scanout(pPixmap)) 2511 pipe = i830_crtc_to_pipe(crtc); 2512 2513 if (pipe >= 0) { 2514 if (pipe == 0) { 2515 event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 2516 load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 2517 } else { 2518 event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 2519 load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 2520 } 2521 2522 box = REGION_EXTENTS(unused, clipBoxes); 2523 box_in_crtc_coordinates = *box; 2524 if (crtc->transform_in_use) 2525 pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &box_in_crtc_coordinates); 2526 2527 BEGIN_BATCH(5); 2528 /* The documentation says that the LOAD_SCAN_LINES command 2529 * always comes in pairs. Don't ask me why. */ 2530 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe); 2531 OUT_BATCH((box_in_crtc_coordinates.y1 << 16) | box_in_crtc_coordinates.y2); 2532 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe); 2533 OUT_BATCH((box_in_crtc_coordinates.y1 << 16) | box_in_crtc_coordinates.y2); 2534 OUT_BATCH(MI_WAIT_FOR_EVENT | event); 2535 ADVANCE_BATCH(); 2536 } 2537 } 2538 2539 if (IS_I965G(pI830)) { 2540#ifdef INTEL_XVMC 2541 if (id == FOURCC_XVMC && pPriv->rotation == RR_Rotate_0) { 2542 pPriv->YBuf0offset = buf - pI830->FbBase; 2543 pPriv->UBuf0offset = pPriv->YBuf0offset + height*width; 2544 pPriv->VBuf0offset = pPriv->UBuf0offset + height*width/4; 2545 } 2546#endif 2547 I965DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height, 2548 dstPitch, x1, y1, x2, y2, 2549 src_w, src_h, drw_w, drw_h, pPixmap); 2550 } else { 2551 I915DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height, 2552 dstPitch, dstPitch2, x1, y1, x2, y2, 2553 src_w, src_h, drw_w, drw_h, pPixmap); 2554 } 2555 } 2556 if (pPriv->textured) { 2557 DamageDamageRegion(pDraw, clipBoxes); 2558 } 2559 2560 pPriv->videoStatus = CLIENT_VIDEO_ON; 2561 2562 return Success; 2563} 2564 2565static int 2566I830QueryImageAttributes(ScrnInfoPtr pScrn, 2567 int id, 2568 unsigned short *w, unsigned short *h, 2569 int *pitches, int *offsets) 2570{ 2571 I830Ptr pI830 = I830PTR(pScrn); 2572 int size, tmp; 2573 2574#if 0 2575 ErrorF("I830QueryImageAttributes: w is %d, h is %d\n", *w, *h); 2576#endif 2577 2578 if (IS_845G(pI830) || IS_I830(pI830)) { 2579 if (*w > IMAGE_MAX_WIDTH_LEGACY) 2580 *w = IMAGE_MAX_WIDTH_LEGACY; 2581 if (*h > IMAGE_MAX_HEIGHT_LEGACY) 2582 *h = IMAGE_MAX_HEIGHT_LEGACY; 2583 } else { 2584 if (*w > IMAGE_MAX_WIDTH) 2585 *w = IMAGE_MAX_WIDTH; 2586 if (*h > IMAGE_MAX_HEIGHT) 2587 *h = IMAGE_MAX_HEIGHT; 2588 } 2589 2590 *w = (*w + 1) & ~1; 2591 if (offsets) 2592 offsets[0] = 0; 2593 2594 switch (id) { 2595 /* IA44 is for XvMC only */ 2596 case FOURCC_IA44: 2597 case FOURCC_AI44: 2598 if (pitches) 2599 pitches[0] = *w; 2600 size = *w * *h; 2601 break; 2602 case FOURCC_YV12: 2603 case FOURCC_I420: 2604 *h = (*h + 1) & ~1; 2605 size = (*w + 3) & ~3; 2606 if (pitches) 2607 pitches[0] = size; 2608 size *= *h; 2609 if (offsets) 2610 offsets[1] = size; 2611 tmp = ((*w >> 1) + 3) & ~3; 2612 if (pitches) 2613 pitches[1] = pitches[2] = tmp; 2614 tmp *= (*h >> 1); 2615 size += tmp; 2616 if (offsets) 2617 offsets[2] = size; 2618 size += tmp; 2619#if 0 2620 if (pitches) 2621 ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", pitches[0], 2622 pitches[1], pitches[2]); 2623 if (offsets) 2624 ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], offsets[2]); 2625 if (offsets) 2626 ErrorF("size is %d\n", size); 2627#endif 2628 break; 2629#ifdef INTEL_XVMC 2630 case FOURCC_XVMC: 2631 *h = (*h + 1) & ~1; 2632 size = sizeof(struct intel_xvmc_command); 2633 if (pitches) 2634 pitches[0] = size; 2635 break; 2636#endif 2637 case FOURCC_UYVY: 2638 case FOURCC_YUY2: 2639 default: 2640 size = *w << 1; 2641 if (pitches) 2642 pitches[0] = size; 2643 size *= *h; 2644 break; 2645 } 2646 2647 return size; 2648} 2649 2650void 2651I830VideoBlockHandler(int i, pointer blockData, pointer pTimeout, 2652 pointer pReadmask) 2653{ 2654 ScrnInfoPtr pScrn = xf86Screens[i]; 2655 I830Ptr pI830 = I830PTR(pScrn); 2656 I830PortPrivPtr pPriv; 2657 2658 /* no overlay */ 2659 if (pI830->adaptor == NULL) 2660 return; 2661 2662 pPriv = GET_PORT_PRIVATE(pScrn); 2663 2664 if (pPriv->videoStatus & TIMER_MASK) { 2665#if 1 2666 Time now = currentTime.milliseconds; 2667#else 2668 UpdateCurrentTime(); 2669#endif 2670 if (pPriv->videoStatus & OFF_TIMER) { 2671 if (pPriv->offTime < now) { 2672 /* Turn off the overlay */ 2673 OVERLAY_DEBUG("BLOCKHANDLER\n"); 2674 2675 i830_overlay_off (pScrn); 2676 2677 pPriv->videoStatus = FREE_TIMER; 2678 pPriv->freeTime = now + FREE_DELAY; 2679 } 2680 } else { /* FREE_TIMER */ 2681 if (pPriv->freeTime < now) { 2682 if (!pPriv->textured) 2683 drm_intel_bo_unpin(pPriv->buf); 2684 drm_intel_bo_unreference(pPriv->buf); 2685 pPriv->buf = NULL; 2686 pPriv->videoStatus = 0; 2687 } 2688 } 2689 } 2690} 2691 2692/*************************************************************************** 2693 * Offscreen Images 2694 ***************************************************************************/ 2695 2696typedef struct { 2697 Bool isOn; 2698} OffscreenPrivRec, *OffscreenPrivPtr; 2699 2700static int 2701I830AllocateSurface(ScrnInfoPtr pScrn, 2702 int id, 2703 unsigned short w, 2704 unsigned short h, XF86SurfacePtr surface) 2705{ 2706 int pitch, fbpitch, size; 2707 OffscreenPrivPtr pPriv; 2708 I830Ptr pI830 = I830PTR(pScrn); 2709 2710 OVERLAY_DEBUG("I830AllocateSurface\n"); 2711 2712 if (IS_845G(pI830) || IS_I830(pI830)) { 2713 if ((w > IMAGE_MAX_WIDTH_LEGACY) || (h > IMAGE_MAX_HEIGHT_LEGACY)) 2714 return BadAlloc; 2715 } else { 2716 if ((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT)) 2717 return BadAlloc; 2718 } 2719 2720 if (!(surface->pitches = xalloc(sizeof(int)))) 2721 return BadAlloc; 2722 if (!(surface->offsets = xalloc(sizeof(int)))) { 2723 xfree(surface->pitches); 2724 return BadAlloc; 2725 } 2726 if (!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) { 2727 xfree(surface->pitches); 2728 xfree(surface->offsets); 2729 return BadAlloc; 2730 } 2731 2732 w = (w + 1) & ~1; 2733 pitch = ((w << 1) + 15) & ~15; 2734 fbpitch = pI830->cpp * pScrn->displayWidth; 2735 size = pitch * h; 2736 2737 surface->width = w; 2738 surface->height = h; 2739 2740 pPriv->isOn = FALSE; 2741 2742 surface->pScrn = pScrn; 2743 surface->id = id; 2744 surface->pitches[0] = pitch; 2745 surface->offsets[0] = 0; 2746 surface->devPrivate.ptr = (pointer) pPriv; 2747 2748 return Success; 2749} 2750 2751static int 2752I830StopSurface(XF86SurfacePtr surface) 2753{ 2754 OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr; 2755 ScrnInfoPtr pScrn = surface->pScrn; 2756 2757 if (pPriv->isOn) { 2758 OVERLAY_DEBUG("StopSurface\n"); 2759 2760 i830_overlay_off (pScrn); 2761 2762 pPriv->isOn = FALSE; 2763 } 2764 2765 return Success; 2766} 2767 2768static int 2769I830FreeSurface(XF86SurfacePtr surface) 2770{ 2771 I830StopSurface(surface); 2772 xfree(surface->pitches); 2773 xfree(surface->offsets); 2774 xfree(surface->devPrivate.ptr); 2775 2776 return Success; 2777} 2778 2779static int 2780I830GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 * value) 2781{ 2782 return I830GetPortAttribute(pScrn, attribute, value, NULL); 2783} 2784 2785static int 2786I830SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value) 2787{ 2788 return I830SetPortAttributeOverlay(pScrn, attribute, value, NULL); 2789} 2790 2791static int 2792I830DisplaySurface(XF86SurfacePtr surface, 2793 short src_x, short src_y, 2794 short drw_x, short drw_y, 2795 short src_w, short src_h, 2796 short drw_w, short drw_h, RegionPtr clipBoxes) 2797{ 2798 OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr; 2799 ScrnInfoPtr pScrn = surface->pScrn; 2800 ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; 2801 I830Ptr pI830 = I830PTR(pScrn); 2802 I830PortPrivPtr pI830Priv = GET_PORT_PRIVATE(pScrn); 2803 INT32 x1, y1, x2, y2; 2804 BoxRec dstBox; 2805 xf86CrtcPtr crtc; 2806 2807 OVERLAY_DEBUG("I830DisplaySurface\n"); 2808 2809 x1 = src_x; 2810 x2 = src_x + src_w; 2811 y1 = src_y; 2812 y2 = src_y + src_h; 2813 2814 dstBox.x1 = drw_x; 2815 dstBox.x2 = drw_x + drw_w; 2816 dstBox.y1 = drw_y; 2817 dstBox.y2 = drw_y + drw_h; 2818 2819 if (!i830_clip_video_helper (pScrn, pI830Priv, &crtc, &dstBox, 2820 &x1, &x2, &y1, &y2, clipBoxes, 2821 surface->width, surface->height)) 2822 return Success; 2823 2824 /* fixup pointers */ 2825 pI830Priv->YBuf0offset = surface->offsets[0]; 2826 pI830Priv->YBuf1offset = pI830Priv->YBuf0offset; 2827 2828 /* Pick the idle buffer */ 2829 if (!pI830Priv->textured && pI830->overlayOn && pI830Priv->doubleBuffer) 2830 pI830Priv->currentBuf = !((INREG(DOVSTA) & OC_BUF) >> 20); 2831 2832 i830_display_video(pScrn, crtc, surface->id, surface->width, surface->height, 2833 surface->pitches[0], x1, y1, x2, y2, &dstBox, 2834 src_w, src_h, drw_w, drw_h); 2835 2836 xf86XVFillKeyHelper(pScrn->pScreen, pI830Priv->colorKey, clipBoxes); 2837 2838 pPriv->isOn = TRUE; 2839 /* we've prempted the XvImage stream so set its free timer */ 2840 if (pI830Priv->videoStatus & CLIENT_VIDEO_ON) { 2841 REGION_EMPTY(pScrn->pScreen, &pI830Priv->clip); 2842 UpdateCurrentTime(); 2843 pI830Priv->videoStatus = FREE_TIMER; 2844 pI830Priv->freeTime = currentTime.milliseconds + FREE_DELAY; 2845 } 2846 2847 return Success; 2848} 2849 2850static void 2851I830InitOffscreenImages(ScreenPtr pScreen) 2852{ 2853 XF86OffscreenImagePtr offscreenImages; 2854 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 2855 I830Ptr pI830 = I830PTR(pScrn); 2856 2857 if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) { 2858 return; 2859 } 2860 2861 pI830->offscreenImages = offscreenImages; 2862 2863 offscreenImages[0].image = &Images[0]; 2864 offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/; 2865 offscreenImages[0].alloc_surface = I830AllocateSurface; 2866 offscreenImages[0].free_surface = I830FreeSurface; 2867 offscreenImages[0].display = I830DisplaySurface; 2868 offscreenImages[0].stop = I830StopSurface; 2869 offscreenImages[0].setAttribute = I830SetSurfaceAttribute; 2870 offscreenImages[0].getAttribute = I830GetSurfaceAttribute; 2871 if (IS_845G(pI830) || IS_I830(pI830)) { 2872 offscreenImages[0].max_width = IMAGE_MAX_WIDTH_LEGACY; 2873 offscreenImages[0].max_height = IMAGE_MAX_HEIGHT_LEGACY; 2874 } else { 2875 offscreenImages[0].max_width = IMAGE_MAX_WIDTH; 2876 offscreenImages[0].max_height = IMAGE_MAX_HEIGHT; 2877 } 2878 offscreenImages[0].num_attributes = 1; 2879 offscreenImages[0].attributes = Attributes; 2880 2881 xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1); 2882} 2883 2884void 2885i830_crtc_dpms_video(xf86CrtcPtr crtc, Bool on) 2886{ 2887 ScrnInfoPtr pScrn = crtc->scrn; 2888 I830Ptr pI830 = I830PTR(pScrn); 2889 I830PortPrivPtr pPriv; 2890 2891 /* no overlay */ 2892 if (pI830->adaptor == NULL) 2893 return; 2894 2895 pPriv = GET_PORT_PRIVATE(pScrn); 2896 2897 if (crtc != pPriv->current_crtc) 2898 return; 2899 2900 /* Check if it's the crtc the overlay is off */ 2901 if (!on) { 2902 /* We stop the video when mode switching, so we don't lock up 2903 * the engine. The overlayOK will determine whether we can re-enable 2904 * with the current video on completion of the mode switch. 2905 */ 2906 I830StopVideo(pScrn, pPriv, TRUE); 2907 pPriv->current_crtc = NULL; 2908 pPriv->overlayOK = FALSE; 2909 pPriv->oneLineMode = FALSE; 2910 } 2911} 2912