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