vl: add support for bob deinterlacing
[mesa.git] / src / gallium / state_trackers / xorg / xvmc / surface.c
index 67dc57d43440c4713c30a64a0ab5876021b04471..7f7eeadcbc682fdb053ffa11cd41400c6882b3da 100644 (file)
 
 #include <assert.h>
 #include <stdio.h>
+
 #include <X11/Xlibint.h>
-#include <vl_winsys.h>
-#include <pipe/p_video_context.h>
-#include <pipe/p_video_state.h>
-#include <pipe/p_state.h>
-#include <util/u_inlines.h>
-#include <util/u_memory.h>
-#include <util/u_math.h>
+
+#include "pipe/p_video_decoder.h"
+#include "pipe/p_video_state.h"
+#include "pipe/p_state.h"
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include "vl_winsys.h"
+
 #include "xvmc_private.h"
 
-static enum pipe_mpeg12_macroblock_type TypeToPipe(int xvmc_mb_type)
+static void
+MacroBlocksToPipe(XvMCContextPrivate *context,
+                  XvMCSurfacePrivate *surface,
+                  unsigned int xvmc_picture_structure,
+                  const XvMCMacroBlock *xvmc_mb,
+                  const XvMCBlockArray *xvmc_blocks,
+                  struct pipe_mpeg12_macroblock *mb,
+                  unsigned int num_macroblocks)
 {
-   if (xvmc_mb_type & XVMC_MB_TYPE_INTRA)
-      return PIPE_MPEG12_MACROBLOCK_TYPE_INTRA;
-   if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_FORWARD)
-      return PIPE_MPEG12_MACROBLOCK_TYPE_FWD;
-   if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_BACKWARD)
-      return PIPE_MPEG12_MACROBLOCK_TYPE_BKWD;
-   if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD))
-      return PIPE_MPEG12_MACROBLOCK_TYPE_BI;
+   unsigned int i, j, k;
 
-   assert(0);
+   assert(xvmc_mb);
+   assert(xvmc_blocks);
+   assert(num_macroblocks);
 
-   XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized mb type 0x%08X.\n", xvmc_mb_type);
+   for (; num_macroblocks > 0; --num_macroblocks) {
+      mb->base.codec = PIPE_VIDEO_CODEC_MPEG12;
+      mb->x = xvmc_mb->x;
+      mb->y = xvmc_mb->y;
+      mb->macroblock_type = xvmc_mb->macroblock_type;
 
-   return -1;
-}
+      switch (xvmc_picture_structure) {
+      case XVMC_FRAME_PICTURE:
+         mb->macroblock_modes.bits.frame_motion_type = xvmc_mb->motion_type;
+         mb->macroblock_modes.bits.field_motion_type = 0;
+         break;
 
-static enum pipe_mpeg12_picture_type PictureToPipe(int xvmc_pic)
-{
-   switch (xvmc_pic) {
       case XVMC_TOP_FIELD:
-         return PIPE_MPEG12_PICTURE_TYPE_FIELD_TOP;
       case XVMC_BOTTOM_FIELD:
-         return PIPE_MPEG12_PICTURE_TYPE_FIELD_BOTTOM;
-      case XVMC_FRAME_PICTURE:
-         return PIPE_MPEG12_PICTURE_TYPE_FRAME;
+         mb->macroblock_modes.bits.frame_motion_type = 0;
+         mb->macroblock_modes.bits.field_motion_type = xvmc_mb->motion_type;
+         break;
+
       default:
          assert(0);
-   }
+      }
 
-   XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized picture type 0x%08X.\n", xvmc_pic);
+      mb->macroblock_modes.bits.dct_type = xvmc_mb->dct_type;
+      mb->motion_vertical_field_select = xvmc_mb->motion_vertical_field_select;
 
-   return -1;
-}
+      for (i = 0; i < 2; ++i)
+         for (j = 0; j < 2; ++j)
+            for (k = 0; k < 2; ++k)
+               mb->PMV[i][j][k] = xvmc_mb->PMV[i][j][k];
 
