blob: a809c8bb267d76f368a557693b7ecb46acef4d7f [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"
Sean Paul6a55e9f2015-04-30 15:31:06 -040020#include "drmresources.h"
Sean Paulda6270d2015-06-01 14:11:52 -040021#include "importer.h"
Sean Paulef8f1f92015-04-29 16:05:23 -040022
Sean Paule0c4c3d2015-01-20 16:56:04 -050023#include <errno.h>
Sean Paulef8f1f92015-04-29 16:05:23 -040024#include <fcntl.h>
Sean Paul5ad302c2015-05-11 10:43:31 -070025#include <list>
Sean Paule42febf2015-05-07 11:35:29 -070026#include <map>
Sean Paulef8f1f92015-04-29 16:05:23 -040027#include <pthread.h>
Dan Albertc5255b32015-05-07 23:42:54 -070028#include <stdlib.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050029#include <sys/param.h>
Sean Paul9aa5ad32015-01-22 15:47:54 -050030#include <sys/resource.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050031#include <xf86drm.h>
32#include <xf86drmMode.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050033
Sean Paulef8f1f92015-04-29 16:05:23 -040034#include <cutils/log.h>
35#include <cutils/properties.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050036#include <hardware/hardware.h>
37#include <hardware/hwcomposer.h>
Sean Paulf1dc1912015-01-24 01:34:31 -050038#include <sw_sync.h>
Sean Paulef8f1f92015-04-29 16:05:23 -040039#include <sync/sync.h>
Sean Paule0c4c3d2015-01-20 16:56:04 -050040
Sean Paule0c4c3d2015-01-20 16:56:04 -050041#define UM_PER_INCH 25400
42
Sean Paul6a55e9f2015-04-30 15:31:06 -040043namespace android {
Sean Paule0c4c3d2015-01-20 16:56:04 -050044
Sean Paul9aa5ad32015-01-22 15:47:54 -050045struct hwc_worker {
Sean Paulef8f1f92015-04-29 16:05:23 -040046 pthread_t thread;
47 pthread_mutex_t lock;
48 pthread_cond_t cond;
49 bool exit;
Sean Paul9aa5ad32015-01-22 15:47:54 -050050};
51
Sean Paule42febf2015-05-07 11:35:29 -070052typedef struct hwc_drm_display {
Sean Paulef8f1f92015-04-29 16:05:23 -040053 struct hwc_context_t *ctx;
54 int display;
Sean Paul9aa5ad32015-01-22 15:47:54 -050055
Sean Paul6a55e9f2015-04-30 15:31:06 -040056 std::vector<uint32_t> config_ids;
Sean Paul9aa5ad32015-01-22 15:47:54 -050057
Sean Paulef8f1f92015-04-29 16:05:23 -040058 bool enable_vsync_events;
59 unsigned int vsync_sequence;
Sean Paule42febf2015-05-07 11:35:29 -070060} hwc_drm_display_t;
Sean Paule0c4c3d2015-01-20 16:56:04 -050061
62struct hwc_context_t {
Sean Paule42febf2015-05-07 11:35:29 -070063 // map of display:hwc_drm_display_t
64 typedef std::map<int, hwc_drm_display_t> DisplayMap;
65 typedef DisplayMap::iterator DisplayMapIter;
Sean Paule0c4c3d2015-01-20 16:56:04 -050066
Sean Paulda6270d2015-06-01 14:11:52 -040067 hwc_context_t() : procs(NULL), importer(NULL) {
68 }
69
70 ~hwc_context_t() {
71 delete importer;
72 }
73
Sean Paule42febf2015-05-07 11:35:29 -070074 hwc_composer_device_1_t device;
Sean Paulef8f1f92015-04-29 16:05:23 -040075 hwc_procs_t const *procs;
Sean Paule0c4c3d2015-01-20 16:56:04 -050076
Sean Paulef8f1f92015-04-29 16:05:23 -040077 struct hwc_worker event_worker;
Sean Paul6a55e9f2015-04-30 15:31:06 -040078
Sean Paule42febf2015-05-07 11:35:29 -070079 DisplayMap displays;
Sean Paul6a55e9f2015-04-30 15:31:06 -040080 DrmResources drm;
Sean Paulda6270d2015-06-01 14:11:52 -040081 Importer *importer;
Sean Paule0c4c3d2015-01-20 16:56:04 -050082};
83
Sean Paulb386f1b2015-05-13 06:33:23 -070084static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
Sean Paulef8f1f92015-04-29 16:05:23 -040085 hwc_display_contents_1_t **display_contents) {
Sean Paulb386f1b2015-05-13 06:33:23 -070086 // XXX: Once we have a GL compositor, just make everything HWC_OVERLAY
87 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
88 Composition *composition =
89 ctx->drm.compositor()->CreateComposition(ctx->importer);
90 if (!composition) {
91 ALOGE("Drm composition init failed");
92 return -EINVAL;
93 }
Sean Paule0c4c3d2015-01-20 16:56:04 -050094
Sean Paule42febf2015-05-07 11:35:29 -070095 for (int i = 0; i < (int)num_displays; ++i) {
Sean Paulef8f1f92015-04-29 16:05:23 -040096 if (!display_contents[i])
97 continue;
Sean Paule0c4c3d2015-01-20 16:56:04 -050098
Sean Paulb386f1b2015-05-13 06:33:23 -070099 int num_layers = display_contents[i]->numHwLayers;
100 int num_planes = composition->GetRemainingLayers(i, num_layers);
101
102 // XXX: Should go away with atomic modeset
103 DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
104 if (!crtc) {
105 ALOGE("No crtc for display %d", i);
106 delete composition;
107 return -ENODEV;
108 }
109 if (crtc->requires_modeset())
110 num_planes = 0;
111
112 for (int j = std::max(0, num_layers - num_planes); j < num_layers; j++) {
113 if (j >= num_planes)
114 break;
115
116 hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
117 if (layer->compositionType == HWC_FRAMEBUFFER)
118 layer->compositionType = HWC_OVERLAY;
Sean Paulef8f1f92015-04-29 16:05:23 -0400119 }
120 }
Sean Pauldffca952015-02-04 10:19:55 -0800121
Sean Paulb386f1b2015-05-13 06:33:23 -0700122 delete composition;
Sean Paulef8f1f92015-04-29 16:05:23 -0400123 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500124}
125
Sean Paulb386f1b2015-05-13 06:33:23 -0700126static void hwc_set_cleanup(size_t num_displays,
127 hwc_display_contents_1_t **display_contents,
128 Composition *composition) {
129 for (int i = 0; i < (int)num_displays; ++i) {
130 if (!display_contents[i])
131 continue;
132
133 hwc_display_contents_1_t *dc = display_contents[i];
134 for (size_t j = 0; j < dc->numHwLayers; ++j) {
135 hwc_layer_1_t *layer = &dc->hwLayers[j];
136 if (layer->acquireFenceFd >= 0) {
137 close(layer->acquireFenceFd);
138 layer->acquireFenceFd = -1;
139 }
140 }
141 if (dc->outbufAcquireFenceFd >= 0) {
142 close(dc->outbufAcquireFenceFd);
143 dc->outbufAcquireFenceFd = -1;
144 }
145 }
146
147 delete composition;
148}
149
Sean Paulef8f1f92015-04-29 16:05:23 -0400150static int hwc_queue_vblank_event(struct hwc_drm_display *hd) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400151 DrmCrtc *crtc = hd->ctx->drm.GetCrtcForDisplay(hd->display);
152 if (!crtc) {
153 ALOGE("Failed to get crtc for display");
154 return -ENODEV;
Sean Paulef8f1f92015-04-29 16:05:23 -0400155 }
Sean Paul814bddb2015-03-03 17:46:19 -0500156
Sean Paulef8f1f92015-04-29 16:05:23 -0400157 drmVBlank vblank;
158 memset(&vblank, 0, sizeof(vblank));
Sean Paul814bddb2015-03-03 17:46:19 -0500159
Sean Paul6a55e9f2015-04-30 15:31:06 -0400160 uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
Sean Paulef8f1f92015-04-29 16:05:23 -0400161 vblank.request.type = (drmVBlankSeqType)(
162 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT |
163 (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
164 vblank.request.signal = (unsigned long)hd;
165 vblank.request.sequence = hd->vsync_sequence + 1;
Sean Paul814bddb2015-03-03 17:46:19 -0500166
Sean Paul6a55e9f2015-04-30 15:31:06 -0400167 int ret = drmWaitVBlank(hd->ctx->drm.fd(), &vblank);
Sean Paulef8f1f92015-04-29 16:05:23 -0400168 if (ret) {
169 ALOGE("Failed to wait for vblank %d", ret);
170 return ret;
171 }
Sean Paul814bddb2015-03-03 17:46:19 -0500172
Sean Paulef8f1f92015-04-29 16:05:23 -0400173 return 0;
Sean Paul814bddb2015-03-03 17:46:19 -0500174}
175
176static void hwc_vblank_event_handler(int /* fd */, unsigned int sequence,
Sean Paulef8f1f92015-04-29 16:05:23 -0400177 unsigned int tv_sec, unsigned int tv_usec,
178 void *user_data) {
179 struct hwc_drm_display *hd = (struct hwc_drm_display *)user_data;
Sean Paul814bddb2015-03-03 17:46:19 -0500180
Sean Paulef8f1f92015-04-29 16:05:23 -0400181 if (!hd->enable_vsync_events || !hd->ctx->procs->vsync)
182 return;
Sean Paul814bddb2015-03-03 17:46:19 -0500183
Sean Paulef8f1f92015-04-29 16:05:23 -0400184 /*
185 * Discard duplicate vsync (can happen when enabling vsync events while
186 * already processing vsyncs).
187 */
188 if (sequence <= hd->vsync_sequence)
189 return;
Sean Paul814bddb2015-03-03 17:46:19 -0500190
Sean Paulef8f1f92015-04-29 16:05:23 -0400191 hd->vsync_sequence = sequence;
192 int ret = hwc_queue_vblank_event(hd);
193 if (ret)
194 ALOGE("Failed to queue vblank event ret=%d", ret);
Sean Paul814bddb2015-03-03 17:46:19 -0500195
Sean Paulef8f1f92015-04-29 16:05:23 -0400196 int64_t timestamp =
197 (int64_t)tv_sec * 1000 * 1000 * 1000 + (int64_t)tv_usec * 1000;
198 hd->ctx->procs->vsync(hd->ctx->procs, hd->display, timestamp);
Sean Paul814bddb2015-03-03 17:46:19 -0500199}
200
Sean Paulef8f1f92015-04-29 16:05:23 -0400201static void *hwc_event_worker(void *arg) {
202 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
Sean Paul814bddb2015-03-03 17:46:19 -0500203
Sean Paulef8f1f92015-04-29 16:05:23 -0400204 struct hwc_context_t *ctx = (struct hwc_context_t *)arg;
205 do {
206 fd_set fds;
207 FD_ZERO(&fds);
Sean Paul6a55e9f2015-04-30 15:31:06 -0400208 FD_SET(ctx->drm.fd(), &fds);
Sean Paul814bddb2015-03-03 17:46:19 -0500209
Sean Paulef8f1f92015-04-29 16:05:23 -0400210 drmEventContext event_context;
211 event_context.version = DRM_EVENT_CONTEXT_VERSION;
Sean Paulb386f1b2015-05-13 06:33:23 -0700212 event_context.page_flip_handler = NULL;
Sean Paulef8f1f92015-04-29 16:05:23 -0400213 event_context.vblank_handler = hwc_vblank_event_handler;
Sean Paul814bddb2015-03-03 17:46:19 -0500214
Sean Paulef8f1f92015-04-29 16:05:23 -0400215 int ret;
216 do {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400217 ret = select(ctx->drm.fd() + 1, &fds, NULL, NULL, NULL);
Sean Paulef8f1f92015-04-29 16:05:23 -0400218 } while (ret == -1 && errno == EINTR);
Sean Paul814bddb2015-03-03 17:46:19 -0500219
Sean Paulef8f1f92015-04-29 16:05:23 -0400220 if (ret != 1) {
221 ALOGE("Failed waiting for drm event\n");
222 continue;
223 }
Sean Paul814bddb2015-03-03 17:46:19 -0500224
Sean Paul6a55e9f2015-04-30 15:31:06 -0400225 drmHandleEvent(ctx->drm.fd(), &event_context);
Sean Paulef8f1f92015-04-29 16:05:23 -0400226 } while (true);
Sean Paul814bddb2015-03-03 17:46:19 -0500227
Sean Paulef8f1f92015-04-29 16:05:23 -0400228 return NULL;
Sean Paul814bddb2015-03-03 17:46:19 -0500229}
230
Sean Paulb386f1b2015-05-13 06:33:23 -0700231static int hwc_add_layer(int display, hwc_context_t *ctx, hwc_layer_1_t *layer,
232 Composition *composition) {
233 hwc_drm_bo_t bo;
234 int ret = ctx->importer->ImportBuffer(layer->handle, &bo);
235 if (ret) {
236 ALOGE("Failed to import handle to bo %d", ret);
237 return ret;
Sean Paulef8f1f92015-04-29 16:05:23 -0400238 }
Sean Paulefb20cb2015-02-04 09:29:15 -0800239
Sean Paulb386f1b2015-05-13 06:33:23 -0700240 ret = composition->AddLayer(display, layer, &bo);
241 if (!ret)
Sean Paulef8f1f92015-04-29 16:05:23 -0400242 return 0;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500243
Sean Paulb386f1b2015-05-13 06:33:23 -0700244 int destroy_ret = ctx->importer->ReleaseBuffer(&bo);
245 if (destroy_ret)
246 ALOGE("Failed to destroy buffer %d", destroy_ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500247
Sean Paulef8f1f92015-04-29 16:05:23 -0400248 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500249}
250
251static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays,
Sean Paulef8f1f92015-04-29 16:05:23 -0400252 hwc_display_contents_1_t **display_contents) {
253 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paulb386f1b2015-05-13 06:33:23 -0700254 Composition *composition =
255 ctx->drm.compositor()->CreateComposition(ctx->importer);
256 if (!composition) {
257 ALOGE("Drm composition init failed");
258 hwc_set_cleanup(num_displays, display_contents, NULL);
259 return -EINVAL;
Sean Paulef8f1f92015-04-29 16:05:23 -0400260 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500261
Sean Paulb386f1b2015-05-13 06:33:23 -0700262 int ret;
263 for (int i = 0; i < (int)num_displays; ++i) {
264 if (!display_contents[i])
265 continue;
266
267 DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(i);
268 if (!crtc) {
269 ALOGE("No crtc for display %d", i);
270 hwc_set_cleanup(num_displays, display_contents, composition);
271 return -ENODEV;
272 }
273
274 hwc_display_contents_1_t *dc = display_contents[i];
275 unsigned num_layers = dc->numHwLayers;
276 unsigned num_planes = composition->GetRemainingLayers(i, num_layers);
277 bool use_target = false;
278 // XXX: We don't need to check for modeset required with atomic modeset
279 if (crtc->requires_modeset() || num_layers > num_planes)
280 use_target = true;
281
282 // XXX: Won't need to worry about FB_TARGET with GL Compositor
283 for (int j = 0; use_target && j < (int)num_layers; ++j) {
284 hwc_layer_1_t *layer = &dc->hwLayers[j];
285 if (layer->compositionType != HWC_FRAMEBUFFER_TARGET)
286 continue;
287
288 ret = hwc_add_layer(i, ctx, layer, composition);
289 if (ret) {
290 ALOGE("Add layer failed %d", ret);
291 hwc_set_cleanup(num_displays, display_contents, composition);
292 return ret;
293 }
294 --num_planes;
295 break;
296 }
297
298 for (int j = 0; num_planes && j < (int)num_layers; ++j) {
299 hwc_layer_1_t *layer = &dc->hwLayers[j];
300 if (layer->compositionType != HWC_OVERLAY)
301 continue;
302
303 ret = hwc_add_layer(i, ctx, layer, composition);
304 if (ret) {
305 ALOGE("Add layer failed %d", ret);
306 hwc_set_cleanup(num_displays, display_contents, composition);
307 return ret;
308 }
309 --num_planes;
310 }
311 }
312
313 ret = ctx->drm.compositor()->QueueComposition(composition);
314 if (ret) {
315 ALOGE("Failed to queue the composition");
316 hwc_set_cleanup(num_displays, display_contents, composition);
317 return ret;
318 }
319 hwc_set_cleanup(num_displays, display_contents, NULL);
Sean Paulef8f1f92015-04-29 16:05:23 -0400320 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500321}
322
Sean Paulef8f1f92015-04-29 16:05:23 -0400323static int hwc_event_control(struct hwc_composer_device_1 *dev, int display,
324 int event, int enabled) {
325 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule42febf2015-05-07 11:35:29 -0700326 struct hwc_drm_display *hd = &ctx->displays[display];
Sean Paulef8f1f92015-04-29 16:05:23 -0400327 if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1))
328 return -EINVAL;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500329
Sean Paul6a55e9f2015-04-30 15:31:06 -0400330 DrmCrtc *crtc = ctx->drm.GetCrtcForDisplay(display);
331 if (!crtc) {
332 ALOGD("Can't service events for display %d, no crtc", display);
Sean Paulef8f1f92015-04-29 16:05:23 -0400333 return -EINVAL;
334 }
Sean Pauleb9e75c2015-01-25 23:31:30 -0500335
Sean Paulef8f1f92015-04-29 16:05:23 -0400336 hd->enable_vsync_events = !!enabled;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500337
Sean Paulef8f1f92015-04-29 16:05:23 -0400338 if (!hd->enable_vsync_events)
339 return 0;
Sean Pauleb9e75c2015-01-25 23:31:30 -0500340
Sean Paulef8f1f92015-04-29 16:05:23 -0400341 /*
342 * Note that it's possible that the event worker is already waiting for
343 * a vsync, and this will be a duplicate request. In that event, we'll
344 * end up firing the event handler twice, and it will discard the second
345 * event. Not ideal, but not worth introducing a bunch of additional
346 * logic/locks/state for.
347 */
Sean Paule42febf2015-05-07 11:35:29 -0700348 int ret = hwc_queue_vblank_event(hd);
Sean Paulef8f1f92015-04-29 16:05:23 -0400349 if (ret) {
350 ALOGE("Failed to queue vblank event ret=%d", ret);
351 return ret;
352 }
Sean Pauleb9e75c2015-01-25 23:31:30 -0500353
Sean Paulef8f1f92015-04-29 16:05:23 -0400354 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500355}
356
Sean Paulef8f1f92015-04-29 16:05:23 -0400357static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display,
358 int mode) {
359 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500360
Sean Paul6a55e9f2015-04-30 15:31:06 -0400361 uint64_t dpmsValue = 0;
Sean Paulef8f1f92015-04-29 16:05:23 -0400362 switch (mode) {
363 case HWC_POWER_MODE_OFF:
Sean Paul6a55e9f2015-04-30 15:31:06 -0400364 dpmsValue = DRM_MODE_DPMS_OFF;
Sean Paulef8f1f92015-04-29 16:05:23 -0400365 break;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500366
Sean Paulef8f1f92015-04-29 16:05:23 -0400367 /* We can't support dozing right now, so go full on */
368 case HWC_POWER_MODE_DOZE:
369 case HWC_POWER_MODE_DOZE_SUSPEND:
370 case HWC_POWER_MODE_NORMAL:
Sean Paul6a55e9f2015-04-30 15:31:06 -0400371 dpmsValue = DRM_MODE_DPMS_ON;
Sean Paulef8f1f92015-04-29 16:05:23 -0400372 break;
373 };
Sean Paul6a55e9f2015-04-30 15:31:06 -0400374 return ctx->drm.SetDpmsMode(display, dpmsValue);
Sean Paule0c4c3d2015-01-20 16:56:04 -0500375}
376
Sean Paulef8f1f92015-04-29 16:05:23 -0400377static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what,
378 int *value) {
379 switch (what) {
380 case HWC_BACKGROUND_LAYER_SUPPORTED:
381 *value = 0; /* TODO: We should do this */
382 break;
383 case HWC_VSYNC_PERIOD:
384 ALOGW("Query for deprecated vsync value, returning 60Hz");
385 *value = 1000 * 1000 * 1000 / 60;
386 break;
387 case HWC_DISPLAY_TYPES_SUPPORTED:
388 *value = HWC_DISPLAY_PRIMARY | HWC_DISPLAY_EXTERNAL;
389 break;
390 }
391 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500392}
393
Sean Paulef8f1f92015-04-29 16:05:23 -0400394static void hwc_register_procs(struct hwc_composer_device_1 *dev,
395 hwc_procs_t const *procs) {
396 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500397
Sean Paulef8f1f92015-04-29 16:05:23 -0400398 ctx->procs = procs;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500399}
400
Sean Paulef8f1f92015-04-29 16:05:23 -0400401static int hwc_get_display_configs(struct hwc_composer_device_1 *dev,
402 int display, uint32_t *configs,
Sean Paul6a55e9f2015-04-30 15:31:06 -0400403 size_t *num_configs) {
404 if (!*num_configs)
Sean Paulef8f1f92015-04-29 16:05:23 -0400405 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500406
Sean Paulef8f1f92015-04-29 16:05:23 -0400407 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule42febf2015-05-07 11:35:29 -0700408 hwc_drm_display_t *hd = &ctx->displays[display];
Sean Paul6a55e9f2015-04-30 15:31:06 -0400409 hd->config_ids.clear();
410
411 DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display);
412 if (!connector) {
413 ALOGE("Failed to get connector for display %d", display);
Sean Paulef8f1f92015-04-29 16:05:23 -0400414 return -ENODEV;
415 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500416
Sean Paule42febf2015-05-07 11:35:29 -0700417 int ret = connector->UpdateModes();
Sean Paul6a55e9f2015-04-30 15:31:06 -0400418 if (ret) {
419 ALOGE("Failed to update display modes %d", ret);
Sean Paulef8f1f92015-04-29 16:05:23 -0400420 return ret;
Sean Paulef8f1f92015-04-29 16:05:23 -0400421 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500422
Sean Paul6a55e9f2015-04-30 15:31:06 -0400423 for (DrmConnector::ModeIter iter = connector->begin_modes();
424 iter != connector->end_modes(); ++iter) {
425 size_t idx = hd->config_ids.size();
426 if (idx == *num_configs)
427 break;
428 hd->config_ids.push_back(iter->id());
429 configs[idx] = iter->id();
430 }
431 *num_configs = hd->config_ids.size();
432 return *num_configs == 0 ? -1 : 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500433}
434
Sean Paulef8f1f92015-04-29 16:05:23 -0400435static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev,
436 int display, uint32_t config,
437 const uint32_t *attributes,
438 int32_t *values) {
439 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400440 DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
Sean Paulef8f1f92015-04-29 16:05:23 -0400441 if (!c) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400442 ALOGE("Failed to get DrmConnector for display %d", display);
Sean Paulef8f1f92015-04-29 16:05:23 -0400443 return -ENODEV;
444 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400445 DrmMode mode;
446 for (DrmConnector::ModeIter iter = c->begin_modes(); iter != c->end_modes();
447 ++iter) {
448 if (iter->id() == config) {
449 mode = *iter;
450 break;
451 }
452 }
453 if (mode.id() == 0) {
454 ALOGE("Failed to find active mode for display %d", display);
455 return -ENOENT;
Sean Paulef8f1f92015-04-29 16:05:23 -0400456 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500457
Sean Paul6a55e9f2015-04-30 15:31:06 -0400458 uint32_t mm_width = c->mm_width();
459 uint32_t mm_height = c->mm_height();
Sean Paulef8f1f92015-04-29 16:05:23 -0400460 for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) {
461 switch (attributes[i]) {
462 case HWC_DISPLAY_VSYNC_PERIOD:
Sean Paul6a55e9f2015-04-30 15:31:06 -0400463 values[i] = 1000 * 1000 * 1000 / mode.v_refresh();
Sean Paulef8f1f92015-04-29 16:05:23 -0400464 break;
465 case HWC_DISPLAY_WIDTH:
Sean Paul6a55e9f2015-04-30 15:31:06 -0400466 values[i] = mode.h_display();
Sean Paulef8f1f92015-04-29 16:05:23 -0400467 break;
468 case HWC_DISPLAY_HEIGHT:
Sean Paul6a55e9f2015-04-30 15:31:06 -0400469 values[i] = mode.v_display();
Sean Paulef8f1f92015-04-29 16:05:23 -0400470 break;
471 case HWC_DISPLAY_DPI_X:
472 /* Dots per 1000 inches */
Sean Paul6a55e9f2015-04-30 15:31:06 -0400473 values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0;
Sean Paulef8f1f92015-04-29 16:05:23 -0400474 break;
475 case HWC_DISPLAY_DPI_Y:
476 /* Dots per 1000 inches */
Sean Paul6a55e9f2015-04-30 15:31:06 -0400477 values[i] =
478 mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0;
Sean Paulef8f1f92015-04-29 16:05:23 -0400479 break;
480 }
481 }
Sean Paulef8f1f92015-04-29 16:05:23 -0400482 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500483}
484
Sean Paulef8f1f92015-04-29 16:05:23 -0400485static int hwc_get_active_config(struct hwc_composer_device_1 *dev,
486 int display) {
487 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paul6a55e9f2015-04-30 15:31:06 -0400488 DrmConnector *c = ctx->drm.GetConnectorForDisplay(display);
489 if (!c) {
490 ALOGE("Failed to get DrmConnector for display %d", display);
Sean Paulef8f1f92015-04-29 16:05:23 -0400491 return -ENODEV;
492 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500493
Sean Paul6a55e9f2015-04-30 15:31:06 -0400494 DrmMode mode = c->active_mode();
Sean Paule42febf2015-05-07 11:35:29 -0700495 hwc_drm_display_t *hd = &ctx->displays[display];
Sean Paul6a55e9f2015-04-30 15:31:06 -0400496 for (size_t i = 0; i < hd->config_ids.size(); ++i) {
497 if (hd->config_ids[i] == mode.id())
498 return i;
Sean Paulef8f1f92015-04-29 16:05:23 -0400499 }
Sean Paul6a55e9f2015-04-30 15:31:06 -0400500 return -1;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500501}
502
Sean Paulef8f1f92015-04-29 16:05:23 -0400503static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display,
504 int index) {
505 struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
Sean Paule42febf2015-05-07 11:35:29 -0700506 hwc_drm_display_t *hd = &ctx->displays[display];
Sean Paul6a55e9f2015-04-30 15:31:06 -0400507 if (index >= (int)hd->config_ids.size()) {
508 ALOGE("Invalid config index %d passed in", index);
509 return -EINVAL;
Sean Paulef8f1f92015-04-29 16:05:23 -0400510 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500511
Sean Paule42febf2015-05-07 11:35:29 -0700512 int ret =
Sean Paul6a55e9f2015-04-30 15:31:06 -0400513 ctx->drm.SetDisplayActiveMode(display, hd->config_ids[index]);
514 if (ret) {
515 ALOGE("Failed to set config for display %d", display);
516 return ret;
Sean Paulef8f1f92015-04-29 16:05:23 -0400517 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500518
Sean Paul6a55e9f2015-04-30 15:31:06 -0400519 return ret;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500520}
521
Sean Paulef8f1f92015-04-29 16:05:23 -0400522static int hwc_destroy_worker(struct hwc_worker *worker) {
523 int ret = pthread_mutex_lock(&worker->lock);
524 if (ret) {
525 ALOGE("Failed to lock in destroy() %d", ret);
526 return ret;
527 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500528
Sean Paulef8f1f92015-04-29 16:05:23 -0400529 worker->exit = true;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500530
Sean Paulef8f1f92015-04-29 16:05:23 -0400531 ret |= pthread_cond_signal(&worker->cond);
532 if (ret)
533 ALOGE("Failed to signal cond in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500534
Sean Paulef8f1f92015-04-29 16:05:23 -0400535 ret |= pthread_mutex_unlock(&worker->lock);
536 if (ret)
537 ALOGE("Failed to unlock in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500538
Sean Paulef8f1f92015-04-29 16:05:23 -0400539 ret |= pthread_join(worker->thread, NULL);
540 if (ret && ret != ESRCH)
541 ALOGE("Failed to join thread in destroy() %d", ret);
Sean Paul9aa5ad32015-01-22 15:47:54 -0500542
Sean Paulef8f1f92015-04-29 16:05:23 -0400543 return ret;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500544}
545
Sean Paulef8f1f92015-04-29 16:05:23 -0400546static int hwc_device_close(struct hw_device_t *dev) {
547 struct hwc_context_t *ctx = (struct hwc_context_t *)dev;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500548
Sean Paulef8f1f92015-04-29 16:05:23 -0400549 if (hwc_destroy_worker(&ctx->event_worker))
550 ALOGE("Destroy event worker failed");
Sean Paul814bddb2015-03-03 17:46:19 -0500551
Sean Paulef8f1f92015-04-29 16:05:23 -0400552 delete ctx;
Sean Paulef8f1f92015-04-29 16:05:23 -0400553 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500554}
555
Sean Paul814bddb2015-03-03 17:46:19 -0500556static int hwc_initialize_worker(struct hwc_worker *worker,
Sean Paulef8f1f92015-04-29 16:05:23 -0400557 void *(*routine)(void *), void *arg) {
558 int ret = pthread_cond_init(&worker->cond, NULL);
559 if (ret) {
560 ALOGE("Failed to create worker condition %d", ret);
561 return ret;
562 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500563
Sean Paulef8f1f92015-04-29 16:05:23 -0400564 ret = pthread_mutex_init(&worker->lock, NULL);
565 if (ret) {
566 ALOGE("Failed to initialize worker lock %d", ret);
567 pthread_cond_destroy(&worker->cond);
568 return ret;
569 }
Sean Paul9aa5ad32015-01-22 15:47:54 -0500570
Sean Paulef8f1f92015-04-29 16:05:23 -0400571 worker->exit = false;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500572
Sean Paulef8f1f92015-04-29 16:05:23 -0400573 ret = pthread_create(&worker->thread, NULL, routine, arg);
574 if (ret) {
575 ALOGE("Could not create worker thread %d", ret);
576 pthread_mutex_destroy(&worker->lock);
577 pthread_cond_destroy(&worker->cond);
578 return ret;
579 }
580 return 0;
Sean Paul9aa5ad32015-01-22 15:47:54 -0500581}
582
Sean Paul24a26e32015-02-04 10:34:47 -0800583/*
584 * TODO: This function sets the active config to the first one in the list. This
585 * should be fixed such that it selects the preferred mode for the display, or
586 * some other, saner, method of choosing the config.
587 */
Sean Paule42febf2015-05-07 11:35:29 -0700588static int hwc_set_initial_config(hwc_drm_display_t *hd) {
Sean Paulef8f1f92015-04-29 16:05:23 -0400589 uint32_t config;
590 size_t num_configs = 1;
591 int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config,
592 &num_configs);
593 if (ret || !num_configs)
594 return 0;
Sean Paul24a26e32015-02-04 10:34:47 -0800595
Sean Paulef8f1f92015-04-29 16:05:23 -0400596 ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0);
597 if (ret) {
598 ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret);
599 return ret;
600 }
Sean Paul24a26e32015-02-04 10:34:47 -0800601
Sean Paulef8f1f92015-04-29 16:05:23 -0400602 return ret;
Sean Paul24a26e32015-02-04 10:34:47 -0800603}
604
Sean Paul6a55e9f2015-04-30 15:31:06 -0400605static int hwc_initialize_display(struct hwc_context_t *ctx, int display) {
Sean Paule42febf2015-05-07 11:35:29 -0700606 hwc_drm_display_t *hd = &ctx->displays[display];
Sean Paulef8f1f92015-04-29 16:05:23 -0400607 hd->ctx = ctx;
608 hd->display = display;
Sean Paulef8f1f92015-04-29 16:05:23 -0400609 hd->enable_vsync_events = false;
610 hd->vsync_sequence = 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500611
Sean Paulb386f1b2015-05-13 06:33:23 -0700612 int ret = hwc_set_initial_config(hd);
Sean Paulef8f1f92015-04-29 16:05:23 -0400613 if (ret) {
614 ALOGE("Failed to set initial config for d=%d ret=%d", display, ret);
Sean Paulef8f1f92015-04-29 16:05:23 -0400615 return ret;
616 }
Sean Paul24a26e32015-02-04 10:34:47 -0800617
Sean Paulef8f1f92015-04-29 16:05:23 -0400618 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500619}
620
Sean Paulef8f1f92015-04-29 16:05:23 -0400621static int hwc_enumerate_displays(struct hwc_context_t *ctx) {
Sean Paul6a55e9f2015-04-30 15:31:06 -0400622 int ret;
623 for (DrmResources::ConnectorIter c = ctx->drm.begin_connectors();
624 c != ctx->drm.end_connectors(); ++c) {
625 ret = hwc_initialize_display(ctx, (*c)->display());
626 if (ret) {
627 ALOGE("Failed to initialize display %d", (*c)->display());
628 return ret;
Sean Paulef8f1f92015-04-29 16:05:23 -0400629 }
630 }
Sean Paulef8f1f92015-04-29 16:05:23 -0400631
632 return 0;
Sean Paule0c4c3d2015-01-20 16:56:04 -0500633}
634
Sean Paulef8f1f92015-04-29 16:05:23 -0400635static int hwc_device_open(const struct hw_module_t *module, const char *name,
636 struct hw_device_t **dev) {
637 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
638 ALOGE("Invalid module name- %s", name);
639 return -EINVAL;
640 }
641
642 struct hwc_context_t *ctx = new hwc_context_t();
643 if (!ctx) {
644 ALOGE("Failed to allocate hwc context");
645 return -ENOMEM;
646 }
647
Sean Paul6a55e9f2015-04-30 15:31:06 -0400648 int ret = ctx->drm.Init();
649 if (ret) {
650 ALOGE("Can't initialize Drm object %d", ret);
651 delete ctx;
652 return ret;
653 }
654
Sean Paulda6270d2015-06-01 14:11:52 -0400655 ctx->importer = Importer::CreateInstance(&ctx->drm);
656 if (!ctx->importer) {
657 ALOGE("Failed to create importer instance");
Sean Paulef8f1f92015-04-29 16:05:23 -0400658 delete ctx;
659 return ret;
660 }
661
Sean Paulef8f1f92015-04-29 16:05:23 -0400662 ret = hwc_enumerate_displays(ctx);
663 if (ret) {
664 ALOGE("Failed to enumerate displays: %s", strerror(ret));
Sean Paul6a55e9f2015-04-30 15:31:06 -0400665 delete ctx;
666 return ret;
667 }
668
669 ret = hwc_initialize_worker(&ctx->event_worker, hwc_event_worker, ctx);
670 if (ret) {
671 ALOGE("Failed to create event worker %d\n", ret);
Sean Paulef8f1f92015-04-29 16:05:23 -0400672 delete ctx;
673 return ret;
674 }
675
676 ctx->device.common.tag = HARDWARE_DEVICE_TAG;
677 ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4;
678 ctx->device.common.module = const_cast<hw_module_t *>(module);
679 ctx->device.common.close = hwc_device_close;
680
681 ctx->device.prepare = hwc_prepare;
682 ctx->device.set = hwc_set;
683 ctx->device.eventControl = hwc_event_control;
684 ctx->device.setPowerMode = hwc_set_power_mode;
685 ctx->device.query = hwc_query;
686 ctx->device.registerProcs = hwc_register_procs;
687 ctx->device.getDisplayConfigs = hwc_get_display_configs;
688 ctx->device.getDisplayAttributes = hwc_get_display_attributes;
689 ctx->device.getActiveConfig = hwc_get_active_config;
690 ctx->device.setActiveConfig = hwc_set_active_config;
691 ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */
692
693 *dev = &ctx->device.common;
694
695 return 0;
696}
Sean Paul6a55e9f2015-04-30 15:31:06 -0400697}
Sean Paulef8f1f92015-04-29 16:05:23 -0400698
Sean Paul6a55e9f2015-04-30 15:31:06 -0400699static struct hw_module_methods_t hwc_module_methods = {
700 open : android::hwc_device_open
701};
Sean Paule0c4c3d2015-01-20 16:56:04 -0500702
703hwc_module_t HAL_MODULE_INFO_SYM = {
Sean Paulef8f1f92015-04-29 16:05:23 -0400704 common : {
705 tag : HARDWARE_MODULE_TAG,
706 version_major : 1,
707 version_minor : 0,
708 id : HWC_HARDWARE_MODULE_ID,
709 name : "DRM hwcomposer module",
710 author : "The Android Open Source Project",
711 methods : &hwc_module_methods,
712 dso : NULL,
713 reserved : {0},
714 }
Sean Paule0c4c3d2015-01-20 16:56:04 -0500715};