/* 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), 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; }