-static enum pipe_mpeg12_motion_type MotionToPipe(int xvmc_motion_type, unsigned int xvmc_picture_structure)
-{
-   switch (xvmc_motion_type) {
-      case XVMC_PREDICTION_FRAME:
-         if (xvmc_picture_structure == XVMC_FRAME_PICTURE)
-            return PIPE_MPEG12_MOTION_TYPE_FRAME;
-         else
-            return PIPE_MPEG12_MOTION_TYPE_16x8;
-         break;
-      case XVMC_PREDICTION_FIELD:
-         return PIPE_MPEG12_MOTION_TYPE_FIELD;
-      case XVMC_PREDICTION_DUAL_PRIME:
-         return PIPE_MPEG12_MOTION_TYPE_DUALPRIME;
-      default:
-         assert(0);
-   }
-
-   XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized motion type 0x%08X (with picture structure 0x%08X).\n", xvmc_motion_type, xvmc_picture_structure);
+      mb->coded_block_pattern = xvmc_mb->coded_block_pattern;
+      mb->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES;
+      mb->num_skipped_macroblocks = 0;
 
-   return -1;
+      ++xvmc_mb;
+      ++mb;
+   }
 }
 
 static void
-MacroBlocksToPipe(struct pipe_screen *screen,
-                  unsigned int xvmc_picture_structure,
-                  const XvMCMacroBlockArray *xvmc_macroblocks,
-                  const XvMCBlockArray *xvmc_blocks,
-                  unsigned int first_macroblock,
-                  unsigned int num_macroblocks,
-                  struct pipe_mpeg12_macroblock *mb)
+GetPictureDescription(XvMCSurfacePrivate *surface, struct pipe_mpeg12_picture_desc *desc)
 {
-   unsigned int i, j;
-   XvMCMacroBlock *xvmc_mb;
+   unsigned i, num_refs = 0;
 
-   assert(xvmc_macroblocks);
-   assert(xvmc_blocks);
-   assert(mb);
-   assert(num_macroblocks);
+   assert(surface && desc);
 
-   xvmc_mb = xvmc_macroblocks->macro_blocks + first_macroblock;
+   memset(desc, 0, sizeof(*desc));
+   desc->base.profile = PIPE_VIDEO_PROFILE_MPEG1;
+   desc->picture_structure = surface->picture_structure;
+   for (i = 0; i < 2; ++i) {
+      if (surface->ref[i]) {
+         XvMCSurfacePrivate *ref = surface->ref[i]->privData;
 
-   for (i = 0; i < num_macroblocks; ++i) {
-      mb->base.codec = PIPE_VIDEO_CODEC_MPEG12;
-      mb->mbx = xvmc_mb->x;
-      mb->mby = xvmc_mb->y;
-      mb->mb_type = TypeToPipe(xvmc_mb->macroblock_type);
-      if (mb->mb_type != PIPE_MPEG12_MACROBLOCK_TYPE_INTRA)
-         mb->mo_type = MotionToPipe(xvmc_mb->motion_type, xvmc_picture_structure);
-      /* Get rid of Valgrind 'undefined' warnings */
-      else
-         mb->mo_type = -1;
-      mb->dct_type = xvmc_mb->dct_type == XVMC_DCT_TYPE_FIELD ?
-         PIPE_MPEG12_DCT_TYPE_FIELD : PIPE_MPEG12_DCT_TYPE_FRAME;
-
-      for (j = 0; j < 2; ++j) {
-         mb->mv[j].top.x = xvmc_mb->PMV[0][j][0];
-         mb->mv[j].top.y = xvmc_mb->PMV[0][j][1];
-         mb->mv[j].bottom.x = xvmc_mb->PMV[1][j][0];
-         mb->mv[j].bottom.y = xvmc_mb->PMV[1][j][1];
+         if (ref)
+            desc->ref[num_refs++] = ref->video_buffer;
       }
-
-      mb->mv[0].top.field_select = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_FIRST_FORWARD;
-      mb->mv[1].top.field_select = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_FIRST_BACKWARD;
-      mb->mv[0].bottom.field_select = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_SECOND_FORWARD;
-      mb->mv[1].bottom.field_select = xvmc_mb->motion_vertical_field_select & XVMC_SELECT_SECOND_BACKWARD;
-
-      mb->cbp = xvmc_mb->coded_block_pattern;
-      mb->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES;
-
-      ++mb;
-      ++xvmc_mb;
    }
 }
 
 static void
-unmap_and_flush_surface(XvMCSurfacePrivate *surface)
+RecursiveEndFrame(XvMCSurfacePrivate *surface)
 {
-   struct pipe_video_buffer *ref_frames[2];
+   XvMCContextPrivate *context_priv;
    unsigned i;
 
    assert(surface);
 
-   for ( i = 0; i < 3; ++i ) {
-      if (surface->ref_surfaces[i]) {
-         XvMCSurfacePrivate *ref = surface->ref_surfaces[i]->privData;
+   context_priv = surface->context->privData;
+
+   for ( i = 0; i < 2; ++i ) {
+      if (surface->ref[i]) {
+         XvMCSurface *ref = surface->ref[i];
 
          assert(ref);
 
-         unmap_and_flush_surface(ref);
-         surface->ref_surfaces[i] = NULL;
-         ref_frames[i] = ref->pipe_buffer;
-      } else {
-         ref_frames[i] = NULL;
+         surface->ref[i] = NULL;
+         RecursiveEndFrame(ref->privData);
+         surface->ref[i] = ref;
       }
    }
 
-   if (surface->mapped) {
-      surface->pipe_buffer->unmap(surface->pipe_buffer);
-      surface->pipe_buffer->flush(surface->pipe_buffer,
-                                  ref_frames,
-                                  &surface->flush_fence);
-      surface->mapped = 0;
+   if (surface->picture_structure) {
+      struct pipe_mpeg12_picture_desc desc;
+      GetPictureDescription(surface, &desc);
+      surface->picture_structure = 0;
+
+      for (i = 0; i < 2; ++i)
+         surface->ref[i] = NULL;
+
+      context_priv->decoder->end_frame(context_priv->decoder, surface->video_buffer, &desc.base);
    }
 }
 
@@ -182,8 +154,9 @@ PUBLIC
 Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface)
 {
    XvMCContextPrivate *context_priv;
-   struct pipe_video_context *vpipe;
+   struct pipe_context *pipe;
    XvMCSurfacePrivate *surface_priv;
+   struct pipe_video_buffer tmpl;
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface);
 
@@ -195,13 +168,30 @@ Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surfac
       return XvMCBadSurface;
 
    context_priv = context->privData;
-   vpipe = context_priv->vctx->vpipe;
+   pipe = context_priv->vctx->pipe;
 
    surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate));
    if (!surface_priv)
       return BadAlloc;
 
-   surface_priv->pipe_buffer = vpipe->create_buffer(vpipe);
+   memset(&tmpl, 0, sizeof(tmpl));
+   tmpl.buffer_format = pipe->screen->get_video_param
+   (
+      pipe->screen,
+      PIPE_VIDEO_PROFILE_MPEG2_MAIN,
+      PIPE_VIDEO_CAP_PREFERED_FORMAT
+   );
+   tmpl.chroma_format = context_priv->decoder->chroma_format;
+   tmpl.width = context_priv->decoder->width;
+   tmpl.height = context_priv->decoder->height;
+   tmpl.interlaced = pipe->screen->get_video_param
+   (
+      pipe->screen,
+      PIPE_VIDEO_PROFILE_MPEG2_MAIN,
+      PIPE_VIDEO_CAP_PREFERS_INTERLACED
+   );
+
+   surface_priv->video_buffer = pipe->create_video_buffer(pipe, &tmpl);
    surface_priv->context = context;
 
    surface->surface_id = XAllocID(dpy);
@@ -225,15 +215,18 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur
                          XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks
 )
 {
-   struct pipe_video_context *vpipe;
-   struct pipe_video_buffer *t_buffer;
+   struct pipe_mpeg12_macroblock mb[num_macroblocks];
+   struct pipe_video_decoder *decoder;
+   struct pipe_mpeg12_picture_desc desc;
+
    XvMCContextPrivate *context_priv;
    XvMCSurfacePrivate *target_surface_priv;
    XvMCSurfacePrivate *past_surface_priv;
    XvMCSurfacePrivate *future_surface_priv;
-   struct pipe_mpeg12_macroblock pipe_macroblocks[num_macroblocks];
+   XvMCMacroBlock *xvmc_mb;
 
-   XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p.\n", target_surface);
+   XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
+            target_surface, past_surface, future_surface);
 
    assert(dpy);
 
@@ -262,6 +255,9 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur
 
    assert(flags == 0 || flags == XVMC_SECOND_FIELD);
 
+   context_priv = context->privData;
+   decoder = context_priv->decoder;
+
    target_surface_priv = target_surface->privData;
    past_surface_priv = past_surface ? past_surface->privData : NULL;
    future_surface_priv = future_surface ? future_surface->privData : NULL;
@@ -270,39 +266,44 @@ Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int pictur
    assert(!past_surface || past_surface_priv->context == context);
    assert(!future_surface || future_surface_priv->context == context);
 
-   context_priv = context->privData;
-   vpipe = context_priv->vctx->vpipe;
-
-   t_buffer = target_surface_priv->pipe_buffer;
-
-   // enshure that all reference frames are flushed
-   // not really nessasary, but speeds ups rendering
+   // call end frame on all referenced frames
    if (past_surface)
-      unmap_and_flush_surface(past_surface->privData);
+      RecursiveEndFrame(past_surface->privData);
 
    if (future_surface)
-      unmap_and_flush_surface(future_surface->privData);
+      RecursiveEndFrame(future_surface->privData);
 
-   /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
-   if (target_surface_priv->mapped && (
-       target_surface_priv->ref_surfaces[0] != past_surface ||
-       target_surface_priv->ref_surfaces[1] != future_surface)) {
+   xvmc_mb = macroblocks->macro_blocks + first_macroblock;
 
-      // If they change anyway we need to flush our surface
-      unmap_and_flush_surface(target_surface_priv);
+   /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
+   if (target_surface_priv->picture_structure > 0 && (
+       target_surface_priv->picture_structure != picture_structure ||
+       target_surface_priv->ref[0] != past_surface ||
+       target_surface_priv->ref[1] != future_surface ||
+       (xvmc_mb->x == 0 && xvmc_mb->y == 0))) {
+
+      // If they change anyway we must assume that the current frame is ended
+      RecursiveEndFrame(target_surface_priv);
    }
 
-   MacroBlocksToPipe(vpipe->screen, picture_structure, macroblocks, blocks, first_macroblock,
-                     num_macroblocks, pipe_macroblocks);
+   target_surface_priv->ref[0] = past_surface;
+   target_surface_priv->ref[1] = future_surface;
 
-   if (!target_surface_priv->mapped) {
-      t_buffer->map(t_buffer);
-      target_surface_priv->ref_surfaces[0] = past_surface;
-      target_surface_priv->ref_surfaces[1] = future_surface;
-      target_surface_priv->mapped = 1;
+   if (target_surface_priv->picture_structure)
+      GetPictureDescription(target_surface_priv, &desc);
+   else {
+      target_surface_priv->picture_structure = picture_structure;
+      GetPictureDescription(target_surface_priv, &desc);
+      decoder->begin_frame(decoder, target_surface_priv->video_buffer, &desc.base);
    }
 
-   t_buffer->add_macroblocks(t_buffer, num_macroblocks, &pipe_macroblocks->base);
+   MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure,
+                     xvmc_mb, blocks, mb, num_macroblocks);
+
+   context_priv->decoder->decode_macroblock(context_priv->decoder,
+                                            target_surface_priv->video_buffer,
+                                            &desc.base,
+                                            &mb[0].base, num_macroblocks);
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);
 
@@ -320,6 +321,8 @@ Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)
    // don't call flush here, because this is usually
    // called once for every slice instead of every frame
 
