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#include "intel_video_overlay.h" 77 78/* overlay debugging printf function */ 79#if 0 80#define OVERLAY_DEBUG ErrorF 81#else 82#define OVERLAY_DEBUG if (0) ErrorF 83#endif 84 85/* kernel modesetting overlay functions */ 86static Bool intel_has_overlay(intel_screen_private *intel) 87{ 88 struct drm_i915_getparam gp; 89 int has_overlay = 0; 90 int ret; 91 92 gp.param = I915_PARAM_HAS_OVERLAY; 93 gp.value = &has_overlay; 94 ret = drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, sizeof(gp)); 95 96 return ret == 0 && !! has_overlay; 97} 98 99static Bool intel_overlay_update_attrs(intel_screen_private *intel) 100{ 101 intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); 102 struct drm_intel_overlay_attrs attrs; 103 104 attrs.flags = I915_OVERLAY_UPDATE_ATTRS; 105 attrs.brightness = adaptor_priv->brightness; 106 attrs.contrast = adaptor_priv->contrast; 107 attrs.saturation = adaptor_priv->saturation; 108 attrs.color_key = adaptor_priv->colorKey; 109 attrs.gamma0 = adaptor_priv->gamma0; 110 attrs.gamma1 = adaptor_priv->gamma1; 111 attrs.gamma2 = adaptor_priv->gamma2; 112 attrs.gamma3 = adaptor_priv->gamma3; 113 attrs.gamma4 = adaptor_priv->gamma4; 114 attrs.gamma5 = adaptor_priv->gamma5; 115 116 return drmCommandWriteRead(intel->drmSubFD, DRM_I915_OVERLAY_ATTRS, 117 &attrs, sizeof(attrs)) == 0; 118} 119 120void intel_video_overlay_off(intel_screen_private *intel) 121{ 122 struct drm_intel_overlay_put_image request; 123 int ret; 124 125 request.flags = 0; 126 127 ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, 128 &request, sizeof(request)); 129 (void) ret; 130} 131static int 132intel_video_overlay_set_port_attribute(ScrnInfoPtr scrn, 133 Atom attribute, INT32 value, pointer data) 134{ 135 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 136 intel_screen_private *intel = intel_get_screen_private(scrn); 137 138 if (attribute == intel_xv_Brightness) { 139 if ((value < -128) || (value > 127)) 140 return BadValue; 141 adaptor_priv->brightness = value; 142 OVERLAY_DEBUG("BRIGHTNESS\n"); 143 } else if (attribute == intel_xv_Contrast) { 144 if ((value < 0) || (value > 255)) 145 return BadValue; 146 adaptor_priv->contrast = value; 147 OVERLAY_DEBUG("CONTRAST\n"); 148 } else if (attribute == intel_xv_Saturation) { 149 if ((value < 0) || (value > 1023)) 150 return BadValue; 151 adaptor_priv->saturation = value; 152 } else if (attribute == intel_xv_Pipe) { 153 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 154 if ((value < -1) || (value >= xf86_config->num_crtc)) 155 return BadValue; 156 if (value < 0) 157 adaptor_priv->desired_crtc = NULL; 158 else 159 adaptor_priv->desired_crtc = xf86_config->crtc[value]; 160 } else if (attribute == intel_xv_Gamma0 && (INTEL_INFO(intel)->gen >= 030)) { 161 adaptor_priv->gamma0 = value; 162 } else if (attribute == intel_xv_Gamma1 && (INTEL_INFO(intel)->gen >= 030)) { 163 adaptor_priv->gamma1 = value; 164 } else if (attribute == intel_xv_Gamma2 && (INTEL_INFO(intel)->gen >= 030)) { 165 adaptor_priv->gamma2 = value; 166 } else if (attribute == intel_xv_Gamma3 && (INTEL_INFO(intel)->gen >= 030)) { 167 adaptor_priv->gamma3 = value; 168 } else if (attribute == intel_xv_Gamma4 && (INTEL_INFO(intel)->gen >= 030)) { 169 adaptor_priv->gamma4 = value; 170 } else if (attribute == intel_xv_Gamma5 && (INTEL_INFO(intel)->gen >= 030)) { 171 adaptor_priv->gamma5 = value; 172 } else if (attribute == intel_xv_ColorKey) { 173 adaptor_priv->colorKey = value; 174 OVERLAY_DEBUG("COLORKEY\n"); 175 } else 176 return BadMatch; 177 178 if ((attribute == intel_xv_Gamma0 || 179 attribute == intel_xv_Gamma1 || 180 attribute == intel_xv_Gamma2 || 181 attribute == intel_xv_Gamma3 || 182 attribute == intel_xv_Gamma4 || 183 attribute == intel_xv_Gamma5) && (INTEL_INFO(intel)->gen >= 030)) { 184 OVERLAY_DEBUG("GAMMA\n"); 185 } 186 187 if (!intel_overlay_update_attrs(intel)) 188 return BadValue; 189 190 if (attribute == intel_xv_ColorKey) 191 REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip); 192 193 return Success; 194} 195 196static Bool 197intel_overlay_put_image(intel_screen_private *intel, 198 xf86CrtcPtr crtc, 199 int id, short width, short height, 200 int dstPitch, int dstPitch2, 201 BoxPtr dstBox, short src_w, short src_h, short drw_w, 202 short drw_h) 203{ 204 intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); 205 struct drm_intel_overlay_put_image request; 206 int ret; 207 int planar = is_planar_fourcc(id); 208 float scale; 209 dri_bo *tmp; 210 211 request.flags = I915_OVERLAY_ENABLE; 212 213 request.bo_handle = adaptor_priv->buf->handle; 214 if (planar) { 215 request.stride_Y = dstPitch2; 216 request.stride_UV = dstPitch; 217 } else { 218 request.stride_Y = dstPitch; 219 request.stride_UV = 0; 220 } 221 request.offset_Y = adaptor_priv->YBufOffset; 222 request.offset_U = adaptor_priv->UBufOffset; 223 request.offset_V = adaptor_priv->VBufOffset; 224 OVERLAY_DEBUG("off_Y: %i, off_U: %i, off_V: %i\n", request.offset_Y, 225 request.offset_U, request.offset_V); 226 227 request.crtc_id = intel_crtc_id(crtc); 228 request.dst_x = dstBox->x1; 229 request.dst_y = dstBox->y1; 230 request.dst_width = dstBox->x2 - dstBox->x1; 231 request.dst_height = dstBox->y2 - dstBox->y1; 232 233 request.src_width = width; 234 request.src_height = height; 235 /* adjust src dimensions */ 236 if (request.dst_height > 1) { 237 scale = ((float)request.dst_height - 1) / ((float)drw_h - 1); 238 request.src_scan_height = src_h * scale; 239 } else 240 request.src_scan_height = 1; 241 242 if (request.dst_width > 1) { 243 scale = ((float)request.dst_width - 1) / ((float)drw_w - 1); 244 request.src_scan_width = src_w * scale; 245 } else 246 request.src_scan_width = 1; 247 248 if (planar) { 249 request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420; 250 } else { 251 request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422; 252 if (id == FOURCC_UYVY) 253 request.flags |= I915_OVERLAY_Y_SWAP; 254 } 255 256 ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, 257 &request, sizeof(request)); 258 if (ret) 259 return FALSE; 260 261 if (!adaptor_priv->reusable) { 262 drm_intel_bo_unreference(adaptor_priv->buf); 263 adaptor_priv->buf = NULL; 264 adaptor_priv->reusable = TRUE; 265 } 266 267 tmp = adaptor_priv->old_buf[1]; 268 adaptor_priv->old_buf[1] = adaptor_priv->old_buf[0]; 269 adaptor_priv->old_buf[0] = adaptor_priv->buf; 270 adaptor_priv->buf = tmp; 271 272 return TRUE; 273} 274 275static void 276intel_update_dst_box_to_crtc_coords(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 277 BoxPtr dstBox) 278{ 279 int tmp; 280 281 /* for overlay, we should take it from crtc's screen 282 * coordinate to current crtc's display mode. 283 * yeah, a bit confusing. 284 */ 285 switch (crtc->rotation & 0xf) { 286 case RR_Rotate_0: 287 dstBox->x1 -= crtc->x; 288 dstBox->x2 -= crtc->x; 289 dstBox->y1 -= crtc->y; 290 dstBox->y2 -= crtc->y; 291 break; 292 case RR_Rotate_90: 293 tmp = dstBox->x1; 294 dstBox->x1 = dstBox->y1 - crtc->x; 295 dstBox->y1 = scrn->virtualX - tmp - crtc->y; 296 tmp = dstBox->x2; 297 dstBox->x2 = dstBox->y2 - crtc->x; 298 dstBox->y2 = scrn->virtualX - tmp - crtc->y; 299 tmp = dstBox->y1; 300 dstBox->y1 = dstBox->y2; 301 dstBox->y2 = tmp; 302 break; 303 case RR_Rotate_180: 304 tmp = dstBox->x1; 305 dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x; 306 dstBox->x2 = scrn->virtualX - tmp - crtc->x; 307 tmp = dstBox->y1; 308 dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y; 309 dstBox->y2 = scrn->virtualY - tmp - crtc->y; 310 break; 311 case RR_Rotate_270: 312 tmp = dstBox->x1; 313 dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x; 314 dstBox->y1 = tmp - crtc->y; 315 tmp = dstBox->x2; 316 dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x; 317 dstBox->y2 = tmp - crtc->y; 318 tmp = dstBox->x1; 319 dstBox->x1 = dstBox->x2; 320 dstBox->x2 = tmp; 321 break; 322 } 323 324 return; 325} 326 327static Bool 328intel_video_overlay_display(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 329 int id, short width, short height, 330 int dstPitch, int dstPitch2, 331 BoxPtr dstBox, short src_w, short src_h, short drw_w, 332 short drw_h) 333{ 334 intel_screen_private *intel = intel_get_screen_private(scrn); 335 int tmp; 336 337 OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height, 338 dstPitch); 339 340 /* 341 * If the video isn't visible on any CRTC, turn it off 342 */ 343 if (!crtc) { 344 intel_video_overlay_off(intel); 345 return TRUE; 346 } 347 348 intel_update_dst_box_to_crtc_coords(scrn, crtc, dstBox); 349 350 if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 351 tmp = width; 352 width = height; 353 height = tmp; 354 tmp = drw_w; 355 drw_w = drw_h; 356 drw_h = tmp; 357 tmp = src_w; 358 src_w = src_h; 359 src_h = tmp; 360 } 361 362 return intel_overlay_put_image(intel, crtc, id, 363 width, height, 364 dstPitch, dstPitch2, dstBox, 365 src_w, src_h, drw_w, drw_h); 366} 367 368static int 369intel_video_overlay_put_image(ScrnInfoPtr scrn, 370 short src_x, short src_y, 371 short drw_x, short drw_y, 372 short src_w, short src_h, 373 short drw_w, short drw_h, 374 int id, unsigned char *buf, 375 short width, short height, 376 Bool sync, RegionPtr clipBoxes, pointer data, 377 DrawablePtr drawable) 378{ 379 intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 380 int dstPitch, dstPitch2; 381 BoxRec dstBox; 382 xf86CrtcPtr crtc; 383 int top, left, npixels, nlines; 384 385#if 0 386 ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" 387 "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, 388 drw_y, drw_w, drw_h, width, height); 389#endif 390 391 /* If dst width and height are less than 1/8th the src size, the 392 * src/dst scale factor becomes larger than 8 and doesn't fit in 393 * the scale register. */ 394 if (src_w >= (drw_w * 8)) 395 drw_w = src_w / 7; 396 397 if (src_h >= (drw_h * 8)) 398 drw_h = src_h / 7; 399 400 if (!intel_clip_video_helper(scrn, 401 adaptor_priv, 402 &crtc, 403 &dstBox, 404 src_x, src_y, drw_x, drw_y, 405 src_w, src_h, drw_w, drw_h, 406 id, 407 &top, &left, &npixels, &nlines, clipBoxes, 408 width, height)) 409 return Success; 410 411 /* overlay can't handle rotation natively, store it for the copy func */ 412 if (crtc) 413 adaptor_priv->rotation = crtc->rotation; 414 else { 415 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 416 "Fail to clip video to any crtc!\n"); 417 return Success; 418 } 419 420 if (!intel_video_copy_data(scrn, adaptor_priv, width, height, 421 &dstPitch, &dstPitch2, 422 top, left, npixels, nlines, id, buf)) 423 return BadAlloc; 424 425 if (!intel_video_overlay_display 426 (scrn, crtc, id, width, height, dstPitch, dstPitch2, 427 &dstBox, src_w, src_h, drw_w, drw_h)) 428 return BadAlloc; 429 430 /* update cliplist */ 431 if (!REGION_EQUAL(scrn->pScreen, &adaptor_priv->clip, clipBoxes)) { 432 REGION_COPY(scrn->pScreen, &adaptor_priv->clip, clipBoxes); 433 xf86XVFillKeyHelperDrawable(drawable, 434 adaptor_priv->colorKey, 435 clipBoxes); 436 } 437 438 adaptor_priv->videoStatus = CLIENT_VIDEO_ON; 439 440 return Success; 441} 442 443XF86VideoAdaptorPtr intel_video_overlay_setup_image(ScreenPtr screen) 444{ 445 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 446 intel_screen_private *intel = intel_get_screen_private(scrn); 447 XF86VideoAdaptorPtr adapt; 448 intel_adaptor_private *adaptor_priv; 449 XF86AttributePtr att; 450 451 /* Set up overlay video if it is available */ 452 intel->use_overlay = intel_has_overlay(intel); 453 if (!intel->use_overlay) 454 return NULL; 455 456 OVERLAY_DEBUG("intel_video_overlay_setup_image\n"); 457 458 if (!(adapt = calloc(1, 459 sizeof(XF86VideoAdaptorRec) + 460 sizeof(intel_adaptor_private) + 461 sizeof(DevUnion)))) 462 return NULL; 463 464 adapt->type = XvWindowMask | XvInputMask | XvImageMask; 465 adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ; 466 adapt->name = "Intel(R) Video Overlay"; 467 adapt->nEncodings = 1; 468 adapt->pEncodings = xnfalloc(sizeof(intel_xv_dummy_encoding)); 469 memcpy(adapt->pEncodings, intel_xv_dummy_encoding, sizeof(intel_xv_dummy_encoding)); 470 if (IS_845G(intel) || IS_I830(intel)) { 471 adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY; 472 adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY; 473 } 474 adapt->nFormats = NUM_FORMATS; 475 adapt->pFormats = intel_xv_formats; 476 adapt->nPorts = 1; 477 adapt->pPortPrivates = (DevUnion *) (&adapt[1]); 478 479 adaptor_priv = (intel_adaptor_private *)&adapt->pPortPrivates[1]; 480 481 adapt->pPortPrivates[0].ptr = (pointer) (adaptor_priv); 482 adapt->nAttributes = NUM_ATTRIBUTES; 483 if (INTEL_INFO(intel)->gen >= 030) 484 adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */ 485 adapt->pAttributes = 486 xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes); 487 /* Now copy the attributes */ 488 att = adapt->pAttributes; 489 memcpy((char *)att, (char *)intel_xv_attributes, 490 sizeof(XF86AttributeRec) * NUM_ATTRIBUTES); 491 att += NUM_ATTRIBUTES; 492 if (INTEL_INFO(intel)->gen >= 030) { 493 memcpy((char *)att, (char *)intel_xv_gamma_attributes, 494 sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES); 495 } 496 adapt->nImages = NUM_IMAGES - XVMC_IMAGE; 497 498 adapt->pImages = intel_xv_images; 499 adapt->PutVideo = NULL; 500 adapt->PutStill = NULL; 501 adapt->GetVideo = NULL; 502 adapt->GetStill = NULL; 503 adapt->StopVideo = intel_video_stop_video; 504 adapt->SetPortAttribute = intel_video_overlay_set_port_attribute; 505 adapt->GetPortAttribute = intel_video_get_port_attribute; 506 adapt->QueryBestSize = intel_video_query_best_size; 507 adapt->PutImage = intel_video_overlay_put_image; 508 adapt->QueryImageAttributes = intel_video_query_image_attributes; 509 510 adaptor_priv->textured = FALSE; 511 adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1); 512 adaptor_priv->videoStatus = 0; 513 adaptor_priv->brightness = -19; /* (255/219) * -16 */ 514 adaptor_priv->contrast = 75; /* 255/219 * 64 */ 515 adaptor_priv->saturation = 146; /* 128/112 * 128 */ 516 adaptor_priv->desired_crtc = NULL; 517 adaptor_priv->buf = NULL; 518 adaptor_priv->old_buf[0] = NULL; 519 adaptor_priv->old_buf[1] = NULL; 520 adaptor_priv->gamma5 = 0xc0c0c0; 521 adaptor_priv->gamma4 = 0x808080; 522 adaptor_priv->gamma3 = 0x404040; 523 adaptor_priv->gamma2 = 0x202020; 524 adaptor_priv->gamma1 = 0x101010; 525 adaptor_priv->gamma0 = 0x080808; 526 527 adaptor_priv->rotation = RR_Rotate_0; 528 529 /* gotta uninit this someplace */ 530 REGION_NULL(screen, &adaptor_priv->clip); 531 532 intel->adaptor = adapt; 533 534 intel_xv_ColorKey = MAKE_ATOM("XV_COLORKEY"); 535 intel_xv_Brightness = MAKE_ATOM("XV_BRIGHTNESS"); 536 intel_xv_Contrast = MAKE_ATOM("XV_CONTRAST"); 537 intel_xv_Saturation = MAKE_ATOM("XV_SATURATION"); 538 539 /* Allow the pipe to be switched from pipe A to B when in clone mode */ 540 intel_xv_Pipe = MAKE_ATOM("XV_PIPE"); 541 542 if (INTEL_INFO(intel)->gen >= 030) { 543 intel_xv_Gamma0 = MAKE_ATOM("XV_GAMMA0"); 544 intel_xv_Gamma1 = MAKE_ATOM("XV_GAMMA1"); 545 intel_xv_Gamma2 = MAKE_ATOM("XV_GAMMA2"); 546 intel_xv_Gamma3 = MAKE_ATOM("XV_GAMMA3"); 547 intel_xv_Gamma4 = MAKE_ATOM("XV_GAMMA4"); 548 intel_xv_Gamma5 = MAKE_ATOM("XV_GAMMA5"); 549 } 550 551 intel_overlay_update_attrs(intel); 552 553 return adapt; 554} 555