2 // Copyright (c) 2016 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "drmdisplaymanager.h"
23 #include <sys/socket.h>
25 #include <sys/types.h>
29 #include <xf86drmMode.h>
31 #include <linux/netlink.h>
32 #include <linux/types.h>
34 #include <gpudevice.h>
37 #include <nativebufferhandler.h>
39 namespace hwcomposer {
41 DrmDisplayManager::DrmDisplayManager() : HWCThread(-8, "DisplayManager") {
45 DrmDisplayManager::~DrmDisplayManager() {
47 std::vector<std::unique_ptr<DrmDisplay>>().swap(displays_);
49 #ifndef DISABLE_HOTPLUG_NOTIFICATION
55 bool DrmDisplayManager::Initialize() {
57 fd_ = drmOpen("i915", NULL);
59 ETRACE("Failed to open dri %s", PRINTERROR());
63 struct drm_set_client_cap cap = {DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1};
64 drmIoctl(fd_, DRM_IOCTL_SET_CLIENT_CAP, &cap);
65 int ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
67 ETRACE("Failed to set atomic cap %s", PRINTERROR());
71 ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
73 ETRACE("Failed to set atomic cap %d", ret);
77 ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
78 if (res->count_crtcs == 0)
81 for (int32_t i = 0; i < res->count_crtcs; ++i) {
82 ScopedDrmCrtcPtr c(drmModeGetCrtc(fd_, res->crtcs[i]));
84 ETRACE("Failed to get crtc %d", res->crtcs[i]);
88 std::unique_ptr<DrmDisplay> display(
89 new DrmDisplay(fd_, i, c->crtc_id, this));
91 displays_.emplace_back(std::move(display));
94 #ifndef DISABLE_HOTPLUG_NOTIFICATION
95 hotplug_fd_ = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
96 if (hotplug_fd_ < 0) {
97 ETRACE("Failed to create socket for hot plug monitor. %s", PRINTERROR());
101 struct sockaddr_nl addr;
102 memset(&addr, 0, sizeof(addr));
103 addr.nl_family = AF_NETLINK;
104 addr.nl_pid = getpid();
105 addr.nl_groups = 0xffffffff;
107 ret = bind(hotplug_fd_, (struct sockaddr *)&addr, sizeof(addr));
109 ETRACE("Failed to bind sockaddr_nl and hot plug monitor fd. %s",
114 fd_handler_.AddFd(hotplug_fd_);
117 IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
121 void DrmDisplayManager::HotPlugEventHandler() {
123 int fd = hotplug_fd_;
124 char buffer[DRM_HOTPLUG_EVENT_SIZE];
127 memset(&buffer, 0, sizeof(buffer));
129 bool drm_event = false, hotplug_event = false;
130 size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
131 ret = read(fd, &buffer, srclen);
134 ETRACE("Failed to read uevent. %s", PRINTERROR());
141 for (int32_t i = 0; i < ret;) {
142 char *event = buffer + i;
143 if (!strcmp(event, "DEVTYPE=drm_minor"))
145 else if (!strcmp(event, "HOTPLUG=1") || // Common hotplug request
147 "HDMI-Change")) { // Hotplug happened during suspend
148 hotplug_event = true;
151 if (hotplug_event && drm_event)
154 i += strlen(event) + 1;
157 if (drm_event && hotplug_event) {
159 "Recieved Hot Plug event related to display calling "
160 "UpdateDisplayState.");
161 UpdateDisplayState();
166 void DrmDisplayManager::HandleWait() {
167 if (fd_handler_.Poll(-1) <= 0) {
168 ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
172 void DrmDisplayManager::InitializeDisplayResources() {
173 buffer_handler_.reset(NativeBufferHandler::CreateInstance(fd_));
174 frame_buffer_manager_.reset(new FrameBufferManager(fd_));
175 if (!buffer_handler_) {
176 ETRACE("Failed to create native buffer handler instance");
180 int size = displays_.size();
181 for (int i = 0; i < size; ++i) {
182 if (!displays_.at(i)->Initialize(buffer_handler_.get())) {
183 ETRACE("Failed to Initialize Display %d", i);
188 void DrmDisplayManager::StartHotPlugMonitor() {
189 if (!UpdateDisplayState()) {
190 ETRACE("Failed to connect display.");
194 ETRACE("Failed to initalizer thread to monitor Hot Plug events. %s",
199 void DrmDisplayManager::HandleRoutine() {
201 IHOTPLUGEVENTTRACE("DisplayManager::Routine.");
202 if (fd_handler_.IsReady(hotplug_fd_)) {
203 IHOTPLUGEVENTTRACE("Recieved Hot plug notification.");
204 HotPlugEventHandler();
208 bool DrmDisplayManager::UpdateDisplayState() {
210 ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
212 ETRACE("Failed to get DrmResources resources");
217 // Start of assuming no displays are connected
218 for (auto &display : displays_) {
219 if (device_.IsReservedDrmPlane() && !display->IsConnected())
220 display->SetPlanesUpdated(false);
221 display->MarkForDisconnect();
224 connected_display_count_ = 0;
225 std::vector<NativeDisplay *> connected_displays;
226 std::vector<uint32_t> no_encoder;
227 uint32_t total_connectors = res->count_connectors;
228 for (uint32_t i = 0; i < total_connectors; ++i) {
229 ScopedDrmConnectorPtr connector(
230 drmModeGetConnector(fd_, res->connectors[i]));
232 ETRACE("Failed to get connector %d", res->connectors[i]);
235 // check if a monitor is connected.
236 if (connector->connection != DRM_MODE_CONNECTED)
238 connected_display_count_++;
241 for (uint32_t i = 0; i < total_connectors; ++i) {
242 ScopedDrmConnectorPtr connector(
243 drmModeGetConnector(fd_, res->connectors[i]));
245 ETRACE("Failed to get connector %d", res->connectors[i]);
248 // check if a monitor is connected.
249 if (connector->connection != DRM_MODE_CONNECTED)
252 // Ensure we have atleast one valid mode.
253 if (connector->count_modes == 0)
256 if (connector->encoder_id == 0) {
257 no_encoder.emplace_back(i);
261 std::vector<drmModeModeInfo> mode;
262 uint32_t preferred_mode = 0;
263 uint32_t size = connector->count_modes;
265 for (uint32_t i = 0; i < size; ++i) {
266 mode[i] = connector->modes[i];
267 // There is only one preferred mode per connector.
268 if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
273 // Lets try to find crts for any connected encoder.
274 ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd_, connector->encoder_id));
275 if (encoder && encoder->crtc_id) {
276 for (auto &display : displays_) {
278 "Trying to connect %d with crtc: %d is display connected: %d \n",
279 encoder->crtc_id, display->CrtcId(), display->IsConnected());
280 // At initilaization preferred mode is set!
281 if (!display->IsConnected() && encoder->crtc_id == display->CrtcId() &&
282 display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
284 IHOTPLUGEVENTTRACE("Connected %d with crtc: %d pipe:%d \n",
285 encoder->crtc_id, display->CrtcId(),
286 display->GetDisplayPipe());
287 // Set the modes supported for each display
288 display->SetDrmModeInfo(mode);
295 // Deal with connectors with encoder_id == 0.
296 uint32_t size = no_encoder.size();
297 for (uint32_t i = 0; i < size; ++i) {
298 ScopedDrmConnectorPtr connector(
299 drmModeGetConnector(fd_, res->connectors[no_encoder.at(i)]));
301 ETRACE("Failed to get connector %d", res->connectors[i]);
305 std::vector<drmModeModeInfo> mode;
306 uint32_t preferred_mode = 0;
307 uint32_t size = connector->count_modes;
309 for (uint32_t i = 0; i < size; ++i) {
310 mode[i] = connector->modes[i];
311 // There is only one preferred mode per connector.
312 if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
317 // Try to find an encoder for the connector.
318 size = connector->count_encoders;
319 for (uint32_t j = 0; j < size; ++j) {
320 ScopedDrmEncoderPtr encoder(
321 drmModeGetEncoder(fd_, connector->encoders[j]));
325 for (auto &display : displays_) {
326 if (!display->IsConnected() &&
327 (encoder->possible_crtcs & (1 << display->GetDisplayPipe())) &&
328 display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
330 IHOTPLUGEVENTTRACE("Connected with crtc: %d pipe:%d \n",
331 display->CrtcId(), display->GetDisplayPipe());
332 // Set the modes supported for each display
333 display->SetDrmModeInfo(mode);
340 for (auto &display : displays_) {
341 if (!display->IsConnected()) {
342 display->DisConnect();
343 } else if (callback_) {
344 connected_displays.emplace_back(display.get());
349 callback_->Callback(connected_displays);
353 #ifndef ENABLE_ANDROID_WA
354 notify_client_ = true;
357 if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
358 IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
359 notify_client_, displays_.at(0)->IsConnected());
360 NotifyClientsOfDisplayChangeStatus();
363 // update plane list for reservation
364 if (device_.IsReservedDrmPlane())
365 RemoveUnreservedPlanes();
370 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
373 for (auto &display : displays_) {
374 if (!display->IsConnected()) {
375 display->NotifyClientOfDisConnectedState();
377 display->NotifyClientOfConnectedState();
381 #ifdef ENABLE_ANDROID_WA
382 notify_client_ = true;
388 NativeDisplay *DrmDisplayManager::CreateVirtualDisplay(uint32_t display_index) {
390 NativeDisplay *latest_display;
391 std::unique_ptr<VirtualDisplay> display(
392 new VirtualDisplay(fd_, buffer_handler_.get(), display_index, 0));
393 virtual_displays_.emplace(display_index, std::move(display));
394 latest_display = virtual_displays_.at(display_index).get();
396 return latest_display;
399 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
401 virtual_displays_.at(display_index).reset(nullptr);
402 virtual_displays_.erase(display_index);
406 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
408 std::vector<NativeDisplay *> all_displays;
409 size_t size = displays_.size();
410 for (size_t i = 0; i < size; ++i) {
411 all_displays.emplace_back(displays_.at(i).get());
417 void DrmDisplayManager::RegisterHotPlugEventCallback(
418 std::shared_ptr<DisplayHotPlugEventCallback> callback) {
420 callback_ = callback;
424 void DrmDisplayManager::ForceRefresh() {
426 ignore_updates_ = false;
427 size_t size = displays_.size();
428 for (size_t i = 0; i < size; ++i) {
429 displays_.at(i)->ForceRefresh();
432 release_lock_ = true;
436 void DrmDisplayManager::IgnoreUpdates() {
438 ignore_updates_ = true;
441 size_t size = displays_.size();
442 for (size_t i = 0; i < size; ++i) {
443 displays_.at(i)->IgnoreUpdates();
447 void DrmDisplayManager::setDrmMaster(bool must_set) {
454 uint8_t retry_times = 0;
456 ret = drmSetMaster(fd_);
460 ETRACE("Failed to call drmSetMaster : %s", PRINTERROR());
463 ITRACE("Successfully set as DRM master.");
466 } while (ret && retry_times < 10);
470 void DrmDisplayManager::DropDrmMaster() {
477 uint8_t retry_times = 0;
479 ret = drmDropMaster(fd_);
482 ETRACE("Failed to call drmDropMaster : %s", PRINTERROR());
485 ITRACE("Successfully drop DRM master.");
488 } while (ret && retry_times < 10);
492 void DrmDisplayManager::HandleLazyInitialization() {
495 device_.DisableWatch();
496 release_lock_ = false;
501 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
502 return connected_display_count_;
505 DisplayManager *DisplayManager::CreateDisplayManager() {
506 return new DrmDisplayManager();
509 void DrmDisplayManager::EnableHDCPSessionForDisplay(
510 uint32_t connector, HWCContentType content_type) {
511 size_t size = displays_.size();
512 for (size_t i = 0; i < size; i++) {
513 if (displays_.at(i)->GetConnectorID() == connector) {
514 displays_.at(i)->SetHDCPState(HWCContentProtection::kDesired,
520 void DrmDisplayManager::EnableHDCPSessionForAllDisplays(
521 HWCContentType content_type) {
522 size_t size = displays_.size();
523 for (size_t i = 0; i < size; i++) {
524 displays_.at(i)->SetHDCPState(HWCContentProtection::kDesired, content_type);
528 void DrmDisplayManager::DisableHDCPSessionForDisplay(uint32_t connector) {
529 size_t size = displays_.size();
530 for (size_t i = 0; i < size; i++) {
531 if (displays_.at(i)->GetConnectorID() == connector) {
532 displays_.at(i)->SetHDCPState(HWCContentProtection::kUnDesired,
533 HWCContentType::kInvalid);
538 void DrmDisplayManager::DisableHDCPSessionForAllDisplays() {
539 size_t size = displays_.size();
540 for (size_t i = 0; i < size; i++) {
541 displays_.at(i)->SetHDCPState(HWCContentProtection::kUnDesired,
542 HWCContentType::kInvalid);
546 void DrmDisplayManager::SetHDCPSRMForAllDisplays(const int8_t *SRM,
547 uint32_t SRMLength) {
548 size_t size = displays_.size();
549 for (size_t i = 0; i < size; i++) {
550 displays_.at(i)->SetHDCPSRM(SRM, SRMLength);
554 void DrmDisplayManager::SetHDCPSRMForDisplay(uint32_t connector,
556 uint32_t SRMLength) {
557 size_t size = displays_.size();
558 for (size_t i = 0; i < size; i++) {
559 if (displays_.at(i)->GetConnectorID() == connector) {
560 displays_.at(i)->SetHDCPSRM(SRM, SRMLength);
565 void DrmDisplayManager::RemoveUnreservedPlanes() {
566 size_t size = displays_.size();
567 for (uint8_t i = 0; i < size; i++) {
568 if (!displays_.at(i)->IsConnected() || displays_.at(i)->IsPlanesUpdated())
570 std::vector<uint32_t> reserved_planes = device_.GetDisplayReservedPlanes(i);
571 if (!reserved_planes.empty() && reserved_planes.size() < 4)
572 displays_.at(i)->ReleaseUnreservedPlanes(reserved_planes);
573 displays_.at(i)->SetPlanesUpdated(true);
577 FrameBufferManager *DrmDisplayManager::GetFrameBufferManager() {
578 return frame_buffer_manager_.get();
581 #ifdef ENABLE_PANORAMA
582 NativeDisplay *DrmDisplayManager::CreateVirtualPanoramaDisplay(
583 uint32_t display_index) {
584 NativeDisplay *latest_display;
585 latest_display = (NativeDisplay *)new VirtualPanoramaDisplay(
586 fd_, buffer_handler_.get(), display_index, 0);
587 return latest_display;
591 } // namespace hwcomposer