3#if defined(Q_OS_WIN) && (defined(QGC_HAS_GST_D3D11_GPU_PATH) || defined(QGC_HAS_GST_D3D12_GPU_PATH))
5#include <QtCore/QMutexLocker>
6#include <glib-object.h>
12namespace GstD3DContextBridgeCommon {
15bool primeLocked(BridgeState& state,
const BridgeOps& ops)
20 if (!checkSnapshotBackend(state, ops.cat(), ops.qrhiBackend, ops.apiName)) {
23 GstObject* device = ops.createDevice(ops.cat());
27 state.device = device;
29 qCInfo(ops.cat()) << ops.apiName <<
"bridge primed: shared device =" << device;
37bool checkSnapshotBackend(BridgeState& state,
const QLoggingCategory& cat,
int expectedBackend,
const char* backendName)
41 qCDebug(cat) <<
"QRhi snapshot not yet populated; will retry on next NEED_CONTEXT";
44 if (backend != expectedBackend) {
45 if (!state.warnedWrongBackend) {
46 qCInfo(cat) <<
"QRhi backend tag is" << backend <<
"(not" << backendName <<
"); bridge inactive";
47 state.warnedWrongBackend =
true;
54void logHandoff(BridgeState& state,
const QLoggingCategory& cat,
GstElement* element,
const char* apiName)
56 if (!state.loggedFirstHandoff.exchange(
true, std::memory_order_relaxed)) {
57 qCInfo(cat) <<
"First" << apiName <<
"device handoff to element" << GST_ELEMENT_NAME(element);
59 qCDebug(cat) <<
"Provided" << apiName <<
"device context to" << GST_ELEMENT_NAME(element);
63gint64 readAdapterLuid(gpointer device)
65 if (!device || !G_IS_OBJECT(device))
68 g_object_get(G_OBJECT(device),
"adapter-luid", &luid,
nullptr);
72void logAdapterMatch(gint64 expectedLuid, gpointer gstDevice,
const QLoggingCategory& cat,
const char* apiName)
74 const gint64 actualLuid = readAdapterLuid(gstDevice);
75 if (actualLuid != expectedLuid) {
76 qCWarning(cat).noquote() << apiName <<
"bridge: gst device LUID mismatch — QRhi LUID=" << expectedLuid
77 <<
"but wrapped device LUID=" << actualLuid
78 <<
"(zero-copy will appear corrupt; check NEED_CONTEXT race)";
81 qCInfo(cat).noquote() << apiName <<
"bridge adapter LUID="
82 << QString::asprintf(
"0x%llx",
static_cast<long long>(expectedLuid));
85void registerBridge(
const QLoggingCategory& cat, GstBusSyncReply (*handler)(GstMessage*),
void (*reset)())
87 GstContextBridge::registerBridge(cat,
"D3D", handler, reset);
90bool prime(BridgeState& state,
const BridgeOps& ops)
92 QMutexLocker lock(&state.mutex);
93 return primeLocked(state, ops);
96GstObject* currentDevice(BridgeState& state)
98 QMutexLocker lock(&state.mutex);
102 return GST_OBJECT(gst_object_ref(state.device));
112 const BridgeOps* ops;
115const QLoggingCategory& vtCat(
void* user)
117 return static_cast<D3DUser*
>(user)->ops->cat();
120QMutex& vtMutex(
void* user)
122 return static_cast<D3DUser*
>(user)->state->mutex;
125bool vtPrime(
void* user)
127 auto* d =
static_cast<D3DUser*
>(user);
128 return primeLocked(*d->state, *d->ops);
131GstObject* vtRefObject(
void* user,
const char* )
133 auto* d =
static_cast<D3DUser*
>(user);
134 return d->state->device ? GST_OBJECT(gst_object_ref(d->state->device)) : nullptr;
137GstContext* vtBuildContext(
void* user,
const char* , GstObject*
object)
139 auto* d =
static_cast<D3DUser*
>(user);
140 GstContext* ctx = d->ops->makeContext(
object);
142 qCWarning(d->ops->cat()) << d->ops->apiName <<
"context_new failed";
147void vtOnHandoff(
void* user,
GstElement* element,
const char* )
149 auto* d =
static_cast<D3DUser*
>(user);
150 logHandoff(*d->state, d->ops->cat(), element, d->ops->apiName);
153GstContextBridge::BridgeVTable makeVTable(
const BridgeOps& ops,
const char** typeStorage)
155 typeStorage[0] = ops.contextType;
156 return GstContextBridge::BridgeVTable{
157 ops.apiName, typeStorage, 1, &vtCat, &vtMutex, &vtPrime, &vtRefObject, &vtBuildContext, &vtOnHandoff,
163GstBusSyncReply handleSyncMessage(BridgeState& state,
const BridgeOps& ops, GstMessage* message)
165 D3DUser user = {&state, &ops};
166 const char* types[1];
167 const GstContextBridge::BridgeVTable vt = makeVTable(ops, types);
168 return GstContextBridge::handleSyncMessage(vt, &user, message);
171bool answerContextQuery(BridgeState& state,
const BridgeOps& ops, GstQuery* query)
173 D3DUser user = {&state, &ops};
174 const char* types[1];
175 const GstContextBridge::BridgeVTable vt = makeVTable(ops, types);
176 return GstContextBridge::answerContextQuery(vt, &user, query);
179void reset(BridgeState& state,
const BridgeOps& ops)
181 QMutexLocker lock(&state.mutex);
182 gst_clear_object(&state.device);
183 state.primed =
false;
184 state.warnedWrongBackend =
false;
185 qCDebug(ops.cat()) << ops.apiName <<
"bridge reset";
struct _GstElement GstElement
DeviceSnapshot & deviceSnapshot() noexcept
Returns the global snapshot. Atomic fields make individual reads thread-safe.
std::atomic< int > backend
QRhi::Implementation cast to int (-1 = unset)