-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Georgi Petrov wrote:
Great Jim! I'm expecting the time when your patch is finally accepted with great pleasure!
Here it is, hot off the press. 1) Texture caps are looked at to decide the best configuration for the output 2) Rendered at a 1x1 ratio using MPlayers renderer (no scaling). This fixes the aspect problems of the previous patch. 3) Clear is invoked when subs are removed to clear any stuff in the boarders in full screen mode. 4) Only configures renderstate when it needs to. If you do lots of resizing and seeking MPlayer needs to load a new subtitle font, so you could see it rendered bigger or smaller for a while until the subtitle render finally decides to pull in another font. Jim
_______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk4TFEACgkQhrNWoHjgI1B9ywCgtgzz1aUD4iAfdjrvP6FJ8W6e WgAAn1dXZ8J8M/GoEMMgmkPDcnCRxnqc =TY4B -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28089) +++ libvo/vo_direct3d.c (working copy) @@ -30,6 +30,7 @@ #include "aspect.h" #include "w32_common.h" #include "libavutil/common.h" +#include "sub.h" static const vo_info_t info = { @@ -71,8 +72,21 @@ 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 */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + int is_osd_populated; /**< 1 = OSD texture has something to display, + 0 = OSD texture is clear */ + int device_caps_power2; /**< 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 + 0 = textures do not have to be square */ + int max_texture_width; /**< from the device capabilities */ + int max_texture_height; /**< from the device capabilities */ + int osd_texture_width; /**< current width of the OSD */ + int osd_texture_height; /**< current height of the OSD */ } *priv; typedef struct { @@ -100,6 +114,13 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1) + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + /**************************************************************************** * * * * @@ -185,6 +206,17 @@ priv->d3d_surface = NULL; } + /* kill the OSD texture and its shadow copy */ + if (priv->d3d_texture_osd != NULL) { + IDirect3DTexture9_Release(priv->d3d_texture_osd); + priv->d3d_texture_osd = NULL; + } + + if (priv->d3d_texture_system != NULL) { + IDirect3DTexture9_Release(priv->d3d_texture_system); + priv->d3d_texture_system = NULL; + } + if (priv->d3d_backbuf) { IDirect3DSurface9_Release(priv->d3d_backbuf); priv->d3d_backbuf = NULL; @@ -213,6 +245,72 @@ return 0; } + /* calculate the best size for the OSD depending on the factors from the device */ + if (priv->device_caps_square_only) { + int osd_width, osd_height; + /* device only supports square textures */ + /* this is likely that they are only power2 (old HW) */ + osd_width = 1 << (32 - __builtin_clz(vo_dwidth)); + osd_height = 1 << (32 - __builtin_clz(vo_dheight)); + priv->osd_texture_width = + priv->osd_texture_height = max(osd_width, osd_height); + } else { + if (priv->device_caps_power2) { + /* device supports non square, but power 2 */ + priv->osd_texture_width = 1 << (32 - __builtin_clz(vo_dwidth)); + priv->osd_texture_height = 1 << (32 - __builtin_clz(vo_dheight)); + } else { + /* device supports any size, but power round to 16pixels */ + priv->osd_texture_width = (vo_dwidth + 15) & ~0xF; + priv->osd_texture_height = (vo_dheight + 15) & ~0xF; + } + } + + /* clamp to recorded max texture width and height */ + priv->osd_texture_width = min(priv->max_texture_width, priv->osd_texture_width); + priv->osd_texture_height = min(priv->max_texture_height, priv->osd_texture_height); + + mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d><INFO>surface (%d, %d) requested = (%d, %d)\n", + vo_dwidth, vo_dheight, priv->osd_texture_width, priv->osd_texture_height); + + /* create OSD */ + if (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><INFO>IDirect3DDevice9_CreateTexture Failed (d3d_texture_system).\n"); + return 0; + } + + if (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><INFO>IDirect3DDevice9_CreateTexture Failed (d3d_texture_osd).\n"); + return 0; + } + + /* setup default renderstate */ + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0x0); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_LIGHTING, FALSE); + IDirect3DDevice9_SetSamplerState(priv->d3d_device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(priv->d3d_device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + return 1; } @@ -470,7 +568,7 @@ mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Accepted image format: %s\n", vo_format_name(fmt_table[i].mplayer_fmt)); return (VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - /*| VFCAP_OSD*/ | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN); + | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN); } } @@ -501,6 +599,8 @@ static int preinit(const char *arg) { D3DDISPLAYMODE disp_mode; + D3DCAPS9 disp_caps; + DWORD TextureCaps; /* Set to zero all global variables. */ priv = calloc(1, sizeof(struct global_priv)); @@ -530,9 +630,30 @@ /* Store in priv->desktop_fmt the user desktop's colorspace. Usually XRGB. */ priv->desktop_fmt = disp_mode.Format; - mp_msg(MSGT_VO, MSGL_V, "disp_mode.Width %d, disp_mode.Height %d\n", + mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>disp_mode.Width %d, disp_mode.Height %d\n", disp_mode.Width, disp_mode.Height); + if (FAILED(IDirect3D9_GetDeviceCaps(priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + &disp_caps))) { + mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Could not read display capabilities\n"); + return -1; + } + + /* Store relevant information reguarding caps of device */ + TextureCaps = disp_caps.TextureCaps; + priv->device_caps_power2 = !(((TextureCaps & D3DPTEXTURECAPS_POW2) != 0) ^ + ((TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) != 0)); + priv->device_caps_square_only = ((TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0); + priv->max_texture_width = disp_caps.MaxTextureWidth; + priv->max_texture_height = disp_caps.MaxTextureHeight; + + mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>device_caps_power2 %d, device_caps_square_only %d\n" + "max_texture_width %d, max_texture_height %d\n", + priv->device_caps_power2, priv->device_caps_square_only, + priv->max_texture_width, priv->max_texture_height); + /* w32_common framework call. Configures window on the screen, gets * fullscreen dimensions and does other useful stuff. */ @@ -667,13 +788,6 @@ } } -/** @brief libvo Callback: Draw OSD/Subtitles, - * @return N/A - */ -static void draw_osd(void) -{ -} - /** @brief libvo Callback: Uninitializes all pointers and closes * all D3D related stuff, * @return N/A @@ -770,3 +884,134 @@ mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + +/** @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 + */ +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; + } +} + +/** @brief Callback function to render the OSD to the texture + */ +static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, + unsigned char *srca, int stride) +{ + 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, + &locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>IDirect3DTexture9_LockRect failure.\n"); + return; + } + + vo_draw_alpha_l8a8(w,h,src,srca,stride, + (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))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>IDirect3DTexture9_UnlockRect failure.\n"); + return; + } + + priv->is_osd_populated = 1; +} + +/** @brief libvo Callback: Draw OSD/Subtitles, + * @return N/A + */ +static void draw_osd(void) +{ + if (vo_osd_changed(0)) { + D3DLOCKED_RECT locked_rect; /**< Offscreen surface we lock in order + to copy MPlayer's frame inside it.*/ + + /* clear the OSD */ + if (FAILED(IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>IDirect3DTexture9_LockRect failure.\n"); + return; + } + + /* only need to clear upto the size of the display window */ + memset(locked_rect.pBits, 0, locked_rect.Pitch * vo_dheight); + + /* this unlock is used for both slice_draw path and D3DRenderFrame path */ + if (FAILED(IDirect3DTexture9_UnlockRect(priv->d3d_texture_system, 0))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>IDirect3DTexture9_UnlockRect failure.\n"); + return; + } + + priv->is_osd_populated = 0; + /* required for if subs are in the boarder region */ + priv->is_clear_needed = 1; + + vo_draw_text(vo_dwidth, vo_dheight, draw_alpha); + + 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>IDirect3DDevice9_UpdateTexture failure.\n"); + return; + } + } + + /* update OSD */ + + if (priv->is_osd_populated) { + + vertex_t osd_quad_vb[] = { + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + {-1.0f,-1.0f, 0.0f, 0, 1 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } + }; + + /* calculate the texture coordinates */ + osd_quad_vb[1].tu = + osd_quad_vb[3].tu = (1.0 / priv->osd_texture_width) * vo_dwidth; + osd_quad_vb[2].tv = + osd_quad_vb[3].tv = (1.0 / priv->osd_texture_height) * vo_dheight; + + if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); + return; + } + + /* turn on alpha test */ + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* 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->d3d_texture_osd); + + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX); + IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLESTRIP, 2, osd_quad_vb, sizeof(vertex_t)); + + /* turn off alpha test */ + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, FALSE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, FALSE); + + if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return; + } + } +}