summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorPancakeTAS <pancake@mgnet.work>2026-06-23 21:12:55 +0200
committerPancakeTAS <pancake@mgnet.work>2026-06-23 21:24:11 +0200
commit5f3f95c67d86cf82ae32d6821b283724eba8b293 (patch)
treec4b48c98bbef45512712059af966b79ae2bd1c2e /include
parentSignificantly reduce line count and code duplication (diff)
Implement GEM objects and dumb buffers
Diffstat (limited to 'include')
-rw-r--r--include/drm++/gem.hpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/include/drm++/gem.hpp b/include/drm++/gem.hpp
new file mode 100644
index 0000000..1dfe1ba
--- /dev/null
+++ b/include/drm++/gem.hpp
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: MIT */
+
+#pragma once
+
+#include "drm++/helper.hpp"
+
+namespace drm::gem {
+
+/// A GEM object wrapping memory.
+/// @throws drm::ioctl::Exception on failure
+class Object {
+ friend class DumbBuffer;
+public:
+ /// Import a DMA-BUF file descriptor into a GEM object.
+ /// Requires DRM_PRIME_CAP_IMPORT.
+ ///
+ /// An import can fail for various driver-specific reasons.
+ ///
+ /// @param close Close fd after import (regardless of success)
+ Object(int fd, int dmabuf_fd, bool close = true);
+
+ /// Flags for exporting fds
+ enum class ExportFlags : u32 {
+ None = 0,
+ ReadWrite = 1 << 0, //!< Allow read/write access (drivers may ignore this)
+ CloseOnExec = 1 << 1, //!< Close fd on execve()
+ };
+
+ /// Obtain a DMA-BUF file descriptor for the GEM object, incrementing the reference count.
+ /// Requires DRM_PRIME_CAP_EXPORT.
+ ///
+ /// An export can fail for various driver-specific reasons, including lack of support on this
+ /// specific GEM object.
+ ///
+ /// @param flags Flags to set on the exported file descriptor.
+ [[nodiscard]] int exportFd(ExportFlags flags = ExportFlags::None) const;
+
+ /// Change the handle of the GEM object.
+ ///
+ /// SAFETY: This is a dangerous operation, as the previous handle will be invalidated. There is
+ /// no guarantee that importing a DMA-BUF file descriptor will return a new handle, so other
+ /// instances of this class on the same file descriptor may become invalid. Use with caution.
+ ///
+ /// @param handle An unused GEM handle to change into.
+ void changeHandle(u32 handle);
+
+ // Private access
+ GETTER(fd)
+ GETTER(handle)
+
+ // Move constructor/operator
+ Object(Object&& other) noexcept : m_fd(other.m_fd), m_handle(other.m_handle) {
+ other.m_fd = -1; // invalidate other
+ }
+
+ Object& operator=(Object&& other) noexcept {
+ if (this != &other) {
+ this->destruct();
+ this->m_handle = other.m_handle;
+ this->m_fd = other.m_fd;
+ other.m_fd = -1; // invalidate other
+ }
+
+ return *this;
+ }
+
+ // Copy constructor/operator
+ Object(const Object& other) = delete;
+ Object& operator=(const Object& other) = delete;
+
+ // Destructor
+ ~Object() noexcept {
+ this->destruct();
+ }
+
+private:
+ int m_fd; // indicates object validity (>= 0)
+ u32 m_handle;
+
+ void destruct() noexcept;
+};
+
+/// A dumb buffer GEM object.
+/// Requires DRM_CAP_DUMB_BUFFER.
+/// @throws drm::ioctl::Exception on failure
+class DumbBuffer : public Object {
+public:
+ /// Create a new dumb buffer.
+ ///
+ /// The bits per pixel (bpp) also indicates the format and compatible formats
+ /// with similar pixel layouts. All buffers are strictly linear.
+ ///
+ /// +-----+------------------------+------------------------+
+ /// | BPP | Framebuffer format | Compatible formats |
+ /// +=====+========================+========================+
+ /// | 32 | * DRM_FORMAT_XRGB8888 | * DRM_FORMAT_BGRX8888 |
+ /// | | | * DRM_FORMAT_RGBX8888 |
+ /// | | | * DRM_FORMAT_XBGR8888 |
+ /// +-----+------------------------+------------------------+
+ /// | 24 | * DRM_FORMAT_RGB888 | * DRM_FORMAT_BGR888 |
+ /// +-----+------------------------+------------------------+
+ /// | 16 | * DRM_FORMAT_RGB565 | * DRM_FORMAT_BGR565 |
+ /// +-----+------------------------+------------------------+
+ /// | 15 | * DRM_FORMAT_XRGB1555 | * DRM_FORMAT_BGRX1555 |
+ /// | | | * DRM_FORMAT_RGBX1555 |
+ /// | | | * DRM_FORMAT_XBGR1555 |
+ /// ------+------------------------+------------------------+
+ /// | 8 | * DRM_FORMAT_C8 | * DRM_FORMAT_D8 |
+ /// | | | * DRM_FORMAT_R8 |
+ /// +-----+------------------------+------------------------+
+ /// | 4 | * DRM_FORMAT_C4 | * DRM_FORMAT_D4 |
+ /// | | | * DRM_FORMAT_R4 |
+ /// +-----+------------------------+------------------------+
+ /// | 2 | * DRM_FORMAT_C2 | * DRM_FORMAT_D2 |
+ /// | | | * DRM_FORMAT_R2 |
+ /// +-----+------------------------+------------------------+
+ /// | 1 | * DRM_FORMAT_C1 | * DRM_FORMAT_D1 |
+ /// | | | * DRM_FORMAT_R1 |
+ /// +-----+------------------------+------------------------+
+ ///
+ /// Table is not exhaustive, however other bpp values should only be used for legacy purposes.
+ ///
+ /// Support for all bits per pixel is optional and successful creation of a dumb buffer does
+ /// not guarantee that all related formats are compatible.
+ DumbBuffer(int fd, u32 width, u32 height, u32 bpp);
+
+ /// Map the dumb buffer into userspace memory. May be called multiple times,
+ /// will return the same pointer if already mapped.
+ /// @throws std::system_error on mmap failure
+ [[nodiscard]] void* map();
+
+ // Private access
+ GETTER(width)
+ GETTER(height)
+ GETTER(bpp)
+ GETTER(pitch)
+ GETTER(size)
+
+ // Move constructor/operator
+ DumbBuffer(DumbBuffer&& other) noexcept
+ : Object(std::move(other)), // NOLINTBEGIN (use after move)
+ m_width(other.m_width), m_height(other.m_height), m_bpp(other.m_bpp),
+ m_pitch(other.m_pitch), m_size(other.m_size),
+ m_map(other.m_map) {
+ other.m_map = nullptr; // invalidate other
+ } // NOLINTEND
+
+ DumbBuffer& operator=(DumbBuffer&& other) noexcept {
+ if (this != &other) {
+ this->destruct();
+ Object::operator=(std::move(other)); // NOLINTBEGIN (use after move)
+ this->m_width = other.m_width;
+ this->m_height = other.m_height;
+ this->m_bpp = other.m_bpp;
+ this->m_pitch = other.m_pitch;
+ this->m_size = other.m_size;
+ this->m_map = other.m_map;
+ other.m_map = nullptr; // invalidate other
+ } // NOLINTEND
+
+ return *this;
+ }
+
+ // Copy constructor/operator
+ DumbBuffer(const DumbBuffer& other) = delete;
+ DumbBuffer& operator=(const DumbBuffer& other) = delete;
+
+ // Destructor
+ ~DumbBuffer() noexcept {
+ this->destruct();
+ }
+
+private:
+ u32 m_width;
+ u32 m_height;
+ u32 m_bpp;
+ u32 m_pitch;
+ u64 m_size;
+ void* m_map{nullptr}; // indicate mapping validity
+
+ void destruct() noexcept;
+};
+
+}