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#include <cerrno>
12#include <cstring>
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/mman.h>
16
17static_assert(QT_CONFIG(linux_dmabuf));
18
20
21Q_STATIC_LOGGING_CATEGORY(qLcDmaBufVideoBuffer, "qt.multimedia.dmabufvideobuffer");
22
23namespace QtMultimediaPrivate {
24
26
32 m_size(size),
33 m_planeCount(std::clamp(0, int(planes.size()), 4)),
35{
36 Q_ASSERT(!planes.empty() && planes.size() <= 4);
37
38 for (int i = 0; i < m_planeCount; ++i) {
39 m_planes[i] = planes[i];
40
41 // Take our own, independent reference: the producer may close its
42 // fd at any point while this buffer is still alive.
43 if (m_planes[i].fd >= 0) {
44 const int dupped = ::fcntl(m_planes[i].fd, F_DUPFD_CLOEXEC, 0);
45 if (dupped < 0) {
47 << "Failed to dup DMABUF fd for plane" << i << ':' << strerror(errno);
48 m_planes[i].fd = -1;
49 } else {
51 }
52 }
53 }
54}
55
57{
59
60 for (int i = 0; i < m_planeCount; ++i) {
61 if (m_planes[i].fd >= 0)
62 ::close(m_planes[i].fd);
63 }
64}
65
68{
71
72 if (rhi.backend() != QRhi::OpenGLES2)
73 return {};
74
75 // DmaBufEglContext is bound to the GL context associated with a QRhi;
76 // textures are (re-)imported on the RHI render thread, so this is
77 // created lazily here (rather than in the constructor, which may run on
78 // a different thread) and cached per-rhi.
80 return DmaBufEglContext(&rhi);
81 });
82
83 if (!eglContext.isValid()) {
84 qCDebug(qLcDmaBufVideoBuffer) << "DmaBufEglContext is not valid, falling back to CPU path";
85 return {};
86 }
87
90 if (!handles) {
93 << "Unrecoverable EGL import failure, disabling texture import for this buffer";
95 }
96 return {};
97 }
98
100 m_size);
101}
102
104{
106
107 // The producer (driver/compositor) owns write access to the DMABUF.
109 return mapData;
110
112 if (!desc)
113 return mapData;
114
115 QVarLengthArray<std::pair<int, std::pair<void *, size_t>>, 4> mappedByFd;
116
117 for (int i = 0; i < m_planeCount; ++i) {
118 const DmaBufPlane &plane = m_planes[i];
119
120 void *base = nullptr;
121 for (const auto &entry : mappedByFd) {
122 if (entry.first == plane.fd) {
124 break;
125 }
126 }
127
128 if (!base) {
129 // Determine the size of the DMABUF via lseek (dma-buf file
130 // objects implement llseek to report their size), then mmap it
131 // read-only in one go; individual planes just index into this
132 // mapping via their offset.
133 const off_t len = ::lseek(plane.fd, 0, SEEK_END);
134 if (len <= 0) {
135 qCWarning(qLcDmaBufVideoBuffer) << "Could not determine DMABUF size for plane" << i;
136 for (const auto &entry : mappedByFd)
138 return {};
139 }
140
141 void *mapped = ::mmap(nullptr, size_t(len), PROT_READ, MAP_SHARED, plane.fd, 0);
142 if (mapped == MAP_FAILED) {
144 << "mmap failed for plane" << i << ':' << strerror(errno);
145 for (const auto &entry : mappedByFd)
147 return {};
148 }
149
151 base = mapped;
152 }
153
154 mapData.data[i] = static_cast<uchar *>(base) + plane.offset;
157 }
158
160
162 for (const auto &entry : mappedByFd)
164
165 m_mapMode = mode;
166 return mapData;
167}
168
170{
171 for (const auto &region : m_mappedRegions)
174
176}
177
178} // namespace QtMultimediaPrivate
179
180QT_END_NAMESPACE
static QRhiValueMapper< DmaBufEglContext > g_eglContexts
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
#define MAP_FAILED