# HG changeset patch # User reimar # Date 1233050567 0 # Node ID a69d51cd4ee3cb531e43f5708fb507b9bec1130d # Parent e45b08f2f5d3270ae5811c2bf74f72d9e12b723f Allocate a larger backbuffer to allow resizing without reinit. Patch by Georgi Petrov [gogothebee gmail com] and Jim Hauxwell [james (at) dattrax co uk] diff -r e45b08f2f5d3 -r a69d51cd4ee3 libvo/vo_direct3d.c --- a/libvo/vo_direct3d.c Mon Jan 26 15:06:44 2009 +0000 +++ b/libvo/vo_direct3d.c Tue Jan 27 10:02:47 2009 +0000 @@ -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 @@ -126,6 +128,10 @@ float tu, tv; /* Texture coordinates */ } struct_vertex; +typedef enum back_buffer_action { + BACKBUFFER_CREATE, + BACKBUFFER_RESET +} back_buffer_action_e; /**************************************************************************** * * * * @@ -224,7 +230,8 @@ priv->d3d_backbuf = NULL; } -/** @brief Create D3D Offscreen and Backbuffer surfaces. +/** @brief Create D3D Offscreen and Backbuffer surfaces. Each + * surface is created only if it's not already present. * @return 1 on success, 0 on failure */ static int create_d3d_surfaces(void) @@ -233,7 +240,8 @@ int tex_width = osd_width, tex_height = osd_height; mp_msg(MSGT_VO, MSGL_V, "create_d3d_surfaces called.\n"); - if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( + if (!priv->d3d_surface && + 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, @@ -241,7 +249,8 @@ return 0; } - if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 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, "Back Buffer address get failed\n"); @@ -279,7 +288,8 @@ vo_dwidth, vo_dheight, priv->osd_texture_width, priv->osd_texture_height); /* create OSD */ - if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, + if (!priv->d3d_texture_system && + FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, priv->osd_texture_width, priv->osd_texture_height, 1, @@ -295,7 +305,8 @@ if (!priv->device_texture_sys) { /* only create if we need a shadow version on the external device */ - if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, + if (!priv->d3d_texture_osd && + FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, priv->osd_texture_width, priv->osd_texture_height, 1, @@ -332,27 +343,78 @@ 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; present_params->BackBufferFormat = priv->desktop_fmt; present_params->BackBufferCount = 1; present_params->EnableAutoDepthStencil = FALSE; } + +/** @brief Create a new backbuffer. Create or Reset the D3D + * device. + * @return 1 on success, 0 on failure + */ +static int change_d3d_backbuffer(back_buffer_action_e action) +{ + D3DPRESENT_PARAMETERS present_params; + + destroy_d3d_surfaces(); + + /* 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_height) + priv->cur_backbuf_height = 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); + + /* vo_w32_window is w32_common variable. It's a handle to the window. */ + if (action == BACKBUFFER_CREATE && + FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, vo_w32_window, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &present_params, &priv->d3d_device))) { + mp_msg(MSGT_VO, MSGL_ERR, + "Could not create the D3D device\n"); + return 0; + } + + if (action == BACKBUFFER_RESET && + FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) { + mp_msg(MSGT_VO, MSGL_ERR, + "Could not reset the D3D device\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 Configure initial Direct3D context. The first * function called to initialize the D3D context. * @return 1 on success, 0 on failure */ static int configure_d3d(void) { - 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"); + destroy_d3d_surfaces(); + /* 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, @@ -366,26 +428,17 @@ /* Write current Desktop's colorspace format in the global storage. */ priv->desktop_fmt = disp_mode.Format; - 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, - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, vo_w32_window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &present_params, &priv->d3d_device))) { - mp_msg(MSGT_VO, MSGL_ERR, - "Could not create the D3D device\n"); + if (!change_d3d_backbuffer(BACKBUFFER_CREATE)) 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); + 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(); @@ -400,7 +453,7 @@ { mp_msg(MSGT_VO, MSGL_V, "reconfigure_d3d called.\n"); - /* Destroy the Offscreen and Backbuffer surfaces */ + /* Destroy the offscreen, OSD and backbuffer surfaces */ destroy_d3d_surfaces(); /* Destroy the D3D Device */ @@ -425,35 +478,49 @@ 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; + D3DVIEWPORT9 vp = {0, 0, vo_dwidth, vo_dheight, 0, 1}; mp_msg(MSGT_VO, MSGL_V, "resize_d3d called.\n"); - destroy_d3d_surfaces(); + /* Make sure that backbuffer is large enough to accomodate the new + viewport dimensions. Grow it if necessary. */ - /* Reset the D3D Device with all parameters the same except the new - * width/height. + if (vo_dwidth > priv->cur_backbuf_width || + vo_dheight > priv->cur_backbuf_height) { + change_d3d_backbuffer (BACKBUFFER_RESET); + } + + /* Destroy the OSD textures. They should always match the new dimensions + * of the onscreen window, so on each resize we need new OSD dimensions. */ - 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 (priv->d3d_texture_osd) + IDirect3DTexture9_Release(priv->d3d_texture_osd); + priv->d3d_texture_osd = NULL; + + if (priv->d3d_texture_system) + IDirect3DTexture9_Release(priv->d3d_texture_system); + priv->d3d_texture_system = NULL; + + + /* Recreate the OSD. The function will observe that the offscreen plain + * surface and the backbuffer are not destroyed and will skip their creation, + * effectively recreating only the OSD. + */ 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); + 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(); @@ -644,8 +711,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, @@ -787,7 +856,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 +865,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; }