Direct3D OSD discussion
Hello, I prefer to move all OSD questions/answers in this thread, because we're over with D3D's performance for time being. First of all - Jim, thanks for updating to the latest SVN version and posting patches relative to it - it saves us all :) Let me ask some questions: 1. Drawing on the next frame is fixed easily I think. I'm sure Jim will do it right. 2. What bothers me more is this:
2) OSD is rendered in software first and then once more in hardware Again does the same as the gl renderer.
You use vo_draw_alpha_rgb32 which does alpha blending and more in software. vo_gl does not.
I will look into this.
Hmmm, I have 2 questions: Why are all other drivers I looked into (like vo_directx.c) using vo_draw_alpha_xxxxx? This is supposed to be "software rendering", right Reimar? I mean - you give a texture of some size to the functions and tell in its colorspace and it draws the OSD for you? Additionally as I see the vo_draw_alpha_xxxxx has MMX/SSE/whatever optimizations and they are used when supported. What would be the "hardware" rendering? I can't really understand what is vo_gl.c doing different... vo_gl calls vo_draw_text() with a parameter "create_osd_texture". Inside "create_osd_texture" you seem to "walk" through every OSD "part" and what... generate texture for each one? Or better - vo_draw_text() calls "create_osd_texture" for every OSD element and "create_osd_texture" creates texture for it and places it somewhere, so finally everything gets "blended" on the backbuffer? Please excuse my prehistoric understanding about everything - my day job is writing software for network adapters :) :) :) Are those things explained somewhere, so you can spare your words explaining what's happening? I'm ready to read literature about it... The second question: why do you use vo_draw_alpha_rgb32? Because you create a texture with the same format as the backbuffer? This means that you DON'T "blend" the OSD with the movie's original offscreen surface and then StretchRect it on the backbuffer, but you render the OSD on a texture with the same format as the backbuffer and blend it independent from the offscreen surface of the movie? BTW, I committed a patch for enabling BGR32/16/15 a few hours ago, but this is related to the format of the offscreen surface. Another question: Why does vo_directx.c have support for: vo_draw_alpha_yv12 vo_draw_alpha_yuy2 vo_draw_alpha_rgb15 .... and so on? I think that it does blend the OSD in the equivalent of the offscreen movie source surface or just when using Overlays, the backbuffer itself is equal to the movie's source format and you have to render the OSD in YV12, YUY2 or whatever your movie uses...
Sorry, I misunderstood. It redraws for each frame whilst it is on. I'll fix this.
Does it mean that you must render the OSD in a texture on the first requested frame and just blend it until OSD is on (and haven't changed), so you don't render the OSD without need to do so on every frame (and use the already rendered instead)? I'm sorry for my dumb questions. I'm trying to understand what's happening in the driver I originally wrote and only a week later don't understand anything :D
Hmm, I need to have freetype installed. I compiled and installed it in the msys environment. But as MPlayer seems to require iconv as well, it doesn't compile in my msys, complaining with. Jim, how did you overcome that? make[2]: Entering directory `D:/Programs/msys/libiconv-1.12/libcharset/lib' D:/Programs/msys/bin/sh.exe ../libtool --mode=compile gcc -I. -I. -I.. -I./.. -I../include -g -O2 -DLIBDIR=\"/usr/local/lib\" -DBUILDING_LIBCHARSET -DBUILDING_DLL -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"/usr/local/lib\" -DNO_XMALLOC -Dset_relocation_prefix=libcharset_set_relocation_prefix -Drelocate=libcharset_relocate -DHAVE_CONFIG_H -c ./localcharset.c gcc -I. -I. -I.. -I./.. -I../include -g -O2 "-DLIBDIR=\\/usr/local/lib\" -DBUILDING_LIBCHARSET -DBUILDING_DLL -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"/usr/local/lib\" -DNO_XMALLOC -Dset_relocation_prefix=libcharset_set_relocation_prefix -Drelocate=libcharset_relocate -DHAVE_CONFIG_H -c ./localcharset.c" -DDLL_EXPORT -DPIC -o .libs/localcharset.o gcc.exe: no input files make[2]: *** [localcharset.lo] Error 1 make[2]: Leaving directory `D:/Programs/msys/libiconv-1.12/libcharset/lib' make[1]: *** [all] Error 2 make[1]: Leaving directory `D:/Programs/msys/libiconv-1.12/libcharset' make: *** [lib/localcharset.h] Error 2
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I had problems with iconv and MSYS, but not this one I had to turn off UAC(or whatever the hell its called) in Vista to get it to work as it was complaining about /bin/install I'm using the same version as yourself, 1.12 configure make make install I can see from your command line you have some additional quotes which I don't >>> ./localcharset.c" <<< has a " character at the end, but I can't find the matching one. Jim Georgi Petrov wrote:
Hmm, I need to have freetype installed. I compiled and installed it in the msys environment. But as MPlayer seems to require iconv as well, it doesn't compile in my msys, complaining with. Jim, how did you overcome that?
make[2]: Entering directory `D:/Programs/msys/libiconv-1.12/libcharset/lib' D:/Programs/msys/bin/sh.exe ../libtool --mode=compile gcc -I. -I. -I.. -I./.. -I../include -g -O2 -DLIBDIR=\"/usr/local/lib\" -DBUILDING_LIBCHARSET -DBUILDING_DLL -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"/usr/local/lib\" -DNO_XMALLOC -Dset_relocation_prefix=libcharset_set_relocation_prefix -Drelocate=libcharset_relocate -DHAVE_CONFIG_H -c ./localcharset.c gcc -I. -I. -I.. -I./.. -I../include -g -O2 "-DLIBDIR=\\/usr/local/lib\" -DBUILDING_LIBCHARSET -DBUILDING_DLL -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"/usr/local/lib\" -DNO_XMALLOC -Dset_relocation_prefix=libcharset_set_relocation_prefix -Drelocate=libcharset_relocate -DHAVE_CONFIG_H -c ./localcharset.c" -DDLL_EXPORT -DPIC -o .libs/localcharset.o gcc.exe: no input files make[2]: *** [localcharset.lo] Error 1 make[2]: Leaving directory `D:/Programs/msys/libiconv-1.12/libcharset/lib' make[1]: *** [all] Error 2 make[1]: Leaving directory `D:/Programs/msys/libiconv-1.12/libcharset' make: *** [lib/localcharset.h] Error 2 _______________________________________________ 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 iEYEARECAAYFAkkrO30ACgkQhrNWoHjgI1BVZgCgvHgaXdMOTYcARD1DUMsBWgmf ArAAnA61qUqXy/rslVnWCIQRgBlNqozC =TBVh -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, New patch which fixes some main issues with the last patch. 1) rendering is performed with no latency. drawn between the stretchblit and the present. 2) uses a L8A8 texture for the osd, so is correctly alphablended. note that even the gl driver has to map the inverted alpha value using software memory copy (line ~551 in vo_gl.c). It should be possible to come up with a better way to do this. Please be aware that although the code may use a glTexSubImage2D() for upload the chances are this is SW in the driver. It will use less memory bandwidth than the gl version as the gl version has no alpha test to reduce GPU loads from the framebuffer and its a two pass version. 3) The image is only rendered once and then presented multiple times if it does not change. 4) If no osd are visible on then there is no cost (well a few branches :-) ) I think that this addresses most of the issues. I think the main outstanding one will be the SW rendering of the subtitle to the texture. This is however a saving over a pure SW solution as the osd doesn't need to be continually blended with the changing video underneath. Like I say I may come up with a better way for texture upload in the next few days, but I think its OK for now. Jim
Hello,
I prefer to move all OSD questions/answers in this thread, because we're over with D3D's performance for time being.
First of all - Jim, thanks for updating to the latest SVN version and posting patches relative to it - it saves us all :) Let me ask some questions:
1. Drawing on the next frame is fixed easily I think. I'm sure Jim will do it right.
2. What bothers me more is this:
2) OSD is rendered in software first and then once more in hardware Again does the same as the gl renderer. You use vo_draw_alpha_rgb32 which does alpha blending and more in software. vo_gl does not.
I will look into this.
Hmmm, I have 2 questions: Why are all other drivers I looked into (like vo_directx.c) using vo_draw_alpha_xxxxx? This is supposed to be "software rendering", right Reimar? I mean - you give a texture of some size to the functions and tell in its colorspace and it draws the OSD for you? Additionally as I see the vo_draw_alpha_xxxxx has MMX/SSE/whatever optimizations and they are used when supported. What would be the "hardware" rendering? I can't really understand what is vo_gl.c doing different...
vo_gl calls vo_draw_text() with a parameter "create_osd_texture". Inside "create_osd_texture" you seem to "walk" through every OSD "part" and what... generate texture for each one?
Or better - vo_draw_text() calls "create_osd_texture" for every OSD element and "create_osd_texture" creates texture for it and places it somewhere, so finally everything gets "blended" on the backbuffer? Please excuse my prehistoric understanding about everything - my day job is writing software for network adapters :) :) :)
Are those things explained somewhere, so you can spare your words explaining what's happening? I'm ready to read literature about it...
The second question: why do you use vo_draw_alpha_rgb32? Because you create a texture with the same format as the backbuffer? This means that you DON'T "blend" the OSD with the movie's original offscreen surface and then StretchRect it on the backbuffer, but you render the OSD on a texture with the same format as the backbuffer and blend it independent from the offscreen surface of the movie?
BTW, I committed a patch for enabling BGR32/16/15 a few hours ago, but this is related to the format of the offscreen surface.
Another question: Why does vo_directx.c have support for:
vo_draw_alpha_yv12 vo_draw_alpha_yuy2 vo_draw_alpha_rgb15 .... and so on?
I think that it does blend the OSD in the equivalent of the offscreen movie source surface or just when using Overlays, the backbuffer itself is equal to the movie's source format and you have to render the OSD in YV12, YUY2 or whatever your movie uses...
Sorry, I misunderstood. It redraws for each frame whilst it is on. I'll fix this.
Does it mean that you must render the OSD in a texture on the first requested frame and just blend it until OSD is on (and haven't changed), so you don't render the OSD without need to do so on every frame (and use the already rendered instead)?
I'm sorry for my dumb questions. I'm trying to understand what's happening in the driver I originally wrote and only a week later don't understand anything :D _______________________________________________ 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 iEYEARECAAYFAkkrOUkACgkQhrNWoHjgI1CeQgCbBnDDPkNm0GyT4R+726utCdYH mdwAn0AT3nXHitLR1DK/Z3Pk4tkXZRrK =HDb8 -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -93,7 +99,28 @@ }; #define DISPLAY_FORMAT_TABLE_ENTRIES \ - (sizeof(fmt_table) / sizeof(fmt_table[0])) + (sizeof(fmt_table) / sizeof(fmt_table[0])) + +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 512 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] = +{ + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + +extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value); /**************************************************************************** * * @@ -180,6 +207,25 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -201,6 +247,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -258,6 +306,55 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -382,7 +479,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); } } @@ -566,13 +663,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 @@ -666,3 +756,131 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + + +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++){ + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0;x<w;x++){ + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + // calculate a width and height based on the OSD_TEXTURE_SIZE + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + memset(locked_rect.pBits, 0, locked_rect.Pitch*OSD_TEXTURE_SIZE); + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) + { + 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_SRCBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)1); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
On Mon, Nov 24, 2008 at 11:31:21PM +0000, Jim Hauxwell wrote:
[...]
Jim, please restore your previous quoting habits and do not top-post here, thank you. Diego
On Mon, Nov 24, 2008 at 11:31:21PM +0000, Jim Hauxwell wrote:
2) uses a L8A8 texture for the osd, so is correctly alphablended. note that even the gl driver has to map the inverted alpha value using software memory copy (line ~551 in vo_gl.c). It should be possible to come up with a better way to do this.
I don't think so. Also + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } Why ~srca[x]? I think it should be -srca[x] (a quicker way of writing ~srca[x]+1).
Please be aware that although the code may use a glTexSubImage2D() for upload the chances are this is SW in the driver. It will use less memory bandwidth than the gl version as the gl version has no alpha test to reduce GPU loads from the framebuffer and its a two pass version.
I never really optimized the OSD-update for speed, never seemed relevant even at fullscreen resolution (at least not compared to the font rendering). But, I can say that back when I tested it, it seemed that NVidia could directly use L8 and A8 textures while it looked like L8A8 was converted in software before transfer (it caused noticeably higher CPU load). That was on an ancient TNT2 though... Note that for blending that matches the other vos, one of your blend settings should be D3DBLEND_ONE (the one that applies to the OSD texture). Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
On Mon, Nov 24, 2008 at 11:31:21PM +0000, Jim Hauxwell wrote:
2) uses a L8A8 texture for the osd, so is correctly alphablended. note that even the gl driver has to map the inverted alpha value using software memory copy (line ~551 in vo_gl.c). It should be possible to come up with a better way to do this.
I don't think so. Also + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } Why ~srca[x]? I think it should be -srca[x] (a quicker way of writing ~srca[x]+1).
No, I wrote what I wrote, - -srca[i] gives the incorrect answer. If you take the value 0x0 then this gets transformed to 0x0 and not 0xFF which is the correct result. This is a bug in vo_gl.c, not my code. If you need a small test then I'll knock up the four or so lines to prove it.
Please be aware that although the code may use a glTexSubImage2D() for upload the chances are this is SW in the driver. It will use less memory bandwidth than the gl version as the gl version has no alpha test to reduce GPU loads from the framebuffer and its a two pass version.
I never really optimized the OSD-update for speed, never seemed relevant even at fullscreen resolution (at least not compared to the font rendering). But, I can say that back when I tested it, it seemed that NVidia could directly use L8 and A8 textures while it looked like L8A8 was converted in software before transfer (it caused noticeably higher CPU load). That was on an ancient TNT2 though... Note that for blending that matches the other vos, one of your blend settings should be D3DBLEND_ONE (the one that applies to the OSD texture).
Again, this is not a bug in my patch. The others vos (well gl anyway) uses a two pass blend, mine is a single pass, so this is the correct blending.
Greetings, Reimar Döffinger _______________________________________________ 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 iEYEARECAAYFAkksPwQACgkQhrNWoHjgI1CqBwCgkMTVxE9qTd2/s6Vgk6nBEEYu 1CsAoKd9i9mz93+zN5QQtRgq+IUFLDJZ =LADZ -----END PGP SIGNATURE-----
On Tue, Nov 25, 2008 at 06:08:04PM +0000, Jim Hauxwell wrote:
I don't think so. Also + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } Why ~srca[x]? I think it should be -srca[x] (a quicker way of writing ~srca[x]+1).
No, I wrote what I wrote,
-srca[i] gives the incorrect answer. If you take the value 0x0 then this gets transformed to 0x0 and not 0xFF which is the correct result.
Why do you think that 0xFF would be the correct result? Due to the if, for your code the result is 0, too, btw. Also, with your code, the final alpha value will never be 0xFF actually, thus the OSD is never completely opaque.
This is a bug in vo_gl.c, not my code.
If you need a small test then I'll knock up the four or so lines to prove it.
Sure, prove it because I don't think it is a good way (without a specification right and wrong is a bit difficult to say, the differences are almost never visible).
Note that for blending that matches the other vos, one of your blend settings should be D3DBLEND_ONE (the one that applies to the OSD texture).
Again, this is not a bug in my patch. The others vos (well gl anyway) uses a two pass blend, mine is a single pass, so this is the correct blending.
I can't see how single or two pass has any relevance (except that vo_gl.c current implementation of two-pass can not do "correct" alpha-blending due to discarding the alpha). The point is that the OSD rendering formula for MPlayer (as seen in osd_template.c) is: if(srca[x]) dstbase[x]=((dstbase[x]*srca[x])>>8)+src[x]; (note that this is the C code which is somewhat broken, the asm code does the clamping to [0,255] before writing back, it isn't noticed usually because currently src is 0 when when srca > 1) Alpha-blending as you do it is _not_ the same thing, e.g. if you do for (int i = h * stride - 1; i >= 0; i--) { if (srca[i]) srca[i] = 0xff; if (src[i]) src[i] = 90; } The effect will be different from anything you can get with alpha-blending. This is not important enough to justify a huge workaround, but I do not see why it would be a good idea to make vo_direct3d's behave different than all of the rest of MPlayer on purpose. Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi Reimar, I was not aware of the reference code to do the osd blending, so I've taken a look at this and basically copied what it does. I've attached a patch which follows the exact blend rules ((dst * srca) >> 8) + src it uses a constant color to pass the multiplication for src, so its actually (1.0f * src) + (dst * srca) where srca is a float As a side effect you can change the color of the subtitles by changing the DWORD value in this line, IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF); for red choose 0xFFFF0000, for example Jim
On Tue, Nov 25, 2008 at 06:08:04PM +0000, Jim Hauxwell wrote:
I don't think so. Also + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } Why ~srca[x]? I think it should be -srca[x] (a quicker way of writing ~srca[x]+1).
No, I wrote what I wrote,
-srca[i] gives the incorrect answer. If you take the value 0x0 then this gets transformed to 0x0 and not 0xFF which is the correct result.
Why do you think that 0xFF would be the correct result? Due to the if, for your code the result is 0, too, btw. Also, with your code, the final alpha value will never be 0xFF actually, thus the OSD is never completely opaque.
This is a bug in vo_gl.c, not my code.
If you need a small test then I'll knock up the four or so lines to prove it.
Sure, prove it because I don't think it is a good way (without a specification right and wrong is a bit difficult to say, the differences are almost never visible).
Note that for blending that matches the other vos, one of your blend settings should be D3DBLEND_ONE (the one that applies to the OSD texture). Again, this is not a bug in my patch. The others vos (well gl anyway) uses a two pass blend, mine is a single pass, so this is the correct blending.
I can't see how single or two pass has any relevance (except that vo_gl.c current implementation of two-pass can not do "correct" alpha-blending due to discarding the alpha). The point is that the OSD rendering formula for MPlayer (as seen in osd_template.c) is: if(srca[x]) dstbase[x]=((dstbase[x]*srca[x])>>8)+src[x]; (note that this is the C code which is somewhat broken, the asm code does the clamping to [0,255] before writing back, it isn't noticed usually because currently src is 0 when when srca > 1) Alpha-blending as you do it is _not_ the same thing, e.g. if you do for (int i = h * stride - 1; i >= 0; i--) { if (srca[i]) srca[i] = 0xff; if (src[i]) src[i] = 90; } The effect will be different from anything you can get with alpha-blending. This is not important enough to justify a huge workaround, but I do not see why it would be a good idea to make vo_direct3d's behave different than all of the rest of MPlayer on purpose.
Greetings, Reimar Döffinger _______________________________________________ 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 iEYEARECAAYFAkkslBMACgkQhrNWoHjgI1A7DQCgpuSIQisJLs8SmqNuRRCrghuz 9igAoMhbPp9UZnU7eBThNxrzWUfpxVuy =cXSh -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -1,668 +1,895 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <windows.h> -#include <errno.h> -#include <stdio.h> -#include <d3d9.h> -#include "config.h" -#include "video_out.h" -#include "video_out_internal.h" -#include "fastmemcpy.h" -#include "mp_msg.h" -#include "aspect.h" -#include "w32_common.h" -#include "libavutil/common.h" - -static const vo_info_t info = -{ - "Direct3D 9 Renderer", - "direct3d", - "Georgi Petrov (gogothebee) <gogothebee@gmail.com>", - "" -}; - -/* - * Link essential libvo functions: preinit, config, control, draw_frame, - * draw_slice, draw_osd, flip_page, check_events, uninit and - * the structure info. - */ -const LIBVO_EXTERN(direct3d) - - -/* Global variables "priv" structure. I try to keep their count low. - */ -static struct global_priv { - int is_paused; /**< 1 = Movie is paused, - 0 = Movie is not paused */ - int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect - 0 = (default) Don't clear it */ - D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ - RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed - in fullscreen */ - RECT fs_panscan_rect; /**< PanScan source surface cropping in - fullscreen */ - int src_width; /**< Source (movie) width */ - int src_height; /**< Source (movie) heigth */ - - D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on - the movie's codec) */ - D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. - Usually XRGB */ - LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ - LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ - IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer - renders inside it. Uses colorspace - priv->movie_src_fmt */ - IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to - display next frame) */ -} *priv; - -typedef struct { - const unsigned int mplayer_fmt; /**< Given by MPlayer */ - const D3DFORMAT fourcc; /**< Required by D3D's test function */ -} struct_fmt_table; - -/* Map table from reported MPlayer format to the required - fourcc. This is needed to perform the format query. */ - -static const struct_fmt_table fmt_table[] = { - {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, - {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, - {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, - {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, - {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, - {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')}, -}; - -#define DISPLAY_FORMAT_TABLE_ENTRIES \ - (sizeof(fmt_table) / sizeof(fmt_table[0])) - -/**************************************************************************** - * * - * * - * * - * Direct3D specific implementation functions * - * * - * * - * * - ****************************************************************************/ - -/** @brief Calculate scaled fullscreen movie rectangle with - * preserved aspect ratio. - */ -static void calc_fs_rect(void) -{ - int scaled_height = 0; - int scaled_width = 0; - - // set default values - priv->fs_movie_rect.left = 0; - priv->fs_movie_rect.right = vo_dwidth; - priv->fs_movie_rect.top = 0; - priv->fs_movie_rect.bottom = vo_dheight; - priv->fs_panscan_rect.left = 0; - priv->fs_panscan_rect.right = priv->src_width; - priv->fs_panscan_rect.top = 0; - priv->fs_panscan_rect.bottom = priv->src_height; - if (!vo_fs) return; - - // adjust for fullscreen aspect and panscan - aspect(&scaled_width, &scaled_height, A_ZOOM); - panscan_calc(); - scaled_width += vo_panscan_x; - scaled_height += vo_panscan_y; - - // note: border is rounded to a multiple of two since at least - // ATI drivers can not handle odd values with YV12 input - if (scaled_width > vo_dwidth) { - int border = priv->src_width * (scaled_width - vo_dwidth) / scaled_width; - border = (border / 2 + 1) & ~1; - priv->fs_panscan_rect.left = border; - priv->fs_panscan_rect.right = priv->src_width - border; - } else { - priv->fs_movie_rect.left = (vo_dwidth - scaled_width) / 2; - priv->fs_movie_rect.right = priv->fs_movie_rect.left + scaled_width; - } - if (scaled_height > vo_dheight) { - int border = priv->src_height * (scaled_height - vo_dheight) / scaled_height; - border = (border / 2 + 1) & ~1; - priv->fs_panscan_rect.top = border; - priv->fs_panscan_rect.bottom = priv->src_height - border; - } else { - priv->fs_movie_rect.top = (vo_dheight - scaled_height) / 2; - priv->fs_movie_rect.bottom = priv->fs_movie_rect.top + scaled_height; - } - - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Fullscreen Movie Rect: t: %ld, l: %ld, r: %ld, b:%ld\r\n", - priv->fs_movie_rect.top, priv->fs_movie_rect.left, - priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); - - /* The backbuffer should be cleared before next StretchRect. This is - * necessary because our new draw area could be smaller than the - * previous one used by StretchRect and without it, leftovers from the - * previous frame will be left. */ - priv->is_clear_needed = 1; -} - -/** @brief Destroy D3D Context related to the current window. - */ -static void destroy_d3d_context(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>destroy_d3d_context called\r\n"); - /* Let's destroy the old (if any) D3D Content */ - - if (priv->locked_rect.pBits) { - IDirect3DSurface9_UnlockRect(priv->d3d_surface); - priv->locked_rect.pBits = NULL; - } - - if (priv->d3d_surface != NULL) { - IDirect3DSurface9_Release (priv->d3d_surface); - priv->d3d_surface = NULL; - } - - if (priv->d3d_device != NULL) { - IDirect3DDevice9_Release (priv->d3d_device); - priv->d3d_device = NULL; - } - - /* The following is not a memory leak. d3d_backbuf is not malloc'ed - * but just holds a pointer to the back buffer. Nobody gets hurt from - * setting it to NULL. - */ - priv->d3d_backbuf = NULL; -} - - -/** @brief (Re)Initialize Direct3D. Kill and recreate context. - * The first function called to initialize D3D context. - * @return 1 on success, 0 on failure - */ -static int reconfigure_d3d(void) -{ - D3DPRESENT_PARAMETERS present_params; - D3DDISPLAYMODE disp_mode; - - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); - - destroy_d3d_context(); - - /* Get the current desktop display mode, so we can set up a back buffer - * of the same format. */ - if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, - D3DADAPTER_DEFAULT, - &disp_mode))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>Could not read adapter display mode.\n"); - return 0; - } - - /* Write current Desktop's colorspace format in the global storage. */ - priv->desktop_fmt = disp_mode.Format; - - /* Prepare Direct3D initialization parameters. */ - memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); - present_params.Windowed = TRUE; - present_params.SwapEffect = D3DSWAPEFFECT_COPY; - present_params.Flags = D3DPRESENTFLAG_VIDEO; - present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ - present_params.BackBufferWidth = 0; /* Fill up window Width */ - present_params.BackBufferHeight = 0; /* Fill up window Height */ - present_params.MultiSampleType = D3DMULTISAMPLE_NONE; - /* D3DPRESENT_INTERVAL_ONE = vsync */ - present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - present_params.BackBufferFormat = priv->desktop_fmt; - present_params.BackBufferCount = 1; - present_params.EnableAutoDepthStencil = FALSE; - - /* vo_w32_window is w32_common variable. It's a handle to the window. */ - if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, vo_w32_window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &present_params, &priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>Could not create the D3D device\n"); - return 0; - } - - mp_msg(MSGT_VO,MSGL_V, - "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", - present_params.BackBufferWidth, present_params.BackBufferHeight, - vo_dwidth, vo_dheight); - - if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( - priv->d3d_device, priv->src_width, priv->src_height, - priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); - return 0; - } - - if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, - D3DBACKBUFFER_TYPE_MONO, - &(priv->d3d_backbuf)))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Back Buffer address get failed\n"); - return 0; - } - - calc_fs_rect(); - - return 1; -} - -/** @brief Uninitialize Direct3D and close the window. - */ -static void uninit_d3d(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>uninit_d3d called\r\n"); - - /* Destroy D3D Context inside the window. */ - destroy_d3d_context(); - - /* Stop the whole D3D. */ - if (NULL != priv->d3d_handle) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Calling IDirect3D9_Release\r\n"); - IDirect3D9_Release(priv->d3d_handle); - } -} - -/** @brief Render a frame on the screen. - * @param mpi mpi structure with the decoded frame inside - * @return VO_TRUE on success, VO_ERROR on failure - */ -static uint32_t render_d3d_frame(mp_image_t *mpi) -{ - /* Uncomment when direct rendering is implemented. - * if (mpi->flags & MP_IMGFLAG_DIRECT) ... - */ - - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - goto skip_upload; - - if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ - draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0); - goto skip_upload; - } - - /* If we're here, then we should lock the rect and copy a packed frame */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Surface lock failure\n"); - return VO_ERROR; - } - } - - memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], - mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); - -skip_upload: - /* This unlock is used for both slice_draw path and render_d3d_frame path. */ - if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface unlock failure\n"); - return VO_ERROR; - } - priv->locked_rect.pBits = NULL; - - if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); - return VO_ERROR; - } - - if (priv->is_clear_needed) { - IDirect3DDevice9_Clear (priv->d3d_device, 0, NULL, - D3DCLEAR_TARGET, 0, 0, 0); - priv->is_clear_needed = 0; - } - - if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, - priv->d3d_surface, - &priv->fs_panscan_rect, - priv->d3d_backbuf, - &priv->fs_movie_rect, - D3DTEXF_LINEAR))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d>Unable to copy the frame to the back buffer\n"); - return VO_ERROR; - } - - if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); - return VO_ERROR; - } - - return VO_TRUE; -} - - -/** @brief Query if movie colorspace is supported by the HW. - * @return 0 on failure, device capabilities (not probed - * currently) on success. - */ -static int query_format(uint32_t movie_fmt) -{ - int i; - for (i=0; i < DISPLAY_FORMAT_TABLE_ENTRIES; i++) { - if (fmt_table[i].mplayer_fmt == movie_fmt) { - /* Test conversion from Movie colorspace to - * display's target colorspace. */ - if (FAILED(IDirect3D9_CheckDeviceFormatConversion( - priv->d3d_handle, - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - fmt_table[i].fourcc, - priv->desktop_fmt))) { - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Rejected image format: %s\n", - vo_format_name(fmt_table[i].mplayer_fmt)); - return 0; - } - - priv->movie_src_fmt = fmt_table[i].fourcc; - 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); - - } - } - - return 0; -} - -/**************************************************************************** - * * - * * - * * - * libvo Control / Callback functions * - * * - * * - * * - ****************************************************************************/ - - - - -/** @brief libvo Callback: Preinitialize the video card. - * Preinit the hardware just enough to be queried about - * supported formats. - * - * @return 0 on success, -1 on failure - */ - -static int preinit(const char *arg) -{ - D3DDISPLAYMODE disp_mode; - - /* Set to zero all global variables. */ - priv = calloc(1, sizeof (struct global_priv)); - if (!priv) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Not enough memory\r\n"); - return -1; - } - - /* FIXME - > Please use subopt-helper.h for this, see vo_gl.c:preinit for - > an example of how to use it. - */ - - priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); - if (!priv->d3d_handle) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Unable to initialize Direct3D\n"); - return -1; - } - - if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, - D3DADAPTER_DEFAULT, - &disp_mode))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Could not read display mode\n"); - return -1; - } - - /* 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", - disp_mode.Width, disp_mode.Height); - - /* w32_common framework call. Configures window on the screen, gets - * fullscreen dimensions and does other useful stuff. - */ - if (!vo_w32_init()) { - mp_msg(MSGT_VO,MSGL_V,"Unable to configure onscreen window\r\n"); - return -1; - } - - return 0; -} - - - -/** @brief libvo Callback: Handle control requests. - * @return VO_TRUE on success, VO_NOTIMPL when not implemented - */ -static int control(uint32_t request, void *data, ...) -{ - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(*(uint32_t*) data); - case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet. */ - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Direct Rendering request. Not implemented yet\n"); - return VO_NOTIMPL; - case VOCTRL_DRAW_IMAGE: - return render_d3d_frame(data); - case VOCTRL_FULLSCREEN: - vo_w32_fullscreen(); - reconfigure_d3d(); - return VO_TRUE; - case VOCTRL_RESET: - return VO_NOTIMPL; - case VOCTRL_PAUSE: - priv->is_paused = 1; - return VO_TRUE; - case VOCTRL_RESUME: - priv->is_paused = 0; - return VO_TRUE; - case VOCTRL_GUISUPPORT: - return VO_NOTIMPL; - case VOCTRL_SET_EQUALIZER: - return VO_NOTIMPL; - case VOCTRL_GET_EQUALIZER: - return VO_NOTIMPL; - case VOCTRL_ONTOP: - vo_w32_ontop(); - return VO_TRUE; - case VOCTRL_BORDER: - vo_w32_border(); - reconfigure_d3d(); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - w32_update_xinerama_info(); - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - calc_fs_rect (); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - } - return VO_FALSE; -} - -/** @brief libvo Callback: Configre the Direct3D adapter. - * @param width Movie source width - * @param height Movie source height - * @param d_width Screen (destination) width - * @param d_height Screen (destination) height - * @param options Options bitmap - * @param title Window title - * @param format Movie colorspace format (using MPlayer's - * defines, e.g. IMGFMT_YUY2) - * @return 0 on success, VO_ERROR on failure - */ -static int config(uint32_t width, uint32_t height, uint32_t d_width, - uint32_t d_height, uint32_t options, char *title, - uint32_t format) -{ - - priv->src_width = width; - priv->src_height = height; - - /* w32_common framework call. Creates window on the screen with - * the given coordinates. - */ - if (!vo_w32_config(d_width, d_height, options)) { - mp_msg(MSGT_VO,MSGL_V,"Unable to create onscreen window\r\n"); - return VO_ERROR; - } - - if (!reconfigure_d3d()) - return VO_ERROR; - - return 0; /* Success */ -} - -/** @brief libvo Callback: Flip next already drawn frame on the - * screen. - * @return N/A - */ -static void flip_page(void) -{ - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Video adapter became uncooperative.\n"); - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Trying to reinitialize it...\n"); - if (!reconfigure_d3d()) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); - return; - } - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); - return; - } - else - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Video adapter reinitialized.\n"); - - } -} - -/** @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 - */ -static void uninit(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Uninitialization\r\n"); - - uninit_d3d(); - vo_w32_uninit(); /* w32_common framework call */ - free (priv); - priv = NULL; -} - -/** @brief libvo Callback: Handles video window events. - * @return N/A - */ -static void check_events(void) -{ - int flags; - /* w32_common framework call. Handles video window events. - * Updates global libvo's vo_dwidth/vo_dheight upon resize - * with the new window width/height. - */ - flags = vo_w32_check_events(); - if (flags & VO_EVENT_RESIZE) - reconfigure_d3d(); - - if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) - flip_page(); -} - -/** @brief libvo Callback: Draw slice - * @return 0 on success - */ -static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) -{ - char *my_src; /**< Pointer to the source image */ - char *dst; /**< Pointer to the destination image */ - int uv_stride; /**< Stride of the U/V planes */ - - /* Lock the offscreen surface if it's not already locked. */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface lock failure\n"); - return VO_FALSE; - } - } - - uv_stride = priv->locked_rect.Pitch / 2; - - /* Copy Y */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * y + x; - my_src=src[0]; - memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); - - w/=2;h/=2;x/=2;y/=2; - - /* Copy U */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src=src[2]; - else - my_src=src[1]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); - - /* Copy V */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * (priv->src_height / 2) + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src=src[1]; - else - my_src=src[2]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); - - return 0; /* Success */ -} - -/** @brief libvo Callback: Unused function - * @return N/A - */ -static int draw_frame(uint8_t *src[]) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); - return VO_FALSE; -} +/* + * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <windows.h> +#include <errno.h> +#include <stdio.h> +#include <d3d9.h> +#include "config.h" +#include "video_out.h" +#include "video_out_internal.h" +#include "fastmemcpy.h" +#include "mp_msg.h" +#include "aspect.h" +#include "w32_common.h" +#include "libavutil/common.h" + +static const vo_info_t info = +{ + "Direct3D 9 Renderer", + "direct3d", + "Georgi Petrov (gogothebee) <gogothebee@gmail.com>", + "" +}; + +/* + * Link essential libvo functions: preinit, config, control, draw_frame, + * draw_slice, draw_osd, flip_page, check_events, uninit and + * the structure info. + */ +const LIBVO_EXTERN(direct3d) + + +/* Global variables "priv" structure. I try to keep their count low. + */ +static struct global_priv { + int is_paused; /**< 1 = Movie is paused, + 0 = Movie is not paused */ + int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect + 0 = (default) Don't clear it */ + D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ + RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed + in fullscreen */ + RECT fs_panscan_rect; /**< PanScan source surface cropping in + fullscreen */ + int src_width; /**< Source (movie) width */ + int src_height; /**< Source (movie) heigth */ + + D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on + the movie's codec) */ + D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. + Usually XRGB */ + LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ + LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ + 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 + cant lock a normal texture. Uses RGBA */ + IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to + display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ +} *priv; + +typedef struct { + const unsigned int mplayer_fmt; /**< Given by MPlayer */ + const D3DFORMAT fourcc; /**< Required by D3D's test function */ +} struct_fmt_table; + +/* Map table from reported MPlayer format to the required + fourcc. This is needed to perform the format query. */ + +static const struct_fmt_table fmt_table[] = { + {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, + {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, + {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, + {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, + {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, + {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')}, +}; + +#define DISPLAY_FORMAT_TABLE_ENTRIES \ + (sizeof(fmt_table) / sizeof(fmt_table[0])) + +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] = +{ + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + +extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value); + +/**************************************************************************** + * * + * * + * * + * Direct3D specific implementation functions * + * * + * * + * * + ****************************************************************************/ + +/** @brief Calculate scaled fullscreen movie rectangle with + * preserved aspect ratio. + */ +static void calc_fs_rect(void) +{ + int scaled_height = 0; + int scaled_width = 0; + + // set default values + priv->fs_movie_rect.left = 0; + priv->fs_movie_rect.right = vo_dwidth; + priv->fs_movie_rect.top = 0; + priv->fs_movie_rect.bottom = vo_dheight; + priv->fs_panscan_rect.left = 0; + priv->fs_panscan_rect.right = priv->src_width; + priv->fs_panscan_rect.top = 0; + priv->fs_panscan_rect.bottom = priv->src_height; + if (!vo_fs) return; + + // adjust for fullscreen aspect and panscan + aspect(&scaled_width, &scaled_height, A_ZOOM); + panscan_calc(); + scaled_width += vo_panscan_x; + scaled_height += vo_panscan_y; + + // note: border is rounded to a multiple of two since at least + // ATI drivers can not handle odd values with YV12 input + if (scaled_width > vo_dwidth) { + int border = priv->src_width * (scaled_width - vo_dwidth) / scaled_width; + border = (border / 2 + 1) & ~1; + priv->fs_panscan_rect.left = border; + priv->fs_panscan_rect.right = priv->src_width - border; + } else { + priv->fs_movie_rect.left = (vo_dwidth - scaled_width) / 2; + priv->fs_movie_rect.right = priv->fs_movie_rect.left + scaled_width; + } + if (scaled_height > vo_dheight) { + int border = priv->src_height * (scaled_height - vo_dheight) / scaled_height; + border = (border / 2 + 1) & ~1; + priv->fs_panscan_rect.top = border; + priv->fs_panscan_rect.bottom = priv->src_height - border; + } else { + priv->fs_movie_rect.top = (vo_dheight - scaled_height) / 2; + priv->fs_movie_rect.bottom = priv->fs_movie_rect.top + scaled_height; + } + + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Fullscreen Movie Rect: t: %ld, l: %ld, r: %ld, b:%ld\r\n", + priv->fs_movie_rect.top, priv->fs_movie_rect.left, + priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); + + /* The backbuffer should be cleared before next StretchRect. This is + * necessary because our new draw area could be smaller than the + * previous one used by StretchRect and without it, leftovers from the + * previous frame will be left. */ + priv->is_clear_needed = 1; +} + +/** @brief Destroy D3D Context related to the current window. + */ +static void destroy_d3d_context(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>destroy_d3d_context called\r\n"); + /* Let's destroy the old (if any) D3D Content */ + + if (priv->locked_rect.pBits) { + IDirect3DSurface9_UnlockRect(priv->d3d_surface); + priv->locked_rect.pBits = NULL; + } + + if (priv->d3d_surface != NULL) { + IDirect3DSurface9_Release (priv->d3d_surface); + priv->d3d_surface = NULL; + } + + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + + if (priv->d3d_device != NULL) { + IDirect3DDevice9_Release (priv->d3d_device); + priv->d3d_device = NULL; + } + + /* The following is not a memory leak. d3d_backbuf is not malloc'ed + * but just holds a pointer to the back buffer. Nobody gets hurt from + * setting it to NULL. + */ + priv->d3d_backbuf = NULL; +} + + +/** @brief (Re)Initialize Direct3D. Kill and recreate context. + * The first function called to initialize D3D context. + * @return 1 on success, 0 on failure + */ +static int reconfigure_d3d(void) +{ + D3DPRESENT_PARAMETERS present_params; + D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; + + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); + + destroy_d3d_context(); + + /* Get the current desktop display mode, so we can set up a back buffer + * of the same format. */ + if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, + D3DADAPTER_DEFAULT, + &disp_mode))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>Could not read adapter display mode.\n"); + return 0; + } + + /* Write current Desktop's colorspace format in the global storage. */ + priv->desktop_fmt = disp_mode.Format; + + /* Prepare Direct3D initialization parameters. */ + memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); + present_params.Windowed = TRUE; + present_params.SwapEffect = D3DSWAPEFFECT_COPY; + present_params.Flags = D3DPRESENTFLAG_VIDEO; + present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ + present_params.BackBufferWidth = 0; /* Fill up window Width */ + present_params.BackBufferHeight = 0; /* Fill up window Height */ + present_params.MultiSampleType = D3DMULTISAMPLE_NONE; + /* D3DPRESENT_INTERVAL_ONE = vsync */ + present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + present_params.BackBufferFormat = priv->desktop_fmt; + present_params.BackBufferCount = 1; + present_params.EnableAutoDepthStencil = FALSE; + + /* vo_w32_window is w32_common variable. It's a handle to the window. */ + if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, vo_w32_window, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &present_params, &priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>Could not create the D3D device\n"); + return 0; + } + + mp_msg(MSGT_VO,MSGL_V, + "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", + present_params.BackBufferWidth, present_params.BackBufferHeight, + vo_dwidth, vo_dheight); + + if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( + priv->d3d_device, priv->src_width, priv->src_height, + priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); + return 0; + } + + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, + D3DBACKBUFFER_TYPE_MONO, + &(priv->d3d_backbuf)))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Back Buffer address get failed\n"); + return 0; + } + + calc_fs_rect(); + + return 1; +} + +/** @brief Uninitialize Direct3D and close the window. + */ +static void uninit_d3d(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>uninit_d3d called\r\n"); + + /* Destroy D3D Context inside the window. */ + destroy_d3d_context(); + + /* Stop the whole D3D. */ + if (NULL != priv->d3d_handle) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Calling IDirect3D9_Release\r\n"); + IDirect3D9_Release(priv->d3d_handle); + } +} + +/** @brief Render a frame on the screen. + * @param mpi mpi structure with the decoded frame inside + * @return VO_TRUE on success, VO_ERROR on failure + */ +static uint32_t render_d3d_frame(mp_image_t *mpi) +{ + /* Uncomment when direct rendering is implemented. + * if (mpi->flags & MP_IMGFLAG_DIRECT) ... + */ + + if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) + goto skip_upload; + + if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ + draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0); + goto skip_upload; + } + + /* If we're here, then we should lock the rect and copy a packed frame */ + if (!priv->locked_rect.pBits) { + if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, + &priv->locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Surface lock failure\n"); + return VO_ERROR; + } + } + + memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], + mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); + +skip_upload: + /* This unlock is used for both slice_draw path and render_d3d_frame path. */ + if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface unlock failure\n"); + return VO_ERROR; + } + priv->locked_rect.pBits = NULL; + + if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); + return VO_ERROR; + } + + if (priv->is_clear_needed) { + IDirect3DDevice9_Clear (priv->d3d_device, 0, NULL, + D3DCLEAR_TARGET, 0, 0, 0); + priv->is_clear_needed = 0; + } + + if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, + priv->d3d_surface, + &priv->fs_panscan_rect, + priv->d3d_backbuf, + &priv->fs_movie_rect, + D3DTEXF_LINEAR))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d>Unable to copy the frame to the back buffer\n"); + return VO_ERROR; + } + + if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return VO_ERROR; + } + + return VO_TRUE; +} + + +/** @brief Query if movie colorspace is supported by the HW. + * @return 0 on failure, device capabilities (not probed + * currently) on success. + */ +static int query_format(uint32_t movie_fmt) +{ + int i; + for (i=0; i < DISPLAY_FORMAT_TABLE_ENTRIES; i++) { + if (fmt_table[i].mplayer_fmt == movie_fmt) { + /* Test conversion from Movie colorspace to + * display's target colorspace. */ + if (FAILED(IDirect3D9_CheckDeviceFormatConversion( + priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + fmt_table[i].fourcc, + priv->desktop_fmt))) { + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Rejected image format: %s\n", + vo_format_name(fmt_table[i].mplayer_fmt)); + return 0; + } + + priv->movie_src_fmt = fmt_table[i].fourcc; + 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); + + } + } + + return 0; +} + +/**************************************************************************** + * * + * * + * * + * libvo Control / Callback functions * + * * + * * + * * + ****************************************************************************/ + + + + +/** @brief libvo Callback: Preinitialize the video card. + * Preinit the hardware just enough to be queried about + * supported formats. + * + * @return 0 on success, -1 on failure + */ + +static int preinit(const char *arg) +{ + D3DDISPLAYMODE disp_mode; + + /* Set to zero all global variables. */ + priv = calloc(1, sizeof (struct global_priv)); + if (!priv) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Not enough memory\r\n"); + return -1; + } + + /* FIXME + > Please use subopt-helper.h for this, see vo_gl.c:preinit for + > an example of how to use it. + */ + + priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); + if (!priv->d3d_handle) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Unable to initialize Direct3D\n"); + return -1; + } + + if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, + D3DADAPTER_DEFAULT, + &disp_mode))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Could not read display mode\n"); + return -1; + } + + /* 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", + disp_mode.Width, disp_mode.Height); + + /* w32_common framework call. Configures window on the screen, gets + * fullscreen dimensions and does other useful stuff. + */ + if (!vo_w32_init()) { + mp_msg(MSGT_VO,MSGL_V,"Unable to configure onscreen window\r\n"); + return -1; + } + + return 0; +} + + + +/** @brief libvo Callback: Handle control requests. + * @return VO_TRUE on success, VO_NOTIMPL when not implemented + */ +static int control(uint32_t request, void *data, ...) +{ + switch (request) { + case VOCTRL_QUERY_FORMAT: + return query_format(*(uint32_t*) data); + case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet. */ + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Direct Rendering request. Not implemented yet\n"); + return VO_NOTIMPL; + case VOCTRL_DRAW_IMAGE: + return render_d3d_frame(data); + case VOCTRL_FULLSCREEN: + vo_w32_fullscreen(); + reconfigure_d3d(); + return VO_TRUE; + case VOCTRL_RESET: + return VO_NOTIMPL; + case VOCTRL_PAUSE: + priv->is_paused = 1; + return VO_TRUE; + case VOCTRL_RESUME: + priv->is_paused = 0; + return VO_TRUE; + case VOCTRL_GUISUPPORT: + return VO_NOTIMPL; + case VOCTRL_SET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_GET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_ONTOP: + vo_w32_ontop(); + return VO_TRUE; + case VOCTRL_BORDER: + vo_w32_border(); + reconfigure_d3d(); + return VO_TRUE; + case VOCTRL_UPDATE_SCREENINFO: + w32_update_xinerama_info(); + return VO_TRUE; + case VOCTRL_SET_PANSCAN: + calc_fs_rect (); + return VO_TRUE; + case VOCTRL_GET_PANSCAN: + return VO_TRUE; + } + return VO_FALSE; +} + +/** @brief libvo Callback: Configre the Direct3D adapter. + * @param width Movie source width + * @param height Movie source height + * @param d_width Screen (destination) width + * @param d_height Screen (destination) height + * @param options Options bitmap + * @param title Window title + * @param format Movie colorspace format (using MPlayer's + * defines, e.g. IMGFMT_YUY2) + * @return 0 on success, VO_ERROR on failure + */ +static int config(uint32_t width, uint32_t height, uint32_t d_width, + uint32_t d_height, uint32_t options, char *title, + uint32_t format) +{ + + priv->src_width = width; + priv->src_height = height; + + /* w32_common framework call. Creates window on the screen with + * the given coordinates. + */ + if (!vo_w32_config(d_width, d_height, options)) { + mp_msg(MSGT_VO,MSGL_V,"Unable to create onscreen window\r\n"); + return VO_ERROR; + } + + if (!reconfigure_d3d()) + return VO_ERROR; + + return 0; /* Success */ +} + +/** @brief libvo Callback: Flip next already drawn frame on the + * screen. + * @return N/A + */ +static void flip_page(void) +{ + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Video adapter became uncooperative.\n"); + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Trying to reinitialize it...\n"); + if (!reconfigure_d3d()) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); + return; + } + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); + return; + } + else + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Video adapter reinitialized.\n"); + + } +} + +/** @brief libvo Callback: Uninitializes all pointers and closes + * all D3D related stuff, + * @return N/A + */ +static void uninit(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Uninitialization\r\n"); + + uninit_d3d(); + vo_w32_uninit(); /* w32_common framework call */ + free (priv); + priv = NULL; +} + +/** @brief libvo Callback: Handles video window events. + * @return N/A + */ +static void check_events(void) +{ + int flags; + /* w32_common framework call. Handles video window events. + * Updates global libvo's vo_dwidth/vo_dheight upon resize + * with the new window width/height. + */ + flags = vo_w32_check_events(); + if (flags & VO_EVENT_RESIZE) + reconfigure_d3d(); + + if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) + flip_page(); +} + +/** @brief libvo Callback: Draw slice + * @return 0 on success + */ +static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) +{ + char *my_src; /**< Pointer to the source image */ + char *dst; /**< Pointer to the destination image */ + int uv_stride; /**< Stride of the U/V planes */ + + /* Lock the offscreen surface if it's not already locked. */ + if (!priv->locked_rect.pBits) { + if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, + &priv->locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface lock failure\n"); + return VO_FALSE; + } + } + + uv_stride = priv->locked_rect.Pitch / 2; + + /* Copy Y */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * y + x; + my_src=src[0]; + memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); + + w/=2;h/=2;x/=2;y/=2; + + /* Copy U */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * priv->src_height + + uv_stride * y + x; + if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) + my_src=src[2]; + else + my_src=src[1]; + + memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); + + /* Copy V */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * priv->src_height + + uv_stride * (priv->src_height / 2) + uv_stride * y + x; + if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) + my_src=src[1]; + else + my_src=src[2]; + + memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); + + return 0; /* Success */ +} + +/** @brief libvo Callback: Unused function + * @return N/A + */ +static int draw_frame(uint8_t *src[]) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); + return VO_FALSE; +} + + +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++){ + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0;x<w;x++){ + if(srca[x]) + dst[x]=(srca[x] << 8) | src[x]; + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + int x, y; + // calculate a width and height based on the OSD_TEXTURE_SIZE + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y = 0; y < OSD_TEXTURE_SIZE; y++) + { + unsigned short * dst = (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x = 0; x < OSD_TEXTURE_SIZE; x++) + { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) + { + 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_SRCBLEND, D3DBLEND_BLENDFACTOR); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + + } +}
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Sorry, Ignore the last one, I had forgotten to change the alpha test, the GPU would have been doing more work than it needed. Jim
Hi Reimar,
I was not aware of the reference code to do the osd blending, so I've taken a look at this and basically copied what it does.
I've attached a patch which follows the exact blend rules
((dst * srca) >> 8) + src
it uses a constant color to pass the multiplication for src, so its actually
(1.0f * src) + (dst * srca) where srca is a float
As a side effect you can change the color of the subtitles by changing the DWORD value in this line,
IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF);
for red choose 0xFFFF0000, for example
Jim
I don't think so. Also + if(srca[x]){ + dst[x]=(~srca[x] << 8) | src[x]; + } Why ~srca[x]? I think it should be -srca[x] (a quicker way of writing ~srca[x]+1). No, I wrote what I wrote,
-srca[i] gives the incorrect answer. If you take the value 0x0 then this gets transformed to 0x0 and not 0xFF which is the correct result. Why do you think that 0xFF would be the correct result? Due to the if, for your code the result is 0, too, btw. Also, with your code, the final alpha value will never be 0xFF actually, thus
On Tue, Nov 25, 2008 at 06:08:04PM +0000, Jim Hauxwell wrote: the OSD is never completely opaque.
This is a bug in vo_gl.c, not my code.
If you need a small test then I'll knock up the four or so lines to prove it. Sure, prove it because I don't think it is a good way (without a specification right and wrong is a bit difficult to say, the differences are almost never visible).
Note that for blending that matches the other vos, one of your blend settings should be D3DBLEND_ONE (the one that applies to the OSD texture). Again, this is not a bug in my patch. The others vos (well gl anyway) uses a two pass blend, mine is a single pass, so this is the correct blending. I can't see how single or two pass has any relevance (except that vo_gl.c current implementation of two-pass can not do "correct" alpha-blending due to discarding the alpha). The point is that the OSD rendering formula for MPlayer (as seen in osd_template.c) is: if(srca[x]) dstbase[x]=((dstbase[x]*srca[x])>>8)+src[x]; (note that this is the C code which is somewhat broken, the asm code does the clamping to [0,255] before writing back, it isn't noticed usually because currently src is 0 when when srca > 1) Alpha-blending as you do it is _not_ the same thing, e.g. if you do for (int i = h * stride - 1; i >= 0; i--) { if (srca[i]) srca[i] = 0xff; if (src[i]) src[i] = 90; } The effect will be different from anything you can get with alpha-blending. This is not important enough to justify a huge workaround, but I do not see why it would be a good idea to make vo_direct3d's behave different than all of the rest of MPlayer on purpose.
Greetings, Reimar Döffinger _______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
- ------------------------------------------------------------------------ _______________________________________________ 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 iEYEARECAAYFAkksl70ACgkQhrNWoHjgI1CRAgCgymC+u3iEgp6FTjLfitFTE/VI q5UAn3dfb63nUjapl1a6PSusT3Z5AgSV =M3ao -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -1,668 +1,895 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <windows.h> -#include <errno.h> -#include <stdio.h> -#include <d3d9.h> -#include "config.h" -#include "video_out.h" -#include "video_out_internal.h" -#include "fastmemcpy.h" -#include "mp_msg.h" -#include "aspect.h" -#include "w32_common.h" -#include "libavutil/common.h" - -static const vo_info_t info = -{ - "Direct3D 9 Renderer", - "direct3d", - "Georgi Petrov (gogothebee) <gogothebee@gmail.com>", - "" -}; - -/* - * Link essential libvo functions: preinit, config, control, draw_frame, - * draw_slice, draw_osd, flip_page, check_events, uninit and - * the structure info. - */ -const LIBVO_EXTERN(direct3d) - - -/* Global variables "priv" structure. I try to keep their count low. - */ -static struct global_priv { - int is_paused; /**< 1 = Movie is paused, - 0 = Movie is not paused */ - int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect - 0 = (default) Don't clear it */ - D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ - RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed - in fullscreen */ - RECT fs_panscan_rect; /**< PanScan source surface cropping in - fullscreen */ - int src_width; /**< Source (movie) width */ - int src_height; /**< Source (movie) heigth */ - - D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on - the movie's codec) */ - D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. - Usually XRGB */ - LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ - LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ - IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer - renders inside it. Uses colorspace - priv->movie_src_fmt */ - IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to - display next frame) */ -} *priv; - -typedef struct { - const unsigned int mplayer_fmt; /**< Given by MPlayer */ - const D3DFORMAT fourcc; /**< Required by D3D's test function */ -} struct_fmt_table; - -/* Map table from reported MPlayer format to the required - fourcc. This is needed to perform the format query. */ - -static const struct_fmt_table fmt_table[] = { - {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, - {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, - {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, - {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, - {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, - {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')}, -}; - -#define DISPLAY_FORMAT_TABLE_ENTRIES \ - (sizeof(fmt_table) / sizeof(fmt_table[0])) - -/**************************************************************************** - * * - * * - * * - * Direct3D specific implementation functions * - * * - * * - * * - ****************************************************************************/ - -/** @brief Calculate scaled fullscreen movie rectangle with - * preserved aspect ratio. - */ -static void calc_fs_rect(void) -{ - int scaled_height = 0; - int scaled_width = 0; - - // set default values - priv->fs_movie_rect.left = 0; - priv->fs_movie_rect.right = vo_dwidth; - priv->fs_movie_rect.top = 0; - priv->fs_movie_rect.bottom = vo_dheight; - priv->fs_panscan_rect.left = 0; - priv->fs_panscan_rect.right = priv->src_width; - priv->fs_panscan_rect.top = 0; - priv->fs_panscan_rect.bottom = priv->src_height; - if (!vo_fs) return; - - // adjust for fullscreen aspect and panscan - aspect(&scaled_width, &scaled_height, A_ZOOM); - panscan_calc(); - scaled_width += vo_panscan_x; - scaled_height += vo_panscan_y; - - // note: border is rounded to a multiple of two since at least - // ATI drivers can not handle odd values with YV12 input - if (scaled_width > vo_dwidth) { - int border = priv->src_width * (scaled_width - vo_dwidth) / scaled_width; - border = (border / 2 + 1) & ~1; - priv->fs_panscan_rect.left = border; - priv->fs_panscan_rect.right = priv->src_width - border; - } else { - priv->fs_movie_rect.left = (vo_dwidth - scaled_width) / 2; - priv->fs_movie_rect.right = priv->fs_movie_rect.left + scaled_width; - } - if (scaled_height > vo_dheight) { - int border = priv->src_height * (scaled_height - vo_dheight) / scaled_height; - border = (border / 2 + 1) & ~1; - priv->fs_panscan_rect.top = border; - priv->fs_panscan_rect.bottom = priv->src_height - border; - } else { - priv->fs_movie_rect.top = (vo_dheight - scaled_height) / 2; - priv->fs_movie_rect.bottom = priv->fs_movie_rect.top + scaled_height; - } - - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Fullscreen Movie Rect: t: %ld, l: %ld, r: %ld, b:%ld\r\n", - priv->fs_movie_rect.top, priv->fs_movie_rect.left, - priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); - - /* The backbuffer should be cleared before next StretchRect. This is - * necessary because our new draw area could be smaller than the - * previous one used by StretchRect and without it, leftovers from the - * previous frame will be left. */ - priv->is_clear_needed = 1; -} - -/** @brief Destroy D3D Context related to the current window. - */ -static void destroy_d3d_context(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>destroy_d3d_context called\r\n"); - /* Let's destroy the old (if any) D3D Content */ - - if (priv->locked_rect.pBits) { - IDirect3DSurface9_UnlockRect(priv->d3d_surface); - priv->locked_rect.pBits = NULL; - } - - if (priv->d3d_surface != NULL) { - IDirect3DSurface9_Release (priv->d3d_surface); - priv->d3d_surface = NULL; - } - - if (priv->d3d_device != NULL) { - IDirect3DDevice9_Release (priv->d3d_device); - priv->d3d_device = NULL; - } - - /* The following is not a memory leak. d3d_backbuf is not malloc'ed - * but just holds a pointer to the back buffer. Nobody gets hurt from - * setting it to NULL. - */ - priv->d3d_backbuf = NULL; -} - - -/** @brief (Re)Initialize Direct3D. Kill and recreate context. - * The first function called to initialize D3D context. - * @return 1 on success, 0 on failure - */ -static int reconfigure_d3d(void) -{ - D3DPRESENT_PARAMETERS present_params; - D3DDISPLAYMODE disp_mode; - - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); - - destroy_d3d_context(); - - /* Get the current desktop display mode, so we can set up a back buffer - * of the same format. */ - if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, - D3DADAPTER_DEFAULT, - &disp_mode))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>Could not read adapter display mode.\n"); - return 0; - } - - /* Write current Desktop's colorspace format in the global storage. */ - priv->desktop_fmt = disp_mode.Format; - - /* Prepare Direct3D initialization parameters. */ - memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); - present_params.Windowed = TRUE; - present_params.SwapEffect = D3DSWAPEFFECT_COPY; - present_params.Flags = D3DPRESENTFLAG_VIDEO; - present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ - present_params.BackBufferWidth = 0; /* Fill up window Width */ - present_params.BackBufferHeight = 0; /* Fill up window Height */ - present_params.MultiSampleType = D3DMULTISAMPLE_NONE; - /* D3DPRESENT_INTERVAL_ONE = vsync */ - present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; - present_params.BackBufferFormat = priv->desktop_fmt; - present_params.BackBufferCount = 1; - present_params.EnableAutoDepthStencil = FALSE; - - /* vo_w32_window is w32_common variable. It's a handle to the window. */ - if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, vo_w32_window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &present_params, &priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>Could not create the D3D device\n"); - return 0; - } - - mp_msg(MSGT_VO,MSGL_V, - "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", - present_params.BackBufferWidth, present_params.BackBufferHeight, - vo_dwidth, vo_dheight); - - if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( - priv->d3d_device, priv->src_width, priv->src_height, - priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); - return 0; - } - - if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, - D3DBACKBUFFER_TYPE_MONO, - &(priv->d3d_backbuf)))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Back Buffer address get failed\n"); - return 0; - } - - calc_fs_rect(); - - return 1; -} - -/** @brief Uninitialize Direct3D and close the window. - */ -static void uninit_d3d(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>uninit_d3d called\r\n"); - - /* Destroy D3D Context inside the window. */ - destroy_d3d_context(); - - /* Stop the whole D3D. */ - if (NULL != priv->d3d_handle) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Calling IDirect3D9_Release\r\n"); - IDirect3D9_Release(priv->d3d_handle); - } -} - -/** @brief Render a frame on the screen. - * @param mpi mpi structure with the decoded frame inside - * @return VO_TRUE on success, VO_ERROR on failure - */ -static uint32_t render_d3d_frame(mp_image_t *mpi) -{ - /* Uncomment when direct rendering is implemented. - * if (mpi->flags & MP_IMGFLAG_DIRECT) ... - */ - - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - goto skip_upload; - - if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ - draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0); - goto skip_upload; - } - - /* If we're here, then we should lock the rect and copy a packed frame */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Surface lock failure\n"); - return VO_ERROR; - } - } - - memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], - mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); - -skip_upload: - /* This unlock is used for both slice_draw path and render_d3d_frame path. */ - if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface unlock failure\n"); - return VO_ERROR; - } - priv->locked_rect.pBits = NULL; - - if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); - return VO_ERROR; - } - - if (priv->is_clear_needed) { - IDirect3DDevice9_Clear (priv->d3d_device, 0, NULL, - D3DCLEAR_TARGET, 0, 0, 0); - priv->is_clear_needed = 0; - } - - if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, - priv->d3d_surface, - &priv->fs_panscan_rect, - priv->d3d_backbuf, - &priv->fs_movie_rect, - D3DTEXF_LINEAR))) { - mp_msg(MSGT_VO,MSGL_ERR, - "<vo_direct3d>Unable to copy the frame to the back buffer\n"); - return VO_ERROR; - } - - if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); - return VO_ERROR; - } - - return VO_TRUE; -} - - -/** @brief Query if movie colorspace is supported by the HW. - * @return 0 on failure, device capabilities (not probed - * currently) on success. - */ -static int query_format(uint32_t movie_fmt) -{ - int i; - for (i=0; i < DISPLAY_FORMAT_TABLE_ENTRIES; i++) { - if (fmt_table[i].mplayer_fmt == movie_fmt) { - /* Test conversion from Movie colorspace to - * display's target colorspace. */ - if (FAILED(IDirect3D9_CheckDeviceFormatConversion( - priv->d3d_handle, - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - fmt_table[i].fourcc, - priv->desktop_fmt))) { - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Rejected image format: %s\n", - vo_format_name(fmt_table[i].mplayer_fmt)); - return 0; - } - - priv->movie_src_fmt = fmt_table[i].fourcc; - 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); - - } - } - - return 0; -} - -/**************************************************************************** - * * - * * - * * - * libvo Control / Callback functions * - * * - * * - * * - ****************************************************************************/ - - - - -/** @brief libvo Callback: Preinitialize the video card. - * Preinit the hardware just enough to be queried about - * supported formats. - * - * @return 0 on success, -1 on failure - */ - -static int preinit(const char *arg) -{ - D3DDISPLAYMODE disp_mode; - - /* Set to zero all global variables. */ - priv = calloc(1, sizeof (struct global_priv)); - if (!priv) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Not enough memory\r\n"); - return -1; - } - - /* FIXME - > Please use subopt-helper.h for this, see vo_gl.c:preinit for - > an example of how to use it. - */ - - priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); - if (!priv->d3d_handle) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Unable to initialize Direct3D\n"); - return -1; - } - - if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, - D3DADAPTER_DEFAULT, - &disp_mode))) { - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Could not read display mode\n"); - return -1; - } - - /* 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", - disp_mode.Width, disp_mode.Height); - - /* w32_common framework call. Configures window on the screen, gets - * fullscreen dimensions and does other useful stuff. - */ - if (!vo_w32_init()) { - mp_msg(MSGT_VO,MSGL_V,"Unable to configure onscreen window\r\n"); - return -1; - } - - return 0; -} - - - -/** @brief libvo Callback: Handle control requests. - * @return VO_TRUE on success, VO_NOTIMPL when not implemented - */ -static int control(uint32_t request, void *data, ...) -{ - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(*(uint32_t*) data); - case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet. */ - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Direct Rendering request. Not implemented yet\n"); - return VO_NOTIMPL; - case VOCTRL_DRAW_IMAGE: - return render_d3d_frame(data); - case VOCTRL_FULLSCREEN: - vo_w32_fullscreen(); - reconfigure_d3d(); - return VO_TRUE; - case VOCTRL_RESET: - return VO_NOTIMPL; - case VOCTRL_PAUSE: - priv->is_paused = 1; - return VO_TRUE; - case VOCTRL_RESUME: - priv->is_paused = 0; - return VO_TRUE; - case VOCTRL_GUISUPPORT: - return VO_NOTIMPL; - case VOCTRL_SET_EQUALIZER: - return VO_NOTIMPL; - case VOCTRL_GET_EQUALIZER: - return VO_NOTIMPL; - case VOCTRL_ONTOP: - vo_w32_ontop(); - return VO_TRUE; - case VOCTRL_BORDER: - vo_w32_border(); - reconfigure_d3d(); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - w32_update_xinerama_info(); - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - calc_fs_rect (); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - } - return VO_FALSE; -} - -/** @brief libvo Callback: Configre the Direct3D adapter. - * @param width Movie source width - * @param height Movie source height - * @param d_width Screen (destination) width - * @param d_height Screen (destination) height - * @param options Options bitmap - * @param title Window title - * @param format Movie colorspace format (using MPlayer's - * defines, e.g. IMGFMT_YUY2) - * @return 0 on success, VO_ERROR on failure - */ -static int config(uint32_t width, uint32_t height, uint32_t d_width, - uint32_t d_height, uint32_t options, char *title, - uint32_t format) -{ - - priv->src_width = width; - priv->src_height = height; - - /* w32_common framework call. Creates window on the screen with - * the given coordinates. - */ - if (!vo_w32_config(d_width, d_height, options)) { - mp_msg(MSGT_VO,MSGL_V,"Unable to create onscreen window\r\n"); - return VO_ERROR; - } - - if (!reconfigure_d3d()) - return VO_ERROR; - - return 0; /* Success */ -} - -/** @brief libvo Callback: Flip next already drawn frame on the - * screen. - * @return N/A - */ -static void flip_page(void) -{ - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { - mp_msg(MSGT_VO,MSGL_V, - "<vo_direct3d>Video adapter became uncooperative.\n"); - mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Trying to reinitialize it...\n"); - if (!reconfigure_d3d()) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); - return; - } - if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); - return; - } - else - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Video adapter reinitialized.\n"); - - } -} - -/** @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 - */ -static void uninit(void) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Uninitialization\r\n"); - - uninit_d3d(); - vo_w32_uninit(); /* w32_common framework call */ - free (priv); - priv = NULL; -} - -/** @brief libvo Callback: Handles video window events. - * @return N/A - */ -static void check_events(void) -{ - int flags; - /* w32_common framework call. Handles video window events. - * Updates global libvo's vo_dwidth/vo_dheight upon resize - * with the new window width/height. - */ - flags = vo_w32_check_events(); - if (flags & VO_EVENT_RESIZE) - reconfigure_d3d(); - - if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) - flip_page(); -} - -/** @brief libvo Callback: Draw slice - * @return 0 on success - */ -static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) -{ - char *my_src; /**< Pointer to the source image */ - char *dst; /**< Pointer to the destination image */ - int uv_stride; /**< Stride of the U/V planes */ - - /* Lock the offscreen surface if it's not already locked. */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface lock failure\n"); - return VO_FALSE; - } - } - - uv_stride = priv->locked_rect.Pitch / 2; - - /* Copy Y */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * y + x; - my_src=src[0]; - memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); - - w/=2;h/=2;x/=2;y/=2; - - /* Copy U */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src=src[2]; - else - my_src=src[1]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); - - /* Copy V */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * (priv->src_height / 2) + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src=src[1]; - else - my_src=src[2]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); - - return 0; /* Success */ -} - -/** @brief libvo Callback: Unused function - * @return N/A - */ -static int draw_frame(uint8_t *src[]) -{ - mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); - return VO_FALSE; -} +/* + * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <windows.h> +#include <errno.h> +#include <stdio.h> +#include <d3d9.h> +#include "config.h" +#include "video_out.h" +#include "video_out_internal.h" +#include "fastmemcpy.h" +#include "mp_msg.h" +#include "aspect.h" +#include "w32_common.h" +#include "libavutil/common.h" + +static const vo_info_t info = +{ + "Direct3D 9 Renderer", + "direct3d", + "Georgi Petrov (gogothebee) <gogothebee@gmail.com>", + "" +}; + +/* + * Link essential libvo functions: preinit, config, control, draw_frame, + * draw_slice, draw_osd, flip_page, check_events, uninit and + * the structure info. + */ +const LIBVO_EXTERN(direct3d) + + +/* Global variables "priv" structure. I try to keep their count low. + */ +static struct global_priv { + int is_paused; /**< 1 = Movie is paused, + 0 = Movie is not paused */ + int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect + 0 = (default) Don't clear it */ + D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ + RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed + in fullscreen */ + RECT fs_panscan_rect; /**< PanScan source surface cropping in + fullscreen */ + int src_width; /**< Source (movie) width */ + int src_height; /**< Source (movie) heigth */ + + D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on + the movie's codec) */ + D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. + Usually XRGB */ + LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ + LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ + 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 + cant lock a normal texture. Uses RGBA */ + IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to + display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ +} *priv; + +typedef struct { + const unsigned int mplayer_fmt; /**< Given by MPlayer */ + const D3DFORMAT fourcc; /**< Required by D3D's test function */ +} struct_fmt_table; + +/* Map table from reported MPlayer format to the required + fourcc. This is needed to perform the format query. */ + +static const struct_fmt_table fmt_table[] = { + {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, + {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, + {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, + {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, + {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, + {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')}, +}; + +#define DISPLAY_FORMAT_TABLE_ENTRIES \ + (sizeof(fmt_table) / sizeof(fmt_table[0])) + +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] = +{ + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + +extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value); + +/**************************************************************************** + * * + * * + * * + * Direct3D specific implementation functions * + * * + * * + * * + ****************************************************************************/ + +/** @brief Calculate scaled fullscreen movie rectangle with + * preserved aspect ratio. + */ +static void calc_fs_rect(void) +{ + int scaled_height = 0; + int scaled_width = 0; + + // set default values + priv->fs_movie_rect.left = 0; + priv->fs_movie_rect.right = vo_dwidth; + priv->fs_movie_rect.top = 0; + priv->fs_movie_rect.bottom = vo_dheight; + priv->fs_panscan_rect.left = 0; + priv->fs_panscan_rect.right = priv->src_width; + priv->fs_panscan_rect.top = 0; + priv->fs_panscan_rect.bottom = priv->src_height; + if (!vo_fs) return; + + // adjust for fullscreen aspect and panscan + aspect(&scaled_width, &scaled_height, A_ZOOM); + panscan_calc(); + scaled_width += vo_panscan_x; + scaled_height += vo_panscan_y; + + // note: border is rounded to a multiple of two since at least + // ATI drivers can not handle odd values with YV12 input + if (scaled_width > vo_dwidth) { + int border = priv->src_width * (scaled_width - vo_dwidth) / scaled_width; + border = (border / 2 + 1) & ~1; + priv->fs_panscan_rect.left = border; + priv->fs_panscan_rect.right = priv->src_width - border; + } else { + priv->fs_movie_rect.left = (vo_dwidth - scaled_width) / 2; + priv->fs_movie_rect.right = priv->fs_movie_rect.left + scaled_width; + } + if (scaled_height > vo_dheight) { + int border = priv->src_height * (scaled_height - vo_dheight) / scaled_height; + border = (border / 2 + 1) & ~1; + priv->fs_panscan_rect.top = border; + priv->fs_panscan_rect.bottom = priv->src_height - border; + } else { + priv->fs_movie_rect.top = (vo_dheight - scaled_height) / 2; + priv->fs_movie_rect.bottom = priv->fs_movie_rect.top + scaled_height; + } + + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Fullscreen Movie Rect: t: %ld, l: %ld, r: %ld, b:%ld\r\n", + priv->fs_movie_rect.top, priv->fs_movie_rect.left, + priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); + + /* The backbuffer should be cleared before next StretchRect. This is + * necessary because our new draw area could be smaller than the + * previous one used by StretchRect and without it, leftovers from the + * previous frame will be left. */ + priv->is_clear_needed = 1; +} + +/** @brief Destroy D3D Context related to the current window. + */ +static void destroy_d3d_context(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>destroy_d3d_context called\r\n"); + /* Let's destroy the old (if any) D3D Content */ + + if (priv->locked_rect.pBits) { + IDirect3DSurface9_UnlockRect(priv->d3d_surface); + priv->locked_rect.pBits = NULL; + } + + if (priv->d3d_surface != NULL) { + IDirect3DSurface9_Release (priv->d3d_surface); + priv->d3d_surface = NULL; + } + + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + + if (priv->d3d_device != NULL) { + IDirect3DDevice9_Release (priv->d3d_device); + priv->d3d_device = NULL; + } + + /* The following is not a memory leak. d3d_backbuf is not malloc'ed + * but just holds a pointer to the back buffer. Nobody gets hurt from + * setting it to NULL. + */ + priv->d3d_backbuf = NULL; +} + + +/** @brief (Re)Initialize Direct3D. Kill and recreate context. + * The first function called to initialize D3D context. + * @return 1 on success, 0 on failure + */ +static int reconfigure_d3d(void) +{ + D3DPRESENT_PARAMETERS present_params; + D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; + + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); + + destroy_d3d_context(); + + /* Get the current desktop display mode, so we can set up a back buffer + * of the same format. */ + if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, + D3DADAPTER_DEFAULT, + &disp_mode))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>Could not read adapter display mode.\n"); + return 0; + } + + /* Write current Desktop's colorspace format in the global storage. */ + priv->desktop_fmt = disp_mode.Format; + + /* Prepare Direct3D initialization parameters. */ + memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); + present_params.Windowed = TRUE; + present_params.SwapEffect = D3DSWAPEFFECT_COPY; + present_params.Flags = D3DPRESENTFLAG_VIDEO; + present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ + present_params.BackBufferWidth = 0; /* Fill up window Width */ + present_params.BackBufferHeight = 0; /* Fill up window Height */ + present_params.MultiSampleType = D3DMULTISAMPLE_NONE; + /* D3DPRESENT_INTERVAL_ONE = vsync */ + present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; + present_params.BackBufferFormat = priv->desktop_fmt; + present_params.BackBufferCount = 1; + present_params.EnableAutoDepthStencil = FALSE; + + /* vo_w32_window is w32_common variable. It's a handle to the window. */ + if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, vo_w32_window, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &present_params, &priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>Could not create the D3D device\n"); + return 0; + } + + mp_msg(MSGT_VO,MSGL_V, + "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", + present_params.BackBufferWidth, present_params.BackBufferHeight, + vo_dwidth, vo_dheight); + + if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( + priv->d3d_device, priv->src_width, priv->src_height, + priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); + return 0; + } + + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, + D3DBACKBUFFER_TYPE_MONO, + &(priv->d3d_backbuf)))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Back Buffer address get failed\n"); + return 0; + } + + calc_fs_rect(); + + return 1; +} + +/** @brief Uninitialize Direct3D and close the window. + */ +static void uninit_d3d(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>uninit_d3d called\r\n"); + + /* Destroy D3D Context inside the window. */ + destroy_d3d_context(); + + /* Stop the whole D3D. */ + if (NULL != priv->d3d_handle) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Calling IDirect3D9_Release\r\n"); + IDirect3D9_Release(priv->d3d_handle); + } +} + +/** @brief Render a frame on the screen. + * @param mpi mpi structure with the decoded frame inside + * @return VO_TRUE on success, VO_ERROR on failure + */ +static uint32_t render_d3d_frame(mp_image_t *mpi) +{ + /* Uncomment when direct rendering is implemented. + * if (mpi->flags & MP_IMGFLAG_DIRECT) ... + */ + + if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) + goto skip_upload; + + if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ + draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0); + goto skip_upload; + } + + /* If we're here, then we should lock the rect and copy a packed frame */ + if (!priv->locked_rect.pBits) { + if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, + &priv->locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Surface lock failure\n"); + return VO_ERROR; + } + } + + memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], + mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); + +skip_upload: + /* This unlock is used for both slice_draw path and render_d3d_frame path. */ + if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface unlock failure\n"); + return VO_ERROR; + } + priv->locked_rect.pBits = NULL; + + if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); + return VO_ERROR; + } + + if (priv->is_clear_needed) { + IDirect3DDevice9_Clear (priv->d3d_device, 0, NULL, + D3DCLEAR_TARGET, 0, 0, 0); + priv->is_clear_needed = 0; + } + + if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, + priv->d3d_surface, + &priv->fs_panscan_rect, + priv->d3d_backbuf, + &priv->fs_movie_rect, + D3DTEXF_LINEAR))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d>Unable to copy the frame to the back buffer\n"); + return VO_ERROR; + } + + if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return VO_ERROR; + } + + return VO_TRUE; +} + + +/** @brief Query if movie colorspace is supported by the HW. + * @return 0 on failure, device capabilities (not probed + * currently) on success. + */ +static int query_format(uint32_t movie_fmt) +{ + int i; + for (i=0; i < DISPLAY_FORMAT_TABLE_ENTRIES; i++) { + if (fmt_table[i].mplayer_fmt == movie_fmt) { + /* Test conversion from Movie colorspace to + * display's target colorspace. */ + if (FAILED(IDirect3D9_CheckDeviceFormatConversion( + priv->d3d_handle, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + fmt_table[i].fourcc, + priv->desktop_fmt))) { + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Rejected image format: %s\n", + vo_format_name(fmt_table[i].mplayer_fmt)); + return 0; + } + + priv->movie_src_fmt = fmt_table[i].fourcc; + 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); + + } + } + + return 0; +} + +/**************************************************************************** + * * + * * + * * + * libvo Control / Callback functions * + * * + * * + * * + ****************************************************************************/ + + + + +/** @brief libvo Callback: Preinitialize the video card. + * Preinit the hardware just enough to be queried about + * supported formats. + * + * @return 0 on success, -1 on failure + */ + +static int preinit(const char *arg) +{ + D3DDISPLAYMODE disp_mode; + + /* Set to zero all global variables. */ + priv = calloc(1, sizeof (struct global_priv)); + if (!priv) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Not enough memory\r\n"); + return -1; + } + + /* FIXME + > Please use subopt-helper.h for this, see vo_gl.c:preinit for + > an example of how to use it. + */ + + priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); + if (!priv->d3d_handle) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Unable to initialize Direct3D\n"); + return -1; + } + + if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, + D3DADAPTER_DEFAULT, + &disp_mode))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Could not read display mode\n"); + return -1; + } + + /* 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", + disp_mode.Width, disp_mode.Height); + + /* w32_common framework call. Configures window on the screen, gets + * fullscreen dimensions and does other useful stuff. + */ + if (!vo_w32_init()) { + mp_msg(MSGT_VO,MSGL_V,"Unable to configure onscreen window\r\n"); + return -1; + } + + return 0; +} + + + +/** @brief libvo Callback: Handle control requests. + * @return VO_TRUE on success, VO_NOTIMPL when not implemented + */ +static int control(uint32_t request, void *data, ...) +{ + switch (request) { + case VOCTRL_QUERY_FORMAT: + return query_format(*(uint32_t*) data); + case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet. */ + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Direct Rendering request. Not implemented yet\n"); + return VO_NOTIMPL; + case VOCTRL_DRAW_IMAGE: + return render_d3d_frame(data); + case VOCTRL_FULLSCREEN: + vo_w32_fullscreen(); + reconfigure_d3d(); + return VO_TRUE; + case VOCTRL_RESET: + return VO_NOTIMPL; + case VOCTRL_PAUSE: + priv->is_paused = 1; + return VO_TRUE; + case VOCTRL_RESUME: + priv->is_paused = 0; + return VO_TRUE; + case VOCTRL_GUISUPPORT: + return VO_NOTIMPL; + case VOCTRL_SET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_GET_EQUALIZER: + return VO_NOTIMPL; + case VOCTRL_ONTOP: + vo_w32_ontop(); + return VO_TRUE; + case VOCTRL_BORDER: + vo_w32_border(); + reconfigure_d3d(); + return VO_TRUE; + case VOCTRL_UPDATE_SCREENINFO: + w32_update_xinerama_info(); + return VO_TRUE; + case VOCTRL_SET_PANSCAN: + calc_fs_rect (); + return VO_TRUE; + case VOCTRL_GET_PANSCAN: + return VO_TRUE; + } + return VO_FALSE; +} + +/** @brief libvo Callback: Configre the Direct3D adapter. + * @param width Movie source width + * @param height Movie source height + * @param d_width Screen (destination) width + * @param d_height Screen (destination) height + * @param options Options bitmap + * @param title Window title + * @param format Movie colorspace format (using MPlayer's + * defines, e.g. IMGFMT_YUY2) + * @return 0 on success, VO_ERROR on failure + */ +static int config(uint32_t width, uint32_t height, uint32_t d_width, + uint32_t d_height, uint32_t options, char *title, + uint32_t format) +{ + + priv->src_width = width; + priv->src_height = height; + + /* w32_common framework call. Creates window on the screen with + * the given coordinates. + */ + if (!vo_w32_config(d_width, d_height, options)) { + mp_msg(MSGT_VO,MSGL_V,"Unable to create onscreen window\r\n"); + return VO_ERROR; + } + + if (!reconfigure_d3d()) + return VO_ERROR; + + return 0; /* Success */ +} + +/** @brief libvo Callback: Flip next already drawn frame on the + * screen. + * @return N/A + */ +static void flip_page(void) +{ + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + mp_msg(MSGT_VO,MSGL_V, + "<vo_direct3d>Video adapter became uncooperative.\n"); + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Trying to reinitialize it...\n"); + if (!reconfigure_d3d()) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); + return; + } + if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); + return; + } + else + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Video adapter reinitialized.\n"); + + } +} + +/** @brief libvo Callback: Uninitializes all pointers and closes + * all D3D related stuff, + * @return N/A + */ +static void uninit(void) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Uninitialization\r\n"); + + uninit_d3d(); + vo_w32_uninit(); /* w32_common framework call */ + free (priv); + priv = NULL; +} + +/** @brief libvo Callback: Handles video window events. + * @return N/A + */ +static void check_events(void) +{ + int flags; + /* w32_common framework call. Handles video window events. + * Updates global libvo's vo_dwidth/vo_dheight upon resize + * with the new window width/height. + */ + flags = vo_w32_check_events(); + if (flags & VO_EVENT_RESIZE) + reconfigure_d3d(); + + if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) + flip_page(); +} + +/** @brief libvo Callback: Draw slice + * @return 0 on success + */ +static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) +{ + char *my_src; /**< Pointer to the source image */ + char *dst; /**< Pointer to the destination image */ + int uv_stride; /**< Stride of the U/V planes */ + + /* Lock the offscreen surface if it's not already locked. */ + if (!priv->locked_rect.pBits) { + if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, + &priv->locked_rect, NULL, 0))) { + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface lock failure\n"); + return VO_FALSE; + } + } + + uv_stride = priv->locked_rect.Pitch / 2; + + /* Copy Y */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * y + x; + my_src=src[0]; + memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); + + w/=2;h/=2;x/=2;y/=2; + + /* Copy U */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * priv->src_height + + uv_stride * y + x; + if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) + my_src=src[2]; + else + my_src=src[1]; + + memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); + + /* Copy V */ + dst = priv->locked_rect.pBits; + dst = dst + priv->locked_rect.Pitch * priv->src_height + + uv_stride * (priv->src_height / 2) + uv_stride * y + x; + if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) + my_src=src[1]; + else + my_src=src[2]; + + memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); + + return 0; /* Success */ +} + +/** @brief libvo Callback: Unused function + * @return N/A + */ +static int draw_frame(uint8_t *src[]) +{ + mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); + return VO_FALSE; +} + + +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++){ + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0;x<w;x++){ + if(srca[x]) + dst[x]=(srca[x] << 8) | src[x]; + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + int x, y; + // calculate a width and height based on the OSD_TEXTURE_SIZE + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y = 0; y < OSD_TEXTURE_SIZE; y++) + { + unsigned short * dst = (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x = 0; x < OSD_TEXTURE_SIZE; x++) + { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) + { + 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_SRCBLEND, D3DBLEND_BLENDFACTOR); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + + } +}
Huh, just a side note - why does this patch seems so broken? You exclude the whole file and then include yours... See all the minuses in the beginning of the patch and then all pluses at the end. Your patch doesn't just exclude/include "in-place"... Also - you use tabs everywhere... This file originally uses 4 spaces instead of a tab... I can fix it myself, but right now the patch is unreadable because of the "whole file exclude and then include".
On Wed, 26 Nov 2008 00:26:37 +0000, Jim Hauxwell wrote:
Sorry,
Ignore the last one, I had forgotten to change the alpha test, the GPU would have been doing more work than it needed.
[diff8.diff text/plain (56.1KB)] Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -1,668 +1,895 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * This file is part of MPlayer.
still a bad patch, maybe you got diff order wrong or forgot something ? -compn
On Wed, Nov 26, 2008 at 12:26:37AM +0000, Jim Hauxwell wrote:
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -1,668 +1,895 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +/* + * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */
This patch is broken and does not apply. I suspect Windows linebreaks. Diego
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 12:26:37AM +0000, Jim Hauxwell wrote:
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -1,668 +1,895 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +/* + * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */
This patch is broken and does not apply. I suspect Windows linebreaks.
Diego
Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account. New, smaller patch file 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 iEYEARECAAYFAkktASIACgkQhrNWoHjgI1DZ7gCdHXix/HtFzJTbJlJchE7EY6ml J00AnjSskO/BoWsHCtxx9eiScK5/qAKX =A++o -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -95,6 +101,27 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] = +{ + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + +extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value); + /**************************************************************************** * * * * @@ -180,6 +207,25 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -201,6 +247,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -258,6 +306,55 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -382,7 +479,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); } } @@ -566,13 +663,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 @@ -666,3 +756,140 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + + +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++){ + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0;x<w;x++){ + if(srca[x]) + dst[x]=(srca[x] << 8) | src[x]; + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + int x, y; + // calculate a width and height based on the OSD_TEXTURE_SIZE + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y = 0; y < OSD_TEXTURE_SIZE; y++) + { + unsigned short * dst = (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x = 0; x < OSD_TEXTURE_SIZE; x++) + { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) + { + 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_SRCBLEND, D3DBLEND_BLENDFACTOR); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + + } +}
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks.
Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */
Do not add tabs to a file without tabs
@@ -95,6 +101,27 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0]))
+#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] =
trailing whitespace
+extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value);
You need to #include the appropriate header, not add extern declarations all over the file.
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + {
Respect the coding style of the file, keep braces on the same line as the if.
@@ -666,3 +756,140 @@ + + +void vo_draw_alpha_l8a8(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride)
Please break long lines.
+{ + int y; + for(y=0;y<h;y++){
Again, respect the surrounding coding style. Diego
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */
Do not add tabs to a file without tabs
Done
@@ -95,6 +101,27 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0]))
+#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 // as this is a texture, it can be a different size to the movie + +typedef struct vertex_s +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} vertex_t; + +vertex_t osd_quad_vb[] =
trailing whitespace
Done
+extern void vo_draw_text(int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)); +extern int vo_osd_changed(int new_value);
You need to #include the appropriate header, not add extern declarations all over the file.
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + {
Respect the coding style of the file, keep braces on the same line as the if.
Done
@@ -666,3 +756,140 @@ + + +void vo_draw_alpha_l8a8(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride)
Please break long lines.
Done
+{ + int y; + for(y=0;y<h;y++){
Again, respect the surrounding coding style.
Done
Diego _______________________________________________ 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 iEYEARECAAYFAkktotEACgkQhrNWoHjgI1AkFwCdHeD3lx24kT+MMy1QC4gwfFip rzIAoLSCbxRsdpNoETqEaxDW8bu/E8D5 =N+Xe -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28042) +++ 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,14 @@ 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 + cant lock a normal texture. Uses RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -101,6 +108,22 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +vertex_t osd_quad_vb[] = { + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + /**************************************************************************** * * * * @@ -186,6 +209,25 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -207,6 +249,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -264,6 +308,50 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -388,7 +476,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); } } @@ -572,13 +660,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 @@ -672,3 +753,133 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + + +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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x]) + dst[x]=((srca[x]-1) << 8) | src[x]; + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + int x, y; + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y=0; y < OSD_TEXTURE_SIZE; y++) { + unsigned short * dst = + (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x=0; x < OSD_TEXTURE_SIZE; x++) { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
On Wed, Nov 26, 2008 at 07:26:10PM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */
Do not add tabs to a file without tabs
Done
No.
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + {
Respect the coding style of the file, keep braces on the same line as the if.
Done
No.
--- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +72,14 @@ + IDirect3DTexture9 *d3d_texture_osd; /**< Direct3D Texture. Uses RGBA */ + IDirect3DTexture9 *d3d_texture_system; /**< Direct3D Texture. System memory + cant lock a normal texture. Uses RGBA */
cannot
@@ -101,6 +108,22 @@
+#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */
than the movie
@@ -264,6 +308,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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");
random indentation, same below
+ memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) );
No other function call in the file has spaces around the parentheses.
+ /* populate the Y with the correct coordinate */
"the Y"?
@@ -672,3 +753,133 @@ + + for (y=0; y < h; y++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x])
You have spaces after if and for in other places.
+ src+=srcstride; + srca+=srcstride; + dstbase+=dststride;
This would be more readable aligned and with spaces around the operators.
+ if (FAILED (IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) {
random indentation
+ if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return;
3 space indentation Diego
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:26:10PM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */ Do not add tabs to a file without tabs Done
No.
Should now be no tabs
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + { Respect the coding style of the file, keep braces on the same line as the if. Done
No.
Again, I don't know how those slipped through
--- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +72,14 @@ + IDirect3DTexture9 *d3d_texture_osd; /**< Direct3D Texture. Uses RGBA */ + IDirect3DTexture9 *d3d_texture_system; /**< Direct3D Texture. System memory + cant lock a normal texture. Uses RGBA */
cannot
spelling!!! arrrgg
@@ -101,6 +108,22 @@
+#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */
than the movie
@@ -264,6 +308,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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");
random indentation, same below
I've altered it, but I just copied mine from the if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( priv->d3d_device, priv->src_width, priv->src_height, priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); return 0; } which is already in svn. To your case this has broken indentation.
+ memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) );
No other function call in the file has spaces around the parentheses.
Fixed
+ /* populate the Y with the correct coordinate */
"the Y"?
@@ -672,3 +753,133 @@ + + for (y=0; y < h; y++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x])
You have spaces after if and for in other places.
+ src+=srcstride; + srca+=srcstride; + dstbase+=dststride;
fixed
This would be more readable aligned and with spaces around the operators.
+ if (FAILED (IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) {
random indentation
fixed
+ if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return;
3 space indentation
A cut and paste from the other place lock is used. That has also got a 3 space indentation and made it into svn by mistake.
Diego _______________________________________________ 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 iEYEARECAAYFAkkvrJgACgkQhrNWoHjgI1AEuwCfVqkpqeSXKhG+WEoWlkc1cePB fIUAn2iVRSXK0dNBj+A6YGuzQJN9o6J8 =jBI/ -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -22,6 +22,7 @@ #include <errno.h> #include <stdio.h> #include <d3d9.h> +#include <mmintrin.h> #include "config.h" #include "video_out.h" #include "video_out_internal.h" @@ -30,6 +31,7 @@ #include "aspect.h" #include "w32_common.h" #include "libavutil/common.h" +#include "sub.h" static const vo_info_t info = { @@ -71,8 +73,14 @@ 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) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -101,6 +109,23 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size to the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +vertex_t osd_quad_vb[] = { + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + /**************************************************************************** * * * * @@ -186,6 +211,22 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -207,6 +248,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -264,6 +307,50 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy(vertices, osd_quad_vb, sizeof(osd_quad_vb)); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -388,7 +475,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); } } @@ -572,13 +659,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 @@ -672,3 +752,139 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + +/** @brief Maps mplayer alpha to D3D + * 0x0 -> 0xFF is handled already in the clear + * 0x1 -> 0x00 to become opaque + * other alphas reduce by one + */ +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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for (x=0; x < w; x++) { + if (srca[x]) + dst[x] = ((srca[x]-1) << 8) | src[x]; + } + src += srcstride; + srca += srcstride; + dstbase += dststride; + } + return; +} + +/** @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, + (void *)((unsigned int)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) +{ + int x, y; + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + if (vo_osd_changed(0)) { + const __m64 fp = _mm_set1_pi16(0xFF00); + 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; + } + + for (y=0; y < OSD_TEXTURE_SIZE; y++) { + unsigned short * dst = + (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x=0; x < OSD_TEXTURE_SIZE; x++) { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:26:10PM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */ Do not add tabs to a file without tabs Done No.
Should now be no tabs
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + { Respect the coding style of the file, keep braces on the same line as the if. Done No.
Again, I don't know how those slipped through
--- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +72,14 @@ + IDirect3DTexture9 *d3d_texture_osd; /**< Direct3D Texture. Uses RGBA */ + IDirect3DTexture9 *d3d_texture_system; /**< Direct3D Texture. System memory + cant lock a normal texture. Uses RGBA */ cannot
spelling!!! arrrgg
@@ -101,6 +108,22 @@
+#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */ than the movie
@@ -264,6 +308,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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"); random indentation, same below
I've altered it, but I just copied mine from the
if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( priv->d3d_device, priv->src_width, priv->src_height, priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); return 0; }
which is already in svn. To your case this has broken indentation.
+ memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); No other function call in the file has spaces around the parentheses.
Fixed
+ /* populate the Y with the correct coordinate */ "the Y"?
@@ -672,3 +753,133 @@ + + for (y=0; y < h; y++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x]) You have spaces after if and for in other places.
+ src+=srcstride; + srca+=srcstride; + dstbase+=dststride;
fixed
This would be more readable aligned and with spaces around the operators.
+ if (FAILED (IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) { random indentation
fixed
+ if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return; 3 space indentation
A cut and paste from the other place lock is used. That has also got a 3 space indentation and made it into svn by mistake.
Diego _______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
Sorry, Disregard, last one. It had one line from an experiment I was working on, in it. Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkkvrp4ACgkQhrNWoHjgI1BMtgCfR+Nlx9j5IpIYlwBhefwHD51Y giEAnjfj2XAlMjFVBH2FXyuGg419kA/t =sE95 -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -22,6 +22,7 @@ #include <errno.h> #include <stdio.h> #include <d3d9.h> +#include <mmintrin.h> #include "config.h" #include "video_out.h" #include "video_out_internal.h" @@ -30,6 +31,7 @@ #include "aspect.h" #include "w32_common.h" #include "libavutil/common.h" +#include "sub.h" static const vo_info_t info = { @@ -71,8 +73,14 @@ 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) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -101,6 +109,23 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size to the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +vertex_t osd_quad_vb[] = { + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + /**************************************************************************** * * * * @@ -186,6 +211,22 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -207,6 +248,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -264,6 +307,50 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy(vertices, osd_quad_vb, sizeof(osd_quad_vb)); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -388,7 +475,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); } } @@ -572,13 +659,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 @@ -672,3 +752,138 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + +/** @brief Maps mplayer alpha to D3D + * 0x0 -> 0xFF is handled already in the clear + * 0x1 -> 0x00 to become opaque + * other alphas reduce by one + */ +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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for (x=0; x < w; x++) { + if (srca[x]) + dst[x] = ((srca[x]-1) << 8) | src[x]; + } + src += srcstride; + srca += srcstride; + dstbase += dststride; + } + return; +} + +/** @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, + (void *)((unsigned int)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) +{ + int x, y; + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y=0; y < OSD_TEXTURE_SIZE; y++) { + unsigned short * dst = + (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x=0; x < OSD_TEXTURE_SIZE; x++) { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jim Hauxwell wrote:
Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:26:10PM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
> This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
--- libvo/vo_direct3d.c (revision 28034) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +71,14 @@ 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 + cant lock a normal texture. Uses RGBA */ Do not add tabs to a file without tabs Done No. Should now be no tabs
@@ -180,6 +207,25 @@ + /* kill the VB and the texture */ + if (priv->d3d_texture_osd != NULL) + { Respect the coding style of the file, keep braces on the same line as the if. Done No. Again, I don't know how those slipped through
--- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +72,14 @@ + IDirect3DTexture9 *d3d_texture_osd; /**< Direct3D Texture. Uses RGBA */ + IDirect3DTexture9 *d3d_texture_system; /**< Direct3D Texture. System memory + cant lock a normal texture. Uses RGBA */ cannot spelling!!! arrrgg
@@ -101,6 +108,22 @@
+#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */ than the movie @@ -264,6 +308,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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"); random indentation, same below I've altered it, but I just copied mine from the
if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( priv->d3d_device, priv->src_width, priv->src_height, priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); return 0; }
which is already in svn. To your case this has broken indentation.
+ memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); No other function call in the file has spaces around the parentheses. Fixed
+ /* populate the Y with the correct coordinate */ "the Y"? @@ -672,3 +753,133 @@ + + for (y=0; y < h; y++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x]) You have spaces after if and for in other places. + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; fixed
This would be more readable aligned and with spaces around the operators.
+ if (FAILED (IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) { random indentation fixed
+ if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return; 3 space indentation A cut and paste from the other place lock is used. That has also got a 3 space indentation and made it into svn by mistake.
Diego _______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
Sorry,
Disregard, last one. It had one line from an experiment I was working on, in it.
Jim
And again, another line slipped through. That's the problem when I've already started on some other improvements. 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 iEYEARECAAYFAkkvr6QACgkQhrNWoHjgI1DsbQCgwQhbPZhlSCywHWKBBsNo0H7Z IFUAoI36L3IvELQvnVtxnHJg+AfnPKHH =zRmD -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28042) +++ 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,14 @@ 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) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -101,6 +108,23 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size to the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +vertex_t osd_quad_vb[] = { + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + /**************************************************************************** * * * * @@ -186,6 +210,22 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -207,6 +247,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -264,6 +306,50 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy(vertices, osd_quad_vb, sizeof(osd_quad_vb)); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -388,7 +474,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); } } @@ -572,13 +658,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 @@ -672,3 +751,138 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + +/** @brief Maps mplayer alpha to D3D + * 0x0 -> 0xFF is handled already in the clear + * 0x1 -> 0x00 to become opaque + * other alphas reduce by one + */ +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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for (x=0; x < w; x++) { + if (srca[x]) + dst[x] = ((srca[x]-1) << 8) | src[x]; + } + src += srcstride; + srca += srcstride; + dstbase += dststride; + } + return; +} + +/** @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, + (void *)((unsigned int)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) +{ + int x, y; + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y=0; y < OSD_TEXTURE_SIZE; y++) { + unsigned short * dst = + (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x=0; x < OSD_TEXTURE_SIZE; x++) { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
On Fri, Nov 28, 2008 at 08:45:24AM +0000, Jim Hauxwell wrote:
And again, another line slipped through. That's the problem when I've already started on some other improvements.
--- libvo/vo_direct3d.c (revision 28042) +++ libvo/vo_direct3d.c (working copy) @@ -71,8 +72,14 @@ + int is_osd_populated; /* has the OSD something on it */
That sounds Engrish. Are you a native speaker?
@@ -101,6 +108,23 @@ + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size to the movie */
I repeat: "than the movie".
@@ -264,6 +306,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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");
Please adapt your coding style to the rest of the file, i.e. no space between function name and opening parenthesis, space after the comma that separates function arguments, no random indentation. I already fixed the rest of the file.
+ memcpy(vertices, osd_quad_vb, sizeof(osd_quad_vb)); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */
I repeat: What is "the Y" supposed to mean?
@@ -672,3 +751,138 @@ + +/** @brief Maps mplayer alpha to D3D
MPlayer
+ * other alphas reduce by one
alpha channels?
+ for (y=0; y < h; y++) { + for (x=0; x < w; x++) {
Please put spaces around the =, same below.
+ src += srcstride; + srca += srcstride; + dstbase += dststride;
This could be aligned.
+ if (FAILED (IDirect3DTexture9_LockRect(priv->d3d_texture_system, 0, + &locked_rect, NULL, 0))) {
indentation Diego
Hello, I do not like the design with the intermediate textures, also since its current implementation squishes the OSD weirdly (try -aspect 3 or -aspect 0.5), but I leave that for Georgi to decide.
+ void *vertices = NULL;
Just give it the right type (vertex_t *) instead of casting it several times later.
+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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for (x=0; x < w; x++) { + if (srca[x]) + dst[x] = ((srca[x]-1) << 8) | src[x]; + }
Using D3DBLEND_INVSRCALPHA and -srca[x] would mean 1) You can use memset again in draw_osd, which particularly on x64 will be assembler-optimized and much faster 2) You can leave the "if (srca[x])" out which particularly on P4 systems is likely to be faster (you will not save memory bandwidth most of the time, you'd need 32 consecutive pixels to be transparent to save any thing at all due to the cache).
+ return; +}
That return is quite pointless.
+ vo_draw_alpha_l8a8(w,h,src,srca,stride, + (void *)((unsigned int)locked_rect.pBits+locked_rect.Pitch*y0+2*x0), locked_rect.Pitch);
NEVER EVER CAST a POINTER to INT! This will break on Windows x64. While I am not yet able to build MPlayer for x64, this is only a matter of time. Not to mention that casting to char* has exactly the same effect and you need one cast less overall.
+ /* need to use a texture here */ + 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 );
I guess these one could just be set right at initialization, seems likely the will be appropriate for all cases.
+ IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 );
I know that is the recommended way, but I think it would be simpler to just use DrawPrimitiveUP here... On the "opposite" side, just using D3DPT_TRIANGLESTRIP would only need swapping two vertexes and continue to work if someone ever wants to use D3D10... (opposite because I think DrawPrimitiveUP will not be available in D3D10). Greetings, Reimar Doeffinger
Everything is ok with me as long as we accept at least initial implementation, which is coded reasonably good. I want to understand what's going on and improve on top of it. I think that it's better to have at least the subtitles showing on the screen compared to nothing. Later we can always improve Jim's work if it needs to be improved. So - Jim, you've almost cleared your code. When the patch is accepted, I will begin to ask questions how to make everything work good :)
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Everything is ok with me as long as we accept at least initial implementation, which is coded reasonably good. I want to understand what's going on and improve on top of it. I think that it's better to have at least the subtitles showing on the screen compared to nothing. Later we can always improve Jim's work if it needs to be improved.
So - Jim, you've almost cleared your code. When the patch is accepted, I will begin to ask questions how to make everything work good :) _______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
Hi, I hope this is OK now. 1) I've moved back to a memset 0, and used D3DRS_SRCBLEND, D3DBLEND_ONE D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA as the source/dest filters 2) moved to use a triangle strip rather than a fan 3) took the comments about the setup of the blending, but I think it's clearer to do this stuff together. It should have very little cost (some api overhead) as most drivers will detect when you are trying to set the same state as the previous value. 4) Should have all the random spaces removed to match what was cleaned in svn this afternoon. 5) the vertex_t casting has been changed, the pointer is now a vertex_t, but the reason it didn't make any difference is that I now have to cast to (void *) in two places. That should be it (I hope) P.S. Are you using a tool of some sort to spot tab->space etc formatting issues in the patch? (or just your eyes) Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkkwKSkACgkQhrNWoHjgI1Di0gCgm6DyZC4KERXOWcAG1gVP969v /qEAoJMNCEUBIzB12nm02QpUGgspdo1r =7fHQ -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28047) +++ 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,15 @@ 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) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /**< 1 = OSD texture has something to display, + 0 = OSD texture is clear */ } *priv; typedef struct { @@ -100,6 +108,23 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size than the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +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 } +}; + /**************************************************************************** * * * * @@ -185,6 +210,22 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) { + IDirect3DVertexBuffer9_Release(priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release(priv->d3d_device); priv->d3d_device = NULL; @@ -206,6 +247,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + vertex_t *vertices = NULL; + float aspect; mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -267,6 +310,68 @@ return 0; } + /* create OSD */ + if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, + OSD_TEXTURE_SIZE, + OSD_TEXTURE_SIZE, + 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, + OSD_TEXTURE_SIZE, + OSD_TEXTURE_SIZE, + 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; + } + + if (FAILED(IDirect3DDevice9_CreateVertexBuffer(priv->d3d_device, + sizeof(osd_quad_vb), + 0, + D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, + &priv->d3d_quad_vb, + NULL))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED(IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, + 0, sizeof(osd_quad_vb), + (void *)&vertices, + 0))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy((void *)vertices, osd_quad_vb, sizeof(osd_quad_vb)); + aspect = (float)priv->src_width / priv->src_height; + /* populate the v texture coordinate */ + vertices[2].tv = + vertices[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED(IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -389,7 +494,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); } } @@ -573,13 +678,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 @@ -676,3 +774,130 @@ 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 + * 0x0 -> 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, + (void *)((unsigned int)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) +{ + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + memset(locked_rect.pBits, 0, (locked_rect.Pitch * OSD_TEXTURE_SIZE)); + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0x0); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + 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); + + /* need to use a texture here */ + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t)); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLESTRIP, 0, 2); + + /* 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; + } + } +}
On Fri, Nov 28, 2008 at 05:23:53PM +0000, Jim Hauxwell wrote:
3)
took the comments about the setup of the blending, but I think it's clearer to do this stuff together. It should have very little cost (some api overhead) as most drivers will detect when you are trying to set the same state as the previous value.
That wasn't a performance point, I just would consider setting variables that never change and make sense for all the rendering (even taking into account future development) part of the "setup", and not of the OSD rendering. Not that it really matters.
5)
the vertex_t casting has been changed, the pointer is now a vertex_t, but the reason it didn't make any difference is that I now have to cast to (void *) in two places.
No, you do not have to cast it at all. The cast in the function call is a good idea since it suppresses a warning, the one in the memcpy is just pointless. You don't like DrawPrimitiveUP? It would get rid of all that code...
That should be it (I hope)
Casting pointers to int is still there. Also there is the issue that Clear needs to be called for fullscreen. I'd really suggest to call Clear always when in fullscreen mode, since it makes _no_ performance difference at all, neither under Linux/Wine with an Intel 945 nor on my desktop system, but Georgi said it caused issues for him...
P.S. Are you using a tool of some sort to spot tab->space etc formatting issues in the patch? (or just your eyes)
View the patch with diff and vi, when it uses spaces it will look just horrible in at least one of them. You could just set the tab width in you favourite editor to 32 and you will notice it very quickly, too...
+vertex_t osd_quad_vb[] = {
This should be static const btw...
Casting pointers to int is still there. Also there is the issue that Clear needs to be called for fullscreen. I'd really suggest to call Clear always when in fullscreen mode, since it makes _no_ performance difference at all, neither under Linux/Wine with an Intel 945 nor on my desktop system, but Georgi said it caused issues for him...
Huh, what issues? I don't have any. If I wrote something like that, I was probably drunk :) :) :) No, really - right now we do a Clear in render_d3d_frame() when priv->is_clear_needed is set. And it's set after each recalculation of stretchrect's in/out rects (which includes going to/coming back from fullscreen).
Oh, I remember - Clear was slow if done like every frame. Doing Clear once in a while doesn't hurt. But - don't call it TOO often...
On Fri, Nov 28, 2008 at 08:57:27PM +0200, Georgi Petrov wrote:
Oh, I remember - Clear was slow if done like every frame. Doing Clear once in a while doesn't hurt. But - don't call it TOO often...
Yes, that is what confuses me. I was proposing to call it every frame, because it makes not difference in performance _at all_ (well, definitely < 0.1 %) for me. I wonder why it is problematic for you. Fixing the OSD would be a real pain without that change (well, I just realize it is enough to "only" do priv->is_clear_needed |= vo_fs; in draw_osd inside the if (priv->is_osd_populated) - still than means every frame when in fullscreen and OSD is shown).
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Fri, Nov 28, 2008 at 08:57:27PM +0200, Georgi Petrov wrote:
Oh, I remember - Clear was slow if done like every frame. Doing Clear once in a while doesn't hurt. But - don't call it TOO often...
Yes, that is what confuses me. I was proposing to call it every frame, because it makes not difference in performance _at all_ (well, definitely < 0.1 %) for me. I wonder why it is problematic for you. Fixing the OSD would be a real pain without that change (well, I just realize it is enough to "only" do priv->is_clear_needed |= vo_fs; in draw_osd inside the if (priv->is_osd_populated) - still than means every frame when in fullscreen and OSD is shown).
Reimar, OK, I see the issue, when the OSD is not over the stretchblit 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 iEYEARECAAYFAkkwR6EACgkQhrNWoHjgI1CrIACfX4mMowSXhvkFpjCf3pKFDTC6 O9gAoLJ3MCMQwJB2P7biedtCQfD0x39+ =lW4m -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jim Hauxwell wrote:
Oh, I remember - Clear was slow if done like every frame. Doing Clear once in a while doesn't hurt. But - don't call it TOO often... Yes, that is what confuses me. I was proposing to call it every frame, because it makes not difference in performance _at all_ (well, definitely < 0.1 %) for me. I wonder why it is problematic for you. Fixing the OSD would be a real pain without that change (well, I just realize it is enough to "only" do
On Fri, Nov 28, 2008 at 08:57:27PM +0200, Georgi Petrov wrote: priv->is_clear_needed |= vo_fs; in draw_osd inside the if (priv->is_osd_populated) - still than means every frame when in fullscreen and OSD is shown).
Reimar,
OK, I see the issue,
when the OSD is not over the stretchblit
Jim
_______________________________________________ MPlayer-dev-eng mailing list MPlayer-dev-eng@mplayerhq.hu https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
What about replacing Clear with ColorFill for OSD when the stretchblit doesn't match the screen size? 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 iEYEARECAAYFAkkwSacACgkQhrNWoHjgI1AP2wCeMDbtogKmrgfR4SPVqq+CgNR2 d18AnjzXGJTV027iKUPyp3vNwh8TGxb8 =u7UO -----END PGP SIGNATURE-----
I'm lost. Why don't we execute Clear only when OSD comes/goes out of view? What's the difference if we do Clear each frame compared to not doing Clear each frame when we have OSD on the screen? Clear *have* negative performance effect on nVidia Geforce 7600GS - that's for sure. When disabling v_sync and launching MPlayer with -benchmark -nosound, Clear on each frame has about 20% penalty on my HW, which is way too much for me.
Disabled VSYNC ./mplayer.exe -vo direct3d -benchmark -nosound -frames 2000 -fs /4panasonic.ts Normal: 22.236s Clear always on: 23.275s Hmm, the difference is smaller this time. I don't know why. Anyways this is 5%... Not 20% as before, but 5%... Do we NEED it?
On Fri, Nov 28, 2008 at 09:49:31PM +0200, Georgi Petrov wrote:
I'm lost. Why don't we execute Clear only when OSD comes/goes out of view?
Plus whenever the OSD changes, before it changes (when it becomes visible it is not a problem though).
What's the difference if we do Clear each frame compared to not doing Clear each frame when we have OSD on the screen?
I don't understand what you ask here. Anyway, my suggestion was to always call Clear when there is an OSD and we are in fullscreen. It seems like an acceptable compromise, compared to rendering the OSD even the 5% you measured of the Clear should not matter much IMO...
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Fri, Nov 28, 2008 at 05:23:53PM +0000, Jim Hauxwell wrote:
3)
took the comments about the setup of the blending, but I think it's clearer to do this stuff together. It should have very little cost (some api overhead) as most drivers will detect when you are trying to set the same state as the previous value.
That wasn't a performance point, I just would consider setting variables that never change and make sense for all the rendering (even taking into account future development) part of the "setup", and not of the OSD rendering. Not that it really matters.
it was done for clarity, this way if the device is lost, it will always have the correct setup. The code could move to the device creation, but I wanted to keep it together.
5)
the vertex_t casting has been changed, the pointer is now a vertex_t, but the reason it didn't make any difference is that I now have to cast to (void *) in two places.
No, you do not have to cast it at all. The cast in the function call is a good idea since it suppresses a warning, the one in the memcpy is just pointless. You don't like DrawPrimitiveUP? It would get rid of all that code...
Moved to DrawPrimitiveUP, got rid of the code.
That should be it (I hope)
Casting pointers to int is still there. Also there is the issue that Clear needs to be called for fullscreen. I'd really suggest to call Clear always when in fullscreen mode, since it makes _no_ performance difference at all, neither under Linux/Wine with an Intel 945 nor on my desktop system, but Georgi said it caused issues for him...
Yeh, I missed one, changed. What's the issue for clear?
P.S. Are you using a tool of some sort to spot tab->space etc formatting issues in the patch? (or just your eyes)
View the patch with diff and vi, when it uses spaces it will look just horrible in at least one of them. You could just set the tab width in you favourite editor to 32 and you will notice it very quickly, too...
+vertex_t osd_quad_vb[] = {
gone anyway now
This should be static const btw... _______________________________________________ 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 iEYEARECAAYFAkkwRrkACgkQhrNWoHjgI1BJFQCeJWC98oXyCY8WAExgJl6xVHzd fZMAnRE1KPErurd2Pdo++jRhWu+Jl8N8 =JQ9h -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28047) +++ 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,13 @@ 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 */ } *priv; typedef struct { @@ -100,6 +106,16 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be + a different size than the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + /**************************************************************************** * * * * @@ -185,6 +201,17 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_device != NULL) { IDirect3DDevice9_Release(priv->d3d_device); priv->d3d_device = NULL; @@ -267,6 +294,35 @@ return 0; } + /* create OSD */ + if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, + OSD_TEXTURE_SIZE, + OSD_TEXTURE_SIZE, + 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, + OSD_TEXTURE_SIZE, + OSD_TEXTURE_SIZE, + 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; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -389,7 +445,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); } } @@ -573,13 +629,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 @@ -676,3 +725,145 @@ 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 + * 0x0 -> 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, + (void *)((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) +{ + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + memset(locked_rect.pBits, 0, (locked_rect.Pitch * OSD_TEXTURE_SIZE)); + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + float aspect; + + 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 } + }; + + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_GREATER); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0x0); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + 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); + + /* need to use a texture here */ + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + + aspect = (float)priv->src_width / priv->src_height; + /* populate the v texture coordinate */ + osd_quad_vb[2].tv = + osd_quad_vb[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + 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; + } + } +}
+/** @brief Maps MPlayer alpha to D3D + * 0x0 -> transparent and discarded by alpha test + * 0x0 -> 0xFF to become opaque
You mean 0x00 and 0x01?
+ vo_draw_alpha_l8a8(w,h,src,srca,stride, + (void *)((char *)locked_rect.pBits+locked_rect.Pitch*y0+2*x0), locked_rect.Pitch);
cast to (unsigned char *) instead of (char *) and you do not have to cast to (void *)
+ unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect));
Both the cast and the outer () are quite pointless and IMO more confusing than helpful.
+ memset(locked_rect.pBits, 0, (locked_rect.Pitch * OSD_TEXTURE_SIZE));
the inner () seem pointless too.
+ osd_quad_vb[2].tv = + osd_quad_vb[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect));
This is the same as 1.0f / aspect, though for clarity/readability it might be better to do (float)calc_height / OSD_TEXTURE_SIZE. I'm mostly waiting for more info on how we can solve the issue with the clear function, but I think it is good to apply basically. A bit unrelated: all those error checking paths are quite bad and full of memleaks (e.g. when one function fails in preinit all resources that were allocated before should be freed before returning), somewhen those should be fixed - but it's nothing that should be hurried, it should be done without making a mess of the code.
On the other side - this is 5% when playing as fast as possible on my HW (which is REALLY fast). When playing with 25fps this will mean less than 1%. I agree if we really do in ONLY in fullscreen + OSD. Otherwise don't do Clear each frame. Ok?
Another question - I haven't see Jim's code yet (I await patch commit), but - we are going to have OSD's texture equal to the current scaled resolution, so we have pixel-perfect OSD, right? I don't want OSD to be of lower resolution and scaled by the HW later. Nevertheless - Jim may commit his current code, so I can review it and make improvements in this aspect.
On Fri, Nov 28, 2008 at 10:07:07PM +0200, Georgi Petrov wrote:
Another question - I haven't see Jim's code yet (I await patch commit), but - we are going to have OSD's texture equal to the current scaled resolution, so we have pixel-perfect OSD, right? I don't want OSD to be of lower resolution and scaled by the HW later.
Argh, that is exactly what I asked you about just a few mails ago.
Nevertheless - Jim may commit his current code, so I can review it and make improvements in this aspect.
You're supposed to be the maintainer of vo_direct3d, it should be your job to review and test it (and before it gets committed).
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Fri, Nov 28, 2008 at 10:07:07PM +0200, Georgi Petrov wrote:
Another question - I haven't see Jim's code yet (I await patch commit), but - we are going to have OSD's texture equal to the current scaled resolution, so we have pixel-perfect OSD, right? I don't want OSD to be of lower resolution and scaled by the HW later.
Argh, that is exactly what I asked you about just a few mails ago.
Nevertheless - Jim may commit his current code, so I can review it and make improvements in this aspect.
You're supposed to be the maintainer of vo_direct3d, it should be your job to review and test it (and before it gets committed).
I have a fix for the OSD and the display size issue - -aspect etc. It basically adjusts the texture coordinates to maximize the OSD in the viewable area, keeping square pixel ratio for the OSD. Do you want another patch with those other cleanups and this? 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 iEYEARECAAYFAkkwVKcACgkQhrNWoHjgI1BfPACfTytl1fYmXUhK4K2IgO7zzkEn Eo4AnRi9ZDkCdx62iaMJDHPRqBc23XMn =G6Z3 -----END PGP SIGNATURE-----
On Fri, Nov 28, 2008 at 08:29:27PM +0000, Jim Hauxwell wrote:
I have a fix for the OSD and the display size issue
-aspect etc.
It basically adjusts the texture coordinates to maximize the OSD in the viewable area, keeping square pixel ratio for the OSD.
Well, just replacing (float)priv->src_width / priv->src_height with (float)vo_dwidth / vo_dheight should do it I think...
Do you want another patch with those other cleanups and this?
If it is no effort for you. But I am not in a hurry... Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
On Fri, Nov 28, 2008 at 08:29:27PM +0000, Jim Hauxwell wrote:
I have a fix for the OSD and the display size issue
-aspect etc.
It basically adjusts the texture coordinates to maximize the OSD in the viewable area, keeping square pixel ratio for the OSD.
Well, just replacing (float)priv->src_width / priv->src_height with (float)vo_dwidth / vo_dheight should do it I think...
Do you want another patch with those other cleanups and this?
If it is no effort for you. But I am not in a hurry...
Actually, can we defer as I think some discussion is needed for this? Currently the OSD is rendered at the movie aspect not the display aspect. The fix I have (which seems to work) modifies the x or y texture coordinates to map the movie aspect to the display aspect. OSD is a big patch and has required many goes from me to get the formatting correct etc. I think it would be better to have a small patch to enhance the OSD later. Jim
Greetings, Reimar Döffinger _______________________________________________ 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 iEYEARECAAYFAkkwe4AACgkQhrNWoHjgI1BYQwCeJQWuta9Ylvu+oqmDK/vTcrXx TlgAn3vkoItlQwpkNRLVokKWmjiUYbSQ =IPYZ -----END PGP SIGNATURE-----
On Fri, Nov 28, 2008 at 11:15:12PM +0000, Jim Hauxwell wrote:
OSD is a big patch and has required many goes from me to get the formatting correct etc. I think it would be better to have a small patch to enhance the OSD later.
Well, if the vo_direct3d maintainer agrees with that I don't really have a problem with it. But there is one issue I just noticed that can't really be ignored because I can not guarantee that it is not exploitable: For a source video aspect < 1 the calc_height variable can be larger than the OSD texture size, allowing to write beyond the bounds of the texture memory buffer. Greetings, Reimar Döffinger
On Wed, Dec 3, 2008 at 1:44 PM, Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de> wrote:
On Fri, Nov 28, 2008 at 11:15:12PM +0000, Jim Hauxwell wrote:
OSD is a big patch and has required many goes from me to get the formatting correct etc. I think it would be better to have a small patch to enhance the OSD later.
Well, if the vo_direct3d maintainer agrees with that I don't really have a problem with it.
I absolutely agree that the patch should be included!!! I prefer to see the code and try to find problems/improve it myself and discuss it with Jim, who has the know-how.
But there is one issue I just noticed that can't really be ignored because I can not guarantee that it is not exploitable: For a source video aspect < 1 the calc_height variable can be larger than the OSD texture size, allowing to write beyond the bounds of the texture memory buffer.
Jim, can you fix it and submit the patch again?
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Georgi Petrov wrote:
On Wed, Dec 3, 2008 at 1:44 PM, Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de> wrote:
On Fri, Nov 28, 2008 at 11:15:12PM +0000, Jim Hauxwell wrote:
OSD is a big patch and has required many goes from me to get the formatting correct etc. I think it would be better to have a small patch to enhance the OSD later. Well, if the vo_direct3d maintainer agrees with that I don't really have a problem with it.
I absolutely agree that the patch should be included!!! I prefer to see the code and try to find problems/improve it myself and discuss it with Jim, who has the know-how.
But there is one issue I just noticed that can't really be ignored because I can not guarantee that it is not exploitable: For a source video aspect < 1 the calc_height variable can be larger than the OSD texture size, allowing to write beyond the bounds of the texture memory buffer.
Jim, can you fix it and submit the patch again?
I was going to change it based on the new stuff in the source tree. I hope to have it complete later tonight, when I get a moment 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 iEYEARECAAYFAkk4J20ACgkQhrNWoHjgI1CFGACdHD9mDDy/bG6DXWMK6uEZ5Epe XBsAmgJGrEWa9clUeChhmD8KYOedMtEt =ux2a -----END PGP SIGNATURE-----
Great Jim! I'm expecting the time when your patch is finally accepted with great pleasure!
-----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; + } + } +}
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.
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. thanks a bundle Diego
-----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; + } + } +}
On Sat, Dec 06, 2008 at 08:53:33AM +0000, Jim Hauxwell wrote:
From my patch the other day, I noticed some variables had capital letters at the start, so I've fixed this.
--- libvo/vo_direct3d.c (revision 28089) +++ libvo/vo_direct3d.c (working copy) @@ -100,6 +116,13 @@
+typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t;
The _t namespace is reserved by POSIX, so please use something else.
@@ -213,6 +247,75 @@ + + 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);
Indent the second line to be aligned with the rest of the text within the parentheses, same below. Diego
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Diego Biurrun wrote:
--- libvo/vo_direct3d.c (revision 28089) +++ libvo/vo_direct3d.c (working copy) @@ -100,6 +116,13 @@
+typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t;
The _t namespace is reserved by POSIX, so please use something else.
You learn something new every day! Just made it match the struct_fmt_table structure layout
@@ -213,6 +247,75 @@ + + 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);
Indent the second line to be aligned with the rest of the text within the parentheses, same below.
Done in both messages Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk6W10ACgkQhrNWoHjgI1BOnwCcCwfyfMs3w8GzuSvN8VhHGeph wQsAmwayAJqPMy4zrvfWh9/fVfdqnxib =WapD -----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 { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} struct_vertex; + /**************************************************************************** * * * * @@ -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) { + + struct_vertex 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(struct_vertex)); + + /* 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; + } + } +}
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD.
BTW, I can't find information anywhere - what's exactly EOSD?
On Mon, Dec 08, 2008 at 09:14:59AM +0200, Georgi Petrov wrote:
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD.
Have you tested it? Also there is still almost the same buffer flow problem: the allocated texture may be smaller than the arguments to vo_draw_text, allowing for a buffer overflow. There are also minor issues like the expression to select non-power-of-two texture is extremely overcomplicated (e.g. !(a ^ b) is the same as a == b) and also wrong. I guess I can go over it myself and fix it when I got a bit of time. Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
On Mon, Dec 08, 2008 at 09:14:59AM +0200, Georgi Petrov wrote:
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD.
Have you tested it? Also there is still almost the same buffer flow problem: the allocated texture may be smaller than the arguments to vo_draw_text, allowing for a buffer overflow.
Yeh, I see the issue. I'll fix this.
There are also minor issues like the expression to select non-power-of-two texture is extremely overcomplicated (e.g. !(a ^ b) is the same as a == b) and also wrong. I guess I can go over it myself and fix it when I got a bit of time.
a = D3DPTEXTURECAPS_POW2 b = D3DPTEXTURECAPS_NONPOW2CONDITIONAL a b a ^b !(a^b) (a==b) 0 0 0 1 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 The D3D docs say the if a & b are neither defined then you assume the device can support non power2 textures. If they are both set then also this is true. If a then power2 dimensions, but possibly not square. The other case is invalid. I think the logic is correct, but as you said it could be simplified by the use of (a==b) Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk8/4IACgkQhrNWoHjgI1DfcQCgqmJITjU3wpJVnMZkjz/0qsyJ JeYAnRG1RnDcZOSwmjhaFbnZFBrd+kdx =lOj3 -----END PGP SIGNATURE-----
On Mon, Dec 08, 2008 at 11:05:38AM +0000, Jim Hauxwell wrote:
The D3D docs say the if a & b are neither defined then you assume the device can support non power2 textures.
Argl! where did they hide that part? They forgot to say that in the part I read... Greetings, Reimar Döffinger
On Mon, Dec 08, 2008 at 11:05:38AM +0000, Jim Hauxwell wrote:
a = D3DPTEXTURECAPS_POW2 b = D3DPTEXTURECAPS_NONPOW2CONDITIONAL
a b a ^b !(a^b) (a==b) 0 0 0 1 1 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1
The D3D docs say the if a & b are neither defined then you assume the device can support non power2 textures. If they are both set then also this is true. If a then power2 dimensions, but possibly not square. The other case is invalid.
Sorry, yes, you are right. But there is also the case a = 0, b = 1. This probably does not exist, but as I read it, it means non-pow2 is supported, and more importantly it leads to simpler code. (and I misunderstood what you said in my previoous mail). Greetings, Reimar Döffinger
Hello, On Mon, Dec 08, 2008 at 11:22:41AM +0100, Reimar Döffinger wrote:
On Mon, Dec 08, 2008 at 09:14:59AM +0200, Georgi Petrov wrote:
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD.
Have you tested it? Also there is still almost the same buffer flow problem: the allocated texture may be smaller than the arguments to vo_draw_text, allowing for a buffer overflow. There are also minor issues like the expression to select non-power-of-two texture is extremely overcomplicated (e.g. !(a ^ b) is the same as a == b) and also wrong. I guess I can go over it myself and fix it when I got a bit of time.
This one should be better, but I could not test since wine is currently broken on my system.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
Hello, On Mon, Dec 08, 2008 at 11:22:41AM +0100, Reimar Döffinger wrote:
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD. Have you tested it? Also there is still almost the same buffer flow problem: the allocated texture may be smaller than the arguments to vo_draw_text, allowing for a buffer overflow. There are also minor issues like the expression to select non-power-of-two texture is extremely overcomplicated (e.g. !(a ^ b) is
On Mon, Dec 08, 2008 at 09:14:59AM +0200, Georgi Petrov wrote: the same as a == b) and also wrong. I guess I can go over it myself and fix it when I got a bit of time.
This one should be better, but I could not test since wine is currently broken on my system.
I think it will suffer from the same problem that the original patch has. The texture will be stretched when the aspect is changed. I'm also confused as to why the intrinsics were dropped, doesn't MPlayer stipulate to compile on gcc only? This is not an issue, just I would like to know for future. I would also like to know why there is a second draw in the render_d3d_frame which only has enough vertices for a single triangle? Are you trying to redraw the OSD? If so, why? Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9B1IACgkQhrNWoHjgI1D9UACfZESj/flV4+3tfJ5dOH0nFgmB 3IkAoJWL5XFsAWKSnTs676caFmAwmESB =Ed1s -----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jim Hauxwell wrote:
Reimar Döffinger wrote:
Hello, On Mon, Dec 08, 2008 at 11:22:41AM +0100, Reimar Döffinger wrote:
I vote for inclusion now. If there are some indent / spacing issues, I'll fix them after the patch is commited. We need the OSD. Have you tested it? Also there is still almost the same buffer flow problem: the allocated texture may be smaller than the arguments to vo_draw_text, allowing for a buffer overflow. There are also minor issues like the expression to select non-power-of-two texture is extremely overcomplicated (e.g. !(a ^ b) is
On Mon, Dec 08, 2008 at 09:14:59AM +0200, Georgi Petrov wrote: the same as a == b) and also wrong. I guess I can go over it myself and fix it when I got a bit of time. This one should be better, but I could not test since wine is currently broken on my system.
I think it will suffer from the same problem that the original patch has. The texture will be stretched when the aspect is changed.
I'm also confused as to why the intrinsics were dropped, doesn't MPlayer stipulate to compile on gcc only? This is not an issue, just I would like to know for future.
I would also like to know why there is a second draw in the render_d3d_frame which only has enough vertices for a single triangle? Are you trying to redraw the OSD? If so, why?
Here is another patch, with the two issues fixed. It should never go outside the texture area when generating the OSD and the logic for the power2 has been simplified as discussed. Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9DHQACgkQhrNWoHjgI1CxfwCffw+bU6VpwmoF4nYPlogvZc4n sskAnREFxMaUKydvrsf1L3X2lL+61Xqi =m1W/ -----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 { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} struct_vertex; + /**************************************************************************** * * * * @@ -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; } @@ -397,7 +500,7 @@ /* If we're here, then we should lock the rect and copy a packed frame */ if (!priv->locked_rect.pBits) { if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { + &priv->locked_rect, NULL, D3DLOCK_DISCARD))) { mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Surface lock failure\n"); return VO_ERROR; } @@ -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 @@ -718,7 +842,7 @@ /* Lock the offscreen surface if it's not already locked. */ if (!priv->locked_rect.pBits) { if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { + &priv->locked_rect, NULL, D3DLOCK_DISCARD))) { mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Surface lock failure\n"); return VO_FALSE; } @@ -770,3 +894,141 @@ 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, D3DLOCK_DISCARD))) { + 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 * min(vo_dheight, priv->osd_texture_height)); + + /* 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(min(vo_dwidth, priv->osd_texture_width), + min(vo_dheight, priv->osd_texture_height), 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) { + + struct_vertex 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 = min((1.0 / priv->osd_texture_width) * vo_dwidth, 1.0); + osd_quad_vb[2].tv = + osd_quad_vb[3].tv = min((1.0 / priv->osd_texture_height) * vo_dheight, 1.0); + + 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(struct_vertex)); + + /* 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; + } + } +}
On Mon, Dec 08, 2008 at 12:00:52PM +0000, Jim Hauxwell wrote:
It should never go outside the texture area when generating the OSD
While that is true you fall back to using the whole texture, which i think is as in your very first patch, so the aspect issue should arise again. Setiing max_texture_width to 256 should help you see the issue if I am right.
@@ -397,7 +500,7 @@ /* If we're here, then we should lock the rect and copy a packed frame */ if (!priv->locked_rect.pBits) { if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { + &priv->locked_rect, NULL, D3DLOCK_DISCARD))) { mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Surface lock failure\n"); return VO_ERROR; }
Unrelated. If that is intentional and you explain the why i can make this change, you don't need to send a separate patch.
@@ -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);
Unrelated, remind me to fix it (at the latest) after the OSD was applied if I forget. Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
On Mon, Dec 08, 2008 at 12:00:52PM +0000, Jim Hauxwell wrote:
It should never go outside the texture area when generating the OSD
While that is true you fall back to using the whole texture, which i think is as in your very first patch, so the aspect issue should arise again. Setiing max_texture_width to 256 should help you see the issue if I am right.
This is exactly what I did to test it. Yes I agree the results for some really low end cards (which don't support decent texture sizes) wont be ideal, but it will probably not affect 99% of people. Also it shouldn't now crash. Ideally for a card which only supported say 1024 width, I wanted to use the whole width to get the best OSD possible
@@ -397,7 +500,7 @@ /* If we're here, then we should lock the rect and copy a packed frame */ if (!priv->locked_rect.pBits) { if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { + &priv->locked_rect, NULL, D3DLOCK_DISCARD))) { mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Surface lock failure\n"); return VO_ERROR; }
Unrelated. If that is intentional and you explain the why i can make this change, you don't need to send a separate patch.
Sorry, I was playing elsewhere with some performance enhancing stuff. It didn't actually make any noticeable difference on my card, so could probably come out for now. I'll go back to it later.
@@ -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);
Unrelated, remind me to fix it (at the latest) after the OSD was applied if I forget.
Will do Patch attached with no intrinsics as per your last mail. I am running this on Vista just FYI Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9VrAACgkQhrNWoHjgI1DLcQCgj29GX0Q6aZcDvj5jYWv73urj 5RMAn1UA3D40e6rwq2QNM/hAGekpBnZV =JZPU -----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 { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} struct_vertex; + /**************************************************************************** * * * * @@ -185,17 +208,42 @@ 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; } } +/** @brief Round up to the next power2 of the input + */ +static unsigned int next_power2(unsigned int p) +{ + p--; + p |= p >> 1; + p |= p >> 2; + p |= p >> 4; + p |= p >> 8; + p |= p >> 16; + return p + 1; +} + /** @brief Create D3D Offscreen and Backbuffer surfaces. * @return 1 on success, 0 on failure */ static int create_d3d_surfaces(void) { + int osd_width, osd_height; mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d><INFO>create_d3d_surfaces called.\n"); if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( @@ -213,6 +261,76 @@ return 0; } + /* round up to next power of 2 */ + osd_width = next_power2(vo_dwidth); + osd_height = next_power2(vo_dheight); + + /* calculate the best size for the OSD depending on the factors from the device */ + if (priv->device_caps_square_only) { + /* device only supports square textures */ + /* this is likely that they are only power2 (old HW) */ + 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 = osd_width; + priv->osd_texture_height = osd_height; + } 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 +588,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 +619,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)); @@ -533,6 +654,31 @@ mp_msg(MSGT_VO, MSGL_V, "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 +813,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 +909,141 @@ 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 * min(vo_dheight, priv->osd_texture_height)); + + /* 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(min(vo_dwidth, priv->osd_texture_width), + min(vo_dheight, priv->osd_texture_height), 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) { + + struct_vertex 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 = min((1.0 / priv->osd_texture_width) * vo_dwidth, 1.0); + osd_quad_vb[2].tv = + osd_quad_vb[3].tv = min((1.0 / priv->osd_texture_height) * vo_dheight, 1.0); + + 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(struct_vertex)); + + /* 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; + } + } +}
The OSD works very good. I noticed just one bug. Start a video, hit right arrow to show the movie progress bar. Notice it's size. Hit "f" for fullscreen and hit the right arrow immediately. It still displays with the old size (that of the previous lower resolution scale). After the movie progress bar disappears, the size is normal again. The same happens when going back from fullscreen to window.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Georgi Petrov wrote:
The OSD works very good. I noticed just one bug. Start a video, hit right arrow to show the movie progress bar. Notice it's size. Hit "f" for fullscreen and hit the right arrow immediately. It still displays with the old size (that of the previous lower resolution scale). After the movie progress bar disappears, the size is normal again. The same happens when going back from fullscreen to window.
Yes, I mentioned this in my original mail. It's to do with the currently loaded font (of which I have no control over). If you turn on - -v you will see that the font reloads and the display becomes correct. You can get the same effect from just a standard resize and right arrow. If anyone does have any ideas on this then throw them this way. Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9WNIACgkQhrNWoHjgI1DOEQCfWG8hY+ztx10jfGHxPEhgG2B8 bdEAoIB8G83zDBTXUurEOqA9/FZgwQlx =S+nv -----END PGP SIGNATURE-----
Hello, On Mon, Dec 08, 2008 at 07:23:47PM +0200, Georgi Petrov wrote:
The OSD works very good. I noticed just one bug. Start a video, hit right arrow to show the movie progress bar. Notice it's size. Hit "f" for fullscreen and hit the right arrow immediately. It still displays with the old size (that of the previous lower resolution scale). After the movie progress bar disappears, the size is normal again. The same happens when going back from fullscreen to window.
My version (attached, fixed a crash with low max texture size, too) fixes this one, too. Greetings, Reimar Döffinger
On Mon, Dec 08, 2008 at 06:48:19PM +0100, Reimar Döffinger wrote:
On Mon, Dec 08, 2008 at 07:23:47PM +0200, Georgi Petrov wrote:
The OSD works very good. I noticed just one bug. Start a video, hit right arrow to show the movie progress bar. Notice it's size. Hit "f" for fullscreen and hit the right arrow immediately. It still displays with the old size (that of the previous lower resolution scale). After the movie progress bar disappears, the size is normal again. The same happens when going back from fullscreen to window.
My version (attached, fixed a crash with low max texture size, too) fixes this one, too.
Applied, and sorry for forgetting to mention the original author the first time ;-).
On Mon, Dec 08, 2008 at 05:17:36PM +0000, Jim Hauxwell wrote:
Ideally for a card which only supported say 1024 width, I wanted to use the whole width to get the best OSD possible
Well, I obviously prefer by solution :-P Reasons: 0) OSD always has the right aspect 1) the scaling is the same in x- and y-direction, looking less weird 2) the scale factor is always a power of two, giving less "weird" aliasing, IMO also better readable for letters. This is obviously a very, very minor issue though with no clear "winner".
Question: 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; } What's C "speed policy" about such declared pointers inside the for statement? Would it be better this this way (speed wise): unsigned short *dst; for (y = 0; y < h; y++) { 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; }
/* clear the whole texture to avoid issues due to interpolation */ memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->osd_texture_height); This is most likely not correct. Pitch != Width!!!!!
/** @brief libvo Callback: Draw OSD/Subtitles, */ 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.*/ locked_rect shadows the global variable priv->locked_rect. I know this is not a problem, but may create confusion in the future.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Georgi Petrov wrote:
/** @brief libvo Callback: Draw OSD/Subtitles, */ 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.*/
locked_rect shadows the global variable priv->locked_rect. I know this is not a problem, but may create confusion in the future.
The priv->locked_rect is locking a surface the size of the playing video , and the local locking is for the size of the display. So in this case it is not a 'shadow' of the other lock, as the parameters are different. Now I want to answer all your questions in one post... Aaaarg
What's C "speed policy" about such declared pointers inside the for statement? Would it be better this this way (speed wise):
Should be non as its just a cast to make the compiler do the correct address calculation in the loop
/* clear the whole texture to avoid issues due to interpolation */ memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->osd_texture_height);
This is most likely not correct. Pitch != Width!!!!!
Yes, but pitch is guaranteed to be greater than width, so it is correct. Otherwise you would have to loop over the clear and probably get a slower solution, given that memset is normally well optimized on most systems. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9Z6MACgkQhrNWoHjgI1DLtACgnT6pPdzSGvYh+xmfd5xJ8Jw/ HqAAoI8yiW1LvMtlzOvz9SO0elEEYaIn =I3dh -----END PGP SIGNATURE-----
The priv->locked_rect is locking a surface the size of the playing video , and the local locking is for the size of the display. So in this case it is not a 'shadow' of the other lock, as the parameters are different.
Yep - there's real problem. I mean just "name shadowing". Never mind.
Now I want to answer all your questions in one post... Aaaarg
What's C "speed policy" about such declared pointers inside the for statement? Would it be better this this way (speed wise):
Should be non as its just a cast to make the compiler do the correct address calculation in the loop
I means that the both code snippets translate into the same ASM instructions, right? I hope the compiler doesn't do something dynamically for each from iteration when the pointer is declared inside it.
Yes, but pitch is guaranteed to be greater than width, so it is correct. Otherwise you would have to loop over the clear and probably get a slower solution, given that memset is normally well optimized on most systems.
I see. The memory after each line (if pitch > width) is reserved for cache, so you delete it as well. I'm sure there are no problems with that, I just wanted to make sure you know about it.
Yep - there's real problem. I mean just "name shadowing". Never mind.
I mean "no real problem"...
On Mon, Dec 08, 2008 at 08:39:21PM +0200, Georgi Petrov wrote:
The priv->locked_rect is locking a surface the size of the playing video , and the local locking is for the size of the display. So in this case it is not a 'shadow' of the other lock, as the parameters are different.
Yep - there's real problem. I mean just "name shadowing". Never mind.
Just a minor note: the term "shadowing" means that you can not access the other variable, which is not the case here (and gcc would warn about it).
I means that the both code snippets translate into the same ASM instructions, right? I hope the compiler doesn't do something dynamically for each from iteration when the pointer is declared inside it.
That would just be a lot of pain for no advantage, compilers always allocate the stack frame (i.e. the memory for all stack variables) at the start of the function, no matter where they are declared. At -O3 it might do some useless assignments, but at higher optimization levels that should not matter either. Also performance is not that critical here, it's done only once per line, not per pixel.
I see. The memory after each line (if pitch > width) is reserved for cache, so you delete it as well. I'm sure there are no problems with that, I just wanted to make sure you know about it.
"reserved for cache"? Anyway it is just completely ordinary memory, that's exactly the point of it, to allow processing each line e.g. with operations that always process full 16 bytes (some DMA controllers) etc. Greetings, Reimar Döffinger
Ok. Great work Jim and Reimar! The OSD works really great! Exactly fulfilling my high expectations! There might be bugs, but not obvious ones, so if it's ok with you, I think that it's finally time (after waiting soooo long) for Direct3D vo to have OSD!!!
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Reimar Döffinger wrote:
On Mon, Dec 08, 2008 at 05:17:36PM +0000, Jim Hauxwell wrote:
Ideally for a card which only supported say 1024 width, I wanted to use the whole width to get the best OSD possible
Well, I obviously prefer by solution :-P Reasons: 0) OSD always has the right aspect 1) the scaling is the same in x- and y-direction, looking less weird 2) the scale factor is always a power of two, giving less "weird" aliasing, IMO also better readable for letters.
This is obviously a very, very minor issue though with no clear "winner".
I agree with all but point (2?) as the scaling is determined via the size of the display window. The scaling by this virtue is always non deterministic. Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkk9aU4ACgkQhrNWoHjgI1BO8QCbBur//hTPKtR/PyRRAjlq4oJI TFwAoMNlZdlpzdTb/821wPfDJd++ttiY =6bBg -----END PGP SIGNATURE-----
On Mon, Dec 08, 2008 at 06:37:02PM +0000, Jim Hauxwell wrote:
Reimar Döffinger wrote:
Well, I obviously prefer by solution :-P Reasons: 0) OSD always has the right aspect 1) the scaling is the same in x- and y-direction, looking less weird 2) the scale factor is always a power of two, giving less "weird" aliasing, IMO also better readable for letters.
This is obviously a very, very minor issue though with no clear "winner".
I agree with all but point (2?) as the scaling is determined via the size of the display window. The scaling by this virtue is always non deterministic.
Well, no the OSD is rendered at the same size as the display window, so the OSD does not get scaled - unless the maximum texture size is too small. The way you did it, the display size could be just a few percent larger than the size the OSD is rendered at, which leads to that sinus-like aliasing patter of sharp and washed-out parts. Which is why I always made the OSD a power of two smaller than the display size. I guess that's mostly a matter of taste, still I applied my variant simply because I had the resizing fixed and a few whitespace fixes already in it, it can still be changed later on.
Hello, On Mon, Dec 08, 2008 at 11:38:58AM +0000, Jim Hauxwell wrote:
I think it will suffer from the same problem that the original patch has. The texture will be stretched when the aspect is changed.
It should behave exactly the same as your patch, there is just an additional fix for the case vo_dwidth > max_texture_width (which is the only case where priv->osd_width != vo_dwidth) (same if vo_dheight > max_texture_height). Of course I may have done something stupid somewhere.
I'm also confused as to why the intrinsics were dropped, doesn't MPlayer stipulate to compile on gcc only? This is not an issue, just I would like to know for future.
No, certainly not! Though _currently_ it only works with gcc on Windows the long term goal is to work with any C99 compliant compiler (which unfortunately means probably never with the Microsoft compiler). For adequate performance support for gcc-style inline-assembly is required, too.
I would also like to know why there is a second draw in the render_d3d_frame which only has enough vertices for a single triangle? Are you trying to redraw the OSD? If so, why?
Sorry, debugging code. Wine renders nothing at all unless at least one primitive is drawn as well. Should be fixed in attached patch. And yes I should probably try to find a Windows-PC to properly test. Greetings, Reimar Döffinger
I can test everything in the following two days on a Vista PC.
On Fri, Nov 28, 2008 at 08:32:24AM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:26:10PM +0000, Jim Hauxwell wrote:
Diego Biurrun wrote:
On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
This patch is broken and does not apply. I suspect Windows linebreaks. Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
New, smaller patch file
@@ -264,6 +308,50 @@
+ /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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");
random indentation, same below
I've altered it, but I just copied mine from the
if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( priv->d3d_device, priv->src_width, priv->src_height, priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); return 0; }
which is already in svn. To your case this has broken indentation.
Fixed.
+ if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { + mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); + return;
3 space indentation
A cut and paste from the other place lock is used. That has also got a 3 space indentation and made it into svn by mistake.
Fixed. Diego
Hello, On Wed, Nov 26, 2008 at 07:56:18AM +0000, Jim Hauxwell wrote:
Sorry, my mistake. Visual Studio had decided to add CR/LF to all the lines and svn diff doesn't take this into account.
Consider using TortoiseSVN, it will check out all files with Windows CR/LF linebreaks (though that means you better don't edit them with msys vi, it only creates Unix linebreaks) Greetings, Reimar Döffinger
Hello, On Wed, Nov 26, 2008 at 12:10:59AM +0000, Jim Hauxwell wrote:
I was not aware of the reference code to do the osd blending, so I've taken a look at this and basically copied what it does.
I've attached a patch which follows the exact blend rules
((dst * srca) >> 8) + src
it uses a constant color to pass the multiplication for src, so its actually
(1.0f * src) + (dst * srca) where srca is a float
Well, I have been using tmp[i] = -srca[i] for a very good reason, because these are not the same, and has the same issue as your previous approach. For srca == 1, ((dst * srca) >> 8) will _always_ be 0, because dst * srca < 256 becomes 0 after an integer divide by 256. Also, even mathematically, srca == 1 means a blend factor of 1 / 256, whereas in OpenGL/Direct3D it is 1 / 255. This of course means you can't implement _exactly_ the same algortihm with 3D hardware, but I considered it important to get at least the corner cases right, i.e. MPlayer srca == 0 -> osd completely transparent MPlayer srca == 1 -> osd completely opaque MPlayer srca == 2 to == 255 -> progressively more transparent, exact values do not really matter. Which is why I chose to use -srca for the OpenGL alpha values: it is fast to calculate and does not need a branch (though in your case the branch may save some memory bandwidth - if that saves more than the branch costs probably depends on the hardware). And yes, I spent probably a few hours of thinking on how to implement that horrid scheme, the EOSD stuff for ASS subtitles was much simpler in that respect. And thanks for the hint on alpha test, now that I have access to a low-level integrated Intel card it might make sense to test if it helps here (it made no difference I could measure with my GeForce3 back then, though vo_gl only draws on the actual OSD areas, not the whole window).
As a side effect you can change the color of the subtitles by changing the DWORD value in this line,
IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_BLENDFACTOR, 0xFFFFFFFF);
for red choose 0xFFFF0000, for example
Google tells me some Intel cards/drivers do not support D3DRS_BLENDFACTOR, you could use D3DBLEND_ONE to avoid that. If you want to be able to change texture colour you can probably do that in a better supported way by changing the vertex colours (just assuming that D3D works similarly to OpenGL here). Greetings, Reimar Döffinger
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, Did anyone look at the patch I put in two days ago to resolve the tab->space, formatting, blending, includes.... issues? Did it get lost in the noise? I've reattached in case. Jim -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkku9rwACgkQhrNWoHjgI1DTFACfXKAsn2Wk+2jXXi6FgUMNCvzG txEAnRTzoxBr7NwOLuXzyfFTlYFmy8Cb =ySjs -----END PGP SIGNATURE----- Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 28042) +++ 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,14 @@ 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 + cant lock a normal texture. Uses RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ + IDirect3DVertexBuffer9 *d3d_quad_vb; /**< Vertex buffer that contains the texture + coordinates for the quad. */ + int is_osd_populated; /* has the OSD something on it */ } *priv; typedef struct { @@ -101,6 +108,22 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(fmt_table) / sizeof(fmt_table[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 1024 /* as this is a texture, it can be a different size to the movie */ + +typedef struct vertex_s { + float x, y, z; /* Position of vertex in 3D space */ + float tu, tv; /* Texture coordinates */ +} vertex_t; + +vertex_t osd_quad_vb[] = { + {-1.0f,-1.0f, 0.0f, 0, 1 }, + {-1.0f, 1.0f, 0.0f, 0, 0 }, + { 1.0f, 1.0f, 0.0f, 1, 0 }, + { 1.0f,-1.0f, 0.0f, 1, 1 } +}; + /**************************************************************************** * * * * @@ -186,6 +209,25 @@ priv->d3d_surface = NULL; } + /* kill the VB and the texture */ + 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_quad_vb != NULL) + { + IDirect3DVertexBuffer9_Release (priv->d3d_quad_vb); + priv->d3d_quad_vb = NULL; + } + if (priv->d3d_device != NULL) { IDirect3DDevice9_Release (priv->d3d_device); priv->d3d_device = NULL; @@ -207,6 +249,8 @@ { D3DPRESENT_PARAMETERS present_params; D3DDISPLAYMODE disp_mode; + void *vertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); @@ -264,6 +308,50 @@ return 0; } + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + priv->d3d_device, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 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; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( priv->d3d_device, sizeof(osd_quad_vb), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &priv->d3d_quad_vb, NULL ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DDevice9_CreateVertexBuffer Failed (d3d_quad_vb).\n"); + return 0; + } + + if (FAILED (IDirect3DVertexBuffer9_Lock(priv->d3d_quad_vb, 0, sizeof(osd_quad_vb), + &vertices, 0 ))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Lock Failed.\n"); + return 0; + } + + memcpy( vertices, osd_quad_vb, sizeof(osd_quad_vb) ); + aspect = (float)priv->src_width / priv->src_height; + /* populate the Y with the correct coordinate */ + ((vertex_t *)vertices)[0].tv = + ((vertex_t *)vertices)[3].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(priv->d3d_quad_vb))) { + mp_msg(MSGT_VO,MSGL_ERR, + "<vo_direct3d><INFO>IDirect3DVertexBuffer9_Unlock Failed.\n"); + return 0; + } + if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(priv->d3d_backbuf)))) { @@ -388,7 +476,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); } } @@ -572,13 +660,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 @@ -672,3 +753,133 @@ mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); return VO_FALSE; } + + +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++) { + register unsigned short *dst = (unsigned short*) dstbase; + register int x; + for(x=0; x < w; x++) { + if(srca[x]) + dst[x]=((srca[x]-1) << 8) | src[x]; + } + src+=srcstride; + srca+=srcstride; + dstbase+=dststride; + } + return; +} + + +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, + (void *)((unsigned int)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) +{ + int x, y; + /* calculate a width and height based on the OSD_TEXTURE_SIZE */ + float aspect = (float)priv->src_width / priv->src_height; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + + 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; + } + + for (y=0; y < OSD_TEXTURE_SIZE; y++) { + unsigned short * dst = + (unsigned short *)((unsigned int)locked_rect.pBits + (locked_rect.Pitch * y)); + for (x=0; x < OSD_TEXTURE_SIZE; x++) { + dst[x] = 0xFF00; + } + } + + /* 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; + + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, 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) { + 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_SRCBLEND, D3DBLEND_ONE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_DESTBLEND, D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAFUNC, D3DCMP_LESS); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHAREF, (DWORD)0xFF); + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + 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 ); + + IDirect3DDevice9_SetTexture(priv->d3d_device, 0, (IDirect3DBaseTexture9 *)priv->d3d_texture_osd); + IDirect3DDevice9_SetStreamSource(priv->d3d_device, 0, priv->d3d_quad_vb, 0, sizeof(vertex_t) ); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(priv->d3d_device, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* 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; + } + } +}
Jim, I'll take a look at it very soon, but the other guys should check if it's ok with them.
participants (5)
-
compn -
Diego Biurrun -
Georgi Petrov -
Jim Hauxwell -
Reimar Döffinger