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_);
48 #ifndef DISABLE_HOTPLUG_NOTIFICATION
54 bool DrmDisplayManager::Initialize() {
56 fd_ = drmOpen("i915", NULL);
58 ETRACE("Failed to open dri %s", PRINTERROR());
62 struct drm_set_client_cap cap = {DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1};
63 drmIoctl(fd_, DRM_IOCTL_SET_CLIENT_CAP, &cap);
64 int ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
66 ETRACE("Failed to set atomic cap %s", PRINTERROR());
70 ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
72 ETRACE("Failed to set atomic cap %d", ret);
76 ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
77 if (res->count_crtcs == 0)
80 for (int32_t i = 0; i < res->count_crtcs; ++i) {
81 ScopedDrmCrtcPtr c(drmModeGetCrtc(fd_, res->crtcs[i]));
83 ETRACE("Failed to get crtc %d", res->crtcs[i]);
87 std::unique_ptr<DrmDisplay> display(
88 new DrmDisplay(fd_, i, c->crtc_id, this));
90 displays_.emplace_back(std::move(display));
93 #ifndef DISABLE_HOTPLUG_NOTIFICATION
94 hotplug_fd_ = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
95 if (hotplug_fd_ < 0) {
96 ETRACE("Failed to create socket for hot plug monitor. %s", PRINTERROR());
100 struct sockaddr_nl addr;
101 memset(&addr, 0, sizeof(addr));
102 addr.nl_family = AF_NETLINK;
103 addr.nl_pid = getpid();
104 addr.nl_groups = 0xffffffff;
106 ret = bind(hotplug_fd_, (struct sockaddr *)&addr, sizeof(addr));
108 ETRACE("Failed to bind sockaddr_nl and hot plug monitor fd. %s",
113 fd_handler_.AddFd(hotplug_fd_);
115 IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
119 void DrmDisplayManager::HotPlugEventHandler() {
121 int fd = hotplug_fd_;
122 char buffer[DRM_HOTPLUG_EVENT_SIZE];
125 memset(&buffer, 0, sizeof(buffer));
127 bool drm_event = false, hotplug_event = false;
128 size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
129 ret = read(fd, &buffer, srclen);
132 ETRACE("Failed to read uevent. %s", PRINTERROR());
139 for (int32_t i = 0; i < ret;) {
140 char *event = buffer + i;
141 if (!strcmp(event, "DEVTYPE=drm_minor"))
143 else if (!strcmp(event, "HOTPLUG=1") || // Common hotplug request
145 "HDMI-Change")) { // Hotplug happened during suspend
146 hotplug_event = true;
149 if (hotplug_event && drm_event)
152 i += strlen(event) + 1;
155 if (drm_event && hotplug_event) {
157 "Recieved Hot Plug event related to display calling "
158 "UpdateDisplayState.");
159 UpdateDisplayState();
164 void DrmDisplayManager::HandleWait() {
165 if (fd_handler_.Poll(-1) <= 0) {
166 ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
170 void DrmDisplayManager::InitializeDisplayResources() {
171 buffer_handler_.reset(NativeBufferHandler::CreateInstance(fd_));
172 frame_buffer_manager_.reset(new FrameBufferManager(fd_));
173 if (!buffer_handler_) {
174 ETRACE("Failed to create native buffer handler instance");
178 int size = displays_.size();
179 for (int i = 0; i < size; ++i) {
180 if (!displays_.at(i)->Initialize(buffer_handler_.get())) {
181 ETRACE("Failed to Initialize Display %d", i);
186 void DrmDisplayManager::StartHotPlugMonitor() {
187 if (!UpdateDisplayState()) {
188 ETRACE("Failed to connect display.");
192 ETRACE("Failed to initalizer thread to monitor Hot Plug events. %s",
197 void DrmDisplayManager::HandleRoutine() {
199 IHOTPLUGEVENTTRACE("DisplayManager::Routine.");
200 if (fd_handler_.IsReady(hotplug_fd_)) {
201 IHOTPLUGEVENTTRACE("Recieved Hot plug notification.");
202 HotPlugEventHandler();
206 bool DrmDisplayManager::UpdateDisplayState() {
208 ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
210 ETRACE("Failed to get DrmResources resources");
215 // Start of assuming no displays are connected
216 for (auto &display : displays_) {
217 if (device_.IsReservedDrmPlane() && !display->IsConnected())
218 display->SetPlanesUpdated(false);
219 display->MarkForDisconnect();
222 connected_display_count_ = 0;
223 std::vector<NativeDisplay *> connected_displays;
224 std::vector<uint32_t> no_encoder;
225 uint32_t total_connectors = res->count_connectors;
226 for (uint32_t i = 0; i < total_connectors; ++i) {
227 ScopedDrmConnectorPtr connector(
228 drmModeGetConnector(fd_, res->connectors[i]));
230 ETRACE("Failed to get connector %d", res->connectors[i]);
233 // check if a monitor is connected.
234 if (connector->connection != DRM_MODE_CONNECTED)
236 connected_display_count_++;
239 for (uint32_t i = 0; i < total_connectors; ++i) {
240 ScopedDrmConnectorPtr connector(
241 drmModeGetConnector(fd_, res->connectors[i]));
243 ETRACE("Failed to get connector %d", res->connectors[i]);
246 // check if a monitor is connected.
247 if (connector->connection != DRM_MODE_CONNECTED)
250 // Ensure we have atleast one valid mode.
251 if (connector->count_modes == 0)
254 if (connector->encoder_id == 0) {
255 no_encoder.emplace_back(i);
259 std::vector<drmModeModeInfo> mode;
260 uint32_t preferred_mode = 0;
261 uint32_t size = connector->count_modes;
263 for (uint32_t i = 0; i < size; ++i) {
264 mode[i] = connector->modes[i];
265 // There is only one preferred mode per connector.
266 if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
271 // Lets try to find crts for any connected encoder.
272 ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd_, connector->encoder_id));
273 if (encoder && encoder->crtc_id) {
274 for (auto &display : displays_) {
276 "Trying to connect %d with crtc: %d is display connected: %d \n",
277 encoder->crtc_id, display->CrtcId(), display->IsConnected());
278 // At initilaization preferred mode is set!
279 if (!display->IsConnected() && encoder->crtc_id == display->CrtcId() &&
280 display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
282 IHOTPLUGEVENTTRACE("Connected %d with crtc: %d pipe:%d \n",
283 encoder->crtc_id, display->CrtcId(),
284 display->GetDisplayPipe());
285 // Set the modes supported for each display
286 display->SetDrmModeInfo(mode);
293 // Deal with connectors with encoder_id == 0.
294 uint32_t size = no_encoder.size();
295 for (uint32_t i = 0; i < size; ++i) {
296 ScopedDrmConnectorPtr connector(
297 drmModeGetConnector(fd_, res->connectors[no_encoder.at(i)]));
299 ETRACE("Failed to get connector %d", res->connectors[i]);
303 std::vector<drmModeModeInfo> mode;
304 uint32_t preferred_mode = 0;
305 uint32_t size = connector->count_modes;
307 for (uint32_t i = 0; i < size; ++i) {
308 mode[i] = connector->modes[i];
309 // There is only one preferred mode per connector.
310 if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
315 // Try to find an encoder for the connector.
316 size = connector->count_encoders;
317 for (uint32_t j = 0; j < size; ++j) {
318 ScopedDrmEncoderPtr encoder(
319 drmModeGetEncoder(fd_, connector->encoders[j]));
323 for (auto &display : displays_) {
324 if (!display->IsConnected() &&
325 (encoder->possible_crtcs & (1 << display->GetDisplayPipe())) &&
326 display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
328 IHOTPLUGEVENTTRACE("Connected with crtc: %d pipe:%d \n",
329 display->CrtcId(), display->GetDisplayPipe());
330 // Set the modes supported for each display
331 display->SetDrmModeInfo(mode);
338 for (auto &display : displays_) {
339 if (!display->IsConnected()) {
340 display->DisConnect();
341 } else if (callback_) {
342 connected_displays.emplace_back(display.get());
347 callback_->Callback(connected_displays);
351 #ifndef ENABLE_ANDROID_WA
352 notify_client_ = true;
355 if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
356 IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
357 notify_client_, displays_.at(0)->IsConnected());
358 NotifyClientsOfDisplayChangeStatus();
361 // update plane list for reservation
362 if (device_.IsReservedDrmPlane())
363 RemoveUnreservedPlanes();
368 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
371 for (auto &display : displays_) {
372 if (!display->IsConnected()) {
373 display->NotifyClientOfDisConnectedState();
375 display->NotifyClientOfConnectedState();
379 #ifdef ENABLE_ANDROID_WA
380 notify_client_ = true;
386 NativeDisplay *DrmDisplayManager::CreateVirtualDisplay(uint32_t display_index) {
388 NativeDisplay *latest_display;
389 std::unique_ptr<VirtualDisplay> display(
390 new VirtualDisplay(fd_, buffer_handler_.get(), display_index, 0));
391 virtual_displays_.emplace(display_index, std::move(display));
392 latest_display = virtual_displays_.at(display_index).get();
394 return latest_display;
397 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
399 virtual_displays_.at(display_index).reset(nullptr);
400 virtual_displays_.erase(display_index);
404 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
406 std::vector<NativeDisplay *> all_displays;
407 size_t size = displays_.size();
408 for (size_t i = 0; i < size; ++i) {
409 all_displays.emplace_back(displays_.at(i).get());
415 void DrmDisplayManager::RegisterHotPlugEventCallback(
416 std::shared_ptr<DisplayHotPlugEventCallback> callback) {
418 callback_ = callback;
422 void DrmDisplayManager::ForceRefresh() {
424 ignore_updates_ = false;
425 size_t size = displays_.size();
426 for (size_t i = 0; i < size; ++i) {
427 displays_.at(i)->ForceRefresh();
430 release_lock_ = true;
434 void DrmDisplayManager::IgnoreUpdates() {
436 ignore_updates_ = true;
439 size_t size = displays_.size();
440 for (size_t i = 0; i < size; ++i) {
441 displays_.at(i)->IgnoreUpdates();
445 void DrmDisplayManager::setDrmMaster() {
446 int ret = drmSetMaster(fd_);
449 ret = drmSetMaster(fd_);
451 ETRACE("Failed to call drmSetMaster : %s", PRINTERROR());
456 void DrmDisplayManager::HandleLazyInitialization() {
459 device_.DisableWatch();
460 release_lock_ = false;
465 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
466 return connected_display_count_;
469 DisplayManager *DisplayManager::CreateDisplayManager() {
470 return new DrmDisplayManager();
473 void DrmDisplayManager::EnableHDCPSessionForDisplay(
474 uint32_t connector, HWCContentType content_type) {
475 size_t size = displays_.size();
476 for (size_t i = 0; i < size; i++) {
477 if (displays_.at(i)->GetConnectorID() == connector) {
478 displays_.at(i)->SetHDCPState(HWCContentProtection::kDesired,
484 void DrmDisplayManager::EnableHDCPSessionForAllDisplays(
485 HWCContentType content_type) {
486 size_t size = displays_.size();
487 for (size_t i = 0; i < size; i++) {
488 displays_.at(i)->SetHDCPState(HWCContentProtection::kDesired, content_type);
492 void DrmDisplayManager::DisableHDCPSessionForDisplay(uint32_t connector) {
493 size_t size = displays_.size();
494 for (size_t i = 0; i < size; i++) {
495 if (displays_.at(i)->GetConnectorID() == connector) {
496 displays_.at(i)->SetHDCPState(HWCContentProtection::kUnDesired,
497 HWCContentType::kInvalid);
502 void DrmDisplayManager::DisableHDCPSessionForAllDisplays() {
503 size_t size = displays_.size();
504 for (size_t i = 0; i < size; i++) {
505 displays_.at(i)->SetHDCPState(HWCContentProtection::kUnDesired,
506 HWCContentType::kInvalid);
510 void DrmDisplayManager::SetHDCPSRMForAllDisplays(const int8_t *SRM,
511 uint32_t SRMLength) {
512 size_t size = displays_.size();
513 for (size_t i = 0; i < size; i++) {
514 displays_.at(i)->SetHDCPSRM(SRM, SRMLength);
518 void DrmDisplayManager::SetHDCPSRMForDisplay(uint32_t connector,
520 uint32_t SRMLength) {
521 size_t size = displays_.size();
522 for (size_t i = 0; i < size; i++) {
523 if (displays_.at(i)->GetConnectorID() == connector) {
524 displays_.at(i)->SetHDCPSRM(SRM, SRMLength);
529 void DrmDisplayManager::RemoveUnreservedPlanes() {
530 size_t size = displays_.size();
531 for (uint8_t i = 0; i < size; i++) {
532 if (!displays_.at(i)->IsConnected() || displays_.at(i)->IsPlanesUpdated())
534 std::vector<uint32_t> reserved_planes = device_.GetDisplayReservedPlanes(i);
535 if (!reserved_planes.empty() && reserved_planes.size() < 4)
536 displays_.at(i)->ReleaseUnreservedPlanes(reserved_planes);
537 displays_.at(i)->SetPlanesUpdated(true);
541 FrameBufferManager *DrmDisplayManager::GetFrameBufferManager() {
542 return frame_buffer_manager_.get();
545 #ifdef ENABLE_PANORAMA
546 NativeDisplay *DrmDisplayManager::CreateVirtualPanoramaDisplay(
547 uint32_t display_index) {
548 NativeDisplay *latest_display;
549 latest_display = (NativeDisplay *)new VirtualPanoramaDisplay(
550 fd_, buffer_handler_.get(), display_index, 0);
551 return latest_display;
555 } // namespace hwcomposer