diff options
Diffstat (limited to '')
-rw-r--r-- | xbmc/utils/UDMABufferObject.cpp | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/xbmc/utils/UDMABufferObject.cpp b/xbmc/utils/UDMABufferObject.cpp new file mode 100644 index 0000000..2b8336b --- /dev/null +++ b/xbmc/utils/UDMABufferObject.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "UDMABufferObject.h" + +#include "utils/BufferObjectFactory.h" +#include "utils/log.h" + +#include <drm_fourcc.h> +#include <fcntl.h> +#include <linux/udmabuf.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> + +#include "PlatformDefs.h" + +namespace +{ + +const auto PAGESIZE = getpagesize(); + +int RoundUp(int num, int factor) +{ + return num + factor - 1 - (num - 1) % factor; +} + +} // namespace + +std::unique_ptr<CBufferObject> CUDMABufferObject::Create() +{ + return std::make_unique<CUDMABufferObject>(); +} + +void CUDMABufferObject::Register() +{ + int fd = open("/dev/udmabuf", O_RDWR); + if (fd < 0) + { + CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__, + strerror(errno)); + return; + } + + close(fd); + + CBufferObjectFactory::RegisterBufferObject(CUDMABufferObject::Create); +} + +CUDMABufferObject::~CUDMABufferObject() +{ + ReleaseMemory(); + DestroyBufferObject(); + + int ret = close(m_udmafd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close /dev/udmabuf failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_udmafd = -1; +} + +bool CUDMABufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height) +{ + if (m_fd >= 0) + return true; + + uint32_t bpp{1}; + + switch (format) + { + case DRM_FORMAT_ARGB8888: + bpp = 4; + break; + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_RGB565: + bpp = 2; + break; + default: + throw std::runtime_error("CUDMABufferObject: pixel format not implemented"); + } + + m_stride = width * bpp; + + return CreateBufferObject(width * height * bpp); +} + +bool CUDMABufferObject::CreateBufferObject(uint64_t size) +{ + // Must be rounded to the system page size + m_size = RoundUp(size, PAGESIZE); + + m_memfd = memfd_create("kodi", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (m_memfd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - memfd_create failed: {}", __FUNCTION__, + strerror(errno)); + return false; + } + + if (ftruncate(m_memfd, m_size) < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - ftruncate failed: {}", __FUNCTION__, + strerror(errno)); + return false; + } + + if (fcntl(m_memfd, F_ADD_SEALS, F_SEAL_SHRINK) < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - fcntl failed: {}", __FUNCTION__, strerror(errno)); + close(m_memfd); + return false; + } + + if (m_udmafd < 0) + { + m_udmafd = open("/dev/udmabuf", O_RDWR); + if (m_udmafd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__, + strerror(errno)); + close(m_memfd); + return false; + } + } + + struct udmabuf_create_item create{}; + create.memfd = static_cast<uint32_t>(m_memfd); + create.offset = 0; + create.size = m_size; + + m_fd = ioctl(m_udmafd, UDMABUF_CREATE, &create); + if (m_fd < 0) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - ioctl UDMABUF_CREATE failed: {}", __FUNCTION__, + strerror(errno)); + close(m_memfd); + return false; + } + + return true; +} + +void CUDMABufferObject::DestroyBufferObject() +{ + if (m_fd < 0) + return; + + int ret = close(m_fd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close fd failed, errno={}", __FUNCTION__, + strerror(errno)); + + ret = close(m_memfd); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - close memfd failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_memfd = -1; + m_fd = -1; + m_stride = 0; + m_size = 0; +} + +uint8_t* CUDMABufferObject::GetMemory() +{ + if (m_fd < 0) + return nullptr; + + if (m_map) + { + CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - already mapped fd={} map={}", __FUNCTION__, m_fd, + fmt::ptr(m_map)); + return m_map; + } + + m_map = static_cast<uint8_t*>(mmap(nullptr, m_size, PROT_WRITE, MAP_SHARED, m_memfd, 0)); + if (m_map == MAP_FAILED) + { + CLog::Log(LOGERROR, "CUDMABufferObject::{} - mmap failed, errno={}", __FUNCTION__, + strerror(errno)); + return nullptr; + } + + return m_map; +} + +void CUDMABufferObject::ReleaseMemory() +{ + if (!m_map) + return; + + int ret = munmap(m_map, m_size); + if (ret < 0) + CLog::Log(LOGERROR, "CUDMABufferObject::{} - munmap failed, errno={}", __FUNCTION__, + strerror(errno)); + + m_map = nullptr; +} |