[MPlayer-dev-eng] [PATCH] Address some sizing related glitches in vo_direct3d

David Bolen db3l.net at gmail.com
Fri Mar 20 02:50:29 CET 2009


While using vo_direct3d with mplayer in slave mode while attached to
an embedded window in my application, I've run into a few instances of
glitches or brief corruption of the display while the window is being
resized, especially when the video is currently paused (in which case
the corruption may persist until playing resumes).  There is also
sometimes an initial glitch when displaying into an attached window
that is not the same size as the video being loaded.

The attached proposed patch helps clean up the cases I've encountered,
via:

* An initial processing of the window message queue during configuration
  so it can have the most current size, which otherwise is typically
  wrong at this point if we are attaching to an existing window that
  isn't the same size as the video.

* Clearing the backbuffer when created.  This leaves any newly exposed
  portions of a resized window black if the backbuffer gets used
  during an expose event but before a new frame has been rendered into
  it at its current size.
  
* During a resize operation, as long as the offscreen surface has not
  been destroyed (which was a nice improvement in r28379 compared to
  an older version I had been using), it is used to refresh the
  backbuffer at its new size, thus adjusting the current frame.  (This
  change extracts the StretchRect operation to the backbuffer from
  render_d3d_frame to be common to their and resize_d3d)
  
* Refreshing the display both on an expose event as well as a resize
  event.  The latter supports a resize to a smaller window since
  otherwise Windows typically doesn't consider the new smaller window
  contents to be invalidated.

-- David

Index: vo_direct3d.c
===================================================================
--- vo_direct3d.c	(revision 29004)
+++ vo_direct3d.c	(working copy)
@@ -225,12 +225,22 @@
         return 0;
     }
 
-    if (!priv->d3d_backbuf &&
-        FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0,
-                                              D3DBACKBUFFER_TYPE_MONO,
-                                              &priv->d3d_backbuf))) {
-        mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Allocating backbuffer failed.\n");
-        return 0;
+    if (!priv->d3d_backbuf) {
+        if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0,
+                                                  D3DBACKBUFFER_TYPE_MONO,
+                                                  &priv->d3d_backbuf))) {
+            mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Allocating backbuffer failed.\n");
+            return 0;
+        }
+
+        /* Clear newly allocated backbuffer to cover case when it (or part
+           of it) is used before we render into it */
+        if (FAILED(IDirect3DDevice9_ColorFill(priv->d3d_device,
+                                              priv->d3d_backbuf, NULL,
+                                              D3DCOLOR_RGBA(0,0,0,255)))) {
+            mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>BackBuffer ColorFill failure\n");
+            return 0;
+        }
     }
 
     /* calculate the best size for the OSD depending on the factors from the device */
@@ -407,6 +417,10 @@
     if (!change_d3d_backbuffer(BACKBUFFER_CREATE))
         return 0;
 
+    /* Process events to update for accurate target window size (especially
+       when attaching to an existing window) */
+    vo_w32_check_events();
+
     if (!create_d3d_surfaces())
         return 0;
 
@@ -454,11 +468,48 @@
     return 1;
 }
 
+/** @brief Refresh backbuffer from offscreen surface
+ *  @return 1 on success, 0 on failure
+ */
+static int refresh_d3d_backbuffer()
+{
+    if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) {
+        mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>BeginScene failed.\n");
+        return 0;
+    }
+
+    if (priv->is_clear_needed) {
+        IDirect3DDevice9_Clear(priv->d3d_device, 0, NULL,
+                               D3DCLEAR_TARGET, 0, 0, 0);
+        priv->is_clear_needed = 0;
+    }
+
+    if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device,
+                                            priv->d3d_surface,
+                                            &priv->fs_panscan_rect,
+                                            priv->d3d_backbuf,
+                                            &priv->fs_movie_rect,
+                                            D3DTEXF_LINEAR))) {
+        mp_msg(MSGT_VO, MSGL_ERR,
+               "<vo_direct3d>Copying frame to the backbuffer failed.\n");
+        return 0;
+    }
+
+    if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) {
+        mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>EndScene failed.\n");
+        return 0;
+    }
+
+    return 1;
+}
+
 /** @brief Resize Direct3D context on window resize.
  *  @return 1 on success, 0 on failure
  */
 static int resize_d3d(void)
 {
+    int do_refresh = 1;
+
     D3DVIEWPORT9 vp = {0, 0, vo_dwidth, vo_dheight, 0, 1};
 
     mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>resize_d3d called.\n");
@@ -470,6 +521,8 @@
         vo_dheight > priv->cur_backbuf_height) {
         if (!change_d3d_backbuffer(BACKBUFFER_RESET))
             return 0;
+        /* This will have destroyed our offscreen surface, so can't refresh */
+        do_refresh = 0;
     }
 
     /* Destroy the OSD textures. They should always match the new dimensions
@@ -501,6 +554,11 @@
 
     calc_fs_rect();
 
+    if (do_refresh) {
+        if (!refresh_d3d_backbuffer())
+            return 0;
+    }
+
 #ifdef CONFIG_FREETYPE
     // font needs to be adjusted
     force_load_font = 1;
@@ -575,33 +633,10 @@
     }
     priv->locked_rect.pBits = NULL;
 
-    if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) {
-        mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>BeginScene failed.\n");
+    if (!refresh_d3d_backbuffer()) {
         return VO_ERROR;
     }
 
-    if (priv->is_clear_needed) {
-        IDirect3DDevice9_Clear(priv->d3d_device, 0, NULL,
-                               D3DCLEAR_TARGET, 0, 0, 0);
-        priv->is_clear_needed = 0;
-    }
-
-    if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device,
-                                            priv->d3d_surface,
-                                            &priv->fs_panscan_rect,
-                                            priv->d3d_backbuf,
-                                            &priv->fs_movie_rect,
-                                            D3DTEXF_LINEAR))) {
-        mp_msg(MSGT_VO, MSGL_ERR,
-               "<vo_direct3d>Copying frame to the backbuffer failed.\n");
-        return VO_ERROR;
-    }
-
-    if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) {
-        mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>EndScene failed.\n");
-        return VO_ERROR;
-    }
-
     return VO_TRUE;
 }
 
@@ -878,7 +913,9 @@
     if (flags & VO_EVENT_RESIZE)
         resize_d3d();
 
-    if ((flags & VO_EVENT_EXPOSE) && priv->is_paused)
+    /* Render frame on resize as well as expose, since resizing to a smaller
+       window may not otherwise generate a paint/expose event */
+    if ((flags & (VO_EVENT_EXPOSE | VO_EVENT_RESIZE)) && priv->is_paused)
         flip_page();
 }
 




More information about the MPlayer-dev-eng mailing list