[vlc-commits] direct3d9: reorder code to avoid forward declarations

Steve Lhomme git at videolan.org
Tue Nov 20 09:18:09 CET 2018


vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Thu Nov 15 09:37:13 2018 +0100| [71bf7530e1566f8b6b41326bc630cab33085eb4e] | committer: Steve Lhomme

direct3d9: reorder code to avoid forward declarations

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=71bf7530e1566f8b6b41326bc630cab33085eb4e
---

 modules/video_output/win32/direct3d9.c | 1730 ++++++++++++++++----------------
 1 file changed, 847 insertions(+), 883 deletions(-)

diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c
index 19cd570f84..797e5656a3 100644
--- a/modules/video_output/win32/direct3d9.c
+++ b/modules/video_output/win32/direct3d9.c
@@ -167,25 +167,6 @@ struct vout_display_sys_t
     bool           desktop_requested;
 };
 
-static const d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target);
-
-static int  Open(vlc_object_t *);
-
-static picture_pool_t *Direct3D9CreatePicturePool  (vlc_object_t *, d3d9_device_t *,
-     const d3d9_format_t *, const video_format_t *, unsigned);
-
-static void           Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture, vlc_tick_t);
-static void           Display(vout_display_t *, picture_t *);
-static picture_pool_t*DisplayPool(vout_display_t *, unsigned);
-static int            Control(vout_display_t *, int, va_list);
-static void           Manage (vout_display_t *);
-
-static int  Direct3D9Reset  (vout_display_t *);
-static void Direct3D9Destroy(vout_display_sys_t *);
-
-static int  Direct3D9Open (vout_display_t *, video_format_t *);
-static void Direct3D9Close(vout_display_t *);
-
 /* */
 typedef struct
 {
@@ -204,16 +185,7 @@ typedef struct d3d_region_t {
     IDirect3DTexture9  *texture;
 } d3d_region_t;
 
-static void Direct3D9DeleteRegions(size_t, d3d_region_t *);
-
-static int  Direct3D9ImportPicture(vout_display_t *vd, d3d_region_t *, IDirect3DSurface9 *surface);
-static void Direct3D9ImportSubpicture(vout_display_t *vd, size_t *, d3d_region_t **, subpicture_t *);
-
-static void Direct3D9RenderScene(vout_display_t *vd, d3d_region_t *, size_t, d3d_region_t *);
-
 /* */
-static int DesktopCallback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
-
 static bool is_d3d9_opaque(vlc_fourcc_t chroma)
 {
     switch (chroma)
@@ -239,136 +211,6 @@ static HINSTANCE Direct3D9LoadShaderLibrary(void)
     return instance;
 }
 
-/**
- * It creates a Direct3D vout display.
- */
-static int Open(vlc_object_t *object)
-{
-    vout_display_t *vd = (vout_display_t *)object;
-    vout_display_sys_t *sys;
-
-    if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
-        return VLC_EGENERIC; /* let a module who can handle it do it */
-
-    if ( !vd->obj.force && vd->source.mastering.max_luminance != 0)
-        return VLC_EGENERIC; /* let a module who can handle it do it */
-
-#if !VLC_WINSTORE_APP
-    /* do not use D3D9 on XP unless forced */
-    if (!vd->obj.force)
-    {
-        bool isVistaOrGreater = false;
-        HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
-        if (likely(hKernel32 != NULL))
-            isVistaOrGreater = GetProcAddress(hKernel32, "EnumResourceLanguagesExW") != NULL;
-        if (!isVistaOrGreater)
-            return VLC_EGENERIC;
-    }
-#endif
-
-    /* Allocate structure */
-    vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
-    if (!sys)
-        return VLC_ENOMEM;
-
-    if (D3D9_Create(vd, &sys->hd3d)) {
-        msg_Err(vd, "Direct3D9 could not be initialized");
-        free(sys);
-        return VLC_EGENERIC;
-    }
-
-    sys->hxdll = Direct3D9LoadShaderLibrary();
-    if (!sys->hxdll)
-        msg_Warn(object, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
-
-    sys->sys.use_desktop = var_CreateGetBool(vd, "video-wallpaper");
-    sys->reset_device = false;
-    sys->reopen_device = false;
-    sys->lost_not_ready = 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, false))
-        goto error;
-
-    /* */
-    video_format_t fmt;
-    if (Direct3D9Open(vd, &fmt)) {
-        msg_Err(vd, "Direct3D9 could not be opened");
-        goto error;
-    }
-
-    /* */
-    vout_display_info_t info = vd->info;
-    info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
-    info.has_double_click = true;
-    info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
-    if (var_InheritBool(vd, "direct3d9-hw-blending") &&
-        sys->d3dregion_format != D3DFMT_UNKNOWN &&
-        (sys->d3d_dev.caps.SrcBlendCaps  & D3DPBLENDCAPS_SRCALPHA) &&
-        (sys->d3d_dev.caps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
-        (sys->d3d_dev.caps.TextureCaps   & D3DPTEXTURECAPS_ALPHA) &&
-        (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1) &&
-        (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE))
-        info.subpicture_chromas = d3d_subpicture_chromas;
-    else
-        info.subpicture_chromas = NULL;
-
-    /* Interaction */
-    vlc_mutex_init(&sys->lock);
-    sys->ch_desktop = false;
-    sys->desktop_requested = sys->sys.use_desktop;
-
-    var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, _("Desktop"));
-    var_AddCallback(vd, "video-wallpaper", DesktopCallback, NULL);
-
-    /* Setup vout_display now that everything is fine */
-    video_format_Clean(&vd->fmt);
-    video_format_Copy(&vd->fmt, &fmt);
-    vd->info = info;
-
-    vd->pool = DisplayPool;
-    vd->prepare = Prepare;
-    vd->display = Display;
-    vd->control = Control;
-
-    /* Fix state in case of desktop mode */
-    if (sys->sys.use_desktop && vd->cfg->is_fullscreen)
-        vout_display_SendEventFullscreen(vd, false);
-
-    return VLC_SUCCESS;
-error:
-    Direct3D9Close(vd);
-    CommonClean(vd);
-    Direct3D9Destroy(sys);
-    free(vd->sys);
-    return VLC_EGENERIC;
-}
-
-/**
- * It destroyes a Direct3D vout display.
- */
-static void Close(vlc_object_t *object)
-{
-    vout_display_t * vd = (vout_display_t *)object;
-
-    var_DelCallback(vd, "video-wallpaper", DesktopCallback, NULL);
-    vlc_mutex_destroy(&vd->sys->lock);
-
-    Direct3D9Close(vd);
-
-    CommonClean(vd);
-
-    Direct3D9Destroy(vd->sys);
-
-    free(vd->sys);
-}
-
 static void DestroyPicture(picture_t *picture)
 {
     ReleasePictureSys(picture->p_sys);
@@ -500,419 +342,222 @@ static picture_pool_t *DisplayPool(vout_display_t *vd, unsigned count)
     return vd->sys->sys.pool;
 }
 