+   XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface);
+
    return Success;
 }
 
@@ -331,6 +334,8 @@ Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)
    if (!surface)
       return XvMCBadSurface;
 
+   XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface);
+
    return Success;
 }
 
@@ -342,14 +347,15 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
 {
    static int dump_window = -1;
 
-   struct pipe_video_context *vpipe;
+   struct pipe_context *pipe;
+   struct vl_compositor *compositor;
+
    XvMCSurfacePrivate *surface_priv;
    XvMCContextPrivate *context_priv;
    XvMCSubpicturePrivate *subpicture_priv;
    XvMCContext *context;
    struct pipe_video_rect src_rect = {srcx, srcy, srcw, srch};
    struct pipe_video_rect dst_rect = {destx, desty, destw, desth};
-   struct pipe_surface *drawable_surface;
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);
 
@@ -362,13 +368,27 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
    context = surface_priv->context;
    context_priv = context->privData;
 
-   drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable);
-   if (!drawable_surface)
-      return BadDrawable;
-
    assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
    assert(srcx + srcw - 1 < surface->width);
    assert(srcy + srch - 1 < surface->height);
+
+   subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
+   pipe = context_priv->vctx->pipe;
+   compositor = &context_priv->compositor;
+
+   if (!context_priv->drawable_surface ||
+       context_priv->dst_rect.x != dst_rect.x || context_priv->dst_rect.y != dst_rect.y ||
+       context_priv->dst_rect.w != dst_rect.w || context_priv->dst_rect.h != dst_rect.h) {
+
+      pipe_surface_reference(&context_priv->drawable_surface, NULL);
+      context_priv->drawable_surface = vl_drawable_surface_get(context_priv->vctx, drawable);
+      context_priv->dst_rect = dst_rect;
+      vl_compositor_reset_dirty_area(&context_priv->dirty_area);
+   }
+
+   if (!context_priv->drawable_surface)
+      return BadDrawable;
+
    /*
     * Some apps (mplayer) hit these asserts because they call
     * this function after the window has been resized by the WM
@@ -381,42 +401,47 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
    assert(desty + desth - 1 < drawable_surface->height);
     */
 
