]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/direct3d.c
Factorized Direct3DLockSurface/DirectXLock.
[vlc] / modules / video_output / msw / direct3d.c
index 7d385468c2b4c0b8540f180f3e649e2d31a71794..161693748e347c6cddb1782fd186f365bccb89de 100644 (file)
  * effectively display the pictures.
  *
  *****************************************************************************/
-#include <errno.h>                                                 /* ENOMEM */
-
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_interface.h>
 #include <vlc_playlist.h>
-#include <vlc_vout.h>
+#include <vlc_vout_display.h>
 
 #include <windows.h>
 #include <d3d9.h>
 
-#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; c<count; ++c )
-    {
-        HRESULT hr;
-        D3DFORMAT format = formats[c];
-        /* test whether device can create a surface of that format */
-        hr = IDirect3D9_CheckDeviceFormat(p_d3dobj, D3DADAPTER_DEFAULT,
-                D3DDEVTYPE_HAL, target, 0, D3DRTYPE_SURFACE, format);
-        if( SUCCEEDED(hr) )
-        {
-            /* test whether device can perform color-conversion
-            ** from that format to target format
-            */
-            hr = IDirect3D9_CheckDeviceFormatConversion(p_d3dobj,
-                    D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
-                    format, target);
-        }
-        if( SUCCEEDED(hr) )
-        {
-            // found a compatible format
-            switch( format )
-            {
-                case D3DFMT_UYVY:
-                    msg_Dbg( p_vout, "selected surface pixel format is UYVY");
-                    break;
-                case D3DFMT_YUY2:
-                    msg_Dbg( p_vout, "selected surface pixel format is YUY2");
-                    break;
-                case D3DFMT_X8R8G8B8:
-                    msg_Dbg( p_vout, "selected surface pixel format is X8R8G8B8");
-                    break;
-                case D3DFMT_A8R8G8B8:
-                    msg_Dbg( p_vout, "selected surface pixel format is A8R8G8B8");
-                    break;
-                case D3DFMT_R8G8B8:
-                    msg_Dbg( p_vout, "selected surface pixel format is R8G8B8");
-                    break;
-                case D3DFMT_R5G6B5:
-                    msg_Dbg( p_vout, "selected surface pixel format is R5G6B5");
-                    break;
-                case D3DFMT_X1R5G5B5:
-                    msg_Dbg( p_vout, "selected surface pixel format is X1R5G5B5");
-                    break;
-                default:
-                    msg_Dbg( p_vout, "selected surface pixel format is 0x%0X", format);
-                    break;
-            }
-            return format;
-        }
-        else if( D3DERR_NOTAVAILABLE != hr )
-        {
-            msg_Err( p_vout, "Could not query adapter supported formats. (hr=0x%lX)", hr);
-            break;
-        }
-    }
-    return D3DFMT_UNKNOWN;
-}
+/* */
+static int  Direct3DCreatePool(vout_display_t *vd, video_format_t *fmt);
+static void Direct3DDestroyPool(vout_display_t *vd);
 
-static D3DFORMAT Direct3DVoutFindFormat(vout_thread_t *p_vout, int i_chroma, D3DFORMAT target)
+static int  Direct3DCreateScene(vout_display_t *vd);
+static void Direct3DDestroyScene(vout_display_t *vd);
+
+/**
+ * It creates the picture and scene resources.
+ */
+static int Direct3DCreateResources(vout_display_t *vd, video_format_t *fmt)
 {
-    //if( p_vout->p_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; c<i_num_pics; )
-    {
+typedef struct
+{
+    const char   *name;
+    D3DFORMAT    format;    /* D3D format */
+    vlc_fourcc_t fourcc;    /* VLC fourcc */
+    uint32_t     rmask;
+    uint32_t     gmask;
+    uint32_t     bmask;
+} d3d_format_t;
+
+static const d3d_format_t d3d_formats[] = {
+    /* YV12 is always used for planar 420, the planes are then swapped in Lock() */
+    { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_YV12,  0,0,0 },
+    { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_I420,  0,0,0 },
+    { "YV12",       MAKEFOURCC('Y','V','1','2'),    VLC_CODEC_J420,  0,0,0 },
+    { "UYVY",       D3DFMT_UYVY,    VLC_CODEC_UYVY,  0,0,0 },
+    { "YUY2",       D3DFMT_YUY2,    VLC_CODEC_YUYV,  0,0,0 },
+    { "X8R8G8B8",   D3DFMT_X8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
+    { "A8R8G8B8",   D3DFMT_A8R8G8B8,VLC_CODEC_RGB32, 0xff0000, 0x00ff00, 0x0000ff },
+    { "8G8B8",      D3DFMT_R8G8B8,  VLC_CODEC_RGB24, 0xff0000, 0x00ff00, 0x0000ff },
+    { "R5G6B5",     D3DFMT_R5G6B5,  VLC_CODEC_RGB16, 0x1f<<11, 0x3f<<5,  0x1f<<0 },
+    { "X1R5G5B5",   D3DFMT_X1R5G5B5,VLC_CODEC_RGB15, 0x1f<<10, 0x1f<<5,  0x1f<<0 },
+
+    { NULL, 0, 0, 0,0,0}
+};
+
+/**
+ * It returns the format (closest to chroma) that can be converted to target */
+static const d3d_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-        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; c<i_num_pics; ++c )
-    {
-        picture_t *p_pic = p_vout->p_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;
+}