blob: 6fd5c0c1dcbbf3b124d0685a308349a543d0559e [file] [log] [blame]
Sean Paul6a55e9f2015-04-30 15:31:06 -04001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Sean Paul468a7542024-07-16 19:50:58 +000017#define LOG_TAG "drmhwc"
Sean Paul6a55e9f2015-04-30 15:31:06 -040018
Roman Stratiienko13cc3662020-08-29 21:35:39 +030019#include "DrmDevice.h"
Sean Paul6a55e9f2015-04-30 15:31:06 -040020
Roman Stratiienko2290dc62025-02-09 12:53:35 +020021#include <sys/mman.h>
Sean Paul6a55e9f2015-04-30 15:31:06 -040022#include <xf86drm.h>
23#include <xf86drmMode.h>
24
Roman Stratiienko13cc3662020-08-29 21:35:39 +030025#include <cinttypes>
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +020026#include <cstdint>
Roman Kovalivskyid07c3702019-11-04 17:54:31 +020027#include <string>
28
Roman Stratiienko4e994052022-02-09 17:40:35 +020029#include "drm/DrmAtomicStateManager.h"
Roman Stratiienko24a7fc42021-12-23 16:25:20 +020030#include "drm/DrmPlane.h"
Roman Stratiienko5f21dbc2022-05-03 18:31:13 +030031#include "drm/ResourceManager.h"
Roman Stratiienkod518a052021-02-25 19:15:14 +020032#include "utils/log.h"
33#include "utils/properties.h"
34
Sean Paul6a55e9f2015-04-30 15:31:06 -040035namespace android {
36
Roman Stratiienko5f21dbc2022-05-03 18:31:13 +030037auto DrmDevice::CreateInstance(std::string const &path,
Gil Dekel907a51a2025-02-14 22:44:01 -050038 ResourceManager *res_man, uint32_t index)
Roman Stratiienko5f21dbc2022-05-03 18:31:13 +030039 -> std::unique_ptr<DrmDevice> {
40 if (!IsKMSDev(path.c_str())) {
41 return {};
42 }
43
Gil Dekel907a51a2025-02-14 22:44:01 -050044 auto device = std::unique_ptr<DrmDevice>(new DrmDevice(res_man, index));
Roman Stratiienko5f21dbc2022-05-03 18:31:13 +030045
46 if (device->Init(path.c_str()) != 0) {
47 return {};
48 }
49
50 return device;
51}
52
Gil Dekel907a51a2025-02-14 22:44:01 -050053DrmDevice::DrmDevice(ResourceManager *res_man, uint32_t index)
54 : index_in_dev_array_(index), res_man_(res_man) {
Roman Stratiienko7d899112022-01-31 11:30:27 +020055 drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
Sean Paul047b9b22015-07-28 14:15:42 -040056}
57
Roman Stratiienko3dacd472022-01-11 19:18:34 +020058auto DrmDevice::Init(const char *path) -> int {
Sean Paul6a55e9f2015-04-30 15:31:06 -040059 /* TODO: Use drmOpenControl here instead */
Roman Stratiienko76892782023-01-16 17:15:53 +020060 fd_ = MakeSharedFd(open(path, O_RDWR | O_CLOEXEC));
Roman Stratiienko7d899112022-01-31 11:30:27 +020061 if (!fd_) {
Roman Stratiienko5f2f3ce2021-12-22 11:46:03 +020062 // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
Peter Collingbournec77052e2020-02-19 11:25:08 -080063 ALOGE("Failed to open dri %s: %s", path, strerror(errno));
Roman Stratiienko3dacd472022-01-11 19:18:34 +020064 return -ENODEV;
Sean Paul6a55e9f2015-04-30 15:31:06 -040065 }
66
Roman Stratiienko76892782023-01-16 17:15:53 +020067 int ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
Roman Stratiienko7d899112022-01-31 11:30:27 +020068 if (ret != 0) {
Sean Paul6a55e9f2015-04-30 15:31:06 -040069 ALOGE("Failed to set universal plane cap %d", ret);
Roman Stratiienko3dacd472022-01-11 19:18:34 +020070 return ret;
Sean Paul6a55e9f2015-04-30 15:31:06 -040071 }
72
Roman Stratiienko76892782023-01-16 17:15:53 +020073 ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
Roman Stratiienko7d899112022-01-31 11:30:27 +020074 if (ret != 0) {
Sean Paul6a55e9f2015-04-30 15:31:06 -040075 ALOGE("Failed to set atomic cap %d", ret);
Roman Stratiienko3dacd472022-01-11 19:18:34 +020076 return ret;
Sean Paul6a55e9f2015-04-30 15:31:06 -040077 }
78
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000079#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
Roman Stratiienko76892782023-01-16 17:15:53 +020080 ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
Roman Stratiienko7d899112022-01-31 11:30:27 +020081 if (ret != 0) {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000082 ALOGI("Failed to set writeback cap %d", ret);
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +000083 }
84#endif
85
Roman Stratiienko8666dc92021-02-09 17:49:55 +020086 uint64_t cap_value = 0;
Roman Stratiienko76892782023-01-16 17:15:53 +020087 if (drmGetCap(*GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
Roman Stratiienko8666dc92021-02-09 17:49:55 +020088 ALOGW("drmGetCap failed. Fallback to no modifier support.");
89 cap_value = 0;
90 }
91 HasAddFb2ModifiersSupport_ = cap_value != 0;
92
Roman Stratiienko76892782023-01-16 17:15:53 +020093 drmSetMaster(*GetFd());
94 if (drmIsMaster(*GetFd()) == 0) {
John Stultzfa002332021-02-02 01:34:45 +000095 ALOGE("DRM/KMS master access required");
Roman Stratiienko3dacd472022-01-11 19:18:34 +020096 return -EACCES;
Roman Stratiienko3b24cd92021-01-13 10:32:04 +020097 }
98
Roman Stratiienko76892782023-01-16 17:15:53 +020099 auto res = MakeDrmModeResUnique(*GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -0400100 if (!res) {
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100101 ALOGE("Failed to get DrmDevice resources");
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200102 return -ENODEV;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400103 }
104
Sean Paulf72cccd2018-08-27 13:59:08 -0400105 min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
106 res->min_height);
107 max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
108 res->max_height);
Sean Paul406dbfc2016-02-10 15:35:17 -0800109
Roman Stratiienko10be8752022-01-30 20:28:46 +0200110 for (int i = 0; i < res->count_crtcs; ++i) {
111 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
112 auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
113 if (crtc) {
114 crtcs_.emplace_back(std::move(crtc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400115 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400116 }
117
Roman Stratiienko027987b2022-01-30 21:06:35 +0200118 for (int i = 0; i < res->count_encoders; ++i) {
119 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
120 auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
121 if (enc) {
122 encoders_.emplace_back(std::move(enc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400123 }
Alexandru Gheorghee8b668c2018-03-22 11:31:29 +0000124 }
125
Roman Stratiienko650299a2022-01-30 23:46:10 +0200126 for (int i = 0; i < res->count_connectors; ++i) {
127 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
128 auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
129
130 if (!conn) {
131 continue;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400132 }
133
Roman Stratiienko650299a2022-01-30 23:46:10 +0200134 if (conn->IsWriteback()) {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000135 writeback_connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200136 } else {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000137 connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200138 }
Robert Foss610d9892017-11-01 12:50:04 -0500139 }
140
Roman Stratiienko76892782023-01-16 17:15:53 +0200141 auto plane_res = MakeDrmModePlaneResUnique(*GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -0400142 if (!plane_res) {
143 ALOGE("Failed to get plane resources");
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200144 return -ENOENT;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400145 }
146
147 for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
Roman Stratiienkob671fab2022-01-29 00:50:22 +0200148 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
149 auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
150
151 if (plane) {
152 planes_.emplace_back(std::move(plane));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400153 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400154 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400155
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200156 return 0;
Sean Paul877be972015-06-03 14:08:27 -0400157}
158
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300159auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
160 -> DrmModeUserPropertyBlobUnique {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200161 struct drm_mode_create_blob create_blob {};
Sean Paul877be972015-06-03 14:08:27 -0400162 create_blob.length = length;
Roman Stratiienko7d899112022-01-31 11:30:27 +0200163 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
Sean Paul877be972015-06-03 14:08:27 -0400164 create_blob.data = (__u64)data;
165
Roman Stratiienko76892782023-01-16 17:15:53 +0200166 auto ret = drmIoctl(*GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200167 if (ret != 0) {
Sean Paul877be972015-06-03 14:08:27 -0400168 ALOGE("Failed to create mode property blob %d", ret);
Roman Stratiienko780f7da2022-01-10 16:04:15 +0200169 return {};
Sean Paul877be972015-06-03 14:08:27 -0400170 }
Sean Paul877be972015-06-03 14:08:27 -0400171
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300172 return DrmModeUserPropertyBlobUnique(
173 new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
174 struct drm_mode_destroy_blob destroy_blob {};
175 destroy_blob.blob_id = (__u32)*it;
Roman Stratiienko76892782023-01-16 17:15:53 +0200176 auto err = drmIoctl(*GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300177 &destroy_blob);
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300178 if (err != 0) {
179 ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
180 err);
181 }
182 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
183 delete it;
184 });
Sean Paul877be972015-06-03 14:08:27 -0400185}
186
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100187int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200188 const char *prop_name, DrmProperty *property) const {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200189 drmModeObjectPropertiesPtr props = nullptr;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400190
Roman Stratiienko76892782023-01-16 17:15:53 +0200191 props = drmModeObjectGetProperties(*GetFd(), obj_id, obj_type);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200192 if (props == nullptr) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400193 ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
194 return -ENODEV;
195 }
196
197 bool found = false;
198 for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
Roman Stratiienko7d899112022-01-31 11:30:27 +0200199 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Roman Stratiienko76892782023-01-16 17:15:53 +0200200 drmModePropertyPtr p = drmModeGetProperty(*GetFd(), props->props[i]);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200201 if (strcmp(p->name, prop_name) == 0) {
202 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Roman Stratiienko7fd8f882021-09-29 12:46:54 +0300203 property->Init(obj_id, p, props->prop_values[i]);
Sean Paul6a55e9f2015-04-30 15:31:06 -0400204 found = true;
205 }
206 drmModeFreeProperty(p);
207 }
208
209 drmModeFreeObjectProperties(props);
210 return found ? 0 : -ENOENT;
211}
212
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200213std::string DrmDevice::GetName() const {
Roman Stratiienko76892782023-01-16 17:15:53 +0200214 auto *ver = drmGetVersion(*GetFd());
Roman Stratiienko7d899112022-01-31 11:30:27 +0200215 if (ver == nullptr) {
Roman Stratiienko76892782023-01-16 17:15:53 +0200216 ALOGW("Failed to get drm version for fd=%d", *GetFd());
Matvii Zorinef3c7972020-08-11 15:15:44 +0300217 return "generic";
218 }
219
220 std::string name(ver->name);
221 drmFreeVersion(ver);
222 return name;
223}
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300224
225auto DrmDevice::IsKMSDev(const char *path) -> bool {
Roman Stratiienko76892782023-01-16 17:15:53 +0200226 auto fd = MakeUniqueFd(open(path, O_RDWR | O_CLOEXEC));
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300227 if (!fd) {
228 return false;
229 }
230
Roman Stratiienko76892782023-01-16 17:15:53 +0200231 auto res = MakeDrmModeResUnique(*fd);
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300232 if (!res) {
233 return false;
234 }
235
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300236 auto is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300237 res->count_encoders > 0;
238
239 return is_kms;
240}
241
Roman Stratiienko7d899112022-01-31 11:30:27 +0200242auto DrmDevice::GetConnectors()
243 -> const std::vector<std::unique_ptr<DrmConnector>> & {
244 return connectors_;
245}
246
Roman Stratiienkof2c060f2023-09-18 22:46:08 +0300247auto DrmDevice::GetWritebackConnectors()
248 -> const std::vector<std::unique_ptr<DrmConnector>> & {
249 return writeback_connectors_;
250}
251
Roman Stratiienko7d899112022-01-31 11:30:27 +0200252auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
253 return planes_;
254}
255
256auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
257 return crtcs_;
258}
259
260auto DrmDevice::GetEncoders()
261 -> const std::vector<std::unique_ptr<DrmEncoder>> & {
262 return encoders_;
263}
264
Roman Stratiienko2290dc62025-02-09 12:53:35 +0200265class DumbBufferFd : public PrimeFdsSharedBase {
266 public:
267 SharedFd fd;
268};
269
270// NOLINTBEGIN(cppcoreguidelines-avoid-goto)
271auto DrmDevice::CreateBufferForModeset(uint32_t width, uint32_t height)
272 -> std::optional<BufferInfo> {
273 constexpr uint32_t kDumbBufferFormat = DRM_FORMAT_XRGB8888;
274 constexpr uint32_t kDumbBufferBpp = 32;
275
276 std::optional<BufferInfo> result;
277 void *ptr = MAP_FAILED;
278 struct drm_mode_create_dumb create = {
279 .height = height,
280 .width = width,
281 .bpp = kDumbBufferBpp,
282 .flags = 0,
283 };
284
285 int ret = drmIoctl(*fd_, DRM_IOCTL_MODE_CREATE_DUMB, &create);
286 if (ret != 0) {
287 ALOGE("Failed to DRM_IOCTL_MODE_CREATE_DUMB %d", errno);
288 return {};
289 }
290
291 struct drm_mode_map_dumb map = {
292 .handle = create.handle,
293 };
294
295 auto dumb_buffer_fd = std::make_shared<DumbBufferFd>();
296
297 BufferInfo buffer_info = {
298 .width = width,
299 .height = height,
300
301 .format = kDumbBufferFormat,
302 .pitches = {create.pitch},
303 .prime_fds = {-1, -1, -1, -1},
304 .modifiers = {DRM_FORMAT_MOD_NONE},
305
306 .color_space = BufferColorSpace::kUndefined,
307 .sample_range = BufferSampleRange::kUndefined,
308 .blend_mode = BufferBlendMode::kNone,
309
310 .fds_shared = dumb_buffer_fd,
311 };
312
313 ret = drmIoctl(*fd_, DRM_IOCTL_MODE_MAP_DUMB, &map);
314 if (ret != 0) {
315 ALOGE("Failed to DRM_IOCTL_MODE_MAP_DUMB %d", errno);
316 goto done;
317 }
318
319 ptr = mmap(nullptr, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd_,
320 (off_t)map.offset);
321 if (ptr == MAP_FAILED) {
322 ALOGE("Failed to mmap dumb buffer %d", errno);
323 goto done;
324 }
325
326 memset(ptr, 0, create.size);
327
328 if (munmap(ptr, create.size) != 0) {
329 ALOGE("Failed to unmap dumb buffer: %d", errno);
330 }
331
332 ret = drmPrimeHandleToFD(*fd_, create.handle, 0, &buffer_info.prime_fds[0]);
333 if (ret != 0) {
334 ALOGE("Failed to export dumb buffer as FD: %d", errno);
335 goto done;
336 }
337
338 dumb_buffer_fd->fd = MakeSharedFd(buffer_info.prime_fds[0]);
339
340 result = buffer_info;
341
342done:
343 if (create.handle > 0) {
344 struct drm_mode_destroy_dumb destroy = {
345 .handle = create.handle,
346 };
347 drmIoctl(*fd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
348 }
349
350 return result;
351}
352// NOLINTEND(cppcoreguidelines-avoid-goto)
353
Sean Paulf72cccd2018-08-27 13:59:08 -0400354} // namespace android