Merge pull request #26166 from ksooo/improve-plugin-ctx-menus
[xbmc.git] / xbmc / utils / UDMABufferObject.cpp
blob2b8336bcea9c8c4b50895d7bc7233c2fe728af38
1 /*
2 * Copyright (C) 2005-2020 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "UDMABufferObject.h"
11 #include "utils/BufferObjectFactory.h"
12 #include "utils/log.h"
14 #include <drm_fourcc.h>
15 #include <fcntl.h>
16 #include <linux/udmabuf.h>
17 #include <sys/ioctl.h>
18 #include <sys/mman.h>
19 #include <unistd.h>
21 #include "PlatformDefs.h"
23 namespace
26 const auto PAGESIZE = getpagesize();
28 int RoundUp(int num, int factor)
30 return num + factor - 1 - (num - 1) % factor;
33 } // namespace
35 std::unique_ptr<CBufferObject> CUDMABufferObject::Create()
37 return std::make_unique<CUDMABufferObject>();
40 void CUDMABufferObject::Register()
42 int fd = open("/dev/udmabuf", O_RDWR);
43 if (fd < 0)
45 CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__,
46 strerror(errno));
47 return;
50 close(fd);
52 CBufferObjectFactory::RegisterBufferObject(CUDMABufferObject::Create);
55 CUDMABufferObject::~CUDMABufferObject()
57 ReleaseMemory();
58 DestroyBufferObject();
60 int ret = close(m_udmafd);
61 if (ret < 0)
62 CLog::Log(LOGERROR, "CUDMABufferObject::{} - close /dev/udmabuf failed, errno={}", __FUNCTION__,
63 strerror(errno));
65 m_udmafd = -1;
68 bool CUDMABufferObject::CreateBufferObject(uint32_t format, uint32_t width, uint32_t height)
70 if (m_fd >= 0)
71 return true;
73 uint32_t bpp{1};
75 switch (format)
77 case DRM_FORMAT_ARGB8888:
78 bpp = 4;
79 break;
80 case DRM_FORMAT_ARGB1555:
81 case DRM_FORMAT_RGB565:
82 bpp = 2;
83 break;
84 default:
85 throw std::runtime_error("CUDMABufferObject: pixel format not implemented");
88 m_stride = width * bpp;
90 return CreateBufferObject(width * height * bpp);
93 bool CUDMABufferObject::CreateBufferObject(uint64_t size)
95 // Must be rounded to the system page size
96 m_size = RoundUp(size, PAGESIZE);
98 m_memfd = memfd_create("kodi", MFD_CLOEXEC | MFD_ALLOW_SEALING);
99 if (m_memfd < 0)
101 CLog::Log(LOGERROR, "CUDMABufferObject::{} - memfd_create failed: {}", __FUNCTION__,
102 strerror(errno));
103 return false;
106 if (ftruncate(m_memfd, m_size) < 0)
108 CLog::Log(LOGERROR, "CUDMABufferObject::{} - ftruncate failed: {}", __FUNCTION__,
109 strerror(errno));
110 return false;
113 if (fcntl(m_memfd, F_ADD_SEALS, F_SEAL_SHRINK) < 0)
115 CLog::Log(LOGERROR, "CUDMABufferObject::{} - fcntl failed: {}", __FUNCTION__, strerror(errno));
116 close(m_memfd);
117 return false;
120 if (m_udmafd < 0)
122 m_udmafd = open("/dev/udmabuf", O_RDWR);
123 if (m_udmafd < 0)
125 CLog::Log(LOGERROR, "CUDMABufferObject::{} - unable to open /dev/udmabuf: {}", __FUNCTION__,
126 strerror(errno));
127 close(m_memfd);
128 return false;
132 struct udmabuf_create_item create{};
133 create.memfd = static_cast<uint32_t>(m_memfd);
134 create.offset = 0;
135 create.size = m_size;
137 m_fd = ioctl(m_udmafd, UDMABUF_CREATE, &create);
138 if (m_fd < 0)
140 CLog::Log(LOGERROR, "CUDMABufferObject::{} - ioctl UDMABUF_CREATE failed: {}", __FUNCTION__,
141 strerror(errno));
142 close(m_memfd);
143 return false;
146 return true;
149 void CUDMABufferObject::DestroyBufferObject()
151 if (m_fd < 0)
152 return;
154 int ret = close(m_fd);
155 if (ret < 0)
156 CLog::Log(LOGERROR, "CUDMABufferObject::{} - close fd failed, errno={}", __FUNCTION__,
157 strerror(errno));
159 ret = close(m_memfd);
160 if (ret < 0)
161 CLog::Log(LOGERROR, "CUDMABufferObject::{} - close memfd failed, errno={}", __FUNCTION__,
162 strerror(errno));
164 m_memfd = -1;
165 m_fd = -1;
166 m_stride = 0;
167 m_size = 0;
170 uint8_t* CUDMABufferObject::GetMemory()
172 if (m_fd < 0)
173 return nullptr;
175 if (m_map)
177 CLog::Log(LOGDEBUG, "CUDMABufferObject::{} - already mapped fd={} map={}", __FUNCTION__, m_fd,
178 fmt::ptr(m_map));
179 return m_map;
182 m_map = static_cast<uint8_t*>(mmap(nullptr, m_size, PROT_WRITE, MAP_SHARED, m_memfd, 0));
183 if (m_map == MAP_FAILED)
185 CLog::Log(LOGERROR, "CUDMABufferObject::{} - mmap failed, errno={}", __FUNCTION__,
186 strerror(errno));
187 return nullptr;
190 return m_map;
193 void CUDMABufferObject::ReleaseMemory()
195 if (!m_map)
196 return;
198 int ret = munmap(m_map, m_size);
199 if (ret < 0)
200 CLog::Log(LOGERROR, "CUDMABufferObject::{} - munmap failed, errno={}", __FUNCTION__,
201 strerror(errno));
203 m_map = nullptr;