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
qdmabufallocator.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/qmultimediautils_p.h>
7#include <QtMultimedia/private/qtmm_alignment_support_p.h>
8#include <QtCore/private/qcore_unix_p.h>
9
10#include <fcntl.h>
11#include <sys/mman.h>
12#include <unistd.h>
13
14#include <cerrno>
15
16#if __has_include(<linux/dma-heap.h>)
17# include <linux/dma-heap.h>
18# define QT_DMABUF_HAS_DMA_HEAP
19#endif
20#if __has_include(<linux/udmabuf.h>)
21# include <linux/udmabuf.h>
22# define QT_DMABUF_HAS_UDMABUF
23#endif
24
25QT_BEGIN_NAMESPACE
26
27using namespace Qt::StringLiterals;
28
29namespace QtMultimediaPrivate {
30
31namespace {
32
33#ifdef QT_DMABUF_HAS_DMA_HEAP
34constexpr auto kDmaHeapPaths = std::initializer_list<const char *>{
35 "/dev/dma_heap/linux,cma",
36 "/dev/dma_heap/reserved",
37 "/dev/dma_heap/system",
38};
39#endif
40
41q23::expected<QUniqueFileDescriptorHandle, QString>
42allocFromDmaHeap([[maybe_unused]] int heapFd, [[maybe_unused]] qsizetype size)
43{
44#ifdef QT_DMABUF_HAS_DMA_HEAP
45 dma_heap_allocation_data alloc{
46 .len = __u64(size),
47 .fd = 0,
48 .fd_flags = O_CLOEXEC | O_RDWR,
49 .heap_flags = 0,
50 };
51
52 if (qt_safe_ioctl(heapFd, DMA_HEAP_IOCTL_ALLOC, &alloc) < 0) {
53 const int error = errno;
54 return q23::unexpected(u"DMA heap allocation failed: %1"_s.arg(qt_error_string(error)));
55 }
56
57 return QUniqueFileDescriptorHandle{ int(alloc.fd) };
58#else
59 return q23::unexpected(u"dma-heap is not supported by the kernel headers"_s);
60#endif
61}
62
63q23::expected<QUniqueFileDescriptorHandle, QString>
64allocFromUDmaBuf([[maybe_unused]] int udmabufFd, [[maybe_unused]] qsizetype size)
65{
66#ifdef QT_DMABUF_HAS_UDMABUF
67 QUniqueFileDescriptorHandle memfd{ memfd_create("qt-dmabuf", MFD_CLOEXEC | MFD_ALLOW_SEALING) };
68 if (!memfd.isValid()) {
69 const int error = errno;
70 return q23::unexpected(u"memfd_create failed: %1"_s.arg(qt_error_string(error)));
71 }
72
73 if (ftruncate(memfd.get(), size) < 0) {
74 const int error = errno;
75 return q23::unexpected(u"ftruncate failed: %1"_s.arg(qt_error_string(error)));
76 }
77
78 // udmabuf requires the memfd to be sealed against shrinking.
79 if (fcntl(memfd.get(), F_ADD_SEALS, F_SEAL_SHRINK) < 0) {
80 const int error = errno;
81 return q23::unexpected(u"sealing memfd failed: %1"_s.arg(qt_error_string(error)));
82 }
83
84 udmabuf_create create{
85 .memfd = __u32(memfd.get()),
86 .flags = UDMABUF_FLAGS_CLOEXEC,
87 .offset = 0,
88 .size = __u64(size),
89 };
90
91 // The kernel keeps its own reference to the memfd, so it may be closed afterwards.
92 QUniqueFileDescriptorHandle buffer{ qt_safe_ioctl(udmabufFd, UDMABUF_CREATE, &create) };
93 if (!buffer.isValid()) {
94 const int error = errno;
95 return q23::unexpected(u"UDMABUF_CREATE failed: %1"_s.arg(qt_error_string(error)));
96 }
97
98 return buffer;
99#else
100 return q23::unexpected(u"udmabuf is not supported by the kernel headers"_s);
101#endif
102}
103
104} // namespace
105
109
112{
113}
114
116{
117#ifdef QT_DMABUF_HAS_DMA_HEAP
118 for (const char *path : kDmaHeapPaths) {
119 QUniqueFileDescriptorHandle fd{ qt_safe_open(path, O_RDONLY | O_CLOEXEC) };
120 if (fd.isValid())
122 }
123#endif
124
125#ifdef QT_DMABUF_HAS_UDMABUF
126 QUniqueFileDescriptorHandle fd{ qt_safe_open("/dev/udmabuf", O_RDWR | O_CLOEXEC) };
127 if (fd.isValid())
129#endif
130
131 return q23::unexpected(u"no DMA-BUF provider (dma-heap or udmabuf) is accessible"_s);
132}
133
146
147} // namespace QtMultimediaPrivate
148
149QT_END_NAMESPACE
#define __has_include(x)