summaryrefslogtreecommitdiffstats
path: root/libvo/vo_direct3d.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvo/vo_direct3d.c')
-rw-r--r--libvo/vo_direct3d.c318
1 files changed, 166 insertions, 152 deletions
diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c
index 0bd00ec6fe..c48dabbac9 100644
--- a/libvo/vo_direct3d.c
+++ b/libvo/vo_direct3d.c
@@ -22,6 +22,8 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
+#include <stdbool.h>
#include <assert.h>
#include <d3d9.h>
#include "config.h"
@@ -72,6 +74,23 @@ typedef struct {
float tu, tv;
} vertex_eosd;
+struct d3dtex {
+ // user-requested size
+ int w, h;
+ // allocated texture size
+ int tex_w, tex_h;
+ // D3DPOOL_SYSTEMMEM texture:
+ // - can be locked in order to write (and even read) data
+ // - can _not_ (probably) be used as texture for rendering
+ // This is always non-NULL if d3dtex_allocate succeeds.
+ IDirect3DTexture9 *system;
+ // D3DPOOL_DEFAULT texture:
+ // - can't be locked (Probably.)
+ // - must be used for rendering
+ // This will be NULL on systems with device_texture_sys != 0.
+ IDirect3DTexture9 *device;
+};
+
/* Global variables "priv" structure. I try to keep their count low.
*/
static struct global_priv {
@@ -102,12 +121,10 @@ static struct global_priv {
IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer
renders inside it. Uses colorspace
priv->movie_src_fmt */
- IDirect3DTexture9 *d3d_texture_osd; /**< Direct3D Texture. Uses RGBA */
- IDirect3DTexture9 *d3d_texture_system; /**< Direct3D Texture. System memory
- cannot lock a normal texture. Uses RGBA */
+ struct d3dtex texture_osd; /**< RGBA */
IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to
display next frame) */
- IDirect3DTexture9 *d3d_texture_eosd; /**< Direct3D Texture. Uses A8L8 */
+ struct d3dtex texture_eosd; /**< A8 or A8L8 (see USE_A8) */
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,
@@ -120,12 +137,6 @@ static struct global_priv {
0 = device requires shadow */
int max_texture_width; /**< from the device capabilities */
int max_texture_height; /**< from the device capabilities */
- int osd_width; /**< current width of the OSD */
- int osd_height; /**< current height of the OSD */
- int osd_texture_width; /**< current width of the OSD texture */
- int osd_texture_height; /**< current height of the OSD texture */
- int eosd_texture_width;
- int eosd_texture_height;
struct eosd_packer *eosd; /**< EOSD packer (image positions etc.) */
vertex_eosd *eosd_vb; /**< temporary memory for D3D when rendering EOSD */
@@ -208,52 +219,18 @@ static void calc_fs_rect(void)
priv->is_clear_needed = 1;
}
-/** @brief Destroy D3D Offscreen and Backbuffer surfaces.
- */
-static void destroy_d3d_surfaces(void)
-{
- mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>destroy_d3d_surfaces called.\n");
- /* Let's destroy the old (if any) 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;
-
- /* kill the OSD texture and its shadow copy */
- 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;
-
- if (priv->d3d_backbuf)
- IDirect3DSurface9_Release(priv->d3d_backbuf);
- priv->d3d_backbuf = NULL;
-
- if (priv->d3d_texture_eosd)
- IDirect3DSurface9_Release(priv->d3d_texture_eosd);
- priv->d3d_texture_eosd = NULL;
- priv->eosd_texture_width = priv->eosd_texture_height = 0;
-
- if (priv->eosd)
- eosd_packer_reinit(priv->eosd, 0, 0);
-}
-
// Adjust the texture size *width/*height to fit the requirements of the D3D
// device. The texture size is only increased.
-// xxx make clear what happens when exceeding max_texture_width/height,
-// see create_d3d_surfaces(), not sure why that does what it does
+// xxx make clear what happens when exceeding max_texture_width/height
static void d3d_fix_texture_size(int *width, int *height)
{
int tex_width = *width;
int tex_height = *height;
+ // avoid nasty special cases with 0-sized textures and texture sizes
+ tex_width = FFMAX(tex_width, 1);
+ tex_height = FFMAX(tex_height, 1);
+
if (priv->device_caps_power2_only) {
tex_width = 1;
tex_height = 1;
@@ -272,6 +249,102 @@ static void d3d_fix_texture_size(int *width, int *height)
*height = tex_height;
}
+static void d3dtex_release(struct d3dtex *tex)
+{
+ if (tex->system)
+ IDirect3DTexture9_Release(tex->system);
+ tex->system = NULL;
+
+ if (tex->device)
+ IDirect3DTexture9_Release(tex->device);
+ tex->device = NULL;
+
+ tex->tex_w = tex->tex_h = 0;
+}
+
+static bool d3dtex_allocate(struct d3dtex *tex, D3DFORMAT fmt, int w, int h)
+{
+ d3dtex_release(tex);
+
+ tex->w = w;
+ tex->h = h;
+
+ int tw = w, th = h;
+ d3d_fix_texture_size(&tw, &th);
+
+ if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, tw, th, 1,
+ D3DUSAGE_DYNAMIC, fmt, D3DPOOL_SYSTEMMEM, &tex->system, NULL)))
+ {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Allocating %dx%d texture in system RAM failed.\n",
+ w, h);
+ goto error_exit;
+ }
+
+ if (!priv->device_texture_sys) {
+ if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, tw, th, 1,
+ D3DUSAGE_DYNAMIC, fmt, D3DPOOL_DEFAULT, &tex->device, NULL)))
+ {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Allocating %dx%d texture in video RAM failed.\n",
+ w, h);
+ goto error_exit;
+ }
+ }
+
+ tex->tex_w = tw;
+ tex->tex_h = th;
+
+ return true;
+
+error_exit:
+ d3dtex_release(tex);
+ return false;
+}
+
+static IDirect3DBaseTexture9 *d3dtex_get_render_texture(struct d3dtex *tex)
+{
+ return (IDirect3DBaseTexture9 *)
+ (priv->device_texture_sys ? tex->system : tex->device);
+}
+
+// Copy system texture contents to device texture.
+static bool d3dtex_update(struct d3dtex *tex)
+{
+ if (priv->device_texture_sys)
+ return true;
+ return !FAILED(IDirect3DDevice9_UpdateTexture(priv->d3d_device,
+ (IDirect3DBaseTexture9 *)tex->system,
+ (IDirect3DBaseTexture9 *)tex->device));
+}
+
+/** @brief Destroy D3D Offscreen and Backbuffer surfaces.
+ */
+static void destroy_d3d_surfaces(void)
+{
+ mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>destroy_d3d_surfaces called.\n");
+ /* Let's destroy the old (if any) 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;
+
+ d3dtex_release(&priv->texture_osd);
+
+ if (priv->d3d_backbuf)
+ IDirect3DSurface9_Release(priv->d3d_backbuf);
+ priv->d3d_backbuf = NULL;
+
+ d3dtex_release(&priv->texture_eosd);
+
+ if (priv->eosd)
+ eosd_packer_reinit(priv->eosd, 0, 0);
+}
+
/** @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
@@ -311,60 +384,26 @@ static int create_d3d_surfaces(void)
tex_height >>= 1;
}
- priv->osd_width = osd_width;
- priv->osd_height = osd_height;
-
- if (priv->osd_texture_width < tex_width
- || priv->osd_texture_height < tex_height)
+ if (priv->texture_osd.tex_w < tex_width
+ || priv->texture_osd.tex_h < tex_height)
{
- 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;
-
- priv->osd_texture_width = tex_width;
- priv->osd_texture_height = tex_height;
+ d3dtex_release(&priv->texture_osd);
mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>OSD texture size (%dx%d), requested (%dx%d).\n",
- vo_dwidth, vo_dheight, priv->osd_texture_width, priv->osd_texture_height);
- }
-
- if (!priv->d3d_texture_system &&
- FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device,
- priv->osd_texture_width,
- priv->osd_texture_height,
- 1,
- D3DUSAGE_DYNAMIC,
- D3DFMT_A8L8,
- D3DPOOL_SYSTEMMEM,
- &priv->d3d_texture_system,
- NULL))) {
- mp_msg(MSGT_VO,MSGL_ERR,
- "<vo_direct3d>Allocating OSD texture in system RAM failed.\n");
- return 0;
- }
+ vo_dwidth, vo_dheight, tex_width, tex_height);
- if (!priv->device_texture_sys) {
- /* only create if we need a shadow version on the external device */
- if (!priv->d3d_texture_osd &&
- FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device,
- priv->osd_texture_width,
- priv->osd_texture_height,
- 1,
- D3DUSAGE_DYNAMIC,
- D3DFMT_A8L8,
- D3DPOOL_DEFAULT,
- &priv->d3d_texture_osd,
- NULL))) {
- mp_msg(MSGT_VO,MSGL_ERR,
- "<vo_direct3d>Allocating OSD texture in video RAM failed.\n");
+ if (!d3dtex_allocate(&priv->texture_osd, D3DFMT_A8L8, tex_width,
+ tex_height))
+ {
+ mp_msg(MSGT_VO, MSGL_ERR,
+ "<vo_direct3d>Allocating OSD texture failed.\n");
return 0;
}
}
+ priv->texture_osd.w = osd_width;
+ priv->texture_osd.h = osd_height;
+
/* setup default renderstate */
IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND, D3DBLEND_ONE);
IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
@@ -374,7 +413,7 @@ static int create_d3d_surfaces(void)
IDirect3DDevice9_SetSamplerState(priv->d3d_device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
IDirect3DDevice9_SetSamplerState(priv->d3d_device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- if (priv->eosd && !priv->d3d_texture_eosd)
+ if (priv->eosd && !priv->texture_eosd.system)
eosd_packer_reinit(priv->eosd, priv->max_texture_width,
priv->max_texture_height);
@@ -1107,7 +1146,7 @@ static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
D3DLOCKED_RECT locked_rect; /**< Offscreen surface we lock in order
to copy MPlayer's frame inside it.*/
- if (FAILED(IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0,
+ if (FAILED(IDirect3DTexture9_LockRect(priv->texture_osd.system, 0,
&locked_rect, NULL, 0))) {
mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>OSD texture lock failed.\n");
return;
@@ -1117,7 +1156,7 @@ static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
(unsigned char *)locked_rect.pBits + locked_rect.Pitch*y0 + 2*x0, locked_rect.Pitch);
/* this unlock is used for both slice_draw path and D3DRenderFrame path */
- if (FAILED(IDirect3DTexture9_UnlockRect(priv->d3d_texture_system, 0))) {
+ if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_osd.system, 0))) {
mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>OSD texture unlock failed.\n");
return;
}
@@ -1138,17 +1177,16 @@ static void draw_osd(void)
to copy MPlayer's frame inside it.*/
/* clear the OSD */
- if (FAILED(IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0,
+ if (FAILED(IDirect3DTexture9_LockRect(priv->texture_osd.system, 0,
&locked_rect, NULL, 0))) {
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture lock failed.\n");
return;
}
/* clear the whole texture to avoid issues due to interpolation */
- memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->osd_texture_height);
+ memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->texture_osd.tex_h);
- /* this unlock is used for both slice_draw path and D3DRenderFrame path */
- if (FAILED(IDirect3DTexture9_UnlockRect(priv->d3d_texture_system, 0))) {
+ if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_osd.system, 0))) {
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture unlock failed.\n");
return;
}
@@ -1157,19 +1195,12 @@ static void draw_osd(void)
/* required for if subs are in the boarder region */
priv->is_clear_needed = 1;
- vo_draw_text_ext(priv->osd_width, priv->osd_height, priv->border_x, priv->border_y,
- priv->border_x, priv->border_y, priv->src_width, priv->src_height, draw_alpha);
+ vo_draw_text_ext(priv->texture_osd.w, priv->texture_osd.h,
+ priv->border_x, priv->border_y,
+ priv->border_x, priv->border_y,
+ priv->src_width, priv->src_height, draw_alpha);
- if (!priv->device_texture_sys)
- {
- /* only DMA to the shadow if its required */
- if (FAILED(IDirect3DDevice9_UpdateTexture(priv->d3d_device,
- (IDirect3DBaseTexture9 *)priv->d3d_texture_system,
- (IDirect3DBaseTexture9 *)priv->d3d_texture_osd))) {
- mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture transfer failed.\n");
- return;
- }
- }
+ d3dtex_update(&priv->texture_osd);
}
/* update OSD */
@@ -1185,9 +1216,9 @@ static void draw_osd(void)
/* calculate the texture coordinates */
osd_quad_vb[1].tu =
- osd_quad_vb[3].tu = (float)priv->osd_width / priv->osd_texture_width;
+ osd_quad_vb[3].tu = (float)priv->texture_osd.w / priv->texture_osd.tex_w;
osd_quad_vb[2].tv =
- osd_quad_vb[3].tv = (float)priv->osd_height / priv->osd_texture_height;
+ osd_quad_vb[3].tv = (float)priv->texture_osd.h / priv->texture_osd.tex_h;
if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) {
mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed.\n");
@@ -1200,8 +1231,7 @@ static void draw_osd(void)
/* need to use a texture here (done here as we may be able to texture from system memory) */
IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
- (IDirect3DBaseTexture9 *)(priv->device_texture_sys
- ? priv->d3d_texture_system : priv->d3d_texture_osd));
+ d3dtex_get_render_texture(&priv->texture_osd));
IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX);
IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLESTRIP, 2, osd_quad_vb, sizeof(vertex_osd));
@@ -1224,39 +1254,21 @@ static void d3d_realloc_eosd_texture(void)
d3d_fix_texture_size(&new_w, &new_h);
- if (new_w == priv->eosd_texture_width && new_h == priv->eosd_texture_height)
+ if (new_w == priv->texture_eosd.tex_w && new_h == priv->texture_eosd.tex_h)
return;
+ mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate EOSD surface.\n");
+
// fortunately, we don't need to keep the old image data
// we can always free it
- if (priv->d3d_texture_eosd)
- IDirect3DTexture9_Release(priv->d3d_texture_eosd);
- priv->d3d_texture_eosd = NULL;
-
- priv->eosd_texture_width = new_w;
- priv->eosd_texture_height = new_h;
-
- mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate EOSD surface.\n");
+ d3dtex_release(&priv->texture_eosd);
- if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device,
- priv->eosd_texture_width,
- priv->eosd_texture_height,
- 1,
- D3DUSAGE_DYNAMIC,
-#if USE_A8
- D3DFMT_A8,
-#else
- D3DFMT_A8L8,
+ D3DFORMAT fmt = D3DFMT_A8;
+#if !USE_A8
+ fmt = D3DFMT_A8L8;
#endif
- D3DPOOL_DEFAULT,
- &priv->d3d_texture_eosd,
- NULL))) {
- mp_msg(MSGT_VO,MSGL_ERR,
- "<vo_direct3d>Allocating EOSD texture failed.\n");
- priv->eosd_texture_width = 0;
- priv->eosd_texture_height = 0;
- return;
- }
+
+ d3dtex_allocate(&priv->texture_eosd, fmt, new_w, new_h);
}
static D3DCOLOR ass_to_d3d_color(uint32_t color)
@@ -1277,7 +1289,7 @@ static void generate_eosd(mp_eosd_images_t *imgs)
return;
// even if the texture size is unchanged, the texture might have been free'd
d3d_realloc_eosd_texture();
- if (!priv->d3d_texture_eosd)
+ if (!priv->texture_eosd.system)
return; // failed to allocate
// reupload all EOSD images
@@ -1295,17 +1307,17 @@ static void generate_eosd(mp_eosd_images_t *imgs)
D3DLOCKED_RECT locked_rect;
- if (FAILED(IDirect3DTexture9_LockRect(priv->d3d_texture_eosd, 0,
+ if (FAILED(IDirect3DTexture9_LockRect(priv->texture_eosd.system, 0,
&locked_rect, &dirty_rc, 0)))
{
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>EOSD texture lock failed.\n");
return;
}
- //memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->eosd_texture_height);
+ //memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->texture_eosd.tex_h);
- float eosd_w = priv->eosd_texture_width;
- float eosd_h = priv->eosd_texture_height;
+ float eosd_w = priv->texture_eosd.tex_w;
+ float eosd_h = priv->texture_eosd.tex_h;
for (int i = 0; i < priv->eosd->targets_count; i++) {
struct eosd_target *target = &priv->eosd->targets[i];
@@ -1351,10 +1363,12 @@ static void generate_eosd(mp_eosd_images_t *imgs)
v[5] = v[1];
}
- if (FAILED(IDirect3DTexture9_UnlockRect(priv->d3d_texture_eosd, 0))) {
+ if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_eosd.system, 0))) {
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>EOSD texture unlock failed.\n");
return;
}
+
+ d3dtex_update(&priv->texture_eosd);
}
// unfortunately we can't use the D3DX library
@@ -1404,7 +1418,7 @@ static void draw_eosd(void)
IDirect3DDevice9_SetTransform(priv->d3d_device, D3DTS_VIEW, &m);
IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
- (IDirect3DBaseTexture9*)priv->d3d_texture_eosd);
+ d3dtex_get_render_texture(&priv->texture_eosd));
IDirect3DDevice9_SetRenderState(priv->d3d_device,
D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);