blob: 2d2309c42ad1f8c17abcf1c7b79dac2f173f0ad7 [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
Erik Gilling87e707e2012-06-29 17:35:13 -070032#define HWC_REMOVE_DEPRECATED_VERSIONS 1
33
Greg Hackmann86eb1c62012-05-30 09:25:51 -070034#include <cutils/log.h>
35#include <hardware/gralloc.h>
36#include <hardware/hardware.h>
37#include <hardware/hwcomposer.h>
38#include <hardware_legacy/uevent.h>
39#include <utils/Vector.h>
40
Greg Hackmannf4cc0c32012-05-30 09:28:52 -070041#include <sync/sync.h>
42
Greg Hackmann86eb1c62012-05-30 09:25:51 -070043#include "ump.h"
44#include "ion.h"
45#include "gralloc_priv.h"
Benoit Gobycdd61b32012-07-09 12:09:59 -070046#include "exynos_gscaler.h"
Greg Hackmann86eb1c62012-05-30 09:25:51 -070047
48struct hwc_callback_entry
49{
50 void (*callback)(void *, private_handle_t *);
51 void *data;
52};
53typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t;
54
Greg Hackmann69fbbcf2012-06-27 12:33:32 -070055const size_t NUM_HW_WINDOWS = 2;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070056const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1;
57
Erik Gilling87e707e2012-06-29 17:35:13 -070058struct exynos5_hwc_composer_device_1_t;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070059
60struct exynos5_hwc_post_data_t {
Erik Gilling87e707e2012-06-29 17:35:13 -070061 exynos5_hwc_composer_device_1_t *pdev;
62 int overlay_map[NUM_HW_WINDOWS];
63 hwc_layer_1_t overlays[NUM_HW_WINDOWS];
64 int num_overlays;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070065 size_t fb_window;
Erik Gilling87e707e2012-06-29 17:35:13 -070066 int fence;
67 pthread_mutex_t completion_lock;
68 pthread_cond_t completion;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070069};
70
Erik Gilling87e707e2012-06-29 17:35:13 -070071struct exynos5_hwc_composer_device_1_t {
72 hwc_composer_device_1_t base;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070073
74 int fd;
75 exynos5_hwc_post_data_t bufs;
76
77 const private_module_t *gralloc_module;
78 hwc_procs_t *procs;
79 pthread_t vsync_thread;
Benoit Gobycdd61b32012-07-09 12:09:59 -070080
81 bool hdmi_hpd;
82 bool hdmi_mirroring;
83 void *hdmi_gsc;
Greg Hackmann86eb1c62012-05-30 09:25:51 -070084};
85
Erik Gilling87e707e2012-06-29 17:35:13 -070086static void dump_layer(hwc_layer_1_t const *l)
Greg Hackmann86eb1c62012-05-30 09:25:51 -070087{
88 ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, "
89 "{%d,%d,%d,%d}, {%d,%d,%d,%d}",
90 l->compositionType, l->flags, l->handle, l->transform,
91 l->blending,
92 l->sourceCrop.left,
93 l->sourceCrop.top,
94 l->sourceCrop.right,
95 l->sourceCrop.bottom,
96 l->displayFrame.left,
97 l->displayFrame.top,
98 l->displayFrame.right,
99 l->displayFrame.bottom);
100}
101
102static void dump_handle(private_handle_t *h)
103{
104 ALOGV("\t\tformat = %d, width = %u, height = %u, bpp = %u, stride = %u",
105 h->format, h->width, h->height, h->bpp, h->stride);
106}
107
108static void dump_config(s3c_fb_win_config &c)
109{
110 ALOGV("\tstate = %u", c.state);
111 if (c.state == c.S3C_FB_WIN_STATE_BUFFER) {
112 ALOGV("\t\tfd = %d, offset = %u, stride = %u, "
113 "x = %d, y = %d, w = %u, h = %u, "
114 "format = %u",
115 c.fd, c.offset, c.stride,
116 c.x, c.y, c.w, c.h,
117 c.format);
118 }
119 else if (c.state == c.S3C_FB_WIN_STATE_COLOR) {
120 ALOGV("\t\tcolor = %u", c.color);
121 }
122}
123
124inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; }
125inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; }
126
Erik Gilling87e707e2012-06-29 17:35:13 -0700127static bool is_scaled(const hwc_layer_1_t &layer)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700128{
129 return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) ||
130 HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop);
131}
132
133static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format)
134{
135 switch (format) {
136 case HAL_PIXEL_FORMAT_RGBA_8888:
137 return S3C_FB_PIXEL_FORMAT_RGBA_8888;
Greg Hackmann8a249a32012-06-27 11:52:53 -0700138 case HAL_PIXEL_FORMAT_RGBX_8888:
139 return S3C_FB_PIXEL_FORMAT_RGBX_8888;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700140 case HAL_PIXEL_FORMAT_RGBA_5551:
141 return S3C_FB_PIXEL_FORMAT_RGBA_5551;
142 case HAL_PIXEL_FORMAT_RGBA_4444:
143 return S3C_FB_PIXEL_FORMAT_RGBA_4444;
144
145 default:
146 return S3C_FB_PIXEL_FORMAT_MAX;
147 }
148}
149
150static bool exynos5_format_is_supported(int format)
151{
152 return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX;
153}
154
155static bool exynos5_format_is_supported_by_gscaler(int format)
156{
157 switch(format) {
Greg Hackmann8a249a32012-06-27 11:52:53 -0700158 case HAL_PIXEL_FORMAT_RGBA_8888:
159 case HAL_PIXEL_FORMAT_RGBX_8888:
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700160 case HAL_PIXEL_FORMAT_RGB_565:
161 case HAL_PIXEL_FORMAT_YV12:
162 return true;
163
164 default:
165 return false;
166 }
167}
168
169static uint8_t exynos5_format_to_bpp(int format)
170{
171 switch (format) {
172 case HAL_PIXEL_FORMAT_RGBA_8888:
Greg Hackmann8a249a32012-06-27 11:52:53 -0700173 case HAL_PIXEL_FORMAT_RGBX_8888:
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700174 return 32;
175
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700176 case HAL_PIXEL_FORMAT_RGBA_5551:
177 case HAL_PIXEL_FORMAT_RGBA_4444:
178 return 16;
179
180 default:
181 ALOGW("unrecognized pixel format %u", format);
182 return 0;
183 }
184}
185
Benoit Gobycdd61b32012-07-09 12:09:59 -0700186static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev)
187{
188 if (dev->hdmi_mirroring)
189 return 0;
190
191 exynos_gsc_img src_info;
192 exynos_gsc_img dst_info;
193
194 // TODO: Don't hardcode
195 int src_w = 2560;
196 int src_h = 1600;
197 int dst_w = 1920;
198 int dst_h = 1080;
199
200 dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV);
201 if (!dev->hdmi_gsc) {
202 ALOGE("%s: exynos_gsc_create_exclusive failed", __func__);
203 return -ENODEV;
204 }
205
206 memset(&src_info, 0, sizeof(src_info));
207 memset(&dst_info, 0, sizeof(dst_info));
208
209 src_info.w = src_w;
210 src_info.h = src_h;
211 src_info.fw = src_w;
212 src_info.fh = src_h;
213 src_info.format = HAL_PIXEL_FORMAT_BGRA_8888;
214
215 dst_info.w = dst_w;
216 dst_info.h = dst_h;
217 dst_info.fw = dst_w;
218 dst_info.fh = dst_h;
219 dst_info.format = HAL_PIXEL_FORMAT_RGBA_8888;
220
221 int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dst_info);
222 if (ret < 0) {
223 ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret);
224 exynos_gsc_destroy(dev->hdmi_gsc);
225 dev->hdmi_gsc = NULL;
226 return ret;
227 }
228
229 dev->hdmi_mirroring = true;
230 return 0;
231}
232
233static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev)
234{
235 if (!dev->hdmi_mirroring)
236 return;
237 exynos_gsc_destroy(dev->hdmi_gsc);
238 dev->hdmi_gsc = NULL;
239 dev->hdmi_mirroring = false;
240}
241
242static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb)
243{
244 exynos_gsc_img src_info;
245 exynos_gsc_img dst_info;
246
247 memset(&src_info, 0, sizeof(src_info));
248 memset(&dst_info, 0, sizeof(dst_info));
249
250 src_info.yaddr = fb->fd;
251
252 int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info);
253 if (ret < 0) {
254 ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret);
255 return ret;
256 }
257
258 return 0;
259}
260
Erik Gilling87e707e2012-06-29 17:35:13 -0700261bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) {
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700262 private_handle_t *handle = private_handle_t::dynamicCast(layer.handle);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700263
264 if (!handle) {
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700265 ALOGV("\tlayer %u: handle is NULL", i);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700266 return false;
267 }
268 if (!exynos5_format_is_supported(handle->format)) {
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700269 ALOGV("\tlayer %u: pixel format %u not supported", i,
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700270 handle->format);
271 return false;
272 }
273 if (is_scaled(layer)) {
274 // TODO: this can be made into an overlay if a gscaler
275 // unit is available. Also some size and pixel format
276 // limitations (see 46-3 of datasheet)
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700277 ALOGV("\tlayer %u: scaling and transforming not supported", i);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700278 return false;
279 }
280 if (layer.blending != HWC_BLENDING_NONE) {
281 // TODO: support this
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700282 ALOGV("\tlayer %u: blending not supported", i);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700283 return false;
284 }
285
Greg Hackmann69fbbcf2012-06-27 12:33:32 -0700286 return true;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700287}
288
Erik Gilling87e707e2012-06-29 17:35:13 -0700289static int exynos5_prepare(hwc_composer_device_1_t *dev, hwc_layer_list_1_t* list)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700290{
291 if (!list)
292 return 0;
293
294 ALOGV("preparing %u layers", list->numHwLayers);
295
Erik Gilling87e707e2012-06-29 17:35:13 -0700296 exynos5_hwc_composer_device_1_t *pdev =
297 (exynos5_hwc_composer_device_1_t *)dev;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700298 memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays));
299
Benoit Gobycdd61b32012-07-09 12:09:59 -0700300 bool force_fb = false;
301 if (pdev->hdmi_hpd) {
302 hdmi_enable(pdev);
303 force_fb = true;
304 } else {
305 hdmi_disable(pdev);
306 }
307
Erik Gilling87e707e2012-06-29 17:35:13 -0700308 for (size_t i = 0; i < NUM_HW_WINDOWS; i++)
309 pdev->bufs.overlay_map[i] = -1;
310
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700311 bool fb_needed = false;
312 size_t first_fb = 0, last_fb;
313
314 // find unsupported overlays
315 for (size_t i = 0; i < list->numHwLayers; i++) {
Erik Gilling87e707e2012-06-29 17:35:13 -0700316 hwc_layer_1_t &layer = list->hwLayers[i];
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700317
Benoit Gobycdd61b32012-07-09 12:09:59 -0700318 if (layer.compositionType == HWC_BACKGROUND && !force_fb) {
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700319 ALOGV("\tlayer %u: background supported", i);
320 continue;
321 }
322
Benoit Gobycdd61b32012-07-09 12:09:59 -0700323 if (exynos5_supports_overlay(list->hwLayers[i], i) && !force_fb) {
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700324 ALOGV("\tlayer %u: overlay supported", i);
325 layer.compositionType = HWC_OVERLAY;
326 continue;
327 }
328
329 if (!fb_needed) {
330 first_fb = i;
331 fb_needed = true;
332 }
333 last_fb = i;
334 layer.compositionType = HWC_FRAMEBUFFER;
335 }
336
337 // can't composite overlays sandwiched between framebuffers
338 if (fb_needed)
339 for (size_t i = first_fb; i < last_fb; i++)
340 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
341
342 // if we need a framebuffer but can't fit it in, reserve the last
343 // window as a framebuffer
Greg Hackmann853a7f82012-06-27 12:30:44 -0700344 if ((fb_needed && first_fb >= NUM_HW_WINDOWS) ||
345 (!fb_needed && list->numHwLayers > NUM_HW_WINDOWS)) {
346 fb_needed = true;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700347 first_fb = NUM_HW_WINDOWS - 1;
Greg Hackmann853a7f82012-06-27 12:30:44 -0700348 for (size_t i = first_fb; i < list->numHwLayers; i++)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700349 list->hwLayers[i].compositionType = HWC_FRAMEBUFFER;
350 }
351
352 unsigned int nextWindow = 0;
353
354 // assign as many overlays as possible to windows
355 for (size_t i = 0; i < list->numHwLayers; i++) {
Erik Gilling87e707e2012-06-29 17:35:13 -0700356 hwc_layer_1_t &layer = list->hwLayers[i];
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700357
358 if (nextWindow == NUM_HW_WINDOWS) {
359 ALOGV("not enough windows to assign layer %u", i);
360 layer.compositionType = HWC_FRAMEBUFFER;
361 continue;
362 }
363
364 if (fb_needed && i == first_fb) {
365 ALOGV("assigning framebuffer to window %u\n",
366 nextWindow);
367 nextWindow++;
368 continue;
369 }
370
371 if (layer.compositionType != HWC_FRAMEBUFFER) {
372 ALOGV("assigning layer %u to window %u", i, nextWindow);
Erik Gilling87e707e2012-06-29 17:35:13 -0700373 pdev->bufs.overlay_map[nextWindow] = i;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700374 nextWindow++;
375 }
376 }
377
378 if (fb_needed)
379 pdev->bufs.fb_window = first_fb;
380 else
381 pdev->bufs.fb_window = NO_FB_NEEDED;
382
383 for (size_t i = 0; i < list->numHwLayers; i++) {
384 dump_layer(&list->hwLayers[i]);
385 if(list->hwLayers[i].handle)
386 dump_handle(private_handle_t::dynamicCast(
387 list->hwLayers[i].handle));
388 }
389
390 return 0;
391}
392
393static void exynos5_config_handle(private_handle_t *handle,
394 hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame,
395 s3c_fb_win_config &cfg) {
396 cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER;
397 cfg.fd = handle->fd;
398 cfg.x = displayFrame.left;
399 cfg.y = displayFrame.top;
400 cfg.w = WIDTH(displayFrame);
401 cfg.h = HEIGHT(displayFrame);
402 cfg.format = exynos5_format_to_s3c_format(handle->format);
403 uint8_t bpp = exynos5_format_to_bpp(handle->format);
404 cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) *
405 bpp / 8;
406 cfg.stride = handle->stride * bpp / 8;
407}
408
Erik Gilling87e707e2012-06-29 17:35:13 -0700409static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg,
Greg Hackmann8a249a32012-06-27 11:52:53 -0700410 const private_module_t *gralloc_module)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700411{
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700412 if (layer->compositionType == HWC_BACKGROUND) {
413 hwc_color_t color = layer->backgroundColor;
414 cfg.state = cfg.S3C_FB_WIN_STATE_COLOR;
415 cfg.color = (color.r << 16) | (color.g << 8) | color.b;
Greg Hackmann8a249a32012-06-27 11:52:53 -0700416 cfg.x = 0;
417 cfg.y = 0;
418 cfg.w = gralloc_module->xres;
419 cfg.h = gralloc_module->yres;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700420 return;
421 }
422
423 private_handle_t *handle = private_handle_t::dynamicCast(layer->handle);
424 exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame,
425 cfg);
426}
427
428static void exynos5_post_callback(void *data, private_handle_t *fb)
429{
430 exynos5_hwc_post_data_t *pdata =
431 (exynos5_hwc_post_data_t *)data;
432
Greg Hackmannf4cc0c32012-05-30 09:28:52 -0700433 struct s3c_fb_win_config_data win_data;
434 struct s3c_fb_win_config *config = win_data.config;
435 memset(config, 0, sizeof(win_data.config));
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700436 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
437 if (i == pdata->fb_window) {
438 hwc_rect_t rect = { 0, 0, fb->width, fb->height };
439 exynos5_config_handle(fb, rect, rect, config[i]);
Erik Gilling87e707e2012-06-29 17:35:13 -0700440 } else if ( pdata->overlay_map[i] != -1) {
441 exynos5_config_overlay(&pdata->overlays[i], config[i],
Greg Hackmann8a249a32012-06-27 11:52:53 -0700442 pdata->pdev->gralloc_module);
Erik Gilling87e707e2012-06-29 17:35:13 -0700443 if (pdata->overlays[i].acquireFenceFd != -1) {
444 int err = sync_wait(pdata->overlays[i].acquireFenceFd, 100);
445 if (err != 0)
446 ALOGW("fence for layer %zu didn't signal in 100 ms: %s",
447 i, strerror(errno));
448 close(pdata->overlays[i].acquireFenceFd);
449 }
450 }
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700451 dump_config(config[i]);
452 }
453
Greg Hackmannf4cc0c32012-05-30 09:28:52 -0700454 int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700455 if (ret < 0)
Greg Hackmannf4cc0c32012-05-30 09:28:52 -0700456 ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700457
Benoit Gobycdd61b32012-07-09 12:09:59 -0700458 if (pdata->pdev->hdmi_mirroring)
459 hdmi_output(pdata->pdev, fb);
460
Erik Gilling87e707e2012-06-29 17:35:13 -0700461 pthread_mutex_lock(&pdata->completion_lock);
462 pdata->fence = win_data.fence;
463 pthread_cond_signal(&pdata->completion);
464 pthread_mutex_unlock(&pdata->completion_lock);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700465}
466
Erik Gilling87e707e2012-06-29 17:35:13 -0700467static int exynos5_set(struct hwc_composer_device_1 *dev, hwc_display_t dpy,
468 hwc_surface_t sur, hwc_layer_list_1_t* list)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700469{
Erik Gilling87e707e2012-06-29 17:35:13 -0700470 exynos5_hwc_composer_device_1_t *pdev =
471 (exynos5_hwc_composer_device_1_t *)dev;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700472
473 if (!dpy || !sur)
474 return 0;
475
476 hwc_callback_queue_t *queue = NULL;
477 pthread_mutex_t *lock = NULL;
478 exynos5_hwc_post_data_t *data = NULL;
479
480 if (list) {
Erik Gilling87e707e2012-06-29 17:35:13 -0700481 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
482 if (pdev->bufs.overlay_map[i] != -1) {
483 pdev->bufs.overlays[i] =
484 list->hwLayers[pdev->bufs.overlay_map[i]];
485 }
486 }
487
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700488 data = (exynos5_hwc_post_data_t *)
489 malloc(sizeof(exynos5_hwc_post_data_t));
490 memcpy(data, &pdev->bufs, sizeof(pdev->bufs));
491
Erik Gilling87e707e2012-06-29 17:35:13 -0700492 data->fence = -1;
493 pthread_mutex_init(&data->completion_lock, NULL);
494 pthread_cond_init(&data->completion, NULL);
495
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700496 if (pdev->bufs.fb_window == NO_FB_NEEDED) {
497 exynos5_post_callback(data, NULL);
Erik Gilling87e707e2012-06-29 17:35:13 -0700498 } else {
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700499
Erik Gilling87e707e2012-06-29 17:35:13 -0700500 struct hwc_callback_entry entry;
501 entry.callback = exynos5_post_callback;
502 entry.data = data;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700503
Erik Gilling87e707e2012-06-29 17:35:13 -0700504 queue = reinterpret_cast<hwc_callback_queue_t *>(
505 pdev->gralloc_module->queue);
506 lock = const_cast<pthread_mutex_t *>(
507 &pdev->gralloc_module->queue_lock);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700508
Erik Gilling87e707e2012-06-29 17:35:13 -0700509 pthread_mutex_lock(lock);
510 queue->push_front(entry);
511 pthread_mutex_unlock(lock);
512
513 EGLBoolean success = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
514 if (!success) {
515 ALOGE("HWC_EGL_ERROR");
516 if (list) {
517 pthread_mutex_lock(lock);
518 queue->removeAt(0);
519 pthread_mutex_unlock(lock);
520 free(data);
521 }
522 return HWC_EGL_ERROR;
523 }
524 }
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700525 }
526
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700527
Erik Gilling87e707e2012-06-29 17:35:13 -0700528 pthread_mutex_lock(&data->completion_lock);
529 while (data->fence == -1)
530 pthread_cond_wait(&data->completion, &data->completion_lock);
531 pthread_mutex_unlock(&data->completion_lock);
532
533 for (size_t i = 0; i < NUM_HW_WINDOWS; i++) {
534 if (pdev->bufs.overlay_map[i] != -1) {
535 int dup_fd = dup(data->fence);
536 if (dup_fd < 0)
537 ALOGW("release fence dup failed: %s", strerror(errno));
538 list->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd;
539 }
540 }
541 close(data->fence);
542 free(data);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700543 return 0;
544}
545
Erik Gilling87e707e2012-06-29 17:35:13 -0700546static void exynos5_registerProcs(struct hwc_composer_device_1* dev,
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700547 hwc_procs_t const* procs)
548{
Erik Gilling87e707e2012-06-29 17:35:13 -0700549 struct exynos5_hwc_composer_device_1_t* pdev =
550 (struct exynos5_hwc_composer_device_1_t*)dev;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700551 pdev->procs = const_cast<hwc_procs_t *>(procs);
552}
553
Erik Gilling87e707e2012-06-29 17:35:13 -0700554static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value)
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700555{
Erik Gilling87e707e2012-06-29 17:35:13 -0700556 struct exynos5_hwc_composer_device_1_t *pdev =
557 (struct exynos5_hwc_composer_device_1_t *)dev;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700558
559 switch (what) {
560 case HWC_BACKGROUND_LAYER_SUPPORTED:
561 // we support the background layer
562 value[0] = 1;
563 break;
564 case HWC_VSYNC_PERIOD:
565 // vsync period in nanosecond
566 value[0] = 1000000000.0 / pdev->gralloc_module->fps;
567 break;
568 default:
569 // unsupported query
570 return -EINVAL;
571 }
572 return 0;
573}
574
Erik Gilling87e707e2012-06-29 17:35:13 -0700575static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int event,
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700576 int enabled)
577{
Erik Gilling87e707e2012-06-29 17:35:13 -0700578 struct exynos5_hwc_composer_device_1_t *pdev =
579 (struct exynos5_hwc_composer_device_1_t *)dev;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700580
581 switch (event) {
582 case HWC_EVENT_VSYNC:
583 __u32 val = !!enabled;
584 int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val);
585 if (err < 0) {
586 ALOGE("vsync ioctl failed");
587 return -errno;
588 }
589
590 return 0;
591 }
592
593 return -EINVAL;
594}
595
Benoit Gobycdd61b32012-07-09 12:09:59 -0700596static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
597 const char *buff, int len)
598{
599 const char *s = buff;
600 s += strlen(s) + 1;
601
602 while (*s) {
603 if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE=")))
604 pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1;
605
606 s += strlen(s) + 1;
607 if (s - buff >= len)
608 break;
609 }
610
611 ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled");
612
613 if (pdev->procs && pdev->procs->invalidate)
614 pdev->procs->invalidate(pdev->procs);
615}
616
Erik Gilling87e707e2012-06-29 17:35:13 -0700617static void handle_vsync_uevent(struct exynos5_hwc_composer_device_1_t *pdev,
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700618 const char *buff, int len)
619{
620 uint64_t timestamp = 0;
621 const char *s = buff;
622
623 if (!pdev->procs || !pdev->procs->vsync)
624 return;
625
626 s += strlen(s) + 1;
627
628 while (*s) {
629 if (!strncmp(s, "VSYNC=", strlen("VSYNC=")))
630 timestamp = strtoull(s + strlen("VSYNC="), NULL, 0);
631
632 s += strlen(s) + 1;
633 if (s - buff >= len)
634 break;
635 }
636
637 pdev->procs->vsync(pdev->procs, 0, timestamp);
638}
639
640static void *hwc_vsync_thread(void *data)
641{
Erik Gilling87e707e2012-06-29 17:35:13 -0700642 struct exynos5_hwc_composer_device_1_t *pdev =
643 (struct exynos5_hwc_composer_device_1_t *)data;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700644 char uevent_desc[4096];
645 memset(uevent_desc, 0, sizeof(uevent_desc));
646
647 setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
648
649 uevent_init();
650 while (true) {
651 int len = uevent_next_event(uevent_desc,
652 sizeof(uevent_desc) - 2);
653
654 bool vsync = !strcmp(uevent_desc,
655 "change@/devices/platform/exynos5-fb.1");
656 if (vsync)
657 handle_vsync_uevent(pdev, uevent_desc, len);
Benoit Gobycdd61b32012-07-09 12:09:59 -0700658
659 bool hdmi = !strcmp(uevent_desc,
660 "change@/devices/virtual/switch/hdmi");
661 if (hdmi)
662 handle_hdmi_uevent(pdev, uevent_desc, len);
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700663 }
664
665 return NULL;
666}
667
Erik Gilling87e707e2012-06-29 17:35:13 -0700668struct hwc_methods_1 exynos5_methods = {
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700669 eventControl: exynos5_eventControl,
670};
671
672static int exynos5_close(hw_device_t* device);
673
674static int exynos5_open(const struct hw_module_t *module, const char *name,
675 struct hw_device_t **device)
676{
677 int ret;
Benoit Gobycdd61b32012-07-09 12:09:59 -0700678 int sw_fd;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700679
680 if (strcmp(name, HWC_HARDWARE_COMPOSER)) {
681 return -EINVAL;
682 }
683
Erik Gilling87e707e2012-06-29 17:35:13 -0700684 struct exynos5_hwc_composer_device_1_t *dev;
685 dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev));
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700686 memset(dev, 0, sizeof(*dev));
687
688 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
689 (const struct hw_module_t **)&dev->gralloc_module)) {
690 ALOGE("failed to get gralloc hw module");
691 ret = -EINVAL;
692 goto err_get_module;
693 }
694
695 dev->fd = open("/dev/graphics/fb0", O_RDWR);
696 if (dev->fd < 0) {
697 ALOGE("failed to open framebuffer");
698 ret = dev->fd;
699 goto err_get_module;
700 }
701
Benoit Gobycdd61b32012-07-09 12:09:59 -0700702 sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY);
703 if (sw_fd) {
704 char val;
705 if (read(sw_fd, &val, 1) == 1 && val == '1')
706 dev->hdmi_hpd = true;
707 }
708
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700709 dev->base.common.tag = HARDWARE_DEVICE_TAG;
Erik Gilling87e707e2012-06-29 17:35:13 -0700710 dev->base.common.version = HWC_DEVICE_API_VERSION_1_0;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700711 dev->base.common.module = const_cast<hw_module_t *>(module);
712 dev->base.common.close = exynos5_close;
713
714 dev->base.prepare = exynos5_prepare;
715 dev->base.set = exynos5_set;
716 dev->base.registerProcs = exynos5_registerProcs;
717 dev->base.query = exynos5_query;
718 dev->base.methods = &exynos5_methods;
719
720 dev->bufs.pdev = dev;
721
722 *device = &dev->base.common;
723
724 ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev);
725 if (ret) {
726 ALOGE("failed to start vsync thread: %s", strerror(ret));
727 ret = -ret;
728 goto err_ioctl;
729 }
730
731 return 0;
732
733err_ioctl:
734 close(dev->fd);
735err_get_module:
736 free(dev);
737 return ret;
738}
739
740static int exynos5_close(hw_device_t *device)
741{
Erik Gilling87e707e2012-06-29 17:35:13 -0700742 struct exynos5_hwc_composer_device_1_t *dev =
743 (struct exynos5_hwc_composer_device_1_t *)device;
Greg Hackmann86eb1c62012-05-30 09:25:51 -0700744 close(dev->fd);
745 return 0;
746}
747
748static struct hw_module_methods_t exynos5_hwc_module_methods = {
749 open: exynos5_open,
750};
751
752hwc_module_t HAL_MODULE_INFO_SYM = {
753 common: {
754 tag: HARDWARE_MODULE_TAG,
755 module_api_version: HWC_MODULE_API_VERSION_0_1,
756 hal_api_version: HARDWARE_HAL_API_VERSION,
757 id: HWC_HARDWARE_MODULE_ID,
758 name: "Samsung exynos5 hwcomposer module",
759 author: "Google",
760 methods: &exynos5_hwc_module_methods,
761 }
762};