OSDN Git Service

Set HWC as DRM master when got exclusive lock of /vendor/hwc.lock.
[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(GpuDevice *device)
42     : HWCThread(-8, "DisplayManager"), device_(device) {
43   CTRACE();
44 }
45
46 DrmDisplayManager::~DrmDisplayManager() {
47   CTRACE();
48   std::vector<std::unique_ptr<DrmDisplay>>().swap(displays_);
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   IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
117   return true;
118 }
119
120 void DrmDisplayManager::HotPlugEventHandler() {
121   CTRACE();
122   int fd = hotplug_fd_;
123   char buffer[DRM_HOTPLUG_EVENT_SIZE];
124   int ret;
125
126   memset(&buffer, 0, sizeof(buffer));
127   while (true) {
128     bool drm_event = false, hotplug_event = false;
129     size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
130     ret = read(fd, &buffer, srclen);
131     if (ret <= 0) {
132       if (ret < 0)
133         ETRACE("Failed to read uevent. %s", PRINTERROR());
134
135       return;
136     }
137
138     buffer[ret] = '\0';
139
140     for (int32_t i = 0; i < ret;) {
141       char *event = buffer + i;
142       if (!strcmp(event, "DEVTYPE=drm_minor"))
143         drm_event = true;
144       else if (!strcmp(event, "HOTPLUG=1") ||  // Common hotplug request
145                !strcmp(event,
146                        "HDMI-Change")) {  // Hotplug happened during suspend
147         hotplug_event = true;
148       }
149
150       if (hotplug_event && drm_event)
151         break;
152
153       i += strlen(event) + 1;
154     }
155
156     if (drm_event && hotplug_event) {
157       IHOTPLUGEVENTTRACE(
158           "Recieved Hot Plug event related to display calling "
159           "UpdateDisplayState.");
160       UpdateDisplayState();
161     }
162   }
163 }
164
165 void DrmDisplayManager::HandleWait() {
166   if (fd_handler_.Poll(-1) <= 0) {
167     ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
168   }
169 }
170
171 void DrmDisplayManager::InitializeDisplayResources() {
172   buffer_handler_.reset(NativeBufferHandler::CreateInstance(fd_));
173   frame_buffer_manager_.reset(new FrameBufferManager(fd_));
174   if (!buffer_handler_) {
175     ETRACE("Failed to create native buffer handler instance");
176     return;
177   }
178
179   int size = displays_.size();
180   for (int i = 0; i < size; ++i) {
181     if (!displays_.at(i)->Initialize(buffer_handler_.get(),
182                                      frame_buffer_manager_.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     display->MarkForDisconnect();
220   }
221
222   std::vector<NativeDisplay *> connected_displays;
223   std::vector<uint32_t> no_encoder;
224   uint32_t total_connectors = res->count_connectors;
225   for (uint32_t i = 0; i < total_connectors; ++i) {
226     ScopedDrmConnectorPtr connector(
227         drmModeGetConnector(fd_, res->connectors[i]));
228     if (!connector) {
229       ETRACE("Failed to get connector %d", res->connectors[i]);
230       break;
231     }
232     // check if a monitor is connected.
233     if (connector->connection != DRM_MODE_CONNECTED)
234       continue;
235
236     // Ensure we have atleast one valid mode.
237     if (connector->count_modes == 0)
238       continue;
239
240     if (connector->encoder_id == 0) {
241       no_encoder.emplace_back(i);
242       continue;
243     }
244
245     std::vector<drmModeModeInfo> mode;
246     uint32_t preferred_mode = 0;
247     uint32_t size = connector->count_modes;
248     mode.resize(size);
249     for (uint32_t i = 0; i < size; ++i) {
250       mode[i] = connector->modes[i];
251       // There is only one preferred mode per connector.
252       if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
253         preferred_mode = i;
254       }
255     }
256
257     // Lets try to find crts for any connected encoder.
258     ScopedDrmEncoderPtr encoder(drmModeGetEncoder(fd_, connector->encoder_id));
259     if (encoder && encoder->crtc_id) {
260       for (auto &display : displays_) {
261         IHOTPLUGEVENTTRACE(
262             "Trying to connect %d with crtc: %d is display connected: %d \n",
263             encoder->crtc_id, display->CrtcId(), display->IsConnected());
264         // At initilaization  preferred mode is set!
265         if (!display->IsConnected() && encoder->crtc_id == display->CrtcId() &&
266             display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
267                                     preferred_mode)) {
268           IHOTPLUGEVENTTRACE("Connected %d with crtc: %d pipe:%d \n",
269                              encoder->crtc_id, display->CrtcId(),
270                              display->GetDisplayPipe());
271           // Set the modes supported for each display
272           display->SetDrmModeInfo(mode);
273           break;
274         }
275       }
276     }
277   }
278
279   // Deal with connectors with encoder_id == 0.
280   uint32_t size = no_encoder.size();
281   for (uint32_t i = 0; i < size; ++i) {
282     ScopedDrmConnectorPtr connector(
283         drmModeGetConnector(fd_, res->connectors[no_encoder.at(i)]));
284     if (!connector) {
285       ETRACE("Failed to get connector %d", res->connectors[i]);
286       break;
287     }
288
289     std::vector<drmModeModeInfo> mode;
290     uint32_t preferred_mode = 0;
291     uint32_t size = connector->count_modes;
292     mode.resize(size);
293     for (uint32_t i = 0; i < size; ++i) {
294       mode[i] = connector->modes[i];
295       // There is only one preferred mode per connector.
296       if (mode[i].type & DRM_MODE_TYPE_PREFERRED) {
297         preferred_mode = i;
298       }
299     }
300
301     // Try to find an encoder for the connector.
302     size = connector->count_encoders;
303     for (uint32_t j = 0; j < size; ++j) {
304       ScopedDrmEncoderPtr encoder(
305           drmModeGetEncoder(fd_, connector->encoders[j]));
306       if (!encoder)
307         continue;
308
309       for (auto &display : displays_) {
310         if (!display->IsConnected() &&
311             (encoder->possible_crtcs & (1 << display->GetDisplayPipe())) &&
312             display->ConnectDisplay(mode.at(preferred_mode), connector.get(),
313                                     preferred_mode)) {
314           IHOTPLUGEVENTTRACE("Connected with crtc: %d pipe:%d \n",
315                              display->CrtcId(), display->GetDisplayPipe());
316           // Set the modes supported for each display
317           display->SetDrmModeInfo(mode);
318           break;
319         }
320       }
321     }
322   }
323
324   for (auto &display : displays_) {
325     if (!display->IsConnected()) {
326       display->DisConnect();
327     } else if (callback_) {
328       connected_displays.emplace_back(display.get());
329     }
330   }
331
332   if (callback_) {
333     callback_->Callback(connected_displays);
334   }
335
336   spin_lock_.unlock();
337 #ifndef ENABLE_ANDROID_WA
338   notify_client_ = true;
339 #endif
340
341   if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
342     IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
343                        notify_client_, displays_.at(0)->IsConnected());
344     NotifyClientsOfDisplayChangeStatus();
345   }
346
347   return true;
348 }
349
350 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
351   spin_lock_.lock();
352   bool disable_last_plane_usage = false;
353   uint32_t total_connected_displays = 0;
354   for (auto &display : displays_) {
355     if (display->IsConnected()) {
356       display->NotifyClientOfDisConnectedState();
357       total_connected_displays++;
358     }
359
360     if (total_connected_displays > 1) {
361       disable_last_plane_usage = true;
362       break;
363     }
364   }
365
366   for (auto &display : displays_) {
367     display->NotifyDisplayWA(disable_last_plane_usage);
368     if (!ignore_updates_) {
369       display->ForceRefresh();
370     }
371   }
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(),
393                          frame_buffer_manager_.get(), display_index, 0));
394   virtual_displays_.emplace_back(std::move(display));
395   size_t size = virtual_displays_.size();
396   latest_display = virtual_displays_.at(size - 1).get();
397   spin_lock_.unlock();
398   return latest_display;
399 }
400
401 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
402   spin_lock_.lock();
403   virtual_displays_.at(display_index).reset(nullptr);
404   spin_lock_.unlock();
405 }
406
407 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
408   spin_lock_.lock();
409   std::vector<NativeDisplay *> all_displays;
410   size_t size = displays_.size();
411   for (size_t i = 0; i < size; ++i) {
412     all_displays.emplace_back(displays_.at(i).get());
413   }
414   spin_lock_.unlock();
415   return all_displays;
416 }
417
418 void DrmDisplayManager::RegisterHotPlugEventCallback(
419     std::shared_ptr<DisplayHotPlugEventCallback> callback) {
420   spin_lock_.lock();
421   callback_ = callback;
422   spin_lock_.unlock();
423 }
424
425 void DrmDisplayManager::ForceRefresh() {
426   spin_lock_.lock();
427   ignore_updates_ = false;
428   size_t size = displays_.size();
429   for (size_t i = 0; i < size; ++i) {
430     displays_.at(i)->ForceRefresh();
431   }
432
433   release_lock_ = true;
434   spin_lock_.unlock();
435 }
436
437 void DrmDisplayManager::IgnoreUpdates() {
438   spin_lock_.lock();
439   ignore_updates_ = true;
440   spin_lock_.unlock();
441
442   size_t size = displays_.size();
443   for (size_t i = 0; i < size; ++i) {
444     displays_.at(i)->IgnoreUpdates();
445   }
446 }
447
448 void DrmDisplayManager::setDrmMaster() {
449   int ret = drmSetMaster(fd_);
450   if (ret) {
451     ETRACE("Failed to call drmSetMaster : %s", PRINTERROR());
452   }
453 }
454
455 void DrmDisplayManager::HandleLazyInitialization() {
456   spin_lock_.lock();
457   if (release_lock_) {
458     device_->DisableWatch();
459     release_lock_ = false;
460   }
461   spin_lock_.unlock();
462 }
463
464 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
465   size_t size = displays_.size();
466   uint32_t count = 0;
467   for (size_t i = 0; i < size; i++) {
468     if (displays_[i]->IsConnected()) {
469       count++;
470     }
471   }
472   return count;
473 }
474
475 DisplayManager *DisplayManager::CreateDisplayManager(GpuDevice *device) {
476   return new DrmDisplayManager(device);
477 }
478
479 }  // namespace hwcomposer