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; 40 41static XvFormatRec Formats[] = { 42 {15}, {16}, {24} 43}; 44 45static const XvAttributeRec Attributes[] = { 46 {XvSettable | XvGettable, -1, 1, (char *)"XV_SYNC_TO_VBLANK"}, 47 //{XvSettable | XvGettable, -128, 127, (char *)"XV_BRIGHTNESS"}, 48 //{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"}, 49}; 50 51static const XvImageRec Images[] = { 52 XVIMAGE_YUY2, 53 XVIMAGE_YV12, 54 XVIMAGE_I420, 55 XVIMAGE_UYVY, 56 XVMC_YUV, 57}; 58 59static int sna_video_textured_stop(ddStopVideo_ARGS) 60{ 61 struct sna_video *video = port->devPriv.ptr; 62 63 DBG(("%s()\n", __FUNCTION__)); 64 65 RegionUninit(&video->clip); 66 sna_video_free_buffers(video); 67 68 return Success; 69} 70 71static int 72sna_video_textured_set_attribute(ddSetPortAttribute_ARGS) 73{ 74 struct sna_video *video = port->devPriv.ptr; 75 76 if (attribute == xvBrightness) { 77 if (value < -128 || value > 127) 78 return BadValue; 79 80 video->brightness = value; 81 } else if (attribute == xvContrast) { 82 if (value < 0 || value > 255) 83 return BadValue; 84 85 video->contrast = value; 86 } else if (attribute == xvSyncToVblank) { 87 if (value < -1 || value > 1) 88 return BadValue; 89 90 video->SyncToVblank = value; 91 } else 92 return BadMatch; 93 94 return Success; 95} 96 97static int 98sna_video_textured_get_attribute(ddGetPortAttribute_ARGS) 99{ 100 struct sna_video *video = port->devPriv.ptr; 101 102 if (attribute == xvBrightness) 103 *value = video->brightness; 104 else if (attribute == xvContrast) 105 *value = video->contrast; 106 else if (attribute == xvSyncToVblank) 107 *value = video->SyncToVblank; 108 else 109 return BadMatch; 110 111 return Success; 112} 113 114static int 115sna_video_textured_best_size(ddQueryBestSize_ARGS) 116{ 117 if (vid_w > (drw_w << 1)) 118 drw_w = vid_w >> 1; 119 if (vid_h > (drw_h << 1)) 120 drw_h = vid_h >> 1; 121 122 *p_w = drw_w; 123 *p_h = drw_h; 124 125 return Success; 126} 127 128/* 129 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). 130 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). 131 * id is a fourcc code for the format of the video. 132 * buf is the pointer to the source data in system memory. 133 * width and height are the w/h of the source data. 134 * If "sync" is true, then we must be finished with *buf at the point of return 135 * (which we always are). 136 * clip is the clipping region in screen space. 137 * data is a pointer to our port private. 138 * drawable is some Drawable, which might not be the screen in the case of 139 * compositing. It's a new argument to the function in the 1.1 server. 140 */ 141static int 142sna_video_textured_put_image(ddPutImage_ARGS) 143{ 144 struct sna_video *video = port->devPriv.ptr; 145 struct sna *sna = video->sna; 146 struct sna_video_frame frame; 147 PixmapPtr pixmap = get_drawable_pixmap(draw); 148 unsigned int flags; 149 BoxRec dstBox; 150 RegionRec clip; 151 xf86CrtcPtr crtc; 152 bool flush = false; 153 bool ret; 154 155 clip.extents.x1 = draw->x + drw_x; 156 clip.extents.y1 = draw->y + drw_y; 157 clip.extents.x2 = clip.extents.x1 + drw_w; 158 clip.extents.y2 = clip.extents.y1 + drw_h; 159 clip.data = NULL; 160 161 RegionIntersect(&clip, &clip, gc->pCompositeClip); 162 if (!RegionNotEmpty(&clip)) 163 return Success; 164 165 DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n", 166 __FUNCTION__, 167 src_x, src_y, src_w, src_h, 168 drw_x, drw_y, drw_w, drw_h, 169 format->id, width, height, sync)); 170 171 DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__, 172 region_num_rects(&clip), 173 clip.extents.x1, clip.extents.y1, 174 clip.extents.x2, clip.extents.y2)); 175 176 sna_video_frame_init(video, format->id, width, height, &frame); 177 178 if (!sna_video_clip_helper(video, &frame, &crtc, &dstBox, 179 src_x, src_y, drw_x + draw->x, drw_y + draw->y, 180 src_w, src_h, drw_w, drw_h, 181 &clip)) 182 return Success; 183 184 flags = MOVE_WRITE | __MOVE_FORCE; 185 if (clip.data) 186 flags |= MOVE_READ; 187 188 if (!sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags)) { 189 DBG(("%s: attempting to render to a non-GPU pixmap\n", 190 __FUNCTION__)); 191 return BadAlloc; 192 } 193 194 sna_video_frame_set_rotation(video, &frame, RR_Rotate_0); 195 196 if (xvmc_passthrough(format->id)) { 197 DBG(("%s: using passthough, name=%d\n", 198 __FUNCTION__, *(uint32_t *)buf)); 199 200 frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf); 201 if (frame.bo == NULL) { 202 DBG(("%s: failed to open bo\n", __FUNCTION__)); 203 return BadAlloc; 204 } 205 206 if (kgem_bo_size(frame.bo) < frame.size) { 207 DBG(("%s: bo size=%d, expected=%d\n", 208 __FUNCTION__, kgem_bo_size(frame.bo), frame.size)); 209 kgem_bo_destroy(&sna->kgem, frame.bo); 210 return BadAlloc; 211 } 212 213 frame.image.x1 = 0; 214 frame.image.y1 = 0; 215 frame.image.x2 = frame.width; 216 frame.image.y2 = frame.height; 217 } else { 218 if (!sna_video_copy_data(video, &frame, buf)) { 219 DBG(("%s: failed to copy frame\n", __FUNCTION__)); 220 kgem_bo_destroy(&sna->kgem, frame.bo); 221 return BadAlloc; 222 } 223 } 224 225 if (crtc && video->SyncToVblank != 0 && 226 sna_pixmap_is_scanout(sna, pixmap)) { 227 kgem_set_mode(&sna->kgem, KGEM_RENDER, sna_pixmap(pixmap)->gpu_bo); 228 flush = sna_wait_for_scanline(sna, pixmap, crtc, 229 &clip.extents); 230 } 231 232 ret = Success; 233 if (!sna->render.video(sna, video, &frame, &clip, pixmap)) { 234 DBG(("%s: failed to render video\n", __FUNCTION__)); 235 ret = BadAlloc; 236 } else 237 DamageDamageRegion(draw, &clip); 238 239 kgem_bo_destroy(&sna->kgem, frame.bo); 240 241 /* Push the frame to the GPU as soon as possible so 242 * we can hit the next vsync. 243 */ 244 if (flush || sync) 245 kgem_submit(&sna->kgem); 246 247 RegionUninit(&clip); 248 249 return ret; 250} 251 252static int 253sna_video_textured_query(ddQueryImageAttributes_ARGS) 254{ 255 int size, tmp; 256 257 if (*w > 8192) 258 *w = 8192; 259 if (*h > 8192) 260 *h = 8192; 261 262 *w = (*w + 1) & ~1; 263 if (offsets) 264 offsets[0] = 0; 265 266 switch (format->id) { 267 /* IA44 is for XvMC only */ 268 case FOURCC_IA44: 269 case FOURCC_AI44: 270 if (pitches) 271 pitches[0] = *w; 272 size = *w * *h; 273 break; 274 case FOURCC_YV12: 275 case FOURCC_I420: 276 *h = (*h + 1) & ~1; 277 size = (*w + 3) & ~3; 278 if (pitches) 279 pitches[0] = size; 280 size *= *h; 281 if (offsets) 282 offsets[1] = size; 283 tmp = ((*w >> 1) + 3) & ~3; 284 if (pitches) 285 pitches[1] = pitches[2] = tmp; 286 tmp *= (*h >> 1); 287 size += tmp; 288 if (offsets) 289 offsets[2] = size; 290 size += tmp; 291 break; 292 case FOURCC_UYVY: 293 case FOURCC_YUY2: 294 default: 295 size = *w << 1; 296 if (pitches) 297 pitches[0] = size; 298 size *= *h; 299 break; 300 case FOURCC_XVMC: 301 *h = (*h + 1) & ~1; 302 size = sizeof(uint32_t); 303 if (pitches) 304 pitches[0] = size; 305 break; 306 } 307 308 return size; 309} 310 311void sna_video_textured_setup(struct sna *sna, ScreenPtr screen) 312{ 313 XvAdaptorPtr adaptor; 314 struct sna_video *video; 315 int nports, i; 316 317 if (!sna->render.video) { 318 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 319 "Textured video not supported on this hardware\n"); 320 return; 321 } 322 323 if (wedged(sna)) { 324 xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING, 325 "cannot enable XVideo whilst the GPU is wedged\n"); 326 return; 327 } 328 329 adaptor = sna_xv_adaptor_alloc(sna); 330 if (adaptor == NULL) 331 return; 332 333 nports = 16; 334 if (sna->kgem.gen >= 060) 335 nports = 32; 336 if (sna->kgem.gen >= 0100) 337 nports = 64; 338 339 video = calloc(nports, sizeof(struct sna_video)); 340 adaptor->pPorts = calloc(nports, sizeof(XvPortRec)); 341 if (video == NULL || adaptor->pPorts == NULL) { 342 free(video); 343 free(adaptor->pPorts); 344 sna->xv.num_adaptors--; 345 return; 346 } 347 348 adaptor->type = XvInputMask | XvImageMask; 349 adaptor->pScreen = screen; 350 adaptor->name = (char *)"Intel(R) Textured Video"; 351 adaptor->nEncodings = 1; 352 adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec)); 353 adaptor->pEncodings[0].id = 0; 354 adaptor->pEncodings[0].pScreen = screen; 355 adaptor->pEncodings[0].name = (char *)"XV_IMAGE"; 356 adaptor->pEncodings[0].width = sna->render.max_3d_size; 357 adaptor->pEncodings[0].height = sna->render.max_3d_size; 358 adaptor->pEncodings[0].rate.numerator = 1; 359 adaptor->pEncodings[0].rate.denominator = 1; 360 adaptor->pFormats = Formats; 361 adaptor->nFormats = sna_xv_fixup_formats(screen, Formats, 362 ARRAY_SIZE(Formats)); 363 adaptor->nAttributes = ARRAY_SIZE(Attributes); 364 adaptor->pAttributes = (XvAttributeRec *)Attributes; 365 adaptor->nImages = ARRAY_SIZE(Images); 366 adaptor->pImages = (XvImageRec *)Images; 367#if XORG_XV_VERSION < 2 368 adaptor->ddAllocatePort = sna_xv_alloc_port; 369 adaptor->ddFreePort = sna_xv_free_port; 370#endif 371 adaptor->ddPutVideo = NULL; 372 adaptor->ddPutStill = NULL; 373 adaptor->ddGetVideo = NULL; 374 adaptor->ddGetStill = NULL; 375 adaptor->ddStopVideo = sna_video_textured_stop; 376 adaptor->ddSetPortAttribute = sna_video_textured_set_attribute; 377 adaptor->ddGetPortAttribute = sna_video_textured_get_attribute; 378 adaptor->ddQueryBestSize = sna_video_textured_best_size; 379 adaptor->ddPutImage = sna_video_textured_put_image; 380 adaptor->ddQueryImageAttributes = sna_video_textured_query; 381 382 for (i = 0; i < nports; i++) { 383 struct sna_video *v = &video[i]; 384 XvPortPtr port = &adaptor->pPorts[i]; 385 386 v->sna = sna; 387 v->textured = true; 388 v->alignment = 4; 389 v->SyncToVblank = (sna->flags & SNA_NO_WAIT) == 0; 390 391 RegionNull(&v->clip); 392 393 port->id = FakeClientID(0); 394 AddResource(port->id, XvGetRTPort(), port); 395 396 port->pAdaptor = adaptor; 397 port->pNotify = NULL; 398 port->pDraw = NULL; 399 port->client = NULL; 400 port->grab.client = NULL; 401 port->time = currentTime; 402 port->devPriv.ptr = v; 403 } 404 adaptor->base_id = adaptor->pPorts[0].id; 405 adaptor->nPorts = nports; 406 407 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); 408 xvContrast = MAKE_ATOM("XV_CONTRAST"); 409 xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 410 411 DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts)); 412} 413