• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 "DrmClient.h"
18 
19 #include <cros_gralloc_handle.h>
20 
21 using ::android::base::guest::AutoReadLock;
22 using ::android::base::guest::AutoWriteLock;
23 using ::android::base::guest::ReadWriteLock;
24 
25 namespace aidl::android::hardware::graphics::composer3::impl {
26 
~DrmClient()27 DrmClient::~DrmClient() {
28     if (mFd > 0) {
29         drmDropMaster(mFd.get());
30     }
31 }
32 
init()33 HWC3::Error DrmClient::init() {
34     DEBUG_LOG("%s", __FUNCTION__);
35 
36     mFd = ::android::base::unique_fd(open("/dev/dri/card0", O_RDWR | O_CLOEXEC));
37     if (mFd < 0) {
38         ALOGE("%s: failed to open drm device: %s", __FUNCTION__, strerror(errno));
39         return HWC3::Error::NoResources;
40     }
41 
42     int ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
43     if (ret) {
44         ALOGE("%s: failed to set cap universal plane %s\n", __FUNCTION__, strerror(errno));
45         return HWC3::Error::NoResources;
46     }
47 
48     ret = drmSetClientCap(mFd.get(), DRM_CLIENT_CAP_ATOMIC, 1);
49     if (ret) {
50         ALOGE("%s: failed to set cap atomic %s\n", __FUNCTION__, strerror(errno));
51         return HWC3::Error::NoResources;
52     }
53 
54     drmSetMaster(mFd.get());
55 
56     if (!drmIsMaster(mFd.get())) {
57         ALOGE("%s: failed to get master drm device", __FUNCTION__);
58         return HWC3::Error::NoResources;
59     }
60 
61     {
62         AutoWriteLock lock(mDisplaysMutex);
63         bool success = loadDrmDisplays();
64         if (success) {
65             DEBUG_LOG("%s: Successfully initialized DRM backend", __FUNCTION__);
66         } else {
67             ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
68             return HWC3::Error::NoResources;
69         }
70     }
71 
72     mDrmEventListener = DrmEventListener::create(mFd, [this]() { handleHotplug(); });
73     if (!mDrmEventListener) {
74         ALOGE("%s: Failed to initialize DRM event listener", __FUNCTION__);
75     } else {
76         DEBUG_LOG("%s: Successfully initialized DRM event listener", __FUNCTION__);
77     }
78 
79     DEBUG_LOG("%s: Successfully initialized.", __FUNCTION__);
80     return HWC3::Error::None;
81 }
82 
getDisplayConfigs(std::vector<DisplayConfig> * configs) const83 HWC3::Error DrmClient::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
84     DEBUG_LOG("%s", __FUNCTION__);
85 
86     AutoReadLock lock(mDisplaysMutex);
87 
88     configs->clear();
89 
90     for (const auto& display : mDisplays) {
91         if (!display->isConnected()) {
92             continue;
93         }
94 
95         configs->emplace_back(DisplayConfig{
96             .id = display->getId(),
97             .width = display->getWidth(),
98             .height = display->getHeight(),
99             .dpiX = display->getDpiX(),
100             .dpiY = display->getDpiY(),
101             .refreshRateHz = display->getRefreshRateUint(),
102         });
103     }
104 
105     return HWC3::Error::None;
106 }
107 
registerOnHotplugCallback(const HotplugCallback & cb)108 HWC3::Error DrmClient::registerOnHotplugCallback(const HotplugCallback& cb) {
109     mHotplugCallback = cb;
110     return HWC3::Error::None;
111 }
112 
unregisterOnHotplugCallback()113 HWC3::Error DrmClient::unregisterOnHotplugCallback() {
114     mHotplugCallback.reset();
115     return HWC3::Error::None;
116 }
117 
loadDrmDisplays()118 bool DrmClient::loadDrmDisplays() {
119     DEBUG_LOG("%s", __FUNCTION__);
120 
121     std::vector<std::unique_ptr<DrmCrtc>> crtcs;
122     std::vector<std::unique_ptr<DrmConnector>> connectors;
123     std::vector<std::unique_ptr<DrmPlane>> planes;
124 
125     drmModePlaneResPtr drmPlaneResources = drmModeGetPlaneResources(mFd.get());
126     for (uint32_t i = 0; i < drmPlaneResources->count_planes; ++i) {
127         const uint32_t planeId = drmPlaneResources->planes[i];
128 
129         auto crtc = DrmPlane::create(mFd, planeId);
130         if (!crtc) {
131             ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
132             return false;
133         }
134 
135         planes.emplace_back(std::move(crtc));
136     }
137     drmModeFreePlaneResources(drmPlaneResources);
138 
139     drmModeRes* drmResources = drmModeGetResources(mFd.get());
140     for (uint32_t crtcIndex = 0; crtcIndex < drmResources->count_crtcs; crtcIndex++) {
141         const uint32_t crtcId = drmResources->crtcs[crtcIndex];
142 
143         auto crtc = DrmCrtc::create(mFd, crtcId, crtcIndex);
144         if (!crtc) {
145             ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
146             return false;
147         }
148 
149         crtcs.emplace_back(std::move(crtc));
150     }
151 
152     for (uint32_t i = 0; i < drmResources->count_connectors; ++i) {
153         const uint32_t connectorId = drmResources->connectors[i];
154 
155         auto connector = DrmConnector::create(mFd, connectorId);
156         if (!connector) {
157             ALOGE("%s: Failed to create DRM CRTC.", __FUNCTION__);
158             return false;
159         }
160 
161         connectors.emplace_back(std::move(connector));
162     }
163 
164     drmModeFreeResources(drmResources);
165 
166     if (crtcs.size() != connectors.size()) {
167         ALOGE("%s: Failed assumption mCrtcs.size():%zu equals mConnectors.size():%zu", __FUNCTION__,
168               crtcs.size(), connectors.size());
169         return false;
170     }
171 
172     for (uint32_t i = 0; i < crtcs.size(); i++) {
173         std::unique_ptr<DrmCrtc> crtc = std::move(crtcs[i]);
174         std::unique_ptr<DrmConnector> connector = std::move(connectors[i]);
175 
176         auto planeIt =
177             std::find_if(planes.begin(), planes.end(), [&](const std::unique_ptr<DrmPlane>& plane) {
178                 if (!plane->isOverlay() && !plane->isPrimary()) {
179                     return false;
180                 }
181                 return plane->isCompatibleWith(*crtc);
182             });
183         if (planeIt == planes.end()) {
184             ALOGE("%s: Failed to find plane for display:%" PRIu32, __FUNCTION__, i);
185             return false;
186         }
187 
188         std::unique_ptr<DrmPlane> plane = std::move(*planeIt);
189         planes.erase(planeIt);
190 
191         auto display =
192             DrmDisplay::create(i, std::move(connector), std::move(crtc), std::move(plane), mFd);
193         if (!display) {
194             return false;
195         }
196         mDisplays.push_back(std::move(display));
197     }
198 
199     return true;
200 }
201 
create(const native_handle_t * handle)202 std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> DrmClient::create(
203     const native_handle_t* handle) {
204     cros_gralloc_handle* crosHandle = (cros_gralloc_handle*)handle;
205     if (crosHandle == nullptr) {
206         ALOGE("%s: invalid cros_gralloc_handle", __FUNCTION__);
207         return std::make_tuple(HWC3::Error::NoResources, nullptr);
208     }
209 
210     DrmPrimeBufferHandle primeHandle = 0;
211     int ret = drmPrimeFDToHandle(mFd.get(), crosHandle->fds[0], &primeHandle);
212     if (ret) {
213         ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
214         return std::make_tuple(HWC3::Error::NoResources, nullptr);
215     }
216 
217     auto buffer = std::shared_ptr<DrmBuffer>(new DrmBuffer(*this));
218     buffer->mWidth = crosHandle->width;
219     buffer->mHeight = crosHandle->height;
220     buffer->mDrmFormat = crosHandle->format;
221     buffer->mPlaneFds[0] = crosHandle->fds[0];
222     buffer->mPlaneHandles[0] = primeHandle;
223     buffer->mPlanePitches[0] = crosHandle->strides[0];
224     buffer->mPlaneOffsets[0] = crosHandle->offsets[0];
225 
226     uint32_t framebuffer = 0;
227     ret = drmModeAddFB2(mFd.get(), buffer->mWidth, buffer->mHeight, buffer->mDrmFormat,
228                         buffer->mPlaneHandles, buffer->mPlanePitches, buffer->mPlaneOffsets,
229                         &framebuffer, 0);
230     if (ret) {
231         ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
232         return std::make_tuple(HWC3::Error::NoResources, nullptr);
233     }
234     DEBUG_LOG("%s: created framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
235     buffer->mDrmFramebuffer = framebuffer;
236 
237     return std::make_tuple(HWC3::Error::None, std::shared_ptr<DrmBuffer>(buffer));
238 }
239 
destroyDrmFramebuffer(DrmBuffer * buffer)240 HWC3::Error DrmClient::destroyDrmFramebuffer(DrmBuffer* buffer) {
241     if (buffer->mDrmFramebuffer) {
242         uint32_t framebuffer = *buffer->mDrmFramebuffer;
243         if (drmModeRmFB(mFd.get(), framebuffer)) {
244             ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__, strerror(errno), errno);
245             return HWC3::Error::NoResources;
246         }
247         DEBUG_LOG("%s: destroyed framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
248         buffer->mDrmFramebuffer.reset();
249     }
250     if (buffer->mPlaneHandles[0]) {
251         struct drm_gem_close gem_close = {};
252         gem_close.handle = buffer->mPlaneHandles[0];
253         if (drmIoctl(mFd.get(), DRM_IOCTL_GEM_CLOSE, &gem_close)) {
254             ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__, strerror(errno),
255                   errno);
256             return HWC3::Error::NoResources;
257         }
258     }
259 
260     return HWC3::Error::None;
261 }
262 
handleHotplug()263 bool DrmClient::handleHotplug() {
264     DEBUG_LOG("%s", __FUNCTION__);
265 
266     struct HotplugToReport {
267         uint32_t id;
268         uint32_t width;
269         uint32_t height;
270         uint32_t dpiX;
271         uint32_t dpiY;
272         uint32_t rr;
273         bool connected;
274     };
275 
276     std::vector<HotplugToReport> hotplugs;
277 
278     {
279         AutoWriteLock lock(mDisplaysMutex);
280 
281         for (auto& display : mDisplays) {
282             auto change = display->checkAndHandleHotplug(mFd);
283             if (change == DrmHotplugChange::kNoChange) {
284                 continue;
285             }
286 
287             hotplugs.push_back(HotplugToReport{
288                 .id = display->getId(),
289                 .width = display->getWidth(),
290                 .height = display->getHeight(),
291                 .dpiX = display->getDpiX(),
292                 .dpiY = display->getDpiY(),
293                 .rr = display->getRefreshRateUint(),
294                 .connected = change == DrmHotplugChange::kConnected,
295             });
296         }
297     }
298 
299     for (const auto& hotplug : hotplugs) {
300         if (mHotplugCallback) {
301             (*mHotplugCallback)(hotplug.connected,  //
302                                 hotplug.id,         //
303                                 hotplug.width,      //
304                                 hotplug.height,     //
305                                 hotplug.dpiX,       //
306                                 hotplug.dpiY,       //
307                                 hotplug.rr);
308         }
309     }
310 
311     return true;
312 }
313 
flushToDisplay(int displayId,const std::shared_ptr<DrmBuffer> & buffer,::android::base::borrowed_fd inSyncFd)314 std::tuple<HWC3::Error, ::android::base::unique_fd> DrmClient::flushToDisplay(
315     int displayId, const std::shared_ptr<DrmBuffer>& buffer,
316     ::android::base::borrowed_fd inSyncFd) {
317     ATRACE_CALL();
318 
319     if (!buffer->mDrmFramebuffer) {
320         ALOGE("%s: failed, no framebuffer created.", __FUNCTION__);
321         return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
322     }
323 
324     AutoReadLock lock(mDisplaysMutex);
325     return mDisplays[displayId]->flush(mFd, inSyncFd, buffer);
326 }
327 
getEdid(uint32_t displayId)328 std::optional<std::vector<uint8_t>> DrmClient::getEdid(uint32_t displayId) {
329     AutoReadLock lock(mDisplaysMutex);
330 
331     if (displayId >= mDisplays.size()) {
332         DEBUG_LOG("%s: invalid display:%" PRIu32, __FUNCTION__, displayId);
333         return std::nullopt;
334     }
335 
336     return mDisplays[displayId]->getEdid();
337 }
338 
339 }  // namespace aidl::android::hardware::graphics::composer3::impl
340