-   subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;
-   vpipe = context_priv->vctx->vpipe;
+   RecursiveEndFrame(surface_priv);
 
-   if (subpicture_priv) {
-      struct pipe_video_rect src_rect = {surface_priv->subx, surface_priv->suby, surface_priv->subw, surface_priv->subh};
-      struct pipe_video_rect dst_rect = {surface_priv->surfx, surface_priv->surfy, surface_priv->surfw, surface_priv->surfh};
-      struct pipe_video_rect *src_rects[1] = {&src_rect};
-      struct pipe_video_rect *dst_rects[1] = {&dst_rect};
+   context_priv->decoder->flush(context_priv->decoder);
+
+   vl_compositor_clear_layers(compositor);
+   vl_compositor_set_buffer_layer(compositor, 0, surface_priv->video_buffer,
+                                  &src_rect, NULL, VL_COMPOSITOR_WEAVE);
 
+   if (subpicture_priv) {
       XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);
 
       assert(subpicture_priv->surface == surface);
-      vpipe->set_picture_layers(vpipe, &subpicture_priv->sampler, &subpicture_priv->palette, src_rects, dst_rects, 1);
+
+      if (subpicture_priv->palette)
+         vl_compositor_set_palette_layer(compositor, 1, subpicture_priv->sampler, subpicture_priv->palette,
+                                         &subpicture_priv->src_rect, &subpicture_priv->dst_rect, true);
+      else
+         vl_compositor_set_rgba_layer(compositor, 1, subpicture_priv->sampler,
+                                      &subpicture_priv->src_rect, &subpicture_priv->dst_rect);
 
       surface_priv->subpicture = NULL;
       subpicture_priv->surface = NULL;
    }
