Index: libvo/vo_direct3d.c =================================================================== --- libvo/vo_direct3d.c (revision 27958) +++ libvo/vo_direct3d.c (working copy) @@ -45,6 +45,11 @@ */ const LIBVO_EXTERN(direct3d) +typedef struct +{ + const unsigned int MPlayerFormat; /**< Given by MPlayer */ + const D3DFORMAT FourCC; /**< Required by D3D's test function */ +} DisplayFormatTable; /* Global variables. Each one starts with "g". Pointers include "p". * I try to keep their count low. @@ -52,8 +57,6 @@ static int gIsPaused; /**< 1 = Movie is paused, 0 = Movie is not paused */ -static int gIsD3DConfigFinished; /**< Synchronization "semaphore". 1 when - instance of D3DConfigure is finished */ static int gIsPanscan; /**< 1= Panscan enabled, 0 = Panscan disabled */ static RECT gFullScrMovieRect; /**< Rect (upscaled) of the movie when displayed in fullscreen */ @@ -66,17 +69,21 @@ static IDirect3DSurface9 *gpD3DSurface; /**< Offscreen Direct3D Surface. MPlayer renders inside it. Uses colorspace MovieSrcFmt */ +static IDirect3DTexture9 *gpD3DTexture_OSD; /**< Direct3D Texture. MPlayer + renders inside it. Uses RGBA */ +static IDirect3DTexture9 *gpD3DTexture_SYSTEM; /**< Direct3D Texture. MPlayer + renders inside it. Uses RGBA */ static IDirect3DSurface9 *gpD3DBackBuf; /**< Video card's back buffer (used to display next frame) */ -static D3DFORMAT gMovieSrcFmt; /**< Movie colorspace format (depends on +static DisplayFormatTable * gpMovieSrcFmt; /**< Movie colorspace format (depends on the movie's codec) */ static D3DFORMAT gDesktopFmt; /**< Desktop (screen) colorspace format. Usually XRGB */ -typedef struct -{ - const unsigned int MPlayerFormat; /**< Given by MPlayer */ - const D3DFORMAT FourCC; /**< Required by D3D's test function */ -} DisplayFormatTable; +static int gIsLocked; /* is the region locked */ +static D3DLOCKED_RECT gLockedRect; /**< Offscreen surface we lock in order + to copy MPlayer's frame inside it.*/ +static int gIsOSDUpdated; /* has an update been made on the OSD surface */ +static LPDIRECT3DVERTEXBUFFER9 gpQuad_VB; /* Map table from reported MPlayer format to the required FourCC. This is needed to perform the format query. */ @@ -94,6 +101,26 @@ #define DISPLAY_FORMAT_TABLE_ENTRIES \ (sizeof(gDisplayFormatTable) / sizeof(gDisplayFormatTable[0])) +#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_TEX1 ) + +#define OSD_TEXTURE_SIZE 512 // at this is a texture blitted, it can be a different size to the movie + +typedef struct Vertex_t +{ + float x, y, z; // Position of vertex in 3D space + float tu, tv; // Texture coordinates +} Vertex; + +Vertex g_OSDQuad[] = +{ + {-1.0f,-1.0f, 0.0f, 0, 0 }, + {-1.0f, 1.0f, 0.0f, 0, 1 }, + { 1.0f, 1.0f, 0.0f, 1, 1 }, + { 1.0f,-1.0f, 0.0f, 1, 0 } +}; + +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)); + /**************************************************************************** * * * * @@ -191,6 +218,12 @@ mp_msg(MSGT_VO,MSGL_V,"D3DDestroyContext called\r\n"); /* Let's destroy the old (if any) D3D Content */ + if (gIsLocked) + { + IDirect3DSurface9_UnlockRect(gpD3DSurface); + gIsLocked = 0; + } + if (gpD3DSurface != NULL) { IDirect3DSurface9_Release (gpD3DSurface); @@ -203,6 +236,25 @@ gpD3DDevice = NULL; } + /* kill the VB and the texture */ + if (gpD3DTexture_OSD != NULL) + { + IDirect3DTexture9_Release (gpD3DTexture_OSD); + gpD3DTexture_OSD = NULL; + } + + if (gpD3DTexture_SYSTEM != NULL) + { + IDirect3DTexture9_Release (gpD3DTexture_SYSTEM); + gpD3DTexture_SYSTEM = NULL; + } + + if (gpQuad_VB != NULL) + { + IDirect3DVertexBuffer9_Release (gpQuad_VB); + gpQuad_VB = NULL; + } + /* The following is not a memory leak. pD3DBackBuf is not malloc'ed * but just holds a pointer to the back buffer. Nobody gets hurt from * setting it to NULL. @@ -219,6 +271,8 @@ { D3DPRESENT_PARAMETERS PresentParams; D3DDISPLAYMODE DisplayMode; + Vertex *pVertices = NULL; + float aspect; mp_msg(MSGT_VO,MSGL_V,"D3DConfigure CALLED\n"); @@ -272,13 +326,63 @@ if (FAILED (IDirect3DDevice9_CreateOffscreenPlainSurface( gpD3DDevice, gSrcWidth, gSrcHeight, - gMovieSrcFmt, D3DPOOL_DEFAULT, &gpD3DSurface, NULL))) + gpMovieSrcFmt->FourCC, D3DPOOL_DEFAULT, &gpD3DSurface, NULL))) { mp_msg(MSGT_VO,MSGL_ERR, "IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); return 0; } + + /* create OSD */ + if (FAILED (IDirect3DDevice9_CreateTexture( + gpD3DDevice, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 1, D3DUSAGE_DYNAMIC, + D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &gpD3DTexture_SYSTEM, NULL))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3DDevice9_CreateTexture Failed (OSD).\n"); + return 0; + } + + if (FAILED (IDirect3DDevice9_CreateTexture( + gpD3DDevice, OSD_TEXTURE_SIZE, OSD_TEXTURE_SIZE, 1, D3DUSAGE_DYNAMIC, + D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &gpD3DTexture_OSD, NULL))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3DDevice9_CreateTexture Failed (OSD).\n"); + return 0; + } + + if (FAILED (IDirect3DDevice9_CreateVertexBuffer( gpD3DDevice, sizeof(g_OSDQuad), + 0, D3DFVF_MY_VERTEX, + D3DPOOL_DEFAULT, &gpQuad_VB, NULL ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3DDevice9_CreateVertexBuffer Failed (OSD).\n"); + return 0; + } + + pVertices = NULL; + if (FAILED (IDirect3DVertexBuffer9_Lock(gpQuad_VB, 0, sizeof(g_OSDQuad), + (void**)&pVertices, 0 ))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3DVertexBuffer9 (lock) Failed (OSD).\n"); + return 0; + } + + memcpy( pVertices, g_OSDQuad, sizeof(g_OSDQuad) ); + aspect = (float)gSrcWidth / gSrcHeight; + /* populate the Y with the correct coordinate */ + pVertices[1].tv = pVertices[2].tv = ((1.0f / OSD_TEXTURE_SIZE) * (OSD_TEXTURE_SIZE / aspect)); + + if (FAILED (IDirect3DVertexBuffer9_Unlock(gpQuad_VB))) + { + mp_msg(MSGT_VO,MSGL_ERR, + "IDirect3DVertexBuffer9 (lock) Failed (OSD).\n"); + return 0; + } + if (FAILED (IDirect3DDevice9_GetBackBuffer (gpD3DDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &(gpD3DBackBuf)))) @@ -303,9 +407,6 @@ { mp_msg(MSGT_VO,MSGL_V,"D3DUninit called\r\n"); - /* Block further calls to D3DConfigure(). */ - gIsD3DConfigFinished = 0; - /* Destroy D3D Context inside the window. */ D3DDestroyContext(); @@ -330,20 +431,16 @@ * if (mpi->flags & MP_IMGFLAG_DIRECT) ... */ + IDirect3DDevice9_Clear(gpD3DDevice, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0 ); + if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - return VO_TRUE; + 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); - return VO_TRUE; - } - - /* If the previous if failed, we should draw a packed frame */ - if (FAILED (IDirect3DDevice9_BeginScene(gpD3DDevice))) - { - mp_msg(MSGT_VO,MSGL_ERR,"BeginScene failed\n"); - return VO_ERROR; + goto skip_upload; } if (FAILED (IDirect3DSurface9_LockRect(gpD3DSurface, @@ -356,11 +453,22 @@ memcpy_pic(stLockedRect.pBits, mpi->planes[0], mpi->stride[0], mpi->height, stLockedRect.Pitch, mpi->stride[0]); +skip_upload: + + /* this unlock is used for both slice_draw path and D3DRenderFrame path */ if (FAILED (IDirect3DSurface9_UnlockRect(gpD3DSurface))) { mp_msg(MSGT_VO,MSGL_V,"Surface unlock failure\n"); return VO_ERROR; } + gIsLocked = 0; + + /* If the previous if failed, we should draw a packed frame */ + if (FAILED (IDirect3DDevice9_BeginScene(gpD3DDevice))) + { + mp_msg(MSGT_VO,MSGL_ERR,"BeginScene failed\n"); + return VO_ERROR; + } if (FAILED (IDirect3DDevice9_StretchRect (gpD3DDevice, gpD3DSurface, @@ -376,6 +484,31 @@ return VO_ERROR; } + /* update OSD */ + if (gIsOSDUpdated) + { + /* turn on alpha test */ + IDirect3DDevice9_SetRenderState(gpD3DDevice, D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + IDirect3DDevice9_SetRenderState(gpD3DDevice, D3DRS_ALPHAREF, (DWORD)1); + IDirect3DDevice9_SetRenderState(gpD3DDevice, D3DRS_ALPHATESTENABLE, TRUE); + + /* need to use a texture here */ + IDirect3DDevice9_SetRenderState(gpD3DDevice, D3DRS_LIGHTING, FALSE); + + IDirect3DDevice9_SetSamplerState(gpD3DDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); + IDirect3DDevice9_SetSamplerState(gpD3DDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); + + IDirect3DDevice9_SetTexture(gpD3DDevice, 0, gpD3DTexture_OSD); + IDirect3DDevice9_SetStreamSource(gpD3DDevice, 0, gpQuad_VB, 0, sizeof(Vertex) ); + IDirect3DDevice9_SetFVF(gpD3DDevice, D3DFVF_MY_VERTEX ); + IDirect3DDevice9_DrawPrimitive(gpD3DDevice, D3DPT_TRIANGLEFAN, 0, 2 ); + + /* turn off alpha test */ + IDirect3DDevice9_SetRenderState(gpD3DDevice, D3DRS_ALPHATESTENABLE, FALSE); + + gIsOSDUpdated = 0; + } + if (FAILED (IDirect3DDevice9_EndScene(gpD3DDevice))) { mp_msg(MSGT_VO,MSGL_ERR,"EndScene failed\n"); @@ -407,11 +540,11 @@ gDesktopFmt))) return 0; - gMovieSrcFmt = gDisplayFormatTable[i].FourCC; + gpMovieSrcFmt = (DisplayFormatTable *)&(gDisplayFormatTable[i]); mp_msg(MSGT_VO,MSGL_V,"Accepted Colorspace %s\n", vo_format_name(gDisplayFormatTable[i].MPlayerFormat)); 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); } } @@ -443,12 +576,18 @@ D3DDISPLAYMODE DisplayMode; /* Set to zero all global variables. */ gIsPaused = 0; - gIsD3DConfigFinished = 0; + //gIsD3DConfigFinished = 0; + gIsLocked = 0; gIsPanscan = 0; gpD3DHandle = NULL; gpD3DDevice = NULL; gpD3DSurface = NULL; + gpD3DTexture_OSD = NULL; + gpD3DTexture_SYSTEM = NULL; gpD3DBackBuf = NULL; + gIsOSDUpdated = 0; + gpQuad_VB = 0; + /* FIXME > Please use subopt-helper.h for this, see vo_gl.c:preinit for @@ -484,9 +623,6 @@ return -1; } - /* Allow the first call to D3DConfigure. */ - gIsD3DConfigFinished = 1; - return 0; } @@ -573,16 +709,11 @@ return VO_ERROR; } - if (gIsD3DConfigFinished == 1) - { - gIsD3DConfigFinished = 0; if (D3DConfigure () == 0) { - gIsD3DConfigFinished = 1; return VO_ERROR; } - gIsD3DConfigFinished = 1; - } + return 0; /* Success */ } @@ -614,13 +745,6 @@ /*IDirect3DDevice9_Clear (gpD3DDevice, 0, NULL, D3DCLEAR_TARGET, 0, 0, 0);*/ } -/** @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 @@ -656,40 +780,37 @@ */ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) { - D3DLOCKED_RECT stLockedRect; /**< Offscreen surface we lock in order - to copy MPlayer's frame inside it.*/ char *Src; /**< Pointer to the source image */ char *Dst; /**< Pointer to the destination image */ int UVstride; /**< Stride of the U/V planes */ - if (FAILED (IDirect3DDevice9_BeginScene(gpD3DDevice))) + if (gIsLocked == 0) { - mp_msg(MSGT_VO,MSGL_ERR,"BeginScene failed\n"); - return VO_ERROR; - } - if (FAILED (IDirect3DSurface9_LockRect(gpD3DSurface, - &stLockedRect, NULL, 0))) + &gLockedRect, NULL, 0))) { mp_msg(MSGT_VO,MSGL_V,"Surface lock failure\n"); return VO_FALSE; } - UVstride = stLockedRect.Pitch / 2; + gIsLocked = 1; /* Dont lock again! */ + } + + UVstride = gLockedRect.Pitch / 2; /* Copy Y */ - Dst = stLockedRect.pBits; - Dst = Dst + stLockedRect.Pitch * y + x; + Dst = gLockedRect.pBits; + Dst = Dst + gLockedRect.Pitch * y + x; Src=src[0]; - memcpy_pic(Dst, Src, w, h, stLockedRect.Pitch, stride[0]); + memcpy_pic(Dst, Src, w, h, gLockedRect.Pitch, stride[0]); w/=2;h/=2;x/=2;y/=2; /* Copy U */ - Dst = stLockedRect.pBits; - Dst = Dst + stLockedRect.Pitch * gSrcHeight + Dst = gLockedRect.pBits; + Dst = Dst + gLockedRect.Pitch * gSrcHeight + UVstride * y + x; - if (gMovieSrcFmt == MAKEFOURCC('Y','V','1','2')) + if (gpMovieSrcFmt->FourCC == MAKEFOURCC('Y','V','1','2')) Src=src[2]; else Src=src[1]; @@ -697,55 +818,77 @@ memcpy_pic(Dst, Src, w, h, UVstride, stride[1]); /* Copy V */ - Dst = stLockedRect.pBits; - Dst = Dst + stLockedRect.Pitch * gSrcHeight + Dst = gLockedRect.pBits; + Dst = Dst + gLockedRect.Pitch * gSrcHeight + UVstride * (gSrcHeight / 2) + UVstride * y + x; - if (gMovieSrcFmt == MAKEFOURCC('Y','V','1','2')) + if (gpMovieSrcFmt->FourCC == MAKEFOURCC('Y','V','1','2')) Src=src[1]; else Src=src[2]; memcpy_pic(Dst, Src, w, h, UVstride, stride[2]); - if (FAILED (IDirect3DSurface9_UnlockRect(gpD3DSurface))) - { - mp_msg(MSGT_VO,MSGL_V,"Surface unlock failure\n"); - return VO_ERROR; + return 0; /* Success */ } - if (FAILED (IDirect3DDevice9_StretchRect (gpD3DDevice, - gpD3DSurface, - gIsPanscan == 1 ? - &gPanScanSrcRect : NULL, - gpD3DBackBuf, - vo_fs == 1 ? - &gFullScrMovieRect : NULL, - D3DTEXF_LINEAR))) +/** @brief libvo Callback: Unused function + * @return N/A + */ +static int draw_frame(uint8_t *src[]) { - mp_msg(MSGT_VO,MSGL_V, - "Unable to copy the frame to the back buffer\n"); - return VO_ERROR; + mp_msg(MSGT_VO,MSGL_V,"draw_frame called\n"); + return VO_FALSE; } - if (FAILED (IDirect3DDevice9_EndScene(gpD3DDevice))) + +static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, + unsigned char *srca, int stride) { - mp_msg(MSGT_VO,MSGL_ERR,"EndScene failed\n"); - return VO_ERROR; + D3DLOCKED_RECT stLockedRect; /**< Offscreen surface we lock in order + to copy MPlayer's frame inside it.*/ + + if (FAILED (IDirect3DTexture9_LockRect(gpD3DTexture_SYSTEM, 0, + &stLockedRect, NULL, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR,"Surface lock failure (OSD)\n"); + return; } - return 0; /* Success */ + /* if mplayer has an asm clear then use this here instead, I couldn't see one */ + for (int j = 0; j < OSD_TEXTURE_SIZE; j++) + { + unsigned int * dst = (unsigned int *)((unsigned int)stLockedRect.pBits + (stLockedRect.Pitch * j)); + for (int i = 0; i < stLockedRect.Pitch/4; i++) + { + dst[i] = 0x00000000; + } } -/** @brief libvo Callback: Unused function - * @return N/A - */ -static int draw_frame(uint8_t *src[]) + vo_draw_alpha_rgb32(w,h,src,srca,stride, + (void *)((unsigned int)stLockedRect.pBits+stLockedRect.Pitch*y0+4*x0), stLockedRect.Pitch); + + /* this unlock is used for both slice_draw path and D3DRenderFrame path */ + if (FAILED (IDirect3DTexture9_UnlockRect(gpD3DTexture_SYSTEM, 0))) { - mp_msg(MSGT_VO,MSGL_V,"draw_frame called\n"); - return VO_FALSE; + mp_msg(MSGT_VO,MSGL_ERR,"texture unlock failure (OSD)\n"); + return; } + if (FAILED (IDirect3DDevice9_UpdateTexture(gpD3DDevice, gpD3DTexture_SYSTEM, gpD3DTexture_OSD))) + { + mp_msg(MSGT_VO,MSGL_ERR,"IDirect3DDevice9_UpdateTexture failure (OSD)\n"); + return; + } + gIsOSDUpdated = 1; +} +static void draw_osd(void) +{ + // calculate a width and height based on the OSD_TEXTURE_SIZE + float aspect = (float)gSrcWidth / gSrcHeight; + unsigned int calc_height = ((unsigned int)(OSD_TEXTURE_SIZE / aspect)); + vo_draw_text(OSD_TEXTURE_SIZE, calc_height, draw_alpha); +}