blob: f6141d4572fb59157cd16865b537cc6373fe954a [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
Andrew Wolfers9777fba2024-12-12 17:51:43 +000093 uint64_t cursor_width = 0;
94 uint64_t cursor_height = 0;
95 if (drmGetCap(*GetFd(), DRM_CAP_CURSOR_WIDTH, &cursor_width) == 0 &&
96 drmGetCap(*GetFd(), DRM_CAP_CURSOR_HEIGHT, &cursor_height) == 0) {
97 cap_cursor_size_ = std::pair<uint64_t, uint64_t>(cursor_width,
98 cursor_height);
99 }
100
Roman Stratiienko76892782023-01-16 17:15:53 +0200101 drmSetMaster(*GetFd());
102 if (drmIsMaster(*GetFd()) == 0) {
John Stultzfa002332021-02-02 01:34:45 +0000103 ALOGE("DRM/KMS master access required");
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200104 return -EACCES;
Roman Stratiienko3b24cd92021-01-13 10:32:04 +0200105 }
106
Roman Stratiienko76892782023-01-16 17:15:53 +0200107 auto res = MakeDrmModeResUnique(*GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -0400108 if (!res) {
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100109 ALOGE("Failed to get DrmDevice resources");
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200110 return -ENODEV;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400111 }
112
Sean Paulf72cccd2018-08-27 13:59:08 -0400113 min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
114 res->min_height);
115 max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
116 res->max_height);
Sean Paul406dbfc2016-02-10 15:35:17 -0800117
Roman Stratiienko10be8752022-01-30 20:28:46 +0200118 for (int i = 0; i < res->count_crtcs; ++i) {
119 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
120 auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
121 if (crtc) {
122 crtcs_.emplace_back(std::move(crtc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400123 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400124 }
125
Roman Stratiienko027987b2022-01-30 21:06:35 +0200126 for (int i = 0; i < res->count_encoders; ++i) {
127 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
128 auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
129 if (enc) {
130 encoders_.emplace_back(std::move(enc));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400131 }
Alexandru Gheorghee8b668c2018-03-22 11:31:29 +0000132 }
133
Roman Stratiienko650299a2022-01-30 23:46:10 +0200134 for (int i = 0; i < res->count_connectors; ++i) {
135 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
136 auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
137
138 if (!conn) {
139 continue;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400140 }
141
Roman Stratiienko650299a2022-01-30 23:46:10 +0200142 if (conn->IsWriteback()) {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000143 writeback_connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200144 } else {
Alexandru Gheorgheb46b9302018-03-21 14:19:58 +0000145 connectors_.emplace_back(std::move(conn));
Roman Stratiienko650299a2022-01-30 23:46:10 +0200146 }
Robert Foss610d9892017-11-01 12:50:04 -0500147 }
148
Roman Stratiienko76892782023-01-16 17:15:53 +0200149 auto plane_res = MakeDrmModePlaneResUnique(*GetFd());
Sean Paul6a55e9f2015-04-30 15:31:06 -0400150 if (!plane_res) {
151 ALOGE("Failed to get plane resources");
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200152 return -ENOENT;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400153 }
154
155 for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
Roman Stratiienkob671fab2022-01-29 00:50:22 +0200156 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
157 auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
158
159 if (plane) {
160 planes_.emplace_back(std::move(plane));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400161 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400162 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400163
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200164 return 0;
Sean Paul877be972015-06-03 14:08:27 -0400165}
166
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300167auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
168 -> DrmModeUserPropertyBlobUnique {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200169 struct drm_mode_create_blob create_blob {};
Sean Paul877be972015-06-03 14:08:27 -0400170 create_blob.length = length;
Roman Stratiienko7d899112022-01-31 11:30:27 +0200171 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
Sean Paul877be972015-06-03 14:08:27 -0400172 create_blob.data = (__u64)data;
173
Roman Stratiienko76892782023-01-16 17:15:53 +0200174 auto ret = drmIoctl(*GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200175 if (ret != 0) {
Sean Paul877be972015-06-03 14:08:27 -0400176 ALOGE("Failed to create mode property blob %d", ret);
Roman Stratiienko780f7da2022-01-10 16:04:15 +0200177 return {};
Sean Paul877be972015-06-03 14:08:27 -0400178 }
Sean Paul877be972015-06-03 14:08:27 -0400179
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300180 return DrmModeUserPropertyBlobUnique(
181 new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
182 struct drm_mode_destroy_blob destroy_blob {};
183 destroy_blob.blob_id = (__u32)*it;
Roman Stratiienko76892782023-01-16 17:15:53 +0200184 auto err = drmIoctl(*GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300185 &destroy_blob);
Roman Stratiienko6ede4662021-09-30 10:18:28 +0300186 if (err != 0) {
187 ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
188 err);
189 }
190 // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
191 delete it;
192 });
Sean Paul877be972015-06-03 14:08:27 -0400193}
194
Alexandru Gheorghe0f5abd72018-05-01 14:37:10 +0100195int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200196 const char *prop_name, DrmProperty *property) const {
Roman Stratiienkob3b5c1e2021-02-15 13:44:19 +0200197 drmModeObjectPropertiesPtr props = nullptr;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400198
Roman Stratiienko76892782023-01-16 17:15:53 +0200199 props = drmModeObjectGetProperties(*GetFd(), obj_id, obj_type);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200200 if (props == nullptr) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400201 ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
202 return -ENODEV;
203 }
204
205 bool found = false;
206 for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
Roman Stratiienko7d899112022-01-31 11:30:27 +0200207 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Roman Stratiienko76892782023-01-16 17:15:53 +0200208 drmModePropertyPtr p = drmModeGetProperty(*GetFd(), props->props[i]);
Roman Stratiienko7d899112022-01-31 11:30:27 +0200209 if (strcmp(p->name, prop_name) == 0) {
210 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Andrew Wolferse778d032024-12-12 17:32:33 +0000211 property->Init(GetFd(), obj_id, p, props->prop_values[i]);
Sean Paul6a55e9f2015-04-30 15:31:06 -0400212 found = true;
213 }
214 drmModeFreeProperty(p);
215 }
216
217 drmModeFreeObjectProperties(props);
218 return found ? 0 : -ENOENT;
219}
220
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200221std::string DrmDevice::GetName() const {
Roman Stratiienko76892782023-01-16 17:15:53 +0200222 auto *ver = drmGetVersion(*GetFd());
Roman Stratiienko7d899112022-01-31 11:30:27 +0200223 if (ver == nullptr) {
Roman Stratiienko76892782023-01-16 17:15:53 +0200224 ALOGW("Failed to get drm version for fd=%d", *GetFd());
Matvii Zorinef3c7972020-08-11 15:15:44 +0300225 return "generic";
226 }
227
228 std::string name(ver->name);
229 drmFreeVersion(ver);
230 return name;
231}
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300232
233auto DrmDevice::IsKMSDev(const char *path) -> bool {
Roman Stratiienko76892782023-01-16 17:15:53 +0200234 auto fd = MakeUniqueFd(open(path, O_RDWR | O_CLOEXEC));
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300235 if (!fd) {
236 return false;
237 }
238
Roman Stratiienko76892782023-01-16 17:15:53 +0200239 auto res = MakeDrmModeResUnique(*fd);
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300240 if (!res) {
241 return false;
242 }
243
Roman Stratiienkoa7913de2022-10-20 13:18:57 +0300244 auto is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
Roman Stratiienko56f4adc2021-09-29 12:47:12 +0300245 res->count_encoders > 0;
246
247 return is_kms;
248}
249
Roman Stratiienko7d899112022-01-31 11:30:27 +0200250auto DrmDevice::GetConnectors()
251 -> const std::vector<std::unique_ptr<DrmConnector>> & {
252 return connectors_;
253}
254
Roman Stratiienkof2c060f2023-09-18 22:46:08 +0300255auto DrmDevice::GetWritebackConnectors()
256 -> const std::vector<std::unique_ptr<DrmConnector>> & {
257 return writeback_connectors_;
258}
259
Roman Stratiienko7d899112022-01-31 11:30:27 +0200260auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
261 return planes_;
262}
263
264auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
265 return crtcs_;
266}
267
268auto DrmDevice::GetEncoders()
269 -> const std::vector<std::unique_ptr<DrmEncoder>> & {
270 return encoders_;
271}
272
Roman Stratiienko2290dc62025-02-09 12:53:35 +0200273class DumbBufferFd : public PrimeFdsSharedBase {
274 public:
275 SharedFd fd;
276};
277
278// NOLINTBEGIN(cppcoreguidelines-avoid-goto)
279auto DrmDevice::CreateBufferForModeset(uint32_t width, uint32_t height)
280 -> std::optional<BufferInfo> {
281 constexpr uint32_t kDumbBufferFormat = DRM_FORMAT_XRGB8888;
282 constexpr uint32_t kDumbBufferBpp = 32;
283
284 std::optional<BufferInfo> result;
285 void *ptr = MAP_FAILED;
286 struct drm_mode_create_dumb create = {
287 .height = height,
288 .width = width,
289 .bpp = kDumbBufferBpp,
290 .flags = 0,
291 };
292
293 int ret = drmIoctl(*fd_, DRM_IOCTL_MODE_CREATE_DUMB, &create);
294 if (ret != 0) {
295 ALOGE("Failed to DRM_IOCTL_MODE_CREATE_DUMB %d", errno);
296 return {};
297 }
298
299 struct drm_mode_map_dumb map = {
300 .handle = create.handle,
301 };
302
303 auto dumb_buffer_fd = std::make_shared<DumbBufferFd>();
304
305 BufferInfo buffer_info = {
306 .width = width,
307 .height = height,
308
309 .format = kDumbBufferFormat,
310 .pitches = {create.pitch},
311 .prime_fds = {-1, -1, -1, -1},
312 .modifiers = {DRM_FORMAT_MOD_NONE},
313
314 .color_space = BufferColorSpace::kUndefined,
315 .sample_range = BufferSampleRange::kUndefined,
316 .blend_mode = BufferBlendMode::kNone,
317
318 .fds_shared = dumb_buffer_fd,
319 };
320
321 ret = drmIoctl(*fd_, DRM_IOCTL_MODE_MAP_DUMB, &map);
322 if (ret != 0) {
323 ALOGE("Failed to DRM_IOCTL_MODE_MAP_DUMB %d", errno);
324 goto done;
325 }
326
327 ptr = mmap(nullptr, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd_,
328 (off_t)map.offset);
329 if (ptr == MAP_FAILED) {
330 ALOGE("Failed to mmap dumb buffer %d", errno);
331 goto done;
332 }
333
334 memset(ptr, 0, create.size);
335
336 if (munmap(ptr, create.size) != 0) {
337 ALOGE("Failed to unmap dumb buffer: %d", errno);
338 }
339
340 ret = drmPrimeHandleToFD(*fd_, create.handle, 0, &buffer_info.prime_fds[0]);
341 if (ret != 0) {
342 ALOGE("Failed to export dumb buffer as FD: %d", errno);
343 goto done;
344 }
345
346 dumb_buffer_fd->fd = MakeSharedFd(buffer_info.prime_fds[0]);
347
348 result = buffer_info;
349
350done:
351 if (create.handle > 0) {
352 struct drm_mode_destroy_dumb destroy = {
353 .handle = create.handle,
354 };
355 drmIoctl(*fd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
356 }
357
358 return result;
359}
360// NOLINTEND(cppcoreguidelines-avoid-goto)
361
Sean Paulf72cccd2018-08-27 13:59:08 -0400362} // namespace android