From e97d9eb1751623e5434aac08a5746350be2a7341 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Thu, 25 Jun 2026 11:13:16 +0200 Subject: Bug fixes all across the project --- src/gem.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 19 deletions(-) (limited to 'src/gem.cpp') diff --git a/src/gem.cpp b/src/gem.cpp index 0572c3b..b6b3d38 100644 --- a/src/gem.cpp +++ b/src/gem.cpp @@ -4,8 +4,11 @@ #include "drm++/helper.hpp" #include "drm++/ioctl.hpp" +#include #include +#include #include +#include #include #include @@ -18,14 +21,15 @@ using namespace drm::gem; /* GEM object class */ -Object::Object(int fd, int dmabuf_fd, bool close) : m_fd(fd) { +Object::Object(ObjectManager& manager, int dmabuf_fd, bool close) : m_manager(&manager) { try { drm_prime_handle args{ .fd = dmabuf_fd }; - ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, args); this->m_handle = args.handle; + this->m_manager->m_refcounts[this->m_handle]++; } catch (...) { if (close) { ::close(dmabuf_fd); @@ -44,22 +48,36 @@ int Object::exportFd(ExportFlags flags) const { .handle = this->m_handle, .flags = static_cast(flags) }; - ioctl::perform(this->m_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, args); + ioctl::perform(this->m_manager->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 + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[handle] > 0 || refcounts[this->m_handle] > 1) { + throw std::logic_error("GEM handle is still in use"); + } + + drm_gem_change_handle args{ + .handle = this->m_handle, + .new_handle = handle }; - ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_GEM_CHANGE_HANDLE, args); + std::exchange(refcounts[handle], refcounts[this->m_handle]); this->m_handle = handle; } void Object::destruct() noexcept { - if (this->m_fd < 0) { + if (this->m_manager == nullptr) { + return; + } + + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[this->m_handle] > 1) { + refcounts[this->m_handle]--; + this->m_manager = nullptr; return; } @@ -67,26 +85,28 @@ void Object::destruct() noexcept { .handle = this->m_handle }; try { - ioctl::perform(this->m_fd, DRM_IOCTL_GEM_CLOSE, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_GEM_CLOSE, args); } catch(...) { - (void) 0; // not much we can do about the leak + assert(false && "GEM close failed, memory leak likely"); } - this->m_fd = -1; + this->m_manager = nullptr; } /* Dumb buffer class */ -DumbBuffer::DumbBuffer(int fd, u32 width, u32 height, u32 bpp) - : Object(fd), m_width(width), m_height(height), m_bpp(bpp) { +DumbBuffer::DumbBuffer(ObjectManager& manager, u32 width, u32 height, u32 bpp) + : Object(manager), 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); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_MODE_CREATE_DUMB, args); this->m_handle = args.handle; + this->m_manager->m_refcounts[this->m_handle]++; + this->m_pitch = args.pitch; this->m_size = args.size; } @@ -99,10 +119,10 @@ void* DumbBuffer::map() { drm_mode_map_dumb args{ .handle = this->m_handle }; - ioctl::perform(this->m_fd, DRM_IOCTL_MODE_MAP_DUMB, args); + ioctl::perform(this->m_manager->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))}; + this->m_manager->m_fd, static_cast(args.offset))}; if (map == MAP_FAILED) { throw std::system_error(errno, std::generic_category(), "mmap failed"); } @@ -112,7 +132,14 @@ void* DumbBuffer::map() { } void DumbBuffer::destruct() noexcept { - if (this->m_fd < 0) { + if (this->m_manager == nullptr) { + return; + } + + auto& refcounts{this->m_manager->m_refcounts}; + if (refcounts[this->m_handle] > 1) { + refcounts[this->m_handle]--; + this->m_manager = nullptr; return; } @@ -125,10 +152,10 @@ void DumbBuffer::destruct() noexcept { .handle = this->m_handle }; try { - ioctl::perform(this->m_fd, DRM_IOCTL_MODE_DESTROY_DUMB, args); + ioctl::perform(this->m_manager->m_fd, DRM_IOCTL_MODE_DESTROY_DUMB, args); } catch(...) { - (void) 0; // not much we can do about the leak + assert(false && "Dumb buffer destroy failed, memory leak likely"); } - this->m_fd = -1; + this->m_manager = nullptr; } -- cgit v1.3.1