QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstDmaDrmCaps.cc
Go to the documentation of this file.
1#include "GstDmaDrmCaps.h"
2
3#if GST_CHECK_VERSION(1, 24, 0)
4#include <gst/video/video-info-dma.h>
5#endif
6
7#if defined(QGC_HAS_GST_DMABUF_GPU_PATH) && GST_CHECK_VERSION(1, 24, 0)
8#include "GstDmaFourcc.h"
9#include "GstEglHelpers.h"
10
11#include "QGCLoggingCategory.h"
12
13#include <QtCore/QByteArray>
14#include <QtCore/QSet>
15#include <QtGui/QOpenGLContext>
16
17#include <EGL/egl.h>
18#include <EGL/eglext.h>
19
20#include <cstdint>
21#include <vector>
22
23QGC_LOGGING_CATEGORY(GstDmaDrmCapsLog, "Video.GStreamer.HwBuffers.GstDmaDrmCaps")
24#endif
25
26namespace GstHw {
27
28bool dmaDrmAwareVideoInfo(GstCaps* caps, GstVideoInfo* info)
29{
30 if (!caps || !info) {
31 return false;
32 }
33#if GST_CHECK_VERSION(1, 24, 0)
34 if (gst_video_is_dma_drm_caps(caps)) {
35 GstVideoInfoDmaDrm drmInfo;
36 gst_video_info_dma_drm_init(&drmInfo);
37 return gst_video_info_dma_drm_from_caps(&drmInfo, caps) && gst_video_info_dma_drm_to_video_info(&drmInfo, info);
38 }
39#endif
40 return gst_video_info_from_caps(info, caps);
41}
42
43#if defined(QGC_HAS_GST_DMABUF_GPU_PATH) && GST_CHECK_VERSION(1, 24, 0)
44
45namespace {
46
47constexpr const char* kModifiersExt = "EGL_EXT_image_dma_buf_import_modifiers";
48
49// Renderable tokens from the kFormats brace list ("{ NV12, NV21, ... }"); intersected with EGL results below so we
50// never advertise a format the Qt mapper would reject.
51QSet<QByteArray> parseFormatTokens(const char* gstFormatList)
52{
53 QSet<QByteArray> tokens;
54 if (!gstFormatList)
55 return tokens;
56 for (QByteArray tok : QByteArray(gstFormatList).split(',')) {
57 tok.replace('{', "").replace('}', "");
58 tok = tok.trimmed();
59 if (!tok.isEmpty())
60 tokens.insert(tok);
61 }
62 return tokens;
63}
64
65// LINEAR-only: tiled external DMABuf from gst-va/iHD can be negotiated and even imported, but binding the resulting
66// EGLImage through Qt's render-thread GL path segfaults Mesa/Gallium on this stack. The default glupload path can
67// handle those tiled buffers; direct-QGC DMABuf only advertises layouts it can safely bind itself.
68bool isImportableModifier(EGLuint64KHR mod) noexcept
69{
70 return mod == 0; // DRM_FORMAT_MOD_LINEAR
71}
72
73} // namespace
74
75std::string buildSupportedDmaDrmCaps(const char* gstFormatList)
76{
77 const QSet<QByteArray> allowed = parseFormatTokens(gstFormatList);
78 if (allowed.isEmpty())
79 return std::string();
80
81 // Built on the GstVideo worker thread with no current GL context, so the share-context display is
82 // EGL_NO_DISPLAY; fall back to the default display (modifiers are GPU-global). Never eglTerminate'd.
83 EGLDisplay dpy = GstEglHelpers::resolveEglDisplay(QOpenGLContext::globalShareContext());
84 if (dpy == EGL_NO_DISPLAY)
85 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
86 if (dpy != EGL_NO_DISPLAY)
87 eglInitialize(dpy, nullptr, nullptr);
88 if (dpy == EGL_NO_DISPLAY || !GstEglHelpers::displaySupportsExtension(dpy, kModifiersExt)) {
89 qCDebug(GstDmaDrmCapsLog) << "DMA_DRM modifier query unavailable (no EGL display or "
90 "EGL_EXT_image_dma_buf_import_modifiers); offering no DMA_DRM caps";
91 return std::string();
92 }
93
94 const auto queryFormats =
95 reinterpret_cast<PFNEGLQUERYDMABUFFORMATSEXTPROC>(eglGetProcAddress("eglQueryDmaBufFormatsEXT"));
96 const auto queryModifiers =
97 reinterpret_cast<PFNEGLQUERYDMABUFMODIFIERSEXTPROC>(eglGetProcAddress("eglQueryDmaBufModifiersEXT"));
98 if (!queryFormats || !queryModifiers)
99 return std::string();
100
101 EGLint numFormats = 0;
102 if (queryFormats(dpy, 0, nullptr, &numFormats) != EGL_TRUE || numFormats <= 0)
103 return std::string();
104 std::vector<EGLint> formats(static_cast<std::size_t>(numFormats));
105 if (queryFormats(dpy, numFormats, formats.data(), &numFormats) != EGL_TRUE || numFormats <= 0)
106 return std::string();
107 formats.resize(static_cast<std::size_t>(numFormats));
108
109 std::string entries;
110 int formatCount = 0;
111 int modifierCount = 0;
112 int excludedCount = 0;
113 for (const EGLint fourcc : formats) {
114 const char* gstName = gstFormatNameForImportableFourcc(static_cast<uint32_t>(fourcc));
115 if (!gstName || !allowed.contains(QByteArray(gstName)))
116 continue;
117
118 EGLint numMods = 0;
119 if (queryModifiers(dpy, fourcc, 0, nullptr, nullptr, &numMods) != EGL_TRUE || numMods <= 0)
120 continue;
121 std::vector<EGLuint64KHR> mods(static_cast<std::size_t>(numMods));
122 if (queryModifiers(dpy, fourcc, numMods, mods.data(), nullptr, &numMods) != EGL_TRUE || numMods <= 0)
123 continue;
124 mods.resize(static_cast<std::size_t>(numMods));
125
126 bool counted = false;
127 for (const EGLuint64KHR mod : mods) {
128 if (!isImportableModifier(mod)) {
129 ++excludedCount;
130 continue;
131 }
132 // drm-format wants the DRM fourcc 4CC string, not the GStreamer format name; to_string emits a bare
133 // fourcc for LINEAR and "FOURCC:0xMOD" otherwise ("FOURCC:0x0" fails to parse in gst 1.24).
134 gchar* drmStr = gst_video_dma_drm_fourcc_to_string(static_cast<guint32>(fourcc), mod);
135 if (!drmStr)
136 continue;
137 if (!entries.empty())
138 entries += ", ";
139 entries += drmStr;
140 g_free(drmStr);
141 ++modifierCount;
142 counted = true;
143 }
144 if (counted)
145 ++formatCount;
146 }
147
148 if (entries.empty())
149 return std::string();
150
151 qCInfo(GstDmaDrmCapsLog) << "EGL-derived DMA_DRM caps:" << formatCount << "formats," << modifierCount
152 << "modifiers offered," << excludedCount << "non-importable modifiers excluded";
153 return std::string("video/x-raw(memory:DMABuf), format=DMA_DRM, drm-format={ ") + entries + " }; ";
154}
155
156std::string buildLinearDmaDrmCaps(const char* gstFormatList)
157{
158 std::string entries;
159 for (const QByteArray& tok : parseFormatTokens(gstFormatList)) {
160 const GstVideoFormat fmt = gst_video_format_from_string(tok.constData());
161 if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
162 continue;
163 const guint32 fourcc = gst_video_dma_drm_fourcc_from_format(fmt);
164 if (fourcc == 0) // DRM_FORMAT_INVALID
165 continue;
166 gchar* drmStr = gst_video_dma_drm_fourcc_to_string(fourcc, 0); // 0 == DRM_FORMAT_MOD_LINEAR; bare fourcc
167 if (!drmStr)
168 continue;
169 if (!entries.empty())
170 entries += ", ";
171 entries += drmStr;
172 g_free(drmStr);
173 }
174 if (entries.empty())
175 return std::string();
176 return std::string("video/x-raw(memory:DMABuf), format=DMA_DRM, drm-format={ ") + entries + " }; ";
177}
178
179#ifdef QGC_GST_BUILD_TESTING
180bool dmaDrmModifierAdvertisedForTest(guint64 modifier) noexcept
181{
182 return isImportableModifier(static_cast<EGLuint64KHR>(modifier));
183}
184#endif
185
186#else
187
188std::string buildSupportedDmaDrmCaps(const char*)
189{
190 return std::string();
191}
192
193std::string buildLinearDmaDrmCaps(const char*)
194{
195 return std::string();
196}
197
198#ifdef QGC_GST_BUILD_TESTING
199bool dmaDrmModifierAdvertisedForTest(guint64) noexcept
200{
201 return false;
202}
203#endif
204
205#endif // QGC_HAS_GST_DMABUF_GPU_PATH && GST_CHECK_VERSION(1, 24, 0)
206
207} // namespace GstHw
#define QGC_LOGGING_CATEGORY(name, categoryStr)
std::string buildLinearDmaDrmCaps(const char *)
bool dmaDrmAwareVideoInfo(GstCaps *caps, GstVideoInfo *info)
std::string buildSupportedDmaDrmCaps(const char *)