[vlc-commits] direct3d9: add OpenGL interop using WGL_NV_DX_interop ext
Thomas Guillem
git at videolan.org
Mon Nov 13 13:12:17 CET 2017
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Nov 9 16:09:46 2017 +0100| [b6bbde66665dc451c45d15380e33a29b24585884] | committer: Thomas Guillem
direct3d9: add OpenGL interop using WGL_NV_DX_interop ext
See https://www.khronos.org/registry/OpenGL/extensions/NV/WGL_NV_DX_interop.txt
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=b6bbde66665dc451c45d15380e33a29b24585884
---
modules/video_output/win32/direct3d9.c | 226 +++++++++++++++++++++++++++++++++
1 file changed, 226 insertions(+)
diff --git a/modules/video_output/win32/direct3d9.c b/modules/video_output/win32/direct3d9.c
index ed1cfd1758..0d81a6b35f 100644
--- a/modules/video_output/win32/direct3d9.c
+++ b/modules/video_output/win32/direct3d9.c
@@ -63,6 +63,9 @@
static int Open(vlc_object_t *);
static void Close(vlc_object_t *);
+static int GLConvOpen(vlc_object_t *);
+static void GLConvClose(vlc_object_t *);
+
#define DESKTOP_LONGTEXT N_(\
"The desktop mode allows you to display the video on the desktop.")
@@ -100,6 +103,10 @@ vlc_module_begin ()
add_shortcut("direct3d9", "direct3d")
set_callbacks(Open, Close)
+ add_submodule()
+ set_description("DX OpenGL surface converter for D3D9")
+ set_capability("glconv", 1)
+ set_callbacks(GLConvOpen, GLConvClose)
vlc_module_end ()
/*****************************************************************************
@@ -1971,3 +1978,222 @@ static int FindShadersCallback(vlc_object_t *object, const char *name,
return ctx.count;
}
+
+#include "../opengl/converter.h"
+#include <GL/wglew.h>
+
+struct wgl_vt {
+ PFNWGLDXSETRESOURCESHAREHANDLENVPROC DXSetResourceShareHandleNV;
+ PFNWGLDXOPENDEVICENVPROC DXOpenDeviceNV;
+ PFNWGLDXCLOSEDEVICENVPROC DXCloseDeviceNV;
+ PFNWGLDXREGISTEROBJECTNVPROC DXRegisterObjectNV;
+ PFNWGLDXUNREGISTEROBJECTNVPROC DXUnregisterObjectNV;
+ PFNWGLDXLOCKOBJECTSNVPROC DXLockObjectsNV;
+ PFNWGLDXUNLOCKOBJECTSNVPROC DXUnlockObjectsNV;
+};
+struct glpriv
+{
+ struct wgl_vt vt;
+ struct d3dctx d3dctx;
+ HANDLE gl_handle_d3d;
+ HANDLE gl_render;
+ IDirect3DSurface9 *dx_render;
+};
+
+static int
+GLConvUpdate(const opengl_tex_converter_t *tc, GLuint *textures,
+ const GLsizei *tex_width, const GLsizei *tex_height,
+ picture_t *pic, const size_t *plane_offset)
+{
+ VLC_UNUSED(textures); VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); VLC_UNUSED(plane_offset);
+ struct glpriv *priv = tc->priv;
+ HRESULT hr;
+
+ picture_sys_t *picsys = ActivePictureSys(pic);
+ if (!picsys)
+ return VLC_EGENERIC;
+
+ if (!priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
+ {
+ msg_Warn(tc->gl, "DXUnlockObjectsNV failed");
+ return VLC_EGENERIC;
+ }
+
+ hr = IDirect3DDevice9Ex_StretchRect(priv->d3dctx.devex, picsys->surface,
+ NULL, priv->dx_render, NULL, D3DTEXF_NONE);
+ if (FAILED(hr))
+ {
+ msg_Warn(tc->gl, "IDirect3DDevice9Ex_StretchRect failed");
+ return VLC_EGENERIC;
+ }
+
+ if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
+ {
+ msg_Warn(tc->gl, "DXLockObjectsNV failed");
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+static picture_pool_t *
+GLConvGetPool(const opengl_tex_converter_t *tc, unsigned requested_count)
+{
+ struct glpriv *priv = tc->priv;
+ return Direct3D9CreatePicturePool(VLC_OBJECT(tc->gl), &priv->d3dctx, NULL,
+ &tc->fmt, requested_count);
+}
+
+static int
+GLConvAllocateTextures(const opengl_tex_converter_t *tc, GLuint *textures,
+ const GLsizei *tex_width, const GLsizei *tex_height)
+{
+ VLC_UNUSED(tex_width); VLC_UNUSED(tex_height);
+ struct glpriv *priv = tc->priv;
+ tc->vt->GenTextures(1, textures);
+
+ tc->vt->ActiveTexture(GL_TEXTURE0);
+ tc->vt->BindTexture(tc->tex_target, textures[0]);
+ tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ tc->vt->TexParameteri(tc->tex_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ tc->vt->TexParameterf(tc->tex_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ priv->gl_render =
+ priv->vt.DXRegisterObjectNV(priv->gl_handle_d3d, priv->dx_render,
+ textures[0], GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV);
+ if (!priv->gl_render)
+ {
+ msg_Warn(tc->gl, "DXRegisterObjectNV failed: %lu", GetLastError());
+ return VLC_EGENERIC;
+ }
+
+ if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
+ {
+ msg_Warn(tc->gl, "DXLockObjectsNV failed");
+ priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
+ priv->gl_render = NULL;
+ return VLC_EGENERIC;
+ }
+
+ return VLC_SUCCESS;
+}
+
+static void
+GLConvClose(vlc_object_t *obj)
+{
+ opengl_tex_converter_t *tc = (void *)obj;
+ struct glpriv *priv = tc->priv;
+
+ if (priv->gl_handle_d3d)
+ {
+ if (priv->gl_render)
+ {
+ priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render);
+ priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
+ }
+
+ priv->vt.DXCloseDeviceNV(priv->gl_handle_d3d);
+ }
+
+ if (priv->dx_render)
+ IDirect3DSurface9_Release(priv->dx_render);
+
+ Direct3D9DestroyDevice(obj, &priv->d3dctx);
+ Direct3D9Destroy(obj, &priv->d3dctx);
+ free(tc->priv);
+}
+
+static int
+GLConvOpen(vlc_object_t *obj)
+{
+ opengl_tex_converter_t *tc = (void *) obj;
+
+ if (tc->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE
+ && tc->fmt.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
+ return VLC_EGENERIC;
+
+ if (tc->gl->ext != VLC_GL_EXT_WGL || !tc->gl->wgl.getExtensionsString)
+ return VLC_EGENERIC;
+
+ const char *wglExt = tc->gl->wgl.getExtensionsString(tc->gl);
+
+ if (wglExt == NULL || !HasExtension(wglExt, "WGL_NV_DX_interop"))
+ return VLC_EGENERIC;
+
+ struct wgl_vt vt;
+#define LOAD_EXT(name, type) do { \
+ vt.name = (type) vlc_gl_GetProcAddress(tc->gl, "wgl" #name); \
+ if (!vt.name) { \
+ msg_Warn(obj, "'wgl " #name "' could not be loaded"); \
+ return VLC_EGENERIC; \
+ } \
+} while(0)
+
+ LOAD_EXT(DXSetResourceShareHandleNV, PFNWGLDXSETRESOURCESHAREHANDLENVPROC);
+ LOAD_EXT(DXOpenDeviceNV, PFNWGLDXOPENDEVICENVPROC);
+ LOAD_EXT(DXCloseDeviceNV, PFNWGLDXCLOSEDEVICENVPROC);
+ LOAD_EXT(DXRegisterObjectNV, PFNWGLDXREGISTEROBJECTNVPROC);
+ LOAD_EXT(DXUnregisterObjectNV, PFNWGLDXUNREGISTEROBJECTNVPROC);
+ LOAD_EXT(DXLockObjectsNV, PFNWGLDXLOCKOBJECTSNVPROC);
+ LOAD_EXT(DXUnlockObjectsNV, PFNWGLDXUNLOCKOBJECTSNVPROC);
+
+ struct glpriv *priv = calloc(1, sizeof(struct glpriv));
+ if (!priv)
+ return VLC_ENOMEM;
+ tc->priv = priv;
+ priv->vt = vt;
+
+ priv->d3dctx = (struct d3dctx) { .hwnd = tc->gl->surface->handle.hwnd };
+ if (Direct3D9Create(obj, &priv->d3dctx, &tc->fmt) != VLC_SUCCESS)
+ goto error;
+
+ if (!priv->d3dctx.use_ex)
+ {
+ msg_Warn(obj, "DX/GL interrop only working on d3d9x");
+ goto error;
+ }
+
+ if (Direct3D9CreateDevice(obj, &priv->d3dctx, &tc->fmt) != VLC_SUCCESS)
+ goto error;
+
+ HRESULT hr;
+ HANDLE shared_handle = NULL;
+ hr = IDirect3DDevice9_CreateOffscreenPlainSurface(priv->d3dctx.dev,
+ tc->fmt.i_width,
+ tc->fmt.i_height,
+ D3DFMT_X8R8G8B8,
+ D3DPOOL_DEFAULT,
+ &priv->dx_render,
+ &shared_handle);
+ if (FAILED(hr))
+ {
+ msg_Warn(obj, "IDirect3DDevice9_CreateOffscreenPlainSurface failed");
+ goto error;
+ }
+
+ if (shared_handle)
+ priv->vt.DXSetResourceShareHandleNV(priv->dx_render, shared_handle);
+
+ priv->gl_handle_d3d = priv->vt.DXOpenDeviceNV(priv->d3dctx.dev);
+ if (!priv->gl_handle_d3d)
+ {
+ msg_Warn(obj, "DXOpenDeviceNV failed: %lu", GetLastError());
+ goto error;
+ }
+
+ tc->pf_update = GLConvUpdate;
+ tc->pf_get_pool = GLConvGetPool;
+ tc->pf_allocate_textures = GLConvAllocateTextures;
+
+ tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D, VLC_CODEC_RGB32,
+ COLOR_SPACE_UNDEF);
+ if (tc->fshader == 0)
+ goto error;
+
+ return VLC_SUCCESS;
+
+error:
+ GLConvClose(obj);
+ return VLC_EGENERIC;
+}
More information about the vlc-commits
mailing list