Files
fmviewer3/project/fm_viewer/fav/hw_decoder/SurfaceInteropD3D9GL.cpp
2026-02-21 17:11:31 +09:00

130 lines
4.8 KiB
C++

/******************************************************************************
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