[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