[vlc-devel] [PATCH 10/14] direct3D: implement support of NVIDIA 3D Vision

Felix Abecassis felix.abecassis at gmail.com
Tue Sep 9 19:08:29 CEST 2014


---
 modules/video_output/Modules.am            |   4 +-
 modules/video_output/msw/common.h          |  24 ++
 modules/video_output/msw/direct3d.c        |  62 +++--
 modules/video_output/msw/nvidia_3dvision.c | 360 +++++++++++++++++++++++++++++
 modules/video_output/msw/nvidia_3dvision.h |  34 +++
 modules/video_output/msw/stereo3d_api.c    |  51 ++++
 modules/video_output/msw/stereo3d_api.h    |  87 +++++++
 7 files changed, 604 insertions(+), 18 deletions(-)
 create mode 100644 modules/video_output/msw/nvidia_3dvision.c
 create mode 100644 modules/video_output/msw/nvidia_3dvision.h
 create mode 100644 modules/video_output/msw/stereo3d_api.c
 create mode 100644 modules/video_output/msw/stereo3d_api.h

diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am
index ad5737f..e791e53 100644
--- a/modules/video_output/Modules.am
+++ b/modules/video_output/Modules.am
@@ -157,7 +157,9 @@ EXTRA_LTLIBRARIES += libdirect2d_plugin.la
 
 libdirect3d_plugin_la_SOURCES = msw/direct3d.c \
 	msw/common.c msw/common.h msw/events.c msw/events.h msw/builtin_shaders.h \
-	msw/win32touch.c msw/win32touch.h
+	msw/win32touch.c msw/win32touch.h \
+	msw/stereo3d_api.c msw/stereo3d_api.h \
+	msw/nvidia_3dvision.c msw/nvidia_3dvision.h
 libdirect3d_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
 	-DMODULE_NAME_IS_direct3d
 libdirect3d_plugin_la_LIBADD = -lgdi32 -lole32 -luuid
diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index 5ddf85e..f353b51 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -28,6 +28,7 @@
 #ifdef MODULE_NAME_IS_direct3d
 # include <d3d9.h>
 # include <d3dx9effect.h>
+# include "stereo3d_api.h"
 #endif
 #ifdef MODULE_NAME_IS_glwin32
 # include "../opengl.h"
@@ -41,6 +42,26 @@
  *****************************************************************************/
 #include "events.h"
 
+#ifdef MODULE_NAME_IS_direct3d
+typedef struct
+{
+    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)
+
+typedef struct d3d_region_t {
+    D3DFORMAT          format;
+    unsigned           width;
+    unsigned           height;
+    CUSTOMVERTEX       vertex[4];
+    LPDIRECT3DTEXTURE9 texture;
+} d3d_region_t;
+#endif
+
+
 /*****************************************************************************
  * vout_sys_t: video output method descriptor
  *****************************************************************************
@@ -155,6 +176,9 @@ struct vout_display_sys_t
     LPDIRECT3DDEVICE9       d3ddev;
     D3DPRESENT_PARAMETERS   d3dpp;
 
+    // Stereo 3D API
+    Stereo3DAPI             *stereo3d_api;
+
     // scene objects
     LPDIRECT3DTEXTURE9      d3dtex;
     LPDIRECT3DVERTEXBUFFER9 d3dvtc;
diff --git a/modules/video_output/msw/direct3d.c b/modules/video_output/msw/direct3d.c
index 7fa4585..0d00bb1 100644
--- a/modules/video_output/msw/direct3d.c
+++ b/modules/video_output/msw/direct3d.c
@@ -49,6 +49,7 @@
 
 #include "common.h"
 #include "builtin_shaders.h"
+#include "stereo3d_api.h"
 
 /*****************************************************************************
  * Module descriptor
@@ -125,22 +126,6 @@ static int  Direct3DOpen (vout_display_t *, video_format_t *);
 static void Direct3DClose(vout_display_t *);
 
 /* */
-typedef struct
-{
-    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)
-
-typedef struct d3d_region_t {
-    D3DFORMAT          format;
-    unsigned           width;
-    unsigned           height;
-    CUSTOMVERTEX       vertex[4];
-    LPDIRECT3DTEXTURE9 texture;
-} d3d_region_t;
 
 static void Direct3DDeleteRegions(int, d3d_region_t *);
 
