OSDN Git Service

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