-   else
-      vpipe->set_picture_layers(vpipe, NULL, NULL, NULL, NULL, 0);
 
-   unmap_and_flush_surface(surface_priv);
-   vpipe->render_picture(vpipe, surface_priv->pipe_buffer, &src_rect, PictureToPipe(flags),
-                         drawable_surface, &dst_rect, &surface_priv->disp_fence);
+   // Workaround for r600g, there seems to be a bug in the fence refcounting code
+   pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL);
+
+   vl_compositor_render(compositor, context_priv->drawable_surface, &dst_rect, NULL, &context_priv->dirty_area);
+                        
+   pipe->flush(pipe, &surface_priv->fence);
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);
 
-   vpipe->screen->flush_frontbuffer
+   pipe->screen->flush_frontbuffer
    (
-      vpipe->screen,
-      drawable_surface->texture,
+      pipe->screen,
+      context_priv->drawable_surface->texture,
       0, 0,
-      vl_contextprivate_get(context_priv->vctx, drawable_surface)
+      vl_contextprivate_get(context_priv->vctx, context_priv->drawable_surface)
    );
 
-   pipe_surface_reference(&drawable_surface, NULL);
-
    if(dump_window == -1) {
       dump_window = debug_get_num_option("XVMC_DUMP", 0);
    }