@@ -588,6 +573,8 @@ static void Direct3DDestroy(vout_display_t *vd)
         FreeLibrary(sys->hd3d9_dll);
     if (sys->hd3d9x_dll)
         FreeLibrary(sys->hd3d9x_dll);
+    if (sys->stereo3d_api)
+        Stereo3DAPI_Unload(sys->stereo3d_api);
 
     sys->d3dobj = NULL;
     sys->hd3d9_dll = NULL;
@@ -699,6 +686,17 @@ static int Direct3DOpen(vout_display_t *vd, video_format_t *fmt)
 
     UpdateRects(vd, NULL, NULL, true);
 
+    if (vd->fmt.stereo.mode != VLC_STEREO3D_2D)
+        sys->stereo3d_api = Stereo3DAPI_Load(vd);
+    if (sys->stereo3d_api)
+    {
+        if (Stereo3DAPI_CreateResources(sys->stereo3d_api))
+        {
+            Stereo3DAPI_Unload(sys->stereo3d_api);
+            sys->stereo3d_api = NULL;
+        }
+    }
+
     if (Direct3DCreateResources(vd, fmt)) {
         msg_Err(vd, "Failed to allocate resources");
         return VLC_EGENERIC;
@@ -720,6 +718,9 @@ static void Direct3DClose(vout_display_t *vd)
 
     Direct3DDestroyResources(vd);
 
+    if (sys->stereo3d_api)
+        Stereo3DAPI_DestroyResources(sys->stereo3d_api);
+
     if (sys->d3ddev)
        IDirect3DDevice9_Release(sys->d3ddev);
 
@@ -740,6 +741,9 @@ static int Direct3DReset(vout_display_t *vd)
     /* release all D3D objects */
     Direct3DDestroyResources(vd);
 
+    if (sys->stereo3d_api)
+        Stereo3DAPI_DestroyResources(sys->stereo3d_api);
+
     /* */
     HRESULT hr = IDirect3DDevice9_Reset(d3ddev, &sys->d3dpp);
     if (FAILED(hr)) {
@@ -747,6 +751,9 @@ static int Direct3DReset(vout_display_t *vd)
         return VLC_EGENERIC;
     }
 
+    if (sys->stereo3d_api)
+        Stereo3DAPI_CreateResources(sys->stereo3d_api);
+
     UpdateRects(vd, NULL, NULL, true);
 
     /* re-create them */
@@ -774,6 +781,7 @@ static int Direct3DCreateResources(vout_display_t *vd, video_format_t *fmt)
 {
     vout_display_sys_t *sys = vd->sys;
 
+
     if (Direct3DCreatePool(vd, fmt)) {
         msg_Err(vd, "Direct3D picture pool initialization failed");
         return VLC_EGENERIC;
@@ -1047,6 +1055,13 @@ static int Direct3DCreateScene(vout_display_t *vd, const video_format_t *fmt)
     LPDIRECT3DDEVICE9       d3ddev = sys->d3ddev;
     HRESULT hr;
 
+    if (sys->stereo3d_api) {
+        if (Stereo3DAPI_CreateScene(sys->stereo3d_api, fmt)) {
+            msg_Err(vd, "Failed to create Stereo 3D scene.");
+            return VLC_EGENERIC;
+        }
+    }
+
     /*
      * Create a texture for use when rendering a scene
      * for performance reason, texture format is identical to backbuffer
@@ -1165,6 +1180,9 @@ static void Direct3DDestroyScene(vout_display_t *vd)
 
     Direct3DDeleteRegions(sys->d3dregion_count, sys->d3dregion);
 
+    if (sys->stereo3d_api)
+        Stereo3DAPI_DestroyScene(sys->stereo3d_api);
+
     LPDIRECT3DVERTEXBUFFER9 d3dvtc = sys->d3dvtc;
     if (d3dvtc)
         IDirect3DVertexBuffer9_Release(d3dvtc);
@@ -1463,6 +1481,7 @@ static int Direct3DImportPicture(vout_display_t *vd,
      * color space conversion happen here */
     hr = IDirect3DDevice9_StretchRect(sys->d3ddev, source, NULL, destination, NULL, D3DTEXF_LINEAR);
     IDirect3DSurface9_Release(destination);
+
     if (FAILED(hr)) {
         msg_Dbg(vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
         return VLC_EGENERIC;
@@ -1712,15 +1731,24 @@ static void Direct3DRenderScene(vout_display_t *vd,
         return;
     }
 
-    Direct3DRenderRegion(vd, picture, true);
+    if (sys->stereo3d_api && Stereo3DAPI_CanRender(sys->stereo3d_api))
+        Stereo3DAPI_RenderRegion(sys->stereo3d_api, picture);
+    else
+        Direct3DRenderRegion(vd, picture, true);
 
     if (subpicture_count > 0)
         IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, TRUE);
+
+    /* Disable stereo 3D when rendering subpictures */
+    Stereo3DAPI *stereo3d_api = sys->stereo3d_api;
+    sys->stereo3d_api = NULL;
     for (int i = 0; i < subpicture_count; i++) {
         d3d_region_t *r = &subpicture[i];
         if (r->texture)
             Direct3DRenderRegion(vd, r, false);
     }
+    sys->stereo3d_api = stereo3d_api;
+
     if (subpicture_count > 0)
         IDirect3DDevice9_SetRenderState(d3ddev, D3DRS_ALPHABLENDENABLE, FALSE);
 
diff --git a/modules/video_output/msw/nvidia_3dvision.c b/modules/video_output/msw/nvidia_3dvision.c
new file mode 100644
index 0000000..861d1ec
--- /dev/null
+++ b/modules/video_output/msw/nvidia_3dvision.c
@@ -0,0 +1,360 @@
+/*****************************************************************************
+ * nvidia_3dvision.c
+ *****************************************************************************
+ * Copyright (C) 2014 the VideoLAN team
+ *
+ * Authors: Felix Abecassis <felix.abecassis at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "nvidia_3dvision.h"
+
+#include "common.h"
+
+static void Nvidia3DVisionUnload(Stereo3DAPI *);
+
+static int  Nvidia3DVisionCreateResources(Stereo3DAPI *);
+static void Nvidia3DVisionDestroyResources(Stereo3DAPI *);
+
+static int  Nvidia3DVisionCreateScene(Stereo3DAPI *, const video_format_t *);
+static void Nvidia3DVisionDestroyScene(Stereo3DAPI *);
+
+static bool Nvidia3DVisionCanRender(Stereo3DAPI *);
+static int  Nvidia3DVisionRenderRegion(Stereo3DAPI *, d3d_region_t *);
+
+# define NVSTEREO_IMAGE_SIGNATURE 0x4433564e
+# define DXNV_SWAP_EYES 0x01
+# define DXNV_SCALE_TO_FIT 0x02
+
+typedef struct
+{
+    uint32_t dwSignature;
+    uint32_t dwWidth;
+    uint32_t dwHeight;
+    uint32_t dwBPP;
+    uint32_t dwFlags;
+} NVSTEREOIMAGEHEADER;
+
+typedef enum
+{
+    NVAPI_OK = 0,
+} NvAPI_Status;
+
+typedef void* StereoHandle;
+
+typedef struct
+{
+    HINSTANCE    instance;
+    bool         initialized;
+
+    void*        (__cdecl *QueryInterface)(unsigned offset);
+    NvAPI_Status (__cdecl *Initialize)(void);
+    NvAPI_Status (__cdecl *Unload)(void);
+    NvAPI_Status (__cdecl *Stereo_IsEnabled)(uint8_t *pIsStereoEnabled);
+
+    NvAPI_Status (__cdecl *Stereo_CreateHandleFromIUnknown)(IUnknown *pDevice,
+                                                            StereoHandle *pStereoHandle);
+    NvAPI_Status (__cdecl *Stereo_DestroyHandle)(StereoHandle stereoHandle);
+
+    NvAPI_Status (__cdecl *Stereo_IsActivated)(StereoHandle stereoHandle, uint8_t *pIsStereoOn);
+    NvAPI_Status (__cdecl *Stereo_Activate)(StereoHandle stereoHandle);
+    NvAPI_Status (__cdecl *Stereo_Deactivate)(StereoHandle stereoHandle);
+} NvAPIHandle;
+
+struct stereo3d_api_sys_t
+{
+    NvAPIHandle             *nvapi_handle;
+    StereoHandle            nvidia_3dvision_handle;
+    LPDIRECT3DSURFACE9      nvidia_3dvision_surface;
+};
+
+int Nvidia3DVisionLoad(Stereo3DAPI *s)
+{
+    stereo3d_api_sys_t *sys = calloc(1, sizeof(*sys));
+    if (!sys)
+        return VLC_ENOMEM;
+    s->sys = sys;
+
+    sys->nvapi_handle = calloc(1, sizeof(*sys->nvapi_handle));
+    if (!sys->nvapi_handle)
+    {
+        msg_Warn(s->vd, "Initialization of NVIDIA 3D Vision failed: could not find NvAPI dll.");
+        goto error;
+
+    }
+    NvAPIHandle *nvapi_handle = sys->nvapi_handle;
+
+    HINSTANCE nvapi_dll = LoadLibraryA("nvapi.dll");
+    if (!nvapi_dll)
+    {
+        msg_Dbg(s->vd, "Could not load NvAPI library (nvapi.dll)");
+        goto error;
+    }
+    nvapi_handle->instance = nvapi_dll;
+
+    nvapi_handle->initialized = false;
+    nvapi_handle->QueryInterface = (void *)GetProcAddress(nvapi_handle->instance, "nvapi_QueryInterface");
+
+    if (!nvapi_handle->QueryInterface)
+    {
+        msg_Err(s->vd, "Could not find NvAPI_QueryInterface in the NvAPI dll.");
+        goto error;
+    }
+
+    nvapi_handle->Initialize = nvapi_handle->QueryInterface(0x0150E828);
+    nvapi_handle->Unload = nvapi_handle->QueryInterface(0xD22BDD7E);
+    nvapi_handle->Stereo_IsEnabled = nvapi_handle->QueryInterface(0x348FF8E1);
+    nvapi_handle->Stereo_CreateHandleFromIUnknown = nvapi_handle->QueryInterface(0xAC7E37F4);
+    nvapi_handle->Stereo_DestroyHandle = nvapi_handle->QueryInterface(0x3A153134);
+    nvapi_handle->Stereo_IsActivated = nvapi_handle->QueryInterface(0x1FB0BC30);
+    nvapi_handle->Stereo_Activate = nvapi_handle->QueryInterface(0xF6A1AD68);
+    nvapi_handle->Stereo_Deactivate = nvapi_handle->QueryInterface(0x2D68DE96);
+
+    if (!nvapi_handle->Initialize || !nvapi_handle->Unload || !nvapi_handle->Stereo_IsEnabled
+        || !nvapi_handle->Stereo_CreateHandleFromIUnknown || !nvapi_handle->Stereo_DestroyHandle
+        || !nvapi_handle->Stereo_IsActivated || !nvapi_handle->Stereo_Activate
+        || !nvapi_handle->Stereo_Deactivate)
+    {
+        msg_Err(s->vd, "Could not load all NvAPI functions.");
+        goto error;
+    }
+
+    NvAPI_Status status = nvapi_handle->Initialize();
+    if (status != NVAPI_OK)
+    {
+        msg_Warn(s->vd, "Could not initialize NvAPI (err=%d).", status);
+        goto error;
+    }
+    nvapi_handle->initialized = true;
+
+    uint8_t stereoEnabled;
+    status = nvapi_handle->Stereo_IsEnabled(&stereoEnabled);
+    if (status != NVAPI_OK)
+    {
+        msg_Warn(s->vd, "Could not get NVIDIA 3D Vision status (err=%d).", status);
+        goto error;
+    }
+
+    if (!stereoEnabled)
+    {
+        msg_Warn(s->vd, "NVIDIA 3D Vision should be enabled from the NVIDIA Control Panel");
+        goto error;
+    }
+
+    s->unload = Nvidia3DVisionUnload;
+    s->create_resources = Nvidia3DVisionCreateResources;
+    s->destroy_resources = Nvidia3DVisionDestroyResources;
+    s->create_scene = Nvidia3DVisionCreateScene;
+    s->destroy_scene = Nvidia3DVisionDestroyScene;
+    s->can_render = Nvidia3DVisionCanRender;
+    s->render_region = Nvidia3DVisionRenderRegion;
+
+    if (s->vd->fmt.stereo.mode != VLC_STEREO3D_SBS
+        && s->vd->fmt.stereo.mode != VLC_STEREO3D_TB)
+    {
+        /* Unsupported stereo mode: request a conversion to SBS */
+        s->vd->fmt.stereo.mode = VLC_STEREO3D_SBS;
+    }
+
+    return VLC_SUCCESS;
+
+error:
+    Nvidia3DVisionUnload(s);
+    return VLC_EGENERIC;
+}
+
+static void Nvidia3DVisionUnload(Stereo3DAPI *s)
+{
+    stereo3d_api_sys_t *sys = s->sys;
+    NvAPIHandle *nvapi_handle = sys->nvapi_handle;
+
+    if (!nvapi_handle)
+        return;
+
+    if (nvapi_handle->instance)
+    {
+        if (nvapi_handle->initialized)
+            nvapi_handle->Unload();
+        FreeLibrary(nvapi_handle->instance);
+    }
+
+    free(nvapi_handle);
+    sys->nvapi_handle = NULL;
+    sys->nvidia_3dvision_handle = NULL;
+}
+
+static int Nvidia3DVisionCreateResources(Stereo3DAPI *s)
+{
+    vout_display_sys_t *vd_sys = s->vd->sys;
+    stereo3d_api_sys_t *sys = s->sys;
+    NvAPIHandle *nvapi_handle = sys->nvapi_handle;
+    NvAPI_Status status;
+
+    status = nvapi_handle->Stereo_CreateHandleFromIUnknown((IUnknown*)vd_sys->d3ddev,
+                                                           &sys->nvidia_3dvision_handle);
+    if (status != NVAPI_OK)
+    {
+        msg_Err(s->vd, "could not create NVIDIA 3D Vision handle (err=%d)", status);
+        return VLC_EGENERIC;
+    }
+
+    status = nvapi_handle->Stereo_Activate(sys->nvidia_3dvision_handle);
+    if (status != NVAPI_OK)
+    {
+        Nvidia3DVisionDestroyResources(s);
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+static void Nvidia3DVisionDestroyResources(Stereo3DAPI *s)
+{
+    stereo3d_api_sys_t *sys = s->sys;
+    NvAPIHandle *nvapi_handle = sys->nvapi_handle;
+
+    nvapi_handle->Stereo_DestroyHandle(sys->nvidia_3dvision_handle);
+    sys->nvidia_3dvision_handle = NULL;
+}
+
+static int Nvidia3DVisionCreateScene(Stereo3DAPI *s,
+                                     const video_format_t *fmt)
+{
+    VLC_UNUSED(fmt);
+
+    vout_display_sys_t *vd_sys = s->vd->sys;
+    stereo3d_api_sys_t *sys = s->sys;
+    LPDIRECT3DDEVICE9 d3ddev = vd_sys->d3ddev;
+    HRESULT hr;
+
+    LPDIRECT3DSURFACE9 nvidia_3dvision_surface;
+    hr = IDirect3DDevice9_CreateRenderTarget(d3ddev, vd_sys->rect_display.right * 2,
+                                             vd_sys->rect_display.bottom + 1,
+                                             D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE,
+                                             0, TRUE, &nvidia_3dvision_surface, NULL);
+    if (FAILED(hr))
+    {
+        msg_Err(s->vd, "Failed to create stereo surface. (hr=0x%lx)", hr);
+        return VLC_EGENERIC;
+    }
+
+    sys->nvidia_3dvision_surface = nvidia_3dvision_surface;
+
+    return VLC_SUCCESS;
+}
+
+static void Nvidia3DVisionDestroyScene(Stereo3DAPI *s)
+{
+    stereo3d_api_sys_t *sys = s->sys;
+
+    if (sys->nvidia_3dvision_surface)
+        IDirect3DSurface9_Release(sys->nvidia_3dvision_surface);
+    sys->nvidia_3dvision_surface = NULL;
+}
+
+static bool Nvidia3DVisionCanRender(Stereo3DAPI *s)
+{
+    stereo3d_api_sys_t *sys = s->sys;
+
+    uint8_t stereo_enabled = 0;
+    NvAPI_Status status;
+    status = sys->nvapi_handle->Stereo_IsActivated(sys->nvidia_3dvision_handle, &stereo_enabled);
+    return status == NVAPI_OK && stereo_enabled;
+}
+
+static int Nvidia3DVisionRenderRegion(Stereo3DAPI *s,
+                                      d3d_region_t *region)
+{
+    vout_display_sys_t *vd_sys = s->vd->sys;
+    stereo3d_api_sys_t *sys = s->sys;
+    LPDIRECT3DDEVICE9 d3ddev = vd_sys->d3ddev;
+    HRESULT hr;
+
+    LPDIRECT3DSURFACE9 stereo_picture;
+    hr = IDirect3DTexture9_GetSurfaceLevel(vd_sys->d3dtex, 0, &stereo_picture);
+    if (FAILED(hr))
+    {
+        msg_Dbg(s->vd, "%s:%d (hr=0x%0lX)", __FUNCTION__, __LINE__, hr);
+        return VLC_EGENERIC;
+    }
+
+    int width = region->width;
+    int height = region->height;
+    RECT src_left;
+    RECT src_right;
+    if (s->vd->fmt.stereo.mode == VLC_STEREO3D_SBS)
+    {
+        src_left = (RECT){ 0, 0, width / 2, height };
+        src_right = (RECT){ width / 2, 0, width, height };
+    }
+    else
+    {
+        src_left = (RECT){ 0, 0, width, height / 2 };
+        src_right = (RECT){ 0, height / 2, width, height };
+    }
+
+    RECT dst_left = vd_sys->rect_dest_clipped;
+    IDirect3DDevice9_StretchRect(d3ddev, stereo_picture, &src_left,
+                                 sys->nvidia_3dvision_surface, &dst_left,
+                                 D3DTEXF_LINEAR);
+
+    RECT dst_right = { vd_sys->rect_display.right, dst_left.top,
+                       dst_left.right + vd_sys->rect_display.right, dst_left.bottom };
+    IDirect3DDevice9_StretchRect(d3ddev, stereo_picture, &src_right,
+                                 sys->nvidia_3dvision_surface, &dst_right,
+                                 D3DTEXF_LINEAR);
+
+    IDirect3DSurface9_Release(stereo_picture);
+
+    /*
+     * Write the 3D Vision signature at the beginning of the extra
+     * line at the bottom of the stereoscopy surface.
+     */
+    D3DLOCKED_RECT lock;
+    IDirect3DSurface9_LockRect(sys->nvidia_3dvision_surface, &lock, NULL, 0);
+    uint8_t *surface_data = lock.pBits;
+    NVSTEREOIMAGEHEADER *stereo_header = (NVSTEREOIMAGEHEADER *)(surface_data + lock.Pitch * vd_sys->rect_display.bottom);
+    stereo_header->dwSignature = NVSTEREO_IMAGE_SIGNATURE;
+    /* 3D Vision is Right-Left by default. */
+    if (s->vd->fmt.stereo.flags & VLC_STEREO3D_SWAP_EYES)
+        stereo_header->dwFlags = 0;
+    else
+        stereo_header->dwFlags = DXNV_SWAP_EYES;
+
+    /* These fields seems to be currently ignored and could be omitted. */
+    stereo_header->dwBPP = 32;
+    stereo_header->dwWidth = vd_sys->rect_display.right * 2;
+    stereo_header->dwHeight = vd_sys->rect_display.bottom;
+
+    IDirect3DSurface9_UnlockRect(sys->nvidia_3dvision_surface);
+
+    LPDIRECT3DSURFACE9 d3dback_buffer;
+    hr = IDirect3DDevice9_GetBackBuffer(d3ddev, 0, 0, D3DBACKBUFFER_TYPE_MONO,
+                                        &d3dback_buffer);
+    if (FAILED(hr))
+    {
+        msg_Err(s->vd, "Failed to get device back buffer. (hr=0x%lx)", hr);
+        return VLC_EGENERIC;
+    }
+
+    /* copy stereo surface into back buffer */
+    IDirect3DDevice9_StretchRect(d3ddev, sys->nvidia_3dvision_surface, NULL,
+                                 d3dback_buffer, NULL, D3DTEXF_LINEAR);
+
+    IDirect3DSurface9_Release(d3dback_buffer);
+
+    return VLC_SUCCESS;
+}
diff --git a/modules/video_output/msw/nvidia_3dvision.h b/modules/video_output/msw/nvidia_3dvision.h
new file mode 100644
index 0000000..91a9983
--- /dev/null
+++ b/modules/video_output/msw/nvidia_3dvision.h
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * nvidia_3dvision.h
+ *****************************************************************************
+ * Copyright (C) 2014 the VideoLAN team
+ *
+ * Authors: Felix Abecassis <felix.abecassis at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef NVIDIA_3DVISION_H_
+# define NVIDIA_3DVISION_H_
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include "stereo3d_api.h"
+
+int Nvidia3DVisionLoad(Stereo3DAPI *);
+
+#endif
diff --git a/modules/video_output/msw/stereo3d_api.c b/modules/video_output/msw/stereo3d_api.c
new file mode 100644
index 0000000..441f8ce
--- /dev/null
+++ b/modules/video_output/msw/stereo3d_api.c
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * stereo3d_api.c
+ *****************************************************************************
+ * Copyright (C) 2014 the VideoLAN team
+ *
+ * Authors: Felix Abecassis <felix.abecassis at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "stereo3d_api.h"
+
+/* The APIs */
+#include "nvidia_3dvision.h"
+
+Stereo3DAPI *Stereo3DAPI_Load(vout_display_t *vd)
+{
+    Stereo3DAPI *s = calloc(1, sizeof(*s));
+    if (!s)
+        return NULL;
+
+    s->vd = vd;
+
+    /* NVIDIA 3D Vision is the only available API currently */
+    if (Nvidia3DVisionLoad(s))
+        goto error;
+
+    return s;
+
+error:
+    free(s);
+    return NULL;
+}
+
+void Stereo3DAPI_Unload(Stereo3DAPI *s)
+{
+    s->unload(s);
+    free(s);
+}
diff --git a/modules/video_output/msw/stereo3d_api.h b/modules/video_output/msw/stereo3d_api.h
new file mode 100644
index 0000000..457dc84
--- /dev/null
+++ b/modules/video_output/msw/stereo3d_api.h
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ * stereo3d_api.h
+ *****************************************************************************
+ * Copyright (C) 2014 the VideoLAN team
+ *
+ * Authors: Felix Abecassis <felix.abecassis at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef STEREO3D_API_H_
+# define STEREO3D_API_H_
+
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+
+# include <vlc_common.h>
+# include <vlc_vout_display.h>
+
+typedef struct Stereo3DAPI Stereo3DAPI;
+typedef struct stereo3d_api_sys_t stereo3d_api_sys_t;
+typedef struct d3d_region_t d3d_region_t;
+
+struct Stereo3DAPI
+{
+    void (*unload)(Stereo3DAPI *);
+
+    int  (*create_resources)(Stereo3DAPI *);
+    void (*destroy_resources)(Stereo3DAPI *);
+
+    int  (*create_scene)(Stereo3DAPI *, const video_format_t *);
+    void (*destroy_scene)(Stereo3DAPI *);
+
+    bool (*can_render)(Stereo3DAPI *);
+    int  (*render_region)(Stereo3DAPI *, d3d_region_t *);
+
+    vout_display_t *vd;
+    stereo3d_api_sys_t *sys;
+};
+
+Stereo3DAPI *Stereo3DAPI_Load(vout_display_t *);
+void Stereo3DAPI_Unload(Stereo3DAPI *s);
+
+static inline int Stereo3DAPI_CreateResources(Stereo3DAPI *s)
+{
+    return s->create_resources(s);
+}
+
+static inline void Stereo3DAPI_DestroyResources(Stereo3DAPI *s)
+{
+    s->destroy_resources(s);
+}
+
+static inline int Stereo3DAPI_CreateScene(Stereo3DAPI *s, const video_format_t *fmt)
+{
+    return s->create_scene(s, fmt);
+}
+
+static inline void Stereo3DAPI_DestroyScene(Stereo3DAPI *s)
+{
+    s->destroy_scene(s);
+}
+
+static inline bool Stereo3DAPI_CanRender(Stereo3DAPI *s)
+{
+    return s->can_render(s);
+}
+
+static inline int Stereo3DAPI_RenderRegion(Stereo3DAPI *s, d3d_region_t *r)
+{
+    return s->render_region(s, r);
+}
+
+#endif
-- 
1.9.1




More information about the vlc-devel mailing list