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/qmultimedia_ranges_p.h>
7#include <QtMultimedia/private/qvideotexturehelper_p.h>
8
9#include <QtGui/qopenglcontext.h>
10#include <QtGui/rhi/qrhi.h>
11#include <QtCore/qloggingcategory.h>
12#include <QtCore/qscopeguard.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{
28 eglGetProcAddress("glEGLImageTargetTexture2DOES"));
29}
30
36
38{
39 return m_glEGLImageTargetTexture2DOES != nullptr;
40}
41
46
48{
49 if (!rhi || rhi->backend() != QRhi::OpenGLES2) {
50 qWarning() << "DmaBufEglContext: No rhi or non openGL based RHI";
51 return;
52 }
53
55 if (!m_glContext) {
56 qCDebug(qLDmaBuf) << " no GL context, disabling";
57 return;
58 }
59
61 if (!eglContext) {
62 qCDebug(qLDmaBuf) << " no EGL context, disabling";
63 return;
64 }
65
67 if (!m_eglDisplay) {
68 qCDebug(qLDmaBuf) << " no egl display, disabling";
69 return;
70 }
71
73 qCDebug(qLDmaBuf) << " no eglImageTargetTexture2D, disabling";
74 return;
75 }
76
77 m_valid = true;
78}
79
90
97
99importDmaBufTextures(QRhi &rhi, const DmaBufEglContext &eglContext, QSpan<const DmaBufPlane> planes,
100 QVideoFrameFormat::PixelFormat qtFormat, QSize frameSize,
101 std::shared_ptr<void> parentKeepAlive)
102{
103 Qt::HANDLE eglDisplay = eglContext.eglDisplay();
104 QOpenGLContext *glContext = eglContext.glContext();
105
106 QOpenGLFunctions functions(glContext);
107
108 auto *desc = QVideoTextureHelper::textureDescription(qtFormat);
109 int nPlanes = desc->nplanes;
110 Q_ASSERT(planes.size() == nPlanes);
111
112 rhi.makeThreadLocalNativeContextCurrent();
113
114 EGLImage images[4] = {};
115 std::array<GLuint, 4> glTextures{};
116 functions.glGenTextures(nPlanes, glTextures.data());
117
118 auto releaseTextures = qScopeGuard([&] {
119 for (EGLImage img : images | views::filter_nonnull)
120 eglDestroyImage(eglDisplay, img);
121
122 functions.glDeleteTextures(nPlanes, glTextures.data());
123 });
124
125 for (int i = 0; i < nPlanes; ++i) {
126 const DmaBufPlane &plane = planes[i];
127
128 QSize planeSize = desc->rhiPlaneSize(frameSize, i, &rhi);
129 constexpr uint32_t maxAttrCount = 18;
130 EGLAttrib img_attr[maxAttrCount] = {
131 EGL_LINUX_DRM_FOURCC_EXT,
132 (EGLint)qToUnderlying(plane.drmFormat),
133 EGL_WIDTH,
134 planeSize.width(),
135 EGL_HEIGHT,
136 planeSize.height(),
137 EGL_DMA_BUF_PLANE0_FD_EXT,
138 plane.fd,
139 EGL_DMA_BUF_PLANE0_OFFSET_EXT,
140 (EGLint)plane.offset,
141 EGL_DMA_BUF_PLANE0_PITCH_EXT,
142 (EGLint)plane.pitch,
143 };
144 uint32_t img_attr_idx = 12;
145 if (plane.modifier != DmaBufFormatModifierInvalid) {
146 img_attr[img_attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
147 img_attr[img_attr_idx++] = plane.modifier & 0xFFFFFFFF;
148 img_attr[img_attr_idx++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
149 img_attr[img_attr_idx++] = plane.modifier >> 32;
150 }
151 img_attr[img_attr_idx++] = EGL_NONE;
152 Q_ASSERT(img_attr_idx <= maxAttrCount);
153 images[i] = eglCreateImage(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr,
154 img_attr);
155 if (!images[i]) {
156 const GLenum error = eglGetError();
157 if (error == EGL_BAD_MATCH) {
158 qWarning() << "eglCreateImage failed for plane" << i
159 << "with error code EGL_BAD_MATCH, disabling hardware acceleration. "
160 "This could indicate an EGL implementation issue."
161 "\nEGL vendor:"
162 << eglQueryString(eglDisplay, EGL_VENDOR);
163 // Disabling texture conversion here to fix QTBUG-112312
164 return q23::unexpected{ FailureSeverity::unrecoverable };
165 }
166 if (error) {
167 qWarning() << "eglCreateImage failed for plane" << i << "with error code" << error;
168 return q23::unexpected{ FailureSeverity::recoverable };
169 }
170 }
171 functions.glActiveTexture(GL_TEXTURE0 + i);
172 functions.glBindTexture(GL_TEXTURE_2D, glTextures[i]);
173
174 QEglImageFunctions::instance().glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, images[i]);
175 GLenum error = glGetError();
176 if (error) {
177 qWarning() << "eglImageTargetTexture2D failed for plane" << i << "with error code"
178 << error
179 << "(the driver may not support importing this dma-buf as a GL texture)";
180 return q23::unexpected{ FailureSeverity::recoverable };
181 }
182 }
183
184 releaseTextures.dismiss();
185
186 for (int i = 0; i < nPlanes; ++i) {
187 functions.glActiveTexture(GL_TEXTURE0 + i);
188 functions.glBindTexture(GL_TEXTURE_2D, 0);
189 eglDestroyImage(eglDisplay, images[i]);
190 }
191
192 return std::make_unique<DmaBufTextureHandles>(rhi, glContext, nPlanes, glTextures,
193 std::move(parentKeepAlive));
194}
195
196} // namespace QtMultimediaPrivate
197
198QT_END_NAMESPACE
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)