summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gem.cpp134
1 files changed, 134 insertions, 0 deletions
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 <cerrno>
+#include <system_error>
+
+#include <drm.h>
+#include <drm_mode.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+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<u32>(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<off_t>(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;
+}