summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPancakeTAS <pancake@mgnet.work>2026-07-03 16:15:45 +0200
committerPancakeTAS <pancake@mgnet.work>2026-07-03 16:30:05 +0200
commit5dea03465384a91466c293e55deabd0817c7e0bd (patch)
tree7e884acb1bba09fc86487f76ea06e7e1c22781cc
parentImplement version ioctl and expand comments (diff)
Implement framebuffer object
Diffstat (limited to '')
-rw-r--r--.clang-tidy1
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/drm++/mode/framebuffer.hpp105
-rw-r--r--src/mode/framebuffer.cpp70
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;
+}