-static void Prepare(vout_display_t *vd, picture_t *picture,
-                    subpicture_t *subpicture, vlc_tick_t date)
+/**
+ * Compute the vertex ordering needed to rotate the video. Without
+ * rotation, the vertices of the rectangle are defined in a clockwise
+ * order. This function computes a remapping of the coordinates to
+ * implement the rotation, given fixed texture coordinates.
+ * The unrotated order is the following:
+ * 0--1
+ * |  |
+ * 3--2
+ * For a 180 degrees rotation it should like this:
+ * 2--3
+ * |  |
+ * 1--0
+ * Vertex 0 should be assigned coordinates at index 2 from the
+ * unrotated order and so on, thus yielding order: 2 3 0 1.
+ */
+static void orientationVertexOrder(video_orientation_t orientation, int vertex_order[static 4])
 {
-    Manage(vd);
-    VLC_UNUSED(date);
-    vout_display_sys_t *sys = vd->sys;
-    picture_sys_t *p_sys = picture->p_sys;
-    IDirect3DSurface9 *surface = p_sys->surface;
-    d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
-
-    /* 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 */
-    if ( !is_d3d9_opaque(picture->format.i_chroma) )
-        Direct3D9UnlockSurface(picture);
-    else if (picture->context)
-    {
-        const struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context;
-        if (pic_ctx->picsys.surface != surface)
-        {
-            D3DSURFACE_DESC srcDesc, dstDesc;
-            IDirect3DSurface9_GetDesc(pic_ctx->picsys.surface, &srcDesc);
-            IDirect3DSurface9_GetDesc(surface, &dstDesc);
-            if ( srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height )
-                surface = pic_ctx->picsys.surface;
-            else
-            {
-                HRESULT hr;
-                RECT visibleSource;
-                visibleSource.left = 0;
-                visibleSource.top = 0;
-                visibleSource.right = picture->format.i_visible_width;
-                visibleSource.bottom = picture->format.i_visible_height;
-
-                hr = IDirect3DDevice9_StretchRect( p_d3d9_dev->dev, pic_ctx->picsys.surface, &visibleSource, surface, &visibleSource, D3DTEXF_NONE);
-                if (FAILED(hr)) {
-                    msg_Err(vd, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
-                }
-            }
-        }
+    switch (orientation) {
+        case ORIENT_ROTATED_90:      /* ORIENT_RIGHT_TOP */
+            vertex_order[0] = 1;
+            vertex_order[1] = 2;
+            vertex_order[2] = 3;
+            vertex_order[3] = 0;
+            break;
+        case ORIENT_ROTATED_270:     /* ORIENT_LEFT_BOTTOM */
+            vertex_order[0] = 3;
+            vertex_order[1] = 0;
+            vertex_order[2] = 1;
+            vertex_order[3] = 2;
+            break;
+        case ORIENT_ROTATED_180:     /* ORIENT_BOTTOM_RIGHT */
+            vertex_order[0] = 2;
+            vertex_order[1] = 3;
+            vertex_order[2] = 0;
+            vertex_order[3] = 1;
+            break;
+        case ORIENT_TRANSPOSED:      /* ORIENT_LEFT_TOP */
+            vertex_order[0] = 0;
+            vertex_order[1] = 3;
+            vertex_order[2] = 2;
+            vertex_order[3] = 1;
+            break;
+        case ORIENT_HFLIPPED:        /* ORIENT_TOP_RIGHT */
+            vertex_order[0] = 1;
+            vertex_order[1] = 0;
+            vertex_order[2] = 3;
+            vertex_order[3] = 2;
+            break;
+        case ORIENT_VFLIPPED:        /* ORIENT_BOTTOM_LEFT */
+            vertex_order[0] = 3;
+            vertex_order[1] = 2;
+            vertex_order[2] = 1;
+            vertex_order[3] = 0;
+            break;
+        case ORIENT_ANTI_TRANSPOSED: /* ORIENT_RIGHT_BOTTOM */
+            vertex_order[0] = 2;
+            vertex_order[1] = 1;
+            vertex_order[2] = 0;
+            vertex_order[3] = 3;
+            break;
+       default:
+            vertex_order[0] = 0;
+            vertex_order[1] = 1;
+            vertex_order[2] = 2;
+            vertex_order[3] = 3;
+            break;
     }
+}
 
-    /* check if device is still available */
-    HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev->dev);
-    if (FAILED(hr)) {
-        if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
-            if (vd->info.has_pictures_invalid)
-                vout_display_SendEventPicturesInvalid(vd);
-            sys->reset_device = true;
-            sys->lost_not_ready = false;
-        }
-        if (hr == D3DERR_DEVICELOST && !sys->lost_not_ready) {
-            /* Device is lost but not yet ready for reset. */
-            sys->lost_not_ready = true;
-        }
-        return;
-    }
-
-    d3d_region_t picture_region;
-    if (!Direct3D9ImportPicture(vd, &picture_region, surface)) {
-        picture_region.width = picture->format.i_visible_width;
-        picture_region.height = picture->format.i_visible_height;
-        size_t subpicture_region_count     = 0;
-        d3d_region_t *subpicture_region = NULL;
-        if (subpicture)
-            Direct3D9ImportSubpicture(vd, &subpicture_region_count, &subpicture_region,
-                                     subpicture);
+static void  Direct3D9SetupVertices(CUSTOMVERTEX *vertices,
+                                  const RECT *src, const RECT *src_clipped,
+                                  const RECT *dst,
+                                  int alpha,
+                                  video_orientation_t orientation)
+{
+    /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
+    const int vertices_coords[4][2] = {
+        { dst->left,  dst->top    },
+        { dst->right, dst->top    },
+        { dst->right, dst->bottom },
+        { dst->left,  dst->bottom },
+    };
 
-        Direct3D9RenderScene(vd, &picture_region,
-                            subpicture_region_count, subpicture_region);
+    /* Compute index remapping necessary to implement the rotation. */
+    int vertex_order[4];
+    orientationVertexOrder(orientation, vertex_order);
 
-        Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
-        sys->d3dregion_count = subpicture_region_count;
-        sys->d3dregion       = subpicture_region;
+    for (int i = 0; i < 4; ++i) {
+        vertices[i].x  = vertices_coords[vertex_order[i]][0];
+        vertices[i].y  = vertices_coords[vertex_order[i]][1];
     }
-}
 
-static void Display(vout_display_t *vd, picture_t *picture)
-{
-    vout_display_sys_t *sys = vd->sys;
-    const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+    float right = (float)src_clipped->right / (float)src->right;
+    float left = (float)src_clipped->left / (float)src->right;
+    float top = (float)src_clipped->top / (float)src->bottom;
+    float bottom = (float)src_clipped->bottom / (float)src->bottom;
 
-    if (sys->lost_not_ready)
-        return;
+    vertices[0].tu = left;
+    vertices[0].tv = top;
 
-    // Present the back buffer contents to the display
-    // No stretching should happen here !
-    const RECT src = sys->sys.rect_dest_clipped;
-    const RECT dst = sys->sys.rect_dest_clipped;
+    vertices[1].tu = right;
+    vertices[1].tv = top;
 
-    HRESULT hr;
-    if (sys->hd3d.use_ex) {
-        hr = IDirect3DDevice9Ex_PresentEx(p_d3d9_dev->devex, &src, &dst, NULL, NULL, 0);
-    } else {
-        hr = IDirect3DDevice9_Present(p_d3d9_dev->dev, &src, &dst, NULL, NULL);
-    }
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed Present: 0x%0lx", hr);
-    }
+    vertices[2].tu = right;
+    vertices[2].tv = bottom;
 
-    /* XXX See Prepare() */
-    if ( !is_d3d9_opaque(picture->format.i_chroma) )
-        Direct3D9LockSurface(picture);
+    vertices[3].tu = left;
+    vertices[3].tv = bottom;
 
-    CommonDisplay(vd);
+    for (int i = 0; i < 4; i++) {
+        /* -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/ */
+        vertices[i].x -= 0.5;
+        vertices[i].y -= 0.5;
+
+        vertices[i].z       = 0.0f;
+        vertices[i].rhw     = 1.0f;
+        vertices[i].diffuse = D3DCOLOR_ARGB(alpha, 255, 255, 255);
+    }
 }
 
