Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdmabuftextureimporter.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtMultimedia/private/qeglimagefunctions_p.h>
7#include <QtMultimedia/private/qmultimedia_gl_support_p.h>
8#include <QtMultimedia/private/qvideotexturehelper_p.h>
9
10#include <QtGui/qopenglcontext.h>
11#include <QtGui/rhi/qrhi.h>
12#include <QtCore/qloggingcategory.h>
13
14#include <EGL/egl.h>
15#include <EGL/eglext.h>
16
17static_assert(QT_CONFIG(linux_dmabuf));
18
20
21Q_STATIC_LOGGING_CATEGORY(qLDmaBuf, "qt.multimedia.dmabuf");
22
23namespace QtMultimediaPrivate {
24
26{
27 if (!rhi || rhi->backend() != QRhi::OpenGLES2) {
28 qWarning() << "DmaBufEglContext: No rhi or non openGL based RHI";
29 return;
30 }
31
33 if (!m_glContext) {
34 qCDebug(qLDmaBuf) << " no GL context, disabling";
35 return;
36 }
37
39 if (!eglContext) {
40 qCDebug(qLDmaBuf) << " no EGL context, disabling";
41 return;
42 }
43
45 if (!m_eglDisplay) {
46 qCDebug(qLDmaBuf) << " no egl display, disabling";
47 return;
48 }
49
51 qCDebug(qLDmaBuf) << " no eglImageTargetTexture2D, disabling";
52 return;
53 }
54
55 m_valid = true;
56}
57
63
65{
66 // m_textures is destroyed right after this body runs, calling glDeleteTextures on each plane.
68}
69
70static bool dmaModifierIsNotSupportedByDisplay(const DmaBufPlane &plane, EGLDisplay eglDisplay)
71{
72 if (plane.modifier == DmaBufFormatModifierInvalid)
73 return true; // no modifier info to check
74
75 auto &eglFunctions = QEglImageFunctions::instance();
76 constexpr bool assumeSupportedWhenUnknown = true;
77 const bool formatIsSupported =
78 eglFunctions.isDmaBufModifierSupported(eglDisplay, plane.drmFormat, plane.modifier)
79 .value_or(assumeSupportedWhenUnknown);
80 return formatIsSupported;
81}
82
84importDmaBufTextures(QRhi &rhi, const DmaBufEglContext &eglContext, QSpan<const DmaBufPlane> planes,
85 QVideoFrameFormat::PixelFormat qtFormat, QSize frameSize,
86 std::shared_ptr<void> parentKeepAlive)
87{
88 Qt::HANDLE eglDisplay = eglContext.eglDisplay();
89 QOpenGLContext *glContext = eglContext.glContext();
90
91 QOpenGLFunctions functions(glContext);
92 const auto &elgImageFunctions = QEglImageFunctions::instance();
93
94 auto *desc = QVideoTextureHelper::textureDescription(qtFormat);
95 int nPlanes = desc->nplanes;
96 Q_ASSERT(planes.size() == nPlanes);
97
98 rhi.makeThreadLocalNativeContextCurrent();
99
100 std::array<EGLImageHandle, 4> images;
101 std::array<GLuint, 4> rawGlTextures{};
102 functions.glGenTextures(nPlanes, rawGlTextures.data());
103
104 std::array<GlTextureHandle, 4> glTextures;
105 for (int i = 0; i < nPlanes; ++i)
106 glTextures[i] = GlTextureHandle(rawGlTextures[i], GlTextureDeleter(glContext));
107
108 for (int i = 0; i < nPlanes; ++i) {
109 const DmaBufPlane &plane = planes[i];
110
111 QSize planeSize = desc->rhiPlaneSize(frameSize, i, &rhi);
112 constexpr uint32_t maxAttrCount = 18;
113 EGLAttrib img_attr[maxAttrCount] = {
114 EGL_LINUX_DRM_FOURCC_EXT,
115 (EGLint)qToUnderlying(plane.drmFormat),
116 EGL_WIDTH,
117 planeSize.width(),
118 EGL_HEIGHT,
119 planeSize.height(),
120 EGL_DMA_BUF_PLANE0_FD_EXT,
121 plane.fd,
122 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
123 (EGLint)plane.offset,
124 EGL_DMA_BUF_PLANE0_PITCH_EXT,
125 (EGLint)plane.pitch,
126 };
127 uint32_t img_attr_idx = 12;
128 if (plane.modifier != DmaBufFormatModifierInvalid) {
129 const auto modifier = qToUnderlying(plane.modifier);
130 img_attr[img_attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
131 img_attr[img_attr_idx++] = EGLAttrib(modifier & 0xFFFFFFFF);
132 img_attr[img_attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
133 img_attr[img_attr_idx++] = EGLAttrib(modifier >> 32);
134 }
135 img_attr[img_attr_idx++] = EGL_NONE;
136 Q_ASSERT(img_attr_idx <= maxAttrCount);
137 images[i] = elgImageFunctions.eglCreateImage(
138 eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr,
139 QSpan<const EGLAttrib>(img_attr, img_attr_idx));
140 if (!images[i]) {
141 const EGLError error = EGLError(eglGetError());
142 switch (error) {
143 case EGLError::Success: {
144 break;
145 }
146 case EGLError::BadMatch: {
147 qWarning() << "eglCreateImage failed for plane" << i << "with" << error
148 << ", disabling hardware acceleration. "
149 "This could indicate an EGL implementation issue."
150 "\nEGL vendor:"
151 << eglQueryString(eglDisplay, EGL_VENDOR);
152 // Disabling texture conversion here to fix QTBUG-112312
153 return q23::unexpected{ FailureSeverity::unrecoverable };
154 }
155 case EGLError::BadParameter: {
156 bool dmaModifierNotSupported =
157 dmaModifierIsNotSupportedByDisplay(plane, eglDisplay);
158 if (dmaModifierNotSupported) {
159 qWarning() << "eglCreateImage failed for plane" << i << "with" << error
160 << ", disabling hardware acceleration. "
161 "This could indicate an EGL implementation issue."
162 "\nEGL vendor:"
163 << eglQueryString(eglDisplay, EGL_VENDOR);
164 // Disabling texture conversion here to fix QTBUG-112312
165 return q23::unexpected{ FailureSeverity::unrecoverable };
166 }
167 [[fallthrough]];
168 }
169 default: {
170 qWarning() << "eglCreateImage failed for plane" << i << "with" << error;
171 return q23::unexpected{ FailureSeverity::recoverable };
172 }
173 }
174 }
175 functions.glActiveTexture(GL_TEXTURE0 + i);
176 functions.glBindTexture(GL_TEXTURE_2D, glTextures[i].get());
177
178 elgImageFunctions.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, images[i].get());
179 const GLError error = GLError(glGetError());
180 if (error != GLError::NoError) {
181 qWarning() << "eglImageTargetTexture2D failed for plane" << i << "with" << error
182 << "(the driver may not support importing this dma-buf as a GL texture)";
183 return q23::unexpected{ FailureSeverity::recoverable };
184 }
185 }
186
187 for (int i = 0; i < nPlanes; ++i) {
188 functions.glActiveTexture(GL_TEXTURE0 + i);
189 functions.glBindTexture(GL_TEXTURE_2D, 0);
190 }
191
192 return std::make_unique<DmaBufTextureHandles>(rhi, std::move(glTextures),
193 std::move(parentKeepAlive));
194}
195
196} // namespace QtMultimediaPrivate
197
198QT_END_NAMESPACE
static bool dmaModifierIsNotSupportedByDisplay(const DmaBufPlane &plane, EGLDisplay eglDisplay)
q23::expected< QVideoFrameTexturesHandlesUPtr, FailureSeverity > importDmaBufTextures(QRhi &rhi, const DmaBufEglContext &eglContext, QSpan< const DmaBufPlane > planes, QVideoFrameFormat::PixelFormat qtFormat, QSize frameSize, std::shared_ptr< void > parentKeepAlive)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)