Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28049) +++ libvo/vo_direct3d.c (working copy) @@ -168,12 +168,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); @@ -185,32 +185,68 @@ 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) +{ + mp_msg(MSGT_VO, MSGL_V, "create_d3d_surfaces called.\n"); + + 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; + } + + return 1; } +/** @brief Fill D3D Presentation parameters + */ +static void fill_d3d_presentparams(D3DPRESENT_PARAMETERS *present_params) +{ + /* 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; +} -/** @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, "configure_d3d called \n"); - mp_msg(MSGT_VO, MSGL_V, "reconfigure_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, @@ -224,20 +260,7 @@ /* Write current Desktop's colorspace format in the global storage. */ priv->desktop_fmt = disp_mode.Format; - /* 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; + fill_d3d_presentparams(&present_params); /* vo_w32_window is w32_common variable. It's a handle to the window. */ if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, @@ -250,30 +273,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))) { - mp_msg(MSGT_VO, MSGL_ERR, - "IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); - 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); + + 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) +{ + mp_msg(MSGT_VO, MSGL_V, "reconfigure_d3d called.\n"); + + /* 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; } - 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"); + /* 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_V, "resize_d3d called.\n"); + + destroy_d3d_surfaces(); + + /* Reset the D3D Device with all parameters the same except the new + * width/height. + */ + fill_d3d_presentparams(&present_params); + if (FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) { + mp_msg(MSGT_VO,MSGL_ERR, + "Could not reset the D3D device\n"); + return 0; } + if (!create_d3d_surfaces()) + 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); + calc_fs_rect(); return 1; @@ -285,9 +361,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"); @@ -481,7 +562,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; @@ -502,7 +583,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(); @@ -543,7 +624,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 */ @@ -606,7 +700,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();