summaryrefslogtreecommitdiff
path: root/src/gem.cpp
diff options
context:
space:
mode:
authorPancakeTAS <pancake@mgnet.work>2026-06-25 11:13:16 +0200
committerPancakeTAS <pancake@mgnet.work>2026-06-25 11:13:33 +0200
commite97d9eb1751623e5434aac08a5746350be2a7341 (patch)
tree6b0453025be1add7158c6341c3ff2ce082ef4363 /src/gem.cpp
parentLarge documentation overhaul & main DRM device (diff)
Bug fixes all across the project
Diffstat (limited to '')
-rw-r--r--src/gem.cpp65
1 files changed, 46 insertions, 19 deletions
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 <cassert>
#include <cerrno>
+#include <stdexcept>
#include <system_error>
+#include <utility>
#include <drm.h>
#include <drm_mode.h>
@@ -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<u32>(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<off_t>(args.offset))};
+ this->m_manager->m_fd, static_cast<off_t>(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;
}