OSDN Git Service

Merge "drm_hwcomposer: fill hwc_display_contents retireFenceFd" into mnc-dr-dev
[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   for (size_t i = 0; i < num_displays; ++i) {
520     hwc_display_contents_1_t *dc = sf_display_contents[i];
521     if (!dc)
522       continue;
523
524     size_t num_dc_layers = dc->numHwLayers;
525     for (size_t j = 0; j < num_dc_layers; ++j) {
526       hwc_layer_1_t *layer = &dc->hwLayers[j];
527       if (layer->flags & HWC_SKIP_LAYER)
528         continue;
529       hwc_add_layer_to_retire_fence(layer, dc);
530     }
531   }
532
533   composition.reset(NULL);
534
535   return ret;
536 }
537
538 static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
539                              int event, int enabled) {
540   if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
541     return -EINVAL;
542
543   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
544   hwc_drm_display_t *hd = &ctx->displays[display];
545   return hd->vsync_worker.VSyncControl(enabled);
546 }
547
548 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
549                               int mode) {
550   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
551
552   uint64_t dpmsValue = 0;
553   switch (mode) {
554     case HWC_POWER_MODE_OFF:
555       dpmsValue = DRM_MODE_DPMS_OFF;
556       break;
557
558     /* We can't support dozing right now, so go full on */
559     case HWC_POWER_MODE_DOZE:
560     case HWC_POWER_MODE_DOZE_SUSPEND:
561     case HWC_POWER_MODE_NORMAL:
562       dpmsValue = DRM_MODE_DPMS_ON;
563       break;
564   };
565   return ctx->drm.SetDpmsMode(display, dpmsValue);
566 }
567
568 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
569                      int *value) {
570   switch (what) {
571     case HWC_BACKGROUND_LAYER_SUPPORTED:
572       *value = 0; /* TODO: We should do this */
573       break;
574     case HWC_VSYNC_PERIOD:
575       ALOGW("Query for deprecated vsync value, returning 60Hz");
576       *value = 1000 * 1000 * 1000 / 60;
577       break;
578     case HWC_DISPLAY_TYPES_SUPPORTED:
579       *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
580       break;
581   }
582   return 0;
583 }
584
585 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
586                                hwc_procs_t const *procs) {
587   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
588
589   ctx->procs = procs;
590
591   for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin();
592        iter != ctx->displays.end(); ++iter) {
593     iter->second.vsync_worker.SetProcs(procs);
594   }
595 }
596
597 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
598                                    int display, uint32_t *configs,
599                                    size_t *num_configs) {
600   if (!*num_configs)
601     return 0;
602
603   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
604   hwc_drm_display_t *hd = &ctx->displays[display];
605   hd->config_ids.clear();
606
607   DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
608   if (!connector) {
609     ALOGE("Failed to get connector for display %d", display);
610     return -ENODEV;
611   }
612
613   int ret = connector->UpdateModes();
614   if (ret) {
615     ALOGE("Failed to update display modes %d", ret);
616     return ret;
617   }
618
619   for (DrmConnector::ModeIter iter = connector->begin_modes();
620        iter != connector->end_modes(); ++iter) {
621     size_t idx = hd->config_ids.size();
622     if (idx == *num_configs)
623       break;
624     hd->config_ids.push_back(iter->id());
625     configs[idx] = iter->id();
626   }
627   *num_configs = hd->config_ids.size();
628   return *num_configs == 0 ? -1 : 0;
629 }
630
631 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
632                                       int display, uint32_t config,
633                                       const uint32_t *attributes,
634                                       int32_t *values) {
635   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
636   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
637   if (!c) {
638     ALOGE("Failed to get DrmConnector for display %d", display);
639     return -ENODEV;
640   }
641   DrmMode mode;
642   for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
643        ++iter) {
644     if (iter->id() == config) {
645       mode = *iter;
646       break;
647     }
648   }
649   if (mode.id() == 0) {
650     ALOGE("Failed to find active mode for display %d", display);
651     return -ENOENT;
652   }
653
654   uint32_t mm_width = c->mm_width();
655   uint32_t mm_height = c->mm_height();
656   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
657     switch (attributes[i]) {
658       case HWC_DISPLAY_VSYNC_PERIOD:
659         values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
660         break;
661       case HWC_DISPLAY_WIDTH:
662         values[i] = mode.h_display();
663         break;
664       case HWC_DISPLAY_HEIGHT:
665         values[i] = mode.v_display();
666         break;
667       case HWC_DISPLAY_DPI_X:
668         /* Dots per 1000 inches */
669         values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
670         break;
671       case HWC_DISPLAY_DPI_Y:
672         /* Dots per 1000 inches */
673         values[i] =
674             mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
675         break;
676     }
677   }
678   return 0;
679 }
680
681 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
682                                  int display) {
683   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
684   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
685   if (!c) {
686     ALOGE("Failed to get DrmConnector for display %d", display);
687     return -ENODEV;
688   }
689
690   DrmMode mode = c->active_mode();
691   hwc_drm_display_t *hd = &ctx->displays[display];
692   for (size_t i = 0; i < hd->config_ids.size(); ++i) {
693     if (hd->config_ids[i] == mode.id())
694       return i;
695   }
696   return -1;
697 }
698
699 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
700                                  int index) {
701   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
702   hwc_drm_display_t *hd = &ctx->displays[display];
703   if (index >= (int)hd->config_ids.size()) {
704     ALOGE("Invalid config index %d passed in", index);
705     return -EINVAL;
706   }
707
708   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
709   if (!c) {
710     ALOGE("Failed to get connector for display %d", display);
711     return -ENODEV;
712   }
713   DrmMode mode;
714   for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
715        ++iter) {
716     if (iter->id() == hd->config_ids[index]) {
717       mode = *iter;
718       break;
719     }
720   }
721   if (mode.id() != hd->config_ids[index]) {
722     ALOGE("Could not find active mode for %d/%d", index, hd->config_ids[index]);
723     return -ENOENT;
724   }
725   int ret = ctx->drm.SetDisplayActiveMode(display, mode);
726   if (ret) {
727     ALOGE("Failed to set active config %d", ret);
728     return ret;
729   }
730   return ret;
731 }
732
733 static int hwc_device_close(struct hw_device_t *dev) {
734   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
735   delete ctx;
736   return 0;
737 }
738
739 /*
740  * TODO: This function sets the active config to the first one in the list. This
741  * should be fixed such that it selects the preferred mode for the display, or
742  * some other, saner, method of choosing the config.
743  */
744 static int hwc_set_initial_config(hwc_drm_display_t *hd) {
745   uint32_t config;
746   size_t num_configs = 1;
747   int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
748                                     &num_configs);
749   if (ret || !num_configs)
750     return 0;
751
752   ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
753   if (ret) {
754     ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
755     return ret;
756   }
757
758   return ret;
759 }
760
761 static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
762   hwc_drm_display_t *hd = &ctx->displays[display];
763   hd->ctx = ctx;
764   hd->display = display;
765
766   int ret = hwc_set_initial_config(hd);
767   if (ret) {
768     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
769     return ret;
770   }
771
772   ret = hd->vsync_worker.Init(&ctx->drm, display);
773   if (ret) {
774     ALOGE("Failed to create event worker for display %d %d\n", display, ret);
775     return ret;
776   }
777
778   return 0;
779 }
780
781 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
782   int ret;
783   for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();
784        c != ctx->drm.end_connectors(); ++c) {
785     ret = hwc_initialize_display(ctx, (*c)->display());
786     if (ret) {
787       ALOGE("Failed to initialize display %d", (*c)->display());
788       return ret;
789     }
790   }
791
792   return 0;
793 }
794
795 static int hwc_device_open(const struct hw_module_t *module, const char *name,
796                            struct hw_device_t **dev) {
797   if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
798     ALOGE("Invalid module name- %s", name);
799     return -EINVAL;
800   }
801
802   struct hwc_context_t *ctx = new hwc_context_t();
803   if (!ctx) {
804     ALOGE("Failed to allocate hwc context");
805     return -ENOMEM;
806   }
807
808   int ret = ctx->drm.Init();
809   if (ret) {
810     ALOGE("Can't initialize Drm object %d", ret);
811     delete ctx;
812     return ret;
813   }
814
815   ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
816                       (const hw_module_t **)&ctx->gralloc);
817   if (ret) {
818     ALOGE("Failed to open gralloc module %d", ret);
819     delete ctx;
820     return ret;
821   }
822
823   ret = ctx->dummy_timeline.Init();
824   if (ret) {
825     ALOGE("Failed to create dummy sw sync timeline %d", ret);
826     return ret;
827   }
828
829   ctx->importer = Importer::CreateInstance(&ctx->drm);
830   if (!ctx->importer) {
831     ALOGE("Failed to create importer instance");
832     delete ctx;
833     return ret;
834   }
835
836   ret = hwc_enumerate_displays(ctx);
837   if (ret) {
838     ALOGE("Failed to enumerate displays: %s", strerror(ret));
839     delete ctx;
840     return ret;
841   }
842
843   ctx->device.common.tag = HARDWARE_DEVICE_TAG;
844   ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
845   ctx->device.common.module = const_cast<hw_module_t *>(module);
846   ctx->device.common.close = hwc_device_close;
847
848   ctx->device.dump = hwc_dump;
849   ctx->device.prepare = hwc_prepare;
850   ctx->device.set = hwc_set;
851   ctx->device.eventControl = hwc_event_control;
852   ctx->device.setPowerMode = hwc_set_power_mode;
853   ctx->device.query = hwc_query;
854   ctx->device.registerProcs = hwc_register_procs;
855   ctx->device.getDisplayConfigs = hwc_get_display_configs;
856   ctx->device.getDisplayAttributes = hwc_get_display_attributes;
857   ctx->device.getActiveConfig = hwc_get_active_config;
858   ctx->device.setActiveConfig = hwc_set_active_config;
859   ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
860
861   *dev = &ctx->device.common;
862
863   return 0;
864 }
865 }
866
867 static struct hw_module_methods_t hwc_module_methods = {
868   open : android::hwc_device_open
869 };
870
871 hwc_module_t HAL_MODULE_INFO_SYM = {
872   common : {
873     tag : HARDWARE_MODULE_TAG,
874     version_major : 1,
875     version_minor : 0,
876     id : HWC_HARDWARE_MODULE_ID,
877     name : "DRM hwcomposer module",
878     author : "The Android Open Source Project",
879     methods : &hwc_module_methods,
880     dso : NULL,
881     reserved : {0},
882   }
883 };