3#if defined(QGC_HAS_ANY_GPU_PATH)
6#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
9#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
12#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
16#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
20#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
23#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
26#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
29#if defined(QGC_HAS_ANY_GPU_PATH)
33#if defined(QGC_HAS_ANY_GPU_PATH)
37#if defined(QGC_HAS_GST_DMABUF_GPU_PATH) || defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
39#include <QtGui/QGuiApplication>
40#include <qpa/qplatformnativeinterface.h>
45#include <QtCore/QByteArray>
55#if defined(QGC_HAS_ANY_GPU_PATH)
65constexpr std::array<GpuPathEntry, 0
66#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
69#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
72#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
75#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
78#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
81#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
84#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
89#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
92#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
95#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
98#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
101#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
104#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
107#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
116 if (!msg || GST_MESSAGE_TYPE(msg) != GST_MESSAGE_ERROR)
121 GError* err =
nullptr;
122 gchar* debug =
nullptr;
123 gst_message_parse_error(msg, &err, &debug);
125 const auto mentionsDeviceLoss = [](
const gchar* text) {
126 return text && (g_strstr_len(text, -1,
"DEVICE_REMOVED") || g_strstr_len(text, -1,
"DEVICE_RESET") ||
127 g_strstr_len(text, -1,
"device removed") || g_strstr_len(text, -1,
"device reset"));
129 const bool deviceLost = mentionsDeviceLoss(err ? err->message :
nullptr) || mentionsDeviceLoss(debug);
147 const auto truthy = [](
const char* name,
bool dflt)
noexcept {
148 const QByteArray v = qgetenv(name).trimmed().toLower();
152 return v !=
"0" && v !=
"false" && v !=
"off" && v !=
"no";
155 c.
dmaBufCache = truthy(
"QGC_GST_DMABUF_CACHE",
false);
159 qCInfo(HwBuffersConfigLog).nospace()
160 <<
"HwBuffer env config: QGC_GST_DMABUF_CACHE=" << c.
dmaBufCache
171#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH) || defined(QGC_HAS_GST_D3D11_GPU_PATH) || \
172 defined(QGC_HAS_GST_D3D12_GPU_PATH) || defined(QGC_HAS_GST_VULKAN_GPU_PATH)
173 return GstContextBridgeRegistry::dispatchBridges(msg);
184#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
185 GstGlContextBridge::rearm();
187#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
188 GstVulkanContextBridge::rearm();
194#if defined(QGC_HAS_ANY_GPU_PATH)
195 GstContextBridgeRegistry::resetAllBridges();
196 GstContextBridgeRegistry::resetAllCaches();
198#if defined(QGC_HAS_GST_DMABUF_GPU_PATH) || defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
199 GstEglHelpers::resetExtensionCache();
205#if defined(QGC_HAS_ANY_GPU_PATH)
212#if defined(QGC_HAS_ANY_GPU_PATH)
221#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
224 EGLDisplay dpy = EGL_NO_DISPLAY;
225 const QString platform = QGuiApplication::platformName();
226 if (platform == QLatin1String(
"wayland") || platform == QLatin1String(
"wayland-egl")) {
227 if (
auto* ni = QGuiApplication::platformNativeInterface()) {
228 dpy =
static_cast<EGLDisplay
>(ni->nativeResourceForIntegration(
"egldisplay"));
231 if (dpy == EGL_NO_DISPLAY) {
232 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
234 if (dpy == EGL_NO_DISPLAY) {
235 qCWarning(HwBuffersFacadeLog) <<
"GPU zero-copy requested but EGLDisplay unavailable on platform" << platform
236 <<
"— DMABuf path disabled";
238 qCInfo(HwBuffersFacadeLog) <<
"DMABuf zero-copy path available on" << platform
239 <<
"— actual path chosen at caps negotiation";
241 ctx.dmaBufEglDisplay = dpy;
244#if defined(QGC_HAS_GST_AHARDWAREBUFFER_GPU_PATH)
245 ctx.ahbEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
246 if (ctx.ahbEglDisplay == EGL_NO_DISPLAY) {
247 qCWarning(HwBuffersFacadeLog) <<
"AHardwareBuffer path: EGLDisplay unavailable";
249 qCInfo(HwBuffersFacadeLog) <<
"AHardwareBuffer zero-copy path available"
250 <<
"— actual path chosen at caps negotiation";
254#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
255 qCInfo(HwBuffersFacadeLog) <<
"D3D11 zero-copy path available — actual path chosen at caps negotiation";
257#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
258 qCInfo(HwBuffersFacadeLog) <<
"D3D12 zero-copy path available — actual path chosen at caps negotiation";
260#if defined(QGC_HAS_GST_IOSURFACE_GPU_PATH)
261 qCInfo(HwBuffersFacadeLog) <<
"IOSurface zero-copy path available — actual path chosen at caps negotiation";
263#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
264 qCInfo(HwBuffersFacadeLog) <<
"Vulkan zero-copy path available (active only when QRhi uses the Vulkan backend)";
273 bool handled =
false;
274#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
275 handled = GstGlContextBridge::answerContextQuery(query);
277#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
279 handled = GstVulkanContextBridge::answerContextQuery(query);
282#if defined(QGC_HAS_GST_D3D11_GPU_PATH)
284 handled = GstD3D11ContextBridge::answerContextQuery(query);
287#if defined(QGC_HAS_GST_D3D12_GPU_PATH)
289 handled = GstD3D12ContextBridge::answerContextQuery(query);
299#if defined(QGC_HAS_ANY_GPU_PATH)
300 for (
const auto& entry : kEnabledPaths) {
308 QStringLiteral(
" %1:%2 %1-failures:%3").arg(QLatin1String(entry.label)).arg(
delivered).arg(failures);
310 out.
line += QStringLiteral(
" %1:%2/%3").arg(QLatin1String(entry.label)).arg(
delivered).arg(failures);
323#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
325 quint64 glGpuWaits = 0;
327 out += QStringLiteral(
" GL-reuse:%1 GL-wait[gpu/cpu]:%2/%3").arg(glReuse).arg(glGpuWaits).arg(glCpuWaits);
329#if defined(QGC_HAS_GST_VULKAN_GPU_PATH)
330 quint64 vkGpuWaits = 0;
332 out += QStringLiteral(
" Vulkan-wait[gpu/cpu]:%1/%2").arg(vkGpuWaits).arg(vkCpuWaits);
334#if defined(QGC_HAS_GST_DMABUF_GPU_PATH)
335 out += QStringLiteral(
" DMABuf-fence-timeouts:%1 DMABuf-mmap-barriers:%2 DMABuf-explicit-fence-waits:%3")
340#if defined(QGC_HAS_ANY_GPU_PATH)
341 static constexpr std::pair<GstHwPathTelemetry::HwFallbackReason, const char*> kReasons[] = {
353 for (
const auto& entry : kEnabledPaths) {
356 out += QStringLiteral(
" %1-map-us:%2").arg(QLatin1String(entry.label)).arg(ewmaUs);
360 out += QStringLiteral(
" %1-demotions:%2").arg(QLatin1String(entry.label)).arg(demotions);
362 QString reasonBreakdown;
363 for (
const auto& [reason, label] : kReasons) {
366 reasonBreakdown += QStringLiteral(
"%1=%2,").arg(QLatin1String(label)).arg(n);
369 if (!reasonBreakdown.isEmpty()) {
370 reasonBreakdown.chop(1);
371 out += QStringLiteral(
" %1-fallback[%2]").arg(QLatin1String(entry.label)).arg(reasonBreakdown);
376 const quint64 unknownMem =
379 if (unknownMem > 0) {
380 out += QStringLiteral(
" None-fallback[unknown-mem=%1]").arg(unknownMem);
383 if (cpuDemotions > 0) {
384 out += QStringLiteral(
" None-demotions:%1").arg(cpuDemotions);
std::atomic< quint64 > delivered
HwVideoBufferPath
Identifies which GPU path was chosen; used by the adapter to increment the right counter.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
quint64 peekMapFailureCount(HwVideoBufferPath path) noexcept
quint64 takeExplicitFenceWaits(HwVideoBufferPath path) noexcept
quint64 takeTextureReuseHits(HwVideoBufferPath path) noexcept
quint64 takeSyncWaitCounts(HwVideoBufferPath path, quint64 &gpuWaits) noexcept
Reads-and-resets CPU waits; writes GPU waits into gpuWaits.
quint64 peekMapDurationUsEwma(HwVideoBufferPath path) noexcept
quint64 takeFenceTimeouts(HwVideoBufferPath path) noexcept
quint64 takeStreamDemotions(HwVideoBufferPath negotiated) noexcept
quint64 peekDeliveredCount(HwVideoBufferPath path) noexcept
quint64 takeMapFailureCount(HwVideoBufferPath path) noexcept
quint64 takeDeliveredCount(HwVideoBufferPath path) noexcept
quint64 takeFallbackReason(HwVideoBufferPath attemptedPath, HwFallbackReason reason) noexcept
quint64 takeMmapBarrierHits(HwVideoBufferPath path) noexcept
void initializeOnce() noexcept
One-time process init; single call site for future lazy bridge registration.
bool answerSinkBinContextQuery(GstQuery *query) noexcept
Synchronously answer GST_QUERY_CONTEXT (gst.gl.GLDisplay/app_context); false -> let bus NEED_CONTEXT ...
QString takeExtraPathStats() noexcept
Path-specific extras after formatPathStats (GL reuse/sync waits); reads-and-clears,...
void onPipelineRestart() noexcept
Pipeline-restart hook; re-arms one-shot priming latches so a restart can prime on the next NEED_CONTE...
void resetCachedGpuResources() noexcept
Drop process-wide native GPU handles tied to the current Qt scene-graph device/context.
void connectMainWindow(QQuickWindow *window) noexcept
Wire the main QQuickWindow into the RHI-capture path so snapshots follow its QRhi; no-op without GPU.
GstBusSyncReply onBusSyncMessage(GstBus *, GstMessage *msg, gpointer) noexcept
Bus sync handler (GstBusSyncHandler) installed on every pipeline; no-op when no GPU path compiled.
void dispatchBusMessage(GstMessage *msg) noexcept
Receiver-side bus hook; drops cached GPU devices on GST_MESSAGE_ERROR. No-op when no GPU paths compil...
const HwBufferEnvConfig & hwBufferEnvConfig() noexcept
Lazily parses + logs the toggle config on first call; thread-safe via static-init guarantees.
PathStats formatPathStats(bool reset) noexcept
void connectWindow(QQuickWindow *window)
bool dmaBufSingleEglImage
Formatted per-path counters + delivered total; reset=true reads-and-clears (teardown),...
Platform context for the factory; encapsulates EGL handles so callers don't need path-specific ifdefs...