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
qdmabufvideobuffer.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/qvideotexturehelper_p.h>
7#include <QtMultimedia/private/qrhivaluemapper_p.h>
8#include <QtGui/rhi/qrhi.h>
9#include <QtCore/qloggingcategory.h>
10
11#if QT_CONFIG(opengl) && QT_CONFIG(egl)
12# include <QtMultimedia/private/qdmabuftextureimporter_p.h>
13#endif
14
15#include <cerrno>
16#include <cstring>
17#include <fcntl.h>
18#include <unistd.h>
19#include <sys/mman.h>
20
21static_assert(QT_CONFIG(linux_dmabuf));
22
24
25Q_STATIC_LOGGING_CATEGORY(qLcDmaBufVideoBuffer, "qt.multimedia.dmabufvideobuffer");
26
27namespace QtMultimediaPrivate {
28
29#if QT_CONFIG(opengl) && QT_CONFIG(egl)
31#endif
32
38 m_size(size),
39 m_planeCount(std::clamp(0, int(planes.size()), 4)),
41{
42 Q_ASSERT(!planes.empty() && planes.size() <= 4);
43
44 for (int i = 0; i < m_planeCount; ++i) {
45 m_planes[i] = planes[i];
46
47 // Take our own, independent reference: the producer may close its
48 // fd at any point while this buffer is still alive.
49 if (m_planes[i].fd >= 0) {
50 const int dupped = ::fcntl(m_planes[i].fd, F_DUPFD_CLOEXEC, 0);
51 if (dupped < 0) {
52 qCWarning(qLcDmaBufVideoBuffer) << "Failed to dup DMABUF fd for plane" << i << ':'
53 << qt_error_string(errno);
54 m_planes[i].fd = -1;
55 } else {
57 }
58 }
59 }
60}
61
63{
65
66 for (int i = 0; i < m_planeCount; ++i) {
67 if (m_planes[i].fd >= 0)
68 ::close(m_planes[i].fd);
69 }
70}
71
74{
77
78 if (rhi.backend() != QRhi::OpenGLES2)
79 return {};
80
81#if QT_CONFIG(opengl) && QT_CONFIG(egl)
82 // DmaBufEglContext is bound to the GL context associated with a QRhi;
83 // textures are (re-)imported on the RHI render thread, so this is
84 // created lazily here (rather than in the constructor, which may run on
85 // a different thread) and cached per-rhi.
87 return DmaBufEglContext(&rhi);
88 });
89
90 if (!eglContext.isValid()) {
91 qCDebug(qLcDmaBufVideoBuffer) << "DmaBufEglContext is not valid, falling back to CPU path";
92 return {};
93 }
94
97 if (!handles) {
100 << "Unrecoverable EGL import failure, disabling texture import for this buffer";
102 }
103 return {};
104 }
105
107 m_size);
108#else // QT_CONFIG(opengl) && QT_CONFIG(egl)
110 << "DMABUF texture import is not supported in this build, falling back to CPU path";
111 return {};
112#endif // QT_CONFIG(opengl) && QT_CONFIG(egl)
113}
114
116{
118
119 // The producer (driver/compositor) owns write access to the DMABUF.
121 return mapData;
122
124 if (!desc)
125 return mapData;
126
127 QVarLengthArray<std::pair<int, std::pair<void *, size_t>>, 4> mappedByFd;
128
129 for (int i = 0; i < m_planeCount; ++i) {
130 const DmaBufPlane &plane = m_planes[i];
131
132 void *base = nullptr;
133 for (const auto &entry : mappedByFd) {
134 if (entry.first == plane.fd) {
136 break;
137 }
138 }
139
140 if (!base) {
141 // Determine the size of the DMABUF via lseek (dma-buf file
142 // objects implement llseek to report their size), then mmap it
143 // read-only in one go; individual planes just index into this
144 // mapping via their offset.
145 const off_t len = ::lseek(plane.fd, 0, SEEK_END);
146 if (len <= 0) {
147 qCWarning(qLcDmaBufVideoBuffer) << "Could not determine DMABUF size for plane" << i;
148 for (const auto &entry : mappedByFd)
150 return {};
151 }
152
153 void *mapped = ::mmap(nullptr, size_t(len), PROT_READ, MAP_SHARED, plane.fd, 0);
154 if (mapped == MAP_FAILED) {
156 << "mmap failed for plane" << i << ':' << qt_error_string(errno);
157 for (const auto &entry : mappedByFd)
159 return {};
160 }
161
163 base = mapped;
164 }
165
166 mapData.data[i] = static_cast<uchar *>(base) + plane.offset;
169 }
170
172
174 for (const auto &entry : mappedByFd)
176
177 m_mapMode = mode;
178 return mapData;
179}
180
182{
183 for (const auto &region : m_mappedRegions)
186
188}
189
190} // namespace QtMultimediaPrivate
191
192QT_END_NAMESPACE
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define MAP_FAILED