6#if defined(QGC_HAS_GST_GLMEMORY_GPU_PATH)
8#include <QtCore/QLoggingCategory>
9#include <QtCore/QMutex>
10#include <QtCore/QMutexLocker>
11#include <QtGui/QGuiApplication>
12#include <QtGui/QOpenGLContext>
13#include <QtGui/qguiapplication_platform.h>
19#if defined(__linux__) || (defined(_WIN32) && __has_include(<EGL/egl.h>))
21#include <gst/gl/egl/gstgldisplay_egl.h>
22#define QGC_GST_BRIDGE_HAS_EGL 1
26#if __has_include(<gst/gl/x11/gstgldisplay_x11.h>) && __has_include(<QtGui/qopenglcontext_platform.h>)
27#include <QtGui/qopenglcontext_platform.h>
29#include <gst/gl/x11/gstgldisplay_x11.h>
30#define QGC_GST_BRIDGE_HAS_GLX 1
34#if __has_include(<gst/gl/wayland/gstgldisplay_wayland.h>)
35#include <gst/gl/wayland/gstgldisplay_wayland.h>
36#define QGC_GST_BRIDGE_HAS_WAYLAND 1
42namespace GstGlContextBridge {
46GstGLDisplay* s_display =
nullptr;
47GstGLContext* s_context =
nullptr;
49GstBridgePrimeRetry::PrimeRetryState s_retry;
51#if defined(QGC_GST_BRIDGE_HAS_EGL)
52EGLDisplay qtEglDisplay(QOpenGLContext* qtCtx)
57 if (
auto* egl = qtCtx->nativeInterface<QNativeInterface::QEGLContext>()) {
58 EGLDisplay d = egl->display();
59 if (d != EGL_NO_DISPLAY)
63 return eglGetDisplay(EGL_DEFAULT_DISPLAY);
66EGLContext qtEglContext(QOpenGLContext* qtCtx)
69 return EGL_NO_CONTEXT;
70 if (
auto* egl = qtCtx->nativeInterface<QNativeInterface::QEGLContext>()) {
71 return egl->nativeContext();
73 return EGL_NO_CONTEXT;
79 switch (GstBridgePrimeRetry::primeRetryGuard(s_retry)) {
80 case GstBridgePrimeRetry::Decision::AlreadyPrimed:
82 case GstBridgePrimeRetry::Decision::GiveUp:
84 case GstBridgePrimeRetry::Decision::ShouldRetry:
88 QOpenGLContext* qtCtx = QOpenGLContext::globalShareContext();
90 if (GstBridgePrimeRetry::rearmRetry(s_retry)) {
91 qCInfo(GstGlBridgeLog) <<
"globalShareContext() is null — Qt GL not initialized yet"
92 <<
"(attempt" << s_retry.nullCount <<
"/" << s_retry.maxRetries <<
")";
93 }
else if (GstBridgePrimeRetry::justGaveUp(s_retry)) {
94 qCWarning(GstGlBridgeLog) <<
"globalShareContext() still null after" << s_retry.maxRetries
95 <<
"retries; GL bridge giving up";
100#if defined(QGC_GST_BRIDGE_HAS_EGL)
102 EGLContext eglCtx = qtEglContext(qtCtx);
103 EGLDisplay eglDisp = (eglCtx != EGL_NO_CONTEXT) ? qtEglDisplay(qtCtx) : EGL_NO_DISPLAY;
105 auto bail = [](
const char*) ->
bool {
106 s_retry.primeAttempted =
false;
109 if (eglCtx != EGL_NO_CONTEXT && eglDisp != EGL_NO_DISPLAY) {
110#if defined(QGC_GST_BRIDGE_HAS_WAYLAND)
113 const QString platformName = QGuiApplication::platformName();
114 if (platformName == QLatin1String(
"wayland") || platformName == QLatin1String(
"wayland-egl")) {
115 struct wl_display* wlDisp =
nullptr;
116 if (
auto* wl =
qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>()) {
117 wlDisp = wl->display();
120 GstGLDisplayWayland* displayWl = gst_gl_display_wayland_new_with_display(wlDisp);
122 s_display = GST_GL_DISPLAY(displayWl);
123#if GST_CHECK_VERSION(1, 26, 0)
126 if (GstGLDisplayEGL* derived = gst_gl_display_egl_from_gl_display(s_display)) {
127 gst_gl_display_egl_set_foreign(derived, TRUE);
128 gst_object_unref(derived);
136 GstGLDisplayEGL* displayEgl = gst_gl_display_egl_new_with_egl_display(eglDisp);
138 qCWarning(GstGlBridgeLog) <<
"gst_gl_display_egl_new_with_egl_display failed";
139 return bail(
"displayEgl");
141 s_display = GST_GL_DISPLAY(displayEgl);
144 s_context = gst_gl_context_new_wrapped(s_display,
reinterpret_cast<guintptr
>(eglCtx), GST_GL_PLATFORM_EGL,
145 static_cast<GstGLAPI
>(GST_GL_API_GLES2 | GST_GL_API_OPENGL));
147 qCWarning(GstGlBridgeLog) <<
"gst_gl_context_new_wrapped (EGL) failed";
148 gst_clear_object(&s_display);
149 return bail(
"ctxEgl");
151#if defined(QGC_GST_BRIDGE_HAS_WAYLAND)
152 const bool isWayland = GST_IS_GL_DISPLAY_WAYLAND(s_display);
153 qCInfo(GstGlBridgeLog) << (isWayland ?
"GL bridge primed (Wayland+EGL)" :
"GL bridge primed (EGL)");
155 qCInfo(GstGlBridgeLog) <<
"GL bridge primed (EGL)";
158#if defined(QGC_GST_BRIDGE_HAS_GLX)
160 auto* glx = qtCtx->nativeInterface<QNativeInterface::QGLXContext>();
162 qCWarning(GstGlBridgeLog) <<
"Qt GL context exposes neither EGL nor GLX; GL bridge disabled";
163 return bail(
"noGlx");
165 Display* xdisp =
nullptr;
166 if (
auto* x11 =
qGuiApp->nativeInterface<QNativeInterface::QX11Application>()) {
167 xdisp = x11->display();
170 qCWarning(GstGlBridgeLog) <<
"X11 Display unresolvable; GL bridge disabled";
171 return bail(
"xdisp");
173 GstGLDisplayX11* displayX11 = gst_gl_display_x11_new_with_display(xdisp);
175 qCWarning(GstGlBridgeLog) <<
"gst_gl_display_x11_new_with_display failed";
176 return bail(
"displayX11");
178 s_display = GST_GL_DISPLAY(displayX11);
179 s_context = gst_gl_context_new_wrapped(s_display,
reinterpret_cast<guintptr
>(glx->nativeContext()),
180 GST_GL_PLATFORM_GLX,
static_cast<GstGLAPI
>(GST_GL_API_OPENGL));
182 qCWarning(GstGlBridgeLog) <<
"gst_gl_context_new_wrapped (GLX) failed";
183 gst_clear_object(&s_display);
184 return bail(
"ctxGlx");
186 qCInfo(GstGlBridgeLog) <<
"GL bridge primed (GLX)";
188 qCWarning(GstGlBridgeLog) <<
"Qt EGLContext unresolvable and GLX bridge not built; GL bridge disabled";
189 return bail(
"noEglNoGlx");
193 s_retry.primed =
true;
196 qCDebug(GstGlBridgeLog) <<
"GL bridge primed: display=" << s_display <<
"context=" << s_context;
201 qCInfo(GstGlBridgeLog) <<
"GL bridge inactive on this platform (non-EGL)";
210constexpr char kGlAppContextType[] =
"gst.gl.app_context";
211const char*
const kContextTypes[] = {GST_GL_DISPLAY_CONTEXT_TYPE, kGlAppContextType};
213const QLoggingCategory& vtCat(
void*)
215 return GstGlBridgeLog();
218QMutex& vtMutex(
void*)
225 return primeLocked();
228GstObject* vtRefObject(
void*,
const char* contextType)
230 if (g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
231 return s_display ? GST_OBJECT(gst_object_ref(s_display)) : nullptr;
233 return s_context ? GST_OBJECT(gst_object_ref(s_context)) : nullptr;
236GstContext* vtBuildContext(
void*,
const char* contextType, GstObject*
object)
238 if (g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
239 GstContext* ctx = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
240 gst_context_set_gl_display(ctx, GST_GL_DISPLAY(
object));
243 GstContext* ctx = gst_context_new(kGlAppContextType, TRUE);
244 GstStructure* s = gst_context_writable_structure(ctx);
245 gst_structure_set(s,
"context", GST_TYPE_GL_CONTEXT, GST_GL_CONTEXT(
object), NULL);
249const GstContextBridge::BridgeVTable s_vtable = {
250 "GL", kContextTypes, 2, &vtCat, &vtMutex, &vtPrime, &vtRefObject, &vtBuildContext,
nullptr,
257 QMutexLocker lock(&s_mutex);
258 return primeLocked();
261GstBusSyncReply handleSyncMessage(GstMessage* message)
263 return GstContextBridge::handleSyncMessage(s_vtable,
nullptr, message);
266bool answerContextQuery(GstQuery* query)
268 return GstContextBridge::answerContextQuery(s_vtable,
nullptr, query);
273 QMutexLocker lock(&s_mutex);
274 gst_clear_object(&s_context);
275 gst_clear_object(&s_display);
276 GstBridgePrimeRetry::resetRetry(s_retry);
277 qCDebug(GstGlBridgeLog) <<
"GL bridge reset";
282 QMutexLocker lock(&s_mutex);
283 if (GstBridgePrimeRetry::rearmAfterExhaustion(s_retry)) {
284 qCInfo(GstGlBridgeLog) <<
"GL bridge rearm: clearing exhausted retry latch";
289struct GlBridgeRegistrar
293 GstContextBridge::registerBridge(GstGlBridgeLog(),
"GL", &GstGlContextBridge::handleSyncMessage,
294 &GstGlContextBridge::reset);
298static GlBridgeRegistrar s_glBridgeRegistrar;
#define QGC_LOGGING_CATEGORY(name, categoryStr)