OSDN Git Service

Update GPUDevice thread for DRM-master setting/dropping
[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
49 #ifndef DISABLE_HOTPLUG_NOTIFICATION
50   close(hotplug_fd_);
51 #endif
52   drmClose(fd_);
53 }
54
55 bool DrmDisplayManager::Initialize() {
56   CTRACE();
57   fd_ = drmOpen("i915", NULL);
58   if (fd_ < 0) {
59     ETRACE("Failed to open dri %s", PRINTERROR());
60     return -ENODEV;
61   }
62
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);
66   if (ret) {
67     ETRACE("Failed to set atomic cap %s", PRINTERROR());
68     return false;
69   }
70
71   ret = drmSetClientCap(fd_, DRM_CLIENT_CAP_ATOMIC, 1);
72   if (ret) {
73     ETRACE("Failed to set atomic cap %d", ret);
74     return false;
75   }
76
77   ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
78   if (res->count_crtcs == 0)
79     return false;
80
81   for (int32_t i = 0; i < res->count_crtcs; ++i) {
82     ScopedDrmCrtcPtr c(drmModeGetCrtc(fd_, res->crtcs[i]));
83     if (!c) {
84       ETRACE("Failed to get crtc %d", res->crtcs[i]);
85       return false;
86     }
87
88     std::unique_ptr<DrmDisplay> display(
89         new DrmDisplay(fd_, i, c->crtc_id, this));
90
91     displays_.emplace_back(std::move(display));
92   }
93
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());
98     return true;
99   }
100
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;
106
107   ret = bind(hotplug_fd_, (struct sockaddr *)&addr, sizeof(addr));
108   if (ret) {
109     ETRACE("Failed to bind sockaddr_nl and hot plug monitor fd. %s",
110            PRINTERROR());
111     return true;
112   }
113
114   fd_handler_.AddFd(hotplug_fd_);
115 #endif
116
117   IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
118   return true;
119 }
120
121 void DrmDisplayManager::HotPlugEventHandler() {
122   CTRACE();
123   int fd = hotplug_fd_;
124   char buffer[DRM_HOTPLUG_EVENT_SIZE];
125   int ret;
126
127   memset(&buffer, 0, sizeof(buffer));
128   while (true) {
129     bool drm_event = false, hotplug_event = false;
130     size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
131     ret = read(fd, &buffer, srclen);
132     if (ret <= 0) {
133       if (ret < 0)
134         ETRACE("Failed to read uevent. %s", PRINTERROR());
135
136       return;
137     }
138
139     buffer[ret] = '\0';
140
141     for (int32_t i = 0; i < ret;) {
142       char *event = buffer + i;
143       if (!strcmp(event, "DEVTYPE=drm_minor"))
144         drm_event = true;
145       else if (!strcmp(event, "HOTPLUG=1") ||  // Common hotplug request
146                !strcmp(event,
147                        "HDMI-Change")) {  // Hotplug happened during suspend
148         hotplug_event = true;
149       }
150
151       if (hotplug_event && drm_event)
152         break;
153
154       i += strlen(event) + 1;
155     }
156
157     if (drm_event && hotplug_event) {
158       IHOTPLUGEVENTTRACE(
159           "Recieved Hot Plug event related to display calling "
160           "UpdateDisplayState.");
161       UpdateDisplayState();
162     }
163   }
164 }
165
166 void DrmDisplayManager::HandleWait() {
167   if (fd_handler_.Poll(-1) <= 0) {
168     ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
169   }
170 }
171
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");
177     return;
178   }
179
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);
184     }
185   }
186 }
187
188 void DrmDisplayManager::StartHotPlugMonitor() {
189   if (!UpdateDisplayState()) {
190     ETRACE("Failed to connect display.");
191   }
192
193   if (!InitWorker()) {
194     ETRACE("Failed to initalizer thread to monitor Hot Plug events. %s",
195            PRINTERROR());
196   }
197 }
198
199 void DrmDisplayManager::HandleRoutine() {
200   CTRACE();
201   IHOTPLUGEVENTTRACE("DisplayManager::Routine.");
202   if (fd_handler_.IsReady(hotplug_fd_)) {
203     IHOTPLUGEVENTTRACE("Recieved Hot plug notification.");
204     HotPlugEventHandler();
205   }
206 }
207
208 bool DrmDisplayManager::UpdateDisplayState() {
209   CTRACE();
210   ScopedDrmResourcesPtr res(drmModeGetResources(fd_));
211   if (!res) {
212     ETRACE("Failed to get DrmResources resources");
213     return false;
214   }
215
216   spin_lock_.lock();
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();
222   }
223
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]));
231     if (!connector) {
232       ETRACE("Failed to get connector %d", res->connectors[i]);
233       break;
234     }
235     // check if a monitor is connected.
236     if (connector->connection != DRM_MODE_CONNECTED)
237       continue;
238     connected_display_count_++;
239   }
240
241   for (uint32_t i = 0; i < total_connectors; ++i) {
242     ScopedDrmConnectorPtr connector(
243         drmModeGetConnector(fd_, res->connectors[i]));
244     if (!connector) {
245       ETRACE("Failed to get connector %d", res->connectors[i]);
246       break;
247     }
248     // check if a monitor is connected.
249     if (connector->connection != DRM_MODE_CONNECTED)
250       continue;
251
252     // Ensure we have atleast one valid mode.
253     if (connector->count_modes == 0)
254       continue;
255
256     if (connector->encoder_id == 0) {
257       no_encoder.emplace_back(i);
258       continue;
259     }
260
261     std::vector<drmModeModeInfo> mode;
262     uint32_t preferred_mode = 0;
263     uint32_t size = connector->count_modes;
264     mode.resize(size);
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) {
269         preferred_mode = i;
270       }
271     }
272
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_) {
277         IHOTPLUGEVENTTRACE(
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(),
283                                     preferred_mode)) {
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);
289           break;
290         }
291       }
292     }
293   }
294
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)]));
300     if (!connector) {
301       ETRACE("Failed to get connector %d", res->connectors[i]);
302       break;
303     }
304
305     std::vector<drmModeModeInfo> mode;
306     uint32_t preferred_mode = 0;
307     uint32_t size = connector->count_modes;
308     mode.resize(size);
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) {
313         preferred_mode = i;
314       }
315     }
316
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]));
322       if (!encoder)
323         continue;
324
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(),
329                                     preferred_mode)) {
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);
334           break;
335         }
336       }
337     }
338   }
339
340   for (auto &display : displays_) {
341     if (!display->IsConnected()) {
342       display->DisConnect();
343     } else if (callback_) {
344       connected_displays.emplace_back(display.get());
345     }
346   }
347
348   if (callback_) {
349     callback_->Callback(connected_displays);
350   }
351
352   spin_lock_.unlock();
353 #ifndef ENABLE_ANDROID_WA
354   notify_client_ = true;
355 #endif
356
357   if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
358     IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
359                        notify_client_, displays_.at(0)->IsConnected());
360     NotifyClientsOfDisplayChangeStatus();
361   }
362
363   // update plane list for reservation
364   if (device_.IsReservedDrmPlane())
365     RemoveUnreservedPlanes();
366
367   return true;
368 }
369
370 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
371   spin_lock_.lock();
372
373   for (auto &display : displays_) {
374     if (!display->IsConnected()) {
375       display->NotifyClientOfDisConnectedState();
376     } else {
377       display->NotifyClientOfConnectedState();
378     }
379   }
380
381 #ifdef ENABLE_ANDROID_WA
382   notify_client_ = true;
383 #endif
384
385   spin_lock_.unlock();
386 }
387
388 NativeDisplay *DrmDisplayManager::CreateVirtualDisplay(uint32_t display_index) {
389   spin_lock_.lock();
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();
395   spin_lock_.unlock();
396   return latest_display;
397 }
398
399 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
400   spin_lock_.lock();
401   virtual_displays_.at(display_index).reset(nullptr);
402   virtual_displays_.erase(display_index);
403   spin_lock_.unlock();
404 }
405
406 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
407   spin_lock_.lock();
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());
412   }
413   spin_lock_.unlock();
414   return all_displays;
415 }
416
417 void DrmDisplayManager::RegisterHotPlugEventCallback(
418     std::shared_ptr<DisplayHotPlugEventCallback> callback) {
419   spin_lock_.lock();
420   callback_ = callback;
421   spin_lock_.unlock();
422 }
423
424 void DrmDisplayManager::ForceRefresh() {
425   spin_lock_.lock();
426   ignore_updates_ = false;
427   size_t size = displays_.size();
428   for (size_t i = 0; i < size; ++i) {
429     displays_.at(i)->ForceRefresh();
430   }
431
432   release_lock_ = true;
433   spin_lock_.unlock();
434 }
435
436 void DrmDisplayManager::IgnoreUpdates() {
437   spin_lock_.lock();
438   ignore_updates_ = true;
439   spin_lock_.unlock();
440
441   size_t size = displays_.size();
442   for (size_t i = 0; i < size; ++i) {
443     displays_.at(i)->IgnoreUpdates();
444   }
445 }
446
447 void DrmDisplayManager::setDrmMaster(bool must_set) {
448   spin_lock_.lock();
449   if (drm_master_) {
450     spin_lock_.unlock();
451     return;
452   }
453   int ret = 0;
454   uint8_t retry_times = 0;
455   do {
456     ret = drmSetMaster(fd_);
457     if (!must_set)
458       retry_times++;
459     if (ret) {
460       ETRACE("Failed to call drmSetMaster : %s", PRINTERROR());
461       usleep(10000);
462     } else {
463       ITRACE("Successfully set as DRM master.");
464       drm_master_ = true;
465     }
466   } while (ret && retry_times < 10);
467   spin_lock_.unlock();
468 }
469
470 void DrmDisplayManager::DropDrmMaster() {
471   spin_lock_.lock();
472   if (!drm_master_) {
473     spin_lock_.unlock();
474     return;
475   }
476   int ret = 0;
477   uint8_t retry_times = 0;
478   do {
479     ret = drmDropMaster(fd_);
480     retry_times++;
481     if (ret) {
482       ETRACE("Failed to call drmDropMaster : %s", PRINTERROR());
483       usleep(10000);
484     } else {
485       ITRACE("Successfully drop DRM master.");
486       drm_master_ = false;
487     }
488   } while (ret && retry_times < 10);
489   spin_lock_.unlock();
490 }
491
492 void DrmDisplayManager::HandleLazyInitialization() {
493   spin_lock_.lock();
494   if (release_lock_) {
495     device_.DisableWatch();
496     release_lock_ = false;
497   }
498   spin_lock_.unlock();
499 }
500
501 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
502   return connected_display_count_;
503 }
504
505 DisplayManager *DisplayManager::CreateDisplayManager() {
506   return new DrmDisplayManager();
507 }
508
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,
515                                     content_type);
516     }
517   }
518 }
519
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);
525   }
526 }
527
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);
534     }
535   }
536 }
537
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);
543   }
544 }
545
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);
551   }
552 }
553
554 void DrmDisplayManager::SetHDCPSRMForDisplay(uint32_t connector,
555                                              const int8_t *SRM,
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);
561     }
562   }
563 }
564
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())
569       continue;
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);
574   }
575 }
576
577 FrameBufferManager *DrmDisplayManager::GetFrameBufferManager() {
578   return frame_buffer_manager_.get();
579 }
580
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;
588 }
589 #endif
590
591 }  // namespace hwcomposer