Commit | Line | Data |
---|---|---|
86eb1c67 GH |
1 | /* |
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 | */ | |
86eb1c67 GH |
16 | #include <errno.h> |
17 | #include <fcntl.h> | |
2972485a | 18 | #include <poll.h> |
86eb1c67 GH |
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 | ||
87e707ef EG |
32 | #define HWC_REMOVE_DEPRECATED_VERSIONS 1 |
33 | ||
86eb1c67 GH |
34 | #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 | ||
f4cc0c30 GH |
41 | #include <sync/sync.h> |
42 | ||
86eb1c67 GH |
43 | #include "ion.h" |
44 | #include "gralloc_priv.h" | |
cdd61b35 | 45 | #include "exynos_gscaler.h" |
9130e706 | 46 | #include "exynos_format.h" |
d6bb7cef | 47 | #include "videodev2.h" |
86eb1c67 | 48 | |
f6f2e546 GH |
49 | struct hwc_callback_entry { |
50 | void (*callback)(void *, private_handle_t *); | |
51 | void *data; | |
86eb1c67 GH |
52 | }; |
53 | typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t; | |
54 | ||
31991d5b | 55 | const size_t NUM_HW_WINDOWS = 5; |
86eb1c67 | 56 | const size_t NO_FB_NEEDED = NUM_HW_WINDOWS + 1; |
31991d5b | 57 | const size_t MAX_PIXELS = 2560 * 1600 * 2; |
9130e706 GH |
58 | const size_t GSC_W_ALIGNMENT = 16; |
59 | const size_t GSC_H_ALIGNMENT = 16; | |
2ddbc743 GH |
60 | const int AVAILABLE_GSC_UNITS[] = { 0, 3 }; |
61 | const size_t NUM_GSC_UNITS = sizeof(AVAILABLE_GSC_UNITS) / | |
62 | sizeof(AVAILABLE_GSC_UNITS[0]); | |
86eb1c67 | 63 | |
87e707ef | 64 | struct exynos5_hwc_composer_device_1_t; |
86eb1c67 | 65 | |
9130e706 GH |
66 | struct exynos5_gsc_map_t { |
67 | enum { | |
68 | GSC_NONE = 0, | |
69 | GSC_M2M, | |
70 | // TODO: GSC_LOCAL_PATH | |
71 | } mode; | |
72 | int idx; | |
73 | }; | |
74 | ||
86eb1c67 | 75 | struct exynos5_hwc_post_data_t { |
f6f2e546 GH |
76 | exynos5_hwc_composer_device_1_t *pdev; |
77 | int overlay_map[NUM_HW_WINDOWS]; | |
9130e706 | 78 | exynos5_gsc_map_t gsc_map[NUM_HW_WINDOWS]; |
f6f2e546 GH |
79 | hwc_layer_1_t overlays[NUM_HW_WINDOWS]; |
80 | int num_overlays; | |
81 | size_t fb_window; | |
82 | int fence; | |
83 | pthread_mutex_t completion_lock; | |
84 | pthread_cond_t completion; | |
86eb1c67 GH |
85 | }; |
86 | ||
9130e706 GH |
87 | const size_t NUM_GSC_DST_BUFS = 2; |
88 | struct exynos5_gsc_data_t { | |
89 | void *gsc; | |
90 | exynos_gsc_img src_cfg; | |
91 | exynos_gsc_img dst_cfg; | |
92 | buffer_handle_t dst_buf[NUM_GSC_DST_BUFS]; | |
93 | size_t current_buf; | |
94 | }; | |
95 | ||
87e707ef | 96 | struct exynos5_hwc_composer_device_1_t { |
f6f2e546 | 97 | hwc_composer_device_1_t base; |
86eb1c67 | 98 | |
f6f2e546 | 99 | int fd; |
2972485a | 100 | int vsync_fd; |
f6f2e546 | 101 | exynos5_hwc_post_data_t bufs; |
86eb1c67 | 102 | |
f6f2e546 | 103 | const private_module_t *gralloc_module; |
9130e706 | 104 | alloc_device_t *alloc_device; |
f6f2e546 GH |
105 | hwc_procs_t *procs; |
106 | pthread_t vsync_thread; | |
cdd61b35 | 107 | |
d6bb7cef | 108 | int hdmi_fd; |
f6f2e546 GH |
109 | bool hdmi_hpd; |
110 | bool hdmi_mirroring; | |
111 | void *hdmi_gsc; | |
d6bb7cef | 112 | exynos_gsc_img hdmi_cfg; |
9130e706 GH |
113 | |
114 | exynos5_gsc_data_t gsc[NUM_GSC_UNITS]; | |
86eb1c67 GH |
115 | }; |
116 | ||
9130e706 GH |
117 | static void dump_handle(private_handle_t *h) |
118 | { | |
119 | ALOGV("\t\tformat = %d, width = %u, height = %u, stride = %u", | |
120 | h->format, h->width, h->height, h->stride); | |
121 | } | |
122 | ||
87e707ef | 123 | static void dump_layer(hwc_layer_1_t const *l) |
86eb1c67 | 124 | { |
f6f2e546 GH |
125 | ALOGV("\ttype=%d, flags=%08x, handle=%p, tr=%02x, blend=%04x, " |
126 | "{%d,%d,%d,%d}, {%d,%d,%d,%d}", | |
127 | l->compositionType, l->flags, l->handle, l->transform, | |
128 | l->blending, | |
129 | l->sourceCrop.left, | |
130 | l->sourceCrop.top, | |
131 | l->sourceCrop.right, | |
132 | l->sourceCrop.bottom, | |
133 | l->displayFrame.left, | |
134 | l->displayFrame.top, | |
135 | l->displayFrame.right, | |
136 | l->displayFrame.bottom); | |
86eb1c67 | 137 | |
9130e706 GH |
138 | if(l->handle && !(l->flags & HWC_SKIP_LAYER)) |
139 | dump_handle(private_handle_t::dynamicCast(l->handle)); | |
86eb1c67 GH |
140 | } |
141 | ||
142 | static void dump_config(s3c_fb_win_config &c) | |
143 | { | |
f6f2e546 GH |
144 | ALOGV("\tstate = %u", c.state); |
145 | if (c.state == c.S3C_FB_WIN_STATE_BUFFER) { | |
146 | ALOGV("\t\tfd = %d, offset = %u, stride = %u, " | |
147 | "x = %d, y = %d, w = %u, h = %u, " | |
93cc5e7a | 148 | "format = %u, blending = %u", |
f6f2e546 GH |
149 | c.fd, c.offset, c.stride, |
150 | c.x, c.y, c.w, c.h, | |
93cc5e7a | 151 | c.format, c.blending); |
f6f2e546 GH |
152 | } |
153 | else if (c.state == c.S3C_FB_WIN_STATE_COLOR) { | |
154 | ALOGV("\t\tcolor = %u", c.color); | |
155 | } | |
86eb1c67 GH |
156 | } |
157 | ||
9130e706 GH |
158 | static void dump_gsc_img(exynos_gsc_img &c) |
159 | { | |
160 | ALOGV("\tx = %u, y = %u, w = %u, h = %u, fw = %u, fh = %u", | |
161 | c.x, c.y, c.w, c.h, c.fw, c.fh); | |
162 | ALOGV("\taddr = {%u, %u, %u}, rot = %u, cacheable = %u, drmMode = %u", | |
163 | c.yaddr, c.uaddr, c.vaddr, c.rot, c.cacheable, c.drmMode); | |
164 | } | |
165 | ||
86eb1c67 GH |
166 | inline int WIDTH(const hwc_rect &rect) { return rect.right - rect.left; } |
167 | inline int HEIGHT(const hwc_rect &rect) { return rect.bottom - rect.top; } | |
31991d5b GH |
168 | template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; } |
169 | template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; } | |
170 | ||
171 | static bool is_transformed(const hwc_layer_1_t &layer) | |
172 | { | |
f6f2e546 | 173 | return layer.transform != 0; |
31991d5b | 174 | } |
86eb1c67 | 175 | |
9130e706 GH |
176 | static bool is_rotated(const hwc_layer_1_t &layer) |
177 | { | |
178 | return (layer.transform & HAL_TRANSFORM_ROT_90) || | |
179 | (layer.transform & HAL_TRANSFORM_ROT_180); | |
180 | } | |
181 | ||
87e707ef | 182 | static bool is_scaled(const hwc_layer_1_t &layer) |
86eb1c67 | 183 | { |
f6f2e546 GH |
184 | return WIDTH(layer.displayFrame) != WIDTH(layer.sourceCrop) || |
185 | HEIGHT(layer.displayFrame) != HEIGHT(layer.sourceCrop); | |
86eb1c67 GH |
186 | } |
187 | ||
188 | static enum s3c_fb_pixel_format exynos5_format_to_s3c_format(int format) | |
189 | { | |
f6f2e546 GH |
190 | switch (format) { |
191 | case HAL_PIXEL_FORMAT_RGBA_8888: | |
192 | return S3C_FB_PIXEL_FORMAT_RGBA_8888; | |
193 | case HAL_PIXEL_FORMAT_RGBX_8888: | |
194 | return S3C_FB_PIXEL_FORMAT_RGBX_8888; | |
195 | case HAL_PIXEL_FORMAT_RGBA_5551: | |
196 | return S3C_FB_PIXEL_FORMAT_RGBA_5551; | |
f6f2e546 GH |
197 | |
198 | default: | |
199 | return S3C_FB_PIXEL_FORMAT_MAX; | |
200 | } | |
86eb1c67 GH |
201 | } |
202 | ||
203 | static bool exynos5_format_is_supported(int format) | |
204 | { | |
f6f2e546 | 205 | return exynos5_format_to_s3c_format(format) < S3C_FB_PIXEL_FORMAT_MAX; |
86eb1c67 GH |
206 | } |
207 | ||
208 | static bool exynos5_format_is_supported_by_gscaler(int format) | |
209 | { | |
9130e706 | 210 | switch (format) { |
f6f2e546 GH |
211 | case HAL_PIXEL_FORMAT_RGBX_8888: |
212 | case HAL_PIXEL_FORMAT_RGB_565: | |
213 | case HAL_PIXEL_FORMAT_YV12: | |
9130e706 GH |
214 | case HAL_PIXEL_FORMAT_YCbCr_420_P: |
215 | case HAL_PIXEL_FORMAT_YCbCr_422_SP: | |
216 | case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_SP: | |
217 | case HAL_PIXEL_FORMAT_YCbCr_420_SP: | |
218 | case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP: | |
219 | case HAL_PIXEL_FORMAT_YCbCr_422_I: | |
220 | case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_422_I: | |
221 | case HAL_PIXEL_FORMAT_YCbCr_422_P: | |
222 | case HAL_PIXEL_FORMAT_CbYCrY_422_I: | |
223 | case HAL_PIXEL_FORMAT_CUSTOM_CbYCrY_422_I: | |
224 | case HAL_PIXEL_FORMAT_YCrCb_422_SP: | |
225 | case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_SP: | |
226 | case HAL_PIXEL_FORMAT_YCrCb_420_SP: | |
227 | case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_420_SP: | |
228 | case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: | |
229 | case HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED: | |
230 | case HAL_PIXEL_FORMAT_CUSTOM_YCrCb_422_I: | |
231 | case HAL_PIXEL_FORMAT_CUSTOM_CrYCbY_422_I: | |
f6f2e546 GH |
232 | return true; |
233 | ||
234 | default: | |
235 | return false; | |
236 | } | |
86eb1c67 GH |
237 | } |
238 | ||
296668ec GH |
239 | static bool exynos5_format_is_ycrcb(int format) |
240 | { | |
241 | return format == HAL_PIXEL_FORMAT_YV12; | |
242 | } | |
243 | ||
9130e706 GH |
244 | static bool exynos5_format_requires_gscaler(int format) |
245 | { | |
246 | return exynos5_format_is_supported_by_gscaler(format) && | |
247 | format != HAL_PIXEL_FORMAT_RGBX_8888; | |
248 | } | |
249 | ||
86eb1c67 GH |
250 | static uint8_t exynos5_format_to_bpp(int format) |
251 | { | |
f6f2e546 GH |
252 | switch (format) { |
253 | case HAL_PIXEL_FORMAT_RGBA_8888: | |
254 | case HAL_PIXEL_FORMAT_RGBX_8888: | |
255 | return 32; | |
256 | ||
257 | case HAL_PIXEL_FORMAT_RGBA_5551: | |
258 | case HAL_PIXEL_FORMAT_RGBA_4444: | |
259 | return 16; | |
260 | ||
261 | default: | |
262 | ALOGW("unrecognized pixel format %u", format); | |
263 | return 0; | |
264 | } | |
86eb1c67 GH |
265 | } |
266 | ||
227ae8ae GH |
267 | static bool exynos5_supports_gscaler(hwc_layer_1_t &layer, int format, |
268 | bool local_path) | |
9130e706 GH |
269 | { |
270 | private_handle_t *handle = private_handle_t::dynamicCast(layer.handle); | |
271 | ||
272 | int max_w = is_rotated(layer) ? 2048 : 4800; | |
273 | int max_h = is_rotated(layer) ? 2048 : 3344; | |
274 | ||
275 | bool rot90or270 = !!(layer.transform & HAL_TRANSFORM_ROT_90); | |
276 | // n.b.: HAL_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_90 | | |
277 | // HAL_TRANSFORM_ROT_180 | |
278 | ||
227ae8ae GH |
279 | int src_w = WIDTH(layer.sourceCrop), src_h = HEIGHT(layer.sourceCrop); |
280 | int dest_w, dest_h; | |
281 | if (rot90or270) { | |
282 | dest_w = HEIGHT(layer.displayFrame); | |
283 | dest_h = WIDTH(layer.displayFrame); | |
284 | } else { | |
285 | dest_w = WIDTH(layer.displayFrame); | |
286 | dest_h = HEIGHT(layer.displayFrame); | |
287 | } | |
288 | int max_downscale = local_path ? 4 : 16; | |
289 | const int max_upscale = 8; | |
290 | ||
9130e706 GH |
291 | return exynos5_format_is_supported_by_gscaler(format) && |
292 | handle->stride <= max_w && | |
293 | handle->stride % GSC_W_ALIGNMENT == 0 && | |
227ae8ae GH |
294 | src_w <= dest_w * max_downscale && |
295 | dest_w <= src_w * max_upscale && | |
9130e706 GH |
296 | handle->height <= max_h && |
297 | handle->height % GSC_H_ALIGNMENT == 0 && | |
227ae8ae GH |
298 | src_h <= dest_h * max_downscale && |
299 | dest_h <= src_h * max_upscale && | |
9130e706 GH |
300 | // per 46.2 |
301 | (!rot90or270 || layer.sourceCrop.top % 2 == 0) && | |
302 | (!rot90or270 || layer.sourceCrop.left % 2 == 0); | |
303 | // per 46.3.1.6 | |
304 | } | |
305 | ||
d6bb7cef BG |
306 | int hdmi_get_config(struct exynos5_hwc_composer_device_1_t *dev) |
307 | { | |
308 | struct v4l2_dv_preset preset; | |
309 | struct v4l2_dv_enum_preset enum_preset; | |
310 | exynos_gsc_img *info = &dev->hdmi_cfg; | |
311 | int index = 0; | |
312 | bool found = false; | |
313 | int ret; | |
314 | ||
315 | if (ioctl(dev->hdmi_fd, VIDIOC_G_DV_PRESET, &preset) < 0) { | |
316 | ALOGE("%s: g_dv_preset error, %d", __func__, errno); | |
317 | return -1; | |
318 | } | |
319 | ||
320 | while (true) { | |
321 | enum_preset.index = index++; | |
322 | ret = ioctl(dev->hdmi_fd, VIDIOC_ENUM_DV_PRESETS, &enum_preset); | |
323 | ||
324 | if (ret < 0) { | |
325 | if (errno == EINVAL) | |
326 | break; | |
327 | ALOGE("%s: enum_dv_presets error, %d", __func__, errno); | |
328 | return -1; | |
329 | } | |
330 | ||
331 | ALOGV("%s: %d preset=%02d width=%d height=%d name=%s", | |
332 | __func__, enum_preset.index, enum_preset.preset, | |
333 | enum_preset.width, enum_preset.height, enum_preset.name); | |
334 | ||
335 | if (preset.preset == enum_preset.preset) { | |
336 | info->w = enum_preset.width; | |
337 | info->h = enum_preset.height; | |
338 | info->fw = enum_preset.width; | |
339 | info->fh = enum_preset.height; | |
340 | info->format = HAL_PIXEL_FORMAT_YV12; | |
341 | found = true; | |
342 | } | |
343 | } | |
344 | ||
345 | return found ? 0 : -1; | |
346 | } | |
347 | ||
93cc5e7a GH |
348 | static enum s3c_fb_blending exynos5_blending_to_s3c_blending(int32_t blending) |
349 | { | |
350 | switch (blending) { | |
351 | case HWC_BLENDING_NONE: | |
352 | return S3C_FB_BLENDING_NONE; | |
353 | case HWC_BLENDING_PREMULT: | |
354 | return S3C_FB_BLENDING_PREMULT; | |
355 | case HWC_BLENDING_COVERAGE: | |
356 | return S3C_FB_BLENDING_COVERAGE; | |
357 | ||
358 | default: | |
359 | return S3C_FB_BLENDING_MAX; | |
360 | } | |
361 | } | |
362 | ||
363 | static bool exynos5_blending_is_supported(int32_t blending) | |
364 | { | |
365 | return exynos5_blending_to_s3c_blending(blending) < S3C_FB_BLENDING_MAX; | |
366 | } | |
367 | ||
cdd61b35 BG |
368 | static int hdmi_enable(struct exynos5_hwc_composer_device_1_t *dev) |
369 | { | |
f6f2e546 GH |
370 | if (dev->hdmi_mirroring) |
371 | return 0; | |
372 | ||
373 | exynos_gsc_img src_info; | |
f6f2e546 GH |
374 | int src_w = 2560; |
375 | int src_h = 1600; | |
f6f2e546 GH |
376 | |
377 | dev->hdmi_gsc = exynos_gsc_create_exclusive(3, GSC_OUTPUT_MODE, GSC_OUT_TV); | |
378 | if (!dev->hdmi_gsc) { | |
379 | ALOGE("%s: exynos_gsc_create_exclusive failed", __func__); | |
380 | return -ENODEV; | |
381 | } | |
382 | ||
383 | memset(&src_info, 0, sizeof(src_info)); | |
f6f2e546 GH |
384 | |
385 | src_info.w = src_w; | |
386 | src_info.h = src_h; | |
387 | src_info.fw = src_w; | |
388 | src_info.fh = src_h; | |
389 | src_info.format = HAL_PIXEL_FORMAT_BGRA_8888; | |
390 | ||
d6bb7cef | 391 | int ret = exynos_gsc_config_exclusive(dev->hdmi_gsc, &src_info, &dev->hdmi_cfg); |
f6f2e546 GH |
392 | if (ret < 0) { |
393 | ALOGE("%s: exynos_gsc_config_exclusive failed %d", __func__, ret); | |
394 | exynos_gsc_destroy(dev->hdmi_gsc); | |
395 | dev->hdmi_gsc = NULL; | |
396 | return ret; | |
397 | } | |
398 | ||
399 | dev->hdmi_mirroring = true; | |
400 | return 0; | |
cdd61b35 BG |
401 | } |
402 | ||
403 | static void hdmi_disable(struct exynos5_hwc_composer_device_1_t *dev) | |
404 | { | |
f6f2e546 GH |
405 | if (!dev->hdmi_mirroring) |
406 | return; | |
407 | exynos_gsc_destroy(dev->hdmi_gsc); | |
408 | dev->hdmi_gsc = NULL; | |
409 | dev->hdmi_mirroring = false; | |
cdd61b35 BG |
410 | } |
411 | ||
412 | static int hdmi_output(struct exynos5_hwc_composer_device_1_t *dev, private_handle_t *fb) | |
413 | { | |
f6f2e546 GH |
414 | exynos_gsc_img src_info; |
415 | exynos_gsc_img dst_info; | |
cdd61b35 | 416 | |
f6f2e546 GH |
417 | memset(&src_info, 0, sizeof(src_info)); |
418 | memset(&dst_info, 0, sizeof(dst_info)); | |
cdd61b35 | 419 | |
f6f2e546 | 420 | src_info.yaddr = fb->fd; |
cdd61b35 | 421 | |
f6f2e546 GH |
422 | int ret = exynos_gsc_run_exclusive(dev->hdmi_gsc, &src_info, &dst_info); |
423 | if (ret < 0) { | |
424 | ALOGE("%s: exynos_gsc_run_exclusive failed %d", __func__, ret); | |
425 | return ret; | |
426 | } | |
cdd61b35 | 427 | |
f6f2e546 | 428 | return 0; |
cdd61b35 BG |
429 | } |
430 | ||
f6f2e546 GH |
431 | bool exynos5_supports_overlay(hwc_layer_1_t &layer, size_t i) |
432 | { | |
d82ad20e GH |
433 | if (layer.flags & HWC_SKIP_LAYER) { |
434 | ALOGV("\tlayer %u: skipping", i); | |
435 | return false; | |
436 | } | |
437 | ||
f6f2e546 GH |
438 | private_handle_t *handle = private_handle_t::dynamicCast(layer.handle); |
439 | ||
440 | if (!handle) { | |
441 | ALOGV("\tlayer %u: handle is NULL", i); | |
442 | return false; | |
443 | } | |
9130e706 | 444 | if (exynos5_format_requires_gscaler(handle->format)) { |
227ae8ae | 445 | if (!exynos5_supports_gscaler(layer, handle->format, false)) { |
9130e706 GH |
446 | ALOGV("\tlayer %u: gscaler required but not supported", i); |
447 | return false; | |
448 | } | |
449 | } else { | |
450 | if (!exynos5_format_is_supported(handle->format)) { | |
451 | ALOGV("\tlayer %u: pixel format %u not supported", i, handle->format); | |
452 | return false; | |
453 | } | |
454 | if (is_scaled(layer)) { | |
455 | ALOGV("\tlayer %u: scaling not supported", i); | |
456 | return false; | |
457 | } | |
458 | if (is_transformed(layer)) { | |
459 | ALOGV("\tlayer %u: transformations not supported", i); | |
460 | return false; | |
461 | } | |
f6f2e546 | 462 | } |
93cc5e7a GH |
463 | if (!exynos5_blending_is_supported(layer.blending)) { |
464 | ALOGV("\tlayer %u: blending %d not supported", i, layer.blending); | |
f6f2e546 GH |
465 | return false; |
466 | } | |
467 | ||
468 | return true; | |
86eb1c67 GH |
469 | } |
470 | ||
31991d5b GH |
471 | inline bool intersect(const hwc_rect &r1, const hwc_rect &r2) |
472 | { | |
f6f2e546 GH |
473 | return !(r1.left > r2.right || |
474 | r1.right < r2.left || | |
475 | r1.top > r2.bottom || | |
476 | r1.bottom < r2.top); | |
31991d5b GH |
477 | } |
478 | ||
479 | inline hwc_rect intersection(const hwc_rect &r1, const hwc_rect &r2) | |
480 | { | |
f6f2e546 GH |
481 | hwc_rect i; |
482 | i.top = max(r1.top, r2.top); | |
483 | i.bottom = min(r1.bottom, r2.bottom); | |
484 | i.left = max(r1.left, r2.left); | |
485 | i.right = min(r1.right, r2.right); | |
486 | return i; | |
31991d5b GH |
487 | } |
488 | ||
e94046d9 JH |
489 | static int exynos5_prepare(hwc_composer_device_1_t *dev, |
490 | size_t numDisplays, hwc_display_contents_1_t** displays) | |
86eb1c67 | 491 | { |
e94046d9 | 492 | if (!numDisplays || !displays) |
f6f2e546 | 493 | return 0; |
86eb1c67 | 494 | |
e94046d9 | 495 | ALOGV("preparing %u layers", displays[0]->numHwLayers); |
86eb1c67 | 496 | |
f6f2e546 GH |
497 | exynos5_hwc_composer_device_1_t *pdev = |
498 | (exynos5_hwc_composer_device_1_t *)dev; | |
499 | memset(pdev->bufs.overlays, 0, sizeof(pdev->bufs.overlays)); | |
9130e706 | 500 | memset(pdev->bufs.gsc_map, 0, sizeof(pdev->bufs.gsc_map)); |
86eb1c67 | 501 | |
f6f2e546 GH |
502 | bool force_fb = false; |
503 | if (pdev->hdmi_hpd) { | |
504 | hdmi_enable(pdev); | |
505 | force_fb = true; | |
506 | } else { | |
507 | hdmi_disable(pdev); | |
508 | } | |
cdd61b35 | 509 | |
87e707ef EG |
510 | for (size_t i = 0; i < NUM_HW_WINDOWS; i++) |
511 | pdev->bufs.overlay_map[i] = -1; | |
512 | ||
f6f2e546 GH |
513 | bool fb_needed = false; |
514 | size_t first_fb = 0, last_fb = 0; | |
515 | ||
516 | // find unsupported overlays | |
e94046d9 JH |
517 | for (size_t i = 0; i < displays[0]->numHwLayers; i++) { |
518 | hwc_layer_1_t &layer = displays[0]->hwLayers[i]; | |
f6f2e546 GH |
519 | |
520 | if (layer.compositionType == HWC_BACKGROUND && !force_fb) { | |
521 | ALOGV("\tlayer %u: background supported", i); | |
e94046d9 | 522 | dump_layer(&displays[0]->hwLayers[i]); |
f6f2e546 GH |
523 | continue; |
524 | } | |
525 | ||
e94046d9 | 526 | if (exynos5_supports_overlay(displays[0]->hwLayers[i], i) && !force_fb) { |
f6f2e546 GH |
527 | ALOGV("\tlayer %u: overlay supported", i); |
528 | layer.compositionType = HWC_OVERLAY; | |
e94046d9 | 529 | dump_layer(&displays[0]->hwLayers[i]); |
f6f2e546 GH |
530 | continue; |
531 | } | |
532 | ||
533 | if (!fb_needed) { | |
534 | first_fb = i; | |
535 | fb_needed = true; | |
536 | } | |
537 | last_fb = i; | |
538 | layer.compositionType = HWC_FRAMEBUFFER; | |
9130e706 | 539 | |
e94046d9 | 540 | dump_layer(&displays[0]->hwLayers[i]); |
f6f2e546 GH |
541 | } |
542 | ||
543 | // can't composite overlays sandwiched between framebuffers | |
544 | if (fb_needed) | |
545 | for (size_t i = first_fb; i < last_fb; i++) | |
e94046d9 | 546 | displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; |
f6f2e546 GH |
547 | |
548 | // Incrementally try to add our supported layers to hardware windows. | |
549 | // If adding a layer would violate a hardware constraint, force it | |
550 | // into the framebuffer and try again. (Revisiting the entire list is | |
551 | // necessary because adding a layer to the framebuffer can cause other | |
552 | // windows to retroactively violate constraints.) | |
553 | bool changed; | |
554 | do { | |
555 | android::Vector<hwc_rect> rects; | |
556 | android::Vector<hwc_rect> overlaps; | |
9130e706 | 557 | size_t pixels_left, windows_left, gsc_left = NUM_GSC_UNITS; |
f6f2e546 GH |
558 | |
559 | if (fb_needed) { | |
560 | hwc_rect_t fb_rect; | |
561 | fb_rect.top = fb_rect.left = 0; | |
562 | fb_rect.right = pdev->gralloc_module->xres - 1; | |
563 | fb_rect.bottom = pdev->gralloc_module->yres - 1; | |
564 | pixels_left = MAX_PIXELS - pdev->gralloc_module->xres * | |
565 | pdev->gralloc_module->yres; | |
566 | windows_left = NUM_HW_WINDOWS - 1; | |
567 | rects.push_back(fb_rect); | |
568 | } | |
569 | else { | |
570 | pixels_left = MAX_PIXELS; | |
571 | windows_left = NUM_HW_WINDOWS; | |
572 | } | |
9130e706 GH |
573 | if (pdev->hdmi_mirroring) |
574 | gsc_left--; | |
575 | ||
f6f2e546 GH |
576 | changed = false; |
577 | ||
e94046d9 JH |
578 | for (size_t i = 0; i < displays[0]->numHwLayers; i++) { |
579 | hwc_layer_1_t &layer = displays[0]->hwLayers[i]; | |
9130e706 GH |
580 | if (layer.flags & HWC_SKIP_LAYER) |
581 | continue; | |
582 | ||
583 | private_handle_t *handle = private_handle_t::dynamicCast( | |
584 | layer.handle); | |
f6f2e546 GH |
585 | |
586 | // we've already accounted for the framebuffer above | |
587 | if (layer.compositionType == HWC_FRAMEBUFFER) | |
588 | continue; | |
589 | ||
590 | // only layer 0 can be HWC_BACKGROUND, so we can | |
591 | // unconditionally allow it without extra checks | |
592 | if (layer.compositionType == HWC_BACKGROUND) { | |
593 | windows_left--; | |
594 | continue; | |
595 | } | |
596 | ||
597 | size_t pixels_needed = WIDTH(layer.displayFrame) * | |
598 | HEIGHT(layer.displayFrame); | |
599 | bool can_compose = windows_left && pixels_needed <= pixels_left; | |
9130e706 GH |
600 | bool gsc_required = exynos5_format_requires_gscaler(handle->format); |
601 | if (gsc_required) | |
602 | can_compose = can_compose && gsc_left; | |
f6f2e546 GH |
603 | |
604 | // hwc_rect_t right and bottom values are normally exclusive; | |
605 | // the intersection logic is simpler if we make them inclusive | |
606 | hwc_rect_t visible_rect = layer.displayFrame; | |
607 | visible_rect.right--; visible_rect.bottom--; | |
608 | ||
609 | // no more than 2 layers can overlap on a given pixel | |
610 | for (size_t j = 0; can_compose && j < overlaps.size(); j++) { | |
611 | if (intersect(visible_rect, overlaps.itemAt(j))) | |
612 | can_compose = false; | |
613 | } | |
614 | ||
615 | if (!can_compose) { | |
616 | layer.compositionType = HWC_FRAMEBUFFER; | |
617 | if (!fb_needed) { | |
618 | first_fb = last_fb = i; | |
619 | fb_needed = true; | |
620 | } | |
621 | else { | |
622 | first_fb = min(i, first_fb); | |
623 | last_fb = max(i, last_fb); | |
624 | } | |
625 | changed = true; | |
626 | break; | |
627 | } | |
628 | ||
629 | for (size_t j = 0; j < rects.size(); j++) { | |
630 | const hwc_rect_t &other_rect = rects.itemAt(j); | |
631 | if (intersect(visible_rect, other_rect)) | |
632 | overlaps.push_back(intersection(visible_rect, other_rect)); | |
633 | } | |
634 | rects.push_back(visible_rect); | |
635 | pixels_left -= pixels_needed; | |
636 | windows_left--; | |
9130e706 GH |
637 | if (gsc_required) |
638 | gsc_left--; | |
f6f2e546 GH |
639 | } |
640 | ||
641 | if (changed) | |
642 | for (size_t i = first_fb; i < last_fb; i++) | |
e94046d9 | 643 | displays[0]->hwLayers[i].compositionType = HWC_FRAMEBUFFER; |
f6f2e546 GH |
644 | } while(changed); |
645 | ||
646 | unsigned int nextWindow = 0; | |
9130e706 | 647 | int nextGsc = 0; |
f6f2e546 | 648 | |
e94046d9 JH |
649 | for (size_t i = 0; i < displays[0]->numHwLayers; i++) { |
650 | hwc_layer_1_t &layer = displays[0]->hwLayers[i]; | |
f6f2e546 GH |
651 | |
652 | if (fb_needed && i == first_fb) { | |
653 | ALOGV("assigning framebuffer to window %u\n", | |
654 | nextWindow); | |
655 | nextWindow++; | |
656 | continue; | |
657 | } | |
658 | ||
659 | if (layer.compositionType != HWC_FRAMEBUFFER) { | |
660 | ALOGV("assigning layer %u to window %u", i, nextWindow); | |
661 | pdev->bufs.overlay_map[nextWindow] = i; | |
9130e706 GH |
662 | if (layer.compositionType == HWC_OVERLAY) { |
663 | private_handle_t *handle = | |
664 | private_handle_t::dynamicCast(layer.handle); | |
665 | if (exynos5_format_requires_gscaler(handle->format)) { | |
2ddbc743 | 666 | ALOGV("\tusing gscaler %u", AVAILABLE_GSC_UNITS[nextGsc]); |
9130e706 GH |
667 | pdev->bufs.gsc_map[i].mode = |
668 | exynos5_gsc_map_t::GSC_M2M; | |
669 | pdev->bufs.gsc_map[i].idx = nextGsc++; | |
670 | } | |
671 | } | |
f6f2e546 GH |
672 | nextWindow++; |
673 | } | |
674 | } | |
675 | ||
9130e706 GH |
676 | for (size_t i = nextGsc; i < NUM_GSC_UNITS; i++) { |
677 | for (size_t j = 0; j < NUM_GSC_DST_BUFS; j++) | |
678 | if (pdev->gsc[i].dst_buf[j]) | |
679 | pdev->alloc_device->free(pdev->alloc_device, | |
680 | pdev->gsc[i].dst_buf[j]); | |
681 | memset(&pdev->gsc[i], 0, sizeof(pdev->gsc[i])); | |
682 | } | |
683 | ||
f6f2e546 GH |
684 | if (fb_needed) |
685 | pdev->bufs.fb_window = first_fb; | |
686 | else | |
687 | pdev->bufs.fb_window = NO_FB_NEEDED; | |
688 | ||
9130e706 GH |
689 | return 0; |
690 | } | |
691 | ||
692 | static inline bool gsc_dst_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2) | |
693 | { | |
694 | return c1.x != c2.x || | |
695 | c1.y != c2.y || | |
696 | c1.w != c2.w || | |
697 | c1.h != c2.h || | |
698 | c1.format != c2.format || | |
699 | c1.rot != c2.rot || | |
700 | c1.cacheable != c2.cacheable || | |
701 | c1.drmMode != c2.drmMode; | |
702 | } | |
703 | ||
704 | static inline bool gsc_src_cfg_changed(exynos_gsc_img &c1, exynos_gsc_img &c2) | |
705 | { | |
706 | return gsc_dst_cfg_changed(c1, c2) || | |
707 | c1.fw != c2.fw || | |
708 | c1.fh != c2.fh; | |
709 | } | |
710 | ||
711 | static int exynos5_config_gsc_m2m(hwc_layer_1_t &layer, | |
712 | alloc_device_t* alloc_device, exynos5_gsc_data_t *gsc_data, | |
713 | int gsc_idx) | |
714 | { | |
715 | ALOGV("configuring gscaler %u for memory-to-memory", gsc_idx); | |
716 | ||
717 | private_handle_t *src_handle = private_handle_t::dynamicCast(layer.handle); | |
718 | buffer_handle_t dst_buf; | |
719 | private_handle_t *dst_handle; | |
720 | int ret = 0; | |
721 | ||
722 | exynos_gsc_img src_cfg, dst_cfg; | |
723 | memset(&src_cfg, 0, sizeof(src_cfg)); | |
724 | memset(&dst_cfg, 0, sizeof(dst_cfg)); | |
725 | ||
726 | src_cfg.x = layer.sourceCrop.left; | |
727 | src_cfg.y = layer.sourceCrop.top; | |
728 | src_cfg.w = WIDTH(layer.sourceCrop); | |
729 | src_cfg.fw = src_handle->stride; | |
730 | src_cfg.h = HEIGHT(layer.sourceCrop); | |
731 | src_cfg.fh = src_handle->height; | |
732 | src_cfg.yaddr = src_handle->fd; | |
296668ec GH |
733 | if (exynos5_format_is_ycrcb(src_handle->format)) { |
734 | src_cfg.uaddr = src_handle->fd2; | |
735 | src_cfg.vaddr = src_handle->fd1; | |
736 | } else { | |
737 | src_cfg.uaddr = src_handle->fd1; | |
738 | src_cfg.vaddr = src_handle->fd2; | |
739 | } | |
9130e706 GH |
740 | src_cfg.format = src_handle->format; |
741 | ||
742 | dst_cfg.x = 0; | |
743 | dst_cfg.y = 0; | |
744 | dst_cfg.w = WIDTH(layer.displayFrame); | |
745 | dst_cfg.h = HEIGHT(layer.displayFrame); | |
a00c0435 | 746 | dst_cfg.format = HAL_PIXEL_FORMAT_BGRA_8888; |
9130e706 GH |
747 | dst_cfg.rot = layer.transform; |
748 | ||
749 | ALOGV("source configuration:"); | |
750 | dump_gsc_img(src_cfg); | |
751 | ||
752 | if (gsc_src_cfg_changed(src_cfg, gsc_data->src_cfg) || | |
753 | gsc_dst_cfg_changed(dst_cfg, gsc_data->dst_cfg)) { | |
754 | int dst_stride; | |
755 | int usage = GRALLOC_USAGE_SW_READ_NEVER | | |
756 | GRALLOC_USAGE_SW_WRITE_NEVER | | |
757 | GRALLOC_USAGE_HW_COMPOSER; | |
758 | // TODO: add GRALLOC_USAGE_PROTECTED if source buffer is also protected | |
759 | ||
760 | int w = ALIGN(WIDTH(layer.displayFrame), GSC_W_ALIGNMENT); | |
761 | int h = ALIGN(HEIGHT(layer.displayFrame), GSC_H_ALIGNMENT); | |
762 | ||
763 | for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) { | |
764 | if (gsc_data->dst_buf[i]) { | |
765 | alloc_device->free(alloc_device, gsc_data->dst_buf[i]); | |
766 | gsc_data->dst_buf[i] = NULL; | |
767 | } | |
768 | ||
769 | int ret = alloc_device->alloc(alloc_device, w, h, | |
770 | HAL_PIXEL_FORMAT_RGBX_8888, usage, &gsc_data->dst_buf[i], | |
771 | &dst_stride); | |
772 | if (ret < 0) { | |
773 | ALOGE("failed to allocate destination buffer: %s", | |
774 | strerror(-ret)); | |
775 | goto err_alloc; | |
776 | } | |
777 | } | |
778 | ||
779 | gsc_data->current_buf = 0; | |
f6f2e546 GH |
780 | } |
781 | ||
9130e706 GH |
782 | dst_buf = gsc_data->dst_buf[gsc_data->current_buf]; |
783 | dst_handle = private_handle_t::dynamicCast(dst_buf); | |
784 | ||
785 | dst_cfg.fw = dst_handle->stride; | |
786 | dst_cfg.fh = dst_handle->height; | |
787 | dst_cfg.yaddr = dst_handle->fd; | |
788 | ||
789 | ALOGV("destination configuration:"); | |
790 | dump_gsc_img(dst_cfg); | |
791 | ||
2ddbc743 GH |
792 | gsc_data->gsc = exynos_gsc_create_exclusive(AVAILABLE_GSC_UNITS[gsc_idx], |
793 | GSC_M2M_MODE, GSC_DUMMY); | |
9130e706 GH |
794 | if (!gsc_data->gsc) { |
795 | ALOGE("failed to create gscaler handle"); | |
796 | ret = -1; | |
797 | goto err_alloc; | |
798 | } | |
799 | ||
800 | ret = exynos_gsc_config_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg); | |
801 | if (ret < 0) { | |
802 | ALOGE("failed to configure gscaler %u", gsc_idx); | |
803 | goto err_gsc_config; | |
804 | } | |
805 | ||
806 | ret = exynos_gsc_run_exclusive(gsc_data->gsc, &src_cfg, &dst_cfg); | |
807 | if (ret < 0) { | |
808 | ALOGE("failed to run gscaler %u", gsc_idx); | |
809 | goto err_gsc_config; | |
810 | } | |
811 | ||
812 | gsc_data->src_cfg = src_cfg; | |
813 | gsc_data->dst_cfg = dst_cfg; | |
814 | ||
f6f2e546 | 815 | return 0; |
9130e706 GH |
816 | |
817 | err_gsc_config: | |
818 | exynos_gsc_destroy(gsc_data->gsc); | |
819 | gsc_data->gsc = NULL; | |
820 | err_alloc: | |
821 | for (size_t i = 0; i < NUM_GSC_DST_BUFS; i++) { | |
822 | if (gsc_data->dst_buf[i]) { | |
823 | alloc_device->free(alloc_device, gsc_data->dst_buf[i]); | |
824 | gsc_data->dst_buf[i] = NULL; | |
825 | } | |
826 | } | |
827 | return ret; | |
86eb1c67 GH |
828 | } |
829 | ||
830 | static void exynos5_config_handle(private_handle_t *handle, | |
f6f2e546 | 831 | hwc_rect_t &sourceCrop, hwc_rect_t &displayFrame, |
93cc5e7a | 832 | int32_t blending, s3c_fb_win_config &cfg) |
f6f2e546 GH |
833 | { |
834 | cfg.state = cfg.S3C_FB_WIN_STATE_BUFFER; | |
835 | cfg.fd = handle->fd; | |
836 | cfg.x = displayFrame.left; | |
837 | cfg.y = displayFrame.top; | |
838 | cfg.w = WIDTH(displayFrame); | |
839 | cfg.h = HEIGHT(displayFrame); | |
840 | cfg.format = exynos5_format_to_s3c_format(handle->format); | |
841 | uint8_t bpp = exynos5_format_to_bpp(handle->format); | |
842 | cfg.offset = (sourceCrop.top * handle->stride + sourceCrop.left) * bpp / 8; | |
843 | cfg.stride = handle->stride * bpp / 8; | |
93cc5e7a | 844 | cfg.blending = exynos5_blending_to_s3c_blending(blending); |
86eb1c67 GH |
845 | } |
846 | ||
87e707ef | 847 | static void exynos5_config_overlay(hwc_layer_1_t *layer, s3c_fb_win_config &cfg, |
f6f2e546 | 848 | const private_module_t *gralloc_module) |
86eb1c67 | 849 | { |
f6f2e546 GH |
850 | if (layer->compositionType == HWC_BACKGROUND) { |
851 | hwc_color_t color = layer->backgroundColor; | |
852 | cfg.state = cfg.S3C_FB_WIN_STATE_COLOR; | |
853 | cfg.color = (color.r << 16) | (color.g << 8) | color.b; | |
854 | cfg.x = 0; | |
855 | cfg.y = 0; | |
856 | cfg.w = gralloc_module->xres; | |
857 | cfg.h = gralloc_module->yres; | |
858 | return; | |
859 | } | |
860 | ||
861 | private_handle_t *handle = private_handle_t::dynamicCast(layer->handle); | |
93cc5e7a GH |
862 | exynos5_config_handle(handle, layer->sourceCrop, layer->displayFrame, |
863 | layer->blending, cfg); | |
86eb1c67 GH |
864 | } |
865 | ||
866 | static void exynos5_post_callback(void *data, private_handle_t *fb) | |
867 | { | |
f6f2e546 GH |
868 | exynos5_hwc_post_data_t *pdata = (exynos5_hwc_post_data_t *)data; |
869 | ||
870 | struct s3c_fb_win_config_data win_data; | |
871 | struct s3c_fb_win_config *config = win_data.config; | |
872 | memset(config, 0, sizeof(win_data.config)); | |
9130e706 GH |
873 | |
874 | for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { | |
875 | if ( pdata->overlay_map[i] != -1) { | |
876 | hwc_layer_1_t &layer = pdata->overlays[i]; | |
877 | private_handle_t *handle = | |
878 | private_handle_t::dynamicCast(layer.handle); | |
879 | ||
880 | if (layer.acquireFenceFd != -1) { | |
881 | int err = sync_wait(layer.acquireFenceFd, 100); | |
882 | if (err != 0) | |
883 | ALOGW("fence for layer %zu didn't signal in 100 ms: %s", | |
884 | i, strerror(errno)); | |
885 | close(layer.acquireFenceFd); | |
886 | } | |
887 | ||
888 | if (pdata->gsc_map[i].mode == exynos5_gsc_map_t::GSC_M2M) { | |
889 | int gsc_idx = pdata->gsc_map[i].idx; | |
890 | exynos5_config_gsc_m2m(layer, pdata->pdev->alloc_device, | |
891 | &pdata->pdev->gsc[gsc_idx], gsc_idx); | |
892 | } | |
893 | } | |
894 | } | |
895 | ||
f6f2e546 GH |
896 | for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { |
897 | if (i == pdata->fb_window) { | |
898 | hwc_rect_t rect = { 0, 0, fb->width, fb->height }; | |
93cc5e7a GH |
899 | int32_t blending = (i == 0) ? HWC_BLENDING_NONE : |
900 | HWC_BLENDING_PREMULT; | |
901 | exynos5_config_handle(fb, rect, rect, blending, config[i]); | |
f6f2e546 | 902 | } else if ( pdata->overlay_map[i] != -1) { |
9130e706 GH |
903 | hwc_layer_1_t &layer = pdata->overlays[i]; |
904 | private_handle_t *handle = | |
905 | private_handle_t::dynamicCast(layer.handle); | |
906 | ||
907 | if (pdata->gsc_map[i].mode == exynos5_gsc_map_t::GSC_M2M) { | |
908 | int gsc_idx = pdata->gsc_map[i].idx; | |
909 | exynos5_gsc_data_t &gsc = pdata->pdev->gsc[gsc_idx]; | |
910 | ||
911 | if (!gsc.gsc) { | |
912 | ALOGE("failed to queue gscaler %u input for layer %u", | |
913 | gsc_idx, i); | |
914 | continue; | |
915 | } | |
916 | ||
917 | int err = exynos_gsc_stop_exclusive(gsc.gsc); | |
918 | exynos_gsc_destroy(gsc.gsc); | |
919 | gsc.gsc = NULL; | |
920 | if (err < 0) { | |
921 | ALOGE("failed to dequeue gscaler output for layer %u", i); | |
922 | continue; | |
923 | } | |
924 | ||
925 | buffer_handle_t dst_buf = gsc.dst_buf[gsc.current_buf]; | |
926 | gsc.current_buf = (gsc.current_buf + 1) % NUM_GSC_DST_BUFS; | |
927 | private_handle_t *dst_handle = | |
928 | private_handle_t::dynamicCast(dst_buf); | |
90219f32 GH |
929 | hwc_rect_t sourceCrop = { 0, 0, |
930 | WIDTH(layer.displayFrame), HEIGHT(layer.displayFrame) }; | |
931 | exynos5_config_handle(dst_handle, sourceCrop, | |
93cc5e7a | 932 | layer.displayFrame, layer.blending, config[i]); |
9130e706 GH |
933 | } |
934 | else { | |
935 | exynos5_config_overlay(&layer, config[i], | |
936 | pdata->pdev->gralloc_module); | |
87e707ef EG |
937 | } |
938 | } | |
93cc5e7a GH |
939 | if (i == 0 && config[i].blending != S3C_FB_BLENDING_NONE) { |
940 | ALOGV("blending not supported on window 0; forcing BLENDING_NONE"); | |
941 | config[i].blending = S3C_FB_BLENDING_NONE; | |
942 | } | |
943 | ||
9130e706 | 944 | ALOGV("window %u configuration:", i); |
f6f2e546 GH |
945 | dump_config(config[i]); |
946 | } | |
86eb1c67 | 947 | |
f6f2e546 GH |
948 | int ret = ioctl(pdata->pdev->fd, S3CFB_WIN_CONFIG, &win_data); |
949 | if (ret < 0) | |
950 | ALOGE("ioctl S3CFB_WIN_CONFIG failed: %d", errno); | |
86eb1c67 | 951 | |
f6f2e546 GH |
952 | if (pdata->pdev->hdmi_mirroring) |
953 | hdmi_output(pdata->pdev, fb); | |
cdd61b35 | 954 | |
87e707ef EG |
955 | pthread_mutex_lock(&pdata->completion_lock); |
956 | pdata->fence = win_data.fence; | |
957 | pthread_cond_signal(&pdata->completion); | |
958 | pthread_mutex_unlock(&pdata->completion_lock); | |
86eb1c67 GH |
959 | } |
960 | ||
e94046d9 JH |
961 | static int exynos5_set(struct hwc_composer_device_1 *dev, |
962 | size_t numDisplays, hwc_display_contents_1_t** displays) | |
86eb1c67 | 963 | { |
f6f2e546 GH |
964 | exynos5_hwc_composer_device_1_t *pdev = |
965 | (exynos5_hwc_composer_device_1_t *)dev; | |
86eb1c67 | 966 | |
e94046d9 | 967 | if (!numDisplays || !displays || !displays[0] || !displays[0]->dpy || !displays[0]->sur) |
f6f2e546 | 968 | return 0; |
86eb1c67 | 969 | |
f6f2e546 GH |
970 | hwc_callback_queue_t *queue = NULL; |
971 | pthread_mutex_t *lock = NULL; | |
972 | exynos5_hwc_post_data_t *data = NULL; | |
86eb1c67 | 973 | |
e94046d9 | 974 | if (displays[0]->numHwLayers) { |
87e707ef EG |
975 | for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { |
976 | if (pdev->bufs.overlay_map[i] != -1) { | |
977 | pdev->bufs.overlays[i] = | |
e94046d9 | 978 | displays[0]->hwLayers[pdev->bufs.overlay_map[i]]; |
87e707ef EG |
979 | } |
980 | } | |
981 | ||
f6f2e546 GH |
982 | data = (exynos5_hwc_post_data_t *) |
983 | malloc(sizeof(exynos5_hwc_post_data_t)); | |
984 | memcpy(data, &pdev->bufs, sizeof(pdev->bufs)); | |
86eb1c67 | 985 | |
87e707ef EG |
986 | data->fence = -1; |
987 | pthread_mutex_init(&data->completion_lock, NULL); | |
988 | pthread_cond_init(&data->completion, NULL); | |
989 | ||
f6f2e546 GH |
990 | if (pdev->bufs.fb_window == NO_FB_NEEDED) { |
991 | exynos5_post_callback(data, NULL); | |
992 | } else { | |
87e707ef EG |
993 | |
994 | struct hwc_callback_entry entry; | |
995 | entry.callback = exynos5_post_callback; | |
996 | entry.data = data; | |
997 | ||
998 | queue = reinterpret_cast<hwc_callback_queue_t *>( | |
999 | pdev->gralloc_module->queue); | |
1000 | lock = const_cast<pthread_mutex_t *>( | |
1001 | &pdev->gralloc_module->queue_lock); | |
1002 | ||
1003 | pthread_mutex_lock(lock); | |
1004 | queue->push_front(entry); | |
1005 | pthread_mutex_unlock(lock); | |
1006 | ||
e94046d9 JH |
1007 | EGLBoolean success = eglSwapBuffers((EGLDisplay)displays[0]->dpy, |
1008 | (EGLSurface)displays[0]->sur); | |
87e707ef EG |
1009 | if (!success) { |
1010 | ALOGE("HWC_EGL_ERROR"); | |
e94046d9 | 1011 | if (displays[0]) { |
87e707ef EG |
1012 | pthread_mutex_lock(lock); |
1013 | queue->removeAt(0); | |
1014 | pthread_mutex_unlock(lock); | |
1015 | free(data); | |
1016 | } | |
1017 | return HWC_EGL_ERROR; | |
1018 | } | |
1019 | } | |
f6f2e546 | 1020 | } |
86eb1c67 | 1021 | |
86eb1c67 | 1022 | |
87e707ef EG |
1023 | pthread_mutex_lock(&data->completion_lock); |
1024 | while (data->fence == -1) | |
1025 | pthread_cond_wait(&data->completion, &data->completion_lock); | |
1026 | pthread_mutex_unlock(&data->completion_lock); | |
1027 | ||
1028 | for (size_t i = 0; i < NUM_HW_WINDOWS; i++) { | |
1029 | if (pdev->bufs.overlay_map[i] != -1) { | |
1030 | int dup_fd = dup(data->fence); | |
1031 | if (dup_fd < 0) | |
1032 | ALOGW("release fence dup failed: %s", strerror(errno)); | |
e94046d9 | 1033 | displays[0]->hwLayers[pdev->bufs.overlay_map[i]].releaseFenceFd = dup_fd; |
87e707ef EG |
1034 | } |
1035 | } | |
1036 | close(data->fence); | |
1037 | free(data); | |
f6f2e546 | 1038 | return 0; |
86eb1c67 GH |
1039 | } |
1040 | ||
87e707ef | 1041 | static void exynos5_registerProcs(struct hwc_composer_device_1* dev, |
f6f2e546 | 1042 | hwc_procs_t const* procs) |
86eb1c67 | 1043 | { |
f6f2e546 GH |
1044 | struct exynos5_hwc_composer_device_1_t* pdev = |
1045 | (struct exynos5_hwc_composer_device_1_t*)dev; | |
1046 | pdev->procs = const_cast<hwc_procs_t *>(procs); | |
86eb1c67 GH |
1047 | } |
1048 | ||
87e707ef | 1049 | static int exynos5_query(struct hwc_composer_device_1* dev, int what, int *value) |
86eb1c67 | 1050 | { |
f6f2e546 GH |
1051 | struct exynos5_hwc_composer_device_1_t *pdev = |
1052 | (struct exynos5_hwc_composer_device_1_t *)dev; | |
1053 | ||
1054 | switch (what) { | |
1055 | case HWC_BACKGROUND_LAYER_SUPPORTED: | |
1056 | // we support the background layer | |
1057 | value[0] = 1; | |
1058 | break; | |
1059 | case HWC_VSYNC_PERIOD: | |
1060 | // vsync period in nanosecond | |
1061 | value[0] = 1000000000.0 / pdev->gralloc_module->fps; | |
1062 | break; | |
1063 | default: | |
1064 | // unsupported query | |
1065 | return -EINVAL; | |
1066 | } | |
1067 | return 0; | |
86eb1c67 GH |
1068 | } |
1069 | ||
e94046d9 JH |
1070 | static int exynos5_eventControl(struct hwc_composer_device_1 *dev, int dpy, |
1071 | int event, int enabled) | |
86eb1c67 | 1072 | { |
f6f2e546 GH |
1073 | struct exynos5_hwc_composer_device_1_t *pdev = |
1074 | (struct exynos5_hwc_composer_device_1_t *)dev; | |
1075 | ||
1076 | switch (event) { | |
1077 | case HWC_EVENT_VSYNC: | |
1078 | __u32 val = !!enabled; | |
1079 | int err = ioctl(pdev->fd, S3CFB_SET_VSYNC_INT, &val); | |
1080 | if (err < 0) { | |
1081 | ALOGE("vsync ioctl failed"); | |
1082 | return -errno; | |
1083 | } | |
1084 | ||
1085 | return 0; | |
1086 | } | |
1087 | ||
1088 | return -EINVAL; | |
86eb1c67 GH |
1089 | } |
1090 | ||
cdd61b35 | 1091 | static void handle_hdmi_uevent(struct exynos5_hwc_composer_device_1_t *pdev, |
f6f2e546 | 1092 | const char *buff, int len) |
cdd61b35 | 1093 | { |
f6f2e546 GH |
1094 | const char *s = buff; |
1095 | s += strlen(s) + 1; | |
cdd61b35 | 1096 | |
f6f2e546 GH |
1097 | while (*s) { |
1098 | if (!strncmp(s, "SWITCH_STATE=", strlen("SWITCH_STATE="))) | |
1099 | pdev->hdmi_hpd = atoi(s + strlen("SWITCH_STATE=")) == 1; | |
cdd61b35 | 1100 | |
f6f2e546 GH |
1101 | s += strlen(s) + 1; |
1102 | if (s - buff >= len) | |
1103 | break; | |
1104 | } | |
cdd61b35 | 1105 | |
d6bb7cef BG |
1106 | if (pdev->hdmi_hpd) { |
1107 | if (hdmi_get_config(pdev)) { | |
1108 | ALOGE("Error reading HDMI configuration"); | |
1109 | pdev->hdmi_hpd = false; | |
1110 | return; | |
1111 | } | |
1112 | } | |
1113 | ||
f6f2e546 | 1114 | ALOGV("HDMI HPD changed to %s", pdev->hdmi_hpd ? "enabled" : "disabled"); |
d6bb7cef BG |
1115 | if (pdev->hdmi_hpd) |
1116 | ALOGI("HDMI Resolution changed to %dx%d", pdev->hdmi_cfg.h, pdev->hdmi_cfg.w); | |
cdd61b35 | 1117 | |
f6f2e546 GH |
1118 | if (pdev->procs && pdev->procs->invalidate) |
1119 | pdev->procs->invalidate(pdev->procs); | |
cdd61b35 BG |
1120 | } |
1121 | ||
2972485a | 1122 | static void handle_vsync_event(struct exynos5_hwc_composer_device_1_t *pdev) |
86eb1c67 | 1123 | { |
f6f2e546 GH |
1124 | if (!pdev->procs || !pdev->procs->vsync) |
1125 | return; | |
86eb1c67 | 1126 | |
fbeb8534 GH |
1127 | int err = lseek(pdev->vsync_fd, 0, SEEK_SET); |
1128 | if (err < 0) { | |
1129 | ALOGE("error seeking to vsync timestamp: %s", strerror(errno)); | |
1130 | return; | |
1131 | } | |
1132 | ||
2972485a | 1133 | char buf[4096]; |
fbeb8534 | 1134 | err = read(pdev->vsync_fd, buf, sizeof(buf)); |
2972485a GH |
1135 | if (err < 0) { |
1136 | ALOGE("error reading vsync timestamp: %s", strerror(errno)); | |
1137 | return; | |
f6f2e546 | 1138 | } |
2972485a | 1139 | buf[sizeof(buf) - 1] = '\0'; |
86eb1c67 | 1140 | |
2972485a GH |
1141 | errno = 0; |
1142 | uint64_t timestamp = strtoull(buf, NULL, 0); | |
1143 | if (!errno) | |
1144 | pdev->procs->vsync(pdev->procs, 0, timestamp); | |
86eb1c67 GH |
1145 | } |
1146 | ||
1147 | static void *hwc_vsync_thread(void *data) | |
1148 | { | |
f6f2e546 GH |
1149 | struct exynos5_hwc_composer_device_1_t *pdev = |
1150 | (struct exynos5_hwc_composer_device_1_t *)data; | |
1151 | char uevent_desc[4096]; | |
1152 | memset(uevent_desc, 0, sizeof(uevent_desc)); | |
1153 | ||
1154 | setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY); | |
1155 | ||
1156 | uevent_init(); | |
f6f2e546 | 1157 | |
fbeb8534 GH |
1158 | char temp[4096]; |
1159 | int err = read(pdev->vsync_fd, temp, sizeof(temp)); | |
1160 | if (err < 0) { | |
1161 | ALOGE("error reading vsync timestamp: %s", strerror(errno)); | |
1162 | return NULL; | |
1163 | } | |
1164 | ||
2972485a GH |
1165 | struct pollfd fds[2]; |
1166 | fds[0].fd = pdev->vsync_fd; | |
1167 | fds[0].events = POLLPRI; | |
1168 | fds[1].fd = uevent_get_fd(); | |
1169 | fds[1].events = POLLIN; | |
1170 | ||
1171 | while (true) { | |
1172 | int err = poll(fds, 2, -1); | |
3464b1dd | 1173 | |
2972485a GH |
1174 | if (err > 0) { |
1175 | if (fds[0].revents & POLLPRI) { | |
1176 | handle_vsync_event(pdev); | |
1177 | } | |
1178 | else if (fds[1].revents & POLLIN) { | |
1179 | int len = uevent_next_event(uevent_desc, | |
1180 | sizeof(uevent_desc) - 2); | |
1181 | ||
1182 | bool hdmi = !strcmp(uevent_desc, | |
1183 | "change@/devices/virtual/switch/hdmi"); | |
1184 | if (hdmi) | |
1185 | handle_hdmi_uevent(pdev, uevent_desc, len); | |
1186 | } | |
1187 | } | |
1188 | else if (err == -1) { | |
1189 | if (errno == EINTR) | |
1190 | break; | |
1191 | ALOGE("error in vsync thread: %s", strerror(errno)); | |
1192 | } | |
f6f2e546 GH |
1193 | } |
1194 | ||
1195 | return NULL; | |
86eb1c67 GH |
1196 | } |
1197 | ||
e94046d9 | 1198 | static int exynos5_blank(struct hwc_composer_device_1 *dev, int dpy, int blank) |
00359a88 CC |
1199 | { |
1200 | struct exynos5_hwc_composer_device_1_t *pdev = | |
1201 | (struct exynos5_hwc_composer_device_1_t *)dev; | |
1202 | ||
1203 | int fb_blank = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK; | |
1204 | int err = ioctl(pdev->fd, FBIOBLANK, fb_blank); | |
1205 | if (err < 0) { | |
1206 | ALOGE("%sblank ioctl failed", blank ? "" : "un"); | |
1207 | return -errno; | |
1208 | } | |
1209 | ||
1210 | return 0; | |
1211 | } | |
1212 | ||
87e707ef | 1213 | struct hwc_methods_1 exynos5_methods = { |
f6f2e546 | 1214 | eventControl: exynos5_eventControl, |
00359a88 | 1215 | blank: exynos5_blank, |
86eb1c67 GH |
1216 | }; |
1217 | ||
1218 | static int exynos5_close(hw_device_t* device); | |
1219 | ||
1220 | static int exynos5_open(const struct hw_module_t *module, const char *name, | |
f6f2e546 | 1221 | struct hw_device_t **device) |
86eb1c67 | 1222 | { |
f6f2e546 GH |
1223 | int ret; |
1224 | int sw_fd; | |
1225 | ||
1226 | if (strcmp(name, HWC_HARDWARE_COMPOSER)) { | |
1227 | return -EINVAL; | |
1228 | } | |
1229 | ||
1230 | struct exynos5_hwc_composer_device_1_t *dev; | |
1231 | dev = (struct exynos5_hwc_composer_device_1_t *)malloc(sizeof(*dev)); | |
1232 | memset(dev, 0, sizeof(*dev)); | |
1233 | ||
1234 | if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, | |
1235 | (const struct hw_module_t **)&dev->gralloc_module)) { | |
1236 | ALOGE("failed to get gralloc hw module"); | |
1237 | ret = -EINVAL; | |
1238 | goto err_get_module; | |
1239 | } | |
1240 | ||
9130e706 GH |
1241 | if (gralloc_open((const hw_module_t *)dev->gralloc_module, |
1242 | &dev->alloc_device)) { | |
1243 | ALOGE("failed to open gralloc"); | |
1244 | ret = -EINVAL; | |
1245 | goto err_get_module; | |
1246 | } | |
1247 | ||
f6f2e546 GH |
1248 | dev->fd = open("/dev/graphics/fb0", O_RDWR); |
1249 | if (dev->fd < 0) { | |
1250 | ALOGE("failed to open framebuffer"); | |
1251 | ret = dev->fd; | |
9130e706 | 1252 | goto err_open_fb; |
f6f2e546 GH |
1253 | } |
1254 | ||
d6bb7cef BG |
1255 | dev->hdmi_fd = open("/dev/video16", O_RDWR); |
1256 | if (dev->hdmi_fd < 0) { | |
1257 | ALOGE("failed to open hdmi device"); | |
1258 | ret = dev->hdmi_fd; | |
1259 | goto err_ioctl; | |
1260 | } | |
1261 | ||
2972485a GH |
1262 | dev->vsync_fd = open("/sys/devices/platform/exynos5-fb.1/vsync", O_RDONLY); |
1263 | if (dev->vsync_fd < 0) { | |
1264 | ALOGE("failed to open vsync attribute"); | |
1265 | ret = dev->vsync_fd; | |
d6bb7cef | 1266 | goto err_hdmi; |
2972485a GH |
1267 | } |
1268 | ||
f6f2e546 GH |
1269 | sw_fd = open("/sys/class/switch/hdmi/state", O_RDONLY); |
1270 | if (sw_fd) { | |
1271 | char val; | |
1272 | if (read(sw_fd, &val, 1) == 1 && val == '1') | |
1273 | dev->hdmi_hpd = true; | |
1274 | } | |
1275 | ||
1276 | dev->base.common.tag = HARDWARE_DEVICE_TAG; | |
1277 | dev->base.common.version = HWC_DEVICE_API_VERSION_1_0; | |
1278 | dev->base.common.module = const_cast<hw_module_t *>(module); | |
1279 | dev->base.common.close = exynos5_close; | |
1280 | ||
1281 | dev->base.prepare = exynos5_prepare; | |
1282 | dev->base.set = exynos5_set; | |
1283 | dev->base.registerProcs = exynos5_registerProcs; | |
1284 | dev->base.query = exynos5_query; | |
1285 | dev->base.methods = &exynos5_methods; | |
1286 | ||
1287 | dev->bufs.pdev = dev; | |
1288 | ||
1289 | *device = &dev->base.common; | |
1290 | ||
1291 | ret = pthread_create(&dev->vsync_thread, NULL, hwc_vsync_thread, dev); | |
1292 | if (ret) { | |
1293 | ALOGE("failed to start vsync thread: %s", strerror(ret)); | |
1294 | ret = -ret; | |
2972485a | 1295 | goto err_vsync; |
f6f2e546 GH |
1296 | } |
1297 | ||
1298 | return 0; | |
86eb1c67 | 1299 | |
2972485a GH |
1300 | err_vsync: |
1301 | close(dev->vsync_fd); | |
d6bb7cef BG |
1302 | err_hdmi: |
1303 | close(dev->hdmi_fd); | |
86eb1c67 | 1304 | err_ioctl: |
f6f2e546 | 1305 | close(dev->fd); |
9130e706 GH |
1306 | err_open_fb: |
1307 | gralloc_close(dev->alloc_device); | |
86eb1c67 | 1308 | err_get_module: |
f6f2e546 GH |
1309 | free(dev); |
1310 | return ret; | |
86eb1c67 GH |
1311 | } |
1312 | ||
1313 | static int exynos5_close(hw_device_t *device) | |
1314 | { | |
f6f2e546 GH |
1315 | struct exynos5_hwc_composer_device_1_t *dev = |
1316 | (struct exynos5_hwc_composer_device_1_t *)device; | |
2972485a GH |
1317 | pthread_kill(dev->vsync_thread, SIGTERM); |
1318 | pthread_join(dev->vsync_thread, NULL); | |
9130e706 GH |
1319 | for (size_t i = 0; i < NUM_GSC_UNITS; i++) { |
1320 | if (dev->gsc[i].gsc) | |
1321 | exynos_gsc_destroy(dev->gsc[i].gsc); | |
1322 | for (size_t j = 0; i < NUM_GSC_DST_BUFS; j++) | |
1323 | if (dev->gsc[i].dst_buf[j]) | |
1324 | dev->alloc_device->free(dev->alloc_device, dev->gsc[i].dst_buf[j]); | |
1325 | } | |
1326 | gralloc_close(dev->alloc_device); | |
2972485a | 1327 | close(dev->vsync_fd); |
d6bb7cef | 1328 | close(dev->hdmi_fd); |
f6f2e546 GH |
1329 | close(dev->fd); |
1330 | return 0; | |
86eb1c67 GH |
1331 | } |
1332 | ||
1333 | static struct hw_module_methods_t exynos5_hwc_module_methods = { | |
f6f2e546 | 1334 | open: exynos5_open, |
86eb1c67 GH |
1335 | }; |
1336 | ||
1337 | hwc_module_t HAL_MODULE_INFO_SYM = { | |
f6f2e546 GH |
1338 | common: { |
1339 | tag: HARDWARE_MODULE_TAG, | |
1340 | module_api_version: HWC_MODULE_API_VERSION_0_1, | |
1341 | hal_api_version: HARDWARE_HAL_API_VERSION, | |
1342 | id: HWC_HARDWARE_MODULE_ID, | |
1343 | name: "Samsung exynos5 hwcomposer module", | |
1344 | author: "Google", | |
1345 | methods: &exynos5_hwc_module_methods, | |
1346 | } | |
86eb1c67 | 1347 | }; |