-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Diego Biurrun wrote:
On Fri, Dec 05, 2008 at 08:55:11AM +0200, Georgi Petrov wrote:
This sounds good. I wait for Reimar's review and initial acceptance in the tree, so we can see and test the code. I won't write for the next 2 days and afterward I'll review the code myself and will offer any comments.
I'll try one more time: Is there a way to make you change your reply style? There is absolutely no way to tell what you are replying to when you never quote any context. This makes your mails unnecessarily hard to read. So *please* try to improve your quoting like everybody else does around here.
- From my patch the other day, I noticed some variables had capital letters at the start, so I've fixed this. I've also added the capability if you have one of these embedded cores with a UMA, you save the additional shadow texture and copy (well, that's the hope as out of 6 machines I own, non of them has one of these UMA architectures) If someone could test, a quick google showed some embedded intel cards could do it. The debug output '-v' will show the output from the D3DCAPS9 from the preinit <vo_direct3d>device_texture_sys 1 on the console Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk6PY0ACgkQhrNWoHjgI1A/QwCgv4KubFLoReClmEodjIL3492t zy4AoKax/26onmVlnlt18T4px56ff7DG =uTKw -----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,23 @@ 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 device_texture_sys; /**< 1 = device can texture from system memory + 0 = device requires shadow */ + 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 +116,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 +208,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 +247,75 @@ 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 (!priv->device_texture_sys) { + /* only create if we need a shadow version on the external device */ + 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 +573,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 +604,9 @@ static int preinit(const char *arg) { D3DDISPLAYMODE disp_mode; + D3DCAPS9 disp_caps; + DWORD texture_caps; + DWORD dev_caps; /* Set to zero all global variables. */ priv = calloc(1, sizeof(struct global_priv)); @@ -530,9 +636,34 @@ /* 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 */ + texture_caps = disp_caps.TextureCaps; + dev_caps = disp_caps.DevCaps; + priv->device_caps_power2 = !(((texture_caps & D3DPTEXTURECAPS_POW2) != 0) ^ + ((texture_caps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) != 0)); + priv->device_caps_square_only = ((texture_caps & D3DPTEXTURECAPS_SQUAREONLY) != 0); + priv->device_texture_sys = ((dev_caps & D3DDEVCAPS_TEXTURESYSTEMMEMORY) != 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" + "<vo_direct3d>device_texture_sys %d\n" + "<vo_direct3d>max_texture_width %d, max_texture_height %d\n", + priv->device_caps_power2, priv->device_caps_square_only, + priv->device_texture_sys, 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 +798,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 +894,140 @@ 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 (!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>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->device_texture_sys) + ? priv->d3d_texture_system : 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; + } + } +}