diff options
Diffstat (limited to 'src/gem.cpp')
| -rw-r--r-- | src/gem.cpp | 134 |
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; +} |
