Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28044) +++ libvo/vo_direct3d.c (working copy) @@ -169,12 +169,12 @@ priv->is_clear_needed = 1; } -/** @brief Destroy D3D Context related to the current window. +/** @brief Destroy D3D Offscreen and Backbuffer surfaces. */ -static void destroy_d3d_context(void) +static void destroy_d3d_surfaces(void) { - mp_msg(MSGT_VO,MSGL_V,"destroy_d3d_context called\r\n"); - /* Let's destroy the old (if any) D3D Content */ + mp_msg(MSGT_VO,MSGL_V,"destroy_d3d_surfaces called\r\n"); + /* Let's destroy the old (if any) D3D Surfaces */ if (priv->locked_rect.pBits) { IDirect3DSurface9_UnlockRect(priv->d3d_surface); @@ -186,32 +186,44 @@ priv->d3d_surface = NULL; } - if (priv->d3d_device != NULL) { - IDirect3DDevice9_Release (priv->d3d_device); - priv->d3d_device = NULL; + if (priv->d3d_backbuf != NULL) { + IDirect3DSurface9_Release (priv->d3d_backbuf); + priv->d3d_backbuf = NULL; } +} - /* The following is not a memory leak. d3d_backbuf is not malloc'ed - * but just holds a pointer to the back buffer. Nobody gets hurt from - * setting it to NULL. - */ - priv->d3d_backbuf = NULL; +/** @brief Create D3D Offscreen and Backbuffer surfaces. + * @return 1 on success, 0 on failure + */ +static int create_d3d_surfaces(void) +{ + if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( + priv->d3d_device, priv->src_width, priv->src_height, + priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); + return 0; + } + + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, + D3DBACKBUFFER_TYPE_MONO, + &(priv->d3d_backbuf)))) { + mp_msg(MSGT_VO,MSGL_ERR,"Back Buffer address get failed\n"); + return 0; + } } - -/** @brief (Re)Initialize Direct3D. Kill and recreate context. - * The first function called to initialize D3D context. +/** @brief Configure initial Direct3D context. The first + * function called to initialize the D3D context. * @return 1 on success, 0 on failure */ -static int reconfigure_d3d(void) +static int configure_d3d(void) { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; - mp_msg(MSGT_VO,MSGL_V,"reconfigure_d3d called \n"); + mp_msg(MSGT_VO,MSGL_V,"configure_d3d called \n"); - destroy_d3d_context(); - /* Get the current desktop display mode, so we can set up a back buffer * of the same format. */ if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, @@ -251,25 +263,83 @@ return 0; } - mp_msg(MSGT_VO,MSGL_V, - "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", - present_params.BackBufferWidth, present_params.BackBufferHeight, - vo_dwidth, vo_dheight); + if (!create_d3d_surfaces()) + return 0; - if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( - priv->d3d_device, priv->src_width, priv->src_height, - priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { + calc_fs_rect(); + + return 1; +} + +/** @brief Reconfigure the whole Direct3D. Called only + * when the video adapter becomes uncooperative. + * @return 1 on success, 0 on failure + */ +static int reconfigure_d3d(void) +{ + /* Destroy the Offscreen and Backbuffer surfaces */ + destroy_d3d_surfaces(); + + /* Destroy the D3D Device */ + if (priv->d3d_device != NULL) { + IDirect3DDevice9_Release (priv->d3d_device); + priv->d3d_device = NULL; + } + + /* Stop the whole Direct3D */ + IDirect3D9_Release (priv->d3d_handle); + + /* Initialize Direct3D from the beginning */ + priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); + if (!priv->d3d_handle) { + mp_msg(MSGT_VO,MSGL_ERR,"Unable to initialize Direct3D\n"); + return -1; + } + + /* Configure Direct3D */ + if (!configure_d3d()) + return 0; + + return 1; +} + + +/** @brief Resize Direct3D context on window resize. + * @return 1 on success, 0 on failure + */ +static int resize_d3d(void) +{ + D3DPRESENT_PARAMETERS present_params; + + mp_msg(MSGT_VO,MSGL_ERR, "RESIZE called.\n"); + + destroy_d3d_surfaces(); + + /* Prepare Direct3D initialization parameters. */ + memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); + present_params.Windowed = TRUE; + present_params.SwapEffect = D3DSWAPEFFECT_COPY; + present_params.Flags = D3DPRESENTFLAG_VIDEO; + present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ + present_params.BackBufferWidth = 0; /* Fill up window Width */ + present_params.BackBufferHeight = 0; /* Fill up window Height */ + present_params.MultiSampleType = D3DMULTISAMPLE_NONE; + /* D3DPRESENT_INTERVAL_ONE = vsync */ + present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + present_params.BackBufferFormat = priv->desktop_fmt; + present_params.BackBufferCount = 1; + present_params.EnableAutoDepthStencil = FALSE; + + if (FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) { mp_msg(MSGT_VO,MSGL_ERR, - "IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); + "Could not reset the D3D device\n"); return 0; } + else + mp_msg(MSGT_VO,MSGL_ERR, "Reset success.\n"); - if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, - D3DBACKBUFFER_TYPE_MONO, - &(priv->d3d_backbuf)))) { - mp_msg(MSGT_VO,MSGL_ERR,"Back Buffer address get failed\n"); + if (!create_d3d_surfaces()) return 0; - } calc_fs_rect(); @@ -282,9 +352,14 @@ { mp_msg(MSGT_VO,MSGL_V,"uninit_d3d called\r\n"); - /* Destroy D3D Context inside the window. */ - destroy_d3d_context(); + destroy_d3d_surfaces(); + /* Destroy the D3D Device */ + if (priv->d3d_device != NULL) { + IDirect3DDevice9_Release (priv->d3d_device); + priv->d3d_device = NULL; + } + /* Stop the whole D3D. */ if (NULL != priv->d3d_handle) { mp_msg(MSGT_VO,MSGL_V,"Calling IDirect3D9_Release\r\n"); @@ -480,7 +555,7 @@ return render_d3d_frame(data); case VOCTRL_FULLSCREEN: vo_w32_fullscreen(); - reconfigure_d3d(); + resize_d3d(); return VO_TRUE; case VOCTRL_RESET: return VO_NOTIMPL; @@ -501,7 +576,7 @@ return VO_TRUE; case VOCTRL_BORDER: vo_w32_border(); - reconfigure_d3d(); + resize_d3d(); return VO_TRUE; case VOCTRL_UPDATE_SCREENINFO: w32_update_xinerama_info(); @@ -542,7 +617,20 @@ return VO_ERROR; } - if (!reconfigure_d3d()) + /* "config" may be called several times, so if this is not the first + * call, we should destroy Direct3D adapter and surfaces before + * calling configure_d3d, which will create them again. + */ + + destroy_d3d_surfaces(); + + /* Destroy the D3D Device */ + if (priv->d3d_device != NULL) { + IDirect3DDevice9_Release (priv->d3d_device); + priv->d3d_device = NULL; + } + + if (!configure_d3d()) return VO_ERROR; return 0; /* Success */ @@ -558,6 +646,7 @@ mp_msg(MSGT_VO,MSGL_V, "Video adapter became uncooperative.\n"); mp_msg(MSGT_VO,MSGL_ERR,"Trying to reinitialize it...\n"); + if (!reconfigure_d3d()) { mp_msg(MSGT_VO,MSGL_V,"Reinitialization Failed.\n"); return; @@ -605,7 +694,7 @@ */ flags = vo_w32_check_events(); if (flags & VO_EVENT_RESIZE) - reconfigure_d3d(); + resize_d3d(); if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) flip_page();