1/*************************************************************************** 2 3 Copyright 2000-2011 Intel Corporation. All Rights Reserved. 4 5 Permission is hereby granted, free of charge, to any person obtaining a 6 copy of this software and associated documentation files (the 7 "Software"), to deal in the Software without restriction, including 8 without limitation the rights to use, copy, modify, merge, publish, 9 distribute, sub license, and/or sell copies of the Software, and to 10 permit persons to whom the Software is furnished to do so, subject to 11 the following conditions: 12 13 The above copyright notice and this permission notice (including the 14 next paragraph) shall be included in all copies or substantial portions 15 of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 23 THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 **************************************************************************/ 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#include "sna.h" 32#include "sna_video.h" 33 34#include <xf86xv.h> 35#include <X11/extensions/Xv.h> 36 37#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, true) 38 39static Atom xvBrightness, xvContrast, xvSyncToVblank, xvColorspace; 40 41static XvFormatRec Formats[] = { 42 {15}, {16}, {24}, {30} 43}; 44 45static const XvAttributeRec Attributes[] = { 46 {XvSettable | XvGettable, -1, 1, (char *)"XV_SYNC_TO_VBLANK"}, 47 {XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE"}, /* BT.601, BT.709 */ 48 //{XvSettable | XvGettable, -128, 127, (char *)"XV_BRIGHTNESS"}, 49 //{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"}, 50}; 51 52static const XvImageRec gen2_Images[] = { 53 XVIMAGE_YUY2, 54 XVIMAGE_UYVY, 55}; 56 57static const XvImageRec gen3_Images[] = { 58 XVIMAGE_YUY2, 59 XVIMAGE_YV12, 60 XVIMAGE_I420, 61 XVIMAGE_UYVY, 62 XVMC_YUV, 63}; 64 65static const XvImageRec gen4_Images[] = { 66 XVIMAGE_YUY2, 67 XVIMAGE_YV12, 68 XVIMAGE_I420, 69 XVIMAGE_NV12, 70 XVIMAGE_UYVY, 71 XVMC_YUV, 72}; 73 74static const XvImageRec gen9_Images[] = { 75 XVIMAGE_YUY2, 76 XVIMAGE_YV12, 77 XVIMAGE_I420, 78 XVIMAGE_NV12, 79 XVIMAGE_UYVY, 80 XVIMAGE_AYUV, 81 XVMC_YUV, 82}; 83 84static int sna_video_textured_stop(ddStopVideo_ARGS) 85{ 86 struct sna_video *video = port->devPriv.ptr; 87 88 DBG(("%s()\n", __FUNCTION__)); 89 90 RegionUninit(&video->clip); 91 sna_video_free_buffers(video); 92 93 return Success; 94} 95 96static int 97sna_video_textured_set_attribute(ddSetPortAttribute_ARGS) 98{ 99 struct sna_video *video = port->devPriv.ptr; 100 101 if (attribute == xvBrightness) { 102 if (value < -128 || value > 127) 103 return BadValue; 104 105 video->brightness = value; 106 } else if (attribute == xvContrast) { 107 if (value < 0 || value > 255) 108 return BadValue; 109 110 video->contrast = value; 111 } else if (attribute == xvSyncToVblank) { 112 if (value < -1 || value > 1) 113 return BadValue; 114 115 video->SyncToVblank = value; 116 } else if (attribute == xvColorspace) { 117 if (value < 0 || value > 1) 118 return BadValue; 119 120 video->colorspace = value; 121 } else 122 return BadMatch; 123 124 return Success; 125} 126 127static int 128sna_video_textured_get_attribute(ddGetPortAttribute_ARGS) 129{ 130 struct sna_video *video = port->devPriv.ptr; 131 132 if (attribute == xvBrightness) 133 *value = video->brightness; 134 else if (attribute == xvContrast) 135 *value = video->contrast; 136 else if (attribute == xvSyncToVblank) 137 *value = video->SyncToVblank; 138 else if (attribute == xvColorspace) 139 *value = video->colorspace; 140 else 141 return BadMatch; 142 143 return Success; 144} 145 146static int 147sna_video_textured_best_size(ddQueryBestSize_ARGS) 148{ 149 if (vid_w > (drw_w << 1)) 150 drw_w = vid_w >> 1; 151 if (vid_h > (drw_h << 1)) 152 drw_h = vid_h >> 1; 153 154 *p_w = drw_w; 155 *p_h = drw_h; 156 157 return Success; 158} 159 160/* 161 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). 162 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). 163 * id is a fourcc code for the format of the video. 164 * buf is the pointer to the source data in system memory. 165 * width and height are the w/h of the source data. 166 * If "sync" is true, then we must be finished with *buf at the point of return 167 * (which we always are). 168 * clip is the clipping region in screen space. 169 * data is a pointer to our port private. 170 * drawable is some Drawable, which might not be the screen in the case of 171 * compositing. It's a new argument to the function in the 1.1 server. 172 */ 173static int 174sna_video_textured_put_image(ddPutImage_ARGS) 175{ 176 struct sna_video *video = port->devPriv.ptr; 177 struct sna *sna = video->sna; 178 struct sna_video_frame frame; 179 PixmapPtr pixmap = get_drawable_pixmap(draw); 180 unsigned int flags; 181 BoxRec dstBox; 182 RegionRec clip; 183 xf86CrtcPtr crtc; 184 int16_t dx, dy; 185 bool flush = false; 186 bool ret; 187 188 if (wedged(sna)) 189 return BadAlloc; 190 191 init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h); 192 193 ValidateGC(draw, gc); 194 RegionIntersect(&clip, &clip, gc->pCompositeClip); 195 if (!RegionNotEmpty(&clip)) 196 return Success; 197 198 DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n", 199 __FUNCTION__, 200 src_x, src_y, src_w, src_h, 201 drw_x, drw_y, drw_w, drw_h, 202 format->id, width, height, sync)); 203 204 DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__, 205 region_num_rects(&clip), 206 clip.extents.x1, clip.extents.y1, 207 clip.extents.x2, clip.extents.y2)); 208 209 sna_video_frame_init(video, format->id, width, height, &frame); 210 211 if (!sna_video_clip_helper(video, &frame, &crtc, &dstBox, 212 src_x, src_y, drw_x + draw->x, drw_y + draw->y, 213 src_w, src_h, drw_w, drw_h, 214 &clip)) 215 return Success; 216 217 if (get_drawable_deltas(draw, pixmap, &dx, &dy)) 218 RegionTranslate(&clip, dx, dy); 219 220 flags = MOVE_WRITE | __MOVE_FORCE; 221 if (clip.data) 222 flags |= MOVE_READ; 223 224 if (!sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags)) { 225 DBG(("%s: attempting to render to a non-GPU pixmap\n", 226 __FUNCTION__)); 227 return BadAlloc; 228 } 229 230 sna_video_frame_set_rotation(video, &frame, RR_Rotate_0); 231 232 if (xvmc_passthrough(format->id)) { 233 DBG(("%s: using passthough, name=%d\n", 234 __FUNCTION__, *(uint32_t *)buf)); 235 236 frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf); 237 if (frame.bo == NULL) { 238 DBG(("%s: failed to open bo\n", __FUNCTION__)); 239 return BadAlloc; 240 } 241 242 if (kgem_bo_size(frame.bo) < frame.size) { 243 DBG(("%s: bo size=%d, expected=%d\n", 244 __FUNCTION__, kgem_bo_size(frame.bo), frame.size)); 245 kgem_bo_destroy(&sna->kgem, frame.bo); 246 return BadAlloc; 247 } 248 249 frame.image.x1 = 0; 250 frame.image.y1 = 0; 251 frame.image.x2 = frame.width; 252 frame.image.y2 = frame.height; 253 } else { 254 if (!sna_video_copy_data(video, &frame, buf)) { 255 DBG(("%s: failed to copy frame\n", __FUNCTION__)); 256 kgem_bo_destroy(&sna->kgem, frame.bo); 257 return BadAlloc; 258 } 259 } 260 261 if (crtc && video->SyncToVblank != 0 && 262 sna_pixmap_is_scanout(sna, pixmap)) { 263 kgem_set_mode(&sna->kgem, KGEM_RENDER, sna_pixmap(pixmap)->gpu_bo); 264 flush = sna_wait_for_scanline(sna, pixmap, crtc, 265 &clip.extents); 266 } 267 268 ret = Success; 269 if (!sna->render.video(sna, video, &frame, &clip, pixmap)) { 270 DBG(("%s: failed to render video\n", __FUNCTION__)); 271 ret = BadAlloc; 272 } else 273 DamageDamageRegion(&pixmap->drawable, &clip); 274 275 kgem_bo_destroy(&sna->kgem, frame.bo); 276 277 /* Push the frame to the GPU as soon as possible so 278 * we can hit the next vsync. 279 */ 280 if (flush || sync) 281 kgem_submit(&sna->kgem); 282 283 RegionUninit(&clip); 284 285 return ret; 286} 287 288static int 289sna_video_textured_query(ddQueryImageAttributes_ARGS) 290{ 291 int size, tmp; 292 293 if (*w > 8192) 294 *w = 8192; 295 if (*h > 8192) 296 *h = 8192; 297 298 *w = (*w + 1) & ~1; 299 if (offsets) 300 offsets[0] = 0; 301 302 switch (format->id) { 303 /* IA44 is for XvMC only */ 304 case FOURCC_IA44: 305 case FOURCC_AI44: 306 if (pitches) 307 pitches[0] = *w; 308 size = *w * *h; 309 break; 310 case FOURCC_YV12: 311 case FOURCC_I420: 312 *h = (*h + 1) & ~1; 313 size = (*w + 3) & ~3; 314 if (pitches) 315 pitches[0] = size; 316 size *= *h; 317 if (offsets) 318 offsets[1] = size; 319 tmp = ((*w >> 1) + 3) & ~3; 320 if (pitches) 321 pitches[1] = pitches[2] = tmp; 322 tmp *= (*h >> 1); 323 size += tmp; 324 if (offsets) 325 offsets[2] = size; 326 size += tmp; 327 break; 328 case FOURCC_NV12: 329 *h = (*h + 1) & ~1; 330 size = (*w + 3) & ~3; 331 if (pitches) 332 pitches[0] = size; 333 size *= *h; 334 if (offsets) 335 offsets[1] = size; 336 tmp = (*w + 3) & ~3; 337 if (pitches) 338 pitches[1] = tmp; 339 tmp *= (*h >> 1); 340 size += tmp; 341 break; 342 case FOURCC_UYVY: 343 case FOURCC_YUY2: 344 default: 345 size = *w << 1; 346 if (pitches) 347 pitches[0] = size; 348 size *= *h; 349 break; 350 case FOURCC_AYUV: 351 size = *w << 2; 352 if (pitches) 353 pitches[0] = size; 354 size *= *h; 355 break; 356 case FOURCC_XVMC: 357 *h = (*h + 1) & ~1; 358 size = sizeof(uint32_t); 359 if (pitches) 360 pitches[0] = size; 361 break; 362 } 363 364 return size; 365} 366 367void sna_video_textured_setup(struct sna *sna, ScreenPtr screen) 368{ 369 XvAdaptorPtr adaptor; 370 struct sna_video *video; 371 int nports, i; 372 373 if (sna->scrn->depth == 8) { 374 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 375 "Textured video not supported in 8bpp mode\n"); 376 return; 377 } 378 379 if (!sna->render.video) { 380 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 381 "Textured video not supported on this hardware or backend\n"); 382 return; 383 } 384 385 if (wedged(sna)) { 386 xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 387 "cannot enable XVideo whilst the GPU is wedged\n"); 388 return; 389 } 390 391 adaptor = sna_xv_adaptor_alloc(sna); 392 if (adaptor == NULL) 393 return; 394 395 nports = 16; 396 if (sna->kgem.gen >= 060) 397 nports = 32; 398 if (sna->kgem.gen >= 0100) 399 nports = 64; 400 401 video = calloc(nports, sizeof(struct sna_video)); 402 adaptor->pPorts = calloc(nports, sizeof(XvPortRec)); 403 if (video == NULL || adaptor->pPorts == NULL) { 404 free(video); 405 free(adaptor->pPorts); 406 sna->xv.num_adaptors--; 407 return; 408 } 409 410 adaptor->type = XvInputMask | XvImageMask; 411 adaptor->pScreen = screen; 412 adaptor->name = (char *)"Intel(R) Textured Video"; 413 adaptor->nEncodings = 1; 414 adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec)); 415 adaptor->pEncodings[0].id = 0; 416 adaptor->pEncodings[0].pScreen = screen; 417 adaptor->pEncodings[0].name = (char *)"XV_IMAGE"; 418 adaptor->pEncodings[0].width = sna->render.max_3d_size; 419 adaptor->pEncodings[0].height = sna->render.max_3d_size; 420 adaptor->pEncodings[0].rate.numerator = 1; 421 adaptor->pEncodings[0].rate.denominator = 1; 422 adaptor->pFormats = Formats; 423 adaptor->nFormats = sna_xv_fixup_formats(screen, Formats, 424 ARRAY_SIZE(Formats)); 425 adaptor->nAttributes = ARRAY_SIZE(Attributes); 426 adaptor->pAttributes = (XvAttributeRec *)Attributes; 427 if (sna->kgem.gen < 030) { 428 adaptor->nImages = ARRAY_SIZE(gen2_Images); 429 adaptor->pImages = (XvImageRec *)gen2_Images; 430 } else if (sna->kgem.gen < 040) { 431 adaptor->nImages = ARRAY_SIZE(gen3_Images); 432 adaptor->pImages = (XvImageRec *)gen3_Images; 433 } else if (sna->kgem.gen < 0110) { 434 adaptor->nImages = ARRAY_SIZE(gen4_Images); 435 adaptor->pImages = (XvImageRec *)gen4_Images; 436 } else { 437 adaptor->nImages = ARRAY_SIZE(gen9_Images); 438 adaptor->pImages = (XvImageRec *)gen9_Images; 439 } 440#if XORG_XV_VERSION < 2 441 adaptor->ddAllocatePort = sna_xv_alloc_port; 442 adaptor->ddFreePort = sna_xv_free_port; 443#endif 444 adaptor->ddPutVideo = NULL; 445 adaptor->ddPutStill = NULL; 446 adaptor->ddGetVideo = NULL; 447 adaptor->ddGetStill = NULL; 448 adaptor->ddStopVideo = sna_video_textured_stop; 449 adaptor->ddSetPortAttribute = sna_video_textured_set_attribute; 450 adaptor->ddGetPortAttribute = sna_video_textured_get_attribute; 451 adaptor->ddQueryBestSize = sna_video_textured_best_size; 452 adaptor->ddPutImage = sna_video_textured_put_image; 453 adaptor->ddQueryImageAttributes = sna_video_textured_query; 454 455 for (i = 0; i < nports; i++) { 456 struct sna_video *v = &video[i]; 457 XvPortPtr port = &adaptor->pPorts[i]; 458 459 v->sna = sna; 460 v->textured = true; 461 v->alignment = 4; 462 v->colorspace = 1; /* BT.709 */ 463 v->SyncToVblank = (sna->flags & SNA_NO_WAIT) == 0; 464 465 RegionNull(&v->clip); 466 467 port->id = FakeClientID(0); 468 AddResource(port->id, XvGetRTPort(), port); 469 470 port->pAdaptor = adaptor; 471 port->pNotify = NULL; 472 port->pDraw = NULL; 473 port->client = NULL; 474 port->grab.client = NULL; 475 port->time = currentTime; 476 port->devPriv.ptr = v; 477 } 478 adaptor->base_id = adaptor->pPorts[0].id; 479 adaptor->nPorts = nports; 480 481 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 482 xvContrast = MAKE_ATOM("XV_CONTRAST"); 483 xvColorspace = MAKE_ATOM("XV_COLORSPACE"); 484 xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 485 486 DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts)); 487} 488