-static int ControlReopenDevice(vout_display_t *vd)
+/**
+ * It copies picture surface into a texture and setup the associated d3d_region_t.
+ */
+static int Direct3D9ImportPicture(vout_display_t *vd,
+                                 d3d_region_t *region,
+                                 IDirect3DSurface9 *source)
 {
     vout_display_sys_t *sys = vd->sys;
+    HRESULT hr;
 
-    if (!sys->sys.use_desktop) {
-        /* Save non-desktop state */
-        sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
-        sys->desktop_save.is_on_top     = sys->sys.is_on_top;
-
-        WINDOWPLACEMENT wp = { .length = sizeof(wp), };
-        GetWindowPlacement(sys->sys.hparent ? sys->sys.hparent : sys->sys.hwnd, &wp);
-        sys->desktop_save.win = wp.rcNormalPosition;
-    }
-
-    /* */
-    Direct3D9Close(vd);
-    if (!sys->sys.b_windowless)
-        EventThreadStop(sys->sys.event);
-
-    /* */
-    vlc_mutex_lock(&sys->lock);
-    sys->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->sys.use_desktop;
-    if (!sys->sys.use_desktop) {
-        cfg.x      = sys->desktop_save.win.left;
-        cfg.y      = sys->desktop_save.win.top;
-        cfg.width  = sys->desktop_save.win.right  - sys->desktop_save.win.left;
-        cfg.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
+    if (!source) {
+        msg_Dbg(vd, "no surface to render?");
+        return VLC_EGENERIC;
     }
 
-    event_hwnd_t hwnd;
-    if (!sys->sys.b_windowless && EventThreadStart(sys->sys.event, &hwnd, &cfg)) {
-        msg_Err(vd, "Failed to restart event thread");
+    /* retrieve texture top-level surface */
+    IDirect3DSurface9 *destination;
+    hr = IDirect3DTexture9_GetSurfaceLevel(sys->sceneTexture, 0, &destination);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%0lx", hr);
         return VLC_EGENERIC;
     }
-    sys->sys.parent_window = hwnd.parent_window;
-    sys->sys.hparent       = hwnd.hparent;
-    sys->sys.hwnd          = hwnd.hwnd;
-    sys->sys.hvideownd     = hwnd.hvideownd;
-    sys->sys.hfswnd        = hwnd.hfswnd;
-    SetRectEmpty(&sys->sys.rect_parent);
 
-    /* */
-    video_format_t fmt;
-    if (Direct3D9Open(vd, &fmt)) {
-        CommonClean(vd);
-        msg_Err(vd, "Failed to reopen device");
+    /* Copy picture surface into texture surface
+     * color space conversion happen here */
+    RECT copy_rect = sys->sys.rect_src_clipped;
+    // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
+    // When copying the entire buffer, the margin end up being blended in the actual picture
+    // on nVidia (regardless of even/odd dimensions)
+    if ( copy_rect.right & 1 ) copy_rect.right++;
+    if ( copy_rect.left & 1 ) copy_rect.left--;
+    if ( copy_rect.bottom & 1 ) copy_rect.bottom++;
+    if ( copy_rect.top & 1 ) copy_rect.top--;
+    hr = IDirect3DDevice9_StretchRect(sys->d3d_dev.dev, source, &copy_rect, destination,
+                                      &copy_rect, D3DTEXF_NONE);
+    IDirect3DSurface9_Release(destination);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed StretchRect: source 0x%p 0x%0lx",
+                (LPVOID)source, hr);
         return VLC_EGENERIC;
     }
-    vd->fmt = fmt;
-    sys->sys.is_first_display = true;
 
-    if (sys->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);
-    }
+    /* */
+    region->texture = sys->sceneTexture;
+    Direct3D9SetupVertices(region->vertex, &vd->sys->sys.rect_src, &vd->sys->sys.rect_src_clipped,
+                           &vd->sys->sys.rect_dest_clipped, 255, vd->source.orientation);
     return VLC_SUCCESS;
 }
-static int Control(vout_display_t *vd, int query, va_list args)
-{
-    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 (Direct3D9Reset(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);
+static void Direct3D9DeleteRegions(size_t count, d3d_region_t *region)
+{
+    for (size_t i = 0; i < count; i++) {
+        if (region[i].texture)
+            IDirect3DTexture9_Release(region[i].texture);
     }
+    free(region);
 }
-static void Manage (vout_display_t *vd)
+
+/**
+ * It releases the scene resources.
+ */
+static void Direct3D9DestroyScene(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    CommonManage(vd);
+    Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
 
-    /* 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 (sys->sceneVertexBuffer)
+    {
+        IDirect3DVertexBuffer9_Release(sys->sceneVertexBuffer);
+        sys->sceneVertexBuffer = NULL;
+    }
 
-    if (ch_desktop) {
-        sys->reopen_device = true;
-        if (vd->info.has_pictures_invalid)
-            vout_display_SendEventPicturesInvalid(vd);
+    if (sys->sceneTexture)
+    {
+        IDirect3DTexture9_Release(sys->sceneTexture);
+        sys->sceneTexture = NULL;
     }
 
-    /* Position Change */
-    if (sys->sys.changes & DX_POSITION_CHANGE) {
-#if 0 /* need that when bicubic filter is available */
-        RECT rect;
-        UINT width, height;
+    sys->d3dregion_count = 0;
+    sys->d3dregion       = NULL;
 
-        GetClientRect(p_sys->sys.hvideownd, &rect);
-        width  = rect.right-rect.left;
-        height = rect.bottom-rect.top;
+    msg_Dbg(vd, "Direct3D9 scene released successfully");
+}
 
-        if (width != p_sys->pp.BackBufferWidth || height != p_sys->pp.BackBufferHeight)
-        {
-            msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
-            // need to reset D3D device to resize back buffer
-            if (VLC_SUCCESS != Direct3D9ResetDevice(vd, width, height))
-                return VLC_EGENERIC;
-        }
-#endif
-        sys->clear_scene = true;
-        sys->sys.changes &= ~DX_POSITION_CHANGE;
-    }
-}
-
-/**
- * It releases an instance of Direct3D9
- */
-static void Direct3D9Destroy(vout_display_sys_t *sys)
-{
-    D3D9_Destroy( &sys->hd3d );
-
-    if (sys->hxdll)
-    {
-        FreeLibrary(sys->hxdll);
-        sys->hxdll = NULL;
-    }
-}
-
-/* */
-static int  Direct3D9CreateResources (vout_display_t *, video_format_t *);
-static void Direct3D9DestroyResources(vout_display_t *);
-
-/**
- * It creates a Direct3D9 device and the associated resources.
- */
-static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
-{
-    vout_display_sys_t *sys = vd->sys;
-
-    HRESULT hr = D3D9_CreateDevice(vd, &sys->hd3d, sys->sys.hvideownd,
-                                 &vd->source, &sys->d3d_dev);
-
-    if (FAILED(hr)) {
-        msg_Err( vd, "D3D9 Creation failed! (hr=0x%0lx)", hr);
-        return VLC_EGENERIC;
-    }
-
-    const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
-    /* */
-    RECT *display = &vd->sys->sys.rect_display;
-    display->left   = 0;
-    display->top    = 0;
-    display->right  = p_d3d9_dev->pp.BackBufferWidth;
-    display->bottom = p_d3d9_dev->pp.BackBufferHeight;
-
-    *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 d3d9_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, p_d3d9_dev->pp.BackBufferFormat);
-    if (!d3dfmt) {
-        msg_Err(vd, "surface pixel format is not supported.");
-        goto error;
-    }
-    fmt->i_chroma = d3dfmt->fourcc;
-    fmt->i_rmask  = d3dfmt->rmask;
-    fmt->i_gmask  = d3dfmt->gmask;
-    fmt->i_bmask  = d3dfmt->bmask;
-    sys->d3dtexture_format = d3dfmt;
-
-    UpdateRects(vd, NULL, true);
-
-    if (Direct3D9CreateResources(vd, fmt)) {
-        msg_Err(vd, "Failed to allocate resources");
-        goto error;
-    }
-
-    /* Change the window title bar text */
-    if (!vd->sys->sys.b_windowless)
-        EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (Direct3D9 output)");
-
-    msg_Dbg(vd, "Direct3D9 device adapter successfully initialized");
-    return VLC_SUCCESS;
-
-error:
-    D3D9_ReleaseDevice(&sys->d3d_dev);
-    return VLC_EGENERIC;
-}
-
-/**
- * It releases the Direct3D9 device and its resources.
- */
-static void Direct3D9Close(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-
-    Direct3D9DestroyResources(vd);
-    D3D9_ReleaseDevice(&sys->d3d_dev);
-}
-
-/**
- * It reset the Direct3D9 device and its resources.
- */
-static int Direct3D9Reset(vout_display_t *vd)
+static void Direct3D9DestroyShaders(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
-    d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
-
-    if (D3D9_FillPresentationParameters(&sys->hd3d, &vd->source, p_d3d9_dev))
-    {
-        msg_Err(vd, "Could not presentation parameters to reset device");
-        return VLC_EGENERIC;
-    }
-
-    /* release all D3D objects */
-    Direct3D9DestroyResources(vd);
-
-    /* */
-    HRESULT hr;
-    if (sys->hd3d.use_ex){
-        hr = IDirect3DDevice9Ex_ResetEx(p_d3d9_dev->devex, &p_d3d9_dev->pp, NULL);
-    } else {
-        hr = IDirect3DDevice9_Reset(p_d3d9_dev->dev, &p_d3d9_dev->pp);
-    }
-    if (FAILED(hr)) {
-        msg_Err(vd, "IDirect3DDevice9_Reset failed! (hr=0x%0lx)", hr);
-        return VLC_EGENERIC;
-    }
 
-    UpdateRects(vd, NULL, true);
-
-    /* re-create them */
-    if (Direct3D9CreateResources(vd, &vd->fmt)) {
-        msg_Dbg(vd, "Direct3D9CreateResources failed !");
-        return VLC_EGENERIC;
-    }
-    return VLC_SUCCESS;
+    if (sys->d3dx_shader)
+        IDirect3DPixelShader9_Release(sys->d3dx_shader);
+    sys->d3dx_shader = NULL;
 }
 
