OSDN Git Service

Add missing include for calloc/free.
[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
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <pthread.h>
24 #include <stdlib.h>
25 #include <sys/param.h>
26 #include <sys/resource.h>
27
28 #include <list>
29
30 #include <xf86drm.h>
31 #include <xf86drmMode.h>
32
33 #include <cutils/log.h>
34 #include <cutils/properties.h>
35 #include <hardware/hardware.h>
36 #include <hardware/hwcomposer.h>
37 #include <sw_sync.h>
38 #include <sync/sync.h>
39
40 #define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
41
42 #define HWCOMPOSER_DRM_DEVICE "/dev/dri/card0"
43 #define MAX_NUM_DISPLAYS 3
44 #define UM_PER_INCH 25400
45
46 static const uint32_t panel_types[] = {
47     DRM_MODE_CONNECTOR_LVDS, DRM_MODE_CONNECTOR_eDP, DRM_MODE_CONNECTOR_DSI,
48 };
49
50 struct hwc_worker {
51   pthread_t thread;
52   pthread_mutex_t lock;
53   pthread_cond_t cond;
54   bool exit;
55 };
56
57 struct hwc_drm_display {
58   struct hwc_context_t *ctx;
59   int display;
60
61   uint32_t connector_id;
62
63   drmModeModeInfoPtr configs;
64   uint32_t num_configs;
65
66   drmModeModeInfo active_mode;
67   uint32_t active_crtc;
68   int active_pipe;
69   bool initial_modeset_required;
70
71   struct hwc_worker set_worker;
72
73   std::list<struct hwc_drm_bo> buf_queue;
74   struct hwc_drm_bo front;
75   pthread_mutex_t flip_lock;
76   pthread_cond_t flip_cond;
77
78   int timeline_fd;
79   unsigned timeline_next;
80
81   bool enable_vsync_events;
82   unsigned int vsync_sequence;
83 };
84
85 struct hwc_context_t {
86   hwc_composer_device_1_t device;
87
88   int fd;
89
90   hwc_procs_t const *procs;
91   struct hwc_import_context *import_ctx;
92
93   struct hwc_drm_display displays[MAX_NUM_DISPLAYS];
94   int num_displays;
95
96   struct hwc_worker event_worker;
97 };
98
99 static int hwc_get_drm_display(struct hwc_context_t *ctx, int display,
100                                struct hwc_drm_display **hd) {
101   if (display >= MAX_NUM_DISPLAYS) {
102     ALOGE("Requested display is out-of-bounds %d %d", display,
103           MAX_NUM_DISPLAYS);
104     return -EINVAL;
105   }
106   *hd = &ctx->displays[display];
107   return 0;
108 }
109
110 static int hwc_prepare_layer(hwc_layer_1_t *layer) {
111   /* TODO: We can't handle background right now, defer to sufaceFlinger */
112   if (layer->compositionType == HWC_BACKGROUND) {
113     layer->compositionType = HWC_FRAMEBUFFER;
114     ALOGV("Can't handle background layers yet");
115
116     /* TODO: Support sideband compositions */
117   } else if (layer->compositionType == HWC_SIDEBAND) {
118     layer->compositionType = HWC_FRAMEBUFFER;
119     ALOGV("Can't handle sideband content yet");
120   }
121
122   layer->hints = 0;
123
124   /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
125   if (layer->flags & HWC_IS_CURSOR_LAYER) {
126     ALOGV("Can't handle async cursors yet");
127   }
128
129   /* TODO: Handle transformations */
130   if (layer->transform) {
131     ALOGV("Can't handle transformations yet");
132   }
133
134   /* TODO: Handle blending & plane alpha*/
135   if (layer->blending == HWC_BLENDING_PREMULT ||
136       layer->blending == HWC_BLENDING_COVERAGE) {
137     ALOGV("Can't handle blending yet");
138   }
139
140   /* TODO: Handle cropping & scaling */
141
142   return 0;
143 }
144
145 static int hwc_prepare(hwc_composer_device_1_t * /* dev */, size_t num_displays,
146                        hwc_display_contents_1_t **display_contents) {
147   /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
148
149   for (int i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; ++i) {
150     if (!display_contents[i])
151       continue;
152
153     for (int j = 0; j < (int)display_contents[i]->numHwLayers; ++j) {
154       int ret = hwc_prepare_layer(&display_contents[i]->hwLayers[j]);
155       if (ret) {
156         ALOGE("Failed to prepare layer %d:%d", j, i);
157         return ret;
158       }
159     }
160   }
161
162   return 0;
163 }
164
165 static int hwc_queue_vblank_event(struct hwc_drm_display *hd) {
166   if (hd->active_pipe == -1) {
167     ALOGE("Active pipe is -1 disp=%d", hd->display);
168     return -EINVAL;
169   }
170
171   drmVBlank vblank;
172   memset(&vblank, 0, sizeof(vblank));
173
174   uint32_t high_crtc = (hd->active_pipe << DRM_VBLANK_HIGH_CRTC_SHIFT);
175   vblank.request.type = (drmVBlankSeqType)(
176       DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT |
177       (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
178   vblank.request.signal = (unsigned long)hd;
179   vblank.request.sequence = hd->vsync_sequence + 1;
180
181   int ret = drmWaitVBlank(hd->ctx->fd, &vblank);
182   if (ret) {
183     ALOGE("Failed to wait for vblank %d", ret);
184     return ret;
185   }
186
187   return 0;
188 }
189
190 static void hwc_vblank_event_handler(int /* fd */, unsigned int sequence,
191                                      unsigned int tv_sec, unsigned int tv_usec,
192                                      void *user_data) {
193   struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
194
195   if (!hd->enable_vsync_events || !hd->ctx->procs->vsync)
196     return;
197
198   /*
199    * Discard duplicate vsync (can happen when enabling vsync events while
200    * already processing vsyncs).
201    */
202   if (sequence <= hd->vsync_sequence)
203     return;
204
205   hd->vsync_sequence = sequence;
206   int ret = hwc_queue_vblank_event(hd);
207   if (ret)
208     ALOGE("Failed to queue vblank event ret=%d", ret);
209
210   int64_t timestamp =
211       (int64_t)tv_sec * 1000 * 1000 * 1000 + (int64_t)tv_usec * 1000;
212   hd->ctx->procs->vsync(hd->ctx->procs, hd->display, timestamp);
213 }
214
215 static void hwc_flip_event_handler(int /* fd */, unsigned int /* sequence */,
216                                    unsigned int /* tv_sec */,
217                                    unsigned int /* tv_usec */,
218                                    void *user_data) {
219   struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
220
221   int ret = pthread_mutex_lock(&hd->flip_lock);
222   if (ret) {
223     ALOGE("Failed to lock flip lock ret=%d", ret);
224     return;
225   }
226
227   ret = pthread_cond_signal(&hd->flip_cond);
228   if (ret)
229     ALOGE("Failed to signal flip condition ret=%d", ret);
230
231   ret = pthread_mutex_unlock(&hd->flip_lock);
232   if (ret) {
233     ALOGE("Failed to unlock flip lock ret=%d", ret);
234     return;
235   }
236 }
237
238 static void *hwc_event_worker(void *arg) {
239   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
240
241   struct hwc_context_t *ctx = (struct hwc_context_t *)arg;
242   do {
243     fd_set fds;
244     FD_ZERO(&fds);
245     FD_SET(ctx->fd, &fds);
246
247     drmEventContext event_context;
248     event_context.version = DRM_EVENT_CONTEXT_VERSION;
249     event_context.page_flip_handler = hwc_flip_event_handler;
250     event_context.vblank_handler = hwc_vblank_event_handler;
251
252     int ret;
253     do {
254       ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
255     } while (ret == -1 && errno == EINTR);
256
257     if (ret != 1) {
258       ALOGE("Failed waiting for drm event\n");
259       continue;
260     }
261
262     drmHandleEvent(ctx->fd, &event_context);
263   } while (true);
264
265   return NULL;
266 }
267
268 static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b) {
269   return a->clock == b->clock && a->hdisplay == b->hdisplay &&
270          a->hsync_start == b->hsync_start && a->hsync_end == b->hsync_end &&
271          a->htotal == b->htotal && a->hskew == b->hskew &&
272          a->vdisplay == b->vdisplay && a->vsync_start == b->vsync_start &&
273          a->vsync_end == b->vsync_end && a->vtotal == b->vtotal &&
274          a->vscan == b->vscan && a->vrefresh == b->vrefresh &&
275          a->flags == b->flags && a->type == b->type &&
276          !strcmp(a->name, b->name);
277 }
278
279 static int hwc_modeset_required(struct hwc_drm_display *hd,
280                                 bool *modeset_required) {
281   if (hd->initial_modeset_required) {
282     *modeset_required = true;
283     hd->initial_modeset_required = false;
284     return 0;
285   }
286
287   drmModeCrtcPtr crtc;
288   crtc = drmModeGetCrtc(hd->ctx->fd, hd->active_crtc);
289   if (!crtc) {
290     ALOGE("Failed to get crtc for display %d", hd->display);
291     return -ENODEV;
292   }
293
294   drmModeModeInfoPtr m;
295   m = &hd->active_mode;
296
297   /* Do a modeset if we haven't done one, or the mode has changed */
298   if (!crtc->mode_valid || !hwc_mode_is_equal(m, &crtc->mode))
299     *modeset_required = true;
300   else
301     *modeset_required = false;
302
303   drmModeFreeCrtc(crtc);
304
305   return 0;
306 }
307
308 static int hwc_flip(struct hwc_drm_display *hd, struct hwc_drm_bo *buf) {
309   bool modeset_required;
310   int ret = hwc_modeset_required(hd, &modeset_required);
311   if (ret) {
312     ALOGE("Failed to determine if modeset is required %d", ret);
313     return ret;
314   }
315   if (modeset_required) {
316     ret = drmModeSetCrtc(hd->ctx->fd, hd->active_crtc, buf->fb_id, 0, 0,
317                          &hd->connector_id, 1, &hd->active_mode);
318     if (ret) {
319       ALOGE("Modeset failed for crtc %d", hd->active_crtc);
320       return ret;
321     }
322     return 0;
323   }
324
325   ret = drmModePageFlip(hd->ctx->fd, hd->active_crtc, buf->fb_id,
326                         DRM_MODE_PAGE_FLIP_EVENT, hd);
327   if (ret) {
328     ALOGE("Failed to flip buffer for crtc %d", hd->active_crtc);
329     return ret;
330   }
331
332   ret = pthread_cond_wait(&hd->flip_cond, &hd->flip_lock);
333   if (ret) {
334     ALOGE("Failed to wait on condition %d", ret);
335     return ret;
336   }
337
338   return 0;
339 }
340
341 static int hwc_wait_and_set(struct hwc_drm_display *hd,
342                             struct hwc_drm_bo *buf) {
343   int ret;
344   if (buf->acquire_fence_fd >= 0) {
345     ret = sync_wait(buf->acquire_fence_fd, -1);
346     close(buf->acquire_fence_fd);
347     buf->acquire_fence_fd = -1;
348     if (ret) {
349       ALOGE("Failed to wait for acquire %d", ret);
350       return ret;
351     }
352   }
353
354   ret = hwc_flip(hd, buf);
355   if (ret) {
356     ALOGE("Failed to perform flip\n");
357     return ret;
358   }
359
360   if (hwc_import_bo_release(hd->ctx->fd, hd->ctx->import_ctx, &hd->front)) {
361     struct drm_gem_close args;
362     memset(&args, 0, sizeof(args));
363     for (int i = 0; i < ARRAY_SIZE(hd->front.gem_handles); ++i) {
364       if (!hd->front.gem_handles[i])
365         continue;
366
367       ret = pthread_mutex_lock(&hd->set_worker.lock);
368       if (ret) {
369         ALOGE("Failed to lock set lock in wait_and_set() %d", ret);
370         continue;
371       }
372
373       /* check for duplicate handle in buf_queue */
374       bool found = false;
375       for (std::list<struct hwc_drm_bo>::iterator bi = hd->buf_queue.begin();
376            bi != hd->buf_queue.end(); ++bi)
377         for (int j = 0; j < ARRAY_SIZE(bi->gem_handles); ++j)
378           if (hd->front.gem_handles[i] == bi->gem_handles[j])
379             found = true;
380
381       for (int j = 0; j < ARRAY_SIZE(buf->gem_handles); ++j)
382         if (hd->front.gem_handles[i] == buf->gem_handles[j])
383           found = true;
384
385       if (!found) {
386         args.handle = hd->front.gem_handles[i];
387         drmIoctl(hd->ctx->fd, DRM_IOCTL_GEM_CLOSE, &args);
388       }
389       if (pthread_mutex_unlock(&hd->set_worker.lock))
390         ALOGE("Failed to unlock set lock in wait_and_set() %d", ret);
391     }
392   }
393
394   hd->front = *buf;
395
396   return ret;
397 }
398
399 static void *hwc_set_worker(void *arg) {
400   setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
401
402   struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
403   int ret = pthread_mutex_lock(&hd->flip_lock);
404   if (ret) {
405     ALOGE("Failed to lock flip lock ret=%d", ret);
406     return NULL;
407   }
408
409   do {
410     ret = pthread_mutex_lock(&hd->set_worker.lock);
411     if (ret) {
412       ALOGE("Failed to lock set lock %d", ret);
413       return NULL;
414     }
415
416     if (hd->set_worker.exit)
417       break;
418
419     if (hd->buf_queue.empty()) {
420       ret = pthread_cond_wait(&hd->set_worker.cond, &hd->set_worker.lock);
421       if (ret) {
422         ALOGE("Failed to wait on condition %d", ret);
423         break;
424       }
425     }
426
427     struct hwc_drm_bo buf;
428     buf = hd->buf_queue.front();
429     hd->buf_queue.pop_front();
430
431     ret = pthread_mutex_unlock(&hd->set_worker.lock);
432     if (ret) {
433       ALOGE("Failed to unlock set lock %d", ret);
434       return NULL;
435     }
436
437     ret = hwc_wait_and_set(hd, &buf);
438     if (ret)
439       ALOGE("Failed to wait and set %d", ret);
440
441     ret = sw_sync_timeline_inc(hd->timeline_fd, 1);
442     if (ret)
443       ALOGE("Failed to increment sync timeline %d", ret);
444   } while (true);
445
446   ret = pthread_mutex_unlock(&hd->set_worker.lock);
447   if (ret)
448     ALOGE("Failed to unlock set lock while exiting %d", ret);
449
450   ret = pthread_mutex_unlock(&hd->flip_lock);
451   if (ret)
452     ALOGE("Failed to unlock flip lock ret=%d", ret);
453
454   return NULL;
455 }
456
457 static void hwc_close_fences(hwc_display_contents_1_t *display_contents) {
458   for (int i = 0; i < (int)display_contents->numHwLayers; ++i) {
459     hwc_layer_1_t *layer = &display_contents->hwLayers[i];
460     if (layer->acquireFenceFd >= 0) {
461       close(layer->acquireFenceFd);
462       layer->acquireFenceFd = -1;
463     }
464   }
465   if (display_contents->outbufAcquireFenceFd >= 0) {
466     close(display_contents->outbufAcquireFenceFd);
467     display_contents->outbufAcquireFenceFd = -1;
468   }
469 }
470
471 static int hwc_set_display(hwc_context_t *ctx, int display,
472                            hwc_display_contents_1_t *display_contents) {
473   struct hwc_drm_display *hd = NULL;
474   int ret = hwc_get_drm_display(ctx, display, &hd);
475   if (ret) {
476     hwc_close_fences(display_contents);
477     return ret;
478   }
479
480   if (!hd->active_crtc) {
481     ALOGE("There is no active crtc for display %d", display);
482     hwc_close_fences(display_contents);
483     return -ENOENT;
484   }
485
486   /*
487    * TODO: We can only support one hw layer atm, so choose either the
488    * first one or the framebuffer target.
489    */
490   hwc_layer_1_t *layer = NULL;
491   if (!display_contents->numHwLayers) {
492     return 0;
493   } else if (display_contents->numHwLayers == 1) {
494     layer = &display_contents->hwLayers[0];
495   } else {
496     int i;
497     for (i = 0; i < (int)display_contents->numHwLayers; ++i) {
498       layer = &display_contents->hwLayers[i];
499       if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
500         break;
501     }
502     if (i == (int)display_contents->numHwLayers) {
503       ALOGE("Could not find a suitable layer for display %d", display);
504     }
505   }
506
507   ret = pthread_mutex_lock(&hd->set_worker.lock);
508   if (ret) {
509     ALOGE("Failed to lock set lock in set() %d", ret);
510     hwc_close_fences(display_contents);
511     return ret;
512   }
513
514   struct hwc_drm_bo buf;
515   memset(&buf, 0, sizeof(buf));
516   ret = hwc_import_bo_create(ctx->fd, ctx->import_ctx, layer->handle, &buf);
517   if (ret) {
518     ALOGE("Failed to import handle to drm bo %d", ret);
519     hwc_close_fences(display_contents);
520     return ret;
521   }
522   buf.acquire_fence_fd = layer->acquireFenceFd;
523   layer->acquireFenceFd = -1;
524
525   /*
526    * TODO: Retire and release can use the same sync point here b/c hwc is
527    * restricted to one layer. Once that is no longer true, this will need
528    * to change
529    */
530   ++hd->timeline_next;
531   display_contents->retireFenceFd = sw_sync_fence_create(
532       hd->timeline_fd, "drm_hwc_retire", hd->timeline_next);
533   layer->releaseFenceFd = sw_sync_fence_create(
534       hd->timeline_fd, "drm_hwc_release", hd->timeline_next);
535   hd->buf_queue.push_back(buf);
536
537   ret = pthread_cond_signal(&hd->set_worker.cond);
538   if (ret)
539     ALOGE("Failed to signal set worker %d", ret);
540
541   if (pthread_mutex_unlock(&hd->set_worker.lock))
542     ALOGE("Failed to unlock set lock in set()");
543
544   hwc_close_fences(display_contents);
545   return ret;
546 }
547
548 static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
549                    hwc_display_contents_1_t **display_contents) {
550   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
551
552   int ret = 0;
553   for (int i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; ++i) {
554     if (display_contents[i])
555       ret = hwc_set_display(ctx, i, display_contents[i]);
556   }
557
558   return ret;
559 }
560
561 static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
562                              int event, int enabled) {
563   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
564   struct hwc_drm_display *hd = NULL;
565   int ret = hwc_get_drm_display(ctx, display, &hd);
566   if (ret)
567     return ret;
568
569   if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
570     return -EINVAL;
571
572   if (hd->active_pipe == -1) {
573     ALOGD("Can't service events for display %d, no pipe", display);
574     return -EINVAL;
575   }
576
577   hd->enable_vsync_events = !!enabled;
578
579   if (!hd->enable_vsync_events)
580     return 0;
581
582   /*
583    * Note that it's possible that the event worker is already waiting for
584    * a vsync, and this will be a duplicate request. In that event, we'll
585    * end up firing the event handler twice, and it will discard the second
586    * event. Not ideal, but not worth introducing a bunch of additional
587    * logic/locks/state for.
588    */
589   ret = hwc_queue_vblank_event(hd);
590   if (ret) {
591     ALOGE("Failed to queue vblank event ret=%d", ret);
592     return ret;
593   }
594
595   return 0;
596 }
597
598 static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
599                               int mode) {
600   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
601
602   struct hwc_drm_display *hd = NULL;
603   int ret = hwc_get_drm_display(ctx, display, &hd);
604   if (ret)
605     return ret;
606
607   drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
608   if (!c) {
609     ALOGE("Failed to get connector %d", display);
610     return -ENODEV;
611   }
612
613   uint32_t dpms_prop = 0;
614   for (int i = 0; !dpms_prop && i < c->count_props; ++i) {
615     drmModePropertyPtr p;
616
617     p = drmModeGetProperty(ctx->fd, c->props[i]);
618     if (!p)
619       continue;
620
621     if (!strcmp(p->name, "DPMS"))
622       dpms_prop = c->props[i];
623
624     drmModeFreeProperty(p);
625   }
626   if (!dpms_prop) {
627     ALOGE("Failed to get DPMS property from display %d", display);
628     drmModeFreeConnector(c);
629     return -ENOENT;
630   }
631
632   uint64_t dpms_value = 0;
633   switch (mode) {
634     case HWC_POWER_MODE_OFF:
635       dpms_value = DRM_MODE_DPMS_OFF;
636       break;
637
638     /* We can't support dozing right now, so go full on */
639     case HWC_POWER_MODE_DOZE:
640     case HWC_POWER_MODE_DOZE_SUSPEND:
641     case HWC_POWER_MODE_NORMAL:
642       dpms_value = DRM_MODE_DPMS_ON;
643       break;
644   };
645
646   ret = drmModeConnectorSetProperty(ctx->fd, c->connector_id, dpms_prop,
647                                     dpms_value);
648   if (ret) {
649     ALOGE("Failed to set DPMS property for display %d", display);
650     drmModeFreeConnector(c);
651     return ret;
652   }
653
654   drmModeFreeConnector(c);
655   return 0;
656 }
657
658 static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
659                      int *value) {
660   switch (what) {
661     case HWC_BACKGROUND_LAYER_SUPPORTED:
662       *value = 0; /* TODO: We should do this */
663       break;
664     case HWC_VSYNC_PERIOD:
665       ALOGW("Query for deprecated vsync value, returning 60Hz");
666       *value = 1000 * 1000 * 1000 / 60;
667       break;
668     case HWC_DISPLAY_TYPES_SUPPORTED:
669       *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
670       break;
671   }
672   return 0;
673 }
674
675 static void hwc_register_procs(struct hwc_composer_device_1 *dev,
676                                hwc_procs_t const *procs) {
677   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
678
679   ctx->procs = procs;
680 }
681
682 static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
683                                    int display, uint32_t *configs,
684                                    size_t *numConfigs) {
685   if (!*numConfigs)
686     return 0;
687
688   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
689   struct hwc_drm_display *hd = NULL;
690   int ret = hwc_get_drm_display(ctx, display, &hd);
691   if (ret)
692     return ret;
693
694   drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
695   if (!c) {
696     ALOGE("Failed to get connector %d", display);
697     return -ENODEV;
698   }
699
700   if (hd->configs) {
701     free(hd->configs);
702     hd->configs = NULL;
703   }
704
705   if (c->connection == DRM_MODE_DISCONNECTED) {
706     drmModeFreeConnector(c);
707     return -ENODEV;
708   }
709
710   hd->configs =
711       (drmModeModeInfoPtr)calloc(c->count_modes, sizeof(*hd->configs));
712   if (!hd->configs) {
713     ALOGE("Failed to allocate config list for display %d", display);
714     hd->num_configs = 0;
715     drmModeFreeConnector(c);
716     return -ENOMEM;
717   }
718
719   for (int i = 0; i < c->count_modes; ++i) {
720     drmModeModeInfoPtr m = &hd->configs[i];
721
722     memcpy(m, &c->modes[i], sizeof(*m));
723
724     if (i < (int)*numConfigs)
725       configs[i] = i;
726   }
727
728   hd->num_configs = c->count_modes;
729   *numConfigs = MIN(c->count_modes, *numConfigs);
730
731   drmModeFreeConnector(c);
732   return 0;
733 }
734
735 static int hwc_check_config_valid(struct hwc_context_t *ctx,
736                                   drmModeConnectorPtr connector, int display,
737                                   int config_idx) {
738   struct hwc_drm_display *hd = NULL;
739   int ret = hwc_get_drm_display(ctx, display, &hd);
740   if (ret)
741     return ret;
742
743   /* Make sure the requested config is still valid for the display */
744   drmModeModeInfoPtr m = NULL;
745   for (int i = 0; i < connector->count_modes; ++i) {
746     if (hwc_mode_is_equal(&connector->modes[i], &hd->configs[config_idx])) {
747       m = &hd->configs[config_idx];
748       break;
749     }
750   }
751   if (!m)
752     return -ENOENT;
753
754   return 0;
755 }
756
757 static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
758                                       int display, uint32_t config,
759                                       const uint32_t *attributes,
760                                       int32_t *values) {
761   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
762   struct hwc_drm_display *hd = NULL;
763   int ret = hwc_get_drm_display(ctx, display, &hd);
764   if (ret)
765     return ret;
766
767   if (config >= hd->num_configs) {
768     ALOGE("Requested config is out-of-bounds %d %d", config, hd->num_configs);
769     return -EINVAL;
770   }
771
772   drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
773   if (!c) {
774     ALOGE("Failed to get connector %d", display);
775     return -ENODEV;
776   }
777
778   ret = hwc_check_config_valid(ctx, c, display, (int)config);
779   if (ret) {
780     ALOGE("Provided config is no longer valid %u", config);
781     drmModeFreeConnector(c);
782     return ret;
783   }
784
785   drmModeModeInfoPtr m = &hd->configs[config];
786   for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
787     switch (attributes[i]) {
788       case HWC_DISPLAY_VSYNC_PERIOD:
789         values[i] = 1000 * 1000 * 1000 / m->vrefresh;
790         break;
791       case HWC_DISPLAY_WIDTH:
792         values[i] = m->hdisplay;
793         break;
794       case HWC_DISPLAY_HEIGHT:
795         values[i] = m->vdisplay;
796         break;
797       case HWC_DISPLAY_DPI_X:
798         /* Dots per 1000 inches */
799         values[i] = c->mmWidth ? (m->hdisplay * UM_PER_INCH) / c->mmWidth : 0;
800         break;
801       case HWC_DISPLAY_DPI_Y:
802         /* Dots per 1000 inches */
803         values[i] = c->mmHeight ? (m->vdisplay * UM_PER_INCH) / c->mmHeight : 0;
804         break;
805     }
806   }
807
808   drmModeFreeConnector(c);
809   return 0;
810 }
811
812 static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
813                                  int display) {
814   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
815   struct hwc_drm_display *hd = NULL;
816   int ret = hwc_get_drm_display(ctx, display, &hd);
817   if (ret)
818     return ret;
819
820   /* Find the current mode in the config list */
821   int index = -1;
822   for (int i = 0; i < (int)hd->num_configs; ++i) {
823     if (hwc_mode_is_equal(&hd->configs[i], &hd->active_mode)) {
824       index = i;
825       break;
826     }
827   }
828   return index;
829 }
830
831 static bool hwc_crtc_is_bound(struct hwc_context_t *ctx, uint32_t crtc_id) {
832   for (int i = 0; i < MAX_NUM_DISPLAYS; ++i) {
833     if (ctx->displays[i].active_crtc == crtc_id)
834       return true;
835   }
836   return false;
837 }
838
839 static int hwc_try_encoder(struct hwc_context_t *ctx, drmModeResPtr r,
840                            uint32_t encoder_id, uint32_t *crtc_id) {
841   drmModeEncoderPtr e = drmModeGetEncoder(ctx->fd, encoder_id);
842   if (!e) {
843     ALOGE("Failed to get encoder for connector %d", encoder_id);
844     return -ENODEV;
845   }
846
847   /* First try to use the currently-bound crtc */
848   int ret = 0;
849   if (e->crtc_id) {
850     if (!hwc_crtc_is_bound(ctx, e->crtc_id)) {
851       *crtc_id = e->crtc_id;
852       drmModeFreeEncoder(e);
853       return 0;
854     }
855   }
856
857   /* Try to find a possible crtc which will work */
858   for (int i = 0; i < r->count_crtcs; ++i) {
859     if (!(e->possible_crtcs & (1 << i)))
860       continue;
861
862     /* We've already tried this earlier */
863     if (e->crtc_id == r->crtcs[i])
864       continue;
865
866     if (!hwc_crtc_is_bound(ctx, r->crtcs[i])) {
867       *crtc_id = r->crtcs[i];
868       drmModeFreeEncoder(e);
869       return 0;
870     }
871   }
872
873   /* We can't use the encoder, but nothing went wrong, try another one */
874   drmModeFreeEncoder(e);
875   return -EAGAIN;
876 }
877
878 static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
879                                  int index) {
880   struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
881   struct hwc_drm_display *hd = NULL;
882   int ret = hwc_get_drm_display(ctx, display, &hd);
883   if (ret)
884     return ret;
885
886   drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
887   if (!c) {
888     ALOGE("Failed to get connector %d", display);
889     return -ENODEV;
890   }
891
892   if (c->connection == DRM_MODE_DISCONNECTED) {
893     ALOGE("Tried to configure a disconnected display %d", display);
894     drmModeFreeConnector(c);
895     return -ENODEV;
896   }
897
898   if (index >= c->count_modes) {
899     ALOGE("Index is out-of-bounds %d/%d", index, c->count_modes);
900     drmModeFreeConnector(c);
901     return -ENOENT;
902   }
903
904   drmModeResPtr r = drmModeGetResources(ctx->fd);
905   if (!r) {
906     ALOGE("Failed to get drm resources");
907     drmModeFreeResources(r);
908     drmModeFreeConnector(c);
909     return -ENODEV;
910   }
911
912   /* We no longer have an active_crtc */
913   hd->active_crtc = 0;
914   hd->active_pipe = -1;
915
916   /* First, try to use the currently-connected encoder */
917   uint32_t crtc_id = 0;
918   if (c->encoder_id) {
919     ret = hwc_try_encoder(ctx, r, c->encoder_id, &crtc_id);
920     if (ret && ret != -EAGAIN) {
921       ALOGE("Encoder try failed %d", ret);
922       drmModeFreeResources(r);
923       drmModeFreeConnector(c);
924       return ret;
925     }
926   }
927
928   /* We couldn't find a crtc with the attached encoder, try the others */
929   if (!crtc_id) {
930     for (int i = 0; i < c->count_encoders; ++i) {
931       ret = hwc_try_encoder(ctx, r, c->encoders[i], &crtc_id);
932       if (!ret) {
933         break;
934       } else if (ret != -EAGAIN) {
935         ALOGE("Encoder try failed %d", ret);
936         drmModeFreeResources(r);
937         drmModeFreeConnector(c);
938         return ret;
939       }
940     }
941     if (!crtc_id) {
942       ALOGE("Couldn't find valid crtc to modeset");
943       drmModeFreeConnector(c);
944       drmModeFreeResources(r);
945       return -EINVAL;
946     }
947   }
948   drmModeFreeConnector(c);
949
950   hd->active_crtc = crtc_id;
951   memcpy(&hd->active_mode, &hd->configs[index], sizeof(hd->active_mode));
952
953   /* Find the pipe corresponding to the crtc_id */
954   for (int i = 0; i < r->count_crtcs; ++i) {
955     /* We've already tried this earlier */
956     if (r->crtcs[i] == crtc_id) {
957       hd->active_pipe = i;
958       break;
959     }
960   }
961   drmModeFreeResources(r);
962   /* This should never happen... hehehe */
963   if (hd->active_pipe == -1) {
964     ALOGE("Active crtc was not found in resources!!");
965     return -ENODEV;
966   }
967
968   /* TODO: Once we have atomic, set the crtc timing info here */
969   return 0;
970 }
971
972 static int hwc_destroy_worker(struct hwc_worker *worker) {
973   int ret = pthread_mutex_lock(&worker->lock);
974   if (ret) {
975     ALOGE("Failed to lock in destroy() %d", ret);
976     return ret;
977   }
978
979   worker->exit = true;
980
981   ret |= pthread_cond_signal(&worker->cond);
982   if (ret)
983     ALOGE("Failed to signal cond in destroy() %d", ret);
984
985   ret |= pthread_mutex_unlock(&worker->lock);
986   if (ret)
987     ALOGE("Failed to unlock in destroy() %d", ret);
988
989   ret |= pthread_join(worker->thread, NULL);
990   if (ret && ret != ESRCH)
991     ALOGE("Failed to join thread in destroy() %d", ret);
992
993   return ret;
994 }
995
996 static void hwc_destroy_display(struct hwc_drm_display *hd) {
997   if (hwc_destroy_worker(&hd->set_worker))
998     ALOGE("Destroy set worker failed");
999 }
1000
1001 static int hwc_device_close(struct hw_device_t *dev) {
1002   struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
1003
1004   for (int i = 0; i < MAX_NUM_DISPLAYS; ++i)
1005     hwc_destroy_display(&ctx->displays[i]);
1006
1007   if (hwc_destroy_worker(&ctx->event_worker))
1008     ALOGE("Destroy event worker failed");
1009
1010   drmClose(ctx->fd);
1011
1012   int ret = hwc_import_destroy(ctx->import_ctx);
1013   if (ret)
1014     ALOGE("Could not destroy import %d", ret);
1015
1016   delete ctx;
1017
1018   return 0;
1019 }
1020
1021 static int hwc_initialize_worker(struct hwc_worker *worker,
1022                                  void *(*routine)(void *), void *arg) {
1023   int ret = pthread_cond_init(&worker->cond, NULL);
1024   if (ret) {
1025     ALOGE("Failed to create worker condition %d", ret);
1026     return ret;
1027   }
1028
1029   ret = pthread_mutex_init(&worker->lock, NULL);
1030   if (ret) {
1031     ALOGE("Failed to initialize worker lock %d", ret);
1032     pthread_cond_destroy(&worker->cond);
1033     return ret;
1034   }
1035
1036   worker->exit = false;
1037
1038   ret = pthread_create(&worker->thread, NULL, routine, arg);
1039   if (ret) {
1040     ALOGE("Could not create worker thread %d", ret);
1041     pthread_mutex_destroy(&worker->lock);
1042     pthread_cond_destroy(&worker->cond);
1043     return ret;
1044   }
1045   return 0;
1046 }
1047
1048 /*
1049  * TODO: This function sets the active config to the first one in the list. This
1050  * should be fixed such that it selects the preferred mode for the display, or
1051  * some other, saner, method of choosing the config.
1052  */
1053 static int hwc_set_initial_config(struct hwc_drm_display *hd) {
1054   uint32_t config;
1055   size_t num_configs = 1;
1056   int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
1057                                     &num_configs);
1058   if (ret || !num_configs)
1059     return 0;
1060
1061   ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
1062   if (ret) {
1063     ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
1064     return ret;
1065   }
1066
1067   return ret;
1068 }
1069
1070 static int hwc_initialize_display(struct hwc_context_t *ctx, int display,
1071                                   uint32_t connector_id) {
1072   struct hwc_drm_display *hd = NULL;
1073   int ret = hwc_get_drm_display(ctx, display, &hd);
1074   if (ret)
1075     return ret;
1076
1077   hd->ctx = ctx;
1078   hd->display = display;
1079   hd->active_pipe = -1;
1080   hd->initial_modeset_required = true;
1081   hd->connector_id = connector_id;
1082   hd->enable_vsync_events = false;
1083   hd->vsync_sequence = 0;
1084
1085   ret = pthread_mutex_init(&hd->flip_lock, NULL);
1086   if (ret) {
1087     ALOGE("Failed to initialize flip lock %d", ret);
1088     return ret;
1089   }
1090
1091   ret = pthread_cond_init(&hd->flip_cond, NULL);
1092   if (ret) {
1093     ALOGE("Failed to intiialize flip condition %d", ret);
1094     pthread_mutex_destroy(&hd->flip_lock);
1095     return ret;
1096   }
1097
1098   ret = sw_sync_timeline_create();
1099   if (ret < 0) {
1100     ALOGE("Failed to create sw sync timeline %d", ret);
1101     pthread_cond_destroy(&hd->flip_cond);
1102     pthread_mutex_destroy(&hd->flip_lock);
1103     return ret;
1104   }
1105   hd->timeline_fd = ret;
1106
1107   /*
1108    * Initialize timeline_next to 1, because point 0 will be the very first
1109    * set operation. Since we increment every time set() is called,
1110    * initializing to 0 would cause an off-by-one error where
1111    * surfaceflinger would composite on the front buffer.
1112    */
1113   hd->timeline_next = 1;
1114
1115   ret = hwc_set_initial_config(hd);
1116   if (ret) {
1117     ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
1118     close(hd->timeline_fd);
1119     pthread_cond_destroy(&hd->flip_cond);
1120     pthread_mutex_destroy(&hd->flip_lock);
1121     return ret;
1122   }
1123
1124   ret = hwc_initialize_worker(&hd->set_worker, hwc_set_worker, hd);
1125   if (ret) {
1126     ALOGE("Failed to create set worker %d\n", ret);
1127     close(hd->timeline_fd);
1128     pthread_cond_destroy(&hd->flip_cond);
1129     pthread_mutex_destroy(&hd->flip_lock);
1130     return ret;
1131   }
1132
1133   return 0;
1134 }
1135
1136 static void hwc_free_conn_list(drmModeConnectorPtr *conn_list, int num_conn) {
1137   for (int i = 0; i < num_conn; ++i) {
1138     if (conn_list[i])
1139       drmModeFreeConnector(conn_list[i]);
1140   }
1141   free(conn_list);
1142 }
1143
1144 static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
1145   drmModeResPtr res = drmModeGetResources(ctx->fd);
1146   if (!res) {
1147     ALOGE("Failed to get drm resources");
1148     return -ENODEV;
1149   }
1150   int num_connectors = res->count_connectors;
1151
1152   drmModeConnectorPtr *conn_list =
1153       (drmModeConnector **)calloc(num_connectors, sizeof(*conn_list));
1154   if (!conn_list) {
1155     ALOGE("Failed to allocate connector list");
1156     drmModeFreeResources(res);
1157     return -ENOMEM;
1158   }
1159
1160   for (int i = 0; i < num_connectors; ++i) {
1161     conn_list[i] = drmModeGetConnector(ctx->fd, res->connectors[i]);
1162     if (!conn_list[i]) {
1163       ALOGE("Failed to get connector %d", res->connectors[i]);
1164       drmModeFreeResources(res);
1165       return -ENODEV;
1166     }
1167   }
1168   drmModeFreeResources(res);
1169
1170   ctx->num_displays = 0;
1171
1172   /* Find a connected, panel type connector for display 0 */
1173   for (int i = 0; i < num_connectors; ++i) {
1174     drmModeConnectorPtr c = conn_list[i];
1175
1176     int j;
1177     for (j = 0; j < ARRAY_SIZE(panel_types); ++j) {
1178       if (c->connector_type == panel_types[j] &&
1179           c->connection == DRM_MODE_CONNECTED)
1180         break;
1181     }
1182     if (j == ARRAY_SIZE(panel_types))
1183       continue;
1184
1185     hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1186     ++ctx->num_displays;
1187     break;
1188   }
1189
1190   struct hwc_drm_display *panel_hd;
1191   int ret = hwc_get_drm_display(ctx, 0, &panel_hd);
1192   if (ret) {
1193     hwc_free_conn_list(conn_list, num_connectors);
1194     return ret;
1195   }
1196
1197   /* Fill in the other displays */
1198   for (int i = 0; i < num_connectors; ++i) {
1199     drmModeConnectorPtr c = conn_list[i];
1200
1201     if (panel_hd->connector_id == c->connector_id)
1202       continue;
1203
1204     hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1205     ++ctx->num_displays;
1206   }
1207   hwc_free_conn_list(conn_list, num_connectors);
1208
1209   ret = hwc_initialize_worker(&ctx->event_worker, hwc_event_worker, ctx);
1210   if (ret) {
1211     ALOGE("Failed to create event worker %d\n", ret);
1212     return ret;
1213   }
1214
1215   return 0;
1216 }
1217
1218 static int hwc_device_open(const struct hw_module_t *module, const char *name,
1219                            struct hw_device_t **dev) {
1220   if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1221     ALOGE("Invalid module name- %s", name);
1222     return -EINVAL;
1223   }
1224
1225   struct hwc_context_t *ctx = new hwc_context_t();
1226   if (!ctx) {
1227     ALOGE("Failed to allocate hwc context");
1228     return -ENOMEM;
1229   }
1230
1231   int ret = hwc_import_init(&ctx->import_ctx);
1232   if (ret) {
1233     ALOGE("Failed to initialize import context");
1234     delete ctx;
1235     return ret;
1236   }
1237
1238   char path[PROPERTY_VALUE_MAX];
1239   property_get("hwc.drm.device", path, HWCOMPOSER_DRM_DEVICE);
1240   /* TODO: Use drmOpenControl here instead */
1241   ctx->fd = open(path, O_RDWR);
1242   if (ctx->fd < 0) {
1243     ALOGE("Failed to open dri- %s", strerror(-errno));
1244     delete ctx;
1245     return -ENOENT;
1246   }
1247
1248   ret = hwc_enumerate_displays(ctx);
1249   if (ret) {
1250     ALOGE("Failed to enumerate displays: %s", strerror(ret));
1251     close(ctx->fd);
1252     delete ctx;
1253     return ret;
1254   }
1255
1256   ctx->device.common.tag = HARDWARE_DEVICE_TAG;
1257   ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
1258   ctx->device.common.module = const_cast<hw_module_t *>(module);
1259   ctx->device.common.close = hwc_device_close;
1260
1261   ctx->device.prepare = hwc_prepare;
1262   ctx->device.set = hwc_set;
1263   ctx->device.eventControl = hwc_event_control;
1264   ctx->device.setPowerMode = hwc_set_power_mode;
1265   ctx->device.query = hwc_query;
1266   ctx->device.registerProcs = hwc_register_procs;
1267   ctx->device.getDisplayConfigs = hwc_get_display_configs;
1268   ctx->device.getDisplayAttributes = hwc_get_display_attributes;
1269   ctx->device.getActiveConfig = hwc_get_active_config;
1270   ctx->device.setActiveConfig = hwc_set_active_config;
1271   ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
1272
1273   *dev = &ctx->device.common;
1274
1275   return 0;
1276 }
1277
1278 static struct hw_module_methods_t hwc_module_methods = {open : hwc_device_open};
1279
1280 hwc_module_t HAL_MODULE_INFO_SYM = {
1281   common : {
1282     tag : HARDWARE_MODULE_TAG,
1283     version_major : 1,
1284     version_minor : 0,
1285     id : HWC_HARDWARE_MODULE_ID,
1286     name : "DRM hwcomposer module",
1287     author : "The Android Open Source Project",
1288     methods : &hwc_module_methods,
1289     dso : NULL,
1290     reserved : {0},
1291   }
1292 };