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(GpuDevice *device)
42 : HWCThread(-8, "DisplayManager"), device_(device) {
46 DrmDisplayManager::~DrmDisplayManager() {
48 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_);
116 IHOTPLUGEVENTTRACE("DisplayManager Initialization succeeded.");
120 void DrmDisplayManager::HotPlugEventHandler() {
122 int fd = hotplug_fd_;
123 char buffer[DRM_HOTPLUG_EVENT_SIZE];
126 memset(&buffer, 0, sizeof(buffer));
128 bool drm_event = false, hotplug_event = false;
129 size_t srclen = DRM_HOTPLUG_EVENT_SIZE - 1;
130 ret = read(fd, &buffer, srclen);
133 ETRACE("Failed to read uevent. %s", PRINTERROR());
140 for (int32_t i = 0; i < ret;) {
141 char *event = buffer + i;
142 if (!strcmp(event, "DEVTYPE=drm_minor"))
144 else if (!strcmp(event, "HOTPLUG=1") || // Common hotplug request
146 "HDMI-Change")) { // Hotplug happened during suspend
147 hotplug_event = true;
150 if (hotplug_event && drm_event)
153 i += strlen(event) + 1;
156 if (drm_event && hotplug_event) {
158 "Recieved Hot Plug event related to display calling "
159 "UpdateDisplayState.");
160 UpdateDisplayState();
165 void DrmDisplayManager::HandleWait() {
166 if (fd_handler_.Poll(-1) <= 0) {
167 ETRACE("Poll Failed in DisplayManager %s", PRINTERROR());
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");
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);
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 display->MarkForDisconnect();
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]));
229 ETRACE("Failed to get connector %d", res->connectors[i]);
232 // check if a monitor is connected.
233 if (connector->connection != DRM_MODE_CONNECTED)
236 // Ensure we have atleast one valid mode.
237 if (connector->count_modes == 0)
240 if (connector->encoder_id == 0) {
241 no_encoder.emplace_back(i);
245 std::vector<drmModeModeInfo> mode;
246 uint32_t preferred_mode = 0;
247 uint32_t size = connector->count_modes;
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) {
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_) {
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(),
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);
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)]));
285 ETRACE("Failed to get connector %d", res->connectors[i]);
289 std::vector<drmModeModeInfo> mode;
290 uint32_t preferred_mode = 0;
291 uint32_t size = connector->count_modes;
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) {
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]));
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(),
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);
324 for (auto &display : displays_) {
325 if (!display->IsConnected()) {
326 display->DisConnect();
327 } else if (callback_) {
328 connected_displays.emplace_back(display.get());
333 callback_->Callback(connected_displays);
337 #ifndef ENABLE_ANDROID_WA
338 notify_client_ = true;
341 if (notify_client_ || (!(displays_.at(0)->IsConnected()))) {
342 IHOTPLUGEVENTTRACE("NotifyClientsOfDisplayChangeStatus Called %d %d \n",
343 notify_client_, displays_.at(0)->IsConnected());
344 NotifyClientsOfDisplayChangeStatus();
350 void DrmDisplayManager::NotifyClientsOfDisplayChangeStatus() {
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++;
360 if (total_connected_displays > 1) {
361 disable_last_plane_usage = true;
366 for (auto &display : displays_) {
367 display->NotifyDisplayWA(disable_last_plane_usage);
368 display->ForceRefresh();
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(),
391 frame_buffer_manager_.get(), display_index, 0));
392 virtual_displays_.emplace_back(std::move(display));
393 size_t size = virtual_displays_.size();
394 latest_display = virtual_displays_.at(size - 1).get();
396 return latest_display;
399 void DrmDisplayManager::DestroyVirtualDisplay(uint32_t display_index) {
401 virtual_displays_.at(display_index).reset(nullptr);
405 std::vector<NativeDisplay *> DrmDisplayManager::GetAllDisplays() {
407 std::vector<NativeDisplay *> all_displays;
408 size_t size = displays_.size();
409 for (size_t i = 0; i < size; ++i) {
410 all_displays.emplace_back(displays_.at(i).get());
416 void DrmDisplayManager::RegisterHotPlugEventCallback(
417 std::shared_ptr<DisplayHotPlugEventCallback> callback) {
419 callback_ = callback;
423 void DrmDisplayManager::ForceRefresh() {
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() {
435 size_t size = displays_.size();
436 for (size_t i = 0; i < size; ++i) {
437 displays_.at(i)->IgnoreUpdates();
441 void DrmDisplayManager::HandleLazyInitialization() {
444 device_->DisableWatch();
445 release_lock_ = false;
450 uint32_t DrmDisplayManager::GetConnectedPhysicalDisplayCount() {
451 size_t size = displays_.size();
453 for (size_t i = 0; i < size; i++) {
454 if (displays_[i]->IsConnected()) {
461 DisplayManager *DisplayManager::CreateDisplayManager(GpuDevice *device) {
462 return new DrmDisplayManager(device);
465 } // namespace hwcomposer