-/* */
-static int  Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt);
-static void Direct3D9DestroyScene(vout_display_t *vd);
-
-static int  Direct3D9CreateShaders(vout_display_t *vd);
-static void Direct3D9DestroyShaders(vout_display_t *vd);
-
-/**
- * It creates the picture and scene resources.
- */
-static int Direct3D9CreateResources(vout_display_t *vd, video_format_t *fmt)
-{
-    vout_display_sys_t *sys = vd->sys;
-
-    if (Direct3D9CreateScene(vd, fmt)) {
-        msg_Err(vd, "Direct3D scene initialization failed !");
-        return VLC_EGENERIC;
-    }
-    if (Direct3D9CreateShaders(vd)) {
-        /* Failing to initialize shaders is not fatal. */
-        msg_Warn(vd, "Direct3D shaders initialization failed !");
-    }
-
-    sys->d3dregion_format = D3DFMT_UNKNOWN;
-    for (int i = 0; i < 2; i++) {
-        D3DFORMAT dfmt = i == 0 ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8;
-        if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys->hd3d.obj,
-                                                   D3DADAPTER_DEFAULT,
-                                                   D3DDEVTYPE_HAL,
-                                                   sys->d3d_dev.pp.BackBufferFormat,
-                                                   D3DUSAGE_DYNAMIC,
-                                                   D3DRTYPE_TEXTURE,
-                                                   dfmt))) {
-            sys->d3dregion_format = dfmt;
-            break;
-        }
-    }
-    return VLC_SUCCESS;
-}
 /**
  * It destroys the picture and scene resources.
  */
@@ -928,98 +573,6 @@ static void Direct3D9DestroyResources(vout_display_t *vd)
 }
 
 /**
- * It tests if the conversion from src to dst is supported.
- */
-static int Direct3D9CheckConversion(vout_display_t *vd,
-                                   D3DFORMAT src, D3DFORMAT dst)
-{
-    vout_display_sys_t *sys = vd->sys;
-    IDirect3D9 *d3dobj = sys->hd3d.obj;
-    HRESULT hr;
-
-    /* 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%0lx)", hr);
-        return VLC_EGENERIC;
-    }
-    return VLC_SUCCESS;
-}
-
-static const d3d9_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 },
-    { "NV12",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_NV12,  0,0,0 },
-    { "DXA9",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_D3D9_OPAQUE,  0,0,0 },
-    { "DXA9_10",    MAKEFOURCC('P','0','1','0'),    VLC_CODEC_D3D9_OPAQUE_10B,  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 d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
-{
-    vout_display_sys_t *sys = vd->sys;
-    bool hardware_scale_ok = !(vd->fmt.i_visible_width & 1) && !(vd->fmt.i_visible_height & 1);
-    if( !hardware_scale_ok )
-        msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" );
-
-    for (unsigned pass = 0; pass < 2; pass++) {
-        const vlc_fourcc_t *list;
-        const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
-
-        if (pass == 0 && is_d3d9_opaque(chroma))
-            list = dxva_chroma;
-        else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
-            list = vlc_fourcc_GetYUVFallback(chroma);
-        else if (pass == 1)
-            list = vlc_fourcc_GetRGBFallback(chroma);
-        else
-            continue;
-
-        for (unsigned i = 0; list[i] != 0; i++) {
-            for (unsigned j = 0; d3d_formats[j].name; j++) {
-                const d3d9_format_t *format = &d3d_formats[j];
-
-                if (format->fourcc != list[i])
-                    continue;
-
-                msg_Warn(vd, "trying surface pixel format: %s",
-                         format->name);
-                if (!Direct3D9CheckConversion(vd, format->format, target)) {
-                    msg_Dbg(vd, "selected surface pixel format is %s",
-                            format->name);
-                    return format;
-                }
-            }
-        }
-    }
-    return NULL;
-}
-
-/**
  * It allocates and initializes the resources needed to render the scene.
  */
 static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt)
@@ -1139,33 +692,6 @@ static int Direct3D9CreateScene(vout_display_t *vd, const video_format_t *fmt)
     return VLC_SUCCESS;
 }
 
-/**
- * It releases the scene resources.
- */
-static void Direct3D9DestroyScene(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-
-    Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
-
-    if (sys->sceneVertexBuffer)
-    {
-        IDirect3DVertexBuffer9_Release(sys->sceneVertexBuffer);
-        sys->sceneVertexBuffer = NULL;
-    }
-
-    if (sys->sceneTexture)
-    {
-        IDirect3DTexture9_Release(sys->sceneTexture);
-        sys->sceneTexture = NULL;
-    }
-
-    sys->d3dregion_count = 0;
-    sys->d3dregion       = NULL;
-
-    msg_Dbg(vd, "Direct3D9 scene released successfully");
-}
-
 #ifdef HAVE_D3DX9EFFECT_H
 static int Direct3D9CompileShader(vout_display_t *vd, const char *shader_source, size_t source_length)
 {
@@ -1301,210 +827,134 @@ error:
     return VLC_EGENERIC;
 }
 
-static void Direct3D9DestroyShaders(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-
-    if (sys->d3dx_shader)
-        IDirect3DPixelShader9_Release(sys->d3dx_shader);
-    sys->d3dx_shader = NULL;
-}
-
 /**
- * Compute the vertex ordering needed to rotate the video. Without
- * rotation, the vertices of the rectangle are defined in a clockwise
- * order. This function computes a remapping of the coordinates to
- * implement the rotation, given fixed texture coordinates.
- * The unrotated order is the following:
- * 0--1
- * |  |
- * 3--2
- * For a 180 degrees rotation it should like this:
- * 2--3
- * |  |
- * 1--0
- * Vertex 0 should be assigned coordinates at index 2 from the
- * unrotated order and so on, thus yielding order: 2 3 0 1.
+ * It creates the picture and scene resources.
  */
