OSDN Git Service

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