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.c520
1 files changed, 188 insertions, 332 deletions
diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c
index 3270ec9ef1..294a101ffe 100644
--- a/libvo/vo_direct3d.c
+++ b/libvo/vo_direct3d.c
@@ -41,7 +41,7 @@
#include "w32_common.h"
#include "libavutil/common.h"
#include "sub/sub.h"
-#include "eosd_packer.h"
+#include "bitmap_packer.h"
// shaders generated by fxc.exe from d3d_shader_yuv.hlsl
#include "d3d_shader_yuv.h"
@@ -59,21 +59,13 @@
#define DEVTYPE D3DDEVTYPE_HAL
//#define DEVTYPE D3DDEVTYPE_REF
-
-#define D3DFVF_OSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
-
-typedef struct {
- float x, y, z; /* Position of vertex in 3D space */
- float tu, tv; /* Texture coordinates */
-} vertex_osd;
-
-#define D3DFVF_EOSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE)
+#define D3DFVF_OSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE)
typedef struct {
float x, y, z;
D3DCOLOR color;
float tu, tv;
-} vertex_eosd;
+} vertex_osd;
#define D3DFVF_VIDEO_VERTEX (D3DFVF_XYZ | D3DFVF_TEX3)
@@ -116,6 +108,15 @@ struct texplane {
uint8_t clearval;
};
+struct osdpart {
+ enum sub_bitmap_format format;
+ int bitmap_id, bitmap_pos_id;
+ struct d3dtex texture;
+ int num_vertices;
+ vertex_osd *vertices;
+ struct bitmap_packer *packer;
+};
+
/* Global variables "priv" structure. I try to keep their count low.
*/
typedef struct d3d_priv {
@@ -124,7 +125,7 @@ typedef struct d3d_priv {
int opt_disable_stretchrect;
int opt_disable_shaders;
int opt_only_8bit;
- int opt_disable_eosd;
+ int opt_disable_osd;
int opt_disable_texture_align;
// debugging
int opt_force_power_of_2;
@@ -144,8 +145,7 @@ typedef struct d3d_priv {
fullscreen */
int src_width; /**< Source (movie) width */
int src_height; /**< Source (movie) heigth */
- int border_x; /**< horizontal border value for OSD */
- int border_y; /**< vertical border value for OSD */
+ struct mp_osd_res osd_res;
int image_format; /**< mplayer image format */
bool use_textures; /**< use 3D texture rendering, instead of
StretchRect */
@@ -173,14 +173,10 @@ typedef struct d3d_priv {
IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer
renders inside it. Uses colorspace
priv->movie_src_fmt */
- struct d3dtex texture_osd; /**< RGBA */
IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to
display next frame) */
- struct d3dtex texture_eosd; /**< 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,
- 0 = OSD texture is clear */
int device_caps_power2_only; /**< 1 = texture sizes have to be power 2
0 = texture sizes can be anything */
int device_caps_square_only; /**< 1 = textures have to be square
@@ -195,8 +191,7 @@ typedef struct d3d_priv {
struct mp_csp_details colorspace;
struct mp_csp_equalizer video_eq;
- struct eosd_packer *eosd; /**< EOSD packer (image positions etc.) */
- vertex_eosd *eosd_vb; /**< temporary memory for D3D when rendering EOSD */
+ struct osdpart *osd[MAX_OSD_PARTS];
} d3d_priv;
struct fmt_entry {
@@ -230,9 +225,16 @@ static const struct fmt_entry fmt_table[] = {
{0},
};
+static const D3DFORMAT osd_fmt_table[SUBBITMAP_COUNT] = {
+ [SUBBITMAP_LIBASS] = D3DFMT_A8,
+ [SUBBITMAP_RGBA] = D3DFMT_A8R8G8B8,
+};
+static const bool osd_fmt_supported[SUBBITMAP_COUNT] = {
+ [SUBBITMAP_LIBASS] = true,
+ [SUBBITMAP_RGBA] = true,
+};
+
-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 bool resize_d3d(d3d_priv *priv);
@@ -240,7 +242,6 @@ 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);
static void uninit(struct vo *vo);
-static void draw_osd(struct vo *vo, struct osd_state *osd);
static void flip_page(struct vo *vo);
static mp_image_t *get_screenshot(d3d_priv *priv);
static mp_image_t *get_window_screenshot(d3d_priv *priv);
@@ -292,22 +293,18 @@ static bool d3d_begin_scene(d3d_priv *priv)
*/
static void calc_fs_rect(d3d_priv *priv)
{
- struct vo_rect src_rect;
- struct vo_rect dst_rect;
- struct vo_rect borders;
- calc_src_dst_rects(priv->vo, priv->src_width, priv->src_height, &src_rect,
- &dst_rect, &borders, NULL);
-
- priv->fs_movie_rect.left = dst_rect.left;
- priv->fs_movie_rect.right = dst_rect.right;
- priv->fs_movie_rect.top = dst_rect.top;
- priv->fs_movie_rect.bottom = dst_rect.bottom;
- priv->fs_panscan_rect.left = src_rect.left;
- priv->fs_panscan_rect.right = src_rect.right;
- priv->fs_panscan_rect.top = src_rect.top;
- priv->fs_panscan_rect.bottom = src_rect.bottom;
- priv->border_x = borders.left;
- priv->border_y = borders.top;
+ struct mp_rect src_rect;
+ struct mp_rect dst_rect;
+ vo_get_src_dst_rects(priv->vo, &src_rect, &dst_rect, &priv->osd_res);
+
+ priv->fs_movie_rect.left = dst_rect.x0;
+ priv->fs_movie_rect.right = dst_rect.x1;
+ priv->fs_movie_rect.top = dst_rect.y0;
+ priv->fs_movie_rect.bottom = dst_rect.y1;
+ priv->fs_panscan_rect.left = src_rect.x0;
+ priv->fs_panscan_rect.right = src_rect.x1;
+ priv->fs_panscan_rect.top = src_rect.y0;
+ priv->fs_panscan_rect.bottom = src_rect.y1;
mp_msg(MSGT_VO, MSGL_V,
"<vo_direct3d>Video rectangle: t: %ld, l: %ld, r: %ld, b:%ld\n",
@@ -478,17 +475,16 @@ static void destroy_d3d_surfaces(d3d_priv *priv)
d3d_destroy_video_objects(priv);
- d3dtex_release(priv, &priv->texture_osd);
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osdpart *osd = priv->osd[n];
+ d3dtex_release(priv, &osd->texture);
+ osd->bitmap_id = osd->bitmap_pos_id = -1;
+ }
if (priv->d3d_backbuf)
IDirect3DSurface9_Release(priv->d3d_backbuf);
priv->d3d_backbuf = NULL;
- d3dtex_release(priv, &priv->texture_eosd);
-
- if (priv->eosd)
- eosd_packer_reinit(priv->eosd, 0, 0);
-
priv->d3d_in_scene = false;
}
@@ -596,8 +592,6 @@ static void d3d_clear_video_textures(d3d_priv *priv)
// 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;
mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>create_d3d_surfaces called.\n");
if (!priv->d3d_backbuf &&
@@ -611,40 +605,6 @@ static bool create_d3d_surfaces(d3d_priv *priv)
if (!d3d_configure_video_objects(priv))
return 0;
- /* create OSD */
-
- d3d_fix_texture_size(priv, &tex_width, &tex_height);
-
- while (tex_width > priv->max_texture_width
- || tex_height > priv->max_texture_height)
- {
- osd_width >>= 1;
- osd_height >>= 1;
- tex_width >>= 1;
- tex_height >>= 1;
- }
-
- if (priv->texture_osd.tex_w < tex_width
- || priv->texture_osd.tex_h < tex_height)
- {
- d3dtex_release(priv, &priv->texture_osd);
-
- mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>OSD texture size (%dx%d),"
- " requested (%dx%d).\n", osd_width, osd_height, tex_width,
- tex_height);
-
- if (!d3dtex_allocate(priv, &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_SRCALPHA);
@@ -669,10 +629,6 @@ static bool create_d3d_surfaces(d3d_priv *priv)
D3DTADDRESS_CLAMP);
}
- if (priv->eosd && !priv->texture_eosd.system)
- eosd_packer_reinit(priv->eosd, priv->max_texture_width,
- priv->max_texture_height);
-
return 1;
}
@@ -890,8 +846,6 @@ static bool resize_d3d(d3d_priv *priv)
calc_fs_rect(priv);
- vo_osd_resized();
-
priv->vo->want_redraw = true;
return 1;
@@ -1266,11 +1220,11 @@ static int query_format(d3d_priv *priv, uint32_t movie_fmt)
if (!init_rendering_mode(priv, movie_fmt, false))
return 0;
- int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
- | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
- if (priv->eosd)
- eosd_caps |= VFCAP_EOSD | VFCAP_EOSD_UNSCALED;
- return eosd_caps;
+ int osd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
+ | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
+ if (!priv->opt_disable_osd)
+ osd_caps |= VFCAP_OSD;
+ return osd_caps;
}
/****************************************************************************
@@ -1338,7 +1292,7 @@ static void update_colorspace(d3d_priv *priv)
}
const char *options_help_text = "-vo direct3d command line help:\n"
-"Example: -vo direct3d:disable-eosd:disable-textures\n"
+"Example: -vo direct3d:disable-osd:disable-textures\n"
"Options:\n"
" prefer-stretchrect\n"
" Use IDirect3DDevice9::StretchRect over other methods if possible.\n"
@@ -1353,8 +1307,8 @@ const char *options_help_text = "-vo direct3d command line help:\n"
" only-8bit\n"
" Never render YUV video with more than 8 bits per component.\n"
" (Using this flag will force software conversion to 8 bit.)\n"
-" disable-eosd\n"
-" Disable EOSD rendering for subtitles.\n"
+" disable-osd\n"
+" Disable OSD rendering.\n"
" (Using this flag might force the insertion of the 'ass' video filter,\n"
" which will render the subtitles in software.)\n"
" disable-texture-align\n"
@@ -1410,6 +1364,14 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
.video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX },
};
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osdpart *osd = talloc_ptrtype(priv, osd);
+ *osd = (struct osdpart) {
+ .packer = talloc_zero(osd, struct bitmap_packer),
+ };
+ priv->osd[n] = osd;
+ }
+
if (!allow_shaders) {
priv->opt_disable_shaders = priv->opt_disable_textures = true;
}
@@ -1420,7 +1382,7 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
{"disable-stretchrect", OPT_ARG_BOOL, &priv->opt_disable_stretchrect},
{"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},
+ {"disable-osd", OPT_ARG_BOOL, &priv->opt_disable_osd},
{"force-power-of-2", OPT_ARG_BOOL, &priv->opt_force_power_of_2},
{"disable-texture-align", OPT_ARG_BOOL, &priv->opt_disable_texture_align},
{"texture-memory", OPT_ARG_INT, &priv->opt_texture_memory},
@@ -1434,9 +1396,6 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
return -1;
}
- if (!priv->opt_disable_eosd)
- priv->eosd = eosd_packer_create(priv);
-
priv->d3d9_dll = LoadLibraryA("d3d9.dll");
if (!priv->d3d9_dll) {
mp_msg(MSGT_VO, MSGL_ERR,
@@ -1544,22 +1503,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
return VO_TRUE;
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
- case VOCTRL_DRAW_EOSD:
- if (!data)
- return VO_FALSE;
- assert(priv->eosd);
- generate_eosd(priv, data);
- draw_eosd(priv);
- return VO_TRUE;
- case VOCTRL_GET_EOSD_RES: {
- assert(priv->eosd);
- struct mp_eosd_res *r = data;
- r->w = vo->dwidth;
- r->h = vo->dheight;
- r->ml = r->mr = priv->border_x;
- r->mt = r->mb = priv->border_y;
- return VO_TRUE;
- }
case VOCTRL_SCREENSHOT: {
struct voctrl_screenshot_args *args = data;
if (args->full_window)
@@ -1853,8 +1796,10 @@ static mp_image_t *get_screenshot(d3d_priv *priv)
return NULL;
}
- image->w = priv->vo->aspdat.prew;
- image->h = priv->vo->aspdat.preh;
+ image->display_w = priv->vo->aspdat.prew;
+ image->display_h = priv->vo->aspdat.preh;
+
+ mp_image_set_colorspace_details(image, &priv->colorspace);
return image;
}
@@ -1929,142 +1874,86 @@ error_exit:
return NULL;
}
-/** @brief Maps MPlayer alpha to D3D
- * 0x0 -> transparent and discarded by alpha test
- * 0x1 -> 0xFF to become opaque
- * other alpha values are inverted +1 (2 = -2)
- * These values are then inverted again with
- the texture filter D3DBLEND_INVSRCALPHA
- */
-static void vo_draw_alpha_l8a8(int w, int h, unsigned char* src,
- unsigned char *srca, int srcstride,
- unsigned char* dstbase, int dststride)
-{
- int y;
- for (y = 0; y < h; y++) {
- unsigned short *dst = (unsigned short*)dstbase;
- int x;
- for (x = 0; x < w; x++) {
- dst[x] = (-srca[x] << 8) | src[x];
- }
- src += srcstride;
- srca += srcstride;
- dstbase += dststride;
- }
-}
-
-struct draw_osd_closure {
- d3d_priv *priv;
- D3DLOCKED_RECT locked_rect;
-};
-
-/** @brief Callback function to render the OSD to the texture
- */
-static void draw_alpha(void *pctx, int x0, int y0, int w, int h,
- unsigned char *src, unsigned char *srca, int stride)
-{
- struct draw_osd_closure *ctx = pctx;
- D3DLOCKED_RECT locked_rect = ctx->locked_rect;
-
- vo_draw_alpha_l8a8(w, h, src, srca, stride,
- (unsigned char *)locked_rect.pBits + locked_rect.Pitch * y0 + 2 * x0,
- locked_rect.Pitch);
-
- ctx->priv->is_osd_populated = 1;
-}
-
-/** @brief libvo Callback: Draw OSD/Subtitles,
- */
-static void draw_osd(struct vo *vo, struct osd_state *osd)
+static bool upload_osd(d3d_priv *priv, struct osdpart *osd,
+ struct sub_bitmaps *imgs)
{
- d3d_priv *priv = vo->priv;
-
- if (!priv->d3d_device)
- return;
+ D3DFORMAT fmt = osd_fmt_table[imgs->format];
- if (vo_osd_has_changed(osd)) {
- struct draw_osd_closure ctx = { priv };
+ osd->packer->w_max = priv->max_texture_width;
+ osd->packer->h_max = priv->max_texture_height;
- /* clear the OSD */
- if (FAILED(IDirect3DTexture9_LockRect(priv->texture_osd.system, 0,
- &ctx.locked_rect, NULL, 0))) {
- mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture lock failed.\n");
- return;
- }
+ osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling
+ int r = packer_pack_from_subbitmaps(osd->packer, imgs);
+ if (r < 0) {
+ mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>OSD bitmaps do not fit on "
+ "a surface with the maximum supported size %dx%d.\n",
+ osd->packer->w_max, osd->packer->h_max);
+ return false;
+ }
- /* clear the whole texture to avoid issues due to interpolation */
- memset(ctx.locked_rect.pBits, 0,
- ctx.locked_rect.Pitch * priv->texture_osd.tex_h);
+ if (osd->packer->w > osd->texture.tex_w
+ || osd->packer->h > osd->texture.tex_h
+ || osd->format != imgs->format)
+ {
+ osd->format = imgs->format;
- priv->is_osd_populated = 0;
- /* required for if subs are in the boarder region */
- priv->is_clear_needed = 1;
+ int new_w = osd->packer->w;
+ int new_h = osd->packer->h;
+ d3d_fix_texture_size(priv, &new_w, &new_h);
- osd_draw_text_ext(osd, 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, &ctx);
+ mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate OSD surface.\n");
- if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_osd.system, 0))) {
- mp_msg(MSGT_VO,MSGL_ERR,
- "<vo_direct3d>OSD texture unlock failed.\n");
- return;
- }
+ d3dtex_release(priv, &osd->texture);
+ d3dtex_allocate(priv, &osd->texture, fmt, new_w, new_h);
- d3dtex_update(priv, &priv->texture_osd);
+ if (!osd->texture.system)
+ return false; // failed to allocate
}
- if (priv->is_osd_populated) {
- float tw = (float)priv->texture_osd.w / priv->texture_osd.tex_w;
- float th = (float)priv->texture_osd.h / priv->texture_osd.tex_h;
-
- vertex_osd osd_quad_vb[] = {
- { 0, 0, 0.0f, 0, 0 },
- { vo->dwidth, 0, 0.0f, tw, 0 },
- { 0, vo->dheight, 0.0f, 0, th },
- { vo->dwidth, vo->dheight, 0.0f, tw, th }
- };
-
- d3d_begin_scene(priv);
-
- IDirect3DDevice9_SetRenderState(priv->d3d_device,
- D3DRS_ALPHABLENDENABLE, TRUE);
- IDirect3DDevice9_SetRenderState(priv->d3d_device,
- D3DRS_ALPHATESTENABLE, TRUE);
+ struct pos bb[2];
+ packer_get_bb(osd->packer, bb);
+ RECT dirty_rc = { bb[0].x, bb[0].y, bb[1].x, bb[1].y };
- IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
- d3dtex_get_render_texture(priv, &priv->texture_osd));
+ D3DLOCKED_RECT locked_rect;
- IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX);
- IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLESTRIP,
- 2, osd_quad_vb, sizeof(vertex_osd));
+ if (FAILED(IDirect3DTexture9_LockRect(osd->texture.system, 0, &locked_rect,
+ &dirty_rc, 0)))
+ {
+ mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture lock failed.\n");
+ return false;
+ }
- IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL);
+ int ps = fmt == D3DFMT_A8 ? 1 : 4;
+ packer_copy_subbitmaps(osd->packer, imgs, locked_rect.pBits, ps,
+ locked_rect.Pitch);
- IDirect3DDevice9_SetRenderState(priv->d3d_device,
- D3DRS_ALPHATESTENABLE, FALSE);
- IDirect3DDevice9_SetRenderState(priv->d3d_device,
- D3DRS_ALPHABLENDENABLE, FALSE);
+ if (FAILED(IDirect3DTexture9_UnlockRect(osd->texture.system, 0))) {
+ mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture unlock failed.\n");
+ return false;
}
+
+ return d3dtex_update(priv, &osd->texture);
}
-static void d3d_realloc_eosd_texture(d3d_priv *priv)
+static struct osdpart *generate_osd(d3d_priv *priv, struct sub_bitmaps *imgs)
{
- int new_w = priv->eosd->surface.w;
- int new_h = priv->eosd->surface.h;
-
- d3d_fix_texture_size(priv, &new_w, &new_h);
+ if (imgs->num_parts == 0 || !osd_fmt_table[imgs->format])
+ return NULL;
- if (new_w == priv->texture_eosd.tex_w && new_h == priv->texture_eosd.tex_h)
- return;
+ struct osdpart *osd = priv->osd[imgs->render_index];
- mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate EOSD surface.\n");
+ if (imgs->bitmap_pos_id != osd->bitmap_pos_id) {
+ if (imgs->bitmap_id != osd->bitmap_id) {
+ if (!upload_osd(priv, osd, imgs))
+ osd->packer->count = 0;
+ }
- // fortunately, we don't need to keep the old image data
- // we can always free it
- d3dtex_release(priv, &priv->texture_eosd);
+ osd->bitmap_id = imgs->bitmap_id;
+ osd->bitmap_pos_id = imgs->bitmap_pos_id;
+ osd->num_vertices = 0;
+ }
- d3dtex_allocate(priv, &priv->texture_eosd, D3DFMT_A8, new_w, new_h);
+ return osd->packer->count ? osd : NULL;
}
static D3DCOLOR ass_to_d3d_color(uint32_t color)
@@ -2076,102 +1965,51 @@ static D3DCOLOR ass_to_d3d_color(uint32_t color)
return D3DCOLOR_ARGB(a, r, g, b);
}
-static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *imgs)
+static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs)
{
- if (!priv->d3d_device)
- return;
+ d3d_priv *priv = ctx;
- bool need_reposition, need_upload, need_resize;
- eosd_packer_generate(priv->eosd, imgs, &need_reposition, &need_upload,
- &need_resize);
-
- if (!need_reposition)
+ struct osdpart *osd = generate_osd(priv, imgs);
+ if (!osd)
return;
- // even if the texture size is unchanged, the texture might have been free'd
- d3d_realloc_eosd_texture(priv);
- if (!priv->texture_eosd.system)
- return; // failed to allocate
-
- // reupload all EOSD images
- // we need 2 primitives per quad which makes 6 vertices (we could reduce the
- // number of vertices by using an indexed vertex array, but it's probably
- // not worth doing)
- priv->eosd_vb = talloc_realloc_size(priv->eosd, priv->eosd_vb,
- priv->eosd->targets_count
- * sizeof(vertex_eosd) * 6);
-
- if (need_upload) {
- struct eosd_rect rc;
- eosd_packer_calculate_source_bb(priv->eosd, &rc);
- RECT dirty_rc = { rc.x0, rc.y0, rc.x1, rc.y1 };
-
- D3DLOCKED_RECT locked_rect;
-
- 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->texture_eosd.tex_h);
-
- for (int i = 0; i < priv->eosd->targets_count; i++) {
- struct eosd_target *target = &priv->eosd->targets[i];
- ASS_Image *img = target->ass_img;
- char *src = img->bitmap;
- char *dst = (char*)locked_rect.pBits + target->source.x0
- + locked_rect.Pitch * target->source.y0;
- for (int y = 0; y < img->h; y++) {
- memcpy(dst, src, img->w);
- src += img->stride;
- dst += locked_rect.Pitch;
- }
+ if (osd->packer->count && !osd->num_vertices) {
+ // We need 2 primitives per quad which makes 6 vertices (we could reduce
+ // the number of vertices by using an indexed vertex array, but it's
+ // probably not worth doing)
+ osd->num_vertices = osd->packer->count * 6;
+ osd->vertices = talloc_realloc(osd, osd->vertices, vertex_osd,
+ osd->num_vertices);
+
+ float tex_w = osd->texture.tex_w;
+ float tex_h = osd->texture.tex_h;
+
+ for (int n = 0; n < osd->packer->count; n++) {
+ struct sub_bitmap *b = &imgs->parts[n];
+ struct pos p = osd->packer->result[n];
+
+ D3DCOLOR color = imgs->format == SUBBITMAP_LIBASS
+ ? ass_to_d3d_color(b->libass.color)
+ : D3DCOLOR_ARGB(255, 255, 255, 255);
+
+ float x0 = b->x;
+ float y0 = b->y;
+ float x1 = b->x + b->dw;
+ float y1 = b->y + b->dh;
+ float tx0 = p.x / tex_w;
+ float ty0 = p.y / tex_h;
+ float tx1 = (p.x + b->w) / tex_w;
+ float ty1 = (p.y + b->h) / tex_h;
+
+ vertex_osd *v = &osd->vertices[n * 6];
+ v[0] = (vertex_osd) { x0, y0, 0, color, tx0, ty0 };
+ v[1] = (vertex_osd) { x1, y0, 0, color, tx1, ty0 };
+ v[2] = (vertex_osd) { x0, y1, 0, color, tx0, ty1 };
+ v[3] = (vertex_osd) { x1, y1, 0, color, tx1, ty1 };
+ v[4] = v[2];
+ v[5] = v[1];
}
-
- 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, &priv->texture_eosd);
- }
-
- 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];
-
- D3DCOLOR color = ass_to_d3d_color(target->ass_img->color);
-
- float x0 = target->dest.x0;
- float y0 = target->dest.y0;
- float x1 = target->dest.x1;
- float y1 = target->dest.y1;
- float tx0 = target->source.x0 / eosd_w;
- float ty0 = target->source.y0 / eosd_h;
- float tx1 = target->source.x1 / eosd_w;
- float ty1 = target->source.y1 / eosd_h;
-
- vertex_eosd *v = &priv->eosd_vb[i*6];
- v[0] = (vertex_eosd) { x0, y0, 0, color, tx0, ty0 };
- v[1] = (vertex_eosd) { x1, y0, 0, color, tx1, ty0 };
- v[2] = (vertex_eosd) { x0, y1, 0, color, tx0, ty1 };
- v[3] = (vertex_eosd) { x1, y1, 0, color, tx1, ty1 };
- v[4] = v[2];
- v[5] = v[1];
}
-}
-
-static void draw_eosd(d3d_priv *priv)
-{
- if (!priv->d3d_device)
- return;
-
- if (!priv->eosd->targets_count)
- return;
d3d_begin_scene(priv);
@@ -2179,26 +2017,33 @@ static void draw_eosd(d3d_priv *priv)
D3DRS_ALPHABLENDENABLE, TRUE);
IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
- d3dtex_get_render_texture(priv, &priv->texture_eosd));
+ d3dtex_get_render_texture(priv, &osd->texture));
- // do not use the color value from the A8 texture, because that is black
- IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR,
- 0xFFFFFFFF);
- IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
- D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ if (imgs->format == SUBBITMAP_LIBASS) {
+ // do not use the color value from the A8 texture, because that is black
+ IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR,
+ 0xFFFFFFFF);
+ IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
+ D3DTSS_COLORARG1, D3DTA_TFACTOR);
- IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0,
- D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+ IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0,
+ D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+ } else {
+ IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND,
+ D3DBLEND_ONE);
+ }
- IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX);
+ IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX);
IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST,
- priv->eosd->targets_count * 2,
- priv->eosd_vb, sizeof(vertex_eosd));
+ osd->num_vertices / 3,
+ osd->vertices, sizeof(vertex_osd));
IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
D3DTSS_COLORARG1, D3DTA_TEXTURE);
IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0,
D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ IDirect3DDevice9_SetRenderState(priv->d3d_device,
+ D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL);
@@ -2206,6 +2051,17 @@ static void draw_eosd(d3d_priv *priv)
D3DRS_ALPHABLENDENABLE, FALSE);
}
+
+static void draw_osd(struct vo *vo, struct osd_state *osd)
+{
+ d3d_priv *priv = vo->priv;
+ if (!priv->d3d_device)
+ return;
+
+ osd_draw(osd, priv->osd_res, osd->vo_pts, 0, osd_fmt_supported,
+ draw_osd_cb, priv);
+}
+
#define AUTHOR "Georgi Petrov (gogothebee) <gogothebee@gmail.com> and others"
const struct vo_driver video_out_direct3d = {