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
37 m_size(size),
38 m_planeCount(std::clamp(0, int(planes.size()), 4)),
40{
41 Q_ASSERT(!planes.empty() && planes.size() <= 4);
42
43 for (int i = 0; i < m_planeCount; ++i) {
44 m_planes[i] = planes[i];
45
46 // Take our own, independent reference: the producer may close its
47 // fd at any point while this buffer is still alive.
48 if (m_planes[i].fd >= 0) {
49 const int dupped = ::fcntl(m_planes[i].fd, F_DUPFD_CLOEXEC, 0);
50 if (dupped < 0) {
51 qCWarning(qLcDmaBufVideoBuffer) << "Failed to dup DMABUF fd for plane" << i << ':'
52 << qt_error_string(errno);
53 m_planes[i].fd = -1;
54 } else {
56 }
57 }
58 }
59}
60
62{
64
65 for (int i = 0; i < m_planeCount; ++i) {
66 if (m_planes[i].fd >= 0)
67 ::close(m_planes[i].fd);
68 }
69}
70
72{
74
75 if (rhi.backend() != QRhi::OpenGLES2)
76 return {};
77
78#if QT_CONFIG(opengl) && QT_CONFIG(egl)
79 // DmaBufEglContext is bound to the GL context associated with a QRhi;
80 // textures are (re-)imported on the RHI render thread, so this is
81 // created lazily here (rather than in the constructor, which may run on
82 // a different thread) and cached per-rhi.
84 return DmaBufEglContext(&rhi);
85 });
86
87 if (!eglContext.isValid()) {
88 qCDebug(qLcDmaBufVideoBuffer) << "DmaBufEglContext is not valid, falling back to CPU path";
89 return {};
90 }
91
94 if (!handles) {
97 << "Unrecoverable EGL import failure, disabling texture import for this buffer";
99 }
100 return {};
101 }
102
104 m_size);
105#else // QT_CONFIG(opengl) && QT_CONFIG(egl)
107 << "DMABUF texture import is not supported in this build, falling back to CPU path";
108 return {};
109#endif // QT_CONFIG(opengl) && QT_CONFIG(egl)
110}
111
113{
115
116 // The producer (driver/compositor) owns write access to the DMABUF.
118 return mapData;
119
121 if (!desc)
122 return mapData;
123
124 QVarLengthArray<std::pair<int, std::pair<void *, size_t>>, 4> mappedByFd;
125
126 for (int i = 0; i < m_planeCount; ++i) {
127 const DmaBufPlane &plane = m_planes[i];
128
129 void *base = nullptr;
130 for (const auto &entry : mappedByFd) {
131 if (entry.first == plane.fd) {
133 break;
134 }
135 }
136
137 if (!base) {
138 // Determine the size of the DMABUF via lseek (dma-buf file
139 // objects implement llseek to report their size), then mmap it
140 // read-only in one go; individual planes just index into this
141 // mapping via their offset.
142 const off_t len = ::lseek(plane.fd, 0, SEEK_END);
143 if (len <= 0) {
144 qCWarning(qLcDmaBufVideoBuffer) << "Could not determine DMABUF size for plane" << i;
145 for (const auto &entry : mappedByFd)
147 return {};
148 }
149
150 void *mapped = ::mmap(nullptr, size_t(len), PROT_READ, MAP_SHARED, plane.fd, 0);
151 if (mapped == MAP_FAILED) {
153 << "mmap failed for plane" << i << ':' << qt_error_string(errno);
154 for (const auto &entry : mappedByFd)
156 return {};
157 }
158
160 base = mapped;
161 }
162
163 mapData.data[i] = static_cast<uchar *>(base) + plane.offset;
166 }
167
169
171 for (const auto &entry : mappedByFd)
173
174 m_mapMode = mode;
175 return mapData;
176}
177
179{
180 for (const auto &region : m_mappedRegions)
183
185}
186
187} // namespace QtMultimediaPrivate
188
189QT_END_NAMESPACE
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define MAP_FAILED