1 /*
2 * Copyright 2021 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
17 #include "DrmPresenter.h"
18
19 #include <cros_gralloc_handle.h>
20 #include <linux/netlink.h>
21 #include <sys/socket.h>
22
23 using android::base::guest::AutoReadLock;
24 using android::base::guest::AutoWriteLock;
25 using android::base::guest::ReadWriteLock;
26
27 namespace android {
28
init(const HotplugCallback & cb)29 bool DrmPresenter::init(const HotplugCallback& cb) {
30 DEBUG_LOG("%s", __FUNCTION__);
31
32 mHotplugCallback = cb;
33 mFd = android::base::unique_fd(open("/dev/dri/card0", O_RDWR | O_CLOEXEC));
34 if (mFd < 0) {
35 ALOGE("%s HWC2::Error opening DrmPresenter device: %d", __FUNCTION__,
36 errno);
37 return false;
38 }
39
40 int univRet = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
41 if (univRet) {
42 ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
43 return false;
44 }
45
46 int atomicRet = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_ATOMIC, 1);
47 if (atomicRet) {
48 ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
49 errno);
50 return false;
51 }
52
53 {
54 AutoWriteLock lock(mStateMutex);
55 bool initDrmRet = initDrmElementsLocked();
56 if (initDrmRet) {
57 ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
58 } else {
59 ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
60 return false;
61 }
62 }
63
64 mDrmEventListener = sp<DrmEventListener>::make(*this);
65 if (mDrmEventListener->init()) {
66 ALOGD("%s: Successfully initialized DRM event listener", __FUNCTION__);
67 } else {
68 ALOGE("%s: Failed to initialize DRM event listener", __FUNCTION__);
69 }
70 mDrmEventListener->run("", ANDROID_PRIORITY_URGENT_DISPLAY);
71
72 return true;
73 }
74
initDrmElementsLocked()75 bool DrmPresenter::initDrmElementsLocked() {
76 drmModeRes* res;
77 static const int32_t kUmPerInch = 25400;
78
79 res = drmModeGetResources(mFd.get());
80 if (res == nullptr) {
81 ALOGE("%s HWC2::Error reading drm resources: %d", __FUNCTION__, errno);
82 mFd.reset();
83 return false;
84 }
85
86 ALOGD(
87 "drmModeRes count fbs %d crtc %d connector %d encoder %d min w %d max w "
88 "%d min h %d max h %d",
89 res->count_fbs, res->count_crtcs, res->count_connectors,
90 res->count_encoders, res->min_width, res->max_width, res->min_height,
91 res->max_height);
92
93 for (uint32_t i = 0; i < res->count_crtcs; i++) {
94 DrmCrtc crtc = {};
95
96 drmModeCrtcPtr c = drmModeGetCrtc(mFd.get(), res->crtcs[i]);
97 crtc.mId = c->crtc_id;
98
99 drmModeObjectPropertiesPtr crtcProps =
100 drmModeObjectGetProperties(mFd.get(), c->crtc_id, DRM_MODE_OBJECT_CRTC);
101
102 for (uint32_t crtcPropsIndex = 0; crtcPropsIndex < crtcProps->count_props;
103 crtcPropsIndex++) {
104 drmModePropertyPtr crtcProp =
105 drmModeGetProperty(mFd.get(), crtcProps->props[crtcPropsIndex]);
106
107 if (!strcmp(crtcProp->name, "OUT_FENCE_PTR")) {
108 crtc.mOutFencePtrPropertyId = crtcProp->prop_id;
109 } else if (!strcmp(crtcProp->name, "ACTIVE")) {
110 crtc.mActivePropertyId = crtcProp->prop_id;
111 } else if (!strcmp(crtcProp->name, "MODE_ID")) {
112 crtc.mModePropertyId = crtcProp->prop_id;
113 }
114
115 drmModeFreeProperty(crtcProp);
116 }
117
118 drmModeFreeObjectProperties(crtcProps);
119
120 mCrtcs.push_back(crtc);
121 }
122
123 drmModePlaneResPtr planeRes = drmModeGetPlaneResources(mFd.get());
124 for (uint32_t i = 0; i < planeRes->count_planes; ++i) {
125 DrmPlane plane = {};
126
127 drmModePlanePtr p = drmModeGetPlane(mFd.get(), planeRes->planes[i]);
128 plane.mId = p->plane_id;
129
130 ALOGD(
131 "%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d "
132 "possible ctrcs 0x%x",
133 __FUNCTION__, p->plane_id, p->crtc_id, p->fb_id, p->crtc_x, p->crtc_y,
134 p->x, p->y, p->possible_crtcs);
135
136 drmModeObjectPropertiesPtr planeProps =
137 drmModeObjectGetProperties(mFd.get(), plane.mId, DRM_MODE_OBJECT_PLANE);
138
139 for (uint32_t planePropIndex = 0; planePropIndex < planeProps->count_props;
140 ++planePropIndex) {
141 drmModePropertyPtr planeProp =
142 drmModeGetProperty(mFd.get(), planeProps->props[planePropIndex]);
143
144 if (!strcmp(planeProp->name, "CRTC_ID")) {
145 plane.mCrtcPropertyId = planeProp->prop_id;
146 } else if (!strcmp(planeProp->name, "IN_FENCE_FD")) {
147 plane.mInFenceFdPropertyId = planeProp->prop_id;
148 } else if (!strcmp(planeProp->name, "FB_ID")) {
149 plane.mFbPropertyId = planeProp->prop_id;
150 } else if (!strcmp(planeProp->name, "CRTC_X")) {
151 plane.mCrtcXPropertyId = planeProp->prop_id;
152 } else if (!strcmp(planeProp->name, "CRTC_Y")) {
153 plane.mCrtcYPropertyId = planeProp->prop_id;
154 } else if (!strcmp(planeProp->name, "CRTC_W")) {
155 plane.mCrtcWPropertyId = planeProp->prop_id;
156 } else if (!strcmp(planeProp->name, "CRTC_H")) {
157 plane.mCrtcHPropertyId = planeProp->prop_id;
158 } else if (!strcmp(planeProp->name, "SRC_X")) {
159 plane.mSrcXPropertyId = planeProp->prop_id;
160 } else if (!strcmp(planeProp->name, "SRC_Y")) {
161 plane.mSrcYPropertyId = planeProp->prop_id;
162 } else if (!strcmp(planeProp->name, "SRC_W")) {
163 plane.mSrcWPropertyId = planeProp->prop_id;
164 } else if (!strcmp(planeProp->name, "SRC_H")) {
165 plane.mSrcHPropertyId = planeProp->prop_id;
166 } else if (!strcmp(planeProp->name, "type")) {
167 plane.mTypePropertyId = planeProp->prop_id;
168 uint64_t type = planeProp->values[0];
169 switch (type) {
170 case DRM_PLANE_TYPE_OVERLAY:
171 plane.mType = type;
172 ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_OVERLAY",
173 __FUNCTION__, plane.mId);
174 break;
175 case DRM_PLANE_TYPE_PRIMARY:
176 plane.mType = type;
177 ALOGD("%s: plane %" PRIu32 " is DRM_PLANE_TYPE_PRIMARY",
178 __FUNCTION__, plane.mId);
179 break;
180 default:
181 break;
182 }
183 }
184
185 drmModeFreeProperty(planeProp);
186 }
187
188 drmModeFreeObjectProperties(planeProps);
189
190 bool isPrimaryOrOverlay = plane.mType == DRM_PLANE_TYPE_OVERLAY ||
191 plane.mType == DRM_PLANE_TYPE_PRIMARY;
192 if (isPrimaryOrOverlay) {
193 for (uint32_t j = 0; j < mCrtcs.size(); j++) {
194 if ((0x1 << j) & p->possible_crtcs) {
195 ALOGD("%s: plane %" PRIu32 " compatible with crtc mask %" PRIu32,
196 __FUNCTION__, plane.mId, p->possible_crtcs);
197 if (mCrtcs[j].mPlaneId == -1) {
198 mCrtcs[j].mPlaneId = plane.mId;
199 ALOGD("%s: plane %" PRIu32 " associated with crtc %" PRIu32,
200 __FUNCTION__, plane.mId, j);
201 break;
202 }
203 }
204 }
205 }
206
207 drmModeFreePlane(p);
208 mPlanes[plane.mId] = plane;
209 }
210 drmModeFreePlaneResources(planeRes);
211
212 for (uint32_t i = 0; i < res->count_connectors; ++i) {
213 DrmConnector connector = {};
214 connector.mId = res->connectors[i];
215
216 {
217 drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
218 mFd.get(), connector.mId, DRM_MODE_OBJECT_CONNECTOR);
219
220 for (uint32_t connectorPropIndex = 0;
221 connectorPropIndex < connectorProps->count_props;
222 ++connectorPropIndex) {
223 drmModePropertyPtr connectorProp = drmModeGetProperty(
224 mFd.get(), connectorProps->props[connectorPropIndex]);
225 if (!strcmp(connectorProp->name, "CRTC_ID")) {
226 connector.mCrtcPropertyId = connectorProp->prop_id;
227 } else if (!strcmp(connectorProp->name, "EDID")) {
228 connector.mEdidBlobId =
229 connectorProps->prop_values[connectorPropIndex];
230 }
231 drmModeFreeProperty(connectorProp);
232 }
233
234 drmModeFreeObjectProperties(connectorProps);
235 }
236 {
237 drmModeConnector* c = drmModeGetConnector(mFd.get(), connector.mId);
238 if (c == nullptr) {
239 ALOGE("%s: Failed to get connector %" PRIu32 ": %d", __FUNCTION__,
240 connector.mId, errno);
241 return false;
242 }
243 connector.connection = c->connection;
244 if (c->count_modes > 0) {
245 memcpy(&connector.mMode, &c->modes[0], sizeof(drmModeModeInfo));
246 drmModeCreatePropertyBlob(mFd.get(), &connector.mMode,
247 sizeof(connector.mMode),
248 &connector.mModeBlobId);
249
250 // Dots per 1000 inches
251 connector.dpiX =
252 c->mmWidth ? (c->modes[0].hdisplay * kUmPerInch) / (c->mmWidth)
253 : -1;
254 // Dots per 1000 inches
255 connector.dpiY =
256 c->mmHeight ? (c->modes[0].vdisplay * kUmPerInch) / (c->mmHeight)
257 : -1;
258 }
259 ALOGD("%s connector %" PRIu32 " dpiX %" PRIi32 " dpiY %" PRIi32
260 " connection %d",
261 __FUNCTION__, connector.mId, connector.dpiX, connector.dpiY,
262 connector.connection);
263
264 drmModeFreeConnector(c);
265
266 connector.mRefreshRateAsFloat =
267 1000.0f * connector.mMode.clock /
268 ((float)connector.mMode.vtotal * (float)connector.mMode.htotal);
269 connector.mRefreshRateAsInteger =
270 (uint32_t)(connector.mRefreshRateAsFloat + 0.5f);
271 }
272
273 mConnectors.push_back(connector);
274 }
275
276 drmModeFreeResources(res);
277 return true;
278 }
279
resetDrmElementsLocked()280 void DrmPresenter::resetDrmElementsLocked() {
281 for (auto& c : mConnectors) {
282 if (c.mModeBlobId) {
283 if (drmModeDestroyPropertyBlob(mFd.get(), c.mModeBlobId)) {
284 ALOGE("%s: Error destroy PropertyBlob %" PRIu32, __func__,
285 c.mModeBlobId);
286 }
287 }
288 }
289 mConnectors.clear();
290 mCrtcs.clear();
291 mPlanes.clear();
292 }
293
getDrmFB(hwc_drm_bo_t & bo)294 int DrmPresenter::getDrmFB(hwc_drm_bo_t& bo) {
295 int ret = drmPrimeFDToHandle(mFd.get(), bo.prime_fds[0], &bo.gem_handles[0]);
296 if (ret) {
297 ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
298 strerror(errno), errno);
299 return -1;
300 }
301 ret = drmModeAddFB2(mFd.get(), bo.width, bo.height, bo.format, bo.gem_handles,
302 bo.pitches, bo.offsets, &bo.fb_id, 0);
303 if (ret) {
304 ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
305 strerror(errno), errno);
306 return -1;
307 }
308 return 0;
309 }
310
clearDrmFB(hwc_drm_bo_t & bo)311 int DrmPresenter::clearDrmFB(hwc_drm_bo_t& bo) {
312 int ret = 0;
313 if (bo.fb_id) {
314 if (drmModeRmFB(mFd.get(), bo.fb_id)) {
315 ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
316 strerror(errno), errno);
317 }
318 ret = -1;
319 }
320 if (bo.gem_handles[0]) {
321 struct drm_gem_close gem_close = {};
322 gem_close.handle = bo.gem_handles[0];
323 if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
324 ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
325 strerror(errno), errno);
326 }
327 ret = -1;
328 }
329 ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
330 return ret;
331 }
332
handleHotplug()333 bool DrmPresenter::handleHotplug() {
334 std::vector<DrmConnector> oldConnectors(mConnectors);
335 {
336 AutoReadLock lock(mStateMutex);
337 oldConnectors.assign(mConnectors.begin(), mConnectors.end());
338 }
339 {
340 AutoWriteLock lock(mStateMutex);
341 resetDrmElementsLocked();
342 if (!initDrmElementsLocked()) {
343 ALOGE(
344 "%s: failed to initialize drm elements during hotplug. Displays may "
345 "not function correctly!",
346 __FUNCTION__);
347 return false;
348 }
349 }
350
351 AutoReadLock lock(mStateMutex);
352 for (int i = 0; i < mConnectors.size(); i++) {
353 bool changed =
354 oldConnectors[i].dpiX != mConnectors[i].dpiX ||
355 oldConnectors[i].dpiY != mConnectors[i].dpiY ||
356 oldConnectors[i].connection != mConnectors[i].connection ||
357 oldConnectors[i].mMode.hdisplay != mConnectors[i].mMode.hdisplay ||
358 oldConnectors[i].mMode.vdisplay != mConnectors[i].mMode.vdisplay;
359 if (changed) {
360 if (i == 0) {
361 ALOGE(
362 "%s: Ignoring changes to display:0 which is not configurable by "
363 "multi-display interface.",
364 __FUNCTION__);
365 continue;
366 }
367
368 bool connected =
369 mConnectors[i].connection == DRM_MODE_CONNECTED ? true : false;
370 if (mHotplugCallback) {
371 mHotplugCallback(connected, i, mConnectors[i].mMode.hdisplay,
372 mConnectors[i].mMode.vdisplay, mConnectors[i].dpiX,
373 mConnectors[i].dpiY,
374 mConnectors[i].mRefreshRateAsInteger);
375 }
376 }
377 }
378 return true;
379 }
380
flushToDisplay(int display,hwc_drm_bo_t & bo,base::borrowed_fd inSyncFd)381 std::tuple<HWC2::Error, base::unique_fd> DrmPresenter::flushToDisplay(
382 int display, hwc_drm_bo_t& bo, base::borrowed_fd inSyncFd) {
383 ATRACE_CALL();
384
385 AutoReadLock lock(mStateMutex);
386
387 DrmConnector& connector = mConnectors[display];
388 DrmCrtc& crtc = mCrtcs[display];
389
390 HWC2::Error error = HWC2::Error::None;
391
392 drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
393
394 int ret;
395
396 if (!crtc.mDidSetCrtc) {
397 DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
398 ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mActivePropertyId, 1);
399 if (ret < 0) {
400 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
401 }
402 ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mModePropertyId,
403 connector.mModeBlobId);
404 if (ret < 0) {
405 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
406 }
407 ret = drmModeAtomicAddProperty(pset, connector.mId,
408 connector.mCrtcPropertyId, crtc.mId);
409 if (ret < 0) {
410 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
411 }
412
413 crtc.mDidSetCrtc = true;
414 } else {
415 DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
416 }
417
418 int rawOutSyncFd;
419 uint64_t outSyncFdUint =
420 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&rawOutSyncFd));
421
422 ret = drmModeAtomicAddProperty(pset, crtc.mId, crtc.mOutFencePtrPropertyId,
423 outSyncFdUint);
424 if (ret < 0) {
425 ALOGE("%s:%d: set OUT_FENCE_PTR failed %d errno %d\n", __FUNCTION__,
426 __LINE__, ret, errno);
427 }
428
429 if (crtc.mPlaneId == -1) {
430 ALOGE("%s:%d: no plane available for crtc id %" PRIu32, __FUNCTION__,
431 __LINE__, crtc.mId);
432 return std::make_tuple(HWC2::Error::NoResources, base::unique_fd());
433 }
434
435 DrmPlane& plane = mPlanes[crtc.mPlaneId];
436
437 DEBUG_LOG("%s: set plane: plane id %d crtc id %d fbid %d bo w h %d %d\n",
438 __FUNCTION__, plane.mId, crtc.mId, bo.fb_id, bo.width, bo.height);
439
440 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcPropertyId,
441 crtc.mId);
442 if (ret < 0) {
443 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
444 }
445 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mInFenceFdPropertyId,
446 inSyncFd.get());
447 if (ret < 0) {
448 ALOGE("%s:%d: set IN_FENCE_FD failed %d errno %d\n", __FUNCTION__, __LINE__,
449 ret, errno);
450 }
451 ret =
452 drmModeAtomicAddProperty(pset, plane.mId, plane.mFbPropertyId, bo.fb_id);
453 if (ret < 0) {
454 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
455 }
456 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcXPropertyId, 0);
457 if (ret < 0) {
458 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
459 }
460 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcYPropertyId, 0);
461 if (ret < 0) {
462 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
463 }
464 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcWPropertyId,
465 bo.width);
466 if (ret < 0) {
467 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
468 }
469 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mCrtcHPropertyId,
470 bo.height);
471 if (ret < 0) {
472 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
473 }
474 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcXPropertyId, 0);
475 if (ret < 0) {
476 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
477 }
478 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcYPropertyId, 0);
479 if (ret < 0) {
480 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
481 }
482 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcWPropertyId,
483 bo.width << 16);
484 if (ret < 0) {
485 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
486 }
487 ret = drmModeAtomicAddProperty(pset, plane.mId, plane.mSrcHPropertyId,
488 bo.height << 16);
489 if (ret < 0) {
490 ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
491 }
492
493 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
494 ret = drmModeAtomicCommit(mFd.get(), pset, flags, 0);
495
496 if (ret) {
497 ALOGE("%s: Atomic commit failed with %d %d\n", __FUNCTION__, ret, errno);
498 error = HWC2::Error::NoResources;
499 }
500 base::unique_fd outSyncFd(rawOutSyncFd);
501
502 if (pset) {
503 drmModeAtomicFree(pset);
504 }
505
506 DEBUG_LOG("%s: out fence: %d\n", __FUNCTION__, outSyncFd.get());
507 return std::make_tuple(error, std::move(outSyncFd));
508 }
509
getEdid(uint32_t id)510 std::optional<std::vector<uint8_t>> DrmPresenter::getEdid(uint32_t id) {
511 AutoReadLock lock(mStateMutex);
512
513 if (mConnectors[id].mEdidBlobId == -1) {
514 ALOGW("%s: EDID not supported", __func__);
515 return std::nullopt;
516 }
517 drmModePropertyBlobPtr blob =
518 drmModeGetPropertyBlob(mFd.get(), mConnectors[id].mEdidBlobId);
519 if (!blob) {
520 ALOGE("%s: fail to read EDID from DRM", __func__);
521 return std::nullopt;
522 }
523
524 std::vector<uint8_t> edid;
525 uint8_t* start = static_cast<uint8_t*>(blob->data);
526 edid.insert(edid.begin(), start, start + blob->length);
527
528 drmModeFreePropertyBlob(blob);
529
530 return edid;
531 }
532
DrmBuffer(const native_handle_t * handle,DrmPresenter * drmPresenter)533 DrmBuffer::DrmBuffer(const native_handle_t* handle, DrmPresenter* drmPresenter)
534 : mDrmPresenter(drmPresenter), mBo({}) {
535 if (!convertBoInfo(handle)) {
536 mDrmPresenter->getDrmFB(mBo);
537 }
538 }
539
~DrmBuffer()540 DrmBuffer::~DrmBuffer() { mDrmPresenter->clearDrmFB(mBo); }
541
convertBoInfo(const native_handle_t * handle)542 int DrmBuffer::convertBoInfo(const native_handle_t* handle) {
543 cros_gralloc_handle* gr_handle = (cros_gralloc_handle*)handle;
544 if (!gr_handle) {
545 ALOGE("%s: Null buffer handle", __FUNCTION__);
546 return -1;
547 }
548 mBo.width = gr_handle->width;
549 mBo.height = gr_handle->height;
550 mBo.hal_format = gr_handle->droid_format;
551 mBo.format = gr_handle->format;
552 mBo.usage = gr_handle->usage;
553 mBo.prime_fds[0] = gr_handle->fds[0];
554 mBo.pitches[0] = gr_handle->strides[0];
555 return 0;
556 }
557
flushToDisplay(int display,base::borrowed_fd inWaitSyncFd)558 std::tuple<HWC2::Error, base::unique_fd> DrmBuffer::flushToDisplay(
559 int display, base::borrowed_fd inWaitSyncFd) {
560 return mDrmPresenter->flushToDisplay(display, mBo, inWaitSyncFd);
561 }
562
DrmEventListener(DrmPresenter & presenter)563 DrmPresenter::DrmEventListener::DrmEventListener(DrmPresenter& presenter)
564 : mPresenter(presenter) {}
565
~DrmEventListener()566 DrmPresenter::DrmEventListener::~DrmEventListener() {}
567
init()568 bool DrmPresenter::DrmEventListener::init() {
569 mEventFd = android::base::unique_fd(
570 socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT));
571 if (!mEventFd.ok()) {
572 ALOGE("Failed to open uevent socket: %s", strerror(errno));
573 return false;
574 }
575 struct sockaddr_nl addr;
576 memset(&addr, 0, sizeof(addr));
577 addr.nl_family = AF_NETLINK;
578 addr.nl_pid = 0;
579 addr.nl_groups = 0xFFFFFFFF;
580
581 int ret = bind(mEventFd, (struct sockaddr*)&addr, sizeof(addr));
582 if (ret) {
583 ALOGE("Failed to bind uevent socket: %s", strerror(errno));
584 return false;
585 }
586
587 FD_ZERO(&mMonitoredFds);
588 FD_SET(mPresenter.mFd.get(), &mMonitoredFds);
589 FD_SET(mEventFd.get(), &mMonitoredFds);
590 mMaxFd = std::max(mPresenter.mFd.get(), mEventFd.get());
591
592 return true;
593 }
594
threadLoop()595 bool DrmPresenter::DrmEventListener::threadLoop() {
596 int ret;
597 do {
598 ret = select(mMaxFd + 1, &mMonitoredFds, NULL, NULL, NULL);
599 } while (ret == -1 && errno == EINTR);
600
601 // if (FD_ISSET(mPresenter.mFd, &mFds)) {
602 // TODO: handle drm related events
603 // }
604
605 if (FD_ISSET(mEventFd.get(), &mMonitoredFds)) {
606 eventThreadLoop();
607 }
608 return true;
609 }
610
eventThreadLoop()611 void DrmPresenter::DrmEventListener::eventThreadLoop() {
612 char buffer[1024];
613 int ret;
614
615 struct timespec ts;
616 uint64_t timestamp = 0;
617 ret = clock_gettime(CLOCK_MONOTONIC, &ts);
618 if (!ret) {
619 timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
620 } else {
621 ALOGE("Failed to get monotonic clock on hotplug %d", ret);
622 }
623
624 while (true) {
625 ret = read(mEventFd.get(), &buffer, sizeof(buffer));
626 if (ret == 0) {
627 return;
628 } else if (ret < 0) {
629 ALOGE("Got error reading uevent %d", ret);
630 return;
631 }
632
633 bool drmEvent = false, hotplugEvent = false;
634 for (int i = 0; i < ret;) {
635 char* event = buffer + i;
636 if (strcmp(event, "DEVTYPE=drm_minor")) {
637 drmEvent = true;
638 } else if (strcmp(event, "HOTPLUG=1")) {
639 hotplugEvent = true;
640 }
641
642 i += strlen(event) + 1;
643 }
644
645 if (drmEvent && hotplugEvent) {
646 processHotplug(timestamp);
647 }
648 }
649 }
650
processHotplug(uint64_t timestamp)651 void DrmPresenter::DrmEventListener::processHotplug(uint64_t timestamp) {
652 ALOGD("DrmEventListener detected hotplug event %" PRIu64, timestamp);
653 mPresenter.handleHotplug();
654 }
655 } // namespace android
656