6#include <QtMultimedia/private/qvideotexturehelper_p.h>
8#include <QtGui/rhi/qrhi.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtCore/qscopeguard.h>
12#include <QtCore/qvarlengtharray.h>
13#include <QtCore/private/qsystemerror_p.h>
14#include <QtCore/private/qexpected_p.h>
22# include <QtMultimedia/private/qmultimedia_gl_support_p.h>
23# include <QtMultimedia/private/qrhivaluemapper_p.h>
24# include <QtGui/qopenglcontext.h>
25# include <QtGui/qopenglextrafunctions.h>
26# include <QtGui/qopenglfunctions.h>
27# include <QtGui/qopenglext.h>
38Q_LOGGING_CATEGORY(lcD3D11RhiTextureImporter,
"qt.multimedia.windows.d3d11rhitextureimporter");
40class D3D11TextureHandles :
public QVideoFrameTexturesHandles
43 explicit D3D11TextureHandles(ComPtr<ID3D11Texture2D> tex) : m_tex(std::move(tex)) { }
45 quint64 textureHandle(QRhi &rhi,
int ) override
47 if (rhi.backend() != QRhi::D3D11)
49 return quint64(m_tex.Get());
53 const ComPtr<ID3D11Texture2D> m_tex;
56const QRhiD3D11NativeHandles *resolveD3D11NativeHandles(QRhi &rhi)
58 Q_ASSERT(rhi.backend() == QRhi::D3D11);
59 return static_cast<
const QRhiD3D11NativeHandles *>(rhi.nativeHandles());
62q23::expected<ComPtr<ID3D11Device1>, HRESULT>
63resolveD3D11Device(
const QRhiD3D11NativeHandles *nativeHandles)
65 ComPtr<ID3D11Device> rhiDevice =
static_cast<ID3D11Device *>(nativeHandles->dev);
66 ComPtr<ID3D11Device1> rhiDevice1;
67 if (
const HRESULT hr = rhiDevice.As(&rhiDevice1); FAILED(hr))
68 return q23::unexpected{ hr };
73class D3D12TextureHandles :
public QVideoFrameTexturesHandles
76 D3D12TextureHandles(ComPtr<ID3D12Resource> resource, ComPtr<ID3D11On12Device2> on12Device,
77 ComPtr<ID3D11Texture2D> wrappedResource,
78 std::shared_ptr<std::atomic_bool> wrappedResourceInUse)
79 : m_resource(std::move(resource)),
80 m_on12Device(std::move(on12Device)),
81 m_wrappedResource(std::move(wrappedResource)),
82 m_wrappedResourceInUse(std::move(wrappedResourceInUse))
86 ~D3D12TextureHandles() override
89 if (m_on12Device && m_wrappedResource)
90 m_on12Device->ReturnUnderlyingResource(m_wrappedResource.Get(), 0,
nullptr,
nullptr);
92 if (m_wrappedResourceInUse)
93 m_wrappedResourceInUse->store(
false);
96 quint64 textureHandle(QRhi &rhi,
int ) override
98 switch (rhi.backend()) {
100 return quint64(m_resource.Get());
107 ComPtr<ID3D12Resource> m_resource;
108 const ComPtr<ID3D11On12Device2> m_on12Device;
109 const ComPtr<ID3D11Texture2D> m_wrappedResource;
110 const std::shared_ptr<std::atomic_bool> m_wrappedResourceInUse;
116using PFNWGLDXOPENDEVICENVPROC = HANDLE(WINAPI *)(
void *);
117using PFNWGLDXCLOSEDEVICENVPROC = BOOL(WINAPI *)(HANDLE);
118using PFNWGLDXREGISTEROBJECTNVPROC = HANDLE(WINAPI *)(HANDLE,
void *, GLuint, GLenum, GLenum);
119using PFNWGLDXUNREGISTEROBJECTNVPROC = BOOL(WINAPI *)(HANDLE, HANDLE);
120using PFNWGLDXLOCKOBJECTSNVPROC = BOOL(WINAPI *)(HANDLE, GLint, HANDLE *);
121using PFNWGLDXUNLOCKOBJECTSNVPROC = BOOL(WINAPI *)(HANDLE, GLint, HANDLE *);
123# ifndef WGL_ACCESS_READ_ONLY_NV
124# define WGL_ACCESS_READ_ONLY_NV 0x00000000
129 PFNWGLDXOPENDEVICENVPROC wglDXOpenDeviceNV =
nullptr;
130 PFNWGLDXCLOSEDEVICENVPROC wglDXCloseDeviceNV =
nullptr;
131 PFNWGLDXREGISTEROBJECTNVPROC wglDXRegisterObjectNV =
nullptr;
132 PFNWGLDXUNREGISTEROBJECTNVPROC wglDXUnregisterObjectNV =
nullptr;
133 PFNWGLDXLOCKOBJECTSNVPROC wglDXLockObjectsNV =
nullptr;
134 PFNWGLDXUNLOCKOBJECTSNVPROC wglDXUnlockObjectsNV =
nullptr;
136 static WglDxInterop resolve(QOpenGLContext *ctx)
138 using namespace QtMultimediaPrivate;
142 f.wglDXOpenDeviceNV = resolveGlFunction<PFNWGLDXOPENDEVICENVPROC>(ctx,
"wglDXOpenDeviceNV");
143 f.wglDXCloseDeviceNV =
144 resolveGlFunction<PFNWGLDXCLOSEDEVICENVPROC>(ctx,
"wglDXCloseDeviceNV");
145 f.wglDXRegisterObjectNV =
146 resolveGlFunction<PFNWGLDXREGISTEROBJECTNVPROC>(ctx,
"wglDXRegisterObjectNV");
147 f.wglDXUnregisterObjectNV =
148 resolveGlFunction<PFNWGLDXUNREGISTEROBJECTNVPROC>(ctx,
"wglDXUnregisterObjectNV");
149 f.wglDXLockObjectsNV =
150 resolveGlFunction<PFNWGLDXLOCKOBJECTSNVPROC>(ctx,
"wglDXLockObjectsNV");
151 f.wglDXUnlockObjectsNV =
152 resolveGlFunction<PFNWGLDXUNLOCKOBJECTSNVPROC>(ctx,
"wglDXUnlockObjectsNV");
158 return wglDXOpenDeviceNV && wglDXCloseDeviceNV && wglDXRegisterObjectNV
159 && wglDXUnregisterObjectNV && wglDXLockObjectsNV && wglDXUnlockObjectsNV;
163QRhiValueMapper<WglDxInterop> g_wglDxInteropMapper;
165bool supportsGlCopy(QOpenGLContext &glCtx)
167 return (glCtx.format().version() >= std::pair(4, 3)
168 || glCtx.hasExtension(
"GL_ARB_copy_image"_ba));
171GLenum dxFormatToGlTextureFormat(DXGI_FORMAT d3dFormat)
174 case DXGI_FORMAT_R8G8B8A8_UNORM:
176 case DXGI_FORMAT_R8_UNORM:
178 case DXGI_FORMAT_R8G8_UNORM:
180 case DXGI_FORMAT_R16_UNORM:
182 case DXGI_FORMAT_R16G16_UNORM:
193GlTextureHandle copyToOwnedGlTexture(QOpenGLContext *glCtx, GLuint source, DXGI_FORMAT sourceFormat,
194 GLsizei width, GLsizei height)
196 Q_ASSERT(supportsGlCopy(*glCtx));
198 const GLenum internalFormat = dxFormatToGlTextureFormat(sourceFormat);
199 if (!internalFormat) {
200 qCWarning(lcD3D11RhiTextureImporter)
201 <<
"Cannot import D3D11 texture to OpenGL: unsupported DXGI format" << sourceFormat;
205 QOpenGLExtraFunctions *f = glCtx->extraFunctions();
207 const auto checkGlError = [&](
const char *call) {
208 const GLError error = GLError(f->glGetError());
209 if (error == GLError::NoError)
211 qCWarning(lcD3D11RhiTextureImporter) << call <<
"failed with GL error" << error;
215 GLint previousBinding = 0;
216 f->glGetIntegerv(GL_TEXTURE_BINDING_2D, &previousBinding);
217 if (!checkGlError(
"glGetIntegerv(GL_TEXTURE_BINDING_2D)"))
219 auto restoreBinding = qScopeGuard([&] {
220 f->glBindTexture(GL_TEXTURE_2D, GLuint(previousBinding));
224 f->glGenTextures(1, &texId);
225 if (!checkGlError(
"glGenTextures") || !texId)
227 GlTextureHandle result{
229 GlTextureDeleter{ glCtx },
232 f->glBindTexture(GL_TEXTURE_2D, texId);
233 if (!checkGlError(
"glBindTexture"))
236 f->glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, width, height);
237 if (!checkGlError(
"glTexStorage2D"))
240 f->glCopyImageSubData(source, GL_TEXTURE_2D, 0, 0, 0, 0, texId, GL_TEXTURE_2D, 0, 0, 0, 0,
242 if (!checkGlError(
"glCopyImageSubData"))
248class OpenGLTextureHandles :
public QVideoFrameTexturesHandles
251 explicit OpenGLTextureHandles(GlTextureHandle tex) : m_tex(std::move(tex)) { }
253 quint64 textureHandle(QRhi &rhi,
int ) override
255 if (rhi.backend() != QRhi::OpenGLES2)
257 return quint64(m_tex.get());
261 const GlTextureHandle m_tex;
267class MultiPlaneTextureHandles :
public QVideoFrameTexturesHandles
270 explicit MultiPlaneTextureHandles(QVarLengthArray<QVideoFrameTexturesHandlesUPtr, 2> planes)
271 : m_planes(std::move(planes))
275 quint64 textureHandle(QRhi &rhi,
int plane) override
277 if (plane < 0 || plane >= m_planes.size() || !m_planes[plane])
279 return m_planes[plane]->textureHandle(rhi, 0);
283 const QVarLengthArray<QVideoFrameTexturesHandlesUPtr, 2> m_planes;