first commit
This commit is contained in:
129
project/fm_viewer/fav/hw_decoder/SurfaceInteropD3D9GL.cpp
Normal file
129
project/fm_viewer/fav/hw_decoder/SurfaceInteropD3D9GL.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV (from 2015)
|
||||
|
||||
This library 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 library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#ifdef RM_USE_HW_DECODER
|
||||
#include "SurfaceInteropD3D9.h"
|
||||
#define DX_LOG_COMPONENT "D3D9GL Interop"
|
||||
#include "../DirectXHelper.h"
|
||||
#include "../opengl/OpenGLHelper.h"
|
||||
|
||||
//dynamic gl or desktop gl
|
||||
namespace FAV {
|
||||
namespace d3d9 {
|
||||
class GLInteropResource Q_DECL_FINAL: public InteropResource
|
||||
{
|
||||
public:
|
||||
GLInteropResource(IDirect3DDevice9 * d3device);
|
||||
~GLInteropResource();
|
||||
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 ensureResource(int w, int h, GLuint tex);
|
||||
|
||||
HANDLE interop_dev;
|
||||
HANDLE interop_obj;
|
||||
};
|
||||
|
||||
InteropResource* CreateInteropGL(IDirect3DDevice9 *dev)
|
||||
{
|
||||
return new GLInteropResource(dev);
|
||||
}
|
||||
|
||||
GLInteropResource::GLInteropResource(IDirect3DDevice9 *d3device)
|
||||
: InteropResource(d3device)
|
||||
, interop_dev(NULL)
|
||||
, interop_obj(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
GLInteropResource::~GLInteropResource()
|
||||
{
|
||||
// FIXME: why unregister/close interop obj/dev here will crash(tested on intel driver)? must be in current opengl context?
|
||||
}
|
||||
|
||||
bool GLInteropResource::map(IDirect3DSurface9 *surface, GLuint tex, int w, int h, int)
|
||||
{
|
||||
if (!ensureResource(w, h, tex)) {
|
||||
releaseDX();
|
||||
return false;
|
||||
}
|
||||
// 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 = gl().DXOpenDeviceNV(d3ddev)) != NULL, false);
|
||||
// call in ensureResource or in map?
|
||||
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, (~0-1)&w, (~0-1)&h}; //StretchRect does not supports odd values
|
||||
DX_ENSURE_OK(d3ddev->StretchRect(surface, &src, dx_surface, NULL, D3DTEXF_NONE), false);
|
||||
// lock dx resources
|
||||
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;
|
||||
}
|
||||
|
||||
bool GLInteropResource::unmap(GLuint tex)
|
||||
{
|
||||
Q_UNUSED(tex);
|
||||
if (!interop_obj || !interop_dev)
|
||||
return false;
|
||||
DYGL(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
WGL_ENSURE(gl().DXUnlockObjectsNV(interop_dev, 1, &interop_obj), false);
|
||||
WGL_WARN(gl().DXUnregisterObjectNV(interop_dev, interop_obj));
|
||||
// interop operations end
|
||||
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::ensureResource(int w, int h, GLuint tex)
|
||||
{
|
||||
Q_UNUSED(tex);
|
||||
Q_ASSERT(gl().DXRegisterObjectNV && "WGL_NV_DX_interop is required");
|
||||
|
||||
if (dx_surface && width == w && height == h)
|
||||
return true;
|
||||
releaseDX();
|
||||
HANDLE share_handle = NULL;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
const bool has_alpha = QOpenGLContext::currentContext()->format().hasAlpha();
|
||||
#else
|
||||
const bool has_alpha = QOpenGLContext::currentContext()->format().alpha();
|
||||
#endif
|
||||
// _A8 for a yuv plane
|
||||
DX_ENSURE_OK(d3ddev->CreateTexture(w, h, 1,
|
||||
D3DUSAGE_RENDERTARGET,
|
||||
has_alpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
|
||||
D3DPOOL_DEFAULT,
|
||||
&dx_texture,
|
||||
&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(gl().DXSetResourceShareHandleNV(dx_surface, share_handle));
|
||||
width = w;
|
||||
height = h;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef RM_USE_HW_DECODER
|
||||
Reference in New Issue
Block a user