X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fmsw%2Fdirect3d.c;h=161693748e347c6cddb1782fd186f365bccb89de;hb=a0530f4ab42c5e9dbd1b21e5a44c95d208254c55;hp=7d385468c2b4c0b8540f180f3e649e2d31a71794;hpb=78d87996ccb92d1dc91c9987685f976ed3be08a6;p=vlc diff --git a/modules/video_output/msw/direct3d.c b/modules/video_output/msw/direct3d.c index 7d385468c2..161693748e 100644 --- a/modules/video_output/msw/direct3d.c +++ b/modules/video_output/msw/direct3d.c @@ -33,638 +33,436 @@ * effectively display the pictures. * *****************************************************************************/ -#include /* ENOMEM */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include -#include #include -#include +#include #include #include -#include "vout.h" +#include "common.h" /***************************************************************************** - * Local prototypes. + * Module descriptor *****************************************************************************/ -static int OpenVideo ( vlc_object_t * ); -static void CloseVideo ( vlc_object_t * ); +static int OpenVideoXP(vlc_object_t *); +static int OpenVideoVista(vlc_object_t *); +static void Close(vlc_object_t *); -static int Init ( vout_thread_t * ); -static void End ( vout_thread_t * ); -static int Manage ( vout_thread_t * ); -static void Display ( vout_thread_t *, picture_t * ); -static void FirstDisplay( vout_thread_t *, picture_t * ); +#define DESKTOP_TEXT N_("Enable desktop mode ") +#define DESKTOP_LONGTEXT N_(\ + "The desktop mode allows you to display the video on the desktop.") -static int Direct3DVoutCreate ( vout_thread_t * ); -static void Direct3DVoutRelease ( vout_thread_t * ); +#define D3D_HELP N_("Recommended video output for Windows Vista and later versions") -static int Direct3DVoutOpen ( vout_thread_t * ); -static void Direct3DVoutClose ( vout_thread_t * ); +vlc_module_begin () + set_shortname("Direct3D") + set_description(N_("Direct3D video output")) + set_help(D3D_HELP) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) -static int Direct3DVoutResetDevice( vout_thread_t * ); + add_bool("direct3d-desktop", false, NULL, DESKTOP_TEXT, DESKTOP_LONGTEXT, true) -static int Direct3DVoutCreatePictures ( vout_thread_t *, size_t ); -static void Direct3DVoutReleasePictures ( vout_thread_t * ); + set_capability("vout display", 150) + add_shortcut("direct3d") + set_callbacks(OpenVideoVista, Close) -static int Direct3DVoutLockSurface ( vout_thread_t *, picture_t * ); -static int Direct3DVoutUnlockSurface( vout_thread_t *, picture_t * ); + add_submodule() + set_description(N_("Direct3D video output (XP)")) + set_capability("vout display", 70) + add_shortcut("direct3d_xp") + set_callbacks(OpenVideoXP, Close) -static int Direct3DVoutCreateScene ( vout_thread_t * ); -static void Direct3DVoutReleaseScene ( vout_thread_t * ); -static void Direct3DVoutRenderScene ( vout_thread_t *, picture_t * ); +vlc_module_end () /***************************************************************************** - * Module descriptor + * Local prototypes. *****************************************************************************/ - -static bool IsVistaOrAbove(void) +struct picture_sys_t { - OSVERSIONINFO winVer; - winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + LPDIRECT3DSURFACE9 surface; +}; - if( GetVersionEx(&winVer) ) - { - if( winVer.dwMajorVersion > 5 ) - { - /* Windows Vista or above, make this module the default */ - return true; - } - } - /* Windows XP or lower, make sure this module isn't the default */ - return false; -} +static int Open(vlc_object_t *); -static int OpenVideoXP( vlc_object_t *obj ) -{ - return IsVistaOrAbove() ? VLC_EGENERIC : OpenVideo( obj ); -} +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Prepare(vout_display_t *, picture_t *); +static void Display(vout_display_t *, picture_t *); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); -static int OpenVideoVista( vlc_object_t *obj ) -{ - return IsVistaOrAbove() ? OpenVideo( obj ) : VLC_EGENERIC; -} +static int Direct3DCreate (vout_display_t *); +static int Direct3DReset (vout_display_t *); +static void Direct3DDestroy(vout_display_t *); -vlc_module_begin () - set_shortname( "Direct3D" ) - set_category( CAT_VIDEO ) - set_subcategory( SUBCAT_VIDEO_VOUT ) - set_description( N_("DirectX 3D video output") ) - set_capability( "video output", 50 ) - add_shortcut( "direct3d" ) - set_callbacks( OpenVideoXP, CloseVideo ) +static int Direct3DOpen (vout_display_t *, video_format_t *); +static void Direct3DClose(vout_display_t *); - /* FIXME: Hack to avoid unregistering our window class */ - linked_with_a_crap_library_which_uses_atexit () +static void Direct3DRenderScene(vout_display_t *vd, LPDIRECT3DSURFACE9 surface); - add_submodule() - set_capability( "video output", 150 ) - add_shortcut( "direct3d" ) - set_callbacks( OpenVideoVista, CloseVideo ) -vlc_module_end () - -#if 0 /* FIXME */ - /* check if we registered a window class because we need to - * unregister it */ - WNDCLASS wndclass; - if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) ) - UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) ); -#endif - -/***************************************************************************** - * CUSTOMVERTEX: - ***************************************************************************** - *****************************************************************************/ -typedef struct -{ - FLOAT x,y,z; // vertex untransformed position - FLOAT rhw; // eye distance - D3DCOLOR diffuse; // diffuse color - FLOAT tu, tv; // texture relative coordinates -} CUSTOMVERTEX; +/* */ +static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *); -#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) - -/***************************************************************************** - * OpenVideo: allocate Vout video thread output method - ***************************************************************************** - * This function allocates and initialize the Direct3D vout method. - *****************************************************************************/ -static int OpenVideo( vlc_object_t *p_this ) +/** + * It creates a Direct3D vout display. + */ +static int Open(vlc_object_t *object) { - vout_thread_t * p_vout = (vout_thread_t *)p_this; + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; /* Allocate structure */ - p_vout->p_sys = calloc( 1, sizeof( vout_sys_t ) ); - if( p_vout->p_sys == NULL ) + vd->sys = sys = calloc(1, sizeof(vout_display_sys_t)); + if (!sys) return VLC_ENOMEM; - if( VLC_SUCCESS != Direct3DVoutCreate( p_vout ) ) - { - msg_Err( p_vout, "Direct3D could not be initialized !"); - Direct3DVoutRelease( p_vout ); - free( p_vout->p_sys ); + if (Direct3DCreate(vd)) { + msg_Err(vd, "Direct3D could not be initialized"); + Direct3DDestroy(vd); + free(sys); return VLC_EGENERIC; } - /* Initialisations */ - p_vout->pf_init = Init; - p_vout->pf_end = End; - p_vout->pf_manage = Manage; - p_vout->pf_render = Direct3DVoutRenderScene; - p_vout->pf_display = FirstDisplay; - - p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL; - p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL; - p_vout->p_sys->i_changes = 0; - vlc_mutex_init( &p_vout->p_sys->lock ); - SetRectEmpty( &p_vout->p_sys->rect_display ); - SetRectEmpty( &p_vout->p_sys->rect_parent ); - - var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - - p_vout->p_sys->b_cursor_hidden = 0; - p_vout->p_sys->i_lastmoved = mdate(); - p_vout->p_sys->i_mouse_hide_timeout = - var_GetInteger(p_vout, "mouse-hide-timeout") * 1000; - - var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); - var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - - /* Set main window's size */ - p_vout->p_sys->i_window_width = p_vout->i_window_width; - p_vout->p_sys->i_window_height = p_vout->i_window_height; - - /* Create the Vout EventThread, this thread is created by us to isolate - * the Win32 PeekMessage function calls. We want to do this because - * Windows can stay blocked inside this call for a long time, and when - * this happens it thus blocks vlc's video_output thread. - * Vout EventThread will take care of the creation of the video - * window (because PeekMessage has to be called from the same thread which - * created the window). */ - msg_Dbg( p_vout, "creating Vout EventThread" ); - p_vout->p_sys->p_event = - vlc_object_create( p_vout, sizeof(event_thread_t) ); - p_vout->p_sys->p_event->p_vout = p_vout; - p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL ); - if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread", - EventThread, 0 ) ) - { - msg_Err( p_vout, "cannot create Vout EventThread" ); - CloseHandle( p_vout->p_sys->p_event->window_ready ); - vlc_object_release( p_vout->p_sys->p_event ); - p_vout->p_sys->p_event = NULL; + sys->use_desktop = var_CreateGetBool(vd, "direct3d-desktop"); + sys->reset_device = false; + sys->reset_device = false; + sys->allow_hw_yuv = var_CreateGetBool(vd, "directx-hw-yuv"); + sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen; + sys->desktop_save.is_on_top = false; + sys->desktop_save.win.left = var_InheritInteger(vd, "video-x"); + sys->desktop_save.win.right = vd->cfg->display.width; + sys->desktop_save.win.top = var_InheritInteger(vd, "video-y"); + sys->desktop_save.win.bottom = vd->cfg->display.height; + + if (CommonInit(vd)) goto error; - } - WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE ); - CloseHandle( p_vout->p_sys->p_event->window_ready ); - if( p_vout->p_sys->p_event->b_error ) - { - msg_Err( p_vout, "Vout EventThread failed" ); + /* */ + video_format_t fmt; + if (Direct3DOpen(vd, &fmt)) { + msg_Err(vd, "Direct3D could not be opened"); goto error; } - vlc_object_attach( p_vout->p_sys->p_event, p_vout ); - - msg_Dbg( p_vout, "Vout EventThread running" ); - - /* Variable to indicate if the window should be on top of others */ - /* Trigger a callback right now */ - var_TriggerCallback( p_vout, "video-on-top" ); + /* */ + vout_display_info_t info = vd->info; + info.is_slow = true; + info.has_double_click = true; + info.has_hide_mouse = false; + info.has_pictures_invalid = true; + info.has_event_thread = true; + + /* Interaction */ + vlc_mutex_init(&sys->lock); + sys->ch_desktop = false; + sys->desktop_requested = sys->use_desktop; + + vlc_value_t val; + val.psz_string = _("Desktop"); + var_Change(vd, "direct3d-desktop", VLC_VAR_SETTEXT, &val, NULL); + var_AddCallback(vd, "direct3d-desktop", DesktopCallback, NULL); + + /* Setup vout_display now that everything is fine */ + vd->fmt = fmt; + vd->info = info; + + vd->pool = Pool; + vd->prepare = Prepare; + vd->display = Display; + vd->control = Control; + vd->manage = Manage; + + /* Fix state in case of desktop mode */ + if (sys->use_desktop && vd->cfg->is_fullscreen) + vout_display_SendEventFullscreen(vd, false); - /* disable screensaver by temporarily changing system settings */ - p_vout->p_sys->i_spi_lowpowertimeout = 0; - p_vout->p_sys->i_spi_powerofftimeout = 0; - p_vout->p_sys->i_spi_screensavetimeout = 0; - if( var_GetBool( p_vout, "disable-screensaver" ) ) { - msg_Dbg(p_vout, "disabling screen saver"); - SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT, - 0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0); - if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) { - SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0); - } - SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0, - &(p_vout->p_sys->i_spi_powerofftimeout), 0); - if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) { - SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0); - } - SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, - &(p_vout->p_sys->i_spi_screensavetimeout), 0); - if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) { - SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0); - } - } return VLC_SUCCESS; - error: - CloseVideo( VLC_OBJECT(p_vout) ); + Direct3DClose(vd); + CommonClean(vd); + Direct3DDestroy(vd); + free(vd->sys); return VLC_EGENERIC; } -/***************************************************************************** - * CloseVideo: destroy Sys video thread output method - ***************************************************************************** - * Terminate an output method created by Create - *****************************************************************************/ -static void CloseVideo( vlc_object_t *p_this ) +static bool IsVistaOrAbove(void) { - vout_thread_t * p_vout = (vout_thread_t *)p_this; + OSVERSIONINFO winVer; + winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + return GetVersionEx(&winVer) && winVer.dwMajorVersion > 5; +} - Direct3DVoutRelease( p_vout ); +static int OpenVideoXP(vlc_object_t *obj) +{ + /* Windows XP or lower, make sure this module isn't the default */ + return IsVistaOrAbove() ? VLC_EGENERIC : Open(obj); +} - if( p_vout->b_fullscreen ) - { - msg_Dbg( p_vout, "Quitting fullscreen" ); - Win32ToggleFullscreen( p_vout ); - /* Force fullscreen in the core for the next video */ - var_SetBool( p_vout, "fullscreen", true ); - } +static int OpenVideoVista(vlc_object_t *obj) +{ + /* Windows Vista or above, make this module the default */ + return IsVistaOrAbove() ? Open(obj) : VLC_EGENERIC; +} - if( p_vout->p_sys->p_event ) - { - vlc_object_detach( p_vout->p_sys->p_event ); +/** + * It destroyes a Direct3D vout display. + */ +static void Close(vlc_object_t *object) +{ + vout_display_t * vd = (vout_display_t *)object; - /* Kill Vout EventThread */ - vlc_object_kill( p_vout->p_sys->p_event ); + var_DelCallback(vd, "direct3d-desktop", DesktopCallback, NULL); - /* we need to be sure Vout EventThread won't stay stuck in - * GetMessage, so we send a fake message */ - if( p_vout->p_sys->hwnd ) - { - PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0); - } + Direct3DClose(vd); - vlc_thread_join( p_vout->p_sys->p_event ); - vlc_object_release( p_vout->p_sys->p_event ); - } + CommonClean(vd); - vlc_mutex_destroy( &p_vout->p_sys->lock ); + Direct3DDestroy(vd); - /* restore screensaver system settings */ - if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) { - SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, - p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0); - } - if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) { - SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, - p_vout->p_sys->i_spi_powerofftimeout, NULL, 0); - } - if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) { - SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, - p_vout->p_sys->i_spi_screensavetimeout, NULL, 0); - } + free(vd->sys); +} - free( p_vout->p_sys ); - p_vout->p_sys = NULL; +/* */ +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) +{ + VLC_UNUSED(count); + return vd->sys->pool; } -/***************************************************************************** - * Init: initialize Direct3D video thread output method - *****************************************************************************/ -static int Init( vout_thread_t *p_vout ) +static int Direct3DLockSurface(picture_t *); +static void Direct3DUnlockSurface(picture_t *); + +static void Prepare(vout_display_t *vd, picture_t *picture) { - int i_ret; + LPDIRECT3DSURFACE9 surface = picture->p_sys->surface; +#if 0 + picture_Release(picture); + Direct3DRenderScene(vd, surface); +#else + /* FIXME it is a bit ugly, we need the surface to be unlocked for + * rendering. + * The clean way would be to release the picture (and ensure that + * the vout doesn't keep a reference). But because of the vout + * wrapper, we can't */ + + Direct3DUnlockSurface(picture); + + Direct3DRenderScene(vd, surface); + + Direct3DLockSurface(picture); +#endif +} - p_vout->p_sys->b_hw_yuv = var_GetBool( p_vout, "directx-hw-yuv" ); +static void Display(vout_display_t *vd, picture_t *picture) +{ + vout_display_sys_t *sys = vd->sys; + LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev; - /* Initialise Direct3D */ - if( VLC_SUCCESS != Direct3DVoutOpen( p_vout ) ) - { - msg_Err( p_vout, "cannot initialize Direct3D" ); - return VLC_EGENERIC; + // Present the back buffer contents to the display + // No stretching should happen here ! + const RECT src = sys->rect_dest_clipped; + const RECT dst = sys->rect_dest_clipped; + HRESULT hr = IDirect3DDevice9_Present(d3ddev, &src, &dst, NULL, NULL); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); } +#if 0 + VLC_UNUSED(picture); +#else + /* XXX See Prepare() */ + picture_Release(picture); +#endif - /* Initialize the output structure. - * Since Direct3D can do rescaling for us, stick to the default - * coordinates and aspect. */ - p_vout->output.i_width = p_vout->render.i_width; - p_vout->output.i_height = p_vout->render.i_height; - p_vout->output.i_aspect = p_vout->render.i_aspect; - p_vout->fmt_out = p_vout->fmt_in; - UpdateRects( p_vout, true ); - - /* create picture pool */ - p_vout->output.i_chroma = 0; - i_ret = Direct3DVoutCreatePictures(p_vout, 1); - if( VLC_SUCCESS != i_ret ) - { - msg_Err(p_vout, "Direct3D picture pool initialization failed !"); - return i_ret; - } + CommonDisplay(vd); +} +static int ControlResetDevice(vout_display_t *vd) +{ + return Direct3DReset(vd); +} +static int ControlReopenDevice(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + + if (!sys->use_desktop) { + /* Save non-desktop state */ + sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen; + sys->desktop_save.is_on_top = sys->is_on_top; - /* create scene */ - i_ret = Direct3DVoutCreateScene(p_vout); - if( VLC_SUCCESS != i_ret ) - { - msg_Err(p_vout, "Direct3D scene initialization failed !"); - Direct3DVoutReleasePictures(p_vout); - return i_ret; + WINDOWPLACEMENT wp = { .length = sizeof(wp), }; + GetWindowPlacement(sys->hparent ? sys->hparent : sys->hwnd, &wp); + sys->desktop_save.win = wp.rcNormalPosition; } - /* Change the window title bar text */ - PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 ); + /* */ + Direct3DClose(vd); + EventThreadStop(sys->event); + + /* */ + vlc_mutex_lock(&sys->lock); + sys->use_desktop = sys->desktop_requested; + sys->ch_desktop = false; + vlc_mutex_unlock(&sys->lock); + + /* */ + event_cfg_t cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.use_desktop = sys->use_desktop; + if (!sys->use_desktop) { + cfg.win.type = VOUT_WINDOW_TYPE_HWND; + cfg.win.x = sys->desktop_save.win.left; + cfg.win.y = sys->desktop_save.win.top; + cfg.win.width = sys->desktop_save.win.right - sys->desktop_save.win.left; + cfg.win.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top; + } - p_vout->fmt_out.i_chroma = p_vout->output.i_chroma; + event_hwnd_t hwnd; + if (EventThreadStart(sys->event, &hwnd, &cfg)) { + msg_Err(vd, "Failed to restart event thread"); + return VLC_EGENERIC; + } + sys->parent_window = hwnd.parent_window; + sys->hparent = hwnd.hparent; + sys->hwnd = hwnd.hwnd; + sys->hvideownd = hwnd.hvideownd; + sys->hfswnd = hwnd.hfswnd; + SetRectEmpty(&sys->rect_parent); + + /* */ + video_format_t fmt; + if (Direct3DOpen(vd, &fmt)) { + CommonClean(vd); + msg_Err(vd, "Failed to reopen device"); + return VLC_EGENERIC; + } + vd->fmt = fmt; + sys->is_first_display = true; + + if (sys->use_desktop) { + /* Disable fullscreen/on_top while using desktop */ + if (sys->desktop_save.is_fullscreen) + vout_display_SendEventFullscreen(vd, false); + if (sys->desktop_save.is_on_top) + vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_NORMAL); + } else { + /* Restore fullscreen/on_top */ + if (sys->desktop_save.is_fullscreen) + vout_display_SendEventFullscreen(vd, true); + if (sys->desktop_save.is_on_top) + vout_display_SendWindowState(vd, VOUT_WINDOW_STATE_ABOVE); + } return VLC_SUCCESS; } - -/***************************************************************************** - * End: terminate Sys video thread output method - ***************************************************************************** - * Terminate an output method created by Create. - * It is called at the end of the thread. - *****************************************************************************/ -static void End( vout_thread_t *p_vout ) +static int Control(vout_display_t *vd, int query, va_list args) { - Direct3DVoutReleaseScene(p_vout); - Direct3DVoutReleasePictures(p_vout); - Direct3DVoutClose( p_vout ); + vout_display_sys_t *sys = vd->sys; + + switch (query) { + case VOUT_DISPLAY_RESET_PICTURES: + /* FIXME what to do here in case of failure */ + if (sys->reset_device) { + if (ControlResetDevice(vd)) { + msg_Err(vd, "Failed to reset device"); + return VLC_EGENERIC; + } + sys->reset_device = false; + } else if(sys->reopen_device) { + if (ControlReopenDevice(vd)) { + msg_Err(vd, "Failed to reopen device"); + return VLC_EGENERIC; + } + sys->reopen_device = false; + } + return VLC_SUCCESS; + default: + return CommonControl(vd, query, args); + } } - -/***************************************************************************** - * Manage: handle Sys events - ***************************************************************************** - * This function should be called regularly by the video output thread. - * It returns a non null value if an error occurred. - *****************************************************************************/ -static int Manage( vout_thread_t *p_vout ) +static void Manage (vout_display_t *vd) { - /* If we do not control our window, we check for geometry changes - * ourselves because the parent might not send us its events. */ - vlc_mutex_lock( &p_vout->p_sys->lock ); - if( p_vout->p_sys->hparent && !p_vout->b_fullscreen ) - { - RECT rect_parent; - POINT point; - - vlc_mutex_unlock( &p_vout->p_sys->lock ); - - GetClientRect( p_vout->p_sys->hparent, &rect_parent ); - point.x = point.y = 0; - ClientToScreen( p_vout->p_sys->hparent, &point ); - OffsetRect( &rect_parent, point.x, point.y ); - - if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) ) - { - p_vout->p_sys->rect_parent = rect_parent; + vout_display_sys_t *sys = vd->sys; - SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, - rect_parent.right - rect_parent.left, - rect_parent.bottom - rect_parent.top, - SWP_NOZORDER ); - } - } - else - { - vlc_mutex_unlock( &p_vout->p_sys->lock ); + CommonManage(vd); + + /* Desktop mode change */ + vlc_mutex_lock(&sys->lock); + const bool ch_desktop = sys->ch_desktop; + sys->ch_desktop = false; + vlc_mutex_unlock(&sys->lock); + + if (ch_desktop) { + sys->reopen_device = true; + vout_display_SendEventPicturesInvalid(vd); } +#if 0 /* * Position Change */ - if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE ) - { + if (sys->changes & DX_POSITION_CHANGE) { #if 0 /* need that when bicubic filter is available */ RECT rect; UINT width, height; - GetClientRect(p_vout->p_sys->hvideownd, &rect); + GetClientRect(p_sys->hvideownd, &rect); width = rect.right-rect.left; height = rect.bottom-rect.top; - if( (width != p_vout->p_sys->d3dpp.BackBufferWidth) - || (height != p_vout->p_sys->d3dpp.BackBufferHeight) ) + if (width != p_sys->d3dpp.BackBufferWidth || height != p_sys->d3dpp.BackBufferHeight) { - msg_Dbg(p_vout, "resizing device back buffers to (%lux%lu)", width, height); + msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height); // need to reset D3D device to resize back buffer - if( VLC_SUCCESS != Direct3DVoutResetDevice(p_vout, width, height) ) + if (VLC_SUCCESS != Direct3DResetDevice(vd, width, height)) return VLC_EGENERIC; } #endif - p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE; - } - - /* autoscale toggle */ - if( p_vout->i_changes & VOUT_SCALE_CHANGE ) - { - p_vout->i_changes &= ~VOUT_SCALE_CHANGE; - - p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" ); - p_vout->i_zoom = (int) ZOOM_FP_FACTOR; - - UpdateRects( p_vout, true ); - } - - /* scaling factor */ - if( p_vout->i_changes & VOUT_ZOOM_CHANGE ) - { - p_vout->i_changes &= ~VOUT_ZOOM_CHANGE; - - p_vout->b_autoscale = false; - p_vout->i_zoom = - (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) ); - UpdateRects( p_vout, true ); - } - - /* Check for cropping / aspect changes */ - if( p_vout->i_changes & VOUT_CROP_CHANGE || - p_vout->i_changes & VOUT_ASPECT_CHANGE ) - { - p_vout->i_changes &= ~VOUT_CROP_CHANGE; - p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; - - p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset; - p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset; - p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width; - p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height; - p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect; - p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num; - p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den; - p_vout->output.i_aspect = p_vout->fmt_in.i_aspect; - UpdateRects( p_vout, true ); - } - - /* We used to call the Win32 PeekMessage function here to read the window - * messages. But since window can stay blocked into this function for a - * long time (for example when you move your window on the screen), I - * decided to isolate PeekMessage in another thread. */ - - /* - * Fullscreen change - */ - if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE - || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) - { - Win32ToggleFullscreen( p_vout ); - - p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; - p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; - } - - /* - * Pointer change - */ - if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden && - (mdate() - p_vout->p_sys->i_lastmoved) > - p_vout->p_sys->i_mouse_hide_timeout ) - { - POINT point; - HWND hwnd; - - /* Hide the cursor only if it is inside our window */ - GetCursorPos( &point ); - hwnd = WindowFromPoint(point); - if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd ) - { - PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 ); - } - else - { - p_vout->p_sys->i_lastmoved = mdate(); - } - } - - /* - * "Always on top" status change - */ - if( p_vout->p_sys->b_on_top_change ) - { - vlc_value_t val; - HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE ); - - var_Get( p_vout, "video-on-top", &val ); - - /* Set the window on top if necessary */ - if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) - & WS_EX_TOPMOST ) ) - { - CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, - MF_BYCOMMAND | MFS_CHECKED ); - SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE ); - } - else - /* The window shouldn't be on top */ - if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) - & WS_EX_TOPMOST ) ) - { - CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, - MF_BYCOMMAND | MFS_UNCHECKED ); - SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE ); - } - - p_vout->p_sys->b_on_top_change = false; + sys->changes &= ~DX_POSITION_CHANGE; } - - /* Check if the event thread is still running */ - if( !vlc_object_alive (p_vout->p_sys->p_event) ) - { - return VLC_EGENERIC; /* exit */ - } - - return VLC_SUCCESS; -} - -/***************************************************************************** - * Display: displays previously rendered output - ***************************************************************************** - * This function sends the currently rendered image to the display, wait until - * it is displayed and switch the two rendering buffers, preparing next frame. - *****************************************************************************/ -static void Display( vout_thread_t *p_vout, picture_t *p_pic ) -{ - LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev; - // Present the back buffer contents to the display - // stretching and filtering happens here - HRESULT hr = IDirect3DDevice9_Present(p_d3ddev, - &(p_vout->p_sys->rect_src_clipped), - NULL, NULL, NULL); - if( FAILED(hr) ) - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); -} - -/* -** this function is only used once when the first picture is received -** this function will show the video window once a picture is ready -*/ - -static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic ) -{ - /* get initial picture presented through D3D */ - Display(p_vout, p_pic); - - /* - ** Video window is initially hidden, show it now since we got a - ** picture to show. - */ - SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0, - SWP_ASYNCWINDOWPOS| - SWP_FRAMECHANGED| - SWP_SHOWWINDOW| - SWP_NOMOVE| - SWP_NOSIZE| - SWP_NOZORDER ); - - /* use and restores proper display function for further pictures */ - p_vout->pf_display = Display; +#endif } -/***************************************************************************** - * DirectD3DVoutCreate: Initialize and instance of Direct3D9 - ***************************************************************************** - * This function initialize Direct3D and analyze available resources from - * default adapter. - *****************************************************************************/ -static int Direct3DVoutCreate( vout_thread_t *p_vout ) +/** + * It initializes an instance of Direct3D9 + */ +static int Direct3DCreate(vout_display_t *vd) { - HRESULT hr; - LPDIRECT3D9 p_d3dobj; - D3DCAPS9 d3dCaps; - - LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion); + vout_display_sys_t *sys = vd->sys; - p_vout->p_sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL")); - if( NULL == p_vout->p_sys->hd3d9_dll ) - { - msg_Warn( p_vout, "cannot load d3d9.dll, aborting" ); + sys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL")); + if (!sys->hd3d9_dll) { + msg_Warn(vd, "cannot load d3d9.dll, aborting"); return VLC_EGENERIC; } + LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion); OurDirect3DCreate9 = - (void *)GetProcAddress( p_vout->p_sys->hd3d9_dll, - TEXT("Direct3DCreate9") ); - if( OurDirect3DCreate9 == NULL ) - { - msg_Err( p_vout, "Cannot locate reference to Direct3DCreate9 ABI in DLL" ); + (void *)GetProcAddress(sys->hd3d9_dll, TEXT("Direct3DCreate9")); + if (!OurDirect3DCreate9) { + msg_Err(vd, "Cannot locate reference to Direct3DCreate9 ABI in DLL"); return VLC_EGENERIC; } /* Create the D3D object. */ - p_d3dobj = OurDirect3DCreate9( D3D_SDK_VERSION ); - if( NULL == p_d3dobj ) - { - msg_Err( p_vout, "Could not create Direct3D9 instance."); + LPDIRECT3D9 d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION); + if (!d3dobj) { + msg_Err(vd, "Could not create Direct3D9 instance."); return VLC_EGENERIC; } - p_vout->p_sys->p_d3dobj = p_d3dobj; + sys->d3dobj = d3dobj; /* ** Get device capabilities */ + D3DCAPS9 d3dCaps; ZeroMemory(&d3dCaps, sizeof(d3dCaps)); - hr = IDirect3D9_GetDeviceCaps(p_d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps); - if( FAILED(hr) ) - { - msg_Err( p_vout, "Could not read adapter capabilities. (hr=0x%lX)", hr); + HRESULT hr = IDirect3D9_GetDeviceCaps(d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps); + if (FAILED(hr)) { + msg_Err(vd, "Could not read adapter capabilities. (hr=0x%lX)", hr); return VLC_EGENERIC; } /* TODO: need to test device capabilities and select the right render function */ @@ -672,51 +470,53 @@ static int Direct3DVoutCreate( vout_thread_t *p_vout ) return VLC_SUCCESS; } -/***************************************************************************** - * DirectD3DVoutRelease: release an instance of Direct3D9 - *****************************************************************************/ - -static void Direct3DVoutRelease( vout_thread_t *p_vout ) +/** + * It releases an instance of Direct3D9 + */ +static void Direct3DDestroy(vout_display_t *vd) { - if( p_vout->p_sys->p_d3dobj ) - { - IDirect3D9_Release(p_vout->p_sys->p_d3dobj); - p_vout->p_sys->p_d3dobj = NULL; - } - if( NULL != p_vout->p_sys->hd3d9_dll ) - { - FreeLibrary(p_vout->p_sys->hd3d9_dll); - p_vout->p_sys->hd3d9_dll = NULL; - } + vout_display_sys_t *sys = vd->sys; + + if (sys->d3dobj) + IDirect3D9_Release(sys->d3dobj); + if (sys->hd3d9_dll) + FreeLibrary(sys->hd3d9_dll); + + sys->d3dobj = NULL; + sys->hd3d9_dll = NULL; } -static int Direct3DFillPresentationParameters(vout_thread_t *p_vout, D3DPRESENT_PARAMETERS *d3dpp) + +/** + * It setup vout_display_sys_t::d3dpp and vout_display_sys_t::rect_display + * from the default adapter. + */ +static int Direct3DFillPresentationParameters(vout_display_t *vd) { - LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj; - D3DDISPLAYMODE d3ddm; - HRESULT hr; + vout_display_sys_t *sys = vd->sys; /* ** Get the current desktop display mode, so we can set up a back ** buffer of the same format */ - hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm ); - if( FAILED(hr)) - { - msg_Err( p_vout, "Could not read adapter display mode. (hr=0x%lX)", hr); + D3DDISPLAYMODE d3ddm; + HRESULT hr = IDirect3D9_GetAdapterDisplayMode(sys->d3dobj, + D3DADAPTER_DEFAULT, &d3ddm); + if (FAILED(hr)) { + msg_Err(vd, "Could not read adapter display mode. (hr=0x%lX)", hr); return VLC_EGENERIC; } - /* keep a copy of current desktop format */ - p_vout->p_sys->bbFormat = d3ddm.Format; - /* Set up the structure used to create the D3DDevice. */ - ZeroMemory( d3dpp, sizeof(D3DPRESENT_PARAMETERS) ); + D3DPRESENT_PARAMETERS *d3dpp = &vd->sys->d3dpp; + ZeroMemory(d3dpp, sizeof(D3DPRESENT_PARAMETERS)); d3dpp->Flags = D3DPRESENTFLAG_VIDEO; d3dpp->Windowed = TRUE; - d3dpp->hDeviceWindow = p_vout->p_sys->hvideownd; - d3dpp->BackBufferWidth = p_vout->output.i_width; - d3dpp->BackBufferHeight = p_vout->output.i_height; + d3dpp->hDeviceWindow = vd->sys->hvideownd; + d3dpp->BackBufferWidth = __MAX(GetSystemMetrics(SM_CXVIRTUALSCREEN), + d3ddm.Width); + d3dpp->BackBufferHeight = __MAX(GetSystemMetrics(SM_CYVIRTUALSCREEN), + d3ddm.Height); d3dpp->SwapEffect = D3DSWAPEFFECT_COPY; d3dpp->MultiSampleType = D3DMULTISAMPLE_NONE; d3dpp->PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; @@ -724,744 +524,602 @@ static int Direct3DFillPresentationParameters(vout_thread_t *p_vout, D3DPRESENT_ d3dpp->BackBufferCount = 1; d3dpp->EnableAutoDepthStencil = FALSE; + /* */ + RECT *display = &vd->sys->rect_display; + display->left = 0; + display->top = 0; + display->right = d3dpp->BackBufferWidth; + display->bottom = d3dpp->BackBufferHeight; + return VLC_SUCCESS; } -/***************************************************************************** - * DirectD3DVoutOpen: Takes care of all the Direct3D9 initialisations - ***************************************************************************** - * This function creates Direct3D device - * this must be called from the vout thread for performance reason, as - * all Direct3D Device APIs are used in a non multithread safe environment - *****************************************************************************/ -static int Direct3DVoutOpen( vout_thread_t *p_vout ) +/* */ +static int Direct3DCreateResources (vout_display_t *, video_format_t *); +static void Direct3DDestroyResources(vout_display_t *); + +/** + * It creates a Direct3D device and the associated resources. + */ +static int Direct3DOpen(vout_display_t *vd, video_format_t *fmt) { - LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj; - LPDIRECT3DDEVICE9 p_d3ddev; - D3DPRESENT_PARAMETERS d3dpp; - HRESULT hr; + vout_display_sys_t *sys = vd->sys; + LPDIRECT3D9 d3dobj = sys->d3dobj; - if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) ) + if (Direct3DFillPresentationParameters(vd)) return VLC_EGENERIC; // Create the D3DDevice - hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING| - D3DCREATE_MULTITHREADED, - &d3dpp, &p_d3ddev ); - if( FAILED(hr) ) - { - msg_Err(p_vout, "Could not create the D3D device! (hr=0x%lX)", hr); + LPDIRECT3DDEVICE9 d3ddev; + HRESULT hr = IDirect3D9_CreateDevice(d3dobj, D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, sys->hvideownd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING| + D3DCREATE_MULTITHREADED, + &sys->d3dpp, &d3ddev); + if (FAILED(hr)) { + msg_Err(vd, "Could not create the D3D device! (hr=0x%lX)", hr); return VLC_EGENERIC; } - p_vout->p_sys->p_d3ddev = p_d3ddev; + sys->d3ddev = d3ddev; - msg_Dbg( p_vout, "Direct3D device adapter successfully initialized" ); + UpdateRects(vd, NULL, NULL, true); + + if (Direct3DCreateResources(vd, fmt)) { + msg_Err(vd, "Failed to allocate resources"); + return VLC_EGENERIC; + } + + /* Change the window title bar text */ + EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct3D output)"); + + msg_Dbg(vd, "Direct3D device adapter successfully initialized"); return VLC_SUCCESS; } -/***************************************************************************** - * DirectD3DClose: release the Direct3D9 device - *****************************************************************************/ -static void Direct3DVoutClose( vout_thread_t *p_vout ) +/** + * It releases the Direct3D9 device and its resources. + */ +static void Direct3DClose(vout_display_t *vd) { - if( p_vout->p_sys->p_d3ddev ) - { - IDirect3DDevice9_Release(p_vout->p_sys->p_d3ddev); - p_vout->p_sys->p_d3ddev = NULL; - } + vout_display_sys_t *sys = vd->sys; + + Direct3DDestroyResources(vd); + + if (sys->d3ddev) + IDirect3DDevice9_Release(sys->d3ddev); - p_vout->p_sys->hmonitor = NULL; + sys->d3ddev = NULL; } -/***************************************************************************** - * DirectD3DClose: reset the Direct3D9 device - ***************************************************************************** - * All resources must be deallocated before the reset occur, they will be - * realllocated once the reset has been performed successfully - *****************************************************************************/ -static int Direct3DVoutResetDevice( vout_thread_t *p_vout ) +/** + * It reset the Direct3D9 device and its resources. + */ +static int Direct3DReset(vout_display_t *vd) { - LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev; - D3DPRESENT_PARAMETERS d3dpp; - HRESULT hr; + vout_display_sys_t *sys = vd->sys; + LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev; - if( VLC_SUCCESS != Direct3DFillPresentationParameters(p_vout, &d3dpp) ) + if (Direct3DFillPresentationParameters(vd)) return VLC_EGENERIC; - // release all D3D objects - Direct3DVoutReleaseScene( p_vout ); - Direct3DVoutReleasePictures( p_vout ); + /* release all D3D objects */ + Direct3DDestroyResources(vd); - hr = IDirect3DDevice9_Reset(p_d3ddev, &d3dpp); - if( SUCCEEDED(hr) ) - { - // re-create them - if( (VLC_SUCCESS != Direct3DVoutCreatePictures(p_vout, 1)) - || (VLC_SUCCESS != Direct3DVoutCreateScene(p_vout)) ) - { - msg_Dbg(p_vout, "%s failed !", __FUNCTION__); - return VLC_EGENERIC; - } + /* */ + HRESULT hr = IDirect3DDevice9_Reset(d3ddev, &sys->d3dpp); + if (FAILED(hr)) { + msg_Err(vd, "%s failed ! (hr=%08lX)", __FUNCTION__, hr); + return VLC_EGENERIC; } - else { - msg_Err(p_vout, "%s failed ! (hr=%08lX)", __FUNCTION__, hr); + + UpdateRects(vd, NULL, NULL, true); + + /* re-create them */ + if (Direct3DCreateResources(vd, &vd->fmt)) { + msg_Dbg(vd, "%s failed !", __FUNCTION__); return VLC_EGENERIC; } return VLC_SUCCESS; } -static D3DFORMAT Direct3DVoutSelectFormat( vout_thread_t *p_vout, D3DFORMAT target, - const D3DFORMAT *formats, size_t count) -{ - LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj; - size_t c; - - for( c=0; cp_sys->b_hw_yuv && ! _got_vista_or_above ) - if( p_vout->p_sys->b_hw_yuv ) - { - /* it sounds like vista does not support YUV surfaces at all */ - switch( i_chroma ) - { - case VLC_CODEC_UYVY: - { - static const D3DFORMAT formats[] = - { D3DFMT_UYVY, D3DFMT_YUY2, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - case VLC_CODEC_I420: - case VLC_CODEC_I422: - case VLC_CODEC_YV12: - { - /* typically 3D textures don't support planar format - ** fallback to packed version and use CPU for the conversion - */ - static const D3DFORMAT formats[] = - { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - case VLC_CODEC_YUYV: - { - static const D3DFORMAT formats[] = - { D3DFMT_YUY2, D3DFMT_UYVY, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - } + if (Direct3DCreatePool(vd, fmt)) { + msg_Err(vd, "Direct3D picture pool initialization failed"); + return VLC_EGENERIC; } - - switch( i_chroma ) - { - case VLC_CODEC_RGB15: - { - static const D3DFORMAT formats[] = - { D3DFMT_X1R5G5B5 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - case VLC_CODEC_RGB16: - { - static const D3DFORMAT formats[] = - { D3DFMT_R5G6B5 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - case VLC_CODEC_RGB24: - { - static const D3DFORMAT formats[] = - { D3DFMT_R8G8B8, D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - case VLC_CODEC_RGB32: - { - static const D3DFORMAT formats[] = - { D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8 }; - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - default: - { - /* use display default format */ - LPDIRECT3D9 p_d3dobj = p_vout->p_sys->p_d3dobj; - D3DDISPLAYMODE d3ddm; - - HRESULT hr = IDirect3D9_GetAdapterDisplayMode(p_d3dobj, D3DADAPTER_DEFAULT, &d3ddm ); - if( SUCCEEDED(hr)) - { - /* - ** some professional cards could use some advanced pixel format as default, - ** make sure we stick with chromas that we can handle internally - */ - switch( d3ddm.Format ) - { - case D3DFMT_R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - msg_Dbg( p_vout, "defaulting to adapter pixel format"); - return Direct3DVoutSelectFormat(p_vout, target, &d3ddm.Format, 1); - default: - { - /* if we fall here, that probably means that we need to render some YUV format */ - static const D3DFORMAT formats[] = - { D3DFMT_X8R8G8B8, D3DFMT_A8R8G8B8, D3DFMT_R5G6B5, D3DFMT_X1R5G5B5 }; - msg_Dbg( p_vout, "defaulting to built-in pixel format"); - return Direct3DVoutSelectFormat(p_vout, target, formats, sizeof(formats)/sizeof(D3DFORMAT)); - } - } - } - } + if (Direct3DCreateScene(vd)) { + msg_Err(vd, "Direct3D scene initialization failed !"); + return VLC_EGENERIC; } - return D3DFMT_UNKNOWN; + return VLC_SUCCESS; } - -static int Direct3DVoutSetOutputFormat(vout_thread_t *p_vout, D3DFORMAT format) +/** + * It destroys the picture and scene resources. + */ +static void Direct3DDestroyResources(vout_display_t *vd) { - switch( format ) - { - case D3DFMT_YUY2: - p_vout->output.i_chroma = VLC_CODEC_YUYV; - break; - case D3DFMT_UYVY: - p_vout->output.i_chroma = VLC_CODEC_UYVY; - break; - case D3DFMT_R8G8B8: - p_vout->output.i_chroma = VLC_CODEC_RGB24; - p_vout->output.i_rmask = 0xff0000; - p_vout->output.i_gmask = 0x00ff00; - p_vout->output.i_bmask = 0x0000ff; - break; - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - p_vout->output.i_chroma = VLC_CODEC_RGB32; - p_vout->output.i_rmask = 0x00ff0000; - p_vout->output.i_gmask = 0x0000ff00; - p_vout->output.i_bmask = 0x000000ff; - break; - case D3DFMT_R5G6B5: - p_vout->output.i_chroma = VLC_CODEC_RGB16; - p_vout->output.i_rmask = (0x1fL)<<11; - p_vout->output.i_gmask = (0x3fL)<<5; - p_vout->output.i_bmask = (0x1fL)<<0; - break; - case D3DFMT_X1R5G5B5: - p_vout->output.i_chroma = VLC_CODEC_RGB15; - p_vout->output.i_rmask = (0x1fL)<<10; - p_vout->output.i_gmask = (0x1fL)<<5; - p_vout->output.i_bmask = (0x1fL)<<0; - break; - default: - return VLC_EGENERIC; - } - return VLC_SUCCESS; + Direct3DDestroyScene(vd); + Direct3DDestroyPool(vd); } -/***************************************************************************** - * Direct3DVoutCreatePictures: allocate a vector of identical pictures - ***************************************************************************** - * Each picture has an associated offscreen surface in video memory - * depending on hardware capabilities the picture chroma will be as close - * as possible to the orginal render chroma to reduce CPU conversion overhead - * and delegate this work to video card GPU - *****************************************************************************/ -static int Direct3DVoutCreatePictures( vout_thread_t *p_vout, size_t i_num_pics ) +/** + * It tests if the conversion from src to dst is supported. + */ +static int Direct3DCheckConversion(vout_display_t *vd, + D3DFORMAT src, D3DFORMAT dst) { - LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev; - D3DFORMAT format; + vout_display_sys_t *sys = vd->sys; + LPDIRECT3D9 d3dobj = sys->d3dobj; HRESULT hr; - size_t c; - // if vout is already running, use current chroma, otherwise choose from upstream - int i_chroma = p_vout->output.i_chroma ? p_vout->output.i_chroma - : p_vout->render.i_chroma; - - I_OUTPUTPICTURES = 0; - /* - ** find the appropriate D3DFORMAT for the render chroma, the format will be the closest to - ** the requested chroma which is usable by the hardware in an offscreen surface, as they - ** typically support more formats than textures - */ - format = Direct3DVoutFindFormat(p_vout, i_chroma, p_vout->p_sys->bbFormat); - if( VLC_SUCCESS != Direct3DVoutSetOutputFormat(p_vout, format) ) - { - msg_Err(p_vout, "surface pixel format is not supported."); + /* test whether device can create a surface of that format */ + hr = IDirect3D9_CheckDeviceFormat(d3dobj, D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, dst, 0, + D3DRTYPE_SURFACE, src); + if (SUCCEEDED(hr)) { + /* test whether device can perform color-conversion + ** from that format to target format + */ + hr = IDirect3D9_CheckDeviceFormatConversion(d3dobj, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + src, dst); + } + if (!SUCCEEDED(hr)) { + if (D3DERR_NOTAVAILABLE != hr) + msg_Err(vd, "Could not query adapter supported formats. (hr=0x%lX)", hr); return VLC_EGENERIC; } + return VLC_SUCCESS; +} - for( c=0; csys; - LPDIRECT3DSURFACE9 p_d3dsurf; - picture_t *p_pic = p_vout->p_picture+c; + for (unsigned pass = 0; pass < 2; pass++) { + const vlc_fourcc_t *list; - hr = IDirect3DDevice9_CreateOffscreenPlainSurface(p_d3ddev, - p_vout->render.i_width, - p_vout->render.i_height, - format, - D3DPOOL_DEFAULT, - &p_d3dsurf, - NULL); - if( FAILED(hr) ) - { - msg_Err(p_vout, "Failed to create picture surface. (hr=0x%lx)", hr); - Direct3DVoutReleasePictures(p_vout); - return VLC_EGENERIC; - } + if (pass == 0 && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma)) + list = vlc_fourcc_GetYUVFallback(chroma); + else if (pass == 1) + list = vlc_fourcc_GetRGBFallback(chroma); + else + continue; - /* fill surface with black color */ - IDirect3DDevice9_ColorFill(p_d3ddev, p_d3dsurf, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0) ); + for (unsigned i = 0; list[i] != 0; i++) { + for (unsigned j = 0; d3d_formats[j].name; j++) { + const d3d_format_t *format = &d3d_formats[j]; - /* assign surface to internal structure */ - p_pic->p_sys = (void *)p_d3dsurf; + if (format->fourcc != list[i]) + continue; - /* Now that we've got our direct-buffer, we can finish filling in the - * picture_t structures */ - switch( p_vout->output.i_chroma ) - { - case VLC_CODEC_RGB8: - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pixel_pitch = 1; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - break; - case VLC_CODEC_RGB15: - case VLC_CODEC_RGB16: - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pixel_pitch = 2; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - break; - case VLC_CODEC_RGB24: - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pixel_pitch = 3; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - break; - case VLC_CODEC_RGB32: - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pixel_pitch = 4; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - break; - case VLC_CODEC_UYVY: - case VLC_CODEC_YUYV: - p_pic->p->i_lines = p_vout->output.i_height; - p_pic->p->i_visible_lines = p_vout->output.i_height; - p_pic->p->i_pixel_pitch = 2; - p_pic->p->i_visible_pitch = p_vout->output.i_width * - p_pic->p->i_pixel_pitch; - p_pic->i_planes = 1; - break; - default: - Direct3DVoutReleasePictures(p_vout); - return VLC_EGENERIC; + msg_Warn(vd, "trying surface pixel format: %s", + format->name); + if (!Direct3DCheckConversion(vd, format->format, target)) { + msg_Dbg(vd, "selected surface pixel format is %s", + format->name); + return format; + } + } } - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; - p_pic->b_slow = true; - p_pic->pf_lock = Direct3DVoutLockSurface; - p_pic->pf_unlock = Direct3DVoutUnlockSurface; - PP_OUTPUTPICTURE[c] = p_pic; - - I_OUTPUTPICTURES = ++c; } + return NULL; +} - msg_Dbg( p_vout, "%u Direct3D pictures created successfully", c ); +/** + * It locks the surface associated to the picture and get the surface + * descriptor which amongst other things has the pointer to the picture + * data and its pitch. + */ +static int Direct3DLockSurface(picture_t *picture) +{ + /* Lock the surface to get a valid pointer to the picture buffer */ + D3DLOCKED_RECT d3drect; + HRESULT hr = IDirect3DSurface9_LockRect(picture->p_sys->surface, &d3drect, NULL, 0); + if (FAILED(hr)) { + //msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + return VLC_EGENERIC; + } + CommonUpdatePicture(picture, d3drect.pBits, d3drect.Pitch); return VLC_SUCCESS; } - -/***************************************************************************** - * Direct3DVoutReleasePictures: destroy a picture vector - ***************************************************************************** - * release all video resources used for pictures - *****************************************************************************/ -static void Direct3DVoutReleasePictures( vout_thread_t *p_vout) +/** + * It unlocks the surface associated to the picture. + */ +static void Direct3DUnlockSurface(picture_t *picture) { - size_t i_num_pics = I_OUTPUTPICTURES; - size_t c; - for( c=0; cp_picture+c; - if( p_pic->p_sys ) - { - LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys; - - p_pic->p_sys = NULL; - - if( p_d3dsurf ) - { - IDirect3DSurface9_Release(p_d3dsurf); - } - } + /* Unlock the Surface */ + HRESULT hr = IDirect3DSurface9_UnlockRect(picture->p_sys->surface); + if (FAILED(hr)) { + //msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); } - msg_Dbg( p_vout, "%u Direct3D pictures released.", c); - - I_OUTPUTPICTURES = 0; } -/***************************************************************************** - * Direct3DVoutLockSurface: Lock surface and get picture data pointer - ***************************************************************************** - * This function locks a surface and get the surface descriptor which amongst - * other things has the pointer to the picture data. - *****************************************************************************/ -static int Direct3DVoutLockSurface( vout_thread_t *p_vout, picture_t *p_pic ) +/** + * It creates the pool of picture (only 1). + * + * Each picture has an associated offscreen surface in video memory + * depending on hardware capabilities the picture chroma will be as close + * as possible to the orginal render chroma to reduce CPU conversion overhead + * and delegate this work to video card GPU + */ +static int Direct3DCreatePool(vout_display_t *vd, video_format_t *fmt) { - HRESULT hr; - D3DLOCKED_RECT d3drect; - LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys; - - if( NULL == p_d3dsurf ) + vout_display_sys_t *sys = vd->sys; + LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev; + + /* */ + *fmt = vd->source; + + /* Find the appropriate D3DFORMAT for the render chroma, the format will be the closest to + * the requested chroma which is usable by the hardware in an offscreen surface, as they + * typically support more formats than textures */ + const d3d_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, sys->d3dpp.BackBufferFormat); + if (!d3dfmt) { + msg_Err(vd, "surface pixel format is not supported."); return VLC_EGENERIC; - - /* Lock the surface to get a valid pointer to the picture buffer */ - hr = IDirect3DSurface9_LockRect(p_d3dsurf, &d3drect, NULL, 0); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + } + fmt->i_chroma = d3dfmt->fourcc; + fmt->i_rmask = d3dfmt->rmask; + fmt->i_gmask = d3dfmt->gmask; + fmt->i_bmask = d3dfmt->bmask; + + /* We create one picture. + * It is useless to create more as we can't be used for direct rendering */ + + /* Create a surface */ + LPDIRECT3DSURFACE9 surface; + HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev, + fmt->i_width, + fmt->i_height, + d3dfmt->format, + D3DPOOL_DEFAULT, + &surface, + NULL); + if (FAILED(hr)) { + msg_Err(vd, "Failed to create picture surface. (hr=0x%lx)", hr); return VLC_EGENERIC; } + /* fill surface with black color */ + IDirect3DDevice9_ColorFill(d3ddev, surface, NULL, D3DCOLOR_ARGB(0xFF, 0, 0, 0)); + + /* Create the associated picture */ + picture_resource_t *rsc = &sys->resource; + rsc->p_sys = malloc(sizeof(*rsc->p_sys)); + if (!rsc->p_sys) { + IDirect3DSurface9_Release(surface); + return VLC_ENOMEM; + } + rsc->p_sys->surface = surface; + for (int i = 0; i < PICTURE_PLANE_MAX; i++) { + rsc->p[i].p_pixels = NULL; + rsc->p[i].i_pitch = 0; + rsc->p[i].i_lines = fmt->i_height / (i > 0 ? 2 : 1); + } + picture_t *picture = picture_NewFromResource(fmt, rsc); + if (!picture) { + IDirect3DSurface9_Release(surface); + free(rsc->p_sys); + return VLC_ENOMEM; + } - /* fill in buffer info in first plane */ - p_pic->p->p_pixels = d3drect.pBits; - p_pic->p->i_pitch = d3drect.Pitch; - + /* Wrap it into a picture pool */ + picture_pool_configuration_t pool_cfg; + memset(&pool_cfg, 0, sizeof(pool_cfg)); + pool_cfg.picture_count = 1; + pool_cfg.picture = &picture; + pool_cfg.lock = Direct3DLockSurface; + pool_cfg.unlock = Direct3DUnlockSurface; + + sys->pool = picture_pool_NewExtended(&pool_cfg); + if (!sys->pool) { + picture_Release(picture); + IDirect3DSurface9_Release(surface); + return VLC_ENOMEM; + } return VLC_SUCCESS; } - -/***************************************************************************** - * Direct3DVoutUnlockSurface: Unlock a surface locked by Direct3DLockSurface(). - *****************************************************************************/ -static int Direct3DVoutUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic ) +/** + * It destroys the pool of picture and its resources. + */ +static void Direct3DDestroyPool(vout_display_t *vd) { - HRESULT hr; - LPDIRECT3DSURFACE9 p_d3dsurf = (LPDIRECT3DSURFACE9)p_pic->p_sys; + vout_display_sys_t *sys = vd->sys; - if( NULL == p_d3dsurf ) - return VLC_EGENERIC; + if (sys->pool) { + picture_resource_t *rsc = &sys->resource; + IDirect3DSurface9_Release(rsc->p_sys->surface); - /* Unlock the Surface */ - hr = IDirect3DSurface9_UnlockRect(p_d3dsurf); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); - return VLC_EGENERIC; + picture_pool_Delete(sys->pool); } - return VLC_SUCCESS; + sys->pool = NULL; } -/***************************************************************************** - * Direct3DVoutCreateScene: allocate and initialize a 3D scene - ***************************************************************************** - * for advanced blending/filtering a texture needs be used in a 3D scene. - *****************************************************************************/ - -static int Direct3DVoutCreateScene( vout_thread_t *p_vout ) +/* */ +typedef struct { - LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev; - LPDIRECT3DTEXTURE9 p_d3dtex; - LPDIRECT3DVERTEXBUFFER9 p_d3dvtc; + FLOAT x,y,z; // vertex untransformed position + FLOAT rhw; // eye distance + D3DCOLOR diffuse; // diffuse color + FLOAT tu, tv; // texture relative coordinates +} CUSTOMVERTEX; + +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) +/** + * It allocates and initializes the resources needed to render the scene. + */ +static int Direct3DCreateScene(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; + LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev; HRESULT hr; /* - ** Create a texture for use when rendering a scene - ** for performance reason, texture format is identical to backbuffer - ** which would usually be a RGB format - */ - hr = IDirect3DDevice9_CreateTexture(p_d3ddev, - p_vout->render.i_width, - p_vout->render.i_height, - 1, - D3DUSAGE_RENDERTARGET, - p_vout->p_sys->bbFormat, - D3DPOOL_DEFAULT, - &p_d3dtex, - NULL); - if( FAILED(hr)) - { - msg_Err(p_vout, "Failed to create texture. (hr=0x%lx)", hr); + * Create a texture for use when rendering a scene + * for performance reason, texture format is identical to backbuffer + * which would usually be a RGB format + */ + LPDIRECT3DTEXTURE9 d3dtex; + hr = IDirect3DDevice9_CreateTexture(d3ddev, + sys->d3dpp.BackBufferWidth, + sys->d3dpp.BackBufferHeight, + 1, + D3DUSAGE_RENDERTARGET, + sys->d3dpp.BackBufferFormat, + D3DPOOL_DEFAULT, + &d3dtex, + NULL); + if (FAILED(hr)) { + msg_Err(vd, "Failed to create texture. (hr=0x%lx)", hr); return VLC_EGENERIC; } /* ** Create a vertex buffer for use when rendering scene */ - hr = IDirect3DDevice9_CreateVertexBuffer(p_d3ddev, - sizeof(CUSTOMVERTEX)*4, - D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, - D3DFVF_CUSTOMVERTEX, - D3DPOOL_DEFAULT, - &p_d3dvtc, - NULL); - if( FAILED(hr) ) - { - msg_Err(p_vout, "Failed to create vertex buffer. (hr=0x%lx)", hr); - IDirect3DTexture9_Release(p_d3dtex); + LPDIRECT3DVERTEXBUFFER9 d3dvtc; + hr = IDirect3DDevice9_CreateVertexBuffer(d3ddev, + sizeof(CUSTOMVERTEX)*4, + D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, + D3DFVF_CUSTOMVERTEX, + D3DPOOL_DEFAULT, + &d3dvtc, + NULL); + if (FAILED(hr)) { + msg_Err(vd, "Failed to create vertex buffer. (hr=0x%lx)", hr); + IDirect3DTexture9_Release(d3dtex); return VLC_EGENERIC; } - p_vout->p_sys->p_d3dtex = p_d3dtex; - p_vout->p_sys->p_d3dvtc = p_d3dvtc; + /* */ + sys->d3dtex = d3dtex; + sys->d3dvtc = d3dvtc; // Texture coordinates outside the range [0.0, 1.0] are set // to the texture color at 0.0 or 1.0, respectively. - IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); // Set linear filtering quality - IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(p_d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(d3ddev, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); // set maximum ambient light - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255)); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_AMBIENT, D3DCOLOR_XRGB(255,255,255)); // Turn off culling - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_CULLMODE, D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_CULLMODE, D3DCULL_NONE); // Turn off the zbuffer - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ZENABLE, D3DZB_FALSE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ZENABLE, D3DZB_FALSE); // Turn off lights - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_LIGHTING, FALSE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_LIGHTING, FALSE); // Enable dithering - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DITHERENABLE, TRUE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DITHERENABLE, TRUE); // disable stencil - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_STENCILENABLE, FALSE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_STENCILENABLE, FALSE); // manage blending - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHABLENDENABLE, TRUE); - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHATESTENABLE,TRUE); - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAREF, 0x10); - IDirect3DDevice9_SetRenderState(p_d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_SRCBLEND,D3DBLEND_SRCALPHA); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHATESTENABLE,TRUE); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAREF, 0x10); + IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHAFUNC,D3DCMP_GREATER); // Set texture states - IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE); - IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE); + IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLOROP,D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG1,D3DTA_TEXTURE); + IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_COLORARG2,D3DTA_DIFFUSE); // turn off alpha operation - IDirect3DDevice9_SetTextureStageState(p_d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + IDirect3DDevice9_SetTextureStageState(d3ddev, 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - msg_Dbg( p_vout, "Direct3D scene created successfully"); + msg_Dbg(vd, "Direct3D scene created successfully"); return VLC_SUCCESS; } -/***************************************************************************** - * Direct3DVoutReleaseScene - *****************************************************************************/ -static void Direct3DVoutReleaseScene( vout_thread_t *p_vout ) +/** + * It releases the scene resources. + */ +static void Direct3DDestroyScene(vout_display_t *vd) { - LPDIRECT3DTEXTURE9 p_d3dtex = p_vout->p_sys->p_d3dtex; - LPDIRECT3DVERTEXBUFFER9 p_d3dvtc = p_vout->p_sys->p_d3dvtc; + vout_display_sys_t *sys = vd->sys; - if( p_d3dvtc ) - { - IDirect3DVertexBuffer9_Release(p_d3dvtc); - p_vout->p_sys->p_d3dvtc = NULL; - } + LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc; + if (d3dvtc) + IDirect3DVertexBuffer9_Release(d3dvtc); - if( p_d3dtex ) - { - IDirect3DTexture9_Release(p_d3dtex); - p_vout->p_sys->p_d3dtex = NULL; - } - msg_Dbg( p_vout, "Direct3D scene released successfully"); + LPDIRECT3DTEXTURE9 d3dtex = sys->d3dtex; + if (d3dtex) + IDirect3DTexture9_Release(d3dtex); + + sys->d3dvtc = NULL; + sys->d3dtex = NULL; + msg_Dbg(vd, "Direct3D scene released successfully"); } -/***************************************************************************** - * Render: copy picture surface into a texture and render into a scene - ***************************************************************************** +/** + * It copies picture surface into a texture and renders into a scene. + * * This function is intented for higher end 3D cards, with pixel shader support - * and at least 64 MB of video RAM. - *****************************************************************************/ -static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic ) + * and at least 64 MiB of video RAM. + */ +static void Direct3DRenderScene(vout_display_t *vd, LPDIRECT3DSURFACE9 surface) { - LPDIRECT3DDEVICE9 p_d3ddev = p_vout->p_sys->p_d3ddev; - LPDIRECT3DTEXTURE9 p_d3dtex; - LPDIRECT3DVERTEXBUFFER9 p_d3dvtc; - LPDIRECT3DSURFACE9 p_d3dsrc, p_d3ddest; - CUSTOMVERTEX *p_vertices; + vout_display_sys_t *sys = vd->sys; + LPDIRECT3DDEVICE9 d3ddev = sys->d3ddev; HRESULT hr; - float f_width, f_height; // check if device is still available - hr = IDirect3DDevice9_TestCooperativeLevel(p_d3ddev); - if( FAILED(hr) ) - { - if( (D3DERR_DEVICENOTRESET != hr) - || (VLC_SUCCESS != Direct3DVoutResetDevice(p_vout)) ) - { - // device is not usable at present (lost device, out of video mem ?) - return; + hr = IDirect3DDevice9_TestCooperativeLevel(d3ddev); + if (FAILED(hr)) { + if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) { + vout_display_SendEventPicturesInvalid(vd); + sys->reset_device = true; } + return; } - p_d3dtex = p_vout->p_sys->p_d3dtex; - p_d3dvtc = p_vout->p_sys->p_d3dvtc; + /* */ + LPDIRECT3DTEXTURE9 d3dtex = sys->d3dtex; + LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc; /* Clear the backbuffer and the zbuffer */ - hr = IDirect3DDevice9_Clear( p_d3ddev, 0, NULL, D3DCLEAR_TARGET, - D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0 ); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET, + D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } - /* retrieve picture surface */ - p_d3dsrc = (LPDIRECT3DSURFACE9)p_pic->p_sys; - if( NULL == p_d3dsrc ) - { - msg_Dbg( p_vout, "no surface to render ?"); + LPDIRECT3DSURFACE9 d3dsrc = surface; + if (!d3dsrc) { + msg_Dbg(vd, "no surface to render ?"); return; } /* retrieve texture top-level surface */ - hr = IDirect3DTexture9_GetSurfaceLevel(p_d3dtex, 0, &p_d3ddest); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + LPDIRECT3DSURFACE9 d3ddest; + hr = IDirect3DTexture9_GetSurfaceLevel(d3dtex, 0, &d3ddest); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } - /* Copy picture surface into texture surface, color space conversion happens here */ - hr = IDirect3DDevice9_StretchRect(p_d3ddev, p_d3dsrc, NULL, p_d3ddest, NULL, D3DTEXF_NONE); - IDirect3DSurface9_Release(p_d3ddest); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + /* Copy picture surface into texture surface + * color space conversion and scaling happen here */ + RECT src = vd->sys->rect_src_clipped; + RECT dst = vd->sys->rect_dest_clipped; + + hr = IDirect3DDevice9_StretchRect(d3ddev, d3dsrc, &src, d3ddest, &dst, D3DTEXF_LINEAR); + IDirect3DSurface9_Release(d3ddest); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } /* Update the vertex buffer */ - hr = IDirect3DVertexBuffer9_Lock(p_d3dvtc, 0, 0, (VOID **)(&p_vertices), D3DLOCK_DISCARD); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + CUSTOMVERTEX *vertices; + hr = IDirect3DVertexBuffer9_Lock(d3dvtc, 0, 0, &vertices, D3DLOCK_DISCARD); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } /* Setup vertices */ - f_width = (float)(p_vout->output.i_width); - f_height = (float)(p_vout->output.i_height); + const float f_width = vd->sys->d3dpp.BackBufferWidth; + const float f_height = vd->sys->d3dpp.BackBufferHeight; /* -0.5f is a "feature" of DirectX and it seems to apply to Direct3d also */ /* http://www.sjbrown.co.uk/2003/05/01/fix-directx-rasterisation/ */ - p_vertices[0].x = -0.5f; // left - p_vertices[0].y = -0.5f; // top - p_vertices[0].z = 0.0f; - p_vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); - p_vertices[0].rhw = 1.0f; - p_vertices[0].tu = 0.0f; - p_vertices[0].tv = 0.0f; - - p_vertices[1].x = f_width - 0.5f; // right - p_vertices[1].y = -0.5f; // top - p_vertices[1].z = 0.0f; - p_vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); - p_vertices[1].rhw = 1.0f; - p_vertices[1].tu = 1.0f; - p_vertices[1].tv = 0.0f; - - p_vertices[2].x = f_width - 0.5f; // right - p_vertices[2].y = f_height - 0.5f; // bottom - p_vertices[2].z = 0.0f; - p_vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); - p_vertices[2].rhw = 1.0f; - p_vertices[2].tu = 1.0f; - p_vertices[2].tv = 1.0f; - - p_vertices[3].x = -0.5f; // left - p_vertices[3].y = f_height - 0.5f; // bottom - p_vertices[3].z = 0.0f; - p_vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); - p_vertices[3].rhw = 1.0f; - p_vertices[3].tu = 0.0f; - p_vertices[3].tv = 1.0f; - - hr= IDirect3DVertexBuffer9_Unlock(p_d3dvtc); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + vertices[0].x = -0.5f; // left + vertices[0].y = -0.5f; // top + vertices[0].z = 0.0f; + vertices[0].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); + vertices[0].rhw = 1.0f; + vertices[0].tu = 0.0f; + vertices[0].tv = 0.0f; + + vertices[1].x = f_width - 0.5f; // right + vertices[1].y = -0.5f; // top + vertices[1].z = 0.0f; + vertices[1].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); + vertices[1].rhw = 1.0f; + vertices[1].tu = 1.0f; + vertices[1].tv = 0.0f; + + vertices[2].x = f_width - 0.5f; // right + vertices[2].y = f_height - 0.5f; // bottom + vertices[2].z = 0.0f; + vertices[2].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); + vertices[2].rhw = 1.0f; + vertices[2].tu = 1.0f; + vertices[2].tv = 1.0f; + + vertices[3].x = -0.5f; // left + vertices[3].y = f_height - 0.5f; // bottom + vertices[3].z = 0.0f; + vertices[3].diffuse = D3DCOLOR_ARGB(255, 255, 255, 255); + vertices[3].rhw = 1.0f; + vertices[3].tu = 0.0f; + vertices[3].tv = 1.0f; + + hr= IDirect3DVertexBuffer9_Unlock(d3dvtc); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } // Begin the scene - hr = IDirect3DDevice9_BeginScene(p_d3ddev); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + hr = IDirect3DDevice9_BeginScene(d3ddev); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } @@ -1469,47 +1127,71 @@ static void Direct3DVoutRenderScene( vout_thread_t *p_vout, picture_t *p_pic ) // which govern how textures get blended together (in the case of multiple // textures) and lighting information. In this case, we are modulating // (blending) our texture with the diffuse color of the vertices. - hr = IDirect3DDevice9_SetTexture(p_d3ddev, 0, (LPDIRECT3DBASETEXTURE9)p_d3dtex); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); - IDirect3DDevice9_EndScene(p_d3ddev); + hr = IDirect3DDevice9_SetTexture(d3ddev, 0, (LPDIRECT3DBASETEXTURE9)d3dtex); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + IDirect3DDevice9_EndScene(d3ddev); return; } // Render the vertex buffer contents - hr = IDirect3DDevice9_SetStreamSource(p_d3ddev, 0, p_d3dvtc, 0, sizeof(CUSTOMVERTEX)); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); - IDirect3DDevice9_EndScene(p_d3ddev); + hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, d3dvtc, 0, sizeof(CUSTOMVERTEX)); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + IDirect3DDevice9_EndScene(d3ddev); return; } // we use FVF instead of vertex shader - hr = IDirect3DDevice9_SetFVF(p_d3ddev, D3DFVF_CUSTOMVERTEX); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); - IDirect3DDevice9_EndScene(p_d3ddev); + hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + IDirect3DDevice9_EndScene(d3ddev); return; } // draw rectangle - hr = IDirect3DDevice9_DrawPrimitive(p_d3ddev, D3DPT_TRIANGLEFAN, 0, 2); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); - IDirect3DDevice9_EndScene(p_d3ddev); + hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + IDirect3DDevice9_EndScene(d3ddev); return; } // End the scene - hr = IDirect3DDevice9_EndScene(p_d3ddev); - if( FAILED(hr) ) - { - msg_Dbg( p_vout, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); + hr = IDirect3DDevice9_EndScene(d3ddev); + if (FAILED(hr)) { + msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr); return; } } +/***************************************************************************** + * DesktopCallback: desktop mode variable callback + *****************************************************************************/ +static int DesktopCallback(vlc_object_t *object, char const *psz_cmd, + vlc_value_t oldval, vlc_value_t newval, + void *p_data) +{ + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys = vd->sys; + VLC_UNUSED(psz_cmd); + VLC_UNUSED(oldval); + VLC_UNUSED(p_data); + + vlc_mutex_lock(&sys->lock); + const bool ch_desktop = !sys->desktop_requested != !newval.b_bool; + sys->ch_desktop |= ch_desktop; + sys->desktop_requested = newval.b_bool; + vlc_mutex_unlock(&sys->lock); + + /* FIXME we should have a way to export variable to be saved */ + if (ch_desktop) { + playlist_t *p_playlist = pl_Get(vd); + /* Modify playlist as well because the vout might have to be + * restarted */ + var_Create(p_playlist, "direct3d-desktop", VLC_VAR_BOOL); + var_SetBool(p_playlist, "direct3d-desktop", newval.b_bool); + } + return VLC_SUCCESS; +}