3#if defined(Q_OS_WIN) && defined(QGC_HAS_GST_D3D11_GPU_PATH)
10#include <QtCore/QVarLengthArray>
12#include <gst/d3d11/gstd3d11.h>
20using GstD3DVideoBufferCommon::kMaxPlanes;
21using GstD3DVideoBufferCommon::MapDiagnostics;
22using GstD3DVideoBufferCommon::fail;
23using D3D11FrameTextures = GstD3DVideoBufferCommon::FrameTextures<ID3D11Texture2D>;
30ID3D11Texture2D *copySliceToStaging(ID3D11Texture2D *tex, guint subIdx,
int planeIdx,
31 const D3D11_TEXTURE2D_DESC &srcDesc,
32 GstD3D11Memory *d3dmem)
34 ID3D11Device *d3dDev = gst_d3d11_device_get_device_handle(d3dmem->device);
35 ID3D11DeviceContext *d3dCtx = gst_d3d11_device_get_device_context_handle(d3dmem->device);
36 D3D11_TEXTURE2D_DESC dstDesc = srcDesc;
37 dstDesc.ArraySize = 1;
38 dstDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
39 dstDesc.MiscFlags = 0;
40 dstDesc.MipLevels = 1;
41 ID3D11Texture2D *stagingTex =
nullptr;
42 if (FAILED(d3dDev->CreateTexture2D(&dstDesc,
nullptr, &stagingTex))) {
43 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedTextureCreateFail,
44 "mapTextures: CreateTexture2D for slice copy failed (plane=" << planeIdx
45 <<
"subresource=" << subIdx <<
")");
48 d3dCtx->CopySubresourceRegion(stagingTex, 0, 0, 0, 0, tex, subIdx,
nullptr);
56GstD3D11VideoBuffer::GstD3D11VideoBuffer(GstSample *sample,
57 const GstVideoInfo &videoInfo,
58 const QVideoFrameFormat &format)
63GstD3D11VideoBuffer::~GstD3D11VideoBuffer() =
default;
65QAbstractVideoBuffer::MapData GstD3D11VideoBuffer::map(QVideoFrame::MapMode )
70bool GstD3D11VideoBuffer::validatePlaneHandles()
const
72 if (!_sample)
return false;
73 GstBuffer *buffer = gst_sample_get_buffer(_sample);
74 if (!buffer)
return false;
75 const int memCount = qMin(
int(gst_buffer_n_memory(buffer)), kMaxPlanes);
76 if (memCount <= 0)
return false;
77 for (
int i = 0; i < memCount; ++i) {
78 GstMemory *mem = gst_buffer_peek_memory(buffer, i);
79 if (!mem || !gst_is_d3d11_memory(mem))
return false;
81 if (!gst_d3d11_memory_get_resource_handle(GST_D3D11_MEMORY_CAST(mem))) {
88QVideoFrameTexturesUPtr GstD3D11VideoBuffer::mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr & )
90 Q_ASSERT(rhi.thread()->isCurrentThread());
97 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedNullSample,
"mapTextures: GstSample is null");
100 if (rhi.backend() != QRhi::D3D11) {
101 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedBadBackend,
102 "mapTextures: QRhi backend is" << rhi.backendName() <<
"(D3D11 required)");
106 GstBuffer *buffer = gst_sample_get_buffer(_sample);
108 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedNullBuffer,
"mapTextures: GstSample has no buffer");
112 const int memCount = qMin(
int(gst_buffer_n_memory(buffer)), kMaxPlanes);
113 std::array<ID3D11Texture2D *, kMaxPlanes> texs{};
114 QVarLengthArray<ID3D11Texture2D *, kMaxPlanes> refdTexs;
115 for (
int i = 0; i < memCount; ++i) {
116 GstMemory *mem = gst_buffer_peek_memory(buffer, i);
117 if (!mem || !gst_is_d3d11_memory(mem)) {
118 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedNonD3DMemory,
119 "mapTextures: plane" << i <<
"memory is not GstD3D11Memory (allocator="
120 << (mem && mem->allocator ? mem->allocator->mem_type :
"null")
122 for (
auto *t : refdTexs) t->Release();
131 GstD3D11Device *bridgeDev = GstD3D11ContextBridge::currentDevice();
132 GstD3D11Device *bufDev = GST_D3D11_MEMORY_CAST(mem)->device;
133 if (bridgeDev && bufDev != bridgeDev) {
134 const gint64 bridgeLuid = GstD3DContextBridgeCommon::readAdapterLuid(bridgeDev);
135 const gint64 bufLuid = GstD3DContextBridgeCommon::readAdapterLuid(bufDev);
136 gst_object_unref(bridgeDev);
137 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedDeviceMismatch,
138 "mapTextures: GstD3D11Memory on foreign device (bridge LUID="
139 << bridgeLuid <<
"buffer LUID=" << bufLuid
140 <<
"); bridge missed NEED_CONTEXT race — rejecting frame");
143 if (bridgeDev) gst_object_unref(bridgeDev);
145 ID3D11Texture2D *tex =
reinterpret_cast<ID3D11Texture2D *
>(
146 gst_d3d11_memory_get_resource_handle(GST_D3D11_MEMORY_CAST(mem)));
148 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedNullResource,
149 "mapTextures: gst_d3d11_memory_get_resource_handle returned null for plane" << i);
150 for (
auto *t : refdTexs) t->Release();
154 const guint subIdx = gst_d3d11_memory_get_subresource_index(GST_D3D11_MEMORY_CAST(mem));
155 D3D11_TEXTURE2D_DESC srcDesc{};
156 tex->GetDesc(&srcDesc);
157 if (subIdx > 0 || srcDesc.ArraySize > 1) {
158 ID3D11Texture2D *stagingTex = copySliceToStaging(tex, subIdx, i, srcDesc,
159 GST_D3D11_MEMORY_CAST(mem));
161 for (
auto *t : refdTexs) t->Release();
164 refdTexs.append(stagingTex);
165 texs[i] = stagingTex;
168 refdTexs.append(tex);
173 auto textures = std::make_unique<D3D11FrameTextures>(&rhi, _format.frameSize(),
174 _format.pixelFormat(), texs, memCount);
177 for (
int i = 0; i < memCount; ++i) {
178 if (!textures->texture(
static_cast<uint
>(i))) {
179 QGC_D3D_WARN_ONCE(GstD3D11Log, s_diag.loggedTextureCreateFail,
180 "mapTextures: QRhiTexture::createFrom failed plane=" << i
181 <<
" (size=" << _format.frameSize()
182 <<
"format=" <<
int(_format.pixelFormat()) <<
"planes=" << memCount <<
")");
187 if (!s_diag.loggedFirstSuccess.exchange(
true, std::memory_order_relaxed)) {
188 qCInfo(GstD3D11Log) <<
"First D3D11 zero-copy mapTextures success: size=" << _format.frameSize()
189 <<
"format=" << int(_format.pixelFormat()) <<
"planes=" << memCount;
194quint64 GstD3D11VideoBuffer::takeMapFailureCount()
196 return GstD3DVideoBufferCommon::takeMapFailureCount(s_diag);
199quint64 GstD3D11VideoBuffer::peekMapFailureCount()
201 return GstD3DVideoBufferCommon::peekMapFailureCount(s_diag);
#define QGC_LOGGING_CATEGORY(name, categoryStr)