mirror of https://github.com/mpv-player/mpv
vo_direct3d: use new OSD API
This commit is contained in:
parent
7463cff747
commit
ffd6219ecd
|
@ -41,7 +41,7 @@
|
||||||
#include "w32_common.h"
|
#include "w32_common.h"
|
||||||
#include "libavutil/common.h"
|
#include "libavutil/common.h"
|
||||||
#include "sub/sub.h"
|
#include "sub/sub.h"
|
||||||
#include "eosd_packer.h"
|
#include "bitmap_packer.h"
|
||||||
|
|
||||||
// shaders generated by fxc.exe from d3d_shader_yuv.hlsl
|
// shaders generated by fxc.exe from d3d_shader_yuv.hlsl
|
||||||
#include "d3d_shader_yuv.h"
|
#include "d3d_shader_yuv.h"
|
||||||
|
@ -59,14 +59,6 @@
|
||||||
#define DEVTYPE D3DDEVTYPE_HAL
|
#define DEVTYPE D3DDEVTYPE_HAL
|
||||||
//#define DEVTYPE D3DDEVTYPE_REF
|
//#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_EOSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -116,6 +108,15 @@ struct texplane {
|
||||||
uint8_t clearval;
|
uint8_t clearval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct osdpart {
|
||||||
|
enum sub_bitmap_format format;
|
||||||
|
int bitmap_id, bitmap_pos_id;
|
||||||
|
struct d3dtex texture;
|
||||||
|
int num_vertices;
|
||||||
|
vertex_eosd *vertices;
|
||||||
|
struct bitmap_packer *packer;
|
||||||
|
};
|
||||||
|
|
||||||
/* Global variables "priv" structure. I try to keep their count low.
|
/* Global variables "priv" structure. I try to keep their count low.
|
||||||
*/
|
*/
|
||||||
typedef struct d3d_priv {
|
typedef struct d3d_priv {
|
||||||
|
@ -175,14 +176,10 @@ typedef struct d3d_priv {
|
||||||
IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer
|
IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer
|
||||||
renders inside it. Uses colorspace
|
renders inside it. Uses colorspace
|
||||||
priv->movie_src_fmt */
|
priv->movie_src_fmt */
|
||||||
struct d3dtex texture_osd; /**< RGBA */
|
|
||||||
IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to
|
IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to
|
||||||
display next frame) */
|
display next frame) */
|
||||||
struct d3dtex texture_eosd; /**< A8 */
|
|
||||||
int cur_backbuf_width; /**< Current backbuffer width */
|
int cur_backbuf_width; /**< Current backbuffer width */
|
||||||
int cur_backbuf_height; /**< Current backbuffer height */
|
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
|
int device_caps_power2_only; /**< 1 = texture sizes have to be power 2
|
||||||
0 = texture sizes can be anything */
|
0 = texture sizes can be anything */
|
||||||
int device_caps_square_only; /**< 1 = textures have to be square
|
int device_caps_square_only; /**< 1 = textures have to be square
|
||||||
|
@ -197,8 +194,7 @@ typedef struct d3d_priv {
|
||||||
struct mp_csp_details colorspace;
|
struct mp_csp_details colorspace;
|
||||||
struct mp_csp_equalizer video_eq;
|
struct mp_csp_equalizer video_eq;
|
||||||
|
|
||||||
struct eosd_packer *eosd; /**< EOSD packer (image positions etc.) */
|
struct osdpart *osd[MAX_OSD_PARTS];
|
||||||
vertex_eosd *eosd_vb; /**< temporary memory for D3D when rendering EOSD */
|
|
||||||
} d3d_priv;
|
} d3d_priv;
|
||||||
|
|
||||||
struct fmt_entry {
|
struct fmt_entry {
|
||||||
|
@ -232,9 +228,12 @@ static const struct fmt_entry fmt_table[] = {
|
||||||
{0},
|
{0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const D3DFORMAT osd_fmt_table[SUBBITMAP_COUNT] = {
|
||||||
|
[SUBBITMAP_LIBASS] = D3DFMT_A8,
|
||||||
|
[SUBBITMAP_RGBA] = D3DFMT_A8R8G8B8,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
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 update_colorspace(d3d_priv *priv);
|
||||||
static void d3d_clear_video_textures(d3d_priv *priv);
|
static void d3d_clear_video_textures(d3d_priv *priv);
|
||||||
static bool resize_d3d(d3d_priv *priv);
|
static bool resize_d3d(d3d_priv *priv);
|
||||||
|
@ -242,7 +241,7 @@ 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,
|
static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h,
|
||||||
int x, int y);
|
int x, int y);
|
||||||
static void uninit(struct vo *vo);
|
static void uninit(struct vo *vo);
|
||||||
static void draw_osd(struct vo *vo, struct osd_state *osd);
|
static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs);
|
||||||
static void flip_page(struct vo *vo);
|
static void flip_page(struct vo *vo);
|
||||||
static mp_image_t *get_screenshot(d3d_priv *priv);
|
static mp_image_t *get_screenshot(d3d_priv *priv);
|
||||||
static mp_image_t *get_window_screenshot(d3d_priv *priv);
|
static mp_image_t *get_window_screenshot(d3d_priv *priv);
|
||||||
|
@ -480,17 +479,16 @@ static void destroy_d3d_surfaces(d3d_priv *priv)
|
||||||
|
|
||||||
d3d_destroy_video_objects(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)
|
if (priv->d3d_backbuf)
|
||||||
IDirect3DSurface9_Release(priv->d3d_backbuf);
|
IDirect3DSurface9_Release(priv->d3d_backbuf);
|
||||||
priv->d3d_backbuf = NULL;
|
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;
|
priv->d3d_in_scene = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,8 +596,6 @@ static void d3d_clear_video_textures(d3d_priv *priv)
|
||||||
// done.
|
// done.
|
||||||
static bool create_d3d_surfaces(d3d_priv *priv)
|
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");
|
mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>create_d3d_surfaces called.\n");
|
||||||
|
|
||||||
if (!priv->d3d_backbuf &&
|
if (!priv->d3d_backbuf &&
|
||||||
|
@ -613,40 +609,6 @@ static bool create_d3d_surfaces(d3d_priv *priv)
|
||||||
if (!d3d_configure_video_objects(priv))
|
if (!d3d_configure_video_objects(priv))
|
||||||
return 0;
|
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 */
|
/* setup default renderstate */
|
||||||
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
||||||
D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||||
|
@ -671,10 +633,6 @@ static bool create_d3d_surfaces(d3d_priv *priv)
|
||||||
D3DTADDRESS_CLAMP);
|
D3DTADDRESS_CLAMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->eosd && !priv->texture_eosd.system)
|
|
||||||
eosd_packer_reinit(priv->eosd, priv->max_texture_width,
|
|
||||||
priv->max_texture_height);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1270,8 +1228,8 @@ static int query_format(d3d_priv *priv, uint32_t movie_fmt)
|
||||||
|
|
||||||
int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
|
int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
|
||||||
| VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
|
| VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
|
||||||
if (priv->eosd)
|
if (!priv->opt_disable_eosd)
|
||||||
eosd_caps |= VFCAP_EOSD;
|
eosd_caps |= VFCAP_EOSD | VFCAP_EOSD_RGBA;
|
||||||
return eosd_caps;
|
return eosd_caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1412,6 +1370,14 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
|
||||||
.video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX },
|
.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) {
|
if (!allow_shaders) {
|
||||||
priv->opt_disable_shaders = priv->opt_disable_textures = true;
|
priv->opt_disable_shaders = priv->opt_disable_textures = true;
|
||||||
}
|
}
|
||||||
|
@ -1436,9 +1402,6 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!priv->opt_disable_eosd)
|
|
||||||
priv->eosd = eosd_packer_create(priv);
|
|
||||||
|
|
||||||
priv->d3d9_dll = LoadLibraryA("d3d9.dll");
|
priv->d3d9_dll = LoadLibraryA("d3d9.dll");
|
||||||
if (!priv->d3d9_dll) {
|
if (!priv->d3d9_dll) {
|
||||||
mp_msg(MSGT_VO, MSGL_ERR,
|
mp_msg(MSGT_VO, MSGL_ERR,
|
||||||
|
@ -1549,12 +1512,11 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
||||||
case VOCTRL_DRAW_EOSD:
|
case VOCTRL_DRAW_EOSD:
|
||||||
if (!data)
|
if (!data)
|
||||||
return VO_FALSE;
|
return VO_FALSE;
|
||||||
assert(priv->eosd);
|
draw_osd(priv, data);
|
||||||
generate_eosd(priv, data);
|
|
||||||
draw_eosd(priv);
|
|
||||||
return VO_TRUE;
|
return VO_TRUE;
|
||||||
|
case VOCTRL_QUERY_EOSD_FORMAT:
|
||||||
|
return osd_fmt_table[*(int *)data] ? VO_TRUE : VO_NOTIMPL;
|
||||||
case VOCTRL_GET_EOSD_RES: {
|
case VOCTRL_GET_EOSD_RES: {
|
||||||
assert(priv->eosd);
|
|
||||||
struct mp_eosd_res *r = data;
|
struct mp_eosd_res *r = data;
|
||||||
r->w = vo->dwidth;
|
r->w = vo->dwidth;
|
||||||
r->h = vo->dheight;
|
r->h = vo->dheight;
|
||||||
|
@ -1934,142 +1896,86 @@ error_exit:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Maps MPlayer alpha to D3D
|
static bool upload_osd(d3d_priv *priv, struct osdpart *osd,
|
||||||
* 0x0 -> transparent and discarded by alpha test
|
struct sub_bitmaps *imgs)
|
||||||
* 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;
|
D3DFORMAT fmt = osd_fmt_table[imgs->format];
|
||||||
for (y = 0; y < h; y++) {
|
|
||||||
unsigned short *dst = (unsigned short*)dstbase;
|
osd->packer->w_max = priv->max_texture_width;
|
||||||
int x;
|
osd->packer->h_max = priv->max_texture_height;
|
||||||
for (x = 0; x < w; x++) {
|
|
||||||
dst[x] = (-srca[x] << 8) | src[x];
|
osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling
|
||||||
}
|
int r = packer_pack_from_subbitmaps(osd->packer, imgs);
|
||||||
src += srcstride;
|
if (r < 0) {
|
||||||
srca += srcstride;
|
mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>EOSD bitmaps do not fit on "
|
||||||
dstbase += dststride;
|
"a surface with the maximum supported size %dx%d.\n",
|
||||||
}
|
osd->packer->w_max, osd->packer->h_max);
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (osd->packer->w > osd->texture.tex_w
|
||||||
|
|| osd->packer->h > osd->texture.tex_h
|
||||||
|
|| osd->format != imgs->format)
|
||||||
|
{
|
||||||
|
osd->format = imgs->format;
|
||||||
|
|
||||||
|
int new_w = osd->packer->w;
|
||||||
|
int new_h = osd->packer->h;
|
||||||
|
d3d_fix_texture_size(priv, &new_w, &new_h);
|
||||||
|
|
||||||
|
mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate OSD surface.\n");
|
||||||
|
|
||||||
|
d3dtex_release(priv, &osd->texture);
|
||||||
|
d3dtex_allocate(priv, &osd->texture, fmt, new_w, new_h);
|
||||||
|
|
||||||
|
if (!osd->texture.system)
|
||||||
|
return false; // failed to allocate
|
||||||
|
}
|
||||||
|
|
||||||
|
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 };
|
||||||
|
|
||||||
struct draw_osd_closure {
|
|
||||||
d3d_priv *priv;
|
|
||||||
D3DLOCKED_RECT locked_rect;
|
D3DLOCKED_RECT locked_rect;
|
||||||
};
|
|
||||||
|
|
||||||
/** @brief Callback function to render the OSD to the texture
|
if (FAILED(IDirect3DTexture9_LockRect(osd->texture.system, 0, &locked_rect,
|
||||||
*/
|
&dirty_rc, 0)))
|
||||||
static void draw_alpha(void *pctx, int x0, int y0, int w, int h,
|
{
|
||||||
unsigned char *src, unsigned char *srca, int stride)
|
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>EOSD texture lock failed.\n");
|
||||||
{
|
return false;
|
||||||
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)
|
|
||||||
{
|
|
||||||
d3d_priv *priv = vo->priv;
|
|
||||||
|
|
||||||
if (!priv->d3d_device)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (vo_osd_has_changed(osd)) {
|
|
||||||
struct draw_osd_closure ctx = { priv };
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
priv->is_osd_populated = 0;
|
|
||||||
/* required for if subs are in the boarder region */
|
|
||||||
priv->is_clear_needed = 1;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_osd.system, 0))) {
|
|
||||||
mp_msg(MSGT_VO,MSGL_ERR,
|
|
||||||
"<vo_direct3d>OSD texture unlock failed.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d3dtex_update(priv, &priv->texture_osd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->is_osd_populated) {
|
int ps = fmt == D3DFMT_A8 ? 1 : 4;
|
||||||
float tw = (float)priv->texture_osd.w / priv->texture_osd.tex_w;
|
packer_copy_subbitmaps(osd->packer, imgs, locked_rect.pBits, ps,
|
||||||
float th = (float)priv->texture_osd.h / priv->texture_osd.tex_h;
|
locked_rect.Pitch);
|
||||||
|
|
||||||
vertex_osd osd_quad_vb[] = {
|
if (FAILED(IDirect3DTexture9_UnlockRect(osd->texture.system, 0))) {
|
||||||
{ 0, 0, 0.0f, 0, 0 },
|
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>EOSD texture unlock failed.\n");
|
||||||
{ vo->dwidth, 0, 0.0f, tw, 0 },
|
return false;
|
||||||
{ 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);
|
|
||||||
|
|
||||||
IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
|
|
||||||
d3dtex_get_render_texture(priv, &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));
|
|
||||||
|
|
||||||
IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL);
|
|
||||||
|
|
||||||
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
|
||||||
D3DRS_ALPHATESTENABLE, FALSE);
|
|
||||||
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
|
||||||
D3DRS_ALPHABLENDENABLE, 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;
|
if (imgs->num_parts == 0 || !osd_fmt_table[imgs->format])
|
||||||
int new_h = priv->eosd->surface.h;
|
return NULL;
|
||||||
|
|
||||||
d3d_fix_texture_size(priv, &new_w, &new_h);
|
struct osdpart *osd = priv->osd[imgs->render_index];
|
||||||
|
|
||||||
if (new_w == priv->texture_eosd.tex_w && new_h == priv->texture_eosd.tex_h)
|
if (imgs->bitmap_pos_id != osd->bitmap_pos_id) {
|
||||||
return;
|
if (imgs->bitmap_id != osd->bitmap_id) {
|
||||||
|
if (!upload_osd(priv, osd, imgs))
|
||||||
|
osd->packer->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate EOSD surface.\n");
|
osd->bitmap_id = imgs->bitmap_id;
|
||||||
|
osd->bitmap_pos_id = imgs->bitmap_pos_id;
|
||||||
|
osd->num_vertices = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// fortunately, we don't need to keep the old image data
|
return osd->packer->count ? osd : NULL;
|
||||||
// we can always free it
|
|
||||||
d3dtex_release(priv, &priv->texture_eosd);
|
|
||||||
|
|
||||||
d3dtex_allocate(priv, &priv->texture_eosd, D3DFMT_A8, new_w, new_h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static D3DCOLOR ass_to_d3d_color(uint32_t color)
|
static D3DCOLOR ass_to_d3d_color(uint32_t color)
|
||||||
|
@ -2081,124 +1987,76 @@ static D3DCOLOR ass_to_d3d_color(uint32_t color)
|
||||||
return D3DCOLOR_ARGB(a, r, g, b);
|
return D3DCOLOR_ARGB(a, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *imgs)
|
static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs)
|
||||||
{
|
{
|
||||||
if (!priv->d3d_device)
|
if (!priv->d3d_device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool need_reposition, need_upload, need_resize;
|
struct osdpart *osd = generate_osd(priv, imgs);
|
||||||
eosd_packer_generate(priv->eosd, imgs, &need_reposition, &need_upload,
|
if (!osd)
|
||||||
&need_resize);
|
|
||||||
|
|
||||||
if (!need_reposition)
|
|
||||||
return;
|
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
|
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_eosd,
|
||||||
|
osd->num_vertices);
|
||||||
|
|
||||||
// we need 2 primitives per quad which makes 6 vertices (we could reduce the
|
float tex_w = osd->texture.tex_w;
|
||||||
// number of vertices by using an indexed vertex array, but it's probably
|
float tex_h = osd->texture.tex_h;
|
||||||
// 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) {
|
for (int n = 0; n < osd->packer->count; n++) {
|
||||||
struct eosd_rect rc;
|
struct sub_bitmap *b = &imgs->parts[n];
|
||||||
eosd_packer_calculate_source_bb(priv->eosd, &rc);
|
struct pos p = osd->packer->result[n];
|
||||||
RECT dirty_rc = { rc.x0, rc.y0, rc.x1, rc.y1 };
|
|
||||||
|
|
||||||
D3DLOCKED_RECT locked_rect;
|
D3DCOLOR color = imgs->format == SUBBITMAP_LIBASS
|
||||||
|
? ass_to_d3d_color(b->libass.color)
|
||||||
|
: D3DCOLOR_ARGB(255, 255, 255, 255);
|
||||||
|
|
||||||
if (FAILED(IDirect3DTexture9_LockRect(priv->texture_eosd.system, 0,
|
float x0 = b->x;
|
||||||
&locked_rect, &dirty_rc, 0)))
|
float y0 = b->y;
|
||||||
{
|
float x1 = b->x + b->dw;
|
||||||
mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>EOSD texture lock failed.\n");
|
float y1 = b->y + b->dh;
|
||||||
return;
|
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_eosd *v = &osd->vertices[n * 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 (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);
|
d3d_begin_scene(priv);
|
||||||
|
|
||||||
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
IDirect3DDevice9_SetRenderState(priv->d3d_device,
|
||||||
D3DRS_ALPHABLENDENABLE, TRUE);
|
D3DRS_ALPHABLENDENABLE, TRUE);
|
||||||
|
|
||||||
IDirect3DDevice9_SetTexture(priv->d3d_device, 0,
|
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
|
if (imgs->format == SUBBITMAP_LIBASS) {
|
||||||
IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR,
|
// do not use the color value from the A8 texture, because that is black
|
||||||
0xFFFFFFFF);
|
IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR,
|
||||||
IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
|
0xFFFFFFFF);
|
||||||
D3DTSS_COLORARG1, D3DTA_TFACTOR);
|
IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
|
||||||
|
D3DTSS_COLORARG1, D3DTA_TFACTOR);
|
||||||
|
|
||||||
IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0,
|
IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0,
|
||||||
D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||||
|
}
|
||||||
|
|
||||||
IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX);
|
IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX);
|
||||||
IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST,
|
IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST,
|
||||||
priv->eosd->targets_count * 2,
|
osd->num_vertices / 3,
|
||||||
priv->eosd_vb, sizeof(vertex_eosd));
|
osd->vertices, sizeof(vertex_eosd));
|
||||||
|
|
||||||
IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
|
IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0,
|
||||||
D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||||
|
@ -2225,7 +2083,7 @@ const struct vo_driver video_out_direct3d = {
|
||||||
.config = config,
|
.config = config,
|
||||||
.control = control,
|
.control = control,
|
||||||
.draw_slice = draw_slice,
|
.draw_slice = draw_slice,
|
||||||
.draw_osd = draw_osd,
|
.draw_osd = draw_osd_with_eosd,
|
||||||
.flip_page = flip_page,
|
.flip_page = flip_page,
|
||||||
.check_events = check_events,
|
.check_events = check_events,
|
||||||
.uninit = uninit,
|
.uninit = uninit,
|
||||||
|
@ -2243,7 +2101,7 @@ const struct vo_driver video_out_direct3d_shaders = {
|
||||||
.config = config,
|
.config = config,
|
||||||
.control = control,
|
.control = control,
|
||||||
.draw_slice = draw_slice,
|
.draw_slice = draw_slice,
|
||||||
.draw_osd = draw_osd,
|
.draw_osd = draw_osd_with_eosd,
|
||||||
.flip_page = flip_page,
|
.flip_page = flip_page,
|
||||||
.check_events = check_events,
|
.check_events = check_events,
|
||||||
.uninit = uninit,
|
.uninit = uninit,
|
||||||
|
|
Loading…
Reference in New Issue