From 5f3f95c67d86cf82ae32d6821b283724eba8b293 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Tue, 23 Jun 2026 21:12:55 +0200 Subject: Implement GEM objects and dumb buffers --- src/gem.cpp | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/gem.cpp (limited to 'src') diff --git a/src/gem.cpp b/src/gem.cpp new file mode 100644 index 0000000..4b81703 --- /dev/null +++ b/src/gem.cpp @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: MIT */ + +#include "drm++/gem.hpp" +#include "drm++/helper.hpp" +#include "drm++/ioctl.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace drm; +using namespace drm::gem; + +/* GEM object class */ + +Object::Object(int fd, int dmabuf_fd, bool close) : m_fd(fd) { + try { + drm_prime_handle args{ + .fd = dmabuf_fd + }; + ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, args); + + this->m_handle = args.handle; + } catch (...) { + if (close) { + ::close(dmabuf_fd); + } + + throw; + } + + if (close) { + ::close(dmabuf_fd); + } +} + +int Object::exportFd(ExportFlags flags) const { + drm_prime_handle args{ + .handle = this->m_handle, + .flags = static_cast(flags) + }; + ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, args); + + return args.fd; +} + +void Object::changeHandle(u32 handle) { + drm_gem_close args{ + .handle = this->m_handle + }; + ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + + this->m_handle = handle; +} + +void Object::destruct() noexcept { + if (this->m_fd < 0) { + return; + } + + drm_gem_close args{ + .handle = this->m_handle + }; + try { + ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + } catch(...) { + (void) 0; // not much we can do about the leak + } + + this->m_fd = -1; +} + +/* Dumb buffer class */ + +DumbBuffer::DumbBuffer(int fd, u32 width, u32 height, u32 bpp) + : Object(fd, -1), m_width(width), m_height(height), m_bpp(bpp) { + drm_mode_create_dumb args{ + .height = height, + .width = width, + .bpp = bpp + }; + ioctl::perform(this->m_fd, DRM_IOCTL_MODE_CREATE_DUMB, args); + + this->m_handle = args.handle; + this->m_pitch = args.pitch; + this->m_size = args.size; +} + +void* DumbBuffer::map() { + if (this->m_map != nullptr) { + return this->m_map; + } + + drm_mode_map_dumb args{ + .handle = this->m_handle + }; + ioctl::perform(this->m_fd, DRM_IOCTL_MODE_MAP_DUMB, args); + + void* map{::mmap(nullptr, this->m_size, PROT_READ | PROT_WRITE, MAP_SHARED, + this->m_fd, static_cast(args.offset))}; + if (map == MAP_FAILED) { + throw std::system_error(errno, std::generic_category(), "mmap failed"); + } + + this->m_map = map; + return this->m_map; +} + +void DumbBuffer::destruct() noexcept { + if (this->m_fd < 0) { + return; + } + + if (this->m_map != nullptr) { + ::munmap(this->m_map, this->m_size); + this->m_map = nullptr; + } + + drm_mode_destroy_dumb args{ + .handle = this->m_handle + }; + try { + ioctl::perform(this->m_fd, DRM_IOCTL_MODE_DESTROY_DUMB, args); + } catch(...) { + (void) 0; // not much we can do about the leak + } + + this->m_fd = -1; +} -- cgit v1.3.1