[vlc-devel] [PATCH] vout: allow creating a pool of D3D9 GPU surfaces picture_t
Steve Lhomme
robUx4 at videolabs.io
Tue Apr 28 17:41:08 CEST 2015
---
src/Makefile.am | 9 ++
src/video_output/vout_wrapper.c | 15 ++-
src/win32/direct3d9_pool.c | 248 ++++++++++++++++++++++++++++++++++++++++
src/win32/direct3d9_pool.h | 39 +++++++
4 files changed, 307 insertions(+), 4 deletions(-)
create mode 100644 src/win32/direct3d9_pool.c
create mode 100644 src/win32/direct3d9_pool.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 1f02494..a5dba6a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -301,6 +301,15 @@ SOURCES_libvlc_win32 = \
win32/rand.c \
$(NULL)
+if HAVE_DIRECTX
+if !HAVE_WINSTORE
+SOURCES_libvlc_win32 += \
+ win32/direct3d9_pool.c \
+ win32/direct3d9_pool.h \
+ $(NULL)
+endif
+endif
+
SOURCES_libvlc_symbian = \
symbian/path.cpp \
symbian/dirs.c \
diff --git a/src/video_output/vout_wrapper.c b/src/video_output/vout_wrapper.c
index dbaae78..c6fbb87 100644
--- a/src/video_output/vout_wrapper.c
+++ b/src/video_output/vout_wrapper.c
@@ -35,6 +35,9 @@
#include <assert.h>
#include "vout_internal.h"
#include "display.h"
+#if defined(_WIN32) && defined(HAVE_D3D9_H)
+#include "../win32/direct3d9_pool.h"
+#endif
/*****************************************************************************
* Local prototypes
@@ -145,10 +148,14 @@ int vout_InitWrapper(vout_thread_t *vout)
sys->decoder_pool = display_pool;
sys->display_pool = display_pool;
} else if (!sys->decoder_pool) {
- sys->decoder_pool =
- picture_pool_NewFromFormat(&source,
- __MAX(VOUT_MAX_PICTURES,
- reserved_picture + decoder_picture - DISPLAY_PICTURE_COUNT));
+ const unsigned decoder_pool_size = __MAX(VOUT_MAX_PICTURES,
+ reserved_picture + decoder_picture - DISPLAY_PICTURE_COUNT);
+#if defined(_WIN32) && defined(HAVE_D3D9_H)
+ if (source.i_chroma == VLC_CODEC_D3D9_OPAQUE)
+ sys->decoder_pool = AllocPoolD3D9( VLC_OBJECT(vout), &source, decoder_pool_size );
+ else
+#endif
+ sys->decoder_pool = picture_pool_NewFromFormat( &source, decoder_pool_size );
if (!sys->decoder_pool)
return VLC_EGENERIC;
if (allow_dr) {
diff --git a/src/win32/direct3d9_pool.c b/src/win32/direct3d9_pool.c
new file mode 100644
index 0000000..0fdfdf7
--- /dev/null
+++ b/src/win32/direct3d9_pool.c
@@ -0,0 +1,248 @@
+/*****************************************************************************
+ * direct3d9_pool.c: Windows Direct3D9 picture pool creation
+ *****************************************************************************
+ * Copyright (C) 2015 VLC authors and VideoLAN
+ *$Id$
+ *
+ * Authors: Steve Lhomme <robux4 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "direct3d9_pool.h"
+
+static void DestroyPicture(picture_t *picture);
+
+struct picture_sys_t {
+ LPDIRECT3DSURFACE9 surface;
+ HINSTANCE hd3d9_dll;
+};
+
+picture_pool_t *AllocPoolD3D9( vlc_object_t *va, const video_format_t *fmt, unsigned pool_size )
+{
+ HINSTANCE hd3d9_dll = NULL;
+ LPDIRECT3D9 d3dobj = NULL;
+ LPDIRECT3DDEVICE9 d3ddev = NULL;
+
+ if (fmt->i_chroma != VLC_CODEC_D3D9_OPAQUE)
+ return picture_pool_NewFromFormat(fmt, pool_size);
+
+ OSVERSIONINFO winVer;
+ winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if(GetVersionEx(&winVer) && winVer.dwMajorVersion < 6) {
+ msg_Warn(va, "windows version not compatible with D3D9");
+ goto error;
+ }
+
+ hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ if (!hd3d9_dll) {
+ msg_Warn(va, "cannot load d3d9.dll, aborting");
+ goto error;
+ }
+
+ LPDIRECT3D9 (WINAPI *OurDirect3DCreate9)(UINT SDKVersion);
+ OurDirect3DCreate9 = (void *)GetProcAddress(hd3d9_dll, "Direct3DCreate9");
+ if (!OurDirect3DCreate9) {
+ msg_Err(va, "Cannot locate reference to Direct3DCreate9 ABI in DLL");
+ goto error;
+ }
+
+ /* Create the D3D object. */
+ d3dobj = OurDirect3DCreate9(D3D_SDK_VERSION);
+ if (!d3dobj) {
+ msg_Err(va, "Could not create Direct3D9 instance.");
+ goto error;
+ }
+
+ /*
+ ** Get device capabilities
+ */
+ D3DCAPS9 d3dcaps;
+ ZeroMemory(&d3dcaps, sizeof(d3dcaps));
+ HRESULT hr = IDirect3D9_GetDeviceCaps(d3dobj, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dcaps);
+ if (FAILED(hr)) {
+ msg_Err(va, "Could not read adapter capabilities. (hr=0x%0lx)", hr);
+ goto error;
+ }
+
+ /* TODO: need to test device capabilities and select the right render function */
+ if (!(d3dcaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) ||
+ !(d3dcaps.TextureFilterCaps & (D3DPTFILTERCAPS_MAGFLINEAR)) ||
+ !(d3dcaps.TextureFilterCaps & (D3DPTFILTERCAPS_MINFLINEAR))) {
+ msg_Err(va, "Device does not support stretching from textures.");
+ goto error;
+ }
+
+ // Create the D3DDevice
+ UINT AdapterToUse = D3DADAPTER_DEFAULT;
+ D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
+
+#ifndef NDEBUG
+ // Look for 'NVIDIA PerfHUD' adapter
+ // If it is present, override default settings
+ for (UINT Adapter=0; Adapter< IDirect3D9_GetAdapterCount(d3dobj); ++Adapter) {
+ D3DADAPTER_IDENTIFIER9 Identifier;
+ HRESULT Res = IDirect3D9_GetAdapterIdentifier(d3dobj,Adapter,0,&Identifier);
+ if (SUCCEEDED(Res) && strstr(Identifier.Description,"PerfHUD") != 0) {
+ AdapterToUse = Adapter;
+ DeviceType = D3DDEVTYPE_REF;
+ break;
+ }
+ }
+#endif
+
+ /* */
+ D3DADAPTER_IDENTIFIER9 d3dai;
+ if (FAILED(IDirect3D9_GetAdapterIdentifier(d3dobj,AdapterToUse,0, &d3dai))) {
+ msg_Warn(va, "IDirect3D9_GetAdapterIdentifier failed");
+ } else {
+ msg_Dbg(va, "Direct3d9 Device: %s %lu %lu %lu", d3dai.Description,
+ d3dai.VendorId, d3dai.DeviceId, d3dai.Revision );
+ }
+
+ /*
+ ** Get the current desktop display mode, so we can set up a back
+ ** buffer of the same format
+ */
+ D3DDISPLAYMODE d3ddm;
+ hr = IDirect3D9_GetAdapterDisplayMode(d3dobj, D3DADAPTER_DEFAULT, &d3ddm);
+ if (FAILED(hr)) {
+ msg_Err(va, "Could not read adapter display mode. (hr=0x%0lx)", hr);
+ goto error;
+ }
+
+ D3DPRESENT_PARAMETERS d3dpp;
+ ZeroMemory(&d3dpp, sizeof(d3dpp));
+ d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
+ d3dpp.Windowed = TRUE;
+ d3dpp.hDeviceWindow = NULL;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
+ d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ d3dpp.BackBufferCount = 0; /* FIXME may not be right */
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.BackBufferWidth = __MAX((unsigned int)GetSystemMetrics(SM_CXVIRTUALSCREEN),
+ d3ddm.Width);
+ d3dpp.BackBufferHeight = __MAX((unsigned int)GetSystemMetrics(SM_CYVIRTUALSCREEN),
+ d3ddm.Height);
+ d3dpp.EnableAutoDepthStencil = FALSE;
+
+ hr = IDirect3D9_CreateDevice(d3dobj, AdapterToUse,
+ DeviceType, GetDesktopWindow(),
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING|
+ D3DCREATE_MULTITHREADED,
+ &d3dpp, &d3ddev);
+ if (FAILED(hr)) {
+ msg_Err(va, "Could not create the D3D9 device! (hr=0x%0lx)", hr);
+ goto error;
+ }
+
+ picture_pool_t *result = AllocPoolD3D9Ex(va, d3ddev, fmt, pool_size);
+ if (!result)
+ goto error;
+
+ FreeLibrary(hd3d9_dll);
+ return result;
+
+error:
+ if (d3ddev)
+ IDirect3DDevice9_Release(d3ddev);
+ if (d3dobj)
+ IDirect3D9_Release(d3dobj);
+ if (hd3d9_dll)
+ FreeLibrary(hd3d9_dll);
+ return NULL;
+}
+
+picture_pool_t *AllocPoolD3D9Ex(vlc_object_t *va, LPDIRECT3DDEVICE9 d3ddev,
+ const video_format_t *fmt, unsigned pool_size)
+{
+ picture_t** pictures = NULL;
+ unsigned picture_count = 0;
+
+ pictures = calloc(pool_size, sizeof(*pictures));
+ if (!pictures)
+ goto error;
+ for (picture_count = 0; picture_count < pool_size; ++picture_count)
+ {
+ picture_sys_t *picsys = malloc(sizeof(*picsys));
+ if (unlikely(picsys == NULL))
+ goto error;
+
+ HRESULT hr = IDirect3DDevice9_CreateOffscreenPlainSurface(d3ddev,
+ fmt->i_visible_width,
+ fmt->i_visible_height,
+ MAKEFOURCC('N','V','1','2'), /* FIXME d3ddm.Format, */
+ D3DPOOL_DEFAULT,
+ &picsys->surface,
+ NULL);
+ if (FAILED(hr)) {
+ msg_Err(va, "Failed to allocate surface %d (hr=0x%0lx)", picture_count, hr);
+ goto error;
+ }
+
+ picture_resource_t resource = {
+ .p_sys = picsys,
+ .pf_destroy = DestroyPicture,
+ };
+
+ picture_t *picture = picture_NewFromResource(fmt, &resource);
+ if (unlikely(picture == NULL)) {
+ free(picsys);
+ goto error;
+ }
+
+ pictures[picture_count] = picture;
+ /* each picture_t holds a ref to the device and release it on Destroy */
+ IDirect3DDevice9_AddRef(d3ddev);
+ /* each picture_t holds a ref to the DLL */
+ picsys->hd3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
+ }
+
+ /* release the system resources, they will be free'd with the pool */
+ IDirect3DDevice9_Release(d3ddev);
+
+ picture_pool_configuration_t pool_cfg;
+ memset(&pool_cfg, 0, sizeof(pool_cfg));
+ pool_cfg.picture_count = pool_size;
+ pool_cfg.picture = pictures;
+
+ return picture_pool_NewExtended( &pool_cfg );
+
+error:
+ if (pictures) {
+ for (unsigned i=0;i<picture_count; ++i)
+ DestroyPicture(pictures[i]);
+ free(pictures);
+ }
+ return NULL;
+}
+
+static void DestroyPicture(picture_t *picture)
+{
+ LPDIRECT3DDEVICE9 d3ddev;
+ if (!FAILED(IDirect3DSurface9_GetDevice(picture->p_sys->surface, &d3ddev)))
+ IDirect3DDevice9_Release(d3ddev);
+
+ IDirect3DSurface9_Release(picture->p_sys->surface);
+
+ FreeLibrary(picture->p_sys->hd3d9_dll);
+
+ free(picture->p_sys);
+}
diff --git a/src/win32/direct3d9_pool.h b/src/win32/direct3d9_pool.h
new file mode 100644
index 0000000..b1b9fe2
--- /dev/null
+++ b/src/win32/direct3d9_pool.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * direct3d9_pool.c: Windows Direct3D9 picture pool creation
+ *****************************************************************************
+ * Copyright (C) 2015 VLC authors and VideoLAN
+ *$Id$
+ *
+ * Authors: Steve Lhomme <robux4 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 WIN32_DIRECT3D9_POOL_H_
+#define WIN32_DIRECT3D9_POOL_H_
+
+#include <windows.h>
+#include <d3d9.h>
+
+#include <vlc_common.h>
+#include <vlc_picture_pool.h>
+
+#define VA_DXVA2_MAX_SURFACE_COUNT (64)
+
+picture_pool_t *AllocPoolD3D9( vlc_object_t *obj, const video_format_t *p_fmt, unsigned pool_size );
+picture_pool_t *AllocPoolD3D9Ex(vlc_object_t *obj, LPDIRECT3DDEVICE9 d3ddev,
+ const video_format_t *fmt, unsigned pool_size);
+
+#endif /* WIN32_DIRECT3D9_POOL_H_ */
--
2.3.2
More information about the vlc-devel
mailing list