@@ -424,8 +449,10 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
    if(dump_window) {
       static unsigned int framenum = 0;
       char cmd[256];
+
       sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum);
-      system(cmd);
+      if (system(cmd) != 0)
+         XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface);
    }
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface);
@@ -436,6 +463,10 @@ Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,
 PUBLIC
 Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)
 {
+   struct pipe_context *pipe;
+   XvMCSurfacePrivate *surface_priv;
+   XvMCContextPrivate *context_priv;
+
    assert(dpy);
 
    if (!surface)
@@ -443,8 +474,16 @@ Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)
 
    assert(status);
 
+   surface_priv = surface->privData;
+   context_priv = surface_priv->context->privData;
+   pipe = context_priv->vctx->pipe;
+
    *status = 0;
 
+   if (surface_priv->fence)
+      if (!pipe->screen->fence_signalled(pipe->screen, surface_priv->fence))
+         *status |= XVMC_RENDERING;
+
    return Success;
 }
 
@@ -452,6 +491,7 @@ PUBLIC
 Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)
 {
    XvMCSurfacePrivate *surface_priv;
+   XvMCContextPrivate *context_priv;
 
    XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface);
 
@@ -461,7 +501,14 @@ Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)
       return XvMCBadSurface;
 
    surface_priv = surface->privData;
-   surface_priv->pipe_buffer->destroy(surface_priv->pipe_buffer);
+   context_priv = surface_priv->context->privData;
+   
+   if (surface_priv->picture_structure) {
+      struct pipe_mpeg12_picture_desc desc;
+      GetPictureDescription(surface_priv, &desc);
+      context_priv->decoder->end_frame(context_priv->decoder, surface_priv->video_buffer, &desc.base);
+   }
+   surface_priv->video_buffer->destroy(surface_priv->video_buffer);
    FREE(surface_priv);
    surface->privData = NULL;