summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libvo/vo_direct3d.c282
1 files changed, 111 insertions, 171 deletions
diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c
index 619fa09fdc..33265c9c36 100644
--- a/libvo/vo_direct3d.c
+++ b/libvo/vo_direct3d.c
@@ -127,6 +127,7 @@ typedef struct d3d_priv {
int opt_only_8bit;
int opt_disable_eosd;
int opt_disable_texture_align;
+ int opt_force_power_of_2;
struct vo *vo;
@@ -223,16 +224,11 @@ static const struct fmt_entry fmt_table[] = {
};
-typedef enum back_buffer_action {
- BACKBUFFER_CREATE,
- BACKBUFFER_RESET
-} back_buffer_action_e;
-
static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *);
static void draw_eosd(d3d_priv *priv);
static void update_colorspace(d3d_priv *priv);
static void d3d_clear_video_textures(d3d_priv *priv);
-static int resize_d3d(d3d_priv *priv);
+static bool resize_d3d(d3d_priv *priv);
static uint32_t d3d_draw_frame(d3d_priv *priv);
static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h,
int x, int y);
@@ -477,6 +473,8 @@ static void destroy_d3d_surfaces(d3d_priv *priv)
if (priv->eosd)
eosd_packer_reinit(priv->eosd, 0, 0);
+
+ priv->d3d_in_scene = false;
}
// Allocate video surface or textures, and create shaders if needed.
@@ -577,11 +575,11 @@ static void d3d_clear_video_textures(d3d_priv *priv)
d3d_unlock_video_objects(priv);
}
-/** @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(d3d_priv *priv)
+// Recreate and initialize D3D objects if necessary. The amount of work that
+// needs to be done can be quite different: it could be that full initialization
+// is required, or that some objects need to be created, or that nothing is
+// done.
+static bool create_d3d_surfaces(d3d_priv *priv)
{
int osd_width = priv->vo->dwidth, osd_height = priv->vo->dheight;
int tex_width = osd_width, tex_height = osd_height;
@@ -663,6 +661,70 @@ static int create_d3d_surfaces(d3d_priv *priv)
return 1;
}
+static bool init_d3d(d3d_priv *priv)
+{
+ D3DDISPLAYMODE disp_mode;
+ D3DCAPS9 disp_caps;
+ DWORD texture_caps;
+ DWORD dev_caps;
+
+ priv->d3d_handle = priv->pDirect3DCreate9(D3D_SDK_VERSION);
+ if (!priv->d3d_handle) {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Initializing Direct3D failed.\n");
+ return false;
+ }
+
+ if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle,
+ D3DADAPTER_DEFAULT,
+ &disp_mode))) {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Reading display mode failed.\n");
+ return false;
+ }
+
+ 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,
+ "<vo_direct3d>Setting backbuffer dimensions to (%dx%d).\n",
+ disp_mode.Width, disp_mode.Height);
+
+ if (FAILED(IDirect3D9_GetDeviceCaps(priv->d3d_handle,
+ D3DADAPTER_DEFAULT,
+ DEVTYPE,
+ &disp_caps)))
+ {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Reading display capabilities failed.\n");
+ return false;
+ }
+
+ /* Store relevant information reguarding caps of device */
+ texture_caps = disp_caps.TextureCaps;
+ dev_caps = disp_caps.DevCaps;
+ priv->device_caps_power2_only = (texture_caps & D3DPTEXTURECAPS_POW2) &&
+ !(texture_caps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
+ priv->device_caps_square_only = texture_caps & D3DPTEXTURECAPS_SQUAREONLY;
+ priv->device_texture_sys = dev_caps & D3DDEVCAPS_TEXTURESYSTEMMEMORY;
+ priv->max_texture_width = disp_caps.MaxTextureWidth;
+ priv->max_texture_height = disp_caps.MaxTextureHeight;
+
+ if (priv->opt_force_power_of_2)
+ priv->device_caps_power2_only = 1;
+
+ mp_msg(MSGT_VO, MSGL_V,
+ "<vo_direct3d>device_caps_power2_only %d, device_caps_square_only %d\n"
+ "<vo_direct3d>device_texture_sys %d\n"
+ "<vo_direct3d>max_texture_width %d, max_texture_height %d\n",
+ priv->device_caps_power2_only, priv->device_caps_square_only,
+ priv->device_texture_sys, priv->max_texture_width,
+ priv->max_texture_height);
+
+ return true;
+}
+
/** @brief Fill D3D Presentation parameters
*/
static void fill_d3d_presentparams(d3d_priv *priv,
@@ -684,16 +746,11 @@ static void fill_d3d_presentparams(d3d_priv *priv,
}
-/** @brief Create a new backbuffer. Create or Reset the D3D
- * device.
- * @return 1 on success, 0 on failure
- */
-static int change_d3d_backbuffer(d3d_priv *priv, back_buffer_action_e action)
+// Create a new backbuffer. Create or Reset the D3D device.
+static bool change_d3d_backbuffer(d3d_priv *priv)
{
D3DPRESENT_PARAMETERS present_params;
- destroy_d3d_surfaces(priv);
-
int window_w = priv->vo->dwidth;
int window_h = priv->vo->dheight;
@@ -709,23 +766,23 @@ static int change_d3d_backbuffer(d3d_priv *priv, back_buffer_action_e action)
*/
fill_d3d_presentparams(priv, &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,
- DEVTYPE, vo_w32_window,
- D3DCREATE_SOFTWARE_VERTEXPROCESSING,
- &present_params, &priv->d3d_device))) {
+ if (!priv->d3d_device) {
+ if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle,
+ D3DADAPTER_DEFAULT,
+ DEVTYPE, vo_w32_window,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING,
+ &present_params, &priv->d3d_device)))
+ {
mp_msg(MSGT_VO, MSGL_V,
"<vo_direct3d>Creating Direct3D device failed.\n");
- return 0;
- }
-
- if (action == BACKBUFFER_RESET &&
- FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) {
+ return 0;
+ }
+ } else {
+ if (FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) {
mp_msg(MSGT_VO, MSGL_ERR,
"<vo_direct3d>Reseting Direct3D device failed.\n");
- return 0;
+ return 0;
+ }
}
mp_msg(MSGT_VO, MSGL_V,
@@ -736,43 +793,8 @@ static int change_d3d_backbuffer(d3d_priv *priv, back_buffer_action_e action)
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(d3d_priv *priv)
-{
- D3DDISPLAYMODE disp_mode;
-
- mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>configure_d3d called.\n");
-
- destroy_d3d_surfaces(priv);
-
- /* 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,
- D3DADAPTER_DEFAULT,
- &disp_mode))) {
- mp_msg(MSGT_VO, MSGL_ERR,
- "<vo_direct3d>Reading adapter display mode failed.\n");
- return 0;
- }
-
- priv->desktop_fmt = disp_mode.Format;
-
- if (!change_d3d_backbuffer(priv, BACKBUFFER_CREATE))
- return 0;
-
- if (!create_d3d_surfaces(priv))
- return 0;
-
- resize_d3d(priv);
-
- return 1;
-}
-
/** @brief Reconfigure the whole Direct3D. Called only
- * when the video adapter becomes uncooperative.
+ * when the video adapter becomes uncooperative. ("Lost" devices)
* @return 1 on success, 0 on failure
*/
static int reconfigure_d3d(d3d_priv *priv)
@@ -781,28 +803,28 @@ static int reconfigure_d3d(d3d_priv *priv)
destroy_d3d_surfaces(priv);
- if (priv->d3d_device)
- IDirect3DDevice9_Release(priv->d3d_device);
+ IDirect3DDevice9_Release(priv->d3d_device);
priv->d3d_device = NULL;
+ // Force complete destruction of the D3D state.
+ // Note: this step could be omitted. The resize_d3d call below would detect
+ // that d3d_device is NULL, and would properly recreate it. I'm not sure why
+ // the following code to release and recreate the d3d_handle exists.
IDirect3D9_Release(priv->d3d_handle);
-
- priv->d3d_handle = priv->pDirect3DCreate9(D3D_SDK_VERSION);
- if (!priv->d3d_handle) {
- mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Initializing Direct3D failed.\n");
+ priv->d3d_handle = NULL;
+ if (!init_d3d(priv))
return 0;
- }
- if (!configure_d3d(priv))
+ // Proper re-initialization.
+ if (!resize_d3d(priv))
return 0;
return 1;
}
-/** @brief Resize Direct3D context on window resize.
- * @return 1 on success, 0 on failure
- */
-static int resize_d3d(d3d_priv *priv)
+// Resize Direct3D context on window resize.
+// This function also is called when major initializations need to be done.
+static bool resize_d3d(d3d_priv *priv)
{
D3DVIEWPORT9 vp = {0, 0, priv->vo->dwidth, priv->vo->dheight, 0, 1};
@@ -812,17 +834,14 @@ static int resize_d3d(d3d_priv *priv)
viewport dimensions. Grow it if necessary. */
if (priv->vo->dwidth > priv->cur_backbuf_width ||
- priv->vo->dheight > priv->cur_backbuf_height)
+ priv->vo->dheight > priv->cur_backbuf_height ||
+ !priv->d3d_device)
{
- if (!change_d3d_backbuffer(priv, BACKBUFFER_RESET))
+ destroy_d3d_surfaces(priv);
+ if (!change_d3d_backbuffer(priv))
return 0;
}
- /* 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(priv))
return 0;
@@ -890,11 +909,6 @@ static uint32_t d3d_upload_and_render_frame_texture(d3d_priv *priv,
*/
static uint32_t d3d_upload_and_render_frame(d3d_priv *priv, mp_image_t *mpi)
{
- /* If the D3D device is uncooperative (not initialized), return success.
- The device will be probed for reinitialization in the next flip_page() */
- if (!priv->d3d_device)
- return VO_TRUE;
-
if (priv->use_textures)
return d3d_upload_and_render_frame_texture(priv, mpi);
@@ -1273,11 +1287,6 @@ const char *options_help_text = "-vo direct3d command line help:\n"
static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
{
- D3DDISPLAYMODE disp_mode;
- D3DCAPS9 disp_caps;
- DWORD texture_caps;
- DWORD dev_caps;
-
d3d_priv *priv = talloc_zero(vo, d3d_priv);
vo->priv = priv;
@@ -1292,8 +1301,6 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
priv->opt_disable_shaders = priv->opt_disable_textures = true;
}
- int opt_force_power_of_2 = false;
-
const opt_t subopts[] = {
{"prefer-stretchrect", OPT_ARG_BOOL, &priv->opt_prefer_stretchrect},
{"disable-textures", OPT_ARG_BOOL, &priv->opt_disable_textures},
@@ -1301,7 +1308,7 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
{"disable-shaders", OPT_ARG_BOOL, &priv->opt_disable_shaders},
{"only-8bit", OPT_ARG_BOOL, &priv->opt_only_8bit},
{"disable-eosd", OPT_ARG_BOOL, &priv->opt_disable_eosd},
- {"force-power-of-2", OPT_ARG_BOOL, &opt_force_power_of_2},
+ {"force-power-of-2", OPT_ARG_BOOL, &priv->opt_force_power_of_2},
{"disable-texture-align", OPT_ARG_BOOL, &priv->opt_disable_texture_align},
{NULL}
};
@@ -1328,59 +1335,8 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
goto err_out;
}
- priv->d3d_handle = priv->pDirect3DCreate9(D3D_SDK_VERSION);
- if (!priv->d3d_handle) {
- mp_msg(MSGT_VO, MSGL_ERR,
- "<vo_direct3d>Initializing Direct3D failed.\n");
- goto err_out;
- }
-
- if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle,
- D3DADAPTER_DEFAULT,
- &disp_mode))) {
- mp_msg(MSGT_VO, MSGL_ERR,
- "<vo_direct3d>Reading display mode failed.\n");
- goto err_out;
- }
-
- 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,
- "<vo_direct3d>Setting backbuffer dimensions to (%dx%d).\n",
- disp_mode.Width, disp_mode.Height);
-
- if (FAILED(IDirect3D9_GetDeviceCaps(priv->d3d_handle,
- D3DADAPTER_DEFAULT,
- DEVTYPE,
- &disp_caps)))
- {
- mp_msg(MSGT_VO, MSGL_ERR,
- "<vo_direct3d>Reading display capabilities failed.\n");
+ if (!init_d3d(priv))
goto err_out;
- }
-
- /* Store relevant information reguarding caps of device */
- texture_caps = disp_caps.TextureCaps;
- dev_caps = disp_caps.DevCaps;
- priv->device_caps_power2_only = (texture_caps & D3DPTEXTURECAPS_POW2) &&
- !(texture_caps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
- priv->device_caps_square_only = texture_caps & D3DPTEXTURECAPS_SQUAREONLY;
- priv->device_texture_sys = dev_caps & D3DDEVCAPS_TEXTURESYSTEMMEMORY;
- priv->max_texture_width = disp_caps.MaxTextureWidth;
- priv->max_texture_height = disp_caps.MaxTextureHeight;
-
- if (opt_force_power_of_2)
- priv->device_caps_power2_only = 1;
-
- mp_msg(MSGT_VO, MSGL_V,
- "<vo_direct3d>device_caps_power2_only %d, device_caps_square_only %d\n"
- "<vo_direct3d>device_texture_sys %d\n"
- "<vo_direct3d>max_texture_width %d, max_texture_height %d\n",
- priv->device_caps_power2_only, priv->device_caps_square_only,
- priv->device_texture_sys, priv->max_texture_width,
- priv->max_texture_height);
/* w32_common framework call. Configures window on the screen, gets
* fullscreen dimensions and does other useful stuff.
@@ -1532,13 +1488,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
init_rendering_mode(priv, format, true);
}
- if (!priv->d3d_device) {
- if (!configure_d3d(priv))
- return VO_ERROR;
- } else {
- if (!resize_d3d(priv))
- return VO_ERROR;
- }
+ if (!resize_d3d(priv))
+ return VO_ERROR;
return 0; /* Success */
}
@@ -1564,6 +1515,8 @@ static void flip_page(struct vo *vo)
"<vo_direct3d>Trying to reinitialize uncooperative video adapter.\n");
if (!reconfigure_d3d(priv)) {
mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Reinitialization failed.\n");
+ // device recreation failed; we can't deal with this
+ assert(priv->d3d_device);
return;
} else {
mp_msg(MSGT_VO, MSGL_V,
@@ -1640,11 +1593,6 @@ static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h,
char *dst; /**< Pointer to the destination image */
int uv_stride; /**< Stride of the U/V planes */
- /* If the D3D device is uncooperative (not initialized), return success.
- The device will be probed for reinitialization in the next flip_page() */
- if (!priv->d3d_device)
- return 0;
-
if (priv->use_textures)
return draw_slice_textures(priv, src, stride, w, h, x, y);
@@ -1745,10 +1693,6 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
{
d3d_priv *priv = vo->priv;
- // we can not render OSD if we lost the device e.g. because it was uncooperative
- if (!priv->d3d_device)
- return;
-
if (vo_osd_changed(0)) {
struct draw_osd_closure ctx = { priv };
@@ -1924,10 +1868,6 @@ static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *imgs)
static void draw_eosd(d3d_priv *priv)
{
- // we can not render OSD if we lost the device e.g. because it was uncooperative
- if (!priv->d3d_device)
- return;
-
if (!priv->eosd->targets_count)
return;