OSDN Git Service

drm_hwcomposer: fix typo in formats switch statement
[android-x86/external-drm_hwcomposer.git] / hwcomposer.cpp
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 #define LOG_TAG "hwcomposer-drm"
19
20 #include "drmhwcomposer.h"
21 #include "drmeventlistener.h"
22 #include "drmresources.h"
23 #include "platform.h"
24 #include "virtualcompositorworker.h"
25 #include "vsyncworker.h"
26
27 #include <stdlib.h>
28
29 #include <cinttypes>
30 #include <map>
31 #include <vector>
32 #include <sstream>
33
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <pthread.h>
37 #include <sys/param.h>
38 #include <sys/resource.h>
39 #include <xf86drm.h>
40 #include <xf86drmMode.h>
41
42 #include <cutils/log.h>
43 #include <cutils/properties.h>
44 #include <hardware/hardware.h>
45 #include <hardware/hwcomposer.h>
46 #include <sw_sync.h>
47 #include <sync/sync.h>
48 #include <utils/Trace.h>
49
50 #define UM_PER_INCH 25400
51
52 namespace android {
53
54 class DummySwSyncTimeline {
55  public:
56   int Init() {
57     int ret = timeline_fd_.Set(sw_sync_timeline_create());
58     if (ret < 0)
59       return ret;
60     return 0;
61   }
62
63   UniqueFd CreateDummyFence() {
64     int ret = sw_sync_fence_create(timeline_fd_.get(), "dummy fence",
65                                    timeline_pt_ + 1);
66     if (ret < 0) {
67       ALOGE("Failed to create dummy fence %d", ret);
68       return ret;
69     }
70
71     UniqueFd ret_fd(ret);
72
73     ret = sw_sync_timeline_inc(timeline_fd_.get(), 1);
74     if (ret) {
75       ALOGE("Failed to increment dummy sync timeline %d", ret);
76       return ret;
77     }
78
79     ++timeline_pt_;
80     return ret_fd;
81   }
82
83  private:
84   UniqueFd timeline_fd_;
85   int timeline_pt_ = 0;
86 };
87
88 struct CheckedOutputFd {
89   CheckedOutputFd(int *fd, const char *description,
90                   DummySwSyncTimeline &timeline)
91       : fd_(fd), description_(description), timeline_(timeline) {
92   }
93   CheckedOutputFd(CheckedOutputFd &&rhs)
94       : description_(rhs.description_), timeline_(rhs.timeline_) {
95     std::swap(fd_, rhs.fd_);
96   }
97
98   CheckedOutputFd &operator=(const CheckedOutputFd &rhs) = delete;
99
100   ~CheckedOutputFd() {
101     if (fd_ == NULL)
102       return;
103
104     if (*fd_ >= 0)
105       return;
106
107     *fd_ = timeline_.CreateDummyFence().Release();
108
109     if (*fd_ < 0)
110       ALOGE("Failed to fill %s (%p == %d) before destruction",
111             description_.c_str(), fd_, *fd_);
112   }
113
114  private:
115   int *fd_ = NULL;
116   std::string description_;
117   DummySwSyncTimeline &timeline_;
118 };
119
120 typedef struct hwc_drm_display {
121   struct hwc_context_t *ctx;
122   int display;
123
124   std::vector<uint32_t> config_ids;
125
126   VSyncWorker vsync_worker;
127 } hwc_drm_display_t;
128
129 class DrmHotplugHandler : public DrmEventHandler {
130  public:
131   void Init(DrmResources *drm, const struct hwc_procs *procs) {
132     drm_ = drm;
133     procs_ = procs;
134   }
135
136   void HandleEvent(uint64_t timestamp_us) {
137     for (auto &conn : drm_->connectors()) {
138       drmModeConnection old_state = conn->state();
139
140       conn->UpdateModes();
141
142       drmModeConnection cur_state = conn->state();
143
144       if (cur_state == old_state)
145         continue;
146
147       ALOGI("%s event @%" PRIu64 " for connector %u\n",
148             cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
149             conn->id());
150
151       if (cur_state == DRM_MODE_CONNECTED) {
152         // Take the first one, then look for the preferred
153         DrmMode mode = *(conn->modes().begin());
154         for (auto &m : conn->modes()) {
155           if (m.type() & DRM_MODE_TYPE_PREFERRED) {
156             mode = m;
157             break;
158           }
159         }
160         ALOGI("Setting mode %dx%d for connector %d\n", mode.h_display(),
161               mode.v_display(), conn->id());
162         int ret = drm_->SetDisplayActiveMode(conn->display(), mode);
163         if (ret) {
164           ALOGE("Failed to set active config %d", ret);
165           return;
166         }
167       } else {
168         int ret = drm_->SetDpmsMode(conn->display(), DRM_MODE_DPMS_OFF);
169         if (ret) {
170           ALOGE("Failed to set dpms mode off %d", ret);
171           return;
172         }
173       }
174
175       procs_->hotplug(procs_, conn->display(),
176                       cur_state == DRM_MODE_CONNECTED ? 1 : 0);
177     }
178   }
179
180  private:
181   DrmResources *drm_ = NULL;
182   const struct hwc_procs *procs_ = NULL;
183 };
184
185 struct hwc_context_t {
186   // map of display:hwc_drm_display_t
187   typedef std::map<int, hwc_drm_display_t> DisplayMap;
188
189   ~hwc_context_t() {
190     virtual_compositor_worker.Exit();
191   }
192
193   hwc_composer_device_1_t device;
194   hwc_procs_t const *procs = NULL;
195
196   DisplayMap displays;
197   DrmResources drm;
198   std::unique_ptr<Importer> importer;
199   const gralloc_module_t *gralloc;
200   DummySwSyncTimeline dummy_timeline;
201   VirtualCompositorWorker virtual_compositor_worker;
202   DrmHotplugHandler hotplug_handler;
203 };
204
205 class DrmVsyncCallback : public VsyncCallback {
206  public:
207   DrmVsyncCallback(hwc_procs_t const *procs) : procs_(procs) {
208   }
209
210   void Callback(int display, int64_t timestamp) {
211     procs_->vsync(procs_, display, timestamp);
212   }
213  private:
214   hwc_procs_t const *procs_;
215 };
216
217 static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff,
218                      int buff_len) {
219   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
220   std::ostringstream out;
221
222   ctx->drm.compositor()->Dump(&out);
223   std::string out_str = out.str();
224   strncpy(buff, out_str.c_str(),
225           std::min((size_t)buff_len, out_str.length() + 1));
226   buff[buff_len - 1] = '\0';
227 }
228
229 static bool hwc_skip_layer(const std::pair<int, int> &indices, int i) {
230   return indices.first >= 0 && i >= indices.first && i <= indices.second;
231 }
232
233 static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
234                        hwc_display_contents_1_t **display_contents) {
235   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
236
237   for (int i = 0; i < (int)num_displays; ++i) {
238     if (!display_contents[i])
239       continue;
240
241     bool use_framebuffer_target = false;
242     DrmMode mode;
243     if (i == HWC_DISPLAY_VIRTUAL) {
244       use_framebuffer_target = true;
245     } else {
246       DrmConnector *c = ctx->drm.GetConnectorForDisplay(i);
247       if (!c) {
248         ALOGE("Failed to get DrmConnector for display %d", i);
249         return -ENODEV;
250       }
251       mode = c->active_mode();
252     }
253
254     // Since we can't composite HWC_SKIP_LAYERs by ourselves, we'll let SF
255     // handle all layers in between the first and last skip layers. So find the
256     // outer indices and mark everything in between as HWC_FRAMEBUFFER
257     std::pair<int, int> skip_layer_indices(-1, -1);
258     int num_layers = display_contents[i]->numHwLayers;
259     for (int j = 0; !use_framebuffer_target && j < num_layers; ++j) {
260       hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
261
262       if (!(layer->flags & HWC_SKIP_LAYER))
263         continue;
264
265       if (skip_layer_indices.first == -1)
266         skip_layer_indices.first = j;
267       skip_layer_indices.second = j;
268     }
269
270     for (int j = 0; j < num_layers; ++j) {
271       hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
272
273       if (!use_framebuffer_target && !hwc_skip_layer(skip_layer_indices, j)) {
274         // If the layer is off the screen, don't earmark it for an overlay.
275         // We'll leave it as-is, which effectively just drops it from the frame
276         const hwc_rect_t *frame = &layer->displayFrame;
277         if ((frame->right - frame->left) <= 0 ||
278             (frame->bottom - frame->top) <= 0 ||
279             frame->right <= 0 || frame->bottom <= 0 ||
280             frame->left >= (int)mode.h_display() ||
281             frame->top >= (int)mode.v_display())
282             continue;
283
284         if (layer->compositionType == HWC_FRAMEBUFFER)
285           layer->compositionType = HWC_OVERLAY;
286       } else {
287         switch (layer->compositionType) {
288           case HWC_OVERLAY:
289           case HWC_BACKGROUND:
290           case HWC_SIDEBAND:
291           case HWC_CURSOR_OVERLAY:
292             layer->compositionType = HWC_FRAMEBUFFER;
293             break;
294         }
295       }
296     }
297   }
298
299   return 0;
300 }
301
302 static void hwc_add_layer_to_retire_fence(
303     hwc_layer_1_t *layer, hwc_display_contents_1_t *display_contents) {
304   if (layer->releaseFenceFd < 0)
305     return;
306
307   if (display_contents->retireFenceFd >= 0) {
308     int old_retire_fence = display_contents->retireFenceFd;
309     display_contents->retireFenceFd =
310         sync_merge("dc_retire", old_retire_fence, layer->releaseFenceFd);
311     close(old_retire_fence);
312   } else {
313     display_contents->retireFenceFd = dup(layer->releaseFenceFd);
314   }
315 }
316
317 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
318                    hwc_display_contents_1_t **sf_display_contents) {
319   ATRACE_CALL();
320   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
321   int ret = 0;
322
323   std::vector<CheckedOutputFd> checked_output_fences;
324   std::vector<DrmHwcDisplayContents> displays_contents;
325   std::vector<DrmCompositionDisplayLayersMap> layers_map;
326   std::vector<std::vector<size_t>> layers_indices;
327   displays_contents.reserve(num_displays);
328   // layers_map.reserve(num_displays);
329   layers_indices.reserve(num_displays);
330
331   // Phase one does nothing that would cause errors. Only take ownership of FDs.
332   for (size_t i = 0; i < num_displays; ++i) {
333     hwc_display_contents_1_t *dc = sf_display_contents[i];
334     displays_contents.emplace_back();
335     DrmHwcDisplayContents &display_contents = displays_contents.back();
336     layers_indices.emplace_back();
337     std::vector<size_t> &indices_to_composite = layers_indices.back();
338
339     if (!sf_display_contents[i])
340       continue;
341
342     if (i == HWC_DISPLAY_VIRTUAL) {
343       ctx->virtual_compositor_worker.QueueComposite(dc);
344       continue;
345     }
346
347     std::ostringstream display_index_formatter;
348     display_index_formatter << "retire fence for display " << i;
349     std::string display_fence_description(display_index_formatter.str());
350     checked_output_fences.emplace_back(&dc->retireFenceFd,
351                                        display_fence_description.c_str(),
352                                        ctx->dummy_timeline);
353     display_contents.retire_fence = OutputFd(&dc->retireFenceFd);
354
355     size_t num_dc_layers = dc->numHwLayers;
356     int framebuffer_target_index = -1;
357     for (size_t j = 0; j < num_dc_layers; ++j) {
358       hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
359       if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) {
360         framebuffer_target_index = j;
361         break;
362       }
363     }
364
365     for (size_t j = 0; j < num_dc_layers; ++j) {
366       hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
367
368       display_contents.layers.emplace_back();
369       DrmHwcLayer &layer = display_contents.layers.back();
370
371       // In prepare() we marked all layers FRAMEBUFFER between SKIP_LAYER's.
372       // This means we should insert the FB_TARGET layer in the composition
373       // stack at the location of the first skip layer, and ignore the rest.
374       if (sf_layer->flags & HWC_SKIP_LAYER) {
375         if (framebuffer_target_index < 0)
376           continue;
377         int idx = framebuffer_target_index;
378         framebuffer_target_index = -1;
379         hwc_layer_1_t *fbt_layer = &dc->hwLayers[idx];
380         if (!fbt_layer->handle || (fbt_layer->flags & HWC_SKIP_LAYER)) {
381           ALOGE("Invalid HWC_FRAMEBUFFER_TARGET with HWC_SKIP_LAYER present");
382           continue;
383         }
384         indices_to_composite.push_back(idx);
385         continue;
386       }
387
388       if (sf_layer->compositionType == HWC_OVERLAY)
389         indices_to_composite.push_back(j);
390
391       layer.acquire_fence.Set(sf_layer->acquireFenceFd);
392       sf_layer->acquireFenceFd = -1;
393
394       std::ostringstream layer_fence_formatter;
395       layer_fence_formatter << "release fence for layer " << j << " of display "
396                             << i;
397       std::string layer_fence_description(layer_fence_formatter.str());
398       checked_output_fences.emplace_back(&sf_layer->releaseFenceFd,
399                                          layer_fence_description.c_str(),
400                                          ctx->dummy_timeline);
401       layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
402     }
403
404     // This is a catch-all in case we get a frame without any overlay layers, or
405     // skip layers, but with a value fb_target layer. This _shouldn't_ happen,
406     // but it's not ruled out by the hwc specification
407     if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
408       hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
409       if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {
410         ALOGE(
411             "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all "
412             "HWC_OVERLAY layers are skipped.");
413         ret = -EINVAL;
414       }
415       indices_to_composite.push_back(framebuffer_target_index);
416     }
417   }
418
419   if (ret)
420     return ret;
421
422   for (size_t i = 0; i < num_displays; ++i) {
423     hwc_display_contents_1_t *dc = sf_display_contents[i];
424     DrmHwcDisplayContents &display_contents = displays_contents[i];
425     if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL)
426       continue;
427
428     layers_map.emplace_back();
429     DrmCompositionDisplayLayersMap &map = layers_map.back();
430     map.display = i;
431     map.geometry_changed =
432         (dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED;
433     std::vector<size_t> &indices_to_composite = layers_indices[i];
434     for (size_t j : indices_to_composite) {
435       hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
436
437       DrmHwcLayer &layer = display_contents.layers[j];
438
439       ret = layer.InitFromHwcLayer(sf_layer, ctx->importer.get(), ctx->gralloc);
440       if (ret) {
441         ALOGE("Failed to init composition from layer %d", ret);
442         return ret;
443       }
444       map.layers.emplace_back(std::move(layer));
445     }
446   }
447
448   std::unique_ptr<DrmComposition> composition(
449       ctx->drm.compositor()->CreateComposition(ctx->importer.get()));
450   if (!composition) {
451     ALOGE("Drm composition init failed");
452     return -EINVAL;
453   }
454
455   ret = composition->SetLayers(layers_map.size(), layers_map.data());
456   if (ret) {
457     return -EINVAL;
458   }
459
460   ret = ctx->drm.compositor()->QueueComposition(std::move(composition));
461   if (ret) {
462     return -EINVAL;
463   }
464
465   for (size_t i = 0; i < num_displays; ++i) {
466     hwc_display_contents_1_t *dc = sf_display_contents[i];
467     if (!dc)
468       continue;
469
470     size_t num_dc_layers = dc->numHwLayers;
471     for (size_t j = 0; j < num_dc_layers; ++j) {
472       hwc_layer_1_t *layer = &dc->hwLayers[j];
473       if (layer->flags & HWC_SKIP_LAYER)
474         continue;
475       hwc_add_layer_to_retire_fence(layer, dc);
476     }
477   }
478
479   composition.reset(NULL);
480
481   return ret;
482 }
483
484 static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
485                              int event, int enabled) {
486   if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
487     return -EINVAL;
488
489   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
490   hwc_drm_display_t *hd = &ctx->displays[display];
491   hd->vsync_worker.VSyncControl(enabled);
492   return 0;
493 }
494
495 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
496                               int mode) {
497   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
498
499   uint64_t dpmsValue = 0;
500   switch (mode) {
501     case HWC_POWER_MODE_OFF:
502       dpmsValue = DRM_MODE_DPMS_OFF;
503       break;
504
505     /* We can't support dozing right now, so go full on */
506     case HWC_POWER_MODE_DOZE:
507     case HWC_POWER_MODE_DOZE_SUSPEND:
508     case HWC_POWER_MODE_NORMAL:
509       dpmsValue = DRM_MODE_DPMS_ON;
510       break;
511   };
512   return ctx->drm.SetDpmsMode(display, dpmsValue);
513 }
514
515 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
516                      int *value) {
517   switch (what) {
518     case HWC_BACKGROUND_LAYER_SUPPORTED:
519       *value = 0; /* TODO: We should do this */
520       break;
521     case HWC_VSYNC_PERIOD:
522       ALOGW("Query for deprecated vsync value, returning 60Hz");
523       *value = 1000 * 1000 * 1000 / 60;
524       break;
525     case HWC_DISPLAY_TYPES_SUPPORTED:
526       *value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT |
527                HWC_DISPLAY_VIRTUAL_BIT;
528       break;
529   }
530   return 0;
531 }
532
533 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
534                                hwc_procs_t const *procs) {
535   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
536
537   ctx->procs = procs;
538
539   for (std::pair<const int, hwc_drm_display> &display_entry : ctx->displays) {
540     auto callback = std::make_shared<DrmVsyncCallback>(procs);
541     display_entry.second.vsync_worker.RegisterCallback(std::move(callback));
542   }
543
544   ctx->hotplug_handler.Init(&ctx->drm, procs);
545   ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler);
546 }
547
548 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
549                                    int display, uint32_t *configs,
550                                    size_t *num_configs) {
551   if (!*num_configs)
552     return 0;
553
554   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
555   hwc_drm_display_t *hd = &ctx->displays[display];
556   hd->config_ids.clear();
557
558   DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
559   if (!connector) {
560     ALOGE("Failed to get connector for display %d", display);
561     return -ENODEV;
562   }
563
564   int ret = connector->UpdateModes();
565   if (ret) {
566     ALOGE("Failed to update display modes %d", ret);
567     return ret;
568   }
569
570   for (const DrmMode &mode : connector->modes()) {
571     size_t idx = hd->config_ids.size();
572     if (idx == *num_configs)
573       break;
574     hd->config_ids.push_back(mode.id());
575     configs[idx] = mode.id();
576   }
577   *num_configs = hd->config_ids.size();
578   return *num_configs == 0 ? -1 : 0;
579 }
580
581 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
582                                       int display, uint32_t config,
583                                       const uint32_t *attributes,
584                                       int32_t *values) {
585   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
586   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
587   if (!c) {
588     ALOGE("Failed to get DrmConnector for display %d", display);
589     return -ENODEV;
590   }
591   DrmMode mode;
592   for (const DrmMode &conn_mode : c->modes()) {
593     if (conn_mode.id() == config) {
594       mode = conn_mode;
595       break;
596     }
597   }
598   if (mode.id() == 0) {
599     ALOGE("Failed to find active mode for display %d", display);
600     return -ENOENT;
601   }
602
603   uint32_t mm_width = c->mm_width();
604   uint32_t mm_height = c->mm_height();
605   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
606     switch (attributes[i]) {
607       case HWC_DISPLAY_VSYNC_PERIOD:
608         values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
609         break;
610       case HWC_DISPLAY_WIDTH:
611         values[i] = mode.h_display();
612         break;
613       case HWC_DISPLAY_HEIGHT:
614         values[i] = mode.v_display();
615         break;
616       case HWC_DISPLAY_DPI_X:
617         /* Dots per 1000 inches */
618         values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
619         break;
620       case HWC_DISPLAY_DPI_Y:
621         /* Dots per 1000 inches */
622         values[i] =
623             mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
624         break;
625     }
626   }
627   return 0;
628 }
629
630 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
631                                  int display) {
632   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
633   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
634   if (!c) {
635     ALOGE("Failed to get DrmConnector for display %d", display);
636     return -ENODEV;
637   }
638
639   DrmMode mode = c->active_mode();
640   hwc_drm_display_t *hd = &ctx->displays[display];
641   for (size_t i = 0; i < hd->config_ids.size(); ++i) {
642     if (hd->config_ids[i] == mode.id())
643       return i;
644   }
645   return -1;
646 }
647
648 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
649                                  int index) {
650   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
651   hwc_drm_display_t *hd = &ctx->displays[display];
652   if (index >= (int)hd->config_ids.size()) {
653     ALOGE("Invalid config index %d passed in", index);
654     return -EINVAL;
655   }
656
657   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
658   if (!c) {
659     ALOGE("Failed to get connector for display %d", display);
660     return -ENODEV;
661   }
662
663   if (c->state() != DRM_MODE_CONNECTED)
664     return -ENODEV;
665
666   DrmMode mode;
667   for (const DrmMode &conn_mode : c->modes()) {
668     if (conn_mode.id() == hd->config_ids[index]) {
669       mode = conn_mode;
670       break;
671     }
672   }
673   if (mode.id() != hd->config_ids[index]) {
674     ALOGE("Could not find active mode for %d/%d", index, hd->config_ids[index]);
675     return -ENOENT;
676   }
677   int ret = ctx->drm.SetDisplayActiveMode(display, mode);
678   if (ret) {
679     ALOGE("Failed to set active config %d", ret);
680     return ret;
681   }
682   ret = ctx->drm.SetDpmsMode(display, DRM_MODE_DPMS_ON);
683   if (ret) {
684     ALOGE("Failed to set dpms mode on %d", ret);
685     return ret;
686   }
687   return ret;
688 }
689
690 static int hwc_device_close(struct hw_device_t *dev) {
691   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
692   delete ctx;
693   return 0;
694 }
695
696 /*
697  * TODO: This function sets the active config to the first one in the list. This
698  * should be fixed such that it selects the preferred mode for the display, or
699  * some other, saner, method of choosing the config.
700  */
701 static int hwc_set_initial_config(hwc_drm_display_t *hd) {
702   uint32_t config;
703   size_t num_configs = 1;
704   int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
705                                     &num_configs);
706   if (ret || !num_configs)
707     return 0;
708
709   ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
710   if (ret) {
711     ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
712     return ret;
713   }
714
715   return ret;
716 }
717
718 static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
719   hwc_drm_display_t *hd = &ctx->displays[display];
720   hd->ctx = ctx;
721   hd->display = display;
722
723   int ret = hwc_set_initial_config(hd);
724   if (ret) {
725     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
726     return ret;
727   }
728
729   ret = hd->vsync_worker.Init(&ctx->drm, display);
730   if (ret) {
731     ALOGE("Failed to create event worker for display %d %d\n", display, ret);
732     return ret;
733   }
734
735   return 0;
736 }
737
738 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
739   int ret;
740   for (auto &conn : ctx->drm.connectors()) {
741     ret = hwc_initialize_display(ctx, conn->display());
742     if (ret) {
743       ALOGE("Failed to initialize display %d", conn->display());
744       return ret;
745     }
746   }
747
748   ret = ctx->virtual_compositor_worker.Init();
749   if (ret) {
750     ALOGE("Failed to initialize virtual compositor worker");
751     return ret;
752   }
753   return 0;
754 }
755
756 static int hwc_device_open(const struct hw_module_t *module, const char *name,
757                            struct hw_device_t **dev) {
758   if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
759     ALOGE("Invalid module name- %s", name);
760     return -EINVAL;
761   }
762
763   std::unique_ptr<hwc_context_t> ctx(new hwc_context_t());
764   if (!ctx) {
765     ALOGE("Failed to allocate hwc context");
766     return -ENOMEM;
767   }
768
769   int ret = ctx->drm.Init();
770   if (ret) {
771     ALOGE("Can't initialize Drm object %d", ret);
772     return ret;
773   }
774
775   ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
776                       (const hw_module_t **)&ctx->gralloc);
777   if (ret) {
778     ALOGE("Failed to open gralloc module %d", ret);
779     return ret;
780   }
781
782   ret = ctx->dummy_timeline.Init();
783   if (ret) {
784     ALOGE("Failed to create dummy sw sync timeline %d", ret);
785     return ret;
786   }
787
788   ctx->importer.reset(Importer::CreateInstance(&ctx->drm));
789   if (!ctx->importer) {
790     ALOGE("Failed to create importer instance");
791     return ret;
792   }
793
794   ret = hwc_enumerate_displays(ctx.get());
795   if (ret) {
796     ALOGE("Failed to enumerate displays: %s", strerror(ret));
797     return ret;
798   }
799
800   ctx->device.common.tag = HARDWARE_DEVICE_TAG;
801   ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
802   ctx->device.common.module = const_cast<hw_module_t *>(module);
803   ctx->device.common.close = hwc_device_close;
804
805   ctx->device.dump = hwc_dump;
806   ctx->device.prepare = hwc_prepare;
807   ctx->device.set = hwc_set;
808   ctx->device.eventControl = hwc_event_control;
809   ctx->device.setPowerMode = hwc_set_power_mode;
810   ctx->device.query = hwc_query;
811   ctx->device.registerProcs = hwc_register_procs;
812   ctx->device.getDisplayConfigs = hwc_get_display_configs;
813   ctx->device.getDisplayAttributes = hwc_get_display_attributes;
814   ctx->device.getActiveConfig = hwc_get_active_config;
815   ctx->device.setActiveConfig = hwc_set_active_config;
816   ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
817
818   *dev = &ctx->device.common;
819   ctx.release();
820
821   return 0;
822 }
823 }
824
825 static struct hw_module_methods_t hwc_module_methods = {
826   .open = android::hwc_device_open
827 };
828
829 hwc_module_t HAL_MODULE_INFO_SYM = {
830   .common = {
831     .tag = HARDWARE_MODULE_TAG,
832     .version_major = 1,
833     .version_minor = 0,
834     .id = HWC_HARDWARE_MODULE_ID,
835     .name = "DRM hwcomposer module",
836     .author = "The Android Open Source Project",
837     .methods = &hwc_module_methods,
838     .dso = NULL,
839     .reserved = {0},
840   }
841 };