OSDN Git Service

drm_hwcomposer: Add Importer to CreateComposition()
[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 LOG_TAG "hwcomposer-drm"
18
19 #include "drm_hwcomposer.h"
20 #include "drmresources.h"
21 #include "importer.h"
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <list>
26 #include <map>
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <sys/param.h>
30 #include <sys/resource.h>
31 #include <xf86drm.h>
32 #include <xf86drmMode.h>
33
34 #include <cutils/log.h>
35 #include <cutils/properties.h>
36 #include <hardware/hardware.h>
37 #include <hardware/hwcomposer.h>
38 #include <sw_sync.h>
39 #include <sync/sync.h>
40
41 #define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
42
43 #define UM_PER_INCH 25400
44
45 namespace android {
46
47 struct hwc_worker {
48   pthread_t thread;
49   pthread_mutex_t lock;
50   pthread_cond_t cond;
51   bool exit;
52 };
53
54 typedef struct hwc_drm_display {
55   struct hwc_context_t *ctx;
56   int display;
57
58   std::vector<uint32_t> config_ids;
59
60   struct hwc_worker set_worker;
61
62   std::list<struct hwc_drm_bo> buf_queue;
63   struct hwc_drm_bo front;
64   pthread_mutex_t flip_lock;
65   pthread_cond_t flip_cond;
66
67   int timeline_fd;
68   unsigned timeline_next;
69
70   bool enable_vsync_events;
71   unsigned int vsync_sequence;
72 } hwc_drm_display_t;
73
74 struct hwc_context_t {
75   // map of display:hwc_drm_display_t
76   typedef std::map<int, hwc_drm_display_t> DisplayMap;
77   typedef DisplayMap::iterator DisplayMapIter;
78
79   hwc_context_t() : procs(NULL), importer(NULL) {
80   }
81
82   ~hwc_context_t() {
83     delete importer;
84   }
85
86   hwc_composer_device_1_t device;
87   hwc_procs_t const *procs;
88
89   struct hwc_worker event_worker;
90
91   DisplayMap displays;
92   DrmResources drm;
93   Importer *importer;
94 };
95
96 static int hwc_prepare_layer(hwc_layer_1_t *layer) {
97   /* TODO: We can't handle background right now, defer to sufaceFlinger */
98   if (layer->compositionType == HWC_BACKGROUND) {
99     layer->compositionType = HWC_FRAMEBUFFER;
100     ALOGV("Can't handle background layers yet");
101
102     /* TODO: Support sideband compositions */
103   } else if (layer->compositionType == HWC_SIDEBAND) {
104     layer->compositionType = HWC_FRAMEBUFFER;
105     ALOGV("Can't handle sideband content yet");
106   }
107
108   layer->hints = 0;
109
110   /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
111   if (layer->flags & HWC_IS_CURSOR_LAYER) {
112     ALOGV("Can't handle async cursors yet");
113   }
114
115   /* TODO: Handle transformations */
116   if (layer->transform) {
117     ALOGV("Can't handle transformations yet");
118   }
119
120   /* TODO: Handle blending & plane alpha*/
121   if (layer->blending == HWC_BLENDING_PREMULT ||
122       layer->blending == HWC_BLENDING_COVERAGE) {
123     ALOGV("Can't handle blending yet");
124   }
125
126   /* TODO: Handle cropping & scaling */
127
128   return 0;
129 }
130
131 static int hwc_prepare(hwc_composer_device_1_t * /* dev */, size_t num_displays,
132                        hwc_display_contents_1_t **display_contents) {
133   /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
134
135   for (int i = 0; i < (int)num_displays; ++i) {
136     if (!display_contents[i])
137       continue;
138
139     for (int j = 0; j < (int)display_contents[i]->numHwLayers; ++j) {
140       int ret = hwc_prepare_layer(&display_contents[i]->hwLayers[j]);
141       if (ret) {
142         ALOGE("Failed to prepare layer %d:%d", j, i);
143         return ret;
144       }
145     }
146   }
147
148   return 0;
149 }
150
151 static int hwc_queue_vblank_event(struct hwc_drm_display *hd) {
152   DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(hd->display);
153   if (!crtc) {
154     ALOGE("Failed to get crtc for display");
155     return -ENODEV;
156   }
157
158   drmVBlank vblank;
159   memset(&vblank, 0, sizeof(vblank));
160
161   uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
162   vblank.request.type = (drmVBlankSeqType)(
163       DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT |
164       (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
165   vblank.request.signal = (unsigned long)hd;
166   vblank.request.sequence = hd->vsync_sequence + 1;
167
168   int ret = drmWaitVBlank(hd->ctx->drm.fd(), &vblank);
169   if (ret) {
170     ALOGE("Failed to wait for vblank %d", ret);
171     return ret;
172   }
173
174   return 0;
175 }
176
177 static void hwc_vblank_event_handler(int /* fd */, unsigned int sequence,
178                                      unsigned int tv_sec, unsigned int tv_usec,
179                                      void *user_data) {
180   struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
181
182   if (!hd->enable_vsync_events || !hd->ctx->procs->vsync)
183     return;
184
185   /*
186    * Discard duplicate vsync (can happen when enabling vsync events while
187    * already processing vsyncs).
188    */
189   if (sequence <= hd->vsync_sequence)
190     return;
191
192   hd->vsync_sequence = sequence;
193   int ret = hwc_queue_vblank_event(hd);
194   if (ret)
195     ALOGE("Failed to queue vblank event ret=%d", ret);
196
197   int64_t timestamp =
198       (int64_t)tv_sec * 1000 * 1000 * 1000 + (int64_t)tv_usec * 1000;
199   hd->ctx->procs->vsync(hd->ctx->procs, hd->display, timestamp);
200 }
201
202 static void hwc_flip_event_handler(int /* fd */, unsigned int /* sequence */,
203                                    unsigned int /* tv_sec */,
204                                    unsigned int /* tv_usec */,
205                                    void *user_data) {
206   struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
207
208   int ret = pthread_mutex_lock(&hd->flip_lock);
209   if (ret) {
210     ALOGE("Failed to lock flip lock ret=%d", ret);
211     return;
212   }
213
214   ret = pthread_cond_signal(&hd->flip_cond);
215   if (ret)
216     ALOGE("Failed to signal flip condition ret=%d", ret);
217
218   ret = pthread_mutex_unlock(&hd->flip_lock);
219   if (ret) {
220     ALOGE("Failed to unlock flip lock ret=%d", ret);
221     return;
222   }
223 }
224
225 static void *hwc_event_worker(void *arg) {
226   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
227
228   struct hwc_context_t *ctx = (struct hwc_context_t *)arg;
229   do {
230     fd_set fds;
231     FD_ZERO(&fds);
232     FD_SET(ctx->drm.fd(), &fds);
233
234     drmEventContext event_context;
235     event_context.version = DRM_EVENT_CONTEXT_VERSION;
236     event_context.page_flip_handler = hwc_flip_event_handler;
237     event_context.vblank_handler = hwc_vblank_event_handler;
238
239     int ret;
240     do {
241       ret = select(ctx->drm.fd() + 1, &fds, NULL, NULL, NULL);
242     } while (ret == -1 && errno == EINTR);
243
244     if (ret != 1) {
245       ALOGE("Failed waiting for drm event\n");
246       continue;
247     }
248
249     drmHandleEvent(ctx->drm.fd(), &event_context);
250   } while (true);
251
252   return NULL;
253 }
254
255 static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b) {
256   return a->clock == b->clock && a->hdisplay == b->hdisplay &&
257          a->hsync_start == b->hsync_start && a->hsync_end == b->hsync_end &&
258          a->htotal == b->htotal && a->hskew == b->hskew &&
259          a->vdisplay == b->vdisplay && a->vsync_start == b->vsync_start &&
260          a->vsync_end == b->vsync_end && a->vtotal == b->vtotal &&
261          a->vscan == b->vscan && a->vrefresh == b->vrefresh &&
262          a->flags == b->flags && a->type == b->type &&
263          !strcmp(a->name, b->name);
264 }
265
266 static int hwc_flip(struct hwc_drm_display *hd, struct hwc_drm_bo *buf) {
267   DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(hd->display);
268   if (!crtc) {
269     ALOGE("Failed to get crtc for display %d", hd->display);
270     return -ENODEV;
271   }
272
273   DrmConnector *connector = hd->ctx->drm.GetConnectorForDisplay(hd->display);
274   if (!connector) {
275     ALOGE("Failed to get connector for display %d", hd->display);
276     return -ENODEV;
277   }
278
279   int ret;
280   if (crtc->requires_modeset()) {
281     drmModeModeInfo drm_mode;
282     connector->active_mode().ToModeModeInfo(&drm_mode);
283     uint32_t connector_id = connector->id();
284     ret = drmModeSetCrtc(hd->ctx->drm.fd(), crtc->id(), buf->fb_id, 0, 0,
285                          &connector_id, 1, &drm_mode);
286     if (ret) {
287       ALOGE("Modeset failed for crtc %d", crtc->id());
288       return ret;
289     }
290     crtc->set_requires_modeset(false);
291     return 0;
292   }
293
294   ret = drmModePageFlip(hd->ctx->drm.fd(), crtc->id(), buf->fb_id,
295                         DRM_MODE_PAGE_FLIP_EVENT, hd);
296   if (ret) {
297     ALOGE("Failed to flip buffer for crtc %d", crtc->id());
298     return ret;
299   }
300
301   ret = pthread_cond_wait(&hd->flip_cond, &hd->flip_lock);
302   if (ret) {
303     ALOGE("Failed to wait on condition %d", ret);
304     return ret;
305   }
306
307   return 0;
308 }
309
310 static int hwc_wait_and_set(struct hwc_drm_display *hd,
311                             struct hwc_drm_bo *buf) {
312   int ret;
313   if (buf->acquire_fence_fd >= 0) {
314     ret = sync_wait(buf->acquire_fence_fd, -1);
315     close(buf->acquire_fence_fd);
316     buf->acquire_fence_fd = -1;
317     if (ret) {
318       ALOGE("Failed to wait for acquire %d", ret);
319       return ret;
320     }
321   }
322
323   ret = hwc_flip(hd, buf);
324   if (ret) {
325     ALOGE("Failed to perform flip\n");
326     return ret;
327   }
328
329   if (!hd->ctx->importer->ReleaseBuffer(buf)) {
330     struct drm_gem_close args;
331     memset(&args, 0, sizeof(args));
332     for (int i = 0; i < ARRAY_SIZE(hd->front.gem_handles); ++i) {
333       if (!hd->front.gem_handles[i])
334         continue;
335
336       ret = pthread_mutex_lock(&hd->set_worker.lock);
337       if (ret) {
338         ALOGE("Failed to lock set lock in wait_and_set() %d", ret);
339         continue;
340       }
341
342       /* check for duplicate handle in buf_queue */
343       bool found = false;
344       for (std::list<struct hwc_drm_bo>::iterator bi = hd->buf_queue.begin();
345            bi != hd->buf_queue.end(); ++bi)
346         for (int j = 0; j < ARRAY_SIZE(bi->gem_handles); ++j)
347           if (hd->front.gem_handles[i] == bi->gem_handles[j])
348             found = true;
349
350       for (int j = 0; j < ARRAY_SIZE(buf->gem_handles); ++j)
351         if (hd->front.gem_handles[i] == buf->gem_handles[j])
352           found = true;
353
354       if (!found) {
355         args.handle = hd->front.gem_handles[i];
356         drmIoctl(hd->ctx->drm.fd(), DRM_IOCTL_GEM_CLOSE, &args);
357       }
358       if (pthread_mutex_unlock(&hd->set_worker.lock))
359         ALOGE("Failed to unlock set lock in wait_and_set() %d", ret);
360     }
361   }
362
363   hd->front = *buf;
364
365   return ret;
366 }
367
368 static void *hwc_set_worker(void *arg) {
369   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
370
371   struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
372   int ret = pthread_mutex_lock(&hd->flip_lock);
373   if (ret) {
374     ALOGE("Failed to lock flip lock ret=%d", ret);
375     return NULL;
376   }
377
378   do {
379     ret = pthread_mutex_lock(&hd->set_worker.lock);
380     if (ret) {
381       ALOGE("Failed to lock set lock %d", ret);
382       return NULL;
383     }
384
385     if (hd->set_worker.exit)
386       break;
387
388     if (hd->buf_queue.empty()) {
389       ret = pthread_cond_wait(&hd->set_worker.cond, &hd->set_worker.lock);
390       if (ret) {
391         ALOGE("Failed to wait on condition %d", ret);
392         break;
393       }
394     }
395
396     struct hwc_drm_bo buf;
397     buf = hd->buf_queue.front();
398     hd->buf_queue.pop_front();
399
400     ret = pthread_mutex_unlock(&hd->set_worker.lock);
401     if (ret) {
402       ALOGE("Failed to unlock set lock %d", ret);
403       return NULL;
404     }
405
406     ret = hwc_wait_and_set(hd, &buf);
407     if (ret)
408       ALOGE("Failed to wait and set %d", ret);
409
410     ret = sw_sync_timeline_inc(hd->timeline_fd, 1);
411     if (ret)
412       ALOGE("Failed to increment sync timeline %d", ret);
413   } while (true);
414
415   ret = pthread_mutex_unlock(&hd->set_worker.lock);
416   if (ret)
417     ALOGE("Failed to unlock set lock while exiting %d", ret);
418
419   ret = pthread_mutex_unlock(&hd->flip_lock);
420   if (ret)
421     ALOGE("Failed to unlock flip lock ret=%d", ret);
422
423   return NULL;
424 }
425
426 static void hwc_close_fences(hwc_display_contents_1_t *display_contents) {
427   for (int i = 0; i < (int)display_contents->numHwLayers; ++i) {
428     hwc_layer_1_t *layer = &display_contents->hwLayers[i];
429     if (layer->acquireFenceFd >= 0) {
430       close(layer->acquireFenceFd);
431       layer->acquireFenceFd = -1;
432     }
433   }
434   if (display_contents->outbufAcquireFenceFd >= 0) {
435     close(display_contents->outbufAcquireFenceFd);
436     display_contents->outbufAcquireFenceFd = -1;
437   }
438 }
439
440 static int hwc_set_display(hwc_context_t *ctx, int display,
441                            hwc_display_contents_1_t *display_contents) {
442   struct hwc_drm_display *hd = &ctx->displays[display];
443   DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(display);
444   if (!crtc) {
445     ALOGE("There is no active crtc for display %d", display);
446     hwc_close_fences(display_contents);
447     return -ENOENT;
448   }
449
450   /*
451    * TODO: We can only support one hw layer atm, so choose either the
452    * first one or the framebuffer target.
453    */
454   hwc_layer_1_t *layer = NULL;
455   if (!display_contents->numHwLayers) {
456     return 0;
457   } else if (display_contents->numHwLayers == 1) {
458     layer = &display_contents->hwLayers[0];
459   } else {
460     int i;
461     for (i = 0; i < (int)display_contents->numHwLayers; ++i) {
462       layer = &display_contents->hwLayers[i];
463       if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
464         break;
465     }
466     if (i == (int)display_contents->numHwLayers) {
467       ALOGE("Could not find a suitable layer for display %d", display);
468     }
469   }
470
471   int ret = pthread_mutex_lock(&hd->set_worker.lock);
472   if (ret) {
473     ALOGE("Failed to lock set lock in set() %d", ret);
474     hwc_close_fences(display_contents);
475     return ret;
476   }
477
478   struct hwc_drm_bo buf;
479   ret = ctx->importer->ImportBuffer(layer->handle, &buf);
480   if (ret) {
481     ALOGE("Failed to import handle to drm bo %d", ret);
482     hwc_close_fences(display_contents);
483     return ret;
484   }
485   buf.acquire_fence_fd = layer->acquireFenceFd;
486   layer->acquireFenceFd = -1;
487
488   /*
489    * TODO: Retire and release can use the same sync point here b/c hwc is
490    * restricted to one layer. Once that is no longer true, this will need
491    * to change
492    */
493   ++hd->timeline_next;
494   display_contents->retireFenceFd = sw_sync_fence_create(
495       hd->timeline_fd, "drm_hwc_retire", hd->timeline_next);
496   layer->releaseFenceFd = sw_sync_fence_create(
497       hd->timeline_fd, "drm_hwc_release", hd->timeline_next);
498   hd->buf_queue.push_back(buf);
499
500   ret = pthread_cond_signal(&hd->set_worker.cond);
501   if (ret)
502     ALOGE("Failed to signal set worker %d", ret);
503
504   if (pthread_mutex_unlock(&hd->set_worker.lock))
505     ALOGE("Failed to unlock set lock in set()");
506
507   hwc_close_fences(display_contents);
508   return ret;
509 }
510
511 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
512                    hwc_display_contents_1_t **display_contents) {
513   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
514
515   int ret = 0;
516   for (int i = 0; i < (int)num_displays; ++i) {
517     if (display_contents[i])
518       ret = hwc_set_display(ctx, i, display_contents[i]);
519   }
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   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
527   struct hwc_drm_display *hd = &ctx->displays[display];
528   if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
529     return -EINVAL;
530
531   DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(display);
532   if (!crtc) {
533     ALOGD("Can't service events for display %d, no crtc", display);
534     return -EINVAL;
535   }
536
537   hd->enable_vsync_events = !!enabled;
538
539   if (!hd->enable_vsync_events)
540     return 0;
541
542   /*
543    * Note that it's possible that the event worker is already waiting for
544    * a vsync, and this will be a duplicate request. In that event, we'll
545    * end up firing the event handler twice, and it will discard the second
546    * event. Not ideal, but not worth introducing a bunch of additional
547    * logic/locks/state for.
548    */
549   int ret = hwc_queue_vblank_event(hd);
550   if (ret) {
551     ALOGE("Failed to queue vblank event ret=%d", ret);
552     return ret;
553   }
554
555   return 0;
556 }
557
558 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
559                               int mode) {
560   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
561
562   uint64_t dpmsValue = 0;
563   switch (mode) {
564     case HWC_POWER_MODE_OFF:
565       dpmsValue = DRM_MODE_DPMS_OFF;
566       break;
567
568     /* We can't support dozing right now, so go full on */
569     case HWC_POWER_MODE_DOZE:
570     case HWC_POWER_MODE_DOZE_SUSPEND:
571     case HWC_POWER_MODE_NORMAL:
572       dpmsValue = DRM_MODE_DPMS_ON;
573       break;
574   };
575   return ctx->drm.SetDpmsMode(display, dpmsValue);
576 }
577
578 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
579                      int *value) {
580   switch (what) {
581     case HWC_BACKGROUND_LAYER_SUPPORTED:
582       *value = 0; /* TODO: We should do this */
583       break;
584     case HWC_VSYNC_PERIOD:
585       ALOGW("Query for deprecated vsync value, returning 60Hz");
586       *value = 1000 * 1000 * 1000 / 60;
587       break;
588     case HWC_DISPLAY_TYPES_SUPPORTED:
589       *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
590       break;
591   }
592   return 0;
593 }
594
595 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
596                                hwc_procs_t const *procs) {
597   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
598
599   ctx->procs = procs;
600 }
601
602 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
603                                    int display, uint32_t *configs,
604                                    size_t *num_configs) {
605   if (!*num_configs)
606     return 0;
607
608   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
609   hwc_drm_display_t *hd = &ctx->displays[display];
610   hd->config_ids.clear();
611
612   DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
613   if (!connector) {
614     ALOGE("Failed to get connector for display %d", display);
615     return -ENODEV;
616   }
617
618   int ret = connector->UpdateModes();
619   if (ret) {
620     ALOGE("Failed to update display modes %d", ret);
621     return ret;
622   }
623
624   for (DrmConnector::ModeIter iter = connector->begin_modes();
625        iter != connector->end_modes(); ++iter) {
626     size_t idx = hd->config_ids.size();
627     if (idx == *num_configs)
628       break;
629     hd->config_ids.push_back(iter->id());
630     configs[idx] = iter->id();
631   }
632   *num_configs = hd->config_ids.size();
633   return *num_configs == 0 ? -1 : 0;
634 }
635
636 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
637                                       int display, uint32_t config,
638                                       const uint32_t *attributes,
639                                       int32_t *values) {
640   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
641   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
642   if (!c) {
643     ALOGE("Failed to get DrmConnector for display %d", display);
644     return -ENODEV;
645   }
646   DrmMode mode;
647   for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
648        ++iter) {
649     if (iter->id() == config) {
650       mode = *iter;
651       break;
652     }
653   }
654   if (mode.id() == 0) {
655     ALOGE("Failed to find active mode for display %d", display);
656     return -ENOENT;
657   }
658
659   uint32_t mm_width = c->mm_width();
660   uint32_t mm_height = c->mm_height();
661   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
662     switch (attributes[i]) {
663       case HWC_DISPLAY_VSYNC_PERIOD:
664         values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
665         break;
666       case HWC_DISPLAY_WIDTH:
667         values[i] = mode.h_display();
668         break;
669       case HWC_DISPLAY_HEIGHT:
670         values[i] = mode.v_display();
671         break;
672       case HWC_DISPLAY_DPI_X:
673         /* Dots per 1000 inches */
674         values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
675         break;
676       case HWC_DISPLAY_DPI_Y:
677         /* Dots per 1000 inches */
678         values[i] =
679             mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
680         break;
681     }
682   }
683   return 0;
684 }
685
686 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
687                                  int display) {
688   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
689   DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
690   if (!c) {
691     ALOGE("Failed to get DrmConnector for display %d", display);
692     return -ENODEV;
693   }
694
695   DrmMode mode = c->active_mode();
696   hwc_drm_display_t *hd = &ctx->displays[display];
697   for (size_t i = 0; i < hd->config_ids.size(); ++i) {
698     if (hd->config_ids[i] == mode.id())
699       return i;
700   }
701   return -1;
702 }
703
704 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
705                                  int index) {
706   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
707   hwc_drm_display_t *hd = &ctx->displays[display];
708   if (index >= (int)hd->config_ids.size()) {
709     ALOGE("Invalid config index %d passed in", index);
710     return -EINVAL;
711   }
712
713   int ret =
714       ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
715   if (ret) {
716     ALOGE("Failed to set config for display %d", display);
717     return ret;
718   }
719
720   return ret;
721 }
722
723 static int hwc_destroy_worker(struct hwc_worker *worker) {
724   int ret = pthread_mutex_lock(&worker->lock);
725   if (ret) {
726     ALOGE("Failed to lock in destroy() %d", ret);
727     return ret;
728   }
729
730   worker->exit = true;
731
732   ret |= pthread_cond_signal(&worker->cond);
733   if (ret)
734     ALOGE("Failed to signal cond in destroy() %d", ret);
735
736   ret |= pthread_mutex_unlock(&worker->lock);
737   if (ret)
738     ALOGE("Failed to unlock in destroy() %d", ret);
739
740   ret |= pthread_join(worker->thread, NULL);
741   if (ret && ret != ESRCH)
742     ALOGE("Failed to join thread in destroy() %d", ret);
743
744   return ret;
745 }
746
747 static void hwc_destroy_display(struct hwc_drm_display *hd) {
748   if (hwc_destroy_worker(&hd->set_worker))
749     ALOGE("Destroy set worker failed");
750 }
751
752 static int hwc_device_close(struct hw_device_t *dev) {
753   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
754
755   for (hwc_context_t::DisplayMapIter iter = ctx->displays.begin();
756        iter != ctx->displays.end(); ++iter)
757     hwc_destroy_display(&iter->second);
758
759   if (hwc_destroy_worker(&ctx->event_worker))
760     ALOGE("Destroy event worker failed");
761
762   delete ctx;
763   return 0;
764 }
765
766 static int hwc_initialize_worker(struct hwc_worker *worker,
767                                  void *(*routine)(void *), void *arg) {
768   int ret = pthread_cond_init(&worker->cond, NULL);
769   if (ret) {
770     ALOGE("Failed to create worker condition %d", ret);
771     return ret;
772   }
773
774   ret = pthread_mutex_init(&worker->lock, NULL);
775   if (ret) {
776     ALOGE("Failed to initialize worker lock %d", ret);
777     pthread_cond_destroy(&worker->cond);
778     return ret;
779   }
780
781   worker->exit = false;
782
783   ret = pthread_create(&worker->thread, NULL, routine, arg);
784   if (ret) {
785     ALOGE("Could not create worker thread %d", ret);
786     pthread_mutex_destroy(&worker->lock);
787     pthread_cond_destroy(&worker->cond);
788     return ret;
789   }
790   return 0;
791 }
792
793 /*
794  * TODO: This function sets the active config to the first one in the list. This
795  * should be fixed such that it selects the preferred mode for the display, or
796  * some other, saner, method of choosing the config.
797  */
798 static int hwc_set_initial_config(hwc_drm_display_t *hd) {
799   uint32_t config;
800   size_t num_configs = 1;
801   int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
802                                     &num_configs);
803   if (ret || !num_configs)
804     return 0;
805
806   ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
807   if (ret) {
808     ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
809     return ret;
810   }
811
812   return ret;
813 }
814
815 static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
816   hwc_drm_display_t *hd = &ctx->displays[display];
817   hd->ctx = ctx;
818   hd->display = display;
819   hd->enable_vsync_events = false;
820   hd->vsync_sequence = 0;
821
822   int ret = pthread_mutex_init(&hd->flip_lock, NULL);
823   if (ret) {
824     ALOGE("Failed to initialize flip lock %d", ret);
825     return ret;
826   }
827
828   ret = pthread_cond_init(&hd->flip_cond, NULL);
829   if (ret) {
830     ALOGE("Failed to intiialize flip condition %d", ret);
831     pthread_mutex_destroy(&hd->flip_lock);
832     return ret;
833   }
834
835   ret = sw_sync_timeline_create();
836   if (ret < 0) {
837     ALOGE("Failed to create sw sync timeline %d", ret);
838     pthread_cond_destroy(&hd->flip_cond);
839     pthread_mutex_destroy(&hd->flip_lock);
840     return ret;
841   }
842   hd->timeline_fd = ret;
843
844   /*
845    * Initialize timeline_next to 1, because point 0 will be the very first
846    * set operation. Since we increment every time set() is called,
847    * initializing to 0 would cause an off-by-one error where
848    * surfaceflinger would composite on the front buffer.
849    */
850   hd->timeline_next = 1;
851
852   ret = hwc_set_initial_config(hd);
853   if (ret) {
854     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
855     close(hd->timeline_fd);
856     pthread_cond_destroy(&hd->flip_cond);
857     pthread_mutex_destroy(&hd->flip_lock);
858     return ret;
859   }
860
861   ret = hwc_initialize_worker(&hd->set_worker, hwc_set_worker, hd);
862   if (ret) {
863     ALOGE("Failed to create set worker %d\n", ret);
864     close(hd->timeline_fd);
865     pthread_cond_destroy(&hd->flip_cond);
866     pthread_mutex_destroy(&hd->flip_lock);
867     return ret;
868   }
869
870   return 0;
871 }
872
873 static void hwc_free_conn_list(drmModeConnectorPtr *conn_list, int num_conn) {
874   for (int i = 0; i < num_conn; ++i) {
875     if (conn_list[i])
876       drmModeFreeConnector(conn_list[i]);
877   }
878   free(conn_list);
879 }
880
881 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
882   int ret;
883   for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();
884        c != ctx->drm.end_connectors(); ++c) {
885     ret = hwc_initialize_display(ctx, (*c)->display());
886     if (ret) {
887       ALOGE("Failed to initialize display %d", (*c)->display());
888       return ret;
889     }
890   }
891
892   return 0;
893 }
894
895 static int hwc_device_open(const struct hw_module_t *module, const char *name,
896                            struct hw_device_t **dev) {
897   if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
898     ALOGE("Invalid module name- %s", name);
899     return -EINVAL;
900   }
901
902   struct hwc_context_t *ctx = new hwc_context_t();
903   if (!ctx) {
904     ALOGE("Failed to allocate hwc context");
905     return -ENOMEM;
906   }
907
908   int ret = ctx->drm.Init();
909   if (ret) {
910     ALOGE("Can't initialize Drm object %d", ret);
911     delete ctx;
912     return ret;
913   }
914
915   ctx->importer = Importer::CreateInstance(&ctx->drm);
916   if (!ctx->importer) {
917     ALOGE("Failed to create importer instance");
918     delete ctx;
919     return ret;
920   }
921
922   ret = hwc_enumerate_displays(ctx);
923   if (ret) {
924     ALOGE("Failed to enumerate displays: %s", strerror(ret));
925     delete ctx;
926     return ret;
927   }
928
929   ret = hwc_initialize_worker(&ctx->event_worker, hwc_event_worker, ctx);
930   if (ret) {
931     ALOGE("Failed to create event worker %d\n", ret);
932     delete ctx;
933     return ret;
934   }
935
936   ctx->device.common.tag = HARDWARE_DEVICE_TAG;
937   ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
938   ctx->device.common.module = const_cast<hw_module_t *>(module);
939   ctx->device.common.close = hwc_device_close;
940
941   ctx->device.prepare = hwc_prepare;
942   ctx->device.set = hwc_set;
943   ctx->device.eventControl = hwc_event_control;
944   ctx->device.setPowerMode = hwc_set_power_mode;
945   ctx->device.query = hwc_query;
946   ctx->device.registerProcs = hwc_register_procs;
947   ctx->device.getDisplayConfigs = hwc_get_display_configs;
948   ctx->device.getDisplayAttributes = hwc_get_display_attributes;
949   ctx->device.getActiveConfig = hwc_get_active_config;
950   ctx->device.setActiveConfig = hwc_set_active_config;
951   ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
952
953   *dev = &ctx->device.common;
954
955   return 0;
956 }
957 }
958
959 static struct hw_module_methods_t hwc_module_methods = {
960   open : android::hwc_device_open
961 };
962
963 hwc_module_t HAL_MODULE_INFO_SYM = {
964   common : {
965     tag : HARDWARE_MODULE_TAG,
966     version_major : 1,
967     version_minor : 0,
968     id : HWC_HARDWARE_MODULE_ID,
969     name : "DRM hwcomposer module",
970     author : "The Android Open Source Project",
971     methods : &hwc_module_methods,
972     dso : NULL,
973     reserved : {0},
974   }
975 };