-static void orientationVertexOrder(video_orientation_t orientation, int vertex_order[static 4])
-{
-    switch (orientation) {
-        case ORIENT_ROTATED_90:      /* ORIENT_RIGHT_TOP */
-            vertex_order[0] = 1;
-            vertex_order[1] = 2;
-            vertex_order[2] = 3;
-            vertex_order[3] = 0;
-            break;
-        case ORIENT_ROTATED_270:     /* ORIENT_LEFT_BOTTOM */
-            vertex_order[0] = 3;
-            vertex_order[1] = 0;
-            vertex_order[2] = 1;
-            vertex_order[3] = 2;
-            break;
-        case ORIENT_ROTATED_180:     /* ORIENT_BOTTOM_RIGHT */
-            vertex_order[0] = 2;
-            vertex_order[1] = 3;
-            vertex_order[2] = 0;
-            vertex_order[3] = 1;
-            break;
-        case ORIENT_TRANSPOSED:      /* ORIENT_LEFT_TOP */
-            vertex_order[0] = 0;
-            vertex_order[1] = 3;
-            vertex_order[2] = 2;
-            vertex_order[3] = 1;
-            break;
-        case ORIENT_HFLIPPED:        /* ORIENT_TOP_RIGHT */
-            vertex_order[0] = 1;
-            vertex_order[1] = 0;
-            vertex_order[2] = 3;
-            vertex_order[3] = 2;
-            break;
-        case ORIENT_VFLIPPED:        /* ORIENT_BOTTOM_LEFT */
-            vertex_order[0] = 3;
-            vertex_order[1] = 2;
-            vertex_order[2] = 1;
-            vertex_order[3] = 0;
-            break;
-        case ORIENT_ANTI_TRANSPOSED: /* ORIENT_RIGHT_BOTTOM */
-            vertex_order[0] = 2;
-            vertex_order[1] = 1;
-            vertex_order[2] = 0;
-            vertex_order[3] = 3;
-            break;
-       default:
-            vertex_order[0] = 0;
-            vertex_order[1] = 1;
-            vertex_order[2] = 2;
-            vertex_order[3] = 3;
-            break;
-    }
-}
-
-static void  Direct3D9SetupVertices(CUSTOMVERTEX *vertices,
-                                  const RECT *src, const RECT *src_clipped,
-                                  const RECT *dst,
-                                  int alpha,
-                                  video_orientation_t orientation)
+static int Direct3D9CreateResources(vout_display_t *vd, video_format_t *fmt)
 {
-    /* Vertices of the dst rectangle in the unrotated (clockwise) order. */
-    const int vertices_coords[4][2] = {
-        { dst->left,  dst->top    },
-        { dst->right, dst->top    },
-        { dst->right, dst->bottom },
-        { dst->left,  dst->bottom },
-    };
-
-    /* Compute index remapping necessary to implement the rotation. */
-    int vertex_order[4];
-    orientationVertexOrder(orientation, vertex_order);
+    vout_display_sys_t *sys = vd->sys;
 
-    for (int i = 0; i < 4; ++i) {
-        vertices[i].x  = vertices_coords[vertex_order[i]][0];
-        vertices[i].y  = vertices_coords[vertex_order[i]][1];
+    if (Direct3D9CreateScene(vd, fmt)) {
+        msg_Err(vd, "Direct3D scene initialization failed !");
+        return VLC_EGENERIC;
+    }
+    if (Direct3D9CreateShaders(vd)) {
+        /* Failing to initialize shaders is not fatal. */
+        msg_Warn(vd, "Direct3D shaders initialization failed !");
     }
 
-    float right = (float)src_clipped->right / (float)src->right;
-    float left = (float)src_clipped->left / (float)src->right;
-    float top = (float)src_clipped->top / (float)src->bottom;
-    float bottom = (float)src_clipped->bottom / (float)src->bottom;
-
-    vertices[0].tu = left;
-    vertices[0].tv = top;
-
-    vertices[1].tu = right;
-    vertices[1].tv = top;
-
-    vertices[2].tu = right;
-    vertices[2].tv = bottom;
-
-    vertices[3].tu = left;
-    vertices[3].tv = bottom;
-
-    for (int i = 0; i < 4; i++) {
-        /* -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/ */
-        vertices[i].x -= 0.5;
-        vertices[i].y -= 0.5;
-
-        vertices[i].z       = 0.0f;
-        vertices[i].rhw     = 1.0f;
-        vertices[i].diffuse = D3DCOLOR_ARGB(alpha, 255, 255, 255);
+    sys->d3dregion_format = D3DFMT_UNKNOWN;
+    for (int i = 0; i < 2; i++) {
+        D3DFORMAT dfmt = i == 0 ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8;
+        if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(sys->hd3d.obj,
+                                                   D3DADAPTER_DEFAULT,
+                                                   D3DDEVTYPE_HAL,
+                                                   sys->d3d_dev.pp.BackBufferFormat,
+                                                   D3DUSAGE_DYNAMIC,
+                                                   D3DRTYPE_TEXTURE,
+                                                   dfmt))) {
+            sys->d3dregion_format = dfmt;
+            break;
+        }
     }
+    return VLC_SUCCESS;
 }
 
 /**
- * It copies picture surface into a texture and setup the associated d3d_region_t.
+ * It reset the Direct3D9 device and its resources.
  */
-static int Direct3D9ImportPicture(vout_display_t *vd,
-                                 d3d_region_t *region,
-                                 IDirect3DSurface9 *source)
+static int Direct3D9Reset(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
-    HRESULT hr;
+    d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
 
-    if (!source) {
-        msg_Dbg(vd, "no surface to render?");
+    if (D3D9_FillPresentationParameters(&sys->hd3d, &vd->source, p_d3d9_dev))
+    {
+        msg_Err(vd, "Could not presentation parameters to reset device");
         return VLC_EGENERIC;
     }
 
-    /* retrieve texture top-level surface */
-    IDirect3DSurface9 *destination;
-    hr = IDirect3DTexture9_GetSurfaceLevel(sys->sceneTexture, 0, &destination);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed IDirect3DTexture9_GetSurfaceLevel: 0x%0lx", hr);
-        return VLC_EGENERIC;
-    }
+    /* release all D3D objects */
+    Direct3D9DestroyResources(vd);
 
-    /* Copy picture surface into texture surface
-     * color space conversion happen here */
-    RECT copy_rect = sys->sys.rect_src_clipped;
-    // On nVidia & AMD, StretchRect will fail if the visible size isn't even.
-    // When copying the entire buffer, the margin end up being blended in the actual picture
-    // on nVidia (regardless of even/odd dimensions)
-    if ( copy_rect.right & 1 ) copy_rect.right++;
-    if ( copy_rect.left & 1 ) copy_rect.left--;
-    if ( copy_rect.bottom & 1 ) copy_rect.bottom++;
-    if ( copy_rect.top & 1 ) copy_rect.top--;
-    hr = IDirect3DDevice9_StretchRect(sys->d3d_dev.dev, source, &copy_rect, destination,
-                                      &copy_rect, D3DTEXF_NONE);
-    IDirect3DSurface9_Release(destination);
+    /* */
+    HRESULT hr;
+    if (sys->hd3d.use_ex){
+        hr = IDirect3DDevice9Ex_ResetEx(p_d3d9_dev->devex, &p_d3d9_dev->pp, NULL);
+    } else {
+        hr = IDirect3DDevice9_Reset(p_d3d9_dev->dev, &p_d3d9_dev->pp);
+    }
     if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed StretchRect: source 0x%p 0x%0lx",
-                (LPVOID)source, hr);
+        msg_Err(vd, "IDirect3DDevice9_Reset failed! (hr=0x%0lx)", hr);
         return VLC_EGENERIC;
     }
 
-    /* */
-    region->texture = sys->sceneTexture;
-    Direct3D9SetupVertices(region->vertex, &vd->sys->sys.rect_src, &vd->sys->sys.rect_src_clipped,
-                           &vd->sys->sys.rect_dest_clipped, 255, vd->fmt.orientation);
-    return VLC_SUCCESS;
-}
+    UpdateRects(vd, NULL, true);
 
-static void Direct3D9DeleteRegions(size_t count, d3d_region_t *region)
-{
-    for (size_t i = 0; i < count; i++) {
-        if (region[i].texture)
-            IDirect3DTexture9_Release(region[i].texture);
+    /* re-create them */
+    if (Direct3D9CreateResources(vd, &vd->fmt)) {
+        msg_Dbg(vd, "Direct3D9CreateResources failed !");
+        return VLC_EGENERIC;
     }
-    free(region);
+    return VLC_SUCCESS;
 }
 
-static void Direct3D9ImportSubpicture(vout_display_t *vd,
-                                     size_t *count_ptr, d3d_region_t **region,
-                                     subpicture_t *subpicture)
+static void Manage (vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    size_t count = 0;
-    for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
-        count++;
+    CommonManage(vd);
 
-    *count_ptr = count;
-    *region    = calloc(count, sizeof(**region));
-    if (*region == NULL) {
-        *count_ptr = 0;
-        return;
+    /* 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;
+        if (vd->info.has_pictures_invalid)
+            vout_display_SendEventPicturesInvalid(vd);
+    }
+
+    /* Position Change */
+    if (sys->sys.changes & DX_POSITION_CHANGE) {
+#if 0 /* need that when bicubic filter is available */
+        RECT rect;
+        UINT width, height;
+
+        GetClientRect(p_sys->sys.hvideownd, &rect);
+        width  = rect.right-rect.left;
+        height = rect.bottom-rect.top;
+
+        if (width != p_sys->pp.BackBufferWidth || height != p_sys->pp.BackBufferHeight)
+        {
+            msg_Dbg(vd, "resizing device back buffers to (%lux%lu)", width, height);
+            // need to reset D3D device to resize back buffer
+            if (VLC_SUCCESS != Direct3D9ResetDevice(vd, width, height))
+                return VLC_EGENERIC;
+        }
+#endif
+        sys->clear_scene = true;
+        sys->sys.changes &= ~DX_POSITION_CHANGE;
+    }
+}
+
+static void Direct3D9ImportSubpicture(vout_display_t *vd,
+                                     size_t *count_ptr, d3d_region_t **region,
+                                     subpicture_t *subpicture)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    size_t count = 0;
+    for (subpicture_region_t *r = subpicture->p_region; r; r = r->p_next)
+        count++;
+
+    *count_ptr = count;
+    *region    = calloc(count, sizeof(**region));
+    if (*region == NULL) {
+        *count_ptr = 0;
+        return;
     }
 
     int i = 0;
@@ -1664,80 +1114,464 @@ static int Direct3D9RenderRegion(vout_display_t *vd,
         }
     }
 
-    // Render the vertex buffer contents
-    hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, sys->sceneVertexBuffer, 0, sizeof(CUSTOMVERTEX));
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed SetStreamSource: 0x%0lx", hr);
-        return -1;
+    // Render the vertex buffer contents
+    hr = IDirect3DDevice9_SetStreamSource(d3ddev, 0, sys->sceneVertexBuffer, 0, sizeof(CUSTOMVERTEX));
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed SetStreamSource: 0x%0lx", hr);
+        return -1;
+    }
+
+    // we use FVF instead of vertex shader
+    hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed SetFVF: 0x%0lx", hr);
+        return -1;
+    }
+
+    // draw rectangle
+    hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed DrawPrimitive: 0x%0lx", hr);
+        return -1;
+    }
+    return 0;
+}
+
+/**
+ * It renders the scene.
+ *
+ * This function is intented for higher end 3D cards, with pixel shader support
+ * and at least 64 MiB of video RAM.
+ */
+static void Direct3D9RenderScene(vout_display_t *vd,
+                                d3d_region_t *picture,
+                                size_t subpicture_count,
+                                d3d_region_t *subpicture)
+{
+    vout_display_sys_t *sys = vd->sys;
+    IDirect3DDevice9 *d3ddev = sys->d3d_dev.dev;
+    HRESULT hr;
+
+    if (sys->clear_scene) {
+        /* Clear the backbuffer and the zbuffer */
+        hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
+                                  D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
+        if (FAILED(hr)) {
+            msg_Dbg(vd, "Failed Clear: 0x%0lx", hr);
+            return;
+        }
+        sys->clear_scene = false;
+    }
+
+    // Begin the scene
+    hr = IDirect3DDevice9_BeginScene(d3ddev);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed BeginScene: 0x%0lx", hr);
+        return;
+    }
+
+    Direct3D9RenderRegion(vd, picture, true);
+
+    if (subpicture_count)
+    {
+        IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
+        for (size_t i = 0; i < subpicture_count; i++) {
+            d3d_region_t *r = &subpicture[i];
+            if (r->texture)
+                Direct3D9RenderRegion(vd, r, false);
+        }
+        IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
+    }
+
+    // End the scene
+    hr = IDirect3DDevice9_EndScene(d3ddev);
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed EndScene: 0x%0lx", hr);
+        return;
+    }
+}
+
+static void Prepare(vout_display_t *vd, picture_t *picture,
+                    subpicture_t *subpicture, vlc_tick_t date)
+{
+    Manage(vd);
+    VLC_UNUSED(date);
+    vout_display_sys_t *sys = vd->sys;
+    picture_sys_t *p_sys = picture->p_sys;
+    IDirect3DSurface9 *surface = p_sys->surface;
+    d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+
+    /* 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 */
+    if ( !is_d3d9_opaque(picture->format.i_chroma) )
+        Direct3D9UnlockSurface(picture);
+    else if (picture->context)
+    {
+        const struct va_pic_context *pic_ctx = (struct va_pic_context*)picture->context;
+        if (pic_ctx->picsys.surface != surface)
+        {
+            D3DSURFACE_DESC srcDesc, dstDesc;
+            IDirect3DSurface9_GetDesc(pic_ctx->picsys.surface, &srcDesc);
+            IDirect3DSurface9_GetDesc(surface, &dstDesc);
+            if ( srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height )
+                surface = pic_ctx->picsys.surface;
+            else
+            {
+                HRESULT hr;
+                RECT visibleSource;
+                visibleSource.left = 0;
+                visibleSource.top = 0;
+                visibleSource.right = picture->format.i_visible_width;
+                visibleSource.bottom = picture->format.i_visible_height;
+
+                hr = IDirect3DDevice9_StretchRect( p_d3d9_dev->dev, pic_ctx->picsys.surface, &visibleSource, surface, &visibleSource, D3DTEXF_NONE);
+                if (FAILED(hr)) {
+                    msg_Err(vd, "Failed to copy the hw surface to the decoder surface (hr=0x%0lx)", hr );
+                }
+            }
+        }
+    }
+
+    /* check if device is still available */
+    HRESULT hr = IDirect3DDevice9_TestCooperativeLevel(p_d3d9_dev->dev);
+    if (FAILED(hr)) {
+        if (hr == D3DERR_DEVICENOTRESET && !sys->reset_device) {
+            if (vd->info.has_pictures_invalid)
+                vout_display_SendEventPicturesInvalid(vd);
+            sys->reset_device = true;
+            sys->lost_not_ready = false;
+        }
+        if (hr == D3DERR_DEVICELOST && !sys->lost_not_ready) {
+            /* Device is lost but not yet ready for reset. */
+            sys->lost_not_ready = true;
+        }
+        return;
+    }
+
+    d3d_region_t picture_region;
+    if (!Direct3D9ImportPicture(vd, &picture_region, surface)) {
+        picture_region.width = picture->format.i_visible_width;
+        picture_region.height = picture->format.i_visible_height;
+        size_t subpicture_region_count     = 0;
+        d3d_region_t *subpicture_region = NULL;
+        if (subpicture)
+            Direct3D9ImportSubpicture(vd, &subpicture_region_count, &subpicture_region,
+                                     subpicture);
+
+        Direct3D9RenderScene(vd, &picture_region,
+                            subpicture_region_count, subpicture_region);
+
+        Direct3D9DeleteRegions(sys->d3dregion_count, sys->d3dregion);
+        sys->d3dregion_count = subpicture_region_count;
+        sys->d3dregion       = subpicture_region;
+    }
+}
+
+static void Display(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
+    const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+
+    if (sys->lost_not_ready)
+        return;
+
+    // Present the back buffer contents to the display
+    // No stretching should happen here !
+    const RECT src = sys->sys.rect_dest_clipped;
+    const RECT dst = sys->sys.rect_dest_clipped;
+
+    HRESULT hr;
+    if (sys->hd3d.use_ex) {
+        hr = IDirect3DDevice9Ex_PresentEx(p_d3d9_dev->devex, &src, &dst, NULL, NULL, 0);
+    } else {
+        hr = IDirect3DDevice9_Present(p_d3d9_dev->dev, &src, &dst, NULL, NULL);
+    }
+    if (FAILED(hr)) {
+        msg_Dbg(vd, "Failed Present: 0x%0lx", hr);
+    }
+
+    /* XXX See Prepare() */
+    if ( !is_d3d9_opaque(picture->format.i_chroma) )
+        Direct3D9LockSurface(picture);
+
+    CommonDisplay(vd);
+}
+
+/**
+ * It releases an instance of Direct3D9
+ */
+static void Direct3D9Destroy(vout_display_sys_t *sys)
+{
+    D3D9_Destroy( &sys->hd3d );
+
+    if (sys->hxdll)
+    {
+        FreeLibrary(sys->hxdll);
+        sys->hxdll = NULL;
+    }
+}
+
+/**
+ * It tests if the conversion from src to dst is supported.
+ */
+static int Direct3D9CheckConversion(vout_display_t *vd,
+                                   D3DFORMAT src, D3DFORMAT dst)
+{
+    vout_display_sys_t *sys = vd->sys;
+    IDirect3D9 *d3dobj = sys->hd3d.obj;
+    HRESULT hr;
+
+    /* 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%0lx)", hr);
+        return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+static const d3d9_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 },
+    { "NV12",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_NV12,  0,0,0 },
+    { "DXA9",       MAKEFOURCC('N','V','1','2'),    VLC_CODEC_D3D9_OPAQUE,  0,0,0 },
+    { "DXA9_10",    MAKEFOURCC('P','0','1','0'),    VLC_CODEC_D3D9_OPAQUE_10B,  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 d3d9_format_t *Direct3DFindFormat(vout_display_t *vd, vlc_fourcc_t chroma, D3DFORMAT target)
+{
+    vout_display_sys_t *sys = vd->sys;
+    bool hardware_scale_ok = !(vd->fmt.i_visible_width & 1) && !(vd->fmt.i_visible_height & 1);
+    if( !hardware_scale_ok )
+        msg_Warn( vd, "Disabling hardware chroma conversion due to odd dimensions" );
+
+    for (unsigned pass = 0; pass < 2; pass++) {
+        const vlc_fourcc_t *list;
+        const vlc_fourcc_t dxva_chroma[] = {chroma, 0};
+
+        if (pass == 0 && is_d3d9_opaque(chroma))
+            list = dxva_chroma;
+        else if (pass == 0 && hardware_scale_ok && sys->allow_hw_yuv && vlc_fourcc_IsYUV(chroma))
+            list = vlc_fourcc_GetYUVFallback(chroma);
+        else if (pass == 1)
+            list = vlc_fourcc_GetRGBFallback(chroma);
+        else
+            continue;
+
+        for (unsigned i = 0; list[i] != 0; i++) {
+            for (unsigned j = 0; d3d_formats[j].name; j++) {
+                const d3d9_format_t *format = &d3d_formats[j];
+
+                if (format->fourcc != list[i])
+                    continue;
+
+                msg_Warn(vd, "trying surface pixel format: %s",
+                         format->name);
+                if (!Direct3D9CheckConversion(vd, format->format, target)) {
+                    msg_Dbg(vd, "selected surface pixel format is %s",
+                            format->name);
+                    return format;
+                }
+            }
+        }
+    }
+    return NULL;
+}
+
+/**
+ * It creates a Direct3D9 device and the associated resources.
+ */
+static int Direct3D9Open(vout_display_t *vd, video_format_t *fmt)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    HRESULT hr = D3D9_CreateDevice(vd, &sys->hd3d, sys->sys.hvideownd,
+                                 &vd->source, &sys->d3d_dev);
+
+    if (FAILED(hr)) {
+        msg_Err( vd, "D3D9 Creation failed! (hr=0x%0lx)", hr);
+        return VLC_EGENERIC;
+    }
+
+    const d3d9_device_t *p_d3d9_dev = &sys->d3d_dev;
+    /* */
+    RECT *display = &vd->sys->sys.rect_display;
+    display->left   = 0;
+    display->top    = 0;
+    display->right  = p_d3d9_dev->pp.BackBufferWidth;
+    display->bottom = p_d3d9_dev->pp.BackBufferHeight;
+
+    *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 d3d9_format_t *d3dfmt = Direct3DFindFormat(vd, fmt->i_chroma, p_d3d9_dev->pp.BackBufferFormat);
+    if (!d3dfmt) {
+        msg_Err(vd, "surface pixel format is not supported.");
+        goto error;
+    }
+    fmt->i_chroma = d3dfmt->fourcc;
+    fmt->i_rmask  = d3dfmt->rmask;
+    fmt->i_gmask  = d3dfmt->gmask;
+    fmt->i_bmask  = d3dfmt->bmask;
+    sys->d3dtexture_format = d3dfmt;
+
+    UpdateRects(vd, NULL, true);
+
+    if (Direct3D9CreateResources(vd, fmt)) {
+        msg_Err(vd, "Failed to allocate resources");
+        goto error;
+    }
+
+    /* Change the window title bar text */
+    if (!sys->sys.b_windowless)
+        EventThreadUpdateTitle(sys->sys.event, VOUT_TITLE " (Direct3D9 output)");
+
+    msg_Dbg(vd, "Direct3D9 device adapter successfully initialized");
+    return VLC_SUCCESS;
+
+error:
+    D3D9_ReleaseDevice(&sys->d3d_dev);
+    return VLC_EGENERIC;
+}
+
+/**
+ * It releases the Direct3D9 device and its resources.
+ */
+static void Direct3D9Close(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    Direct3D9DestroyResources(vd);
+    D3D9_ReleaseDevice(&sys->d3d_dev);
+}
+
+static int ControlReopenDevice(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if (!sys->sys.use_desktop) {
+        /* Save non-desktop state */
+        sys->desktop_save.is_fullscreen = vd->cfg->is_fullscreen;
+        sys->desktop_save.is_on_top     = sys->sys.is_on_top;
+
+        WINDOWPLACEMENT wp = { .length = sizeof(wp), };
+        GetWindowPlacement(sys->sys.hparent ? sys->sys.hparent : sys->sys.hwnd, &wp);
+        sys->desktop_save.win = wp.rcNormalPosition;
+    }
+
+    /* */
+    Direct3D9Close(vd);
+    if (!sys->sys.b_windowless)
+        EventThreadStop(sys->sys.event);
+
+    /* */
+    vlc_mutex_lock(&sys->lock);
+    sys->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->sys.use_desktop;
+    if (!sys->sys.use_desktop) {
+        cfg.x      = sys->desktop_save.win.left;
+        cfg.y      = sys->desktop_save.win.top;
+        cfg.width  = sys->desktop_save.win.right  - sys->desktop_save.win.left;
+        cfg.height = sys->desktop_save.win.bottom - sys->desktop_save.win.top;
+    }
+
+    event_hwnd_t hwnd;
+    if (!sys->sys.b_windowless && EventThreadStart(sys->sys.event, &hwnd, &cfg)) {
+        msg_Err(vd, "Failed to restart event thread");
+        return VLC_EGENERIC;
     }
+    sys->sys.parent_window = hwnd.parent_window;
+    sys->sys.hparent       = hwnd.hparent;
+    sys->sys.hwnd          = hwnd.hwnd;
+    sys->sys.hvideownd     = hwnd.hvideownd;
+    sys->sys.hfswnd        = hwnd.hfswnd;
+    SetRectEmpty(&sys->sys.rect_parent);
 
-    // we use FVF instead of vertex shader
-    hr = IDirect3DDevice9_SetFVF(d3ddev, D3DFVF_CUSTOMVERTEX);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed SetFVF: 0x%0lx", hr);
-        return -1;
+    /* */
+    video_format_t fmt;
+    if (Direct3D9Open(vd, &fmt)) {
+        CommonClean(vd);
+        msg_Err(vd, "Failed to reopen device");
+        return VLC_EGENERIC;
     }
+    vd->fmt = fmt;
+    sys->sys.is_first_display = true;
 
-    // draw rectangle
-    hr = IDirect3DDevice9_DrawPrimitive(d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed DrawPrimitive: 0x%0lx", hr);
-        return -1;
+    if (sys->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 0;
+    return VLC_SUCCESS;
 }
 
-/**
- * It renders the scene.
- *
- * This function is intented for higher end 3D cards, with pixel shader support
- * and at least 64 MiB of video RAM.
- */
-static void Direct3D9RenderScene(vout_display_t *vd,
-                                d3d_region_t *picture,
-                                size_t subpicture_count,
-                                d3d_region_t *subpicture)
+static int Control(vout_display_t *vd, int query, va_list args)
 {
     vout_display_sys_t *sys = vd->sys;
-    IDirect3DDevice9 *d3ddev = sys->d3d_dev.dev;
-    HRESULT hr;
-
-    if (sys->clear_scene) {
-        /* Clear the backbuffer and the zbuffer */
-        hr = IDirect3DDevice9_Clear(d3ddev, 0, NULL, D3DCLEAR_TARGET,
-                                  D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
-        if (FAILED(hr)) {
-            msg_Dbg(vd, "Failed Clear: 0x%0lx", hr);
-            return;
-        }
-        sys->clear_scene = false;
-    }
-
-    // Begin the scene
-    hr = IDirect3DDevice9_BeginScene(d3ddev);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed BeginScene: 0x%0lx", hr);
-        return;
-    }
-
-    Direct3D9RenderRegion(vd, picture, true);
 
-    if (subpicture_count)
-    {
-        IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
-        for (size_t i = 0; i < subpicture_count; i++) {
-            d3d_region_t *r = &subpicture[i];
-            if (r->texture)
-                Direct3D9RenderRegion(vd, r, false);
+    switch (query) {
+    case VOUT_DISPLAY_RESET_PICTURES:
+        /* FIXME what to do here in case of failure */
+        if (sys->reset_device) {
+            if (Direct3D9Reset(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;
         }
-        IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
-    }
-
-    // End the scene
-    hr = IDirect3DDevice9_EndScene(d3ddev);
-    if (FAILED(hr)) {
-        msg_Dbg(vd, "Failed EndScene: 0x%0lx", hr);
-        return;
+        return VLC_SUCCESS;
+    default:
+        return CommonControl(vd, query, args);
     }
 }
 
@@ -1799,6 +1633,136 @@ static int FindShadersCallback(const char *name, char ***values, char ***descs)
 
 }
 
+/**
+ * It creates a Direct3D vout display.
+ */
+static int Open(vlc_object_t *object)
+{
+    vout_display_t *vd = (vout_display_t *)object;
+    vout_display_sys_t *sys;
+
+    if ( !vd->obj.force && vd->source.projection_mode != PROJECTION_MODE_RECTANGULAR)
+        return VLC_EGENERIC; /* let a module who can handle it do it */
+
+    if ( !vd->obj.force && vd->source.mastering.max_luminance != 0)
+        return VLC_EGENERIC; /* let a module who can handle it do it */
+
+#if !VLC_WINSTORE_APP
+    /* do not use D3D9 on XP unless forced */
+    if (!vd->obj.force)
+    {
+        bool isVistaOrGreater = false;
+        HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+        if (likely(hKernel32 != NULL))
+            isVistaOrGreater = GetProcAddress(hKernel32, "EnumResourceLanguagesExW") != NULL;
+        if (!isVistaOrGreater)
+            return VLC_EGENERIC;
+    }
+#endif
+
+    /* Allocate structure */
+    vd->sys = sys = calloc(1, sizeof(vout_display_sys_t));
+    if (!sys)
+        return VLC_ENOMEM;
+
+    if (D3D9_Create(vd, &sys->hd3d)) {
+        msg_Err(vd, "Direct3D9 could not be initialized");
+        free(sys);
+        return VLC_EGENERIC;
+    }
+
+    sys->hxdll = Direct3D9LoadShaderLibrary();
+    if (!sys->hxdll)
+        msg_Warn(object, "cannot load Direct3D9 Shader Library; HLSL pixel shading will be disabled.");
+
+    sys->sys.use_desktop = var_CreateGetBool(vd, "video-wallpaper");
+    sys->reset_device = false;
+    sys->reopen_device = false;
+    sys->lost_not_ready = 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, false))
+        goto error;
+
+    /* */
+    video_format_t fmt;
+    if (Direct3D9Open(vd, &fmt)) {
+        msg_Err(vd, "Direct3D9 could not be opened");
+        goto error;
+    }
+
+    /* */
+    vout_display_info_t info = vd->info;
+    info.is_slow = !is_d3d9_opaque(fmt.i_chroma);
+    info.has_double_click = true;
+    info.has_pictures_invalid = !is_d3d9_opaque(fmt.i_chroma);
+    if (var_InheritBool(vd, "direct3d9-hw-blending") &&
+        sys->d3dregion_format != D3DFMT_UNKNOWN &&
+        (sys->d3d_dev.caps.SrcBlendCaps  & D3DPBLENDCAPS_SRCALPHA) &&
+        (sys->d3d_dev.caps.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
+        (sys->d3d_dev.caps.TextureCaps   & D3DPTEXTURECAPS_ALPHA) &&
+        (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_SELECTARG1) &&
+        (sys->d3d_dev.caps.TextureOpCaps & D3DTEXOPCAPS_MODULATE))
+        info.subpicture_chromas = d3d_subpicture_chromas;
+    else
+        info.subpicture_chromas = NULL;
+
+    /* Interaction */
+    vlc_mutex_init(&sys->lock);
+    sys->ch_desktop = false;
+    sys->desktop_requested = sys->sys.use_desktop;
+
+    var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, _("Desktop"));
+    var_AddCallback(vd, "video-wallpaper", DesktopCallback, NULL);
+
+    /* Setup vout_display now that everything is fine */
+    video_format_Clean(&vd->fmt);
+    video_format_Copy(&vd->fmt, &fmt);
+    vd->info = info;
+
+    vd->pool = DisplayPool;
+    vd->prepare = Prepare;
+    vd->display = Display;
+    vd->control = Control;
+
+    /* Fix state in case of desktop mode */
+    if (sys->sys.use_desktop && vd->cfg->is_fullscreen)
+        vout_display_SendEventFullscreen(vd, false);
+
+    return VLC_SUCCESS;
+error:
+    Direct3D9Close(vd);
+    CommonClean(vd);
+    Direct3D9Destroy(sys);
+    free(vd->sys);
+    return VLC_EGENERIC;
+}
+
+/**
+ * It destroyes a Direct3D vout display.
+ */
+static void Close(vlc_object_t *object)
+{
+    vout_display_t * vd = (vout_display_t *)object;
+
+    var_DelCallback(vd, "video-wallpaper", DesktopCallback, NULL);
+    vlc_mutex_destroy(&vd->sys->lock);
+
+    Direct3D9Close(vd);
+
+    CommonClean(vd);
+
+    Direct3D9Destroy(vd->sys);
+
+    free(vd->sys);
+}
+
 #ifdef HAVE_GL
 #include "../opengl/converter.h"
 #include <GL/wglew.h>



More information about the vlc-commits mailing list