OSDN Git Service

c1aac7d464075d4e2a7d7713463efa009f52392d
[android-x86/external-IA-Hardware-Composer.git] / wsi / drm / drmdisplaymanager.cpp
1 /*
2 // Copyright (c) 2016 Intel Corporation
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 "drmdisplaymanager.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <sys/mman.h>
23 #include <sys/socket.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <xf86drm.h>
29 #include <xf86drmMode.h>
30
31 #include <linux/netlink.h>
32 #include <linux/types.h>
33
34 #include <gpudevice.h>
35 #include <hwctrace.h>
36
37 #include <nativebufferhandler.h>
38
39 namespace hwcomposer {
40
41 DrmDisplayManager::DrmDisplayManager() : HWCThread(-8, "DisplayManager") {
42   CTRACE();
43 }
44
45 DrmDisplayManager::~DrmDisplayManager() {
46   CTRACE();
47   std::vector<std::unique_ptr<DrmDisplay>>().swap(displays_);
48 #ifndef DISABLE_HOTPLUG_NOTIFICATION
49   close(hotplug_fd_);
50 #endif
51   drmClose(fd_);
52 }
53
54 bool DrmDisplayManager::Initialize() {
55   CTRACE();
56   fd_ = drmOpen("i915", NULL);
57   if (fd_ < 0) {
58     ETRACE("Failed to open dri %s", PRINTERROR());
59     return -ENODEV;
60   }
61
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);
65   if (ret) {
66     ETRACE("Failed to set atomic cap %s", PRINTERROR());
67     return false;
68   }
69
70   ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
71   if (ret) {
72     ETRACE("Failed to set atomic cap %d", ret);
73     return false;
74   }
75
76   ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
77   if (res->count_crtcs == 0)
78     return false;
79
80   for (int32_t i = 0; i < res->count_crtcs; ++i) {
81     ScopedDrmCrtcPtr c(drmModeGetCrtc(fd_, res->crtcs[i]));
82     if (!c) {
83       ETRACE("Failed to get crtc %d", res->crtcs[i]);
84       return false;
85     }
86
87     std::unique_ptr<DrmDisplay> display(
88         new DrmDisplay(fd_, i, c->crtc_id, this));
89
90     displays_.emplace_back(std::move(display));
91   }
92
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());
97     return true;
98   }
99
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;
105
106   ret = bind(hotplug_fd_, (struct sockaddr *)&addr, sizeof(addr));
107   if (ret) {
108     ETRACE("Failed to bind sockaddr_nl and hot plug monitor fd. %s",
109            PRINTERROR());
110     return true;
111   }
112
113   fd_handler_.AddFd(hotplug_fd_);
114 #endif
115   IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
116   return true;
117 }
118
119 void DrmDisplayManager::HotPlugEventHandler() {
120   CTRACE();
121   int fd = hotplug_fd_;
122   char buffer[DRM_HOTPLUG_EVENT_SIZE];
123   int ret;
124
125   memset(&buffer, 0, sizeof(buffer));
126   while (true) {
127     bool drm_event = false, hotplug_event = false;
128     size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
129     ret = read(fd, &buffer, srclen);
130     if (ret <= 0) {
131       if (ret < 0)
132         ETRACE("Failed to read uevent. %s", PRINTERROR());
133
134       return;
135     }
136
137     buffer[ret] = '\0';
138
139     for (int32_t i = 0; i < ret;) {
140       char *event = buffer + i;
141       if (!strcmp(event, "DEVTYPE=drm_minor"))
142         drm_event = true;
143       else if (!strcmp(event, "HOTPLUG=1") ||  // Common hotplug request
144                !strcmp(event,
145                        "HDMI-Change")) {  // Hotplug happened during suspend
146         hotplug_event = true;
147       }
148
149       if (hotplug_event && drm_event)
150         break;
151
152       i += strlen(event) + 1;
153     }
154
155     if (drm_event && hotplug_event) {
156       IHOTPLUGEVENTTRACE(
157           "Recieved Hot Plug event related to display calling "
158           "UpdateDisplayState.");
159       UpdateDisplayState();
160     }
161   }
162 }
163
164 void DrmDisplayManager::HandleWait() {
165   if (fd_handler_.Poll(-1) <= 0) {
166     ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
167   }
168 }
169
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");
175     return;
176   }
177
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);
182     }
183   }
184 }
185
186 void DrmDisplayManager::StartHotPlugMonitor() {
187   if (!UpdateDisplayState()) {
188     ETRACE("Failed to connect display.");
189   }
190
191   if (!InitWorker()) {
192     ETRACE("Failed to initalizer thread to monitor Hot Plug events. %s",
193            PRINTERROR());
194   }
195 }
196
197 void DrmDisplayManager::HandleRoutine() {
198   CTRACE();
199   IHOTPLUGEVENTTRACE("DisplayManager::Routine.");
200   if (fd_handler_.IsReady(hotplug_fd_)) {
201     IHOTPLUGEVENTTRACE("Recieved Hot plug notification.");
202     HotPlugEventHandler();
203   }
204 }
205
206 bool DrmDisplayManager::UpdateDisplayState() {
207   CTRACE();
208   ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
209   if (!res) {
210     ETRACE("Failed to get DrmResources resources");
211     return false;
212   }
213
214   spin_lock_.lock();
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();
220   }
221
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]));
229     if (!connector) {
230       ETRACE("Failed to get connector %d", res->connectors[i]);
231       break;
232     }
233     // check if a monitor is connected.
234     if (connector->connection != DRM_MODE_CONNECTED)
235       continue;
236     connected_display_count_++;
237   }
238
239   for (uint32_t i = 0; i < total_connectors; ++i) {
240     ScopedDrmConnectorPtr connector(
241         drmModeGetConnector(fd_, res->connectors[i]));
242     if (!connector) {
243       ETRACE("Failed to get connector %d", res->connectors[i]);
244       break;
245     }
246     // check if a monitor is connected.
247     if (connector->connection != DRM_MODE_CONNECTED)
248       continue;
249
250     // Ensure we have atleast one valid mode.
251     if (connector->count_modes == 0)
252       continue;
253
254     if (connector->encoder_id == 0) {
255       no_encoder.emplace_back(i);
256       continue;
257     }
258
259     std::vector<drmModeModeInfo> mode;
260     uint32_t preferred_mode = 0;
261     uint32_t size = connector->count_modes;
262     mode.resize(size);
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) {
267         preferred_mode = i;
268       }
269     }
270
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_) {
275         IHOTPLUGEVENTTRACE(
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(),
281                                     preferred_mode)) {
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);
287           break;
288         }
289       }
290     }
291   }
292
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)]));
298     if (!connector) {
299       ETRACE("Failed to get connector %d", res->connectors[i]);
300       break;
301     }
302
303     std::vector<drmModeModeInfo> mode;
304     uint32_t preferred_mode = 0;
305     uint32_t size = connector->count_modes;
306     mode.resize(size);
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) {
311         preferred_mode = i;
312       }
313     }
314
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]));
320       if (!encoder)
321         continue;
322
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(),
327                                     preferred_mode)) {
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);
332           break;
333         }
334       }
335     }
336   }
337
338   for (auto &display : displays_) {
339     if (!display->IsConnected()) {
340       display->DisConnect();
341     } else if (callback_) {
342       connected_displays.emplace_back(display.get());
343     }
344   }
345
346   if (callback_) {
347     callback_->Callback(connected_displays);
348   }
349
350   spin_lock_.unlock();
351 #ifndef ENABLE_ANDROID_WA
352   notify_client_ = true;
353 #endif
354
355   if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
356     IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
357                        notify_client_, displays_.at(0)->IsConnected());
358     NotifyClientsOfDisplayChangeStatus();
359   }
360
361   // update plane list for reservation
362   if (device_.IsReservedDrmPlane())
363     RemoveUnreservedPlanes();
364
365   return true;
366 }
367
368 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
369   spin_lock_.lock();
370
371   for (auto &display : displays_) {
372     if (!display->IsConnected()) {
373       display->NotifyClientOfDisConnectedState();
374     } else {
375       display->NotifyClientOfConnectedState();
376     }
377   }
378
379 #ifdef ENABLE_ANDROID_WA
380   notify_client_ = true;
381 #endif
382
383   spin_lock_.unlock();
384 }
385
386 NativeDisplay *DrmDisplayManager::CreateVirtualDisplay(uint32_t display_index) {
387   spin_lock_.lock();
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();
393   spin_lock_.unlock();
394   return latest_display;
395 }
396
397 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
398   spin_lock_.lock();
399   virtual_displays_.at(display_index).reset(nullptr);
400   virtual_displays_.erase(display_index);
401   spin_lock_.unlock();
402 }
403
404 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
405   spin_lock_.lock();
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());
410   }
411   spin_lock_.unlock();
412   return all_displays;
413 }
414
415 void DrmDisplayManager::RegisterHotPlugEventCallback(
416     std::shared_ptr<DisplayHotPlugEventCallback> callback) {
417   spin_lock_.lock();
418   callback_ = callback;
419   spin_lock_.unlock();
420 }
421
422 void DrmDisplayManager::ForceRefresh() {
423   spin_lock_.lock();
424   ignore_updates_ = false;
425   size_t size = displays_.size();
426   for (size_t i = 0; i < size; ++i) {
427     displays_.at(i)->ForceRefresh();
428   }
429
430   release_lock_ = true;
431   spin_lock_.unlock();
432 }
433
434 void DrmDisplayManager::IgnoreUpdates() {
435   spin_lock_.lock();
436   ignore_updates_ = true;
437   spin_lock_.unlock();
438
439   size_t size = displays_.size();
440   for (size_t i = 0; i < size; ++i) {
441     displays_.at(i)->IgnoreUpdates();
442   }
443 }
444
445 void DrmDisplayManager::setDrmMaster() {
446   int ret = drmSetMaster(fd_);
447   while (ret) {
448     usleep(10000);
449     ret = drmSetMaster(fd_);
450     if (ret) {
451       ETRACE("Failed to call drmSetMaster : %s", PRINTERROR());
452     }
453   }
454 }
455
456 void DrmDisplayManager::HandleLazyInitialization() {
457   spin_lock_.lock();
458   if (release_lock_) {
459     device_.DisableWatch();
460     release_lock_ = false;
461   }
462   spin_lock_.unlock();
463 }
464
465 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
466   return connected_display_count_;
467 }
468
469 DisplayManager *DisplayManager::CreateDisplayManager() {
470   return new DrmDisplayManager();
471 }
472
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,
479                                     content_type);
480     }
481   }
482 }
483
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);
489   }
490 }
491
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);
498     }
499   }
500 }
501
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);
507   }
508 }
509
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);
515   }
516 }
517
518 void DrmDisplayManager::SetHDCPSRMForDisplay(uint32_t connector,
519                                              const int8_t *SRM,
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);
525     }
526   }
527 }
528
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())
533       continue;
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);
538   }
539 }
540
541 FrameBufferManager *DrmDisplayManager::GetFrameBufferManager() {
542   return frame_buffer_manager_.get();
543 }
544
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;
552 }
553 #endif
554
555 }  // namespace hwcomposer