blob: c6b13b5e1483a3d2995e335651949a7ff3bd5790 [file] [log] [blame]
Greg Hackmann86eb1c62012-05-30 09:25:51 -07001/*
2 * Copyright (C) 2012 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#include <errno.h>
18#include <fcntl.h>
19#include <pthread.h>
20#include <stdio.h>
21#include <stdlib.h>
22
23#include <sys/ioctl.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/resource.h>
27
28#include <s3c-fb.h>
29
30#include <EGL/egl.h>
31
32#include <cutils/log.h>
33#include <hardware/gralloc.h>
34#include <hardware/hardware.h>
35#include <hardware/hwcomposer.h>
36#include <hardware_legacy/uevent.h>
37#include <utils/Vector.h>
38
39#include "ump.h"
40#include "ion.h"
41#include "gralloc_priv.h"
42
43struct hwc_callback_entry
44{
45 void (*callback)(void *, private_handle_t *);
46 void *data;
47};
48typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t;
49
50const size_t NUM_HW_WINDOWS = 5;
51const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
52
53struct exynos5_hwc_composer_device_t;
54
55struct exynos5_hwc_post_data_t {
56 exynos5_hwc_composer_device_t *pdev;
57 hwc_layer_t *overlays[NUM_HW_WINDOWS];
58 size_t fb_window;
59};
60
61struct exynos5_hwc_composer_device_t {
62 hwc_composer_device_t base;
63
64 int fd;
65 exynos5_hwc_post_data_t bufs;
66
67 const private_module_t *gralloc_module;
68 hwc_procs_t *procs;
69 pthread_t vsync_thread;
70};
71
72static void dump_layer(hwc_layer_t const *l)
73{
74 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
75 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
76 l->compositionType, l->flags, l->handle, l->transform,
77 l->blending,
78 l->sourceCrop.left,
79 l->sourceCrop.top,
80 l->sourceCrop.right,
81 l->sourceCrop.bottom,
82 l->displayFrame.left,
83 l->displayFrame.top,
84 l->displayFrame.right,
85 l->displayFrame.bottom);
86}
87
88static void dump_handle(private_handle_t *h)
89{
90 ALOGV("\t\tformat = %d, width = %u, height = %u, bpp = %u, stride = %u",
91 h->format, h->width, h->height, h->bpp, h->stride);
92}
93
94static void dump_config(s3c_fb_win_config &c)
95{
96 ALOGV("\tstate = %u", c.state);
97 if (c.state == c.S3C_FB_WIN_STATE_BUFFER) {
98 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
99 "x = %d, y = %d, w = %u, h = %u, "
100 "format = %u",
101 c.fd, c.offset, c.stride,
102 c.x, c.y, c.w, c.h,
103 c.format);
104 }
105 else if (c.state == c.S3C_FB_WIN_STATE_COLOR) {
106 ALOGV("\t\tcolor = %u", c.color);
107 }
108}
109
110inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
111inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
112
113static bool is_scaled(const hwc_layer_t &layer)
114{
115 return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) ||
116 HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop);
117}
118
119static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format)
120{
121 switch (format) {
122 case HAL_PIXEL_FORMAT_RGBA_8888:
123 return S3C_FB_PIXEL_FORMAT_RGBA_8888;
124 case HAL_PIXEL_FORMAT_RGB_888:
125 return S3C_FB_PIXEL_FORMAT_RGB_888;
126 case HAL_PIXEL_FORMAT_RGB_565:
127 return S3C_FB_PIXEL_FORMAT_RGB_565;
128 case HAL_PIXEL_FORMAT_BGRA_8888:
129 return S3C_FB_PIXEL_FORMAT_BGRA_8888;
130 case HAL_PIXEL_FORMAT_RGBA_5551:
131 return S3C_FB_PIXEL_FORMAT_RGBA_5551;
132 case HAL_PIXEL_FORMAT_RGBA_4444:
133 return S3C_FB_PIXEL_FORMAT_RGBA_4444;
134
135 default:
136 return S3C_FB_PIXEL_FORMAT_MAX;
137 }
138}
139
140static bool exynos5_format_is_supported(int format)
141{
142 return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX;
143}
144
145static bool exynos5_format_is_supported_by_gscaler(int format)
146{
147 switch(format) {
148 case HAL_PIXEL_FORMAT_RGB_888:
149 case HAL_PIXEL_FORMAT_RGB_565:
150 case HAL_PIXEL_FORMAT_YV12:
151 return true;
152
153 default:
154 return false;
155 }
156}
157
158static uint8_t exynos5_format_to_bpp(int format)
159{
160 switch (format) {
161 case HAL_PIXEL_FORMAT_RGBA_8888:
162 case HAL_PIXEL_FORMAT_BGRA_8888:
163 return 32;
164
165 case HAL_PIXEL_FORMAT_RGB_888:
166 return 24;
167
168 case HAL_PIXEL_FORMAT_RGB_565:
169 case HAL_PIXEL_FORMAT_RGBA_5551:
170 case HAL_PIXEL_FORMAT_RGBA_4444:
171 return 16;
172
173 default:
174 ALOGW("unrecognized pixel format %u", format);
175 return 0;
176 }
177}
178
179bool exynos5_supports_overlay(hwc_layer_t &layer, size_t i) {
180/* private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
181
182 if (!handle) {
183 ALOGW("\tlayer %u: handle is NULL", i);
184 return false;
185 }
186 if (!exynos5_format_is_supported(handle->format)) {
187 ALOGW("\tlayer %u: pixel format %u not supported", i,
188 handle->format);
189 return false;
190 }
191 if (is_scaled(layer)) {
192 // TODO: this can be made into an overlay if a gscaler
193 // unit is available. Also some size and pixel format
194 // limitations (see 46-3 of datasheet)
195 ALOGW("\tlayer %u: scaling and transforming not supported", i);
196 return false;
197 }
198 if (layer.blending != HWC_BLENDING_NONE) {
199 // TODO: support this
200 ALOGW("\tlayer %u: blending not supported", i);
201 return false;
202 }
203
204 return true;*/
205
206 return false;
207 // for debugging purposes, everything goes into a framebuffer
208}
209
210static int exynos5_prepare(hwc_composer_device_t *dev, hwc_layer_list_t* list)
211{
212 if (!list)
213 return 0;
214
215 ALOGV("preparing %u layers", list->numHwLayers);
216
217 exynos5_hwc_composer_device_t *pdev =
218 (exynos5_hwc_composer_device_t *)dev;
219 memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays));
220
221 bool fb_needed = false;
222 size_t first_fb = 0, last_fb;
223
224 // find unsupported overlays
225 for (size_t i = 0; i < list->numHwLayers; i++) {
226 hwc_layer_t &layer = list->hwLayers[i];
227
228 if (layer.compositionType == HWC_BACKGROUND) {
229 ALOGV("\tlayer %u: background supported", i);
230 continue;
231 }
232
233 if (exynos5_supports_overlay(list->hwLayers[i], i)) {
234 ALOGV("\tlayer %u: overlay supported", i);
235 layer.compositionType = HWC_OVERLAY;
236 continue;
237 }
238
239 if (!fb_needed) {
240 first_fb = i;
241 fb_needed = true;
242 }
243 last_fb = i;
244 layer.compositionType = HWC_FRAMEBUFFER;
245 }
246
247 // can't composite overlays sandwiched between framebuffers
248 if (fb_needed)
249 for (size_t i = first_fb; i < last_fb; i++)
250 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
251
252 // if we need a framebuffer but can't fit it in, reserve the last
253 // window as a framebuffer
254 if (fb_needed && first_fb >= NUM_HW_WINDOWS) {
255 first_fb = NUM_HW_WINDOWS - 1;
256 for (size_t i = first_fb + 1; i < list->numHwLayers; i++)
257 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
258 }
259
260 unsigned int nextWindow = 0;
261
262 // assign as many overlays as possible to windows
263 for (size_t i = 0; i < list->numHwLayers; i++) {
264 hwc_layer_t &layer = list->hwLayers[i];
265
266 if (nextWindow == NUM_HW_WINDOWS) {
267 ALOGV("not enough windows to assign layer %u", i);
268 layer.compositionType = HWC_FRAMEBUFFER;
269 continue;
270 }
271
272 if (fb_needed && i == first_fb) {
273 ALOGV("assigning framebuffer to window %u\n",
274 nextWindow);
275 nextWindow++;
276 continue;
277 }
278
279 if (layer.compositionType != HWC_FRAMEBUFFER) {
280 ALOGV("assigning layer %u to window %u", i, nextWindow);
281 pdev->bufs.overlays[nextWindow] = &layer;
282 nextWindow++;
283 }
284 }
285
286 if (fb_needed)
287 pdev->bufs.fb_window = first_fb;
288 else
289 pdev->bufs.fb_window = NO_FB_NEEDED;
290
291 for (size_t i = 0; i < list->numHwLayers; i++) {
292 dump_layer(&list->hwLayers[i]);
293 if(list->hwLayers[i].handle)
294 dump_handle(private_handle_t::dynamicCast(
295 list->hwLayers[i].handle));
296 }
297
298 return 0;
299}
300
301static void exynos5_config_handle(private_handle_t *handle,
302 hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame,
303 s3c_fb_win_config &cfg) {
304 cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER;
305 cfg.fd = handle->fd;
306 cfg.x = displayFrame.left;
307 cfg.y = displayFrame.top;
308 cfg.w = WIDTH(displayFrame);
309 cfg.h = HEIGHT(displayFrame);
310 cfg.format = exynos5_format_to_s3c_format(handle->format);
311 uint8_t bpp = exynos5_format_to_bpp(handle->format);
312 cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) *
313 bpp / 8;
314 cfg.stride = handle->stride * bpp / 8;
315}
316
317
318static void exynos5_config_overlay(hwc_layer_t *layer, s3c_fb_win_config &cfg)
319{
320 if (!layer)
321 return;
322
323 if (layer->compositionType == HWC_BACKGROUND) {
324 hwc_color_t color = layer->backgroundColor;
325 cfg.state = cfg.S3C_FB_WIN_STATE_COLOR;
326 cfg.color = (color.r << 16) | (color.g << 8) | color.b;
327 return;
328 }
329
330 private_handle_t *handle = private_handle_t::dynamicCast(layer->handle);
331 exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame,
332 cfg);
333}
334
335static void exynos5_post_callback(void *data, private_handle_t *fb)
336{
337 exynos5_hwc_post_data_t *pdata =
338 (exynos5_hwc_post_data_t *)data;
339
340 struct s3c_fb_win_config config[NUM_HW_WINDOWS];
341 memset(config, 0, sizeof(config));
342 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
343 if (i == pdata->fb_window) {
344 hwc_rect_t rect = { 0, 0, fb->width, fb->height };
345 exynos5_config_handle(fb, rect, rect, config[i]);
346 } else
347 exynos5_config_overlay(pdata->overlays[i], config[i]);
348 dump_config(config[i]);
349 }
350
351 int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, config);
352 if (ret < 0)
353 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", ret);
354
355 free(pdata);
356}
357
358static int exynos5_set(struct hwc_composer_device *dev, hwc_display_t dpy,
359 hwc_surface_t sur, hwc_layer_list_t* list)
360{
361 exynos5_hwc_composer_device_t *pdev =
362 (exynos5_hwc_composer_device_t *)dev;
363
364 if (!dpy || !sur)
365 return 0;
366
367 hwc_callback_queue_t *queue = NULL;
368 pthread_mutex_t *lock = NULL;
369 exynos5_hwc_post_data_t *data = NULL;
370
371 if (list) {
372 data = (exynos5_hwc_post_data_t *)
373 malloc(sizeof(exynos5_hwc_post_data_t));
374 memcpy(data, &pdev->bufs, sizeof(pdev->bufs));
375
376 if (pdev->bufs.fb_window == NO_FB_NEEDED) {
377 exynos5_post_callback(data, NULL);
378 return 0;
379 }
380
381 struct hwc_callback_entry entry;
382 entry.callback = exynos5_post_callback;
383 entry.data = data;
384
385 queue = reinterpret_cast<hwc_callback_queue_t *>(
386 pdev->gralloc_module->queue);
387 lock = const_cast<pthread_mutex_t *>(
388 &pdev->gralloc_module->queue_lock);
389
390 pthread_mutex_lock(lock);
391 queue->push_front(entry);
392 pthread_mutex_unlock(lock);
393 }
394
395 EGLBoolean success = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
396 if (!success) {
397 ALOGE("HWC_EGL_ERROR");
398 if (list) {
399 pthread_mutex_lock(lock);
400 queue->removeAt(0);
401 pthread_mutex_unlock(lock);
402 free(data);
403 }
404 return HWC_EGL_ERROR;
405 }
406
407 return 0;
408}
409
410static void exynos5_registerProcs(struct hwc_composer_device* dev,
411 hwc_procs_t const* procs)
412{
413 struct exynos5_hwc_composer_device_t* pdev =
414 (struct exynos5_hwc_composer_device_t*)dev;
415 pdev->procs = const_cast<hwc_procs_t *>(procs);
416}
417
418static int exynos5_query(struct hwc_composer_device* dev, int what, int *value)
419{
420 struct exynos5_hwc_composer_device_t *pdev =
421 (struct exynos5_hwc_composer_device_t *)dev;
422
423 switch (what) {
424 case HWC_BACKGROUND_LAYER_SUPPORTED:
425 // we support the background layer
426 value[0] = 1;
427 break;
428 case HWC_VSYNC_PERIOD:
429 // vsync period in nanosecond
430 value[0] = 1000000000.0 / pdev->gralloc_module->fps;
431 break;
432 default:
433 // unsupported query
434 return -EINVAL;
435 }
436 return 0;
437}
438
439static int exynos5_eventControl(struct hwc_composer_device *dev, int event,
440 int enabled)
441{
442 struct exynos5_hwc_composer_device_t *pdev =
443 (struct exynos5_hwc_composer_device_t *)dev;
444
445 switch (event) {
446 case HWC_EVENT_VSYNC:
447 __u32 val = !!enabled;
448 int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val);
449 if (err < 0) {
450 ALOGE("vsync ioctl failed");
451 return -errno;
452 }
453
454 return 0;
455 }
456
457 return -EINVAL;
458}
459
460static void handle_vsync_uevent(struct exynos5_hwc_composer_device_t *pdev,
461 const char *buff, int len)
462{
463 uint64_t timestamp = 0;
464 const char *s = buff;
465
466 if (!pdev->procs || !pdev->procs->vsync)
467 return;
468
469 s += strlen(s) + 1;
470
471 while (*s) {
472 if (!strncmp(s, "VSYNC=", strlen("VSYNC=")))
473 timestamp = strtoull(s + strlen("VSYNC="), NULL, 0);
474
475 s += strlen(s) + 1;
476 if (s - buff >= len)
477 break;
478 }
479
480 pdev->procs->vsync(pdev->procs, 0, timestamp);
481}
482
483static void *hwc_vsync_thread(void *data)
484{
485 struct exynos5_hwc_composer_device_t *pdev =
486 (struct exynos5_hwc_composer_device_t *)data;
487 char uevent_desc[4096];
488 memset(uevent_desc, 0, sizeof(uevent_desc));
489
490 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
491
492 uevent_init();
493 while (true) {
494 int len = uevent_next_event(uevent_desc,
495 sizeof(uevent_desc) - 2);
496
497 bool vsync = !strcmp(uevent_desc,
498 "change@/devices/platform/exynos5-fb.1");
499 if (vsync)
500 handle_vsync_uevent(pdev, uevent_desc, len);
501 }
502
503 return NULL;
504}
505
506struct hwc_methods exynos5_methods = {
507 eventControl: exynos5_eventControl,
508};
509
510static int exynos5_close(hw_device_t* device);
511
512static int exynos5_open(const struct hw_module_t *module, const char *name,
513 struct hw_device_t **device)
514{
515 int ret;
516
517 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
518 return -EINVAL;
519 }
520
521 struct exynos5_hwc_composer_device_t *dev;
522 dev = (struct exynos5_hwc_composer_device_t *)malloc(sizeof(*dev));
523 memset(dev, 0, sizeof(*dev));
524
525 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
526 (const struct hw_module_t **)&dev->gralloc_module)) {
527 ALOGE("failed to get gralloc hw module");
528 ret = -EINVAL;
529 goto err_get_module;
530 }
531
532 dev->fd = open("/dev/graphics/fb0", O_RDWR);
533 if (dev->fd < 0) {
534 ALOGE("failed to open framebuffer");
535 ret = dev->fd;
536 goto err_get_module;
537 }
538
539 dev->base.common.tag = HARDWARE_DEVICE_TAG;
540 dev->base.common.version = HWC_DEVICE_API_VERSION_0_3;
541 dev->base.common.module = const_cast<hw_module_t *>(module);
542 dev->base.common.close = exynos5_close;
543
544 dev->base.prepare = exynos5_prepare;
545 dev->base.set = exynos5_set;
546 dev->base.registerProcs = exynos5_registerProcs;
547 dev->base.query = exynos5_query;
548 dev->base.methods = &exynos5_methods;
549
550 dev->bufs.pdev = dev;
551
552 *device = &dev->base.common;
553
554 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
555 if (ret) {
556 ALOGE("failed to start vsync thread: %s", strerror(ret));
557 ret = -ret;
558 goto err_ioctl;
559 }
560
561 return 0;
562
563err_ioctl:
564 close(dev->fd);
565err_get_module:
566 free(dev);
567 return ret;
568}
569
570static int exynos5_close(hw_device_t *device)
571{
572 struct exynos5_hwc_composer_device_t *dev =
573 (struct exynos5_hwc_composer_device_t *)device;
574 close(dev->fd);
575 return 0;
576}
577
578static struct hw_module_methods_t exynos5_hwc_module_methods = {
579 open: exynos5_open,
580};
581
582hwc_module_t HAL_MODULE_INFO_SYM = {
583 common: {
584 tag: HARDWARE_MODULE_TAG,
585 module_api_version: HWC_MODULE_API_VERSION_0_1,
586 hal_api_version: HARDWARE_HAL_API_VERSION,
587 id: HWC_HARDWARE_MODULE_ID,
588 name: "Samsung exynos5 hwcomposer module",
589 author: "Google",
590 methods: &exynos5_hwc_module_methods,
591 }
592};