Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28145) +++ libvo/vo_direct3d.c (working copy) @@ -56,7 +56,7 @@ 0 = Movie is not paused */ int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect 0 = (default) Don't clear it */ - D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ + D3DLOCKED_RECT locked_rect; /**< The locked offscreen surface */ RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed in fullscreen */ RECT fs_panscan_rect; /**< PanScan source surface cropping in @@ -78,6 +78,8 @@ cannot lock a normal texture. Uses RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + int cur_backbuf_width; /**< Current backbuffer width */ + int cur_backbuf_height; /**< Current backbuffer height */ int is_osd_populated; /**< 1 = OSD texture has something to display, 0 = OSD texture is clear */ int device_caps_power2_only; /**< 1 = texture sizes have to be power 2 @@ -195,21 +197,13 @@ priv->is_clear_needed = 1; } -/** @brief Destroy D3D Offscreen and Backbuffer surfaces. +/** @brief Destroy D3D OSD textures. */ -static void destroy_d3d_surfaces(void) +static void destroy_d3d_osd_textures(void) { - mp_msg(MSGT_VO, MSGL_V, "destroy_d3d_surfaces called\r\n"); - /* Let's destroy the old (if any) D3D Surfaces */ + mp_msg(MSGT_VO, MSGL_V, "destroy_d3d_osd_textures called\r\n"); + /* Let's destroy the old (if any) D3D OSD textures. */ - if (priv->locked_rect.pBits) - IDirect3DSurface9_UnlockRect(priv->d3d_surface); - priv->locked_rect.pBits = NULL; - - if (priv->d3d_surface) - IDirect3DSurface9_Release(priv->d3d_surface); - priv->d3d_surface = NULL; - /* kill the OSD texture and its shadow copy */ if (priv->d3d_texture_osd) IDirect3DTexture9_Release(priv->d3d_texture_osd); @@ -218,36 +212,17 @@ if (priv->d3d_texture_system) IDirect3DTexture9_Release(priv->d3d_texture_system); priv->d3d_texture_system = NULL; - - if (priv->d3d_backbuf) - IDirect3DSurface9_Release(priv->d3d_backbuf); - priv->d3d_backbuf = NULL; } -/** @brief Create D3D Offscreen and Backbuffer surfaces. +/** @brief Create D3D OSD textures. * @return 1 on success, 0 on failure */ -static int create_d3d_surfaces(void) +static int create_d3d_osd_textures(void) { int osd_width = vo_dwidth, osd_height = vo_dheight; int tex_width = osd_width, tex_height = osd_height; - mp_msg(MSGT_VO, MSGL_V, "create_d3d_surfaces called.\n"); + mp_msg(MSGT_VO, MSGL_V, "create_d3d_osd_textures 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; - } - /* calculate the best size for the OSD depending on the factors from the device */ if (priv->device_caps_power2_only) { tex_width = 1; @@ -332,8 +307,8 @@ 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->BackBufferWidth = priv->cur_backbuf_width; + present_params->BackBufferHeight = priv->cur_backbuf_height; present_params->MultiSampleType = D3DMULTISAMPLE_NONE; /* D3DPRESENT_INTERVAL_ONE = vsync */ present_params->PresentationInterval = D3DPRESENT_INTERVAL_ONE; @@ -350,6 +325,7 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + D3DVIEWPORT9 vp = {0, 0, vo_dwidth, vo_dheight, 0, 1}; mp_msg(MSGT_VO, MSGL_V, "configure_d3d called\n"); @@ -366,6 +342,13 @@ /* Write current Desktop's colorspace format in the global storage. */ priv->desktop_fmt = disp_mode.Format; + /* Grow the backbuffer if movie's bigger than the monitor dimensions. */ + if (vo_dwidth > priv->cur_backbuf_width) + priv->cur_backbuf_width = vo_dwidth; + + if (vo_dheight > priv->cur_backbuf_width) + priv->cur_backbuf_width = vo_dheight; + fill_d3d_presentparams(&present_params); /* vo_w32_window is w32_common variable. It's a handle to the window. */ @@ -379,14 +362,35 @@ return 0; } - if (!create_d3d_surfaces()) + if (!create_d3d_osd_textures()) 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; + } + + 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; + } + 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 (FAILED(IDirect3DDevice9_SetViewport(priv->d3d_device, + &vp))) { + mp_msg(MSGT_VO, MSGL_ERR, "Unable to set the viewport\n"); + return VO_ERROR; + } + calc_fs_rect(); return 1; @@ -400,9 +404,18 @@ { mp_msg(MSGT_VO, MSGL_V, "reconfigure_d3d called.\n"); - /* Destroy the Offscreen and Backbuffer surfaces */ - destroy_d3d_surfaces(); + /* Unlock and release the D3D offscreen surface */ + if (priv->locked_rect.pBits) + IDirect3DSurface9_UnlockRect(priv->d3d_surface); + priv->locked_rect.pBits = NULL; + if (priv->d3d_surface) + IDirect3DSurface9_Release(priv->d3d_surface); + priv->d3d_surface = NULL; + + /* Destroy the OSD textures */ + destroy_d3d_osd_textures(); + /* Destroy the D3D Device */ if (priv->d3d_device) IDirect3DDevice9_Release(priv->d3d_device); @@ -425,20 +438,48 @@ return 1; } - -/** @brief Resize Direct3D context on window resize. +/** @brief Check if the backbuffer should be grown and do it. + * This functions only grows the backbuffer in one/both + * directions. No shrinking is allowed (in any direction). * @return 1 on success, 0 on failure */ -static int resize_d3d(void) +static int check_d3d_backbuffer_dimensions(void) { D3DPRESENT_PARAMETERS present_params; - mp_msg(MSGT_VO, MSGL_V, "resize_d3d called.\n"); + if (vo_dwidth <= priv->cur_backbuf_width && + vo_dheight <= priv->cur_backbuf_height) + return 1; - destroy_d3d_surfaces(); + /* One (or both) of the required dimensions (vo_dwidth / vo_dheight) + * are larger than the current backbuffer. Let's grow it. + */ - /* Reset the D3D Device with all parameters the same except the new - * width/height. + /* Unlock and release the D3D offscreen surface */ + if (priv->locked_rect.pBits) + IDirect3DSurface9_UnlockRect(priv->d3d_surface); + priv->locked_rect.pBits = NULL; + + if (priv->d3d_surface) + IDirect3DSurface9_Release(priv->d3d_surface); + priv->d3d_surface = NULL; + + /* Destroy the OSD textures */ + destroy_d3d_osd_textures(); + + if (priv->d3d_backbuf) + IDirect3DSurface9_Release(priv->d3d_backbuf); + priv->d3d_backbuf = NULL; + + /* Grow the backbuffer in the required dimension. */ + if (vo_dwidth > priv->cur_backbuf_width) + priv->cur_backbuf_width = vo_dwidth; + + if (vo_dheight > priv->cur_backbuf_width) + priv->cur_backbuf_width = vo_dheight; + + /* The grown backbuffer dimensions are ready and fill_d3d_presentparams + * will use them, so we can reset the device. */ fill_d3d_presentparams(&present_params); if (FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) { @@ -447,14 +488,54 @@ return 0; } - if (!create_d3d_surfaces()) + 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; + } + 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); + return 1; +} + +/** @brief Resize Direct3D context on window resize. + * @return 1 on success, 0 on failure + */ +static int resize_d3d(void) +{ + D3DVIEWPORT9 vp = {0, 0, vo_dwidth, vo_dheight, 0, 1}; + + mp_msg(MSGT_VO, MSGL_V, "resize_d3d called.\n"); + + /* Make sure that backbuffer is large enough to accomodate the new + viewport dimensions. Grow it if necessary. */ + if (!check_d3d_backbuffer_dimensions()) + return 0; + + if (FAILED(IDirect3DDevice9_SetViewport(priv->d3d_device, + &vp))) { + mp_msg(MSGT_VO, MSGL_ERR, "Unable to set the viewport\n"); + return VO_ERROR; + } + + destroy_d3d_osd_textures(); + + if (!create_d3d_osd_textures()) + return 0; + calc_fs_rect(); #ifdef CONFIG_FREETYPE @@ -473,8 +554,20 @@ { mp_msg(MSGT_VO, MSGL_V, "uninit_d3d called\r\n"); - destroy_d3d_surfaces(); + if (priv->locked_rect.pBits) + IDirect3DSurface9_UnlockRect(priv->d3d_surface); + priv->locked_rect.pBits = NULL; + if (priv->d3d_surface) + IDirect3DSurface9_Release(priv->d3d_surface); + priv->d3d_surface = NULL; + + if (priv->d3d_backbuf) + IDirect3DSurface9_Release(priv->d3d_backbuf); + priv->d3d_backbuf = NULL; + + destroy_d3d_osd_textures(); + /* Destroy the D3D Device */ if (priv->d3d_device) IDirect3DDevice9_Release(priv->d3d_device); @@ -644,8 +737,10 @@ /* Store in priv->desktop_fmt the user desktop's colorspace. Usually XRGB. */ priv->desktop_fmt = disp_mode.Format; + priv->cur_backbuf_width = disp_mode.Width; + priv->cur_backbuf_height = disp_mode.Height; - mp_msg(MSGT_VO, MSGL_V, "disp_mode.Width %d, disp_mode.Height %d\n", + mp_msg(MSGT_VO, MSGL_V, "Setting backbuffer to the screen width: %d, height: %d\n", disp_mode.Width, disp_mode.Height); if (FAILED(IDirect3D9_GetDeviceCaps(priv->d3d_handle, @@ -769,7 +864,7 @@ * calling configure_d3d, which will create them again. */ - destroy_d3d_surfaces(); + destroy_d3d_osd_textures(); /* Destroy the D3D Device */ if (priv->d3d_device) @@ -787,7 +882,8 @@ */ static void flip_page(void) { - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + RECT rect = {0, 0, vo_dwidth, vo_dheight}; + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, &rect, 0, 0, 0))) { mp_msg(MSGT_VO, MSGL_V, "Video adapter became uncooperative.\n"); mp_msg(MSGT_VO, MSGL_ERR, "Trying to reinitialize it...\n"); @@ -795,7 +891,7 @@ mp_msg(MSGT_VO, MSGL_V, "Reinitialization Failed.\n"); return; } - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, &rect, 0, 0, 0))) { mp_msg(MSGT_VO, MSGL_V, "Reinitialization Failed.\n"); return; }