diff options
Diffstat (limited to '')
| -rw-r--r-- | include/drm++/gem.hpp | 184 |
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; +}; + +} |
