1 /************************************************************************** 2 * 3 * Copyright 2009 Younes Manton. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #include <assert.h> 29 #include <stdio.h> 30 31 #include <X11/Xlibint.h> 32 33 #include "pipe/p_video_codec.h" 34 #include "pipe/p_video_state.h" 35 #include "pipe/p_state.h" 36 37 #include "util/macros.h" 38 #include "util/u_inlines.h" 39 #include "util/u_memory.h" 40 #include "util/u_math.h" 41 #include "vl/vl_winsys.h" 42 43 #include "xvmc_private.h" 44 45 static void 46 MacroBlocksToPipe(XvMCContextPrivate *context, 47 XvMCSurfacePrivate *surface, 48 unsigned int xvmc_picture_structure, 49 const XvMCMacroBlock *xvmc_mb, 50 const XvMCBlockArray *xvmc_blocks, 51 struct pipe_mpeg12_macroblock *mb, 52 unsigned int num_macroblocks) 53 { 54 unsigned int i, j, k; 55 56 assert(xvmc_mb); 57 assert(xvmc_blocks); 58 assert(num_macroblocks); 59 60 for (; num_macroblocks > 0; --num_macroblocks) { 61 mb->base.codec = PIPE_VIDEO_FORMAT_MPEG12; 62 mb->x = xvmc_mb->x; 63 mb->y = xvmc_mb->y; 64 mb->macroblock_type = xvmc_mb->macroblock_type; 65 66 switch (xvmc_picture_structure) { 67 case XVMC_FRAME_PICTURE: 68 mb->macroblock_modes.bits.frame_motion_type = xvmc_mb->motion_type; 69 mb->macroblock_modes.bits.field_motion_type = 0; 70 break; 71 72 case XVMC_TOP_FIELD: 73 case XVMC_BOTTOM_FIELD: 74 mb->macroblock_modes.bits.frame_motion_type = 0; 75 mb->macroblock_modes.bits.field_motion_type = xvmc_mb->motion_type; 76 break; 77 78 default: 79 assert(0); 80 } 81 82 mb->macroblock_modes.bits.dct_type = xvmc_mb->dct_type; 83 mb->motion_vertical_field_select = xvmc_mb->motion_vertical_field_select; 84 85 for (i = 0; i < 2; ++i) 86 for (j = 0; j < 2; ++j) 87 for (k = 0; k < 2; ++k) 88 mb->PMV[i][j][k] = xvmc_mb->PMV[i][j][k]; 89 90 mb->coded_block_pattern = xvmc_mb->coded_block_pattern; 91 mb->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES; 92 mb->num_skipped_macroblocks = 0; 93 94 ++xvmc_mb; 95 ++mb; 96 } 97 } 98 99 static void 100 GetPictureDescription(XvMCSurfacePrivate *surface, struct pipe_mpeg12_picture_desc *desc) 101 { 102 unsigned i, num_refs = 0; 103 104 assert(surface && desc); 105 106 memset(desc, 0, sizeof(*desc)); 107 desc->base.profile = PIPE_VIDEO_PROFILE_MPEG1; 108 desc->picture_structure = surface->picture_structure; 109 for (i = 0; i < 2; ++i) { 110 if (surface->ref[i]) { 111 XvMCSurfacePrivate *ref = surface->ref[i]->privData; 112 113 if (ref) 114 desc->ref[num_refs++] = ref->video_buffer; 115 } 116 } 117 } 118 119 static void 120 RecursiveEndFrame(XvMCSurfacePrivate *surface) 121 { 122 XvMCContextPrivate *context_priv; 123 unsigned i; 124 125 assert(surface); 126 127 context_priv = surface->context->privData; 128 129 for ( i = 0; i < 2; ++i ) { 130 if (surface->ref[i]) { 131 XvMCSurface *ref = surface->ref[i]; 132 133 assert(ref); 134 135 surface->ref[i] = NULL; 136 RecursiveEndFrame(ref->privData); 137 surface->ref[i] = ref; 138 } 139 } 140 141 if (surface->picture_structure) { 142 struct pipe_mpeg12_picture_desc desc; 143 GetPictureDescription(surface, &desc); 144 surface->picture_structure = 0; 145 146 for (i = 0; i < 2; ++i) 147 surface->ref[i] = NULL; 148 149 context_priv->decoder->end_frame(context_priv->decoder, surface->video_buffer, &desc.base); 150 } 151 } 152 153 PUBLIC 154 Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface) 155 { 156 XvMCContextPrivate *context_priv; 157 struct pipe_context *pipe; 158 XvMCSurfacePrivate *surface_priv; 159 struct pipe_video_buffer tmpl; 160 161 XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface); 162 163 assert(dpy); 164 165 if (!context) 166 return XvMCBadContext; 167 if (!surface) 168 return XvMCBadSurface; 169 170 context_priv = context->privData; 171 pipe = context_priv->pipe; 172 173 surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate)); 174 if (!surface_priv) 175 return BadAlloc; 176 177 memset(&tmpl, 0, sizeof(tmpl)); 178 tmpl.buffer_format = pipe->screen->get_video_param 179 ( 180 pipe->screen, 181 context_priv->decoder->profile, 182 context_priv->decoder->entrypoint, 183 PIPE_VIDEO_CAP_PREFERED_FORMAT 184 ); 185 tmpl.chroma_format = context_priv->decoder->chroma_format; 186 tmpl.width = context_priv->decoder->width; 187 tmpl.height = context_priv->decoder->height; 188 tmpl.interlaced = pipe->screen->get_video_param 189 ( 190 pipe->screen, 191 context_priv->decoder->profile, 192 context_priv->decoder->entrypoint, 193 PIPE_VIDEO_CAP_PREFERS_INTERLACED 194 ); 195 196 surface_priv->video_buffer = pipe->create_video_buffer(pipe, &tmpl); 197 if (!surface_priv->video_buffer) { 198 FREE(surface_priv); 199 return BadAlloc; 200 } 201 surface_priv->context = context; 202 203 surface->surface_id = XAllocID(dpy); 204 surface->context_id = context->context_id; 205 surface->surface_type_id = context->surface_type_id; 206 surface->width = context->width; 207 surface->height = context->height; 208 surface->privData = surface_priv; 209 210 SyncHandle(); 211 212 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface); 213 214 return Success; 215 } 216 217 PUBLIC 218 Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure, 219 XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface, 220 unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock, 221 XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks 222 ) 223 { 224 struct pipe_mpeg12_macroblock mb[num_macroblocks]; 225 struct pipe_video_codec *decoder; 226 struct pipe_mpeg12_picture_desc desc; 227 228 XvMCContextPrivate *context_priv; 229 XvMCSurfacePrivate *target_surface_priv; 230 MAYBE_UNUSED XvMCSurfacePrivate *past_surface_priv; 231 MAYBE_UNUSED XvMCSurfacePrivate *future_surface_priv; 232 XvMCMacroBlock *xvmc_mb; 233 234 XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n", 235 target_surface, past_surface, future_surface); 236 237 assert(dpy); 238 239 if (!context || !context->privData) 240 return XvMCBadContext; 241 if (!target_surface || !target_surface->privData) 242 return XvMCBadSurface; 243 244 if (picture_structure != XVMC_TOP_FIELD && 245 picture_structure != XVMC_BOTTOM_FIELD && 246 picture_structure != XVMC_FRAME_PICTURE) 247 return BadValue; 248 /* Bkwd pred equivalent to fwd (past && !future) */ 249 if (future_surface && !past_surface) 250 return BadMatch; 251 252 assert(context->context_id == target_surface->context_id); 253 assert(!past_surface || context->context_id == past_surface->context_id); 254 assert(!future_surface || context->context_id == future_surface->context_id); 255 256 assert(macroblocks); 257 assert(blocks); 258 259 assert(macroblocks->context_id == context->context_id); 260 assert(blocks->context_id == context->context_id); 261 262 assert(flags == 0 || flags == XVMC_SECOND_FIELD); 263 264 context_priv = context->privData; 265 decoder = context_priv->decoder; 266 267 target_surface_priv = target_surface->privData; 268 past_surface_priv = past_surface ? past_surface->privData : NULL; 269 future_surface_priv = future_surface ? future_surface->privData : NULL; 270 271 assert(target_surface_priv->context == context); 272 assert(!past_surface || past_surface_priv->context == context); 273 assert(!future_surface || future_surface_priv->context == context); 274 275 // call end frame on all referenced frames 276 if (past_surface) 277 RecursiveEndFrame(past_surface->privData); 278 279 if (future_surface) 280 RecursiveEndFrame(future_surface->privData); 281 282 xvmc_mb = macroblocks->macro_blocks + first_macroblock; 283 284 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */ 285 if (target_surface_priv->picture_structure > 0 && ( 286 target_surface_priv->picture_structure != picture_structure || 287 target_surface_priv->ref[0] != past_surface || 288 target_surface_priv->ref[1] != future_surface || 289 (xvmc_mb->x == 0 && xvmc_mb->y == 0))) { 290 291 // If they change anyway we must assume that the current frame is ended 292 RecursiveEndFrame(target_surface_priv); 293 } 294 295 target_surface_priv->ref[0] = past_surface; 296 target_surface_priv->ref[1] = future_surface; 297 298 if (target_surface_priv->picture_structure) 299 GetPictureDescription(target_surface_priv, &desc); 300 else { 301 target_surface_priv->picture_structure = picture_structure; 302 GetPictureDescription(target_surface_priv, &desc); 303 decoder->begin_frame(decoder, target_surface_priv->video_buffer, &desc.base); 304 } 305 306 MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure, 307 xvmc_mb, blocks, mb, num_macroblocks); 308 309 context_priv->decoder->decode_macroblock(context_priv->decoder, 310 target_surface_priv->video_buffer, 311 &desc.base, 312 &mb[0].base, num_macroblocks); 313 314 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface); 315 316 return Success; 317 } 318 319 PUBLIC 320 Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface) 321 { 322 assert(dpy); 323 324 if (!surface) 325 return XvMCBadSurface; 326 327 // don't call flush here, because this is usually 328 // called once for every slice instead of every frame 329 330 XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface); 331 332 return Success; 333 } 334 335 PUBLIC 336 Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface) 337 { 338 assert(dpy); 339 340 if (!surface) 341 return XvMCBadSurface; 342 343 XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface); 344 345 return Success; 346 } 347 348 PUBLIC 349 Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, 350 short srcx, short srcy, unsigned short srcw, unsigned short srch, 351 short destx, short desty, unsigned short destw, unsigned short desth, 352 int flags) 353 { 354 static int dump_window = -1; 355 356 struct pipe_context *pipe; 357 struct vl_compositor *compositor; 358 struct vl_compositor_state *cstate; 359 struct vl_screen *vscreen; 360 361 XvMCSurfacePrivate *surface_priv; 362 XvMCContextPrivate *context_priv; 363 XvMCSubpicturePrivate *subpicture_priv; 364 XvMCContext *context; 365 struct u_rect src_rect = {srcx, srcx + srcw, srcy, srcy + srch}; 366 struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth}; 367 368 struct pipe_resource *tex; 369 struct pipe_surface surf_templ, *surf; 370 struct u_rect *dirty_area; 371 372 XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface); 373 374 assert(dpy); 375 376 if (!surface || !surface->privData) 377 return XvMCBadSurface; 378 379 surface_priv = surface->privData; 380 context = surface_priv->context; 381 context_priv = context->privData; 382 383 assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); 384 assert(srcx + srcw - 1 < surface->width); 385 assert(srcy + srch - 1 < surface->height); 386 387 subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL; 388 pipe = context_priv->pipe; 389 compositor = &context_priv->compositor; 390 cstate = &context_priv->cstate; 391 vscreen = context_priv->vscreen; 392 393 tex = vscreen->texture_from_drawable(vscreen, (void *)drawable); 394 dirty_area = vscreen->get_dirty_area(vscreen); 395 396 memset(&surf_templ, 0, sizeof(surf_templ)); 397 surf_templ.format = tex->format; 398 surf = pipe->create_surface(pipe, tex, &surf_templ); 399 400 if (!surf) 401 return BadDrawable; 402 403 /* 404 * Some apps (mplayer) hit these asserts because they call 405 * this function after the window has been resized by the WM 406 * but before they've handled the corresponding XEvent and 407 * know about the new dimensions. The output should be clipped 408 * until the app updates destw and desth. 409 */ 410 /* 411 assert(destx + destw - 1 < drawable_surface->width); 412 assert(desty + desth - 1 < drawable_surface->height); 413 */ 414 415 RecursiveEndFrame(surface_priv); 416 417 context_priv->decoder->flush(context_priv->decoder); 418 419 vl_compositor_clear_layers(cstate); 420 vl_compositor_set_buffer_layer(cstate, compositor, 0, surface_priv->video_buffer, 421 &src_rect, NULL, VL_COMPOSITOR_WEAVE); 422 423 if (subpicture_priv) { 424 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture); 425 426 assert(subpicture_priv->surface == surface); 427 428 if (subpicture_priv->palette) 429 vl_compositor_set_palette_layer(cstate, compositor, 1, subpicture_priv->sampler, subpicture_priv->palette, 430 &subpicture_priv->src_rect, &subpicture_priv->dst_rect, true); 431 else 432 vl_compositor_set_rgba_layer(cstate, compositor, 1, subpicture_priv->sampler, 433 &subpicture_priv->src_rect, &subpicture_priv->dst_rect, NULL); 434 435 surface_priv->subpicture = NULL; 436 subpicture_priv->surface = NULL; 437 } 438 439 // Workaround for r600g, there seems to be a bug in the fence refcounting code 440 pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL); 441 442 vl_compositor_set_layer_dst_area(cstate, 0, &dst_rect); 443 vl_compositor_set_layer_dst_area(cstate, 1, &dst_rect); 444 vl_compositor_render(cstate, compositor, surf, dirty_area, true); 445 446 pipe->flush(pipe, &surface_priv->fence, 0); 447 448 XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface); 449 450 pipe->screen->flush_frontbuffer(pipe->screen, tex, 0, 0, 451 vscreen->get_private(vscreen), NULL); 452 453 if(dump_window == -1) { 454 dump_window = debug_get_num_option("XVMC_DUMP", 0); 455 } 456 457 if(dump_window) { 458 static unsigned int framenum = 0; 459 char cmd[256]; 460 461 sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum); 462 if (system(cmd) != 0) 463 XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface); 464 } 465 466 XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface); 467 468 return Success; 469 } 470 471 PUBLIC 472 Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status) 473 { 474 struct pipe_context *pipe; 475 XvMCSurfacePrivate *surface_priv; 476 XvMCContextPrivate *context_priv; 477 478 assert(dpy); 479 480 if (!surface) 481 return XvMCBadSurface; 482 483 assert(status); 484 485 surface_priv = surface->privData; 486 context_priv = surface_priv->context->privData; 487 pipe = context_priv->pipe; 488 489 *status = 0; 490 491 if (surface_priv->fence) 492 if (!pipe->screen->fence_finish(pipe->screen, NULL, surface_priv->fence, 0)) 493 *status |= XVMC_RENDERING; 494 495 return Success; 496 } 497 498 PUBLIC 499 Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface) 500 { 501 XvMCSurfacePrivate *surface_priv; 502 XvMCContextPrivate *context_priv; 503 504 XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface); 505 506 assert(dpy); 507 508 if (!surface || !surface->privData) 509 return XvMCBadSurface; 510 511 surface_priv = surface->privData; 512 context_priv = surface_priv->context->privData; 513 514 if (surface_priv->picture_structure) { 515 struct pipe_mpeg12_picture_desc desc; 516 GetPictureDescription(surface_priv, &desc); 517 context_priv->decoder->end_frame(context_priv->decoder, surface_priv->video_buffer, &desc.base); 518 } 519 surface_priv->video_buffer->destroy(surface_priv->video_buffer); 520 FREE(surface_priv); 521 surface->privData = NULL; 522 523 XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface); 524 525 return Success; 526 } 527 528 PUBLIC 529 Status XvMCHideSurface(Display *dpy, XvMCSurface *surface) 530 { 531 assert(dpy); 532 533 if (!surface || !surface->privData) 534 return XvMCBadSurface; 535 536 /* No op, only for overlaid rendering */ 537 538 return Success; 539 } 540