diff --git a/src/directx/SurfaceInteropD3D9GL.cpp b/src/directx/SurfaceInteropD3D9GL.cpp index cec481449..a7b76abdc 100644 --- a/src/directx/SurfaceInteropD3D9GL.cpp +++ b/src/directx/SurfaceInteropD3D9GL.cpp @@ -25,25 +25,8 @@ #include "opengl/OpenGLHelper.h" //dynamic gl or desktop gl -#define WGL_ENSURE(x, ...) \ - do { \ - if (!(x)) { \ - qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \ - return __VA_ARGS__; \ - } \ - } while(0) -#define WGL_WARN(x, ...) \ - do { \ - if (!(x)) { \ - qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \ - } \ - } while(0) - -//#include //not found in vs2013 - namespace QtAV { namespace d3d9 { -struct WGL; class GLInteropResource Q_DECL_FINAL: public InteropResource { public: @@ -52,12 +35,10 @@ class GLInteropResource Q_DECL_FINAL: public InteropResource bool map(IDirect3DSurface9 *surface, GLuint tex, int frame_w, int frame_h, int) Q_DECL_OVERRIDE; bool unmap(GLuint tex) Q_DECL_OVERRIDE; private: - bool ensureWGL(); bool ensureResource(int w, int h, GLuint tex); HANDLE interop_dev; HANDLE interop_obj; - WGL *wgl; }; InteropResource* CreateInteropGL(IDirect3DDevice9 *dev) @@ -65,45 +46,16 @@ InteropResource* CreateInteropGL(IDirect3DDevice9 *dev) return new GLInteropResource(dev); } -#define WGL_ACCESS_READ_ONLY_NV 0x00000000 -#define WGL_ACCESS_READ_WRITE_NV 0x00000001 -#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 -typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle); -typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice); -typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice); -typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject); -typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access); -typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); -typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects); - -//https://www.opengl.org/registry/specs/NV/DX_interop.txt -struct WGL { - PFNWGLDXSETRESOURCESHAREHANDLENVPROC DXSetResourceShareHandleNV; - PFNWGLDXOPENDEVICENVPROC DXOpenDeviceNV; - PFNWGLDXCLOSEDEVICENVPROC DXCloseDeviceNV; - PFNWGLDXREGISTEROBJECTNVPROC DXRegisterObjectNV; - PFNWGLDXUNREGISTEROBJECTNVPROC DXUnregisterObjectNV; - PFNWGLDXOBJECTACCESSNVPROC DXObjectAccessNV; - PFNWGLDXLOCKOBJECTSNVPROC DXLockObjectsNV; - PFNWGLDXUNLOCKOBJECTSNVPROC DXUnlockObjectsNV; -}; - GLInteropResource::GLInteropResource(IDirect3DDevice9 *d3device) : InteropResource(d3device) , interop_dev(NULL) , interop_obj(NULL) - , wgl(0) { } GLInteropResource::~GLInteropResource() { // FIXME: why unregister/close interop obj/dev here will crash(tested on intel driver)? must be in current opengl context? - if (wgl) { - delete wgl; - wgl = NULL; - } } bool GLInteropResource::map(IDirect3DSurface9 *surface, GLuint tex, int w, int h, int) @@ -114,15 +66,15 @@ bool GLInteropResource::map(IDirect3DSurface9 *surface, GLuint tex, int w, int h } // open/close and register/unregster in every map/unmap to ensure called in current context and avoid crash (tested on intel driver) // interop operations begin - WGL_ENSURE((interop_dev = wgl->DXOpenDeviceNV(d3ddev)) != NULL, false); + WGL_ENSURE((interop_dev = gl().DXOpenDeviceNV(d3ddev)) != NULL, false); // call in ensureResource or in map? - WGL_ENSURE((interop_obj = wgl->DXRegisterObjectNV(interop_dev, dx_surface, tex, GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV)) != NULL, false); + WGL_ENSURE((interop_obj = gl().DXRegisterObjectNV(interop_dev, dx_surface, tex, GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV)) != NULL, false); // prepare dx resources for gl const RECT src = { 0, 0, w, h}; DX_ENSURE_OK(d3ddev->StretchRect(surface, &src, dx_surface, NULL, D3DTEXF_NONE), false); // lock dx resources - WGL_ENSURE(wgl->DXLockObjectsNV(interop_dev, 1, &interop_obj), false); - WGL_ENSURE(wgl->DXObjectAccessNV(interop_obj, WGL_ACCESS_READ_ONLY_NV), false); + WGL_ENSURE(gl().DXLockObjectsNV(interop_dev, 1, &interop_obj), false); + WGL_ENSURE(gl().DXObjectAccessNV(interop_obj, WGL_ACCESS_READ_ONLY_NV), false); DYGL(glBindTexture(GL_TEXTURE_2D, tex)); return true; } @@ -133,55 +85,21 @@ bool GLInteropResource::unmap(GLuint tex) if (!interop_obj || !interop_dev) return false; DYGL(glBindTexture(GL_TEXTURE_2D, 0)); - WGL_ENSURE(wgl->DXUnlockObjectsNV(interop_dev, 1, &interop_obj), false); - WGL_WARN(wgl->DXUnregisterObjectNV(interop_dev, interop_obj)); + WGL_ENSURE(gl().DXUnlockObjectsNV(interop_dev, 1, &interop_obj), false); + WGL_WARN(gl().DXUnregisterObjectNV(interop_dev, interop_obj)); // interop operations end - WGL_WARN(wgl->DXCloseDeviceNV(interop_dev)); + WGL_WARN(gl().DXCloseDeviceNV(interop_dev)); interop_obj = NULL; interop_dev = NULL; return true; } // IDirect3DDevice9 can not be used on WDDM OSes(>=vista) -bool GLInteropResource::ensureWGL() -{ - if (wgl) - return true; - static const char* ext[] = { - "WGL_NV_DX_interop2", - "WGL_NV_DX_interop", - NULL, - }; - if (!OpenGLHelper::hasExtension(ext)) { // TODO: use wgl getprocaddress function (for qt4) - qWarning("WGL_NV_DX_interop is required"); - } - wgl = new WGL(); - memset(wgl, 0, sizeof(*wgl)); - const QOpenGLContext *ctx = QOpenGLContext::currentContext(); //const for qt4 - // QGLContext::getProcAddress(const QByteArray&), QOpenGLContext::getProcAddress(const QString&). So to work with QT_NO_CAST_FROM_ASCII we need a wrapper -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) -#define QB(x) x -#else -#define QB(x) QString::fromLatin1(x) -#endif - wgl->DXSetResourceShareHandleNV = (PFNWGLDXSETRESOURCESHAREHANDLENVPROC)ctx->getProcAddress(QB("wglDXSetResourceShareHandleNV")); - wgl->DXOpenDeviceNV = (PFNWGLDXOPENDEVICENVPROC)ctx->getProcAddress(QB("wglDXOpenDeviceNV")); - wgl->DXCloseDeviceNV = (PFNWGLDXCLOSEDEVICENVPROC)ctx->getProcAddress(QB("wglDXCloseDeviceNV")); - wgl->DXRegisterObjectNV = (PFNWGLDXREGISTEROBJECTNVPROC)ctx->getProcAddress(QB("wglDXRegisterObjectNV")); - wgl->DXUnregisterObjectNV = (PFNWGLDXUNREGISTEROBJECTNVPROC)ctx->getProcAddress(QB("wglDXUnregisterObjectNV")); - wgl->DXObjectAccessNV = (PFNWGLDXOBJECTACCESSNVPROC)ctx->getProcAddress(QB("wglDXObjectAccessNV")); - wgl->DXLockObjectsNV = (PFNWGLDXLOCKOBJECTSNVPROC)ctx->getProcAddress(QB("wglDXLockObjectsNV")); - wgl->DXUnlockObjectsNV = (PFNWGLDXUNLOCKOBJECTSNVPROC)ctx->getProcAddress(QB("wglDXUnlockObjectsNV")); -#undef QB - Q_ASSERT(wgl->DXRegisterObjectNV); - return true; -} - bool GLInteropResource::ensureResource(int w, int h, GLuint tex) { Q_UNUSED(tex); - if (!ensureWGL()) - return false; + Q_ASSERT(gl().DXRegisterObjectNV && "WGL_NV_DX_interop is required"); + if (dx_surface && width == w && height == h) return true; releaseDX(); @@ -200,7 +118,7 @@ bool GLInteropResource::ensureResource(int w, int h, GLuint tex) &share_handle) , false); DX_ENSURE_OK(dx_texture->GetSurfaceLevel(0, &dx_surface), false); // required by d3d9 not d3d10&11: https://www.opengl.org/registry/specs/NV/DX_interop2.txt - WGL_WARN(wgl->DXSetResourceShareHandleNV(dx_surface, share_handle)); + WGL_WARN(gl().DXSetResourceShareHandleNV(dx_surface, share_handle)); width = w; height = h; return true; diff --git a/src/opengl/OpenGLHelper.h b/src/opengl/OpenGLHelper.h index 5a8a9482a..c107c3bde 100644 --- a/src/opengl/OpenGLHelper.h +++ b/src/opengl/OpenGLHelper.h @@ -48,6 +48,21 @@ } \ } while(0) + +#define WGL_ENSURE(x, ...) \ + do { \ + if (!(x)) { \ + qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \ + return __VA_ARGS__; \ + } \ + } while(0) +#define WGL_WARN(x, ...) \ + do { \ + if (!(x)) { \ + qWarning() << "WGL error " << __FILE__ << "@" << __LINE__ << " " << #x << ": " << qt_error_string(GetLastError()); \ + } \ + } while(0) + QT_BEGIN_NAMESPACE class QMatrix4x4; QT_END_NAMESPACE diff --git a/src/opengl/gl_api.cpp b/src/opengl/gl_api.cpp index e8c665a0e..60855a9f9 100644 --- a/src/opengl/gl_api.cpp +++ b/src/opengl/gl_api.cpp @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ #include "gl_api.h" +#include "OpenGLHelper.h" namespace QtAV { typedef void *(*GetProcAddress_t)(const char *); @@ -82,6 +83,11 @@ void* GetProcAddress_Qt(const char *name) } while(0) #endif +#define WGL_RESOLVE(name) do {\ + void** fp = (void**)(&name); \ + *fp = sGetProcAddress("wgl" # name); \ +} while(0) + void api::resolve() { //memset(g, 0, sizeof(g)); @@ -107,6 +113,27 @@ void api::resolve() GL_RESOLVE(UniformMatrix4fv); GL_RESOLVE_ES_3_1(GetTexLevelParameteriv); + +#ifdef Q_OS_WIN32 + if (!OpenGLHelper::isOpenGLES()) { + static const char* ext[] = { + "WGL_NV_DX_interop2", + "WGL_NV_DX_interop", + NULL, + }; + if (OpenGLHelper::hasExtension(ext)) { // TODO: use wgl getprocaddress function (for qt4) + qDebug("resolving WGL_NV_DX_interop..."); + WGL_RESOLVE(DXSetResourceShareHandleNV); + WGL_RESOLVE(DXOpenDeviceNV); + WGL_RESOLVE(DXCloseDeviceNV); + WGL_RESOLVE(DXRegisterObjectNV); + WGL_RESOLVE(DXUnregisterObjectNV); + WGL_RESOLVE(DXObjectAccessNV); + WGL_RESOLVE(DXLockObjectsNV); + WGL_RESOLVE(DXUnlockObjectsNV); + } + } +#endif //Q_OS_WIN32 } api& gl() { diff --git a/src/opengl/gl_api.h b/src/opengl/gl_api.h index 37bd1ee5f..1df602f1c 100644 --- a/src/opengl/gl_api.h +++ b/src/opengl/gl_api.h @@ -143,6 +143,24 @@ struct api { // Before using the following members, check null ptr first because they are not valid everywhere // ES3.1 void (GL_APIENTRY *GetTexLevelParameteriv)(GLenum, GLint, GLenum, GLint *); + +#if defined(Q_OS_WIN32) + //#include //not found in vs2013 + //https://www.opengl.org/registry/specs/NV/DX_interop.txt +#ifndef WGL_ACCESS_READ_ONLY_NV +#define WGL_ACCESS_READ_ONLY_NV 0x00000000 +#define WGL_ACCESS_READ_WRITE_NV 0x00000001 +#define WGL_ACCESS_WRITE_DISCARD_NV 0x00000002 +#endif + BOOL (WINAPI* DXSetResourceShareHandleNV)(void *dxObject, HANDLE shareHandle); + HANDLE (WINAPI* DXOpenDeviceNV)(void *dxDevice); + BOOL (WINAPI* DXCloseDeviceNV)(HANDLE hDevice); + HANDLE (WINAPI* DXRegisterObjectNV)(HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access); + BOOL (WINAPI* DXUnregisterObjectNV)(HANDLE hDevice, HANDLE hObject); + BOOL (WINAPI* DXObjectAccessNV)(HANDLE hObject, GLenum access); + BOOL (WINAPI* DXLockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects); + BOOL (WINAPI* DXUnlockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects); +#endif }; } //namespace QtAV #endif //QT_NO_OPENGL