blob: f2e04b4b7d92d5fa5f720590db86f5a2b5f5238d [file] [log] [blame]
Sean Paule0c4c3d2015-01-20 16:56:04 -05001/*
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
Sean Paulef8f1f92015-04-29 16:05:23 -040019#include "drm_hwcomposer.h"
20
Sean Paule0c4c3d2015-01-20 16:56:04 -050021#include <errno.h>
Sean Paulef8f1f92015-04-29 16:05:23 -040022#include <fcntl.h>
Allen Martin3d3f70a2015-02-21 21:20:17 -080023#include <list>
Sean Paulef8f1f92015-04-29 16:05:23 -040024#include <pthread.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050025#include <sys/param.h>
Sean Paul9aa5ad32015-01-22 15:47:54 -050026#include <sys/resource.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050027#include <xf86drm.h>
28#include <xf86drmMode.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050029
Sean Paulef8f1f92015-04-29 16:05:23 -040030#include <cutils/log.h>
31#include <cutils/properties.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050032#include <hardware/hardware.h>
33#include <hardware/hwcomposer.h>
Sean Paulf1dc1912015-01-24 01:34:31 -050034#include <sw_sync.h>
Sean Paulef8f1f92015-04-29 16:05:23 -040035#include <sync/sync.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050036
37#define ARRAY_SIZE(arr) (int)(sizeof(arr) / sizeof((arr)[0]))
38
39#define HWCOMPOSER_DRM_DEVICE "/dev/dri/card0"
40#define MAX_NUM_DISPLAYS 3
41#define UM_PER_INCH 25400
42
43static const uint32_t panel_types[] = {
Sean Paulef8f1f92015-04-29 16:05:23 -040044 DRM_MODE_CONNECTOR_LVDS, DRM_MODE_CONNECTOR_eDP, DRM_MODE_CONNECTOR_DSI,
Sean Paule0c4c3d2015-01-20 16:56:04 -050045};
46
Sean Paul9aa5ad32015-01-22 15:47:54 -050047struct hwc_worker {
Sean Paulef8f1f92015-04-29 16:05:23 -040048 pthread_t thread;
49 pthread_mutex_t lock;
50 pthread_cond_t cond;
51 bool exit;
Sean Paul9aa5ad32015-01-22 15:47:54 -050052};
53
Sean Paule0c4c3d2015-01-20 16:56:04 -050054struct hwc_drm_display {
Sean Paulef8f1f92015-04-29 16:05:23 -040055 struct hwc_context_t *ctx;
56 int display;
Sean Paul9aa5ad32015-01-22 15:47:54 -050057
Sean Paulef8f1f92015-04-29 16:05:23 -040058 uint32_t connector_id;
Sean Paule0c4c3d2015-01-20 16:56:04 -050059
Sean Paulef8f1f92015-04-29 16:05:23 -040060 drmModeModeInfoPtr configs;
61 uint32_t num_configs;
Sean Paule0c4c3d2015-01-20 16:56:04 -050062
Sean Paulef8f1f92015-04-29 16:05:23 -040063 drmModeModeInfo active_mode;
64 uint32_t active_crtc;
65 int active_pipe;
66 bool initial_modeset_required;
Sean Paul9aa5ad32015-01-22 15:47:54 -050067
Sean Paulef8f1f92015-04-29 16:05:23 -040068 struct hwc_worker set_worker;
Sean Paul9aa5ad32015-01-22 15:47:54 -050069
Sean Paulef8f1f92015-04-29 16:05:23 -040070 std::list<struct hwc_drm_bo> buf_queue;
71 struct hwc_drm_bo front;
72 pthread_mutex_t flip_lock;
73 pthread_cond_t flip_cond;
Sean Paulf1dc1912015-01-24 01:34:31 -050074
Sean Paulef8f1f92015-04-29 16:05:23 -040075 int timeline_fd;
76 unsigned timeline_next;
Sean Pauleb9e75c2015-01-25 23:31:30 -050077
Sean Paulef8f1f92015-04-29 16:05:23 -040078 bool enable_vsync_events;
79 unsigned int vsync_sequence;
Sean Paule0c4c3d2015-01-20 16:56:04 -050080};
81
82struct hwc_context_t {
Sean Paulef8f1f92015-04-29 16:05:23 -040083 hwc_composer_device_1_t device;
Sean Paule0c4c3d2015-01-20 16:56:04 -050084
Sean Paulef8f1f92015-04-29 16:05:23 -040085 int fd;
Sean Paule0c4c3d2015-01-20 16:56:04 -050086
Sean Paulef8f1f92015-04-29 16:05:23 -040087 hwc_procs_t const *procs;
88 struct hwc_import_context *import_ctx;
Sean Paule0c4c3d2015-01-20 16:56:04 -050089
Sean Paulef8f1f92015-04-29 16:05:23 -040090 struct hwc_drm_display displays[MAX_NUM_DISPLAYS];
91 int num_displays;
Sean Paul814bddb2015-03-03 17:46:19 -050092
Sean Paulef8f1f92015-04-29 16:05:23 -040093 struct hwc_worker event_worker;
Sean Paule0c4c3d2015-01-20 16:56:04 -050094};
95
96static int hwc_get_drm_display(struct hwc_context_t *ctx, int display,
Sean Paulef8f1f92015-04-29 16:05:23 -040097 struct hwc_drm_display **hd) {
98 if (display >= MAX_NUM_DISPLAYS) {
99 ALOGE("Requested display is out-of-bounds %d %d", display,
100 MAX_NUM_DISPLAYS);
101 return -EINVAL;
102 }
103 *hd = &ctx->displays[display];
104 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500105}
106
Sean Paulef8f1f92015-04-29 16:05:23 -0400107static int hwc_prepare_layer(hwc_layer_1_t *layer) {
108 /* TODO: We can't handle background right now, defer to sufaceFlinger */
109 if (layer->compositionType == HWC_BACKGROUND) {
110 layer->compositionType = HWC_FRAMEBUFFER;
111 ALOGV("Can't handle background layers yet");
Sean Paule0c4c3d2015-01-20 16:56:04 -0500112
Sean Paulef8f1f92015-04-29 16:05:23 -0400113 /* TODO: Support sideband compositions */
114 } else if (layer->compositionType == HWC_SIDEBAND) {
115 layer->compositionType = HWC_FRAMEBUFFER;
116 ALOGV("Can't handle sideband content yet");
117 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500118
Sean Paulef8f1f92015-04-29 16:05:23 -0400119 layer->hints = 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500120
Sean Paulef8f1f92015-04-29 16:05:23 -0400121 /* TODO: Handle cursor by setting compositionType=HWC_CURSOR_OVERLAY */
122 if (layer->flags & HWC_IS_CURSOR_LAYER) {
123 ALOGV("Can't handle async cursors yet");
124 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500125
Sean Paulef8f1f92015-04-29 16:05:23 -0400126 /* TODO: Handle transformations */
127 if (layer->transform) {
128 ALOGV("Can't handle transformations yet");
129 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500130
Sean Paulef8f1f92015-04-29 16:05:23 -0400131 /* TODO: Handle blending & plane alpha*/
132 if (layer->blending == HWC_BLENDING_PREMULT ||
133 layer->blending == HWC_BLENDING_COVERAGE) {
134 ALOGV("Can't handle blending yet");
135 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500136
Sean Paulef8f1f92015-04-29 16:05:23 -0400137 /* TODO: Handle cropping & scaling */
Sean Paule0c4c3d2015-01-20 16:56:04 -0500138
Sean Paulef8f1f92015-04-29 16:05:23 -0400139 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500140}
141
Sean Paulef8f1f92015-04-29 16:05:23 -0400142static int hwc_prepare(hwc_composer_device_1_t * /* dev */, size_t num_displays,
143 hwc_display_contents_1_t **display_contents) {
144 /* TODO: Check flags for HWC_GEOMETRY_CHANGED */
Sean Paule0c4c3d2015-01-20 16:56:04 -0500145
Sean Paulef8f1f92015-04-29 16:05:23 -0400146 for (int i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; ++i) {
147 if (!display_contents[i])
148 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500149
Sean Paulef8f1f92015-04-29 16:05:23 -0400150 for (int j = 0; j < (int)display_contents[i]->numHwLayers; ++j) {
151 int ret = hwc_prepare_layer(&display_contents[i]->hwLayers[j]);
152 if (ret) {
153 ALOGE("Failed to prepare layer %d:%d", j, i);
154 return ret;
155 }
156 }
157 }
Sean Pauldffca952015-02-04 10:19:55 -0800158
Sean Paulef8f1f92015-04-29 16:05:23 -0400159 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500160}
161
Sean Paulef8f1f92015-04-29 16:05:23 -0400162static int hwc_queue_vblank_event(struct hwc_drm_display *hd) {
163 if (hd->active_pipe == -1) {
164 ALOGE("Active pipe is -1 disp=%d", hd->display);
165 return -EINVAL;
166 }
Sean Paul814bddb2015-03-03 17:46:19 -0500167
Sean Paulef8f1f92015-04-29 16:05:23 -0400168 drmVBlank vblank;
169 memset(&vblank, 0, sizeof(vblank));
Sean Paul814bddb2015-03-03 17:46:19 -0500170
Sean Paulef8f1f92015-04-29 16:05:23 -0400171 uint32_t high_crtc = (hd->active_pipe << DRM_VBLANK_HIGH_CRTC_SHIFT);
172 vblank.request.type = (drmVBlankSeqType)(
173 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT |
174 (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
175 vblank.request.signal = (unsigned long)hd;
176 vblank.request.sequence = hd->vsync_sequence + 1;
Sean Paul814bddb2015-03-03 17:46:19 -0500177
Sean Paulef8f1f92015-04-29 16:05:23 -0400178 int ret = drmWaitVBlank(hd->ctx->fd, &vblank);
179 if (ret) {
180 ALOGE("Failed to wait for vblank %d", ret);
181 return ret;
182 }
Sean Paul814bddb2015-03-03 17:46:19 -0500183
Sean Paulef8f1f92015-04-29 16:05:23 -0400184 return 0;
Sean Paul814bddb2015-03-03 17:46:19 -0500185}
186
187static void hwc_vblank_event_handler(int /* fd */, unsigned int sequence,
Sean Paulef8f1f92015-04-29 16:05:23 -0400188 unsigned int tv_sec, unsigned int tv_usec,
189 void *user_data) {
190 struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
Sean Paul814bddb2015-03-03 17:46:19 -0500191
Sean Paulef8f1f92015-04-29 16:05:23 -0400192 if (!hd->enable_vsync_events || !hd->ctx->procs->vsync)
193 return;
Sean Paul814bddb2015-03-03 17:46:19 -0500194
Sean Paulef8f1f92015-04-29 16:05:23 -0400195 /*
196 * Discard duplicate vsync (can happen when enabling vsync events while
197 * already processing vsyncs).
198 */
199 if (sequence <= hd->vsync_sequence)
200 return;
Sean Paul814bddb2015-03-03 17:46:19 -0500201
Sean Paulef8f1f92015-04-29 16:05:23 -0400202 hd->vsync_sequence = sequence;
203 int ret = hwc_queue_vblank_event(hd);
204 if (ret)
205 ALOGE("Failed to queue vblank event ret=%d", ret);
Sean Paul814bddb2015-03-03 17:46:19 -0500206
Sean Paulef8f1f92015-04-29 16:05:23 -0400207 int64_t timestamp =
208 (int64_t)tv_sec * 1000 * 1000 * 1000 + (int64_t)tv_usec * 1000;
209 hd->ctx->procs->vsync(hd->ctx->procs, hd->display, timestamp);
Sean Paul814bddb2015-03-03 17:46:19 -0500210}
211
212static void hwc_flip_event_handler(int /* fd */, unsigned int /* sequence */,
Sean Paulef8f1f92015-04-29 16:05:23 -0400213 unsigned int /* tv_sec */,
214 unsigned int /* tv_usec */,
215 void *user_data) {
216 struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
Sean Paul814bddb2015-03-03 17:46:19 -0500217
Sean Paulef8f1f92015-04-29 16:05:23 -0400218 int ret = pthread_mutex_lock(&hd->flip_lock);
219 if (ret) {
220 ALOGE("Failed to lock flip lock ret=%d", ret);
221 return;
222 }
Sean Paul814bddb2015-03-03 17:46:19 -0500223
Sean Paulef8f1f92015-04-29 16:05:23 -0400224 ret = pthread_cond_signal(&hd->flip_cond);
225 if (ret)
226 ALOGE("Failed to signal flip condition ret=%d", ret);
Sean Paul814bddb2015-03-03 17:46:19 -0500227
Sean Paulef8f1f92015-04-29 16:05:23 -0400228 ret = pthread_mutex_unlock(&hd->flip_lock);
229 if (ret) {
230 ALOGE("Failed to unlock flip lock ret=%d", ret);
231 return;
232 }
Sean Paul814bddb2015-03-03 17:46:19 -0500233}
234
Sean Paulef8f1f92015-04-29 16:05:23 -0400235static void *hwc_event_worker(void *arg) {
236 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
Sean Paul814bddb2015-03-03 17:46:19 -0500237
Sean Paulef8f1f92015-04-29 16:05:23 -0400238 struct hwc_context_t *ctx = (struct hwc_context_t *)arg;
239 do {
240 fd_set fds;
241 FD_ZERO(&fds);
242 FD_SET(ctx->fd, &fds);
Sean Paul814bddb2015-03-03 17:46:19 -0500243
Sean Paulef8f1f92015-04-29 16:05:23 -0400244 drmEventContext event_context;
245 event_context.version = DRM_EVENT_CONTEXT_VERSION;
246 event_context.page_flip_handler = hwc_flip_event_handler;
247 event_context.vblank_handler = hwc_vblank_event_handler;
Sean Paul814bddb2015-03-03 17:46:19 -0500248
Sean Paulef8f1f92015-04-29 16:05:23 -0400249 int ret;
250 do {
251 ret = select(ctx->fd + 1, &fds, NULL, NULL, NULL);
252 } while (ret == -1 && errno == EINTR);
Sean Paul814bddb2015-03-03 17:46:19 -0500253
Sean Paulef8f1f92015-04-29 16:05:23 -0400254 if (ret != 1) {
255 ALOGE("Failed waiting for drm event\n");
256 continue;
257 }
Sean Paul814bddb2015-03-03 17:46:19 -0500258
Sean Paulef8f1f92015-04-29 16:05:23 -0400259 drmHandleEvent(ctx->fd, &event_context);
260 } while (true);
Sean Paul814bddb2015-03-03 17:46:19 -0500261
Sean Paulef8f1f92015-04-29 16:05:23 -0400262 return NULL;
Sean Paul814bddb2015-03-03 17:46:19 -0500263}
264
Sean Paulef8f1f92015-04-29 16:05:23 -0400265static bool hwc_mode_is_equal(drmModeModeInfoPtr a, drmModeModeInfoPtr b) {
266 return a->clock == b->clock && a->hdisplay == b->hdisplay &&
267 a->hsync_start == b->hsync_start && a->hsync_end == b->hsync_end &&
268 a->htotal == b->htotal && a->hskew == b->hskew &&
269 a->vdisplay == b->vdisplay && a->vsync_start == b->vsync_start &&
270 a->vsync_end == b->vsync_end && a->vtotal == b->vtotal &&
271 a->vscan == b->vscan && a->vrefresh == b->vrefresh &&
272 a->flags == b->flags && a->type == b->type &&
273 !strcmp(a->name, b->name);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500274}
275
Sean Paul9aa5ad32015-01-22 15:47:54 -0500276static int hwc_modeset_required(struct hwc_drm_display *hd,
Sean Paulef8f1f92015-04-29 16:05:23 -0400277 bool *modeset_required) {
278 if (hd->initial_modeset_required) {
279 *modeset_required = true;
280 hd->initial_modeset_required = false;
281 return 0;
282 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500283
Sean Paulef8f1f92015-04-29 16:05:23 -0400284 drmModeCrtcPtr crtc;
285 crtc = drmModeGetCrtc(hd->ctx->fd, hd->active_crtc);
286 if (!crtc) {
287 ALOGE("Failed to get crtc for display %d", hd->display);
288 return -ENODEV;
289 }
Sean Paulefb20cb2015-02-04 09:29:15 -0800290
Sean Paulef8f1f92015-04-29 16:05:23 -0400291 drmModeModeInfoPtr m;
292 m = &hd->active_mode;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500293
Sean Paulef8f1f92015-04-29 16:05:23 -0400294 /* Do a modeset if we haven't done one, or the mode has changed */
295 if (!crtc->mode_valid || !hwc_mode_is_equal(m, &crtc->mode))
296 *modeset_required = true;
297 else
298 *modeset_required = false;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500299
Sean Paulef8f1f92015-04-29 16:05:23 -0400300 drmModeFreeCrtc(crtc);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500301
Sean Paulef8f1f92015-04-29 16:05:23 -0400302 return 0;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500303}
304
Sean Paulef8f1f92015-04-29 16:05:23 -0400305static int hwc_flip(struct hwc_drm_display *hd, struct hwc_drm_bo *buf) {
306 bool modeset_required;
307 int ret = hwc_modeset_required(hd, &modeset_required);
308 if (ret) {
309 ALOGE("Failed to determine if modeset is required %d", ret);
310 return ret;
311 }
312 if (modeset_required) {
313 ret = drmModeSetCrtc(hd->ctx->fd, hd->active_crtc, buf->fb_id, 0, 0,
314 &hd->connector_id, 1, &hd->active_mode);
315 if (ret) {
316 ALOGE("Modeset failed for crtc %d", hd->active_crtc);
317 return ret;
318 }
319 return 0;
320 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500321
Sean Paulef8f1f92015-04-29 16:05:23 -0400322 ret = drmModePageFlip(hd->ctx->fd, hd->active_crtc, buf->fb_id,
323 DRM_MODE_PAGE_FLIP_EVENT, hd);
324 if (ret) {
325 ALOGE("Failed to flip buffer for crtc %d", hd->active_crtc);
326 return ret;
327 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500328
Sean Paulef8f1f92015-04-29 16:05:23 -0400329 ret = pthread_cond_wait(&hd->flip_cond, &hd->flip_lock);
330 if (ret) {
331 ALOGE("Failed to wait on condition %d", ret);
332 return ret;
333 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500334
Sean Paulef8f1f92015-04-29 16:05:23 -0400335 return 0;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500336}
337
Sean Paul3bc48e82015-01-23 01:41:13 -0500338static int hwc_wait_and_set(struct hwc_drm_display *hd,
Sean Paulef8f1f92015-04-29 16:05:23 -0400339 struct hwc_drm_bo *buf) {
340 int ret;
341 if (buf->acquire_fence_fd >= 0) {
342 ret = sync_wait(buf->acquire_fence_fd, -1);
343 close(buf->acquire_fence_fd);
344 buf->acquire_fence_fd = -1;
345 if (ret) {
346 ALOGE("Failed to wait for acquire %d", ret);
347 return ret;
348 }
349 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500350
Sean Paulef8f1f92015-04-29 16:05:23 -0400351 ret = hwc_flip(hd, buf);
352 if (ret) {
353 ALOGE("Failed to perform flip\n");
354 return ret;
355 }
Lauri Peltonen132e0102015-02-12 13:54:33 +0200356
Sean Paulef8f1f92015-04-29 16:05:23 -0400357 if (hwc_import_bo_release(hd->ctx->fd, hd->ctx->import_ctx, &hd->front)) {
358 struct drm_gem_close args;
359 memset(&args, 0, sizeof(args));
360 for (int i = 0; i < ARRAY_SIZE(hd->front.gem_handles); ++i) {
361 if (!hd->front.gem_handles[i])
362 continue;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500363
Sean Paulef8f1f92015-04-29 16:05:23 -0400364 ret = pthread_mutex_lock(&hd->set_worker.lock);
365 if (ret) {
366 ALOGE("Failed to lock set lock in wait_and_set() %d", ret);
367 continue;
368 }
Allen Martin3d3f70a2015-02-21 21:20:17 -0800369
Sean Paulef8f1f92015-04-29 16:05:23 -0400370 /* check for duplicate handle in buf_queue */
371 bool found = false;
372 for (std::list<struct hwc_drm_bo>::iterator bi = hd->buf_queue.begin();
373 bi != hd->buf_queue.end(); ++bi)
374 for (int j = 0; j < ARRAY_SIZE(bi->gem_handles); ++j)
375 if (hd->front.gem_handles[i] == bi->gem_handles[j])
376 found = true;
Allen Martin3d3f70a2015-02-21 21:20:17 -0800377
Sean Paulef8f1f92015-04-29 16:05:23 -0400378 for (int j = 0; j < ARRAY_SIZE(buf->gem_handles); ++j)
379 if (hd->front.gem_handles[i] == buf->gem_handles[j])
380 found = true;
Allen Martin3d3f70a2015-02-21 21:20:17 -0800381
Sean Paulef8f1f92015-04-29 16:05:23 -0400382 if (!found) {
383 args.handle = hd->front.gem_handles[i];
384 drmIoctl(hd->ctx->fd, DRM_IOCTL_GEM_CLOSE, &args);
385 }
386 if (pthread_mutex_unlock(&hd->set_worker.lock))
387 ALOGE("Failed to unlock set lock in wait_and_set() %d", ret);
388 }
389 }
Lauri Peltonen77d6d7a2015-02-23 20:44:16 +0200390
Sean Paulef8f1f92015-04-29 16:05:23 -0400391 hd->front = *buf;
Allen Martin3d3f70a2015-02-21 21:20:17 -0800392
Sean Paulef8f1f92015-04-29 16:05:23 -0400393 return ret;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500394}
395
Sean Paulef8f1f92015-04-29 16:05:23 -0400396static void *hwc_set_worker(void *arg) {
397 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500398
Sean Paulef8f1f92015-04-29 16:05:23 -0400399 struct hwc_drm_display *hd = (struct hwc_drm_display *)arg;
400 int ret = pthread_mutex_lock(&hd->flip_lock);
401 if (ret) {
402 ALOGE("Failed to lock flip lock ret=%d", ret);
403 return NULL;
404 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500405
Sean Paulef8f1f92015-04-29 16:05:23 -0400406 do {
407 ret = pthread_mutex_lock(&hd->set_worker.lock);
408 if (ret) {
409 ALOGE("Failed to lock set lock %d", ret);
410 return NULL;
411 }
Sean Paul814bddb2015-03-03 17:46:19 -0500412
Sean Paulef8f1f92015-04-29 16:05:23 -0400413 if (hd->set_worker.exit)
414 break;
Sean Paul3bc48e82015-01-23 01:41:13 -0500415
Sean Paulef8f1f92015-04-29 16:05:23 -0400416 if (hd->buf_queue.empty()) {
417 ret = pthread_cond_wait(&hd->set_worker.cond, &hd->set_worker.lock);
418 if (ret) {
419 ALOGE("Failed to wait on condition %d", ret);
420 break;
421 }
422 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500423
Sean Paulef8f1f92015-04-29 16:05:23 -0400424 struct hwc_drm_bo buf;
425 buf = hd->buf_queue.front();
426 hd->buf_queue.pop_front();
Sean Paul3bc48e82015-01-23 01:41:13 -0500427
Sean Paulef8f1f92015-04-29 16:05:23 -0400428 ret = pthread_mutex_unlock(&hd->set_worker.lock);
429 if (ret) {
430 ALOGE("Failed to unlock set lock %d", ret);
431 return NULL;
432 }
Sean Paul3bc48e82015-01-23 01:41:13 -0500433
Sean Paulef8f1f92015-04-29 16:05:23 -0400434 ret = hwc_wait_and_set(hd, &buf);
435 if (ret)
436 ALOGE("Failed to wait and set %d", ret);
Sean Paul3bc48e82015-01-23 01:41:13 -0500437
Sean Paulef8f1f92015-04-29 16:05:23 -0400438 ret = sw_sync_timeline_inc(hd->timeline_fd, 1);
439 if (ret)
440 ALOGE("Failed to increment sync timeline %d", ret);
441 } while (true);
Sean Paul3bc48e82015-01-23 01:41:13 -0500442
Sean Paulef8f1f92015-04-29 16:05:23 -0400443 ret = pthread_mutex_unlock(&hd->set_worker.lock);
444 if (ret)
445 ALOGE("Failed to unlock set lock while exiting %d", ret);
Sean Paulf1dc1912015-01-24 01:34:31 -0500446
Sean Paulef8f1f92015-04-29 16:05:23 -0400447 ret = pthread_mutex_unlock(&hd->flip_lock);
448 if (ret)
449 ALOGE("Failed to unlock flip lock ret=%d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500450
Sean Paulef8f1f92015-04-29 16:05:23 -0400451 return NULL;
452}
Sean Paul9aa5ad32015-01-22 15:47:54 -0500453
Sean Paulef8f1f92015-04-29 16:05:23 -0400454static void hwc_close_fences(hwc_display_contents_1_t *display_contents) {
455 for (int i = 0; i < (int)display_contents->numHwLayers; ++i) {
456 hwc_layer_1_t *layer = &display_contents->hwLayers[i];
457 if (layer->acquireFenceFd >= 0) {
458 close(layer->acquireFenceFd);
459 layer->acquireFenceFd = -1;
460 }
461 }
462 if (display_contents->outbufAcquireFenceFd >= 0) {
463 close(display_contents->outbufAcquireFenceFd);
464 display_contents->outbufAcquireFenceFd = -1;
465 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500466}
467
Sean Paule0c4c3d2015-01-20 16:56:04 -0500468static int hwc_set_display(hwc_context_t *ctx, int display,
Sean Paulef8f1f92015-04-29 16:05:23 -0400469 hwc_display_contents_1_t *display_contents) {
470 struct hwc_drm_display *hd = NULL;
471 int ret = hwc_get_drm_display(ctx, display, &hd);
472 if (ret) {
473 hwc_close_fences(display_contents);
474 return ret;
475 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500476
Sean Paulef8f1f92015-04-29 16:05:23 -0400477 if (!hd->active_crtc) {
478 ALOGE("There is no active crtc for display %d", display);
479 hwc_close_fences(display_contents);
480 return -ENOENT;
481 }
Sean Paul9b1bb842015-01-23 01:11:58 -0500482
Sean Paulef8f1f92015-04-29 16:05:23 -0400483 /*
484 * TODO: We can only support one hw layer atm, so choose either the
485 * first one or the framebuffer target.
486 */
487 hwc_layer_1_t *layer = NULL;
488 if (!display_contents->numHwLayers) {
489 return 0;
490 } else if (display_contents->numHwLayers == 1) {
491 layer = &display_contents->hwLayers[0];
492 } else {
493 int i;
494 for (i = 0; i < (int)display_contents->numHwLayers; ++i) {
495 layer = &display_contents->hwLayers[i];
496 if (layer->compositionType == HWC_FRAMEBUFFER_TARGET)
497 break;
498 }
499 if (i == (int)display_contents->numHwLayers) {
500 ALOGE("Could not find a suitable layer for display %d", display);
501 }
502 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500503
Sean Paulef8f1f92015-04-29 16:05:23 -0400504 ret = pthread_mutex_lock(&hd->set_worker.lock);
505 if (ret) {
506 ALOGE("Failed to lock set lock in set() %d", ret);
507 hwc_close_fences(display_contents);
508 return ret;
509 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500510
Sean Paulef8f1f92015-04-29 16:05:23 -0400511 struct hwc_drm_bo buf;
512 memset(&buf, 0, sizeof(buf));
513 ret = hwc_import_bo_create(ctx->fd, ctx->import_ctx, layer->handle, &buf);
514 if (ret) {
515 ALOGE("Failed to import handle to drm bo %d", ret);
516 hwc_close_fences(display_contents);
517 return ret;
518 }
519 buf.acquire_fence_fd = layer->acquireFenceFd;
520 layer->acquireFenceFd = -1;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500521
Sean Paulef8f1f92015-04-29 16:05:23 -0400522 /*
523 * TODO: Retire and release can use the same sync point here b/c hwc is
524 * restricted to one layer. Once that is no longer true, this will need
525 * to change
526 */
527 ++hd->timeline_next;
528 display_contents->retireFenceFd = sw_sync_fence_create(
529 hd->timeline_fd, "drm_hwc_retire", hd->timeline_next);
530 layer->releaseFenceFd = sw_sync_fence_create(
531 hd->timeline_fd, "drm_hwc_release", hd->timeline_next);
532 hd->buf_queue.push_back(buf);
Allen Martin3d3f70a2015-02-21 21:20:17 -0800533
Sean Paulef8f1f92015-04-29 16:05:23 -0400534 ret = pthread_cond_signal(&hd->set_worker.cond);
535 if (ret)
536 ALOGE("Failed to signal set worker %d", ret);
Allen Martin3d3f70a2015-02-21 21:20:17 -0800537
Sean Paulef8f1f92015-04-29 16:05:23 -0400538 if (pthread_mutex_unlock(&hd->set_worker.lock))
539 ALOGE("Failed to unlock set lock in set()");
Sean Paul3bc48e82015-01-23 01:41:13 -0500540
Sean Paulef8f1f92015-04-29 16:05:23 -0400541 hwc_close_fences(display_contents);
542 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500543}
544
545static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
Sean Paulef8f1f92015-04-29 16:05:23 -0400546 hwc_display_contents_1_t **display_contents) {
547 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500548
Sean Paulef8f1f92015-04-29 16:05:23 -0400549 int ret = 0;
550 for (int i = 0; i < (int)num_displays && i < MAX_NUM_DISPLAYS; ++i) {
551 if (display_contents[i])
552 ret = hwc_set_display(ctx, i, display_contents[i]);
553 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500554
Sean Paulef8f1f92015-04-29 16:05:23 -0400555 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500556}
557
Sean Paulef8f1f92015-04-29 16:05:23 -0400558static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
559 int event, int enabled) {
560 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
561 struct hwc_drm_display *hd = NULL;
562 int ret = hwc_get_drm_display(ctx, display, &hd);
563 if (ret)
564 return ret;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500565
Sean Paulef8f1f92015-04-29 16:05:23 -0400566 if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
567 return -EINVAL;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500568
Sean Paulef8f1f92015-04-29 16:05:23 -0400569 if (hd->active_pipe == -1) {
570 ALOGD("Can't service events for display %d, no pipe", display);
571 return -EINVAL;
572 }
Sean Pauleb9e75c2015-01-25 23:31:30 -0500573
Sean Paulef8f1f92015-04-29 16:05:23 -0400574 hd->enable_vsync_events = !!enabled;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500575
Sean Paulef8f1f92015-04-29 16:05:23 -0400576 if (!hd->enable_vsync_events)
577 return 0;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500578
Sean Paulef8f1f92015-04-29 16:05:23 -0400579 /*
580 * Note that it's possible that the event worker is already waiting for
581 * a vsync, and this will be a duplicate request. In that event, we'll
582 * end up firing the event handler twice, and it will discard the second
583 * event. Not ideal, but not worth introducing a bunch of additional
584 * logic/locks/state for.
585 */
586 ret = hwc_queue_vblank_event(hd);
587 if (ret) {
588 ALOGE("Failed to queue vblank event ret=%d", ret);
589 return ret;
590 }
Sean Pauleb9e75c2015-01-25 23:31:30 -0500591
Sean Paulef8f1f92015-04-29 16:05:23 -0400592 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500593}
594
Sean Paulef8f1f92015-04-29 16:05:23 -0400595static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
596 int mode) {
597 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500598
Sean Paulef8f1f92015-04-29 16:05:23 -0400599 struct hwc_drm_display *hd = NULL;
600 int ret = hwc_get_drm_display(ctx, display, &hd);
601 if (ret)
602 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500603
Sean Paulef8f1f92015-04-29 16:05:23 -0400604 drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
605 if (!c) {
606 ALOGE("Failed to get connector %d", display);
607 return -ENODEV;
608 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500609
Sean Paulef8f1f92015-04-29 16:05:23 -0400610 uint32_t dpms_prop = 0;
611 for (int i = 0; !dpms_prop && i < c->count_props; ++i) {
612 drmModePropertyPtr p;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500613
Sean Paulef8f1f92015-04-29 16:05:23 -0400614 p = drmModeGetProperty(ctx->fd, c->props[i]);
615 if (!p)
616 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500617
Sean Paulef8f1f92015-04-29 16:05:23 -0400618 if (!strcmp(p->name, "DPMS"))
619 dpms_prop = c->props[i];
Sean Paule0c4c3d2015-01-20 16:56:04 -0500620
Sean Paulef8f1f92015-04-29 16:05:23 -0400621 drmModeFreeProperty(p);
622 }
623 if (!dpms_prop) {
624 ALOGE("Failed to get DPMS property from display %d", display);
625 drmModeFreeConnector(c);
626 return -ENOENT;
627 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500628
Sean Paulef8f1f92015-04-29 16:05:23 -0400629 uint64_t dpms_value = 0;
630 switch (mode) {
631 case HWC_POWER_MODE_OFF:
632 dpms_value = DRM_MODE_DPMS_OFF;
633 break;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500634
Sean Paulef8f1f92015-04-29 16:05:23 -0400635 /* We can't support dozing right now, so go full on */
636 case HWC_POWER_MODE_DOZE:
637 case HWC_POWER_MODE_DOZE_SUSPEND:
638 case HWC_POWER_MODE_NORMAL:
639 dpms_value = DRM_MODE_DPMS_ON;
640 break;
641 };
Sean Paule0c4c3d2015-01-20 16:56:04 -0500642
Sean Paulef8f1f92015-04-29 16:05:23 -0400643 ret = drmModeConnectorSetProperty(ctx->fd, c->connector_id, dpms_prop,
644 dpms_value);
645 if (ret) {
646 ALOGE("Failed to set DPMS property for display %d", display);
647 drmModeFreeConnector(c);
648 return ret;
649 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500650
Sean Paulef8f1f92015-04-29 16:05:23 -0400651 drmModeFreeConnector(c);
652 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500653}
654
Sean Paulef8f1f92015-04-29 16:05:23 -0400655static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
656 int *value) {
657 switch (what) {
658 case HWC_BACKGROUND_LAYER_SUPPORTED:
659 *value = 0; /* TODO: We should do this */
660 break;
661 case HWC_VSYNC_PERIOD:
662 ALOGW("Query for deprecated vsync value, returning 60Hz");
663 *value = 1000 * 1000 * 1000 / 60;
664 break;
665 case HWC_DISPLAY_TYPES_SUPPORTED:
666 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
667 break;
668 }
669 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500670}
671
Sean Paulef8f1f92015-04-29 16:05:23 -0400672static void hwc_register_procs(struct hwc_composer_device_1 *dev,
673 hwc_procs_t const *procs) {
674 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500675
Sean Paulef8f1f92015-04-29 16:05:23 -0400676 ctx->procs = procs;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500677}
678
Sean Paulef8f1f92015-04-29 16:05:23 -0400679static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
680 int display, uint32_t *configs,
681 size_t *numConfigs) {
682 if (!*numConfigs)
683 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500684
Sean Paulef8f1f92015-04-29 16:05:23 -0400685 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
686 struct hwc_drm_display *hd = NULL;
687 int ret = hwc_get_drm_display(ctx, display, &hd);
688 if (ret)
689 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500690
Sean Paulef8f1f92015-04-29 16:05:23 -0400691 drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
692 if (!c) {
693 ALOGE("Failed to get connector %d", display);
694 return -ENODEV;
695 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500696
Sean Paulef8f1f92015-04-29 16:05:23 -0400697 if (hd->configs) {
698 free(hd->configs);
699 hd->configs = NULL;
700 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500701
Sean Paulef8f1f92015-04-29 16:05:23 -0400702 if (c->connection == DRM_MODE_DISCONNECTED) {
703 drmModeFreeConnector(c);
704 return -ENODEV;
705 }
Sean Paula4283c52015-02-04 10:08:00 -0800706
Sean Paulef8f1f92015-04-29 16:05:23 -0400707 hd->configs =
708 (drmModeModeInfoPtr)calloc(c->count_modes, sizeof(*hd->configs));
709 if (!hd->configs) {
710 ALOGE("Failed to allocate config list for display %d", display);
711 hd->num_configs = 0;
712 drmModeFreeConnector(c);
713 return -ENOMEM;
714 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500715
Sean Paulef8f1f92015-04-29 16:05:23 -0400716 for (int i = 0; i < c->count_modes; ++i) {
717 drmModeModeInfoPtr m = &hd->configs[i];
Sean Paule0c4c3d2015-01-20 16:56:04 -0500718
Sean Paulef8f1f92015-04-29 16:05:23 -0400719 memcpy(m, &c->modes[i], sizeof(*m));
Sean Paule0c4c3d2015-01-20 16:56:04 -0500720
Sean Paulef8f1f92015-04-29 16:05:23 -0400721 if (i < (int)*numConfigs)
722 configs[i] = i;
723 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500724
Sean Paulef8f1f92015-04-29 16:05:23 -0400725 hd->num_configs = c->count_modes;
726 *numConfigs = MIN(c->count_modes, *numConfigs);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500727
Sean Paulef8f1f92015-04-29 16:05:23 -0400728 drmModeFreeConnector(c);
729 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500730}
731
732static int hwc_check_config_valid(struct hwc_context_t *ctx,
Sean Paulef8f1f92015-04-29 16:05:23 -0400733 drmModeConnectorPtr connector, int display,
734 int config_idx) {
735 struct hwc_drm_display *hd = NULL;
736 int ret = hwc_get_drm_display(ctx, display, &hd);
737 if (ret)
738 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500739
Sean Paulef8f1f92015-04-29 16:05:23 -0400740 /* Make sure the requested config is still valid for the display */
741 drmModeModeInfoPtr m = NULL;
742 for (int i = 0; i < connector->count_modes; ++i) {
743 if (hwc_mode_is_equal(&connector->modes[i], &hd->configs[config_idx])) {
744 m = &hd->configs[config_idx];
745 break;
746 }
747 }
748 if (!m)
749 return -ENOENT;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500750
Sean Paulef8f1f92015-04-29 16:05:23 -0400751 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500752}
753
Sean Paulef8f1f92015-04-29 16:05:23 -0400754static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
755 int display, uint32_t config,
756 const uint32_t *attributes,
757 int32_t *values) {
758 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
759 struct hwc_drm_display *hd = NULL;
760 int ret = hwc_get_drm_display(ctx, display, &hd);
761 if (ret)
762 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500763
Sean Paulef8f1f92015-04-29 16:05:23 -0400764 if (config >= hd->num_configs) {
765 ALOGE("Requested config is out-of-bounds %d %d", config, hd->num_configs);
766 return -EINVAL;
767 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500768
Sean Paulef8f1f92015-04-29 16:05:23 -0400769 drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
770 if (!c) {
771 ALOGE("Failed to get connector %d", display);
772 return -ENODEV;
773 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500774
Sean Paulef8f1f92015-04-29 16:05:23 -0400775 ret = hwc_check_config_valid(ctx, c, display, (int)config);
776 if (ret) {
777 ALOGE("Provided config is no longer valid %u", config);
778 drmModeFreeConnector(c);
779 return ret;
780 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500781
Sean Paulef8f1f92015-04-29 16:05:23 -0400782 drmModeModeInfoPtr m = &hd->configs[config];
783 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
784 switch (attributes[i]) {
785 case HWC_DISPLAY_VSYNC_PERIOD:
786 values[i] = 1000 * 1000 * 1000 / m->vrefresh;
787 break;
788 case HWC_DISPLAY_WIDTH:
789 values[i] = m->hdisplay;
790 break;
791 case HWC_DISPLAY_HEIGHT:
792 values[i] = m->vdisplay;
793 break;
794 case HWC_DISPLAY_DPI_X:
795 /* Dots per 1000 inches */
796 values[i] = c->mmWidth ? (m->hdisplay * UM_PER_INCH) / c->mmWidth : 0;
797 break;
798 case HWC_DISPLAY_DPI_Y:
799 /* Dots per 1000 inches */
800 values[i] = c->mmHeight ? (m->vdisplay * UM_PER_INCH) / c->mmHeight : 0;
801 break;
802 }
803 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500804
Sean Paulef8f1f92015-04-29 16:05:23 -0400805 drmModeFreeConnector(c);
806 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500807}
808
Sean Paulef8f1f92015-04-29 16:05:23 -0400809static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
810 int display) {
811 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
812 struct hwc_drm_display *hd = NULL;
813 int ret = hwc_get_drm_display(ctx, display, &hd);
814 if (ret)
815 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500816
Sean Paulef8f1f92015-04-29 16:05:23 -0400817 /* Find the current mode in the config list */
818 int index = -1;
819 for (int i = 0; i < (int)hd->num_configs; ++i) {
820 if (hwc_mode_is_equal(&hd->configs[i], &hd->active_mode)) {
821 index = i;
822 break;
823 }
824 }
825 return index;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500826}
827
Sean Paulef8f1f92015-04-29 16:05:23 -0400828static bool hwc_crtc_is_bound(struct hwc_context_t *ctx, uint32_t crtc_id) {
829 for (int i = 0; i < MAX_NUM_DISPLAYS; ++i) {
830 if (ctx->displays[i].active_crtc == crtc_id)
831 return true;
832 }
833 return false;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500834}
835
836static int hwc_try_encoder(struct hwc_context_t *ctx, drmModeResPtr r,
Sean Paulef8f1f92015-04-29 16:05:23 -0400837 uint32_t encoder_id, uint32_t *crtc_id) {
838 drmModeEncoderPtr e = drmModeGetEncoder(ctx->fd, encoder_id);
839 if (!e) {
840 ALOGE("Failed to get encoder for connector %d", encoder_id);
841 return -ENODEV;
842 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500843
Sean Paulef8f1f92015-04-29 16:05:23 -0400844 /* First try to use the currently-bound crtc */
845 int ret = 0;
846 if (e->crtc_id) {
847 if (!hwc_crtc_is_bound(ctx, e->crtc_id)) {
848 *crtc_id = e->crtc_id;
849 drmModeFreeEncoder(e);
850 return 0;
851 }
852 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500853
Sean Paulef8f1f92015-04-29 16:05:23 -0400854 /* Try to find a possible crtc which will work */
855 for (int i = 0; i < r->count_crtcs; ++i) {
856 if (!(e->possible_crtcs & (1 << i)))
857 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500858
Sean Paulef8f1f92015-04-29 16:05:23 -0400859 /* We've already tried this earlier */
860 if (e->crtc_id == r->crtcs[i])
861 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500862
Sean Paulef8f1f92015-04-29 16:05:23 -0400863 if (!hwc_crtc_is_bound(ctx, r->crtcs[i])) {
864 *crtc_id = r->crtcs[i];
865 drmModeFreeEncoder(e);
866 return 0;
867 }
868 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500869
Sean Paulef8f1f92015-04-29 16:05:23 -0400870 /* We can't use the encoder, but nothing went wrong, try another one */
871 drmModeFreeEncoder(e);
872 return -EAGAIN;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500873}
874
Sean Paulef8f1f92015-04-29 16:05:23 -0400875static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
876 int index) {
877 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
878 struct hwc_drm_display *hd = NULL;
879 int ret = hwc_get_drm_display(ctx, display, &hd);
880 if (ret)
881 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500882
Sean Paulef8f1f92015-04-29 16:05:23 -0400883 drmModeConnectorPtr c = drmModeGetConnector(ctx->fd, hd->connector_id);
884 if (!c) {
885 ALOGE("Failed to get connector %d", display);
886 return -ENODEV;
887 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500888
Sean Paulef8f1f92015-04-29 16:05:23 -0400889 if (c->connection == DRM_MODE_DISCONNECTED) {
890 ALOGE("Tried to configure a disconnected display %d", display);
891 drmModeFreeConnector(c);
892 return -ENODEV;
893 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500894
Sean Paulef8f1f92015-04-29 16:05:23 -0400895 if (index >= c->count_modes) {
896 ALOGE("Index is out-of-bounds %d/%d", index, c->count_modes);
897 drmModeFreeConnector(c);
898 return -ENOENT;
899 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500900
Sean Paulef8f1f92015-04-29 16:05:23 -0400901 drmModeResPtr r = drmModeGetResources(ctx->fd);
902 if (!r) {
903 ALOGE("Failed to get drm resources");
904 drmModeFreeResources(r);
905 drmModeFreeConnector(c);
906 return -ENODEV;
907 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500908
Sean Paulef8f1f92015-04-29 16:05:23 -0400909 /* We no longer have an active_crtc */
910 hd->active_crtc = 0;
911 hd->active_pipe = -1;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500912
Sean Paulef8f1f92015-04-29 16:05:23 -0400913 /* First, try to use the currently-connected encoder */
914 uint32_t crtc_id = 0;
915 if (c->encoder_id) {
916 ret = hwc_try_encoder(ctx, r, c->encoder_id, &crtc_id);
917 if (ret && ret != -EAGAIN) {
918 ALOGE("Encoder try failed %d", ret);
919 drmModeFreeResources(r);
920 drmModeFreeConnector(c);
921 return ret;
922 }
923 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500924
Sean Paulef8f1f92015-04-29 16:05:23 -0400925 /* We couldn't find a crtc with the attached encoder, try the others */
926 if (!crtc_id) {
927 for (int i = 0; i < c->count_encoders; ++i) {
928 ret = hwc_try_encoder(ctx, r, c->encoders[i], &crtc_id);
929 if (!ret) {
930 break;
931 } else if (ret != -EAGAIN) {
932 ALOGE("Encoder try failed %d", ret);
933 drmModeFreeResources(r);
934 drmModeFreeConnector(c);
935 return ret;
936 }
937 }
938 if (!crtc_id) {
939 ALOGE("Couldn't find valid crtc to modeset");
940 drmModeFreeConnector(c);
941 drmModeFreeResources(r);
942 return -EINVAL;
943 }
944 }
945 drmModeFreeConnector(c);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500946
Sean Paulef8f1f92015-04-29 16:05:23 -0400947 hd->active_crtc = crtc_id;
948 memcpy(&hd->active_mode, &hd->configs[index], sizeof(hd->active_mode));
Sean Paule0c4c3d2015-01-20 16:56:04 -0500949
Sean Paulef8f1f92015-04-29 16:05:23 -0400950 /* Find the pipe corresponding to the crtc_id */
951 for (int i = 0; i < r->count_crtcs; ++i) {
952 /* We've already tried this earlier */
953 if (r->crtcs[i] == crtc_id) {
954 hd->active_pipe = i;
955 break;
956 }
957 }
958 drmModeFreeResources(r);
959 /* This should never happen... hehehe */
960 if (hd->active_pipe == -1) {
961 ALOGE("Active crtc was not found in resources!!");
962 return -ENODEV;
963 }
Sean Paulfa406a12015-02-04 10:05:44 -0800964
Sean Paulef8f1f92015-04-29 16:05:23 -0400965 /* TODO: Once we have atomic, set the crtc timing info here */
966 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500967}
968
Sean Paulef8f1f92015-04-29 16:05:23 -0400969static int hwc_destroy_worker(struct hwc_worker *worker) {
970 int ret = pthread_mutex_lock(&worker->lock);
971 if (ret) {
972 ALOGE("Failed to lock in destroy() %d", ret);
973 return ret;
974 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500975
Sean Paulef8f1f92015-04-29 16:05:23 -0400976 worker->exit = true;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500977
Sean Paulef8f1f92015-04-29 16:05:23 -0400978 ret |= pthread_cond_signal(&worker->cond);
979 if (ret)
980 ALOGE("Failed to signal cond in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500981
Sean Paulef8f1f92015-04-29 16:05:23 -0400982 ret |= pthread_mutex_unlock(&worker->lock);
983 if (ret)
984 ALOGE("Failed to unlock in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500985
Sean Paulef8f1f92015-04-29 16:05:23 -0400986 ret |= pthread_join(worker->thread, NULL);
987 if (ret && ret != ESRCH)
988 ALOGE("Failed to join thread in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500989
Sean Paulef8f1f92015-04-29 16:05:23 -0400990 return ret;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500991}
992
Sean Paulef8f1f92015-04-29 16:05:23 -0400993static void hwc_destroy_display(struct hwc_drm_display *hd) {
994 if (hwc_destroy_worker(&hd->set_worker))
995 ALOGE("Destroy set worker failed");
Sean Paul9aa5ad32015-01-22 15:47:54 -0500996}
997
Sean Paulef8f1f92015-04-29 16:05:23 -0400998static int hwc_device_close(struct hw_device_t *dev) {
999 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001000
Sean Paulef8f1f92015-04-29 16:05:23 -04001001 for (int i = 0; i < MAX_NUM_DISPLAYS; ++i)
1002 hwc_destroy_display(&ctx->displays[i]);
Sean Paul9aa5ad32015-01-22 15:47:54 -05001003
Sean Paulef8f1f92015-04-29 16:05:23 -04001004 if (hwc_destroy_worker(&ctx->event_worker))
1005 ALOGE("Destroy event worker failed");
Sean Paul814bddb2015-03-03 17:46:19 -05001006
Sean Paulef8f1f92015-04-29 16:05:23 -04001007 drmClose(ctx->fd);
Sean Paulcd36a9e2015-01-22 18:01:18 -05001008
Sean Paulef8f1f92015-04-29 16:05:23 -04001009 int ret = hwc_import_destroy(ctx->import_ctx);
1010 if (ret)
1011 ALOGE("Could not destroy import %d", ret);
Sean Paulcd36a9e2015-01-22 18:01:18 -05001012
Sean Paulef8f1f92015-04-29 16:05:23 -04001013 delete ctx;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001014
Sean Paulef8f1f92015-04-29 16:05:23 -04001015 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001016}
1017
Sean Paul814bddb2015-03-03 17:46:19 -05001018static int hwc_initialize_worker(struct hwc_worker *worker,
Sean Paulef8f1f92015-04-29 16:05:23 -04001019 void *(*routine)(void *), void *arg) {
1020 int ret = pthread_cond_init(&worker->cond, NULL);
1021 if (ret) {
1022 ALOGE("Failed to create worker condition %d", ret);
1023 return ret;
1024 }
Sean Paul9aa5ad32015-01-22 15:47:54 -05001025
Sean Paulef8f1f92015-04-29 16:05:23 -04001026 ret = pthread_mutex_init(&worker->lock, NULL);
1027 if (ret) {
1028 ALOGE("Failed to initialize worker lock %d", ret);
1029 pthread_cond_destroy(&worker->cond);
1030 return ret;
1031 }
Sean Paul9aa5ad32015-01-22 15:47:54 -05001032
Sean Paulef8f1f92015-04-29 16:05:23 -04001033 worker->exit = false;
Sean Paul9aa5ad32015-01-22 15:47:54 -05001034
Sean Paulef8f1f92015-04-29 16:05:23 -04001035 ret = pthread_create(&worker->thread, NULL, routine, arg);
1036 if (ret) {
1037 ALOGE("Could not create worker thread %d", ret);
1038 pthread_mutex_destroy(&worker->lock);
1039 pthread_cond_destroy(&worker->cond);
1040 return ret;
1041 }
1042 return 0;
Sean Paul9aa5ad32015-01-22 15:47:54 -05001043}
1044
Sean Paul24a26e32015-02-04 10:34:47 -08001045/*
1046 * TODO: This function sets the active config to the first one in the list. This
1047 * should be fixed such that it selects the preferred mode for the display, or
1048 * some other, saner, method of choosing the config.
1049 */
Sean Paulef8f1f92015-04-29 16:05:23 -04001050static int hwc_set_initial_config(struct hwc_drm_display *hd) {
1051 uint32_t config;
1052 size_t num_configs = 1;
1053 int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
1054 &num_configs);
1055 if (ret || !num_configs)
1056 return 0;
Sean Paul24a26e32015-02-04 10:34:47 -08001057
Sean Paulef8f1f92015-04-29 16:05:23 -04001058 ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
1059 if (ret) {
1060 ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
1061 return ret;
1062 }
Sean Paul24a26e32015-02-04 10:34:47 -08001063
Sean Paulef8f1f92015-04-29 16:05:23 -04001064 return ret;
Sean Paul24a26e32015-02-04 10:34:47 -08001065}
1066
Sean Paule0c4c3d2015-01-20 16:56:04 -05001067static int hwc_initialize_display(struct hwc_context_t *ctx, int display,
Sean Paulef8f1f92015-04-29 16:05:23 -04001068 uint32_t connector_id) {
1069 struct hwc_drm_display *hd = NULL;
1070 int ret = hwc_get_drm_display(ctx, display, &hd);
1071 if (ret)
1072 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001073
Sean Paulef8f1f92015-04-29 16:05:23 -04001074 hd->ctx = ctx;
1075 hd->display = display;
1076 hd->active_pipe = -1;
1077 hd->initial_modeset_required = true;
1078 hd->connector_id = connector_id;
1079 hd->enable_vsync_events = false;
1080 hd->vsync_sequence = 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001081
Sean Paulef8f1f92015-04-29 16:05:23 -04001082 ret = pthread_mutex_init(&hd->flip_lock, NULL);
1083 if (ret) {
1084 ALOGE("Failed to initialize flip lock %d", ret);
1085 return ret;
1086 }
Sean Paul814bddb2015-03-03 17:46:19 -05001087
Sean Paulef8f1f92015-04-29 16:05:23 -04001088 ret = pthread_cond_init(&hd->flip_cond, NULL);
1089 if (ret) {
1090 ALOGE("Failed to intiialize flip condition %d", ret);
1091 pthread_mutex_destroy(&hd->flip_lock);
1092 return ret;
1093 }
Sean Paul814bddb2015-03-03 17:46:19 -05001094
Sean Paulef8f1f92015-04-29 16:05:23 -04001095 ret = sw_sync_timeline_create();
1096 if (ret < 0) {
1097 ALOGE("Failed to create sw sync timeline %d", ret);
1098 pthread_cond_destroy(&hd->flip_cond);
1099 pthread_mutex_destroy(&hd->flip_lock);
1100 return ret;
1101 }
1102 hd->timeline_fd = ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001103
Sean Paulef8f1f92015-04-29 16:05:23 -04001104 /*
1105 * Initialize timeline_next to 1, because point 0 will be the very first
1106 * set operation. Since we increment every time set() is called,
1107 * initializing to 0 would cause an off-by-one error where
1108 * surfaceflinger would composite on the front buffer.
1109 */
1110 hd->timeline_next = 1;
Sean Paule147a2a2015-02-22 17:55:43 -05001111
Sean Paulef8f1f92015-04-29 16:05:23 -04001112 ret = hwc_set_initial_config(hd);
1113 if (ret) {
1114 ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
1115 close(hd->timeline_fd);
1116 pthread_cond_destroy(&hd->flip_cond);
1117 pthread_mutex_destroy(&hd->flip_lock);
1118 return ret;
1119 }
Sean Paulf1dc1912015-01-24 01:34:31 -05001120
Sean Paulef8f1f92015-04-29 16:05:23 -04001121 ret = hwc_initialize_worker(&hd->set_worker, hwc_set_worker, hd);
1122 if (ret) {
1123 ALOGE("Failed to create set worker %d\n", ret);
1124 close(hd->timeline_fd);
1125 pthread_cond_destroy(&hd->flip_cond);
1126 pthread_mutex_destroy(&hd->flip_lock);
1127 return ret;
1128 }
Sean Paul24a26e32015-02-04 10:34:47 -08001129
Sean Paulef8f1f92015-04-29 16:05:23 -04001130 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001131}
1132
Sean Paulef8f1f92015-04-29 16:05:23 -04001133static void hwc_free_conn_list(drmModeConnectorPtr *conn_list, int num_conn) {
1134 for (int i = 0; i < num_conn; ++i) {
1135 if (conn_list[i])
1136 drmModeFreeConnector(conn_list[i]);
1137 }
1138 free(conn_list);
Sean Paule0c4c3d2015-01-20 16:56:04 -05001139}
1140
Sean Paulef8f1f92015-04-29 16:05:23 -04001141static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
1142 drmModeResPtr res = drmModeGetResources(ctx->fd);
1143 if (!res) {
1144 ALOGE("Failed to get drm resources");
1145 return -ENODEV;
1146 }
1147 int num_connectors = res->count_connectors;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001148
Sean Paulef8f1f92015-04-29 16:05:23 -04001149 drmModeConnectorPtr *conn_list =
1150 (drmModeConnector **)calloc(num_connectors, sizeof(*conn_list));
1151 if (!conn_list) {
1152 ALOGE("Failed to allocate connector list");
1153 drmModeFreeResources(res);
1154 return -ENOMEM;
1155 }
Sean Paule0c4c3d2015-01-20 16:56:04 -05001156
Sean Paulef8f1f92015-04-29 16:05:23 -04001157 for (int i = 0; i < num_connectors; ++i) {
1158 conn_list[i] = drmModeGetConnector(ctx->fd, res->connectors[i]);
1159 if (!conn_list[i]) {
1160 ALOGE("Failed to get connector %d", res->connectors[i]);
1161 drmModeFreeResources(res);
1162 return -ENODEV;
1163 }
1164 }
1165 drmModeFreeResources(res);
Sean Paule0c4c3d2015-01-20 16:56:04 -05001166
Sean Paulef8f1f92015-04-29 16:05:23 -04001167 ctx->num_displays = 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001168
Sean Paulef8f1f92015-04-29 16:05:23 -04001169 /* Find a connected, panel type connector for display 0 */
1170 for (int i = 0; i < num_connectors; ++i) {
1171 drmModeConnectorPtr c = conn_list[i];
Sean Paule0c4c3d2015-01-20 16:56:04 -05001172
Sean Paulef8f1f92015-04-29 16:05:23 -04001173 int j;
1174 for (j = 0; j < ARRAY_SIZE(panel_types); ++j) {
1175 if (c->connector_type == panel_types[j] &&
1176 c->connection == DRM_MODE_CONNECTED)
1177 break;
1178 }
1179 if (j == ARRAY_SIZE(panel_types))
1180 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001181
Sean Paulef8f1f92015-04-29 16:05:23 -04001182 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1183 ++ctx->num_displays;
1184 break;
1185 }
Sean Paule0c4c3d2015-01-20 16:56:04 -05001186
Sean Paulef8f1f92015-04-29 16:05:23 -04001187 struct hwc_drm_display *panel_hd;
1188 int ret = hwc_get_drm_display(ctx, 0, &panel_hd);
1189 if (ret) {
1190 hwc_free_conn_list(conn_list, num_connectors);
1191 return ret;
1192 }
Sean Paule0c4c3d2015-01-20 16:56:04 -05001193
Sean Paulef8f1f92015-04-29 16:05:23 -04001194 /* Fill in the other displays */
1195 for (int i = 0; i < num_connectors; ++i) {
1196 drmModeConnectorPtr c = conn_list[i];
Sean Paule0c4c3d2015-01-20 16:56:04 -05001197
Sean Paulef8f1f92015-04-29 16:05:23 -04001198 if (panel_hd->connector_id == c->connector_id)
1199 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001200
Sean Paulef8f1f92015-04-29 16:05:23 -04001201 hwc_initialize_display(ctx, ctx->num_displays, c->connector_id);
1202 ++ctx->num_displays;
1203 }
1204 hwc_free_conn_list(conn_list, num_connectors);
1205
1206 ret = hwc_initialize_worker(&ctx->event_worker, hwc_event_worker, ctx);
1207 if (ret) {
1208 ALOGE("Failed to create event worker %d\n", ret);
1209 return ret;
1210 }
1211
1212 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -05001213}
1214
Sean Paulef8f1f92015-04-29 16:05:23 -04001215static int hwc_device_open(const struct hw_module_t *module, const char *name,
1216 struct hw_device_t **dev) {
1217 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
1218 ALOGE("Invalid module name- %s", name);
1219 return -EINVAL;
1220 }
1221
1222 struct hwc_context_t *ctx = new hwc_context_t();
1223 if (!ctx) {
1224 ALOGE("Failed to allocate hwc context");
1225 return -ENOMEM;
1226 }
1227
1228 int ret = hwc_import_init(&ctx->import_ctx);
1229 if (ret) {
1230 ALOGE("Failed to initialize import context");
1231 delete ctx;
1232 return ret;
1233 }
1234
1235 char path[PROPERTY_VALUE_MAX];
1236 property_get("hwc.drm.device", path, HWCOMPOSER_DRM_DEVICE);
1237 /* TODO: Use drmOpenControl here instead */
1238 ctx->fd = open(path, O_RDWR);
1239 if (ctx->fd < 0) {
1240 ALOGE("Failed to open dri- %s", strerror(-errno));
1241 delete ctx;
1242 return -ENOENT;
1243 }
1244
1245 ret = hwc_enumerate_displays(ctx);
1246 if (ret) {
1247 ALOGE("Failed to enumerate displays: %s", strerror(ret));
1248 close(ctx->fd);
1249 delete ctx;
1250 return ret;
1251 }
1252
1253 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
1254 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
1255 ctx->device.common.module = const_cast<hw_module_t *>(module);
1256 ctx->device.common.close = hwc_device_close;
1257
1258 ctx->device.prepare = hwc_prepare;
1259 ctx->device.set = hwc_set;
1260 ctx->device.eventControl = hwc_event_control;
1261 ctx->device.setPowerMode = hwc_set_power_mode;
1262 ctx->device.query = hwc_query;
1263 ctx->device.registerProcs = hwc_register_procs;
1264 ctx->device.getDisplayConfigs = hwc_get_display_configs;
1265 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
1266 ctx->device.getActiveConfig = hwc_get_active_config;
1267 ctx->device.setActiveConfig = hwc_set_active_config;
1268 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
1269
1270 *dev = &ctx->device.common;
1271
1272 return 0;
1273}
1274
1275static struct hw_module_methods_t hwc_module_methods = {open : hwc_device_open};
Sean Paule0c4c3d2015-01-20 16:56:04 -05001276
1277hwc_module_t HAL_MODULE_INFO_SYM = {
Sean Paulef8f1f92015-04-29 16:05:23 -04001278 common : {
1279 tag : HARDWARE_MODULE_TAG,
1280 version_major : 1,
1281 version_minor : 0,
1282 id : HWC_HARDWARE_MODULE_ID,
1283 name : "DRM hwcomposer module",
1284 author : "The Android Open Source Project",
1285 methods : &hwc_module_methods,
1286 dso : NULL,
1287 reserved : {0},
1288 }
Sean Paule0c4c3d2015-01-20 16:56:04 -05001289};