diff options
| author | PancakeTAS <pancake@mgnet.work> | 2026-07-03 16:15:45 +0200 |
|---|---|---|
| committer | PancakeTAS <pancake@mgnet.work> | 2026-07-03 16:30:05 +0200 |
| commit | 5dea03465384a91466c293e55deabd0817c7e0bd (patch) | |
| tree | 7e884acb1bba09fc86487f76ea06e7e1c22781cc | |
| parent | Implement version ioctl and expand comments (diff) | |
Implement framebuffer object
| -rw-r--r-- | .clang-tidy | 1 | ||||
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | include/drm++/mode/framebuffer.hpp | 105 | ||||
| -rw-r--r-- | src/mode/framebuffer.cpp | 70 |
4 files changed, 177 insertions, 0 deletions
diff --git a/.clang-tidy b/.clang-tidy index 8044098..d016a19 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -24,6 +24,7 @@ Checks: - -bugprone-easily-swappable-parameters - -portability-avoid-pragma-once # Various checks that interfere with C-to-C++ style code are disabled +- -cppcoreguidelines-pro-bounds-constant-array-index - -cppcoreguidelines-pro-bounds-pointer-arithmetic - -cppcoreguidelines-pro-type-reinterpret-cast - -cppcoreguidelines-pro-type-vararg diff --git a/CMakeLists.txt b/CMakeLists.txt index 52e6ceb..e12ed45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ include(cmake/Diagnostics.cmake) add_library(drm++ SHARED "src/helper/ioctl.cpp" + "src/mode/framebuffer.cpp" "src/drm.cpp" "src/gem.cpp" "src/syncobject.cpp") diff --git a/include/drm++/mode/framebuffer.hpp b/include/drm++/mode/framebuffer.hpp new file mode 100644 index 0000000..fd904f2 --- /dev/null +++ b/include/drm++/mode/framebuffer.hpp @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: MIT */ + +#pragma once + +/// +/// * Framebuffers +/// +/// ... +/// + + +#include "../gem.hpp" +#include "../helper/macros.hpp" +#include "../helper/types.hpp" + +#include <optional> +#include <utility> +#include <vector> + +namespace drm::mode { + +/// +/// Framebuffer wrapping GEM objects. +/// +/// @throws drm::ioctl::Exception on failure +/// +class Framebuffer { +public: + /// + /// Create a new framebuffer. + /// Requires DRM_CAP_ADDFB2_MODIFIERS when modifier is specified. + /// + /// Up to 4 planes can be specified for multi-planar formats. + /// + /// @param alignments Offset and pitch for each plane + /// @throws std::invalid_argument if planes or alignments are invalid + /// + Framebuffer( + int fd, + u32 width, + u32 height, + u32 format, + std::vector<ref<const gem::Object>> planes, + std::vector<std::pair<u32, u32>> alignments, + std::optional<u64> modifier, + bool interlaced = false + ); + + // Private access + GETTER(handle) + GETTER(width) + GETTER(height) + GETTER(format) + GETTER(alignments) + GETTER(modifier) + GETTER(interlaced) + + // Move constructor/operator + Framebuffer(Framebuffer&& other) noexcept : + m_fd(other.m_fd), m_handle(other.m_handle), + m_width(other.m_width), m_height(other.m_height), + m_format(other.m_format), m_alignments(std::move(other.m_alignments)), + m_modifier(other.m_modifier), m_interlaced(other.m_interlaced) { + other.m_fd = -1; // invalidate other + } + + Framebuffer& operator=(Framebuffer&& other) noexcept { + if (this != &other) { + this->destruct(); + this->m_fd = other.m_fd; + this->m_handle = other.m_handle; + this->m_width = other.m_width; + this->m_height = other.m_height; + this->m_format = other.m_format; + this->m_alignments = std::move(other.m_alignments); + this->m_modifier = other.m_modifier; + this->m_interlaced = other.m_interlaced; + other.m_fd = -1; // invalidate other + } + + return *this; + } + + // Copy constructor/operator + NO_COPY(Framebuffer) + + // Destructor + ~Framebuffer() noexcept { + this->destruct(); + } +private: + int m_fd; // indicates validity (>= 0) + u32 m_handle; + + u32 m_width; + u32 m_height; + u32 m_format; + std::vector<std::pair<u32, u32>> m_alignments; + std::optional<u64> m_modifier; + bool m_interlaced; + + void destruct() noexcept; +}; + +} diff --git a/src/mode/framebuffer.cpp b/src/mode/framebuffer.cpp new file mode 100644 index 0000000..46b98d1 --- /dev/null +++ b/src/mode/framebuffer.cpp @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: MIT */ + +#include "drm++/mode/framebuffer.hpp" +#include "drm++/gem.hpp" +#include "drm++/helper/ioctl.hpp" +#include "drm++/helper/types.hpp" + +#include <cassert> +#include <cstddef> +#include <optional> +#include <stdexcept> +#include <utility> +#include <vector> + +#include <drm.h> +#include <drm_mode.h> + +using namespace drm; +using namespace drm::mode; + +Framebuffer::Framebuffer( + int fd, + u32 width, + u32 height, + u32 format, + std::vector<ref<const gem::Object>> planes, + std::vector<std::pair<u32, u32>> alignments, + std::optional<u64> modifier, + bool interlaced) : m_fd(fd), + m_width(width), m_height(height), m_format(format), + m_alignments(alignments), m_modifier(modifier), m_interlaced(interlaced +) { + if (planes.empty() || planes.size() > 4 || planes.size() != alignments.size()) { + throw std::invalid_argument("invalid number of planes"); + } + + drm_mode_fb_cmd2 args{ + .width = width, + .height = height, + .pixel_format = format, + .flags = (modifier.has_value() ? DRM_MODE_FB_MODIFIERS : 0U) + | (interlaced ? DRM_MODE_FB_INTERLACED : 0U) + }; + for (size_t i = 0; i < planes.size(); ++i) { + args.handles[i] = planes.at(i).get().handle(); + args.offsets[i] = alignments.at(i).first; + args.pitches[i] = alignments.at(i).second; + args.modifier[i] = modifier.value_or(0); + } + ioctl::perform(this->m_fd, DRM_IOCTL_MODE_ADDFB2, args); + + this->m_handle = args.fb_id; +} + +void Framebuffer::destruct() noexcept { + if (this->m_fd < 0) { + return; + } + + drm_mode_fb_cmd2 args{ + .fb_id = this->m_handle + }; + try { + ioctl::perform(this->m_fd, DRM_IOCTL_MODE_CLOSEFB, args); + } catch (...) { + assert(false && "Framebuffer close failed, memory leak likely"); + } + + this->m_fd = -1; +} |
