diff options
Diffstat (limited to 'libvo/vo_direct3d.c')
-rw-r--r-- | libvo/vo_direct3d.c | 520